View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package otherTests;
7   
8   import static org.junit.jupiter.api.Assertions.assertEquals;
9   import static org.junit.jupiter.api.Assertions.assertNotNull;
10  import static org.junit.jupiter.api.Assertions.assertSame;
11  import static org.junit.jupiter.api.Assertions.assertThrows;
12  
13  import java.security.SecureRandom;
14  import java.util.ArrayList;
15  import java.util.Collections;
16  import java.util.HashSet;
17  import java.util.List;
18  import java.util.Set;
19  
20  import mockit.Deencapsulation;
21  
22  import org.junit.jupiter.api.Test;
23  
24  final class DeencapsulationTest {
25  
26      static final class Subclass extends BaseClass {
27          private static final SecureRandom SECURE_RANDOM = new SecureRandom();
28          final int INITIAL_VALUE = SECURE_RANDOM.nextInt();
29          final int initialValue = -1;
30  
31          @SuppressWarnings("unused")
32          private static final Integer constantField = 123;
33  
34          private static StringBuilder buffer;
35          @SuppressWarnings("unused")
36          private static char static1;
37          @SuppressWarnings("unused")
38          private static char static2;
39  
40          static StringBuilder getBuffer() {
41              return buffer;
42          }
43  
44          static void setBuffer(StringBuilder buffer) {
45              Subclass.buffer = buffer;
46          }
47  
48          private String stringField;
49          private int intField;
50          private int intField2;
51          private List<String> listField;
52  
53          int getIntField() {
54              return intField;
55          }
56  
57          void setIntField(int intField) {
58              this.intField = intField;
59          }
60  
61          int getIntField2() {
62              return intField2;
63          }
64  
65          void setIntField2(int intField2) {
66              this.intField2 = intField2;
67          }
68  
69          String getStringField() {
70              return stringField;
71          }
72  
73          void setStringField(String stringField) {
74              this.stringField = stringField;
75          }
76  
77          List<String> getListField() {
78              return listField;
79          }
80  
81          void setListField(List<String> listField) {
82              this.listField = listField;
83          }
84      }
85  
86      final Subclass anInstance = new Subclass();
87  
88      @Test
89      void getInstanceFieldByName() {
90          anInstance.setIntField(3);
91          anInstance.setStringField("test");
92          anInstance.setListField(Collections.<String> emptyList());
93  
94          Integer intValue = Deencapsulation.getField(anInstance, "intField");
95          String stringValue = Deencapsulation.getField(anInstance, "stringField");
96          List<String> listValue = Deencapsulation.getField(anInstance, "listField");
97  
98          assertEquals(anInstance.getIntField(), intValue.intValue());
99          assertEquals(anInstance.getStringField(), stringValue);
100         assertSame(anInstance.getListField(), listValue);
101     }
102 
103     @Test
104     public void attemptToGetInstanceFieldByNameWithWrongName() {
105         Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
106             Deencapsulation.getField(anInstance, "noField");
107         });
108         assertEquals("No instance field of name \"noField\" found in class otherTests.BaseClass",
109                 throwable.getMessage());
110     }
111 
112     @Test
113     void getInheritedInstanceFieldByName() {
114         anInstance.baseInt = 3;
115         anInstance.baseString = "test";
116         anInstance.baseSet = Collections.emptySet();
117 
118         Integer intValue = Deencapsulation.getField(anInstance, "baseInt");
119         String stringValue = Deencapsulation.getField(anInstance, "baseString");
120         Set<Boolean> listValue = Deencapsulation.getField(anInstance, "baseSet");
121 
122         assertEquals(anInstance.baseInt, intValue.intValue());
123         assertEquals(anInstance.baseString, stringValue);
124         assertSame(anInstance.baseSet, listValue);
125     }
126 
127     @Test
128     @SuppressWarnings("unchecked")
129     void getInstanceFieldByType() {
130         anInstance.setStringField("by type");
131         anInstance.setListField(new ArrayList<String>());
132 
133         String stringValue = Deencapsulation.getField(anInstance, String.class);
134         List<String> listValue = Deencapsulation.getField(anInstance, List.class);
135         List<String> listValue2 = Deencapsulation.getField(anInstance, ArrayList.class);
136 
137         assertEquals(anInstance.getStringField(), stringValue);
138         assertSame(anInstance.getListField(), listValue);
139         assertSame(listValue, listValue2);
140     }
141 
142     @Test
143     public void attemptToGetInstanceFieldByTypeWithWrongType() {
144         Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
145             Deencapsulation.getField(anInstance, Byte.class);
146         });
147         assertEquals("Instance field of type byte or Byte not found in class otherTests.BaseClass",
148                 throwable.getMessage());
149     }
150 
151     @Test
152     public void attemptToGetInstanceFieldByTypeForClassWithMultipleFieldsOfThatType() {
153         Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
154             Deencapsulation.getField(anInstance, int.class);
155         });
156         assertEquals("More than one instance field from which a value of type int "
157                 + "can be read exists in class otherTests.DeencapsulationTest$Subclass: "
158                 + "INITIAL_VALUE, initialValue", throwable.getMessage());
159     }
160 
161     @Test
162     @SuppressWarnings("unchecked")
163     void getInheritedInstanceFieldByType() {
164         Set<Boolean> fieldValueOnInstance = new HashSet<>();
165         anInstance.baseSet = fieldValueOnInstance;
166 
167         Set<Boolean> setValue = Deencapsulation.getField(anInstance, fieldValueOnInstance.getClass());
168         Set<Boolean> setValue2 = Deencapsulation.getField(anInstance, HashSet.class);
169 
170         assertSame(fieldValueOnInstance, setValue);
171         assertSame(setValue, setValue2);
172     }
173 
174     @Test
175     void getInstanceFieldOnBaseClassByType() {
176         anInstance.setLongField(15);
177 
178         long longValue = Deencapsulation.getField(anInstance, long.class);
179 
180         assertEquals(15, longValue);
181     }
182 
183     @Test
184     void getStaticFieldByName() {
185         Subclass.setBuffer(new StringBuilder());
186 
187         StringBuilder b = Deencapsulation.getField(Subclass.class, "buffer");
188 
189         assertSame(Subclass.getBuffer(), b);
190     }
191 
192     @Test
193     public void attemptToGetStaticFieldByNameFromWrongClass() {
194         Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
195             Deencapsulation.getField(BaseClass.class, "buffer");
196         });
197         assertEquals("No static field of name \"buffer\" found in class otherTests.BaseClass", throwable.getMessage());
198     }
199 
200     @Test
201     void getStaticFieldByType() {
202         Subclass.setBuffer(new StringBuilder());
203 
204         StringBuilder b = Deencapsulation.getField(Subclass.class, StringBuilder.class);
205 
206         assertSame(Subclass.getBuffer(), b);
207     }
208 
209     @Test
210     void setInstanceFieldByName() {
211         anInstance.setIntField2(1);
212 
213         Deencapsulation.setField(anInstance, "intField2", 901);
214 
215         assertEquals(901, anInstance.getIntField2());
216     }
217 
218     @Test
219     public void attemptToSetInstanceFieldByNameWithWrongName() {
220         Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
221             Deencapsulation.setField(anInstance, "noField", 901);
222         });
223         assertEquals("No instance field of name \"noField\" found in class otherTests.BaseClass",
224                 throwable.getMessage());
225     }
226 
227     @Test
228     void setInstanceFieldByType() {
229         anInstance.setStringField("");
230 
231         Deencapsulation.setField(anInstance, "Test");
232 
233         assertEquals("Test", anInstance.getStringField());
234     }
235 
236     @Test
237     public void attemptToSetInstanceFieldByTypeWithWrongType() {
238         Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
239             Deencapsulation.setField(anInstance, (byte) 123);
240         });
241         assertEquals("Instance field of type byte or Byte not found in class otherTests.BaseClass",
242                 throwable.getMessage());
243     }
244 
245     @Test
246     public void attemptToSetInstanceFieldByTypeForClassWithMultipleFieldsOfThatType() {
247         Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
248             Deencapsulation.setField(anInstance, 901);
249         });
250         assertEquals(
251                 "More than one instance field to which a value of type int "
252                         + "or Integer can be assigned exists in class "
253                         + "otherTests.DeencapsulationTest$Subclass: INITIAL_VALUE, initialValue",
254                 throwable.getMessage());
255     }
256 
257     @Test
258     void setStaticFieldByName() {
259         Subclass.setBuffer(null);
260 
261         Deencapsulation.setField(Subclass.class, "buffer", new StringBuilder());
262 
263         assertNotNull(Subclass.getBuffer());
264     }
265 
266     @Test
267     public void attemptToSetStaticFieldByNameWithWrongName() {
268         Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
269             Deencapsulation.setField(Subclass.class, "noField", null);
270         });
271         assertEquals("No static field of name \"noField\" found in class otherTests.BaseClass", throwable.getMessage());
272     }
273 
274     @Test
275     void setStaticFieldByType() {
276         Subclass.setBuffer(null);
277 
278         Deencapsulation.setField(Subclass.class, new StringBuilder());
279 
280         assertNotNull(Subclass.getBuffer());
281     }
282 
283     @Test
284     public void attemptToSetFieldByTypeWithoutAValue() {
285         Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
286             Deencapsulation.setField(Subclass.class, null);
287         });
288         assertEquals("Missing field value when setting field by type", throwable.getMessage());
289     }
290 
291     @Test
292     public void attemptToSetStaticFieldByTypeWithWrongType() {
293         Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
294             Deencapsulation.setField(Subclass.class, new String());
295         });
296         assertEquals("Static field of type String not found in class otherTests.BaseClass", throwable.getMessage());
297     }
298 
299     @Test
300     public void attemptToSetStaticFieldByTypeForClassWithMultipleFieldsOfThatType() {
301         Throwable throwable = assertThrows(IllegalArgumentException.class, () -> {
302             Deencapsulation.setField(Subclass.class, 'A');
303         });
304         assertEquals("More than one static field to which a value of type char or "
305                 + "Character can be assigned exists in class "
306                 + "otherTests.DeencapsulationTest$Subclass: static1, static2", throwable.getMessage());
307     }
308 
309     @Test
310     void setFinalInstanceFields() {
311         Subclass obj = new Subclass();
312 
313         Deencapsulation.setField(obj, "INITIAL_VALUE", 123);
314         Deencapsulation.setField(obj, "initialValue", 123);
315 
316         assertEquals(123, obj.INITIAL_VALUE);
317         assertEquals(123, (int) Deencapsulation.getField(obj, "initialValue"));
318         assertEquals(-1, obj.initialValue); // in this case, the compile-time constant gets embedded in client code
319     }
320 
321     @Test
322     public void attemptToSetAStaticFinalField() {
323         Throwable throwable = assertThrows(RuntimeException.class, () -> {
324             Deencapsulation.setField(Subclass.class, "constantField", 54);
325         });
326         assertEquals(
327                 "java.lang.IllegalAccessException: Can not set static final java.lang.Integer "
328                         + "field otherTests.DeencapsulationTest$Subclass.constantField to java.lang.Integer",
329                 throwable.getMessage());
330     }
331 }