diff --git a/src/test/java/org/mockitointegration/ClassLoadabilityChecker.java b/src/test/java/org/mockitointegration/ClassLoadabilityChecker.java
new file mode 100644
index 0000000000..3b75689ca9
--- /dev/null
+++ b/src/test/java/org/mockitointegration/ClassLoadabilityChecker.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitointegration;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Check that classes can be loaded and initialized on a provided classloader. Used
+ * for checking that Mockito has no dependency on libraries like JUnit.
+ *
+ * Some classes are excluded from this checking - namely, classes that fail due to
+ * the absence of Java classes. It's assumed that this is due to a specific optional
+ * dependency on APIs available in certain Java versions and so other elements of the
+ * test Matrix will check that those classes do not depend on JUnit or ByteBuddy. We
+ * exclude based on the failure of a ClassNotFoundException, or a NoClassDefFoundError
+ * caused by the failing to load of a failing parent class.
+ */
+public final class ClassLoadabilityChecker {
+ private static final boolean INITIALIZE_CLASSES = true;
+ private final Set excludedClasses = new HashSet<>();
+ private final ClassLoader classLoader;
+ private final String purpose;
+
+ public ClassLoadabilityChecker(ClassLoader classLoader, String purpose) {
+ this.classLoader = classLoader;
+ this.purpose = purpose;
+ }
+
+ public void checkLoadability(String className) {
+ try {
+ Class.forName(className, INITIALIZE_CLASSES, classLoader);
+ } catch (ClassNotFoundException | NoClassDefFoundError e) {
+ if (isFailureExcluded(className, e)) {
+ return;
+ }
+ e.printStackTrace();
+ throw new AssertionError(
+ String.format("'%s' has some dependency to %s",
+ className, purpose));
+ }
+ }
+
+ private boolean isFailureExcluded(String loadedClass, Throwable thrown) {
+ if (thrown == null) {
+ return false;
+ }
+ if (thrown instanceof ClassNotFoundException) {
+ ClassNotFoundException cnf = (ClassNotFoundException) thrown;
+ if (cnf.getMessage().startsWith("java.")) {
+ excludedClasses.add(loadedClass);
+ return true;
+ }
+ } else if (thrown instanceof NoClassDefFoundError) {
+ NoClassDefFoundError ncdf = (NoClassDefFoundError) thrown;
+ // if Foo fails due to depending on a Java class, Foo$Bar will fail with a NCDFE
+ int lastInnerClass = loadedClass.lastIndexOf('$');
+ if (lastInnerClass != -1) {
+ String parent = loadedClass.substring(0, lastInnerClass);
+ if (excludedClasses.contains(parent) && ncdf.getMessage().contains(parent)) {
+ excludedClasses.add(loadedClass);
+ return true;
+ }
+ }
+ }
+
+ return isFailureExcluded(loadedClass, thrown.getCause());
+ }
+}
diff --git a/src/test/java/org/mockitointegration/NoByteCodeDependenciesTest.java b/src/test/java/org/mockitointegration/NoByteCodeDependenciesTest.java
index 3a2908dc1c..1f5a4dc195 100644
--- a/src/test/java/org/mockitointegration/NoByteCodeDependenciesTest.java
+++ b/src/test/java/org/mockitointegration/NoByteCodeDependenciesTest.java
@@ -43,21 +43,10 @@ public void pure_mockito_should_not_depend_bytecode_libraries() throws Exception
pureMockitoAPIClasses.remove(
"org.mockito.internal.util.reflection.InstrumentationMemberAccessor");
+ ClassLoadabilityChecker checker = new ClassLoadabilityChecker(
+ classLoader_without_bytecode_libraries, "ByteBuddy or Objenesis");
for (String pureMockitoAPIClass : pureMockitoAPIClasses) {
- checkDependency(classLoader_without_bytecode_libraries, pureMockitoAPIClass);
- }
- }
-
- private void checkDependency(ClassLoader classLoader, String pureMockitoAPIClass)
- throws ClassNotFoundException {
- try {
- Class.forName(pureMockitoAPIClass, true, classLoader);
- } catch (Throwable e) {
- e.printStackTrace();
- throw new AssertionError(
- String.format(
- "'%s' has some dependency to Byte Buddy or Objenesis",
- pureMockitoAPIClass));
+ checker.checkLoadability(pureMockitoAPIClass);
}
}
}
diff --git a/src/test/java/org/mockitointegration/NoJUnitDependenciesTest.java b/src/test/java/org/mockitointegration/NoJUnitDependenciesTest.java
index 7b156f0aa3..8798b09ccb 100644
--- a/src/test/java/org/mockitointegration/NoJUnitDependenciesTest.java
+++ b/src/test/java/org/mockitointegration/NoJUnitDependenciesTest.java
@@ -42,27 +42,17 @@ public void pure_mockito_should_not_depend_JUnit___ByteBuddy() throws Exception
.omit("runners", "junit", "JUnit", "opentest4j")
.listOwnedClasses();
+ ClassLoadabilityChecker checker = new ClassLoadabilityChecker(classLoader_without_JUnit, "JUnit");
+
// The later class is required to be initialized before any inline mock maker classes can be
// loaded.
- checkDependency(
- classLoader_without_JUnit,
+ checker.checkLoadability(
"org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker");
pureMockitoAPIClasses.remove(
"org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker");
for (String pureMockitoAPIClass : pureMockitoAPIClasses) {
- checkDependency(classLoader_without_JUnit, pureMockitoAPIClass);
- }
- }
-
- private void checkDependency(ClassLoader classLoader_without_JUnit, String pureMockitoAPIClass)
- throws ClassNotFoundException {
- try {
- Class.forName(pureMockitoAPIClass, true, classLoader_without_JUnit);
- } catch (Throwable e) {
- e.printStackTrace();
- throw new AssertionError(
- String.format("'%s' has some dependency to JUnit", pureMockitoAPIClass));
+ checker.checkLoadability(pureMockitoAPIClass);
}
}
}