From 8d4fa8f3e85b566cd32669dddf7bc2ae28a9604a Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Tue, 27 Mar 2018 20:12:02 +0300 Subject: [PATCH] Stop running tests from inner classes in JUnit3RunnerWithInners (KT-23234) Running tests as part of parent class produced test names on TeamCity that were different from test names obtained when inner classes were executed first. And it looks like test order execution in Gradle depends on file walker and file system. #KT-23234 Fixed --- .../kotlin/test/JUnit3RunnerWithInners.java | 137 ++++++------------ 1 file changed, 44 insertions(+), 93 deletions(-) diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/JUnit3RunnerWithInners.java b/compiler/tests-common/tests/org/jetbrains/kotlin/test/JUnit3RunnerWithInners.java index 21c2ac6d953..136eca16c5e 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/JUnit3RunnerWithInners.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/JUnit3RunnerWithInners.java @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.test; import junit.framework.Test; +import junit.framework.TestCase; import junit.framework.TestResult; import junit.framework.TestSuite; import org.junit.internal.MethodSorter; @@ -29,25 +30,27 @@ import org.junit.runner.notification.RunNotifier; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.*; +import java.util.ArrayList; import java.util.regex.Pattern; /** - * This runner runs class with all inners test classes, but monitors situation when - * inner classes are already processed. + * This runner executes own tests and bypass Gradle filtering for inner classes execution. + * Together with the hack in `tasks.kt - fun Project.projectTest()` that adds inner class files to processing, + * this allows running tests in inner classes when parent class pattern is used. + * + * This class also suppress "No tests found in class" warning when inner test classes are present. + * + * Previous implementation that was building test suite with test cases for inner classes automatically, produced unstable test names + * on TeamCity. Names were different when inner test is executed as top class or part of the other parent class. */ public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortable { - private static final Set processedClasses = new HashSet<>(); - - private JUnit38ClassRunner delegateRunner; - private final Class klass; - private boolean isFakeTest = false; + private final JUnit38ClassRunner delegateRunner; private static class FakeEmptyClassTest implements Test, Filterable { - private final String klassName; + private final String className; FakeEmptyClassTest(Class klass) { - this.klassName = klass.getName(); + this.className = klass.getName(); } @Override @@ -63,7 +66,7 @@ public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortab @Override public String toString() { - return "Empty class with inners for " + klassName; + return "Empty class with inners for " + className; } @Override @@ -73,44 +76,26 @@ public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortab } public JUnit3RunnerWithInners(Class klass) { - this.klass = klass; - } + super(); - @Override - public void run(RunNotifier notifier) { - initialize(); - delegateRunner.run(notifier); - } + String className = klass.getName(); - @Override - public Description getDescription() { - initialize(); - return isFakeTest ? Description.EMPTY : delegateRunner.getDescription(); - } + Test test = new TestSuite(klass.asSubclass(TestCase.class)); + if (!hasOwnTestMethods(klass)) { + for (Class declaredClass : klass.getDeclaredClasses()) { + if (TestCase.class.isAssignableFrom(declaredClass)) { + test = new FakeEmptyClassTest(klass); + break; + } + } + } - @Override - public void filter(Filter filter) throws NoTestsRemainException { - initialize(); - delegateRunner.filter(filter); - } - - @Override - public void sort(Sorter sorter) { - initialize(); - delegateRunner.sort(sorter); - } - - private void initialize() { - if (delegateRunner != null) return; - Test collectedTests = getCollectedTests(); - - delegateRunner = new JUnit38ClassRunner(collectedTests) { + delegateRunner = new JUnit38ClassRunner(test) { @Override public void filter(Filter filter) throws NoTestsRemainException { - String classDescription = collectedTests.toString(); String classPatternString = getGradleClassPattern(filter); if (classPatternString != null) { - if (Pattern.compile(classPatternString + "\\$.*").matcher(classDescription).matches()) { + if (Pattern.compile(classPatternString + "\\$.*").matcher(className).matches()) { return; } } @@ -120,64 +105,29 @@ public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortab }; } - private Test getCollectedTests() { - if (processedClasses.contains(klass)) { - isFakeTest = true; - return new FakeEmptyClassTest(klass); - } - - Set classes = collectDeclaredClasses(klass, true); - Set unprocessedClasses = unprocessedClasses(classes); - processedClasses.addAll(unprocessedClasses); - - return createTreeTestSuite(klass, unprocessedClasses); + @Override + public void run(RunNotifier notifier) { + delegateRunner.run(notifier); } - private static Test createTreeTestSuite(Class root, Set classes) { - Map classSuites = new HashMap<>(); - - for (Class aClass : classes) { - classSuites.put(aClass, hasTestMethods(aClass) ? new TestSuite(aClass) : new TestSuite(aClass.getCanonicalName())); - } - - for (Class aClass : classes) { - if (aClass.getEnclosingClass() != null && classes.contains(aClass.getEnclosingClass())) { - classSuites.get(aClass.getEnclosingClass()).addTest(classSuites.get(aClass)); - } - } - - return classSuites.get(root); + @Override + public Description getDescription() { + return delegateRunner.getDescription(); } - private static Set unprocessedClasses(Collection classes) { - Set result = new LinkedHashSet<>(); - for (Class aClass : classes) { - if (!processedClasses.contains(aClass)) { - result.add(aClass); - } - } - - return result; + @Override + public void filter(Filter filter) throws NoTestsRemainException { + delegateRunner.filter(filter); } - private static Set collectDeclaredClasses(Class klass, boolean withItself) { - Set result = new HashSet<>(); - if (withItself) { - result.add(klass); - } - - for (Class aClass : klass.getDeclaredClasses()) { - result.addAll(collectDeclaredClasses(aClass, true)); - } - - return result; + @Override + public void sort(Sorter sorter) { + delegateRunner.sort(sorter); } - private static boolean hasTestMethods(Class klass) { - for (Class currentClass = klass; Test.class.isAssignableFrom(currentClass); currentClass = currentClass.getSuperclass()) { - for (Method each : MethodSorter.getDeclaredMethods(currentClass)) { - if (isTestMethod(each)) return true; - } + private static boolean hasOwnTestMethods(Class klass) { + for (Method each : MethodSorter.getDeclaredMethods(klass)) { + if (isTestMethod(each)) return true; } return false; @@ -229,7 +179,8 @@ public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortab } return patternStr; - } catch (ReflectiveOperationException e) { + } + catch (ReflectiveOperationException e) { throw new IllegalStateException(e); } }