View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit.internal.injection;
7   
8   import edu.umd.cs.findbugs.annotations.NonNull;
9   import edu.umd.cs.findbugs.annotations.Nullable;
10  
11  import java.lang.reflect.Type;
12  import java.net.URI;
13  import java.net.URISyntaxException;
14  import java.nio.file.Path;
15  import java.security.CodeSource;
16  import java.security.ProtectionDomain;
17  
18  import mockit.internal.reflection.GenericTypeReflection;
19  import mockit.internal.util.Utilities;
20  
21  public final class TestedClass {
22      @NonNull
23      final Type declaredType;
24      @NonNull
25      final Class<?> declaredClass;
26      @NonNull
27      public final Class<?> targetClass;
28      @NonNull
29      public final GenericTypeReflection reflection;
30      @NonNull
31      final ProtectionDomain protectionDomainOfTestedClass;
32      @Nullable
33      final String codeLocationParentPath;
34      @NonNull
35      public final String nameOfTestedClass;
36      @Nullable
37      public final TestedClass parent;
38      @Nullable
39      public Class<?> testClass;
40  
41      public TestedClass(@NonNull Type declaredType, @NonNull Class<?> targetClass) {
42          this(declaredType, targetClass, null);
43      }
44  
45      public TestedClass(@NonNull Type declaredType, @NonNull Class<?> targetClass, @Nullable TestedClass parent) {
46          this.declaredType = declaredType;
47          declaredClass = Utilities.getClassType(declaredType);
48          this.targetClass = targetClass;
49          reflection = new GenericTypeReflection(declaredClass, declaredType, false);
50          protectionDomainOfTestedClass = declaredClass.getProtectionDomain();
51          CodeSource codeSource = protectionDomainOfTestedClass.getCodeSource();
52          if (codeSource == null || codeSource.getLocation() == null) {
53              codeLocationParentPath = null;
54          } else {
55              URI location;
56              try {
57                  location = codeSource.getLocation().toURI();
58              } catch (URISyntaxException e) {
59                  location = null;
60              }
61              codeLocationParentPath = Path.of(location).getParent().toString();
62          }
63          nameOfTestedClass = declaredClass.getName();
64          this.parent = parent;
65      }
66  
67      @NonNull
68      public Class<?> getDeclaredClass() {
69          return declaredClass;
70      }
71  
72      public boolean isClassFromSameModuleOrSystemAsTestedClass(@NonNull Class<?> anotherClass) {
73          if (anotherClass.getClassLoader() == null) {
74              return false;
75          }
76  
77          ProtectionDomain anotherProtectionDomain = anotherClass.getProtectionDomain();
78  
79          if (anotherProtectionDomain == null) {
80              return false;
81          }
82  
83          if (anotherProtectionDomain == protectionDomainOfTestedClass) {
84              return true;
85          }
86  
87          CodeSource anotherCodeSource = anotherProtectionDomain.getCodeSource();
88  
89          if (anotherCodeSource == null || anotherCodeSource.getLocation() == null) {
90              return false;
91          }
92  
93          if (codeLocationParentPath != null) {
94              try {
95                  URI anotherClassPath = anotherCodeSource.getLocation().toURI();
96                  String anotherClassParentPath = Path.of(anotherClassPath).getParent().toString();
97  
98                  if (anotherClassParentPath.equals(codeLocationParentPath)) {
99                      return true;
100                 }
101             } catch (URISyntaxException e) {
102                 return false;
103             }
104         }
105 
106         return isInSameSubpackageAsTestedClass(anotherClass);
107     }
108 
109     private boolean isInSameSubpackageAsTestedClass(@NonNull Class<?> anotherClass) {
110         String nameOfAnotherClass = anotherClass.getName();
111         int p1 = nameOfAnotherClass.indexOf('.');
112         int p2 = nameOfTestedClass.indexOf('.');
113         boolean differentPackages = p1 != p2 || p1 == -1;
114 
115         if (differentPackages) {
116             return false;
117         }
118 
119         p1 = nameOfAnotherClass.indexOf('.', p1 + 1);
120         p2 = nameOfTestedClass.indexOf('.', p2 + 1);
121         boolean eitherClassDirectlyInFirstPackageLevel = p1 == -1 || p2 == -1;
122 
123         if (eitherClassDirectlyInFirstPackageLevel) {
124             return true;
125         }
126 
127         boolean differentSubpackages = p1 != p2;
128 
129         return !differentSubpackages && nameOfAnotherClass.substring(0, p1).equals(nameOfTestedClass.substring(0, p2));
130     }
131 }