Skip to content

Commit

Permalink
Class loadability tests no longer fail on Java 8
Browse files Browse the repository at this point in the history
  • Loading branch information
j-baker committed Aug 8, 2022
1 parent 0391e26 commit 9c7d62c
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 28 deletions.
71 changes: 71 additions & 0 deletions 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.
* <p>
* 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<String> 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 (Throwable t) {
if (isFailureExcluded(className, t)) {
return;
}
t.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());
}
}
Expand Up @@ -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);
}
}
}
18 changes: 4 additions & 14 deletions src/test/java/org/mockitointegration/NoJUnitDependenciesTest.java
Expand Up @@ -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);
}
}
}

0 comments on commit 9c7d62c

Please sign in to comment.