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