diff --git a/org.eclipse.jdt.ui.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.ui.tests/META-INF/MANIFEST.MF index 029b52d3035..01ec82f15f5 100644 --- a/org.eclipse.jdt.ui.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.ui.tests/META-INF/MANIFEST.MF @@ -78,7 +78,8 @@ Require-Bundle: Bundle-RequiredExecutionEnvironment: JavaSE-17 Eclipse-BundleShape: dir Bundle-ActivationPolicy: lazy -Import-Package: org.junit.jupiter.api, +Import-Package: org.assertj.core.api;version="3.24.2", + org.junit.jupiter.api, org.junit.platform.suite.api, org.junit.platform.suite.commons;status=INTERNAL, org.junit.platform.suite.engine;status=INTERNAL diff --git a/org.eclipse.jdt.ui.tests/testresources/testClasses/JupiterTests.java b/org.eclipse.jdt.ui.tests/testresources/testClasses/JupiterTests.java new file mode 100644 index 00000000000..a3a273a1f83 --- /dev/null +++ b/org.eclipse.jdt.ui.tests/testresources/testClasses/JupiterTests.java @@ -0,0 +1,76 @@ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; + +import junit.framework.TestCase; + +/** + * This class contains some internal classes that should be found/not found by the + * JUnit5TestFinder.
+ *
+ * The names of the classes give a hint about whether or not the class should be found and the + * reason for that. In order to be discovered, a class needs to fulfill these requirements: + * + * + * Whether or not the class can be instantiated (i.e. if they have a non-private empty + * constructor) does not play a role in the discoverability, but running tests on that class will + * throw an exception, + */ +class JupiterTests { + /** + * Methods using this annotation are also considered tests + */ + @Test + @Retention(RetentionPolicy.RUNTIME) + @interface CustomTestAnnotation {} + + static class FoundStatic { + @Test void myTest() {} + } + + static class FoundStaticCustomTestAnnotation { + @CustomTestAnnotation void myTest() {} + } + + private static class NotFoundPrivate { + @CustomTestAnnotation void myTest() {} + } + + static class NotFoundHasNoTests {} + + static class FoundExtendsTestCase extends TestCase { + @Test void myTest() {} + } + + static class FoundExtendsTestCaseCustomTestAnnotation extends TestCase { + @CustomTestAnnotation public void myTest() {} + } + + private static class NotFoundPrivateExtendsTestCase extends TestCase { + @Test public void myTest() {} + } + + static class FoundTestTemplateClass { + @TestTemplate void myTestTemplate() {} + } + + static abstract class NotFoundAbstractWithInnerClass { + class NotFoundInnerInstanceClassWithTest { + @Test void myTest() {} + } + } + + static class NotFoundExtendsAbstractWithInnerWithTest extends NotFoundAbstractWithInnerClass {} + + static class FoundHasInnerClassWithNested { + @Nested class FoundExtendsAbstractWithNested extends NotFoundAbstractWithInnerClass { + @Test void myTest() {} + } + } +} diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/junit/tests/JUnit5TestFinderJupiterTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/junit/tests/JUnit5TestFinderJupiterTest.java new file mode 100644 index 00000000000..70fe5d14d24 --- /dev/null +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/junit/tests/JUnit5TestFinderJupiterTest.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2000, 2020 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.junit.tests; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import org.eclipse.jdt.junit.JUnitCore; +import org.eclipse.jdt.testplugin.JavaProjectHelper; + +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; + +import org.eclipse.jdt.internal.junit.launcher.JUnit5TestFinder; + + +/** + * Test if the JUnit5TestFinder can find tests annotated with the API of JUnit5 + * (Jupiter) + */ +@RunWith(Parameterized.class) +public class JUnit5TestFinderJupiterTest { + + record TestScenario(String testClass, int testTypesCount) { + } + + private static final String JAVA_CLASS_NAME= "JupiterTests"; + + private static final String JAVA_FILE_NAME= JAVA_CLASS_NAME + ".java"; + + private static final Path TEST_CLASS_FILE= Path.of("testresources").resolve("testClasses").resolve(JAVA_FILE_NAME); + + private static IJavaProject javaProject; + + @Parameters(name= "{0}") + public static Collection getCompilationUnits() { + + // These are the current "valid" results + return List.of(new TestScenario(JAVA_CLASS_NAME, 7), // + new TestScenario("CustomTestAnnotation", 0), // Not a test class + new TestScenario("FoundStatic", 1), // + new TestScenario("FoundStaticCustomTestAnnotation", 1), // + new TestScenario("NotFoundPrivate", 0), // private class + new TestScenario("NotFoundHasNoTests", 0), // empty class (no tests) + new TestScenario("FoundExtendsTestCase", 1), // + new TestScenario("FoundExtendsTestCaseCustomTestAnnotation", 1), // + new TestScenario("NotFoundPrivateExtendsTestCase", 0), // private class + new TestScenario("FoundTestTemplateClass", 1), // + new TestScenario("NotFoundAbstractWithInnerClass", 0), // can't be instantiated + new TestScenario("NotFoundExtendsAbstractWithInnerWithTest", 0), // FIXME: why isn't this one found even though it can be instantiated? + new TestScenario("FoundHasInnerClassWithNested", 1), // + new TestScenario("NotFoundInnerInstanceClassWithTest", 0), // has test but it can't be instantiated (needs enclosing instance) + new TestScenario("FoundExtendsAbstractWithNested", 1) // + ); + + } + + @Parameter + public TestScenario scenario; + + private static ICompilationUnit compilationUnit; + + @BeforeClass + public static void beforeClass() throws Exception { + javaProject= JavaProjectHelper.createJavaProject("TestProject", "bin"); + JavaProjectHelper.addRTJar(javaProject); + IClasspathEntry cpe= JavaCore.newContainerEntry(JUnitCore.JUNIT5_CONTAINER_PATH); + JavaProjectHelper.addToClasspath(javaProject, cpe); + JavaProjectHelper.set18CompilerOptions(javaProject); + + IPackageFragmentRoot root= JavaProjectHelper.addSourceContainer(javaProject, "src"); + IPackageFragment packageFragment= root.createPackageFragment("somepackage", true, null); + + compilationUnit= createCompilationUnit(packageFragment); + } + + @AfterClass + public static void afterClass() throws Exception { + JavaProjectHelper.delete(javaProject); + } + + @Test + public void testFindTestsInContainer() throws Exception { + IType type= findTypeWithName(scenario.testClass()); + Set foundTestTypes= new HashSet<>(); + + JUnit5TestFinder objectUnderTest= new JUnit5TestFinder(); + objectUnderTest.findTestsInContainer(type, foundTestTypes, null); + + assertThat(foundTestTypes).hasSize(scenario.testTypesCount()); + } + + + private IType findTypeWithName(String name) throws JavaModelException { + for (IType type : compilationUnit.getAllTypes()) { + if (type.getElementName().equals(name)) + return type; + } + return null; + } + + private static ICompilationUnit createCompilationUnit(IPackageFragment packageFragment) throws IOException { + String content= Files.readString(TEST_CLASS_FILE); + + try { + return packageFragment.createCompilationUnit(JAVA_FILE_NAME, content, false, null); + } catch (JavaModelException e) { + // let the test fail + throw new RuntimeException(e); + } + } +}