001    package edu.rice.cs.cunit.subAnnot.test;
002    
003    import edu.rice.cs.cunit.subAnnot.ClassEx;
004    import edu.rice.cs.cunit.subAnnot.ConstructorEx;
005    import edu.rice.cs.cunit.subAnnot.MethodEx;
006    import junit.framework.TestCase;
007    
008    import java.lang.annotation.Annotation;
009    import java.lang.annotation.Retention;
010    import java.lang.annotation.RetentionPolicy;
011    import java.lang.reflect.Method;
012    import java.util.HashMap;
013    import java.util.Iterator;
014    import java.util.Map;
015    import java.util.TreeMap;
016    
017    /**
018     * Unit tests for extended Class class to support annotations with subclassing.
019     *
020     * @author Mathias Ricken
021     */
022    public class ClassExTest extends TestCase {
023        public void testAnnotations() throws Exception {
024            doClassTestNoOrder(TestOne.class);
025        }
026        public void testAnnotationsWithDefaults() throws Exception {
027            doClassTestNoOrder(TestDefaults.class);
028        }
029        
030        public void testTwoAnnotations() throws Exception {
031            doClassTestNoOrder(TestTwo.class);
032        }
033        public void testTwoAnnotationsWithDefaults() throws Exception {
034            doClassTestNoOrder(TestTwoDefaults.class);
035        }
036    
037        @SuppressWarnings("unchecked")
038        private void doClassTestNoOrder(Class cl) throws Exception{
039            Annotation[] aOrig = cl.getAnnotations();
040            ClassEx<TestOne> c = new ClassEx<TestOne>(cl);
041            Annotation[] aExt = c.getAnnotations();
042            assertEquals(aOrig.length, aExt.length);
043            TreeMap<String,TreeMap<String, Object>> orig = new TreeMap<String,TreeMap<String, Object>>();
044            TreeMap<String,TreeMap<String, Object>> ext = new TreeMap<String,TreeMap<String, Object>>();
045            for(int i=0; i<aOrig.length; ++i) {
046                TreeMap<String, Object> mapOrig = new TreeMap<String, Object>();
047                for(Method m: aOrig[i].annotationType().getMethods()) {
048                    if ((!m.getDeclaringClass().equals(Annotation.class)) &&
049                        (m.getParameterTypes().length==0)) {
050                        mapOrig.put(m.getName(), m.invoke(aOrig[i]));
051                    }
052                }
053                orig.put(aOrig[i].annotationType().getName(),mapOrig);
054            }
055            for(int i=0; i<aOrig.length; ++i) {
056                TreeMap<String, Object> mapExt = new TreeMap<String, Object>();
057                for(Method m: aExt[i].annotationType().getMethods()) {
058                    if ((!m.getDeclaringClass().equals(Annotation.class)) &&
059                        (m.getParameterTypes().length==0)) {
060                        mapExt.put(m.getName(), m.invoke(aExt[i]));
061                    }
062                }
063                ext.put(aExt[i].annotationType().getName(),mapExt);
064            }
065            assertEquals(orig.size(), ext.size());
066            Iterator<Map.Entry<String,TreeMap<String, Object>>> origIt = orig.entrySet().iterator();
067            Iterator<Map.Entry<String,TreeMap<String, Object>>> extIt = ext.entrySet().iterator();
068            for(int i=0; i<orig.size(); ++i) {
069                final Map.Entry<String, TreeMap<String, Object>> origEntry = origIt.next();
070                final Map.Entry<String, TreeMap<String, Object>> extEntry = extIt.next();
071                assertEquals(origEntry.getKey(), extEntry.getKey());
072                TreeMap<String, Object> mapOrig = origEntry.getValue();
073                TreeMap<String, Object> mapExt = extEntry.getValue();
074                assertEquals(mapOrig.size(), mapExt.size());
075                Iterator<Map.Entry<String, Object>> mapOrigIt = mapOrig.entrySet().iterator();
076                Iterator<Map.Entry<String, Object>> mapExtIt = mapExt.entrySet().iterator();
077                for(int j=0; i<mapOrig.size(); ++i) {
078                    final Map.Entry<String, Object> mapOrigEntry = mapOrigIt.next();
079                    final Map.Entry<String, Object> mapExtEntry = mapExtIt.next();
080                    assertEquals(mapOrigEntry.getKey(), mapExtEntry.getKey());
081                    Object origV = mapOrigEntry.getValue();
082                    Object extV = mapExtEntry.getValue();
083                    assertEquals(origV, extV);
084                }
085            }
086        }
087    
088        public void testMethodParamAnnots() throws Exception {
089            ClassEx<TestOne> c = new ClassEx<TestOne>(TestOne.class);
090            MethodEx m = c.getMethod("foo", int.class, float.class, Class.class);
091            Annotation[][] as = m.getParameterAnnotations();
092            for(Annotation[] ar: as) {
093                for(Annotation a: ar) {
094                    System.out.print(a);
095                    System.out.print(" ");
096                }
097                System.out.println();
098            }
099            assertEquals(3, as.length);
100            assertEquals(2, as[0].length);
101            assertEquals(0, as[1].length);
102            assertEquals(1, as[2].length);
103            assertEquals("@edu.rice.cs.cunit.subAnnot.test.TestStringAnnotation(value=xxx)", as[0][0].toString());
104            assertEquals("@edu.rice.cs.cunit.subAnnot.test.TestIntAnnotation(value=5)", as[0][1].toString());
105    
106            // assertEquals("@edu.rice.cs.cunit.subAnnot.test.TestDefaultsTwoAnnotation(s=foo, i=123)", as[2][0].toString());
107            Map<String, Object> mapOrig = new HashMap<String, Object>();
108            mapOrig.put("s","foo");
109            mapOrig.put("i", 123);
110            Map<String, Object> mapExt = new HashMap<String, Object>();
111            for(Method mm: as[2][0].annotationType().getMethods()) {
112                if ((!mm.getDeclaringClass().equals(Annotation.class)) &&
113                    (mm.getParameterTypes().length==0)) {
114                    mapExt.put(mm.getName(), mm.invoke(as[2][0]));
115                }
116            }
117            assertEquals(mapOrig.size(), mapExt.size());
118            for(Map.Entry<String, Object> e: mapOrig.entrySet()) {
119                Object v = mapExt.get(e.getKey());
120                assertEquals(e.getValue(),v);
121                mapExt.remove(e.getKey());
122            }
123            assertEquals(0, mapExt.size());
124        }
125    
126        public void testCtorParamAnnots() throws Exception {
127            ClassEx<TestOne> c = new ClassEx<TestOne>(TestOne.class);
128            ConstructorEx<TestOne> ctor = c.getConstructor(int.class, float.class, Class.class);
129            Annotation[][] as = ctor.getParameterAnnotations();
130            for(Annotation[] ar: as) {
131                for(Annotation a: ar) {
132                    System.out.print(a);
133                    System.out.print(" ");
134                }
135                System.out.println();
136            }
137            assertEquals(3, as.length);
138            assertEquals(2, as[0].length);
139            assertEquals(0, as[1].length);
140            assertEquals(1, as[2].length);
141            assertEquals("@edu.rice.cs.cunit.subAnnot.test.TestStringAnnotation(value=xxx)", as[0][0].toString());
142            assertEquals("@edu.rice.cs.cunit.subAnnot.test.TestIntAnnotation(value=5)", as[0][1].toString());
143    
144            // assertEquals("@edu.rice.cs.cunit.subAnnot.test.TestDefaultsTwoAnnotation(s=foo, i=123)", as[2][0].toString());
145            Map<String, Object> mapOrig = new HashMap<String, Object>();
146            mapOrig.put("s","foo");
147            mapOrig.put("i", 123);
148            Map<String, Object> mapExt = new HashMap<String, Object>();
149            for(Method mm: as[2][0].annotationType().getMethods()) {
150                if ((!mm.getDeclaringClass().equals(Annotation.class)) &&
151                    (mm.getParameterTypes().length==0)) {
152                    mapExt.put(mm.getName(), mm.invoke(as[2][0]));
153                }
154            }
155            assertEquals(mapOrig.size(), mapExt.size());
156            for(Map.Entry<String, Object> e: mapOrig.entrySet()) {
157                Object v = mapExt.get(e.getKey());
158                assertEquals(e.getValue(),v);
159                mapExt.remove(e.getKey());
160            }
161            assertEquals(0, mapExt.size());
162        }
163    }
164    
165    @TestStringAnnotation("blabla")
166    @TestIntAnnotation(123)
167    @TestLongAnnotation(7890)
168    @TestCharAnnotation('x')
169    @TestByteAnnotation(15)
170    @TestFloatAnnotation(3.14f)
171    @TestDoubleAnnotation(2.54)
172    @TestBooleanAnnotation(true)
173    @TestClassAnnotation(TestOne.class)
174    @TestEnumAnnotation(RetentionPolicy.RUNTIME)
175    @TestAnnotAnnotation(@TestStringAnnotation("annotation"))
176    @TestArrEnumAnnotation({RetentionPolicy.RUNTIME,RetentionPolicy.CLASS})
177    @TestArrClassAnnotation({TestOne.class, ClassEx.class, RetentionPolicy.class})
178    @TestArrStringAnnotation({"blabla","foobar","snafu"})
179    @TestArrIntAnnotation({123,456})
180    @TestArrLongAnnotation({7890,65536,12345})
181    @TestArrCharAnnotation({'x','y'})
182    @TestArrByteAnnotation({15,16,17,18})
183    @TestArrFloatAnnotation({3.14f})
184    @TestArrDoubleAnnotation({2.54,2.1415})
185    @TestArrBooleanAnnotation({true,false,true})
186    @TestArrAnnotAnnotation({@TestStringAnnotation("annotation"),@TestStringAnnotation("annotation2"),@TestStringAnnotation("annotation3")})
187    class TestOne {
188        public TestOne(@TestStringAnnotation("xxx") @TestIntAnnotation(5) int i, float f, @TestDefaultsTwoAnnotation Class c) { }
189        public void foo(@TestStringAnnotation("xxx") @TestIntAnnotation(5) int i, float f, @TestDefaultsTwoAnnotation Class c) { }
190    }
191    
192    @TestTwoAnnotation(s="foo", i=123)
193    class TestTwo {
194    }
195    
196    @Retention(RetentionPolicy.RUNTIME)
197    @interface TestStringAnnotation {
198        String value();
199    }
200    @Retention(RetentionPolicy.RUNTIME)
201    @interface TestIntAnnotation {
202        int value();
203    }
204    @Retention(RetentionPolicy.RUNTIME)
205    @interface TestLongAnnotation {
206        long value();
207    }
208    @Retention(RetentionPolicy.RUNTIME)
209    @interface TestCharAnnotation {
210        char value();
211    }
212    @Retention(RetentionPolicy.RUNTIME)
213    @interface TestByteAnnotation {
214        byte value();
215    }
216    @Retention(RetentionPolicy.RUNTIME)
217    @interface TestFloatAnnotation {
218        float value();
219    }
220    @Retention(RetentionPolicy.RUNTIME)
221    @interface TestDoubleAnnotation {
222        double value();
223    }
224    @Retention(RetentionPolicy.RUNTIME)
225    @interface TestBooleanAnnotation {
226        boolean value();
227    }
228    @Retention(RetentionPolicy.RUNTIME)
229    @interface TestClassAnnotation {
230        Class value();
231    }
232    @Retention(RetentionPolicy.RUNTIME)
233    @interface TestEnumAnnotation {
234        RetentionPolicy value();
235    }
236    @Retention(RetentionPolicy.RUNTIME)
237    @interface TestAnnotAnnotation {
238        TestStringAnnotation value();
239    }
240    @Retention(RetentionPolicy.RUNTIME)
241    @interface TestArrEnumAnnotation {
242        RetentionPolicy[] value();
243    }
244    @Retention(RetentionPolicy.RUNTIME)
245    @interface TestArrClassAnnotation {
246        Class[] value();
247    }
248    @Retention(RetentionPolicy.RUNTIME)
249    @interface TestArrStringAnnotation {
250        String[] value();
251    }
252    @Retention(RetentionPolicy.RUNTIME)
253    @interface TestArrIntAnnotation {
254        int[] value();
255    }
256    @Retention(RetentionPolicy.RUNTIME)
257    @interface TestArrLongAnnotation {
258        long[] value();
259    }
260    @Retention(RetentionPolicy.RUNTIME)
261    @interface TestArrCharAnnotation {
262        char[] value();
263    }
264    @Retention(RetentionPolicy.RUNTIME)
265    @interface TestArrByteAnnotation {
266        byte[] value();
267    }
268    @Retention(RetentionPolicy.RUNTIME)
269    @interface TestArrFloatAnnotation {
270        float[] value();
271    }
272    @Retention(RetentionPolicy.RUNTIME)
273    @interface TestArrDoubleAnnotation {
274        double[] value();
275    }
276    @Retention(RetentionPolicy.RUNTIME)
277    @interface TestArrBooleanAnnotation {
278        boolean[] value();
279    }
280    @Retention(RetentionPolicy.RUNTIME)
281    @interface TestArrAnnotAnnotation {
282        TestStringAnnotation[] value();
283    }
284    @Retention(RetentionPolicy.RUNTIME)
285    @interface TestTwoAnnotation {
286        String s();
287        int i();
288    }
289    
290    @TestDefaultsStringAnnotation
291    @TestDefaultsIntAnnotation
292    @TestDefaultsLongAnnotation
293    @TestDefaultsCharAnnotation
294    @TestDefaultsByteAnnotation
295    @TestDefaultsFloatAnnotation
296    @TestDefaultsDoubleAnnotation
297    @TestDefaultsBooleanAnnotation
298    @TestDefaultsClassAnnotation
299    @TestDefaultsEnumAnnotation
300    @TestDefaultsAnnotAnnotation
301    @TestDefaultsArrEnumAnnotation
302    @TestDefaultsArrClassAnnotation
303    @TestDefaultsArrStringAnnotation
304    @TestDefaultsArrIntAnnotation
305    @TestDefaultsArrLongAnnotation
306    @TestDefaultsArrCharAnnotation
307    @TestDefaultsArrByteAnnotation
308    @TestDefaultsArrFloatAnnotation
309    @TestDefaultsArrDoubleAnnotation
310    @TestDefaultsArrBooleanAnnotation
311    @TestDefaultsArrAnnotAnnotation
312    class TestDefaults {
313    }
314    
315    @TestDefaultsTwoAnnotation
316    class TestTwoDefaults {
317    }
318    
319    @Retention(RetentionPolicy.RUNTIME)
320    @interface TestDefaultsStringAnnotation {
321        String value() default "str";
322    }
323    @Retention(RetentionPolicy.RUNTIME)
324    @interface TestDefaultsIntAnnotation {
325        int value() default 7;
326    }
327    @Retention(RetentionPolicy.RUNTIME)
328    @interface TestDefaultsLongAnnotation {
329        long value() default 12345;
330    }
331    @Retention(RetentionPolicy.RUNTIME)
332    @interface TestDefaultsCharAnnotation {
333        char value() default 'x';
334    }
335    @Retention(RetentionPolicy.RUNTIME)
336    @interface TestDefaultsByteAnnotation {
337        byte value() default 15;
338    }
339    @Retention(RetentionPolicy.RUNTIME)
340    @interface TestDefaultsFloatAnnotation {
341        float value() default 1.23f;
342    }
343    @Retention(RetentionPolicy.RUNTIME)
344    @interface TestDefaultsDoubleAnnotation {
345        double value() default 4.5678;
346    }
347    @Retention(RetentionPolicy.RUNTIME)
348    @interface TestDefaultsBooleanAnnotation {
349        boolean value() default true;
350    }
351    @Retention(RetentionPolicy.RUNTIME)
352    @interface TestDefaultsClassAnnotation {
353        Class value() default Class.class;
354    }
355    @Retention(RetentionPolicy.RUNTIME)
356    @interface TestDefaultsEnumAnnotation {
357        RetentionPolicy value() default RetentionPolicy.CLASS;
358    }
359    @Retention(RetentionPolicy.RUNTIME)
360    @interface TestDefaultsAnnotAnnotation {
361        TestDefaultsStringAnnotation value() default @TestDefaultsStringAnnotation;
362    }
363    @Retention(RetentionPolicy.RUNTIME)
364    @interface TestDefaultsArrEnumAnnotation {
365        RetentionPolicy[] value() default {RetentionPolicy.CLASS, RetentionPolicy.RUNTIME};
366    }
367    @Retention(RetentionPolicy.RUNTIME)
368    @interface TestDefaultsArrClassAnnotation {
369        Class[] value() default {Integer.class, Long.class};
370    }
371    @Retention(RetentionPolicy.RUNTIME)
372    @interface TestDefaultsArrStringAnnotation {
373        String[] value() default {"foo","bar"};
374    }
375    @Retention(RetentionPolicy.RUNTIME)
376    @interface TestDefaultsArrIntAnnotation {
377        int[] value() default {1,2,3,4,5};
378    }
379    @Retention(RetentionPolicy.RUNTIME)
380    @interface TestDefaultsArrLongAnnotation {
381        long[] value() default {12345,67890};
382    }
383    @Retention(RetentionPolicy.RUNTIME)
384    @interface TestDefaultsArrCharAnnotation {
385        char[] value() default {'a', 'b', 'c'};
386    }
387    @Retention(RetentionPolicy.RUNTIME)
388    @interface TestDefaultsArrByteAnnotation {
389        byte[] value() default {100,101,102};
390    }
391    @Retention(RetentionPolicy.RUNTIME)
392    @interface TestDefaultsArrFloatAnnotation {
393        float[] value() default {3.14f,2.53f};
394    }
395    @Retention(RetentionPolicy.RUNTIME)
396    @interface TestDefaultsArrDoubleAnnotation {
397        double[] value() default {1.2345,6.7890};
398    }
399    @Retention(RetentionPolicy.RUNTIME)
400    @interface TestDefaultsArrBooleanAnnotation {
401        boolean[] value() default {false,true,false};
402    }
403    @Retention(RetentionPolicy.RUNTIME)
404    @interface TestDefaultsArrAnnotAnnotation {
405        TestDefaultsStringAnnotation[] value() default {@TestDefaultsStringAnnotation("annot1"),@TestDefaultsStringAnnotation("annot2")};
406    }
407    @Retention(RetentionPolicy.RUNTIME)
408    @interface TestDefaultsTwoAnnotation {
409        String s() default "foo";
410        int i() default 123;
411    }