Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions runner/android_junit_runner/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

* Catch LinkageError when loading annotation classes (b/536117227)

* Support filtering parameterized tests with arbitrary (non-numeric) parameter names by their root method name. (b/564761639)

**New Features**

* Make perfetto trace sections for tests more identifiable by prefixing with "test:" and using fully qualified class name. (b/204992764)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.runner.Description;
import org.junit.runner.Request;
Expand Down Expand Up @@ -364,6 +365,17 @@ public void removeMethod(String className, String methodName) {
/** A {@link Filter} used to filter out desired test methods from a given class */
private static class MethodFilter extends AbstractFilter {

/**
* Matches a parameterized test method name, capturing the root method name.
*
* <p>Parameterized runners name tests as {@code methodName[<params>]}, where {@code <params>}
* is arbitrary text, e.g. {@code [0]}, {@code [0: 1 + 2 = 3]}, {@code [dryRun=true,retries=2]}
* or {@code [[1, 2]]}. Since a JVM method name cannot contain {@code '['}, everything before
* the first {@code '['} is the root method name.
*/
private static final Pattern PARAMETERIZED_SUFFIX_PATTERN =
Pattern.compile("^([^\\[]+)\\[.*\\]$", Pattern.DOTALL);

private final String className;
private Set<String> includedMethods = new HashSet<>();
private Set<String> excludedMethods = new HashSet<>();
Expand Down Expand Up @@ -408,12 +420,9 @@ public boolean evaluateTest(Description description) {
}

// Strips out the parameterized suffix if it exists
private String stripParameterizedSuffix(String name) {
Pattern suffixPattern = Pattern.compile(".+(\\[[0-9]+\\])$");
if (suffixPattern.matcher(name).matches()) {
name = name.substring(0, name.lastIndexOf('['));
}
return name;
private static String stripParameterizedSuffix(String name) {
Matcher matcher = PARAMETERIZED_SUFFIX_PATTERN.matcher(name);
return matcher.matches() ? matcher.group(1) : name;
}

public void addInclusionMethod(String methodName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,30 @@ public static Collection<Object[]> data() {
public void testParameterized() {}
}

/**
* Parameterized test fixture whose generated names have non-numeric parameter suffixes, e.g.
* {@code testFoo[0: a b]}, {@code testFoo[1: [1, 2]]}, {@code testFoo[2: key=value (Integer)]}
* and a multiline {@code testFoo[3: multi\nline]}.
*/
@RunWith(value = Parameterized.class)
public static class NamedParameterizedTest {

public NamedParameterizedTest(String data) {}

@Parameterized.Parameters(name = "{index}: {0}")
public static Collection<Object[]> data() {
Object[][] data =
new Object[][] {{"a b"}, {"[1, 2]"}, {"key=value (Integer)"}, {"multi\nline"}};
return Arrays.asList(data);
}

@Test
public void testFoo() {}

@Test
public void testBar() {}
}

/** Test fixture for verifying support for suite() methods */
public static class JUnit3Suite {
public static junit.framework.Test suite() {
Expand Down Expand Up @@ -1009,6 +1033,42 @@ public void testParameterizedMethods() throws Exception {
Assert.assertEquals(3, result.getRunCount());
}

/** Test including a parameterized method by root name with non-numeric parameter names. */
@Test
public void testNamedParameterizedMethods_include() {
Request request =
builder.addTestMethod(NamedParameterizedTest.class.getName(), "testFoo").build();
JUnitCore testRunner = new JUnitCore();
Result result = testRunner.run(request);
Assert.assertEquals(4, result.getRunCount());
}

/** Test excluding a parameterized method by root name with non-numeric parameter names. */
@Test
public void testNamedParameterizedMethods_exclude() {
Request request =
builder
.addTestClass(NamedParameterizedTest.class.getName())
.removeTestMethod(NamedParameterizedTest.class.getName(), "testFoo")
.build();
JUnitCore testRunner = new JUnitCore();
Result result = testRunner.run(request);
Assert.assertEquals(4, result.getRunCount());
}

/** Test including a single parameterized instance by its full name. */
@Test
public void testNamedParameterizedMethods_includeFullName() {
Request request =
builder
.addTestMethod(NamedParameterizedTest.class.getName(), "testFoo[1: [1, 2]]")
.addTestMethod(NamedParameterizedTest.class.getName(), "testBar[3: multi\nline]")
.build();
JUnitCore testRunner = new JUnitCore();
Result result = testRunner.run(request);
Assert.assertEquals(2, result.getRunCount());
}

/** Verify adding a class method and removing same class leaves no tests. */
@Test
public void testFilterClassAddMethod() {
Expand Down
Loading