Fix JUnit3RunnerWithInners runner for gradle execution (KT-20684)
#KT-20684 Fixed
This commit is contained in:
@@ -17,7 +17,6 @@
|
|||||||
package org.jetbrains.kotlin.test;
|
package org.jetbrains.kotlin.test;
|
||||||
|
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestCase;
|
|
||||||
import junit.framework.TestResult;
|
import junit.framework.TestResult;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
import org.junit.internal.MethodSorter;
|
import org.junit.internal.MethodSorter;
|
||||||
@@ -27,26 +26,28 @@ import org.junit.runner.Runner;
|
|||||||
import org.junit.runner.manipulation.*;
|
import org.junit.runner.manipulation.*;
|
||||||
import org.junit.runner.notification.RunNotifier;
|
import org.junit.runner.notification.RunNotifier;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This runner runs class with all inners test classes, but monitors situation when those classes are planned to be executed
|
* This runner runs class with all inners test classes, but monitors situation when
|
||||||
* with IDEA package test runner.
|
* inner classes are already processed.
|
||||||
*/
|
*/
|
||||||
public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortable {
|
public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortable {
|
||||||
private static final Set<Class> requestedRunners = new HashSet<>();
|
private static final Set<Class> processedClasses = new HashSet<>();
|
||||||
|
|
||||||
private JUnit38ClassRunner delegateRunner;
|
private JUnit38ClassRunner delegateRunner;
|
||||||
private final Class<?> klass;
|
private final Class<?> klass;
|
||||||
private boolean isFakeTest = false;
|
private boolean isFakeTest = false;
|
||||||
|
|
||||||
private static class FakeEmptyClassTest implements Test {
|
private static class FakeEmptyClassTest implements Test, Filterable {
|
||||||
private final Class<?> klass;
|
private final String klassName;
|
||||||
|
|
||||||
public FakeEmptyClassTest(Class<?> klass) {
|
FakeEmptyClassTest(Class<?> klass) {
|
||||||
this.klass = klass;
|
this.klassName = klass.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -60,19 +61,19 @@ public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortab
|
|||||||
result.endTest(this);
|
result.endTest(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<?> getTestClass() {
|
@Override
|
||||||
return klass;
|
public String toString() {
|
||||||
|
return "Empty class with inners for " + klassName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public void filter(Filter filter) throws NoTestsRemainException {
|
||||||
return "Empty class with inners";
|
throw new NoTestsRemainException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public JUnit3RunnerWithInners(Class<?> klass) {
|
public JUnit3RunnerWithInners(Class<?> klass) {
|
||||||
this.klass = klass;
|
this.klass = klass;
|
||||||
requestedRunners.add(klass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -89,7 +90,6 @@ public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortab
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void filter(Filter filter) throws NoTestsRemainException {
|
public void filter(Filter filter) throws NoTestsRemainException {
|
||||||
delegateRunner = new JUnit38ClassRunner(klass);
|
|
||||||
delegateRunner.filter(filter);
|
delegateRunner.filter(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,34 +99,40 @@ public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortab
|
|||||||
delegateRunner.sort(sorter);
|
delegateRunner.sort(sorter);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initialize() {
|
private void initialize() {
|
||||||
if (delegateRunner != null) return;
|
if (delegateRunner != null) return;
|
||||||
delegateRunner = new JUnit38ClassRunner(getCollectedTests());
|
Test collectedTests = getCollectedTests();
|
||||||
|
|
||||||
|
delegateRunner = new JUnit38ClassRunner(collectedTests) {
|
||||||
|
@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()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Test getCollectedTests() {
|
super.filter(filter);
|
||||||
List<Class> innerClasses = collectDeclaredClasses(klass, false);
|
}
|
||||||
Set<Class> unprocessedInnerClasses = unprocessedClasses(innerClasses);
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (unprocessedInnerClasses.isEmpty()) {
|
private Test getCollectedTests() {
|
||||||
if (!innerClasses.isEmpty() && !hasTestMethods(klass)) {
|
if (processedClasses.contains(klass)) {
|
||||||
isFakeTest = true;
|
isFakeTest = true;
|
||||||
return new FakeEmptyClassTest(klass);
|
return new FakeEmptyClassTest(klass);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return new TestSuite(klass.asSubclass(TestCase.class));
|
Set<Class> classes = collectDeclaredClasses(klass, true);
|
||||||
}
|
Set<Class> unprocessedClasses = unprocessedClasses(classes);
|
||||||
}
|
processedClasses.addAll(unprocessedClasses);
|
||||||
else if (unprocessedInnerClasses.size() == innerClasses.size()) {
|
|
||||||
return createTreeTestSuite(klass);
|
return createTreeTestSuite(klass, unprocessedClasses);
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new TestSuite(klass.asSubclass(TestCase.class));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Test createTreeTestSuite(Class root) {
|
private static Test createTreeTestSuite(Class root, Set<Class> classes) {
|
||||||
Set<Class> classes = new LinkedHashSet<>(collectDeclaredClasses(root, true));
|
|
||||||
Map<Class, TestSuite> classSuites = new HashMap<>();
|
Map<Class, TestSuite> classSuites = new HashMap<>();
|
||||||
|
|
||||||
for (Class aClass : classes) {
|
for (Class aClass : classes) {
|
||||||
@@ -145,7 +151,7 @@ public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortab
|
|||||||
private static Set<Class> unprocessedClasses(Collection<Class> classes) {
|
private static Set<Class> unprocessedClasses(Collection<Class> classes) {
|
||||||
Set<Class> result = new LinkedHashSet<>();
|
Set<Class> result = new LinkedHashSet<>();
|
||||||
for (Class aClass : classes) {
|
for (Class aClass : classes) {
|
||||||
if (!requestedRunners.contains(aClass)) {
|
if (!processedClasses.contains(aClass)) {
|
||||||
result.add(aClass);
|
result.add(aClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,8 +159,8 @@ public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortab
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Class> collectDeclaredClasses(Class klass, boolean withItself) {
|
private static Set<Class> collectDeclaredClasses(Class klass, boolean withItself) {
|
||||||
List<Class> result = new ArrayList<>();
|
Set<Class> result = new HashSet<>();
|
||||||
if (withItself) {
|
if (withItself) {
|
||||||
result.add(klass);
|
result.add(klass);
|
||||||
}
|
}
|
||||||
@@ -182,4 +188,48 @@ public class JUnit3RunnerWithInners extends Runner implements Filterable, Sortab
|
|||||||
method.getReturnType().equals(Void.TYPE) &&
|
method.getReturnType().equals(Void.TYPE) &&
|
||||||
Modifier.isPublic(method.getModifiers());
|
Modifier.isPublic(method.getModifiers());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getGradleClassPattern(Filter filter) {
|
||||||
|
try {
|
||||||
|
Class<? extends Filter> filterClass = filter.getClass();
|
||||||
|
if (!"org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter$MethodNameFilter".equals(filterClass.getName())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Field matcherField = filterClass.getDeclaredField("matcher");
|
||||||
|
matcherField.setAccessible(true);
|
||||||
|
Object testSelectionMatcher = matcherField.get(filter);
|
||||||
|
Class<?> testSelectionMatcherClass = testSelectionMatcher.getClass();
|
||||||
|
if (!"org.gradle.api.internal.tasks.testing.filter.TestSelectionMatcher".equals(testSelectionMatcherClass.getName())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Field includePatternsField;
|
||||||
|
try {
|
||||||
|
includePatternsField = testSelectionMatcherClass.getDeclaredField("includePatterns");
|
||||||
|
}
|
||||||
|
catch (NoSuchFieldException exception) {
|
||||||
|
includePatternsField = testSelectionMatcherClass.getDeclaredField("buildScriptIncludePatterns");
|
||||||
|
}
|
||||||
|
|
||||||
|
includePatternsField.setAccessible(true);
|
||||||
|
@SuppressWarnings("unchecked") ArrayList<Pattern> includePatterns =
|
||||||
|
(ArrayList<Pattern>) includePatternsField.get(testSelectionMatcher);
|
||||||
|
|
||||||
|
if (includePatterns.size() != 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pattern pattern = includePatterns.get(0);
|
||||||
|
String patternStr = pattern.pattern();
|
||||||
|
|
||||||
|
if (patternStr.endsWith("*")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return patternStr;
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user