1
2
3
4
5 package mockit.internal.capturing;
6
7 import static mockit.internal.util.GeneratedClasses.isExternallyGeneratedSubclass;
8 import static mockit.internal.util.GeneratedClasses.isGeneratedClass;
9
10 import edu.umd.cs.findbugs.annotations.NonNull;
11 import edu.umd.cs.findbugs.annotations.Nullable;
12
13 import java.security.ProtectionDomain;
14
15 import org.checkerframework.checker.index.qual.NonNegative;
16
17 final class CapturedType {
18 private static final ProtectionDomain JMOCKIT_DOMAIN = CapturedType.class.getProtectionDomain();
19
20 @NonNull
21 final Class<?> baseType;
22
23 CapturedType(@NonNull Class<?> baseType) {
24 this.baseType = baseType;
25 }
26
27 boolean isToBeCaptured(@NonNull Class<?> aClass) {
28 if (aClass == baseType || aClass.isArray() || !baseType.isAssignableFrom(aClass)
29 || extendsJMockitBaseType(aClass)) {
30 return false;
31 }
32
33 return !aClass.isInterface() && !isNotToBeCaptured(aClass.getProtectionDomain(), aClass.getName());
34 }
35
36 @SuppressWarnings("UnnecessaryFullyQualifiedName")
37 private static boolean extendsJMockitBaseType(@NonNull Class<?> aClass) {
38 return mockit.MockUp.class.isAssignableFrom(aClass) || mockit.Expectations.class.isAssignableFrom(aClass)
39 || mockit.Verifications.class.isAssignableFrom(aClass)
40 || mockit.Delegate.class.isAssignableFrom(aClass);
41 }
42
43 static boolean isNotToBeCaptured(@Nullable ProtectionDomain pd, @NonNull String classNameOrDesc) {
44 return pd == JMOCKIT_DOMAIN || classNameOrDesc.endsWith("Test")
45 || isNonEligibleInternalJDKClass(classNameOrDesc) || isNonEligibleStandardJavaClass(classNameOrDesc)
46 || isNonEligibleClassFromIDERuntime(classNameOrDesc)
47 || isNonEligibleClassFromThirdPartyLibrary(classNameOrDesc) || isGeneratedClass(classNameOrDesc)
48 || isExternallyGeneratedSubclass(classNameOrDesc);
49 }
50
51 private static boolean isNonEligibleInternalJDKClass(@NonNull String classNameOrDesc) {
52 return classNameOrDesc.startsWith("jdk/")
53 || classNameOrDesc.startsWith("sun") && !hasSubPackage(classNameOrDesc, 4, "management")
54 || classNameOrDesc.startsWith("com") && hasSubPackage(classNameOrDesc, 4, "sun")
55 && !hasSubPackages(classNameOrDesc, 8, "proxy org");
56 }
57
58 private static boolean isNonEligibleStandardJavaClass(@NonNull String classNameOrDesc) {
59 return classNameOrDesc.startsWith("java") && !hasSubPackage(classNameOrDesc, 10, "concurrent");
60 }
61
62 private static boolean isNonEligibleClassFromIDERuntime(@NonNull String classNameOrDesc) {
63 return classNameOrDesc.startsWith("com") && hasSubPackage(classNameOrDesc, 4, "intellij");
64 }
65
66 private static boolean isNonEligibleClassFromThirdPartyLibrary(@NonNull String classNameOrDesc) {
67 return classNameOrDesc.startsWith("junit") || classNameOrDesc.startsWith("org")
68 && hasSubPackages(classNameOrDesc, 4, "junit testng hamcrest gradle");
69 }
70
71 private static boolean hasSubPackage(@NonNull String nameOrDesc, @NonNegative int offset,
72 @NonNull String subPackage) {
73 return nameOrDesc.regionMatches(offset, subPackage, 0, subPackage.length());
74 }
75
76 private static boolean hasSubPackages(@NonNull String nameOrDesc, @NonNegative int offset,
77 @NonNull String subPackages) {
78 int subPackageStart = 0;
79 int subPackageEnd;
80
81 do {
82 subPackageEnd = subPackages.indexOf(' ', subPackageStart);
83 int subPackageLength = (subPackageEnd > 0 ? subPackageEnd : subPackages.length()) - subPackageStart;
84
85 if (nameOrDesc.regionMatches(offset, subPackages, subPackageStart, subPackageLength)) {
86 return true;
87 }
88
89 subPackageStart = subPackageEnd + 1;
90 } while (subPackageEnd > 0);
91
92 return false;
93 }
94 }