Skip to content

Commit

Permalink
#40: Resolve single UniqueIdSpecification for method
Browse files Browse the repository at this point in the history
------------------------------------------------------------------------
On behalf of the community, the JUnit Lambda Team thanks Klarna AB
(http://www.klarna.com) for supporting the JUnit crowdfunding campaign!
------------------------------------------------------------------------
  • Loading branch information
marcphilipp committed Jan 12, 2016
1 parent 441f64b commit eb487e9
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 12 deletions.
Expand Up @@ -14,11 +14,17 @@
import static java.util.Collections.singleton;
import static java.util.function.Predicate.isEqual;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.gen5.commons.util.CollectionUtils.getOnlyElement;
import static org.junit.gen5.commons.util.FunctionUtils.where;
import static org.junit.gen5.engine.ClassFilters.classNameMatches;
import static org.junit.gen5.engine.TestPlanSpecification.*;
import static org.junit.gen5.engine.TestPlanSpecification.allTests;
import static org.junit.gen5.engine.TestPlanSpecification.build;
import static org.junit.gen5.engine.TestPlanSpecification.forClass;
import static org.junit.gen5.engine.TestPlanSpecification.forMethod;
import static org.junit.gen5.engine.TestPlanSpecification.forPackage;

import java.io.File;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -331,6 +337,22 @@ void resolvesMethodSpecificationForTwoMethodsOfSameClass() throws Exception {
assertTestMethodDescriptor(successfulTest, testClass, "successfulTest", "junit4:" + testClass.getName() + "/");
}

@Test
void resolvesUniqueIdSpecificationForSingleMethod() throws Exception {
Class<?> testClass = PlainJUnit4TestCaseWithFiveTestMethods.class;
TestPlanSpecification specification = build(TestPlanSpecification.forUniqueId(
"junit4:org.junit.gen5.engine.junit4.samples.junit4.PlainJUnit4TestCaseWithFiveTestMethods"
+ "/failingTest(org.junit.gen5.engine.junit4.samples.junit4.PlainJUnit4TestCaseWithFiveTestMethods)"));

TestDescriptor engineDescriptor = engine.discoverTests(specification);

TestDescriptor runnerDescriptor = getOnlyElement(engineDescriptor.getChildren());
assertRunnerTestDescriptor(runnerDescriptor, testClass);

TestDescriptor childDescriptor = getOnlyElement(runnerDescriptor.getChildren());
assertTestMethodDescriptor(childDescriptor, testClass, "failingTest", "junit4:" + testClass.getName() + "/");
}

private TestDescriptor findChildByDisplayName(TestDescriptor runnerDescriptor, String displayName) {
// @formatter:off
Set<? extends TestDescriptor> children = runnerDescriptor.getChildren();
Expand Down
Expand Up @@ -21,10 +21,12 @@
*/
public class RunnerTestDescriptor extends JUnit4TestDescriptor {

public static final char SEPARATOR = ':';

private final Runner runner;

public RunnerTestDescriptor(TestDescriptor parent, Class<?> testClass, Runner runner) {
super(parent, ':', testClass.getName(), runner.getDescription(), Optional.of(new JavaSource(testClass)));
super(parent, SEPARATOR, testClass.getName(), runner.getDescription(), Optional.of(new JavaSource(testClass)));
this.runner = runner;
}

Expand Down
Expand Up @@ -10,8 +10,11 @@

package org.junit.gen5.engine.junit4.discovery;

import static java.util.stream.Collectors.*;
import static org.junit.gen5.commons.util.ReflectionUtils.*;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toCollection;
import static org.junit.gen5.commons.util.ReflectionUtils.findAllClassesInClasspathRoot;
import static org.junit.gen5.commons.util.ReflectionUtils.findAllClassesInPackage;
import static org.junit.gen5.engine.junit4.discovery.RunnerTestDescriptorAwareFilter.adapter;

import java.io.File;
import java.lang.reflect.Method;
Expand All @@ -22,9 +25,11 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.function.IntFunction;

import org.junit.gen5.commons.util.ReflectionUtils;
import org.junit.gen5.engine.ClassFilter;
import org.junit.gen5.engine.EngineDescriptor;
import org.junit.gen5.engine.TestPlanSpecification;
Expand All @@ -39,6 +44,8 @@

public class JUnit4TestPlanSpecificationResolver {

private static final char DEFAULT_SEPARATOR = '/';

private final EngineDescriptor engineDescriptor;

public JUnit4TestPlanSpecificationResolver(EngineDescriptor engineDescriptor) {
Expand All @@ -49,7 +56,7 @@ public void resolve(TestPlanSpecification specification) {
ClassFilter classFilter = specification.getClassFilter();
RunnerBuilder runnerBuilder = new DefensiveAllDefaultPossibilitiesBuilder();
Set<Class<?>> unfilteredTestClasses = new LinkedHashSet<>();
Map<Class<?>, List<Filter>> filteredTestClasses = new LinkedHashMap<>();
Map<Class<?>, List<RunnerTestDescriptorAwareFilter>> filteredTestClasses = new LinkedHashMap<>();
specification.accept(new TestPlanSpecificationElementVisitor() {

private final IsPotentialJUnit4TestClass classTester = new IsPotentialJUnit4TestClass();
Expand All @@ -74,9 +81,26 @@ public void visitPackage(String packageName) {
@Override
public void visitMethod(Class<?> testClass, Method testMethod) {
Description methodDescription = Description.createTestDescription(testClass, testMethod.getName());
Filter filter = Filter.matchMethodDescription(methodDescription);
RunnerTestDescriptorAwareFilter filter = adapter(Filter.matchMethodDescription(methodDescription));
filteredTestClasses.computeIfAbsent(testClass, key -> new LinkedList<>()).add(filter);
}

@Override
public void visitUniqueId(String uniqueId) {
String enginePrefix = engineDescriptor.getEngine().getId() + RunnerTestDescriptor.SEPARATOR;
if (uniqueId.startsWith(enginePrefix)) {
int endIndex = uniqueId.indexOf(DEFAULT_SEPARATOR);
String testClassName = uniqueId.substring(enginePrefix.length(), endIndex);
Optional<Class<?>> testClass = ReflectionUtils.loadClass(testClassName);
if (testClass.isPresent()) {
RunnerTestDescriptorAwareFilter filter = new UniqueIdFilter(uniqueId);
filteredTestClasses.computeIfAbsent(testClass.get(), key -> new LinkedList<>()).add(filter);
}
else {
// TODO Log warning
}
}
}
});

// TODO #40 @marcphilipp Clean this up when uniqueIds are resolved
Expand All @@ -86,13 +110,17 @@ public void visitMethod(Class<?> testClass, Method testMethod) {
engineDescriptor.addChild(createCompleteRunnerTestDescriptor(testClass, runner));
}
}
for (Entry<Class<?>, List<Filter>> entry : filteredTestClasses.entrySet()) {
for (Entry<Class<?>, List<RunnerTestDescriptorAwareFilter>> entry : filteredTestClasses.entrySet()) {
Class<?> testClass = entry.getKey();
List<Filter> filters = entry.getValue();
List<RunnerTestDescriptorAwareFilter> filters = entry.getValue();
Runner runner = runnerBuilder.safeRunnerForClass(testClass);
if (runner != null) {
try {
RunnerTestDescriptor runnerTestDescriptor = createCompleteRunnerTestDescriptor(testClass, runner);
filters.stream().forEach(filter -> filter.initialize(runnerTestDescriptor));
new OrFilter(filters).apply(runner);
// TODO Log warning if runner does not implement Filterable
// We need to re-create the RunnerTestDescriptor here to reflect filtering
engineDescriptor.addChild(createCompleteRunnerTestDescriptor(testClass, runner));
}
catch (NoTestsRemainException e) {
Expand Down Expand Up @@ -120,7 +148,8 @@ private void addChildrenRecursively(JUnit4TestDescriptor parent) {
for (int index = 0; index < childrenWithSameUniqueId.size(); index++) {
String reallyUniqueId = uniqueIdGenerator.apply(index);
Description description = childrenWithSameUniqueId.get(index);
JUnit4TestDescriptor child = new JUnit4TestDescriptor(parent, '/', reallyUniqueId, description);
JUnit4TestDescriptor child = new JUnit4TestDescriptor(parent, DEFAULT_SEPARATOR, reallyUniqueId,
description);
parent.addChild(child);
addChildrenRecursively(child);
}
Expand Down
Expand Up @@ -20,9 +20,9 @@

class OrFilter extends Filter {

private final Collection<Filter> filters;
private final Collection<? extends Filter> filters;

OrFilter(Collection<Filter> filters) {
OrFilter(Collection<? extends Filter> filters) {
this.filters = Preconditions.notEmpty(filters, "filters must not be empty");
}

Expand Down
@@ -0,0 +1,40 @@
/*
* Copyright 2015-2016 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/

package org.junit.gen5.engine.junit4.discovery;

import org.junit.gen5.engine.junit4.descriptor.RunnerTestDescriptor;
import org.junit.runner.Description;
import org.junit.runner.manipulation.Filter;

abstract class RunnerTestDescriptorAwareFilter extends Filter {

abstract void initialize(RunnerTestDescriptor runnerTestDescriptor);

static RunnerTestDescriptorAwareFilter adapter(Filter filter) {
return new RunnerTestDescriptorAwareFilter() {
@Override
void initialize(RunnerTestDescriptor runnerTestDescriptor) {
// do nothing
}

@Override
public boolean shouldRun(Description description) {
return filter.shouldRun(description);
}

@Override
public String describe() {
return filter.describe();
}
};
}

}
@@ -0,0 +1,52 @@
/*
* Copyright 2015-2016 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/

package org.junit.gen5.engine.junit4.discovery;

import java.util.Deque;
import java.util.LinkedList;
import java.util.Optional;

import org.junit.gen5.engine.TestDescriptor;
import org.junit.gen5.engine.junit4.descriptor.JUnit4TestDescriptor;
import org.junit.gen5.engine.junit4.descriptor.RunnerTestDescriptor;
import org.junit.runner.Description;

class UniqueIdFilter extends RunnerTestDescriptorAwareFilter {

private final String uniqueId;

private Deque<Description> path;

public UniqueIdFilter(String uniqueId) {
this.uniqueId = uniqueId;
}

@Override
void initialize(RunnerTestDescriptor runnerTestDescriptor) {
Optional<? extends TestDescriptor> identifiedTestDescriptor = runnerTestDescriptor.findByUniqueId(uniqueId);
path = new LinkedList<>();
while (identifiedTestDescriptor.isPresent() && !identifiedTestDescriptor.get().equals(runnerTestDescriptor)) {
path.addFirst(((JUnit4TestDescriptor) identifiedTestDescriptor.get()).getDescription());
identifiedTestDescriptor = identifiedTestDescriptor.get().getParent();
}
}

@Override
public boolean shouldRun(Description description) {
return path.contains(description);
}

@Override
public String describe() {
return "Unique ID " + uniqueId;
}

}

0 comments on commit eb487e9

Please sign in to comment.