aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Nyman <jnyman@google.com>2023-10-24 14:24:34 +0000
committerJens Nyman <jnyman@google.com>2023-10-24 14:24:34 +0000
commit39f38f236b3472cfc993565022ef17e891b6a198 (patch)
treed003f6b671829e65037775469236270332772e42
parent26744e06e2a05f6967fc4273b7eeada58347f7f9 (diff)
downloadTestParameterInjector-39f38f236b3472cfc993565022ef17e891b6a198.tar.gz
Add support for Powermock by making getOnlyConstructor() more lenient (filter out non-public constructors).
This is consistent with how JUnit's getOnlyConstructor() is implemented. Fixes https://github.com/google/TestParameterInjector/issues/40
-rw-r--r--junit4/src/main/java/com/google/testing/junit/testparameterinjector/PluggableTestRunner.java7
-rw-r--r--junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParameterAnnotationMethodProcessor.java17
-rw-r--r--junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParameterInjectorUtils.java47
-rw-r--r--junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParametersMethodProcessor.java14
-rw-r--r--junit4/src/test/java/com/google/testing/junit/testparameterinjector/TestParameterAnnotationMethodProcessorTest.java12
-rw-r--r--junit4/src/test/java/com/google/testing/junit/testparameterinjector/TestParametersMethodProcessorTest.java14
-rw-r--r--junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParameterAnnotationMethodProcessor.java17
-rw-r--r--junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParameterInjectorUtils.java47
-rw-r--r--junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParametersMethodProcessor.java14
9 files changed, 136 insertions, 53 deletions
diff --git a/junit4/src/main/java/com/google/testing/junit/testparameterinjector/PluggableTestRunner.java b/junit4/src/main/java/com/google/testing/junit/testparameterinjector/PluggableTestRunner.java
index 5f4c061..b2a0ad8 100644
--- a/junit4/src/main/java/com/google/testing/junit/testparameterinjector/PluggableTestRunner.java
+++ b/junit4/src/main/java/com/google/testing/junit/testparameterinjector/PluggableTestRunner.java
@@ -316,7 +316,8 @@ abstract class PluggableTestRunner extends BlockJUnit4ClassRunner {
private Object createTestForMethod(FrameworkMethod method) throws Exception {
TestInfo testInfo = ((OverriddenFrameworkMethod) method).getTestInfo();
- Constructor<?> constructor = getTestClass().getOnlyConstructor();
+ Constructor<?> constructor =
+ TestParameterInjectorUtils.getOnlyConstructor(getTestClass().getJavaClass());
// Construct a test instance
Object testInstance;
@@ -343,7 +344,9 @@ abstract class PluggableTestRunner extends BlockJUnit4ClassRunner {
@Override
protected final void validateZeroArgConstructor(List<Throwable> errorsReturned) {
ExecutableValidationResult validationResult =
- getTestMethodProcessors().validateConstructor(getTestClass().getOnlyConstructor());
+ getTestMethodProcessors()
+ .validateConstructor(
+ TestParameterInjectorUtils.getOnlyConstructor(getTestClass().getJavaClass()));
if (validationResult.wasValidated()) {
errorsReturned.addAll(validationResult.validationErrors());
diff --git a/junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParameterAnnotationMethodProcessor.java b/junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParameterAnnotationMethodProcessor.java
index 31ecf25..4132f12 100644
--- a/junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParameterAnnotationMethodProcessor.java
+++ b/junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParameterAnnotationMethodProcessor.java
@@ -867,7 +867,8 @@ final class TestParameterAnnotationMethodProcessor implements TestMethodProcesso
case FIELD: // Fall through.
case CLASS:
return getAnnotationListWithType(
- getOnlyConstructor(testClass).getAnnotations(),
+ TestParameterInjectorUtils.getOnlyConstructor(testClass)
+ .getAnnotations(),
annotationTypeOrigin.annotationType())
.isEmpty();
default:
@@ -890,7 +891,7 @@ final class TestParameterAnnotationMethodProcessor implements TestMethodProcesso
Origin origin = annotationTypeOrigin.origin();
Class<? extends Annotation> annotationType = annotationTypeOrigin.annotationType();
if (origin == Origin.CONSTRUCTOR_PARAMETER) {
- Constructor<?> constructor = getOnlyConstructor(testClass);
+ Constructor<?> constructor = TestParameterInjectorUtils.getOnlyConstructor(testClass);
List<AnnotationWithMetadata> annotations =
getAnnotationWithMetadataListWithType(constructor, annotationType);
@@ -898,7 +899,8 @@ final class TestParameterAnnotationMethodProcessor implements TestMethodProcesso
return toTestParameterValueList(annotations, origin);
}
} else if (origin == Origin.CONSTRUCTOR) {
- Annotation annotation = getOnlyConstructor(testClass).getAnnotation(annotationType);
+ Annotation annotation =
+ TestParameterInjectorUtils.getOnlyConstructor(testClass).getAnnotation(annotationType);
if (annotation != null) {
return ImmutableList.of(
TestParameterValueHolder.create(
@@ -1022,15 +1024,6 @@ final class TestParameterAnnotationMethodProcessor implements TestMethodProcesso
.toList();
}
- private static Constructor<?> getOnlyConstructor(Class<?> testClass) {
- Constructor<?>[] constructors = testClass.getDeclaredConstructors();
- checkState(
- constructors.length == 1,
- "a single public constructor is required for class %s",
- testClass);
- return constructors[0];
- }
-
@Override
public void postProcessTestInstance(Object testInstance, TestInfo testInfo) {
TestIndexHolder testIndexHolder = testInfo.getAnnotation(TestIndexHolder.class);
diff --git a/junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParameterInjectorUtils.java b/junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParameterInjectorUtils.java
new file mode 100644
index 0000000..215719a
--- /dev/null
+++ b/junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParameterInjectorUtils.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.testing.junit.testparameterinjector;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
+
+import com.google.common.collect.ImmutableList;
+import java.lang.reflect.Constructor;
+
+/** Shared utility methods. */
+class TestParameterInjectorUtils {
+
+ /**
+ * Return the only public constructor of the given test class. If there is none, return the only
+ * constructor.
+ *
+ * <p>Normally, there should be exactly one constructor (public or other), but some frameworks
+ * introduce an extra non-public constructor (see
+ * https://github.com/google/TestParameterInjector/issues/40).
+ */
+ static Constructor<?> getOnlyConstructor(Class<?> testClass) {
+ ImmutableList<Constructor<?>> constructors = ImmutableList.copyOf(testClass.getConstructors());
+ if (constructors.isEmpty()) {
+ // There are no public constructors. This is likely a JUnit5 test, so we should take the only
+ // non-public constructor instead.
+ constructors = ImmutableList.copyOf(testClass.getDeclaredConstructors());
+ }
+ checkState(
+ constructors.size() == 1, "Expected exactly one constructor, but got %s", constructors);
+ return getOnlyElement(constructors);
+ }
+
+ private TestParameterInjectorUtils() {}
+}
diff --git a/junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParametersMethodProcessor.java b/junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParametersMethodProcessor.java
index 1a8d022..7dffc29 100644
--- a/junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParametersMethodProcessor.java
+++ b/junit4/src/main/java/com/google/testing/junit/testparameterinjector/TestParametersMethodProcessor.java
@@ -16,7 +16,6 @@ package com.google.testing.junit.testparameterinjector;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Verify.verify;
-import static com.google.common.collect.Iterables.getOnlyElement;
import com.google.auto.value.AutoAnnotation;
import com.google.common.base.Optional;
@@ -90,7 +89,8 @@ final class TestParametersMethodProcessor implements TestMethodProcessor {
@Override
public List<TestInfo> calculateTestInfos(TestInfo originalTest) {
boolean constructorIsParameterized =
- hasRelevantAnnotation(getOnlyConstructor(originalTest.getTestClass()));
+ hasRelevantAnnotation(
+ TestParameterInjectorUtils.getOnlyConstructor(originalTest.getTestClass()));
boolean methodIsParameterized = hasRelevantAnnotation(originalTest.getMethod());
if (!constructorIsParameterized && !methodIsParameterized) {
@@ -148,7 +148,7 @@ final class TestParametersMethodProcessor implements TestMethodProcessor {
private ImmutableList<Optional<TestParametersValues>>
getConstructorParametersOrSingleAbsentElement(Class<?> testClass) {
- Constructor<?> constructor = getOnlyConstructor(testClass);
+ Constructor<?> constructor = TestParameterInjectorUtils.getOnlyConstructor(testClass);
return hasRelevantAnnotation(constructor)
? FluentIterable.from(getConstructorParameters(constructor))
.transform(Optional::of)
@@ -444,14 +444,6 @@ final class TestParametersMethodProcessor implements TestMethodProcessor {
.toArray(Object.class));
}
- private static Constructor<?> getOnlyConstructor(Class<?> testClass) {
- ImmutableList<Constructor<?>> constructors =
- ImmutableList.copyOf(testClass.getDeclaredConstructors());
- checkState(
- constructors.size() == 1, "Expected exactly one constructor, but got %s", constructors);
- return getOnlyElement(constructors);
- }
-
/**
* This mechanism is a workaround to be able to store the test index in the annotation list of the
* {@link TestInfo}, since we cannot carry other information through the test runner.
diff --git a/junit4/src/test/java/com/google/testing/junit/testparameterinjector/TestParameterAnnotationMethodProcessorTest.java b/junit4/src/test/java/com/google/testing/junit/testparameterinjector/TestParameterAnnotationMethodProcessorTest.java
index 3fff85b..df3a16b 100644
--- a/junit4/src/test/java/com/google/testing/junit/testparameterinjector/TestParameterAnnotationMethodProcessorTest.java
+++ b/junit4/src/test/java/com/google/testing/junit/testparameterinjector/TestParameterAnnotationMethodProcessorTest.java
@@ -675,6 +675,14 @@ public class TestParameterAnnotationMethodProcessorTest {
void test(@TestParameter boolean b) {}
}
+ @ClassTestResult(Result.FAILURE)
+ public static class ErrorPackagePrivateConstructor {
+ ErrorPackagePrivateConstructor() {}
+
+ @Test
+ public void test1() {}
+ }
+
public enum EnumA {
A1,
A2
@@ -829,7 +837,7 @@ public class TestParameterAnnotationMethodProcessorTest {
case SUCCESS_FOR_ALL_PLACEMENTS_ONLY:
assertThrows(
- RuntimeException.class,
+ Exception.class,
() ->
SharedTestUtilitiesJUnit4.runTestsAndGetFailures(
newTestRunnerWithParameterizedSupport(
@@ -838,7 +846,7 @@ public class TestParameterAnnotationMethodProcessorTest {
case FAILURE:
assertThrows(
- RuntimeException.class,
+ Exception.class,
() ->
SharedTestUtilitiesJUnit4.runTestsAndGetFailures(
newTestRunnerWithParameterizedSupport(
diff --git a/junit4/src/test/java/com/google/testing/junit/testparameterinjector/TestParametersMethodProcessorTest.java b/junit4/src/test/java/com/google/testing/junit/testparameterinjector/TestParametersMethodProcessorTest.java
index d5417e6..5628330 100644
--- a/junit4/src/test/java/com/google/testing/junit/testparameterinjector/TestParametersMethodProcessorTest.java
+++ b/junit4/src/test/java/com/google/testing/junit/testparameterinjector/TestParametersMethodProcessorTest.java
@@ -494,6 +494,14 @@ public class TestParametersMethodProcessorTest {
public void test1(TestEnum testEnum) {}
}
+ @RunAsTest(failsWithMessage = "Test class should have exactly one public constructor")
+ public static class InvalidTestBecausePackagePrivateConstructor {
+ InvalidTestBecausePackagePrivateConstructor() {}
+
+ @Test
+ public void test1() {}
+ }
+
@Parameters(name = "{0}")
public static Collection<Object[]> parameters() {
return Arrays.stream(TestParametersMethodProcessorTest.class.getClasses())
@@ -527,12 +535,12 @@ public class TestParametersMethodProcessorTest {
public void test_failure() throws Exception {
assume().that(maybeFailureMessage.isPresent()).isTrue();
- IllegalStateException exception =
+ Exception exception =
assertThrows(
- IllegalStateException.class,
+ Exception.class,
() -> SharedTestUtilitiesJUnit4.runTestsAndGetFailures(newTestRunner()));
- assertThat(exception).hasMessageThat().isEqualTo(maybeFailureMessage.get());
+ assertThat(exception).hasMessageThat().contains(maybeFailureMessage.get());
}
private PluggableTestRunner newTestRunner() throws Exception {
diff --git a/junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParameterAnnotationMethodProcessor.java b/junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParameterAnnotationMethodProcessor.java
index 834a83d..5aefe21 100644
--- a/junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParameterAnnotationMethodProcessor.java
+++ b/junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParameterAnnotationMethodProcessor.java
@@ -867,7 +867,8 @@ final class TestParameterAnnotationMethodProcessor implements TestMethodProcesso
case FIELD: // Fall through.
case CLASS:
return getAnnotationListWithType(
- getOnlyConstructor(testClass).getAnnotations(),
+ TestParameterInjectorUtils.getOnlyConstructor(testClass)
+ .getAnnotations(),
annotationTypeOrigin.annotationType())
.isEmpty();
default:
@@ -890,7 +891,7 @@ final class TestParameterAnnotationMethodProcessor implements TestMethodProcesso
Origin origin = annotationTypeOrigin.origin();
Class<? extends Annotation> annotationType = annotationTypeOrigin.annotationType();
if (origin == Origin.CONSTRUCTOR_PARAMETER) {
- Constructor<?> constructor = getOnlyConstructor(testClass);
+ Constructor<?> constructor = TestParameterInjectorUtils.getOnlyConstructor(testClass);
List<AnnotationWithMetadata> annotations =
getAnnotationWithMetadataListWithType(constructor, annotationType);
@@ -898,7 +899,8 @@ final class TestParameterAnnotationMethodProcessor implements TestMethodProcesso
return toTestParameterValueList(annotations, origin);
}
} else if (origin == Origin.CONSTRUCTOR) {
- Annotation annotation = getOnlyConstructor(testClass).getAnnotation(annotationType);
+ Annotation annotation =
+ TestParameterInjectorUtils.getOnlyConstructor(testClass).getAnnotation(annotationType);
if (annotation != null) {
return ImmutableList.of(
TestParameterValueHolder.create(
@@ -1022,15 +1024,6 @@ final class TestParameterAnnotationMethodProcessor implements TestMethodProcesso
.toList();
}
- private static Constructor<?> getOnlyConstructor(Class<?> testClass) {
- Constructor<?>[] constructors = testClass.getDeclaredConstructors();
- checkState(
- constructors.length == 1,
- "a single public constructor is required for class %s",
- testClass);
- return constructors[0];
- }
-
@Override
public void postProcessTestInstance(Object testInstance, TestInfo testInfo) {
TestIndexHolder testIndexHolder = testInfo.getAnnotation(TestIndexHolder.class);
diff --git a/junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParameterInjectorUtils.java b/junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParameterInjectorUtils.java
new file mode 100644
index 0000000..cd47ea1
--- /dev/null
+++ b/junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParameterInjectorUtils.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.testing.junit.testparameterinjector.junit5;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
+
+import com.google.common.collect.ImmutableList;
+import java.lang.reflect.Constructor;
+
+/** Shared utility methods. */
+class TestParameterInjectorUtils {
+
+ /**
+ * Return the only public constructor of the given test class. If there is none, return the only
+ * constructor.
+ *
+ * <p>Normally, there should be exactly one constructor (public or other), but some frameworks
+ * introduce an extra non-public constructor (see
+ * https://github.com/google/TestParameterInjector/issues/40).
+ */
+ static Constructor<?> getOnlyConstructor(Class<?> testClass) {
+ ImmutableList<Constructor<?>> constructors = ImmutableList.copyOf(testClass.getConstructors());
+ if (constructors.isEmpty()) {
+ // There are no public constructors. This is likely a JUnit5 test, so we should take the only
+ // non-public constructor instead.
+ constructors = ImmutableList.copyOf(testClass.getDeclaredConstructors());
+ }
+ checkState(
+ constructors.size() == 1, "Expected exactly one constructor, but got %s", constructors);
+ return getOnlyElement(constructors);
+ }
+
+ private TestParameterInjectorUtils() {}
+}
diff --git a/junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParametersMethodProcessor.java b/junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParametersMethodProcessor.java
index 3ada177..26a1e65 100644
--- a/junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParametersMethodProcessor.java
+++ b/junit5/src/main/java/com/google/testing/junit/testparameterinjector/junit5/TestParametersMethodProcessor.java
@@ -16,7 +16,6 @@ package com.google.testing.junit.testparameterinjector.junit5;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Verify.verify;
-import static com.google.common.collect.Iterables.getOnlyElement;
import com.google.auto.value.AutoAnnotation;
import com.google.common.base.Optional;
@@ -90,7 +89,8 @@ final class TestParametersMethodProcessor implements TestMethodProcessor {
@Override
public List<TestInfo> calculateTestInfos(TestInfo originalTest) {
boolean constructorIsParameterized =
- hasRelevantAnnotation(getOnlyConstructor(originalTest.getTestClass()));
+ hasRelevantAnnotation(
+ TestParameterInjectorUtils.getOnlyConstructor(originalTest.getTestClass()));
boolean methodIsParameterized = hasRelevantAnnotation(originalTest.getMethod());
if (!constructorIsParameterized && !methodIsParameterized) {
@@ -148,7 +148,7 @@ final class TestParametersMethodProcessor implements TestMethodProcessor {
private ImmutableList<Optional<TestParametersValues>>
getConstructorParametersOrSingleAbsentElement(Class<?> testClass) {
- Constructor<?> constructor = getOnlyConstructor(testClass);
+ Constructor<?> constructor = TestParameterInjectorUtils.getOnlyConstructor(testClass);
return hasRelevantAnnotation(constructor)
? FluentIterable.from(getConstructorParameters(constructor))
.transform(Optional::of)
@@ -444,14 +444,6 @@ final class TestParametersMethodProcessor implements TestMethodProcessor {
.toArray(Object.class));
}
- private static Constructor<?> getOnlyConstructor(Class<?> testClass) {
- ImmutableList<Constructor<?>> constructors =
- ImmutableList.copyOf(testClass.getDeclaredConstructors());
- checkState(
- constructors.size() == 1, "Expected exactly one constructor, but got %s", constructors);
- return getOnlyElement(constructors);
- }
-
/**
* This mechanism is a workaround to be able to store the test index in the annotation list of the
* {@link TestInfo}, since we cannot carry other information through the test runner.