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