001: /***
002: * Retrotranslator: a Java bytecode transformer that translates Java classes
003: * compiled with JDK 5.0 into classes that can be run on JVM 1.4.
004: *
005: * Copyright (c) 2005 - 2008 Taras Puchko
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * 3. Neither the name of the copyright holders nor the names of its
017: * contributors may be used to endorse or promote products derived from
018: * this software without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
022: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
023: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
024: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
025: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
026: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
027: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
028: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
029: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
030: * THE POSSIBILITY OF SUCH DAMAGE.
031: */package net.sf.retrotranslator.tests;
032:
033: import java.io.*;
034: import java.lang.annotation.*;
035: import java.lang.reflect.*;
036: import java.util.Properties;
037: import junit.framework.TestCase;
038:
039: /**
040: * A JUnit test class for JDK1.5 to JDK1.4 bytecode & annotation transformation
041: * using Retrotranslator.
042: * <p/>
043: * This testsuite introduces several annotations that can be useful in a JUnit
044: * environment that makes use annotations like the upcoming JUnit 4 version will do.
045: * Besides testing for positive and negative outcomes it provides several annotation
046: * combination at the class and method level and uses different types for the
047: * annotation members. Furthermore it checks if we can do something useful when
048: * detecting annotations.
049: *
050: * @author Klaus P. Berg
051: */
052: @AnnotationProcessingTestCase.Author(name="Klaus P. Berg",mailTo="Klaus-Peter.Berg@company.com")
053: @AnnotationProcessingTestCase.TestingExternalAPI()
054: public final class AnnotationProcessingTestCase extends TestCase {
055:
056: private PrintWriter out = new PrintWriter(new OutputStream() {
057: public void write(int b) throws IOException {
058: }
059: });
060:
061: private static int nbrAnnotatedMethodsSuccessfullyExcecuted;
062: private static int invocationCount = 1;
063:
064: /**
065: * The type of this invocation if it is duplicated.
066: */
067: private InvocationTypes[] invocationTypes;
068: /**
069: * The method of this invocation if it is duplicated.
070: */
071: private Method duplicateAnnotatedMethod;
072: /**
073: * String parameters to pass on if it is duplicated.
074: */
075: private String[] stringArgs;
076: /**
077: * Int parameters to pass on if it is duplicated.
078: */
079: private int[] intArgs;
080: /**
081: * Char parameters to pass on if it is duplicated.
082: */
083: private char[] charArgs;
084: /**
085: * Boolean parameters to pass on if it is duplicated.
086: */
087: private boolean[] booleanArgs;
088: /**
089: * Number of parameters that will be passed to the invoked test case.
090: */
091: private int numParams;
092:
093: public AnnotationProcessingTestCase(final String name) {
094: super (name);
095: }
096:
097: public void testConstructor() {
098: final AnnotationProcessingTestCase test = new AnnotationProcessingTestCase(
099: "test");
100: assertNotNull(test);
101: }
102:
103: // --- Test @Author annotation --------------------------------------------
104:
105: public void testAuthorAnnotationPresence() {
106: final Class<? extends AnnotationProcessingTestCase> annotatedClass = this
107: .getClass();
108: assertTrue(annotatedClass.isAnnotationPresent(Author.class));
109: }
110:
111: public void testAuthorAnnotationAbsence() {
112: final Class<String> annotatedClass = String.class;
113: assertFalse(annotatedClass.isAnnotationPresent(Author.class));
114: }
115:
116: public void testAuthorAnnotationValues() {
117: final Class<? extends AnnotationProcessingTestCase> annotatedClass = this
118: .getClass();
119: assertTrue(annotatedClass.isAnnotationPresent(Author.class));
120: final Author author = annotatedClass
121: .getAnnotation(Author.class);
122: assertEquals("Klaus P. Berg", author.name());
123: assertEquals("Klaus-Peter.Berg@company.com", author.mailTo());
124: }
125:
126: // --- Test @TestingExternalAPI annotation --------------------------------
127:
128: public void testTestingExternalAPIAnnotationPresence() {
129: final Class<? extends AnnotationProcessingTestCase> annotatedClass = this
130: .getClass();
131: assertTrue(annotatedClass
132: .isAnnotationPresent(TestingExternalAPI.class));
133: }
134:
135: public void testTestingExternalAPIAnnotationAbsence() {
136: final Class<String> annotatedClass = String.class;
137: assertFalse(annotatedClass
138: .isAnnotationPresent(TestingExternalAPI.class));
139: }
140:
141: public void testTestingExternalAPIAnnotationValues() {
142: final Class<? extends AnnotationProcessingTestCase> annotatedClass = this
143: .getClass();
144: assertTrue(annotatedClass
145: .isAnnotationPresent(TestingExternalAPI.class));
146: final TestingExternalAPI testingExternalAPI = annotatedClass
147: .getAnnotation(TestingExternalAPI.class);
148: final String[] value = testingExternalAPI.value();
149: assertEquals(1, value.length);
150:
151: final Class<ClassWithTestingApiAnnotation> annotatedInnerClass = ClassWithTestingApiAnnotation.class;
152: assertTrue(annotatedInnerClass
153: .isAnnotationPresent(TestingExternalAPI.class));
154: }
155:
156: public void testTestingExternalAPIAnnotationValuesForInnerClasses() {
157: final Class<ClassWithTestingApiAnnotation> annotatedClass = ClassWithTestingApiAnnotation.class;
158: assertTrue(annotatedClass
159: .isAnnotationPresent(TestingExternalAPI.class));
160: final TestingExternalAPI testingExternalAPI = annotatedClass
161: .getAnnotation(TestingExternalAPI.class);
162: final String[] value = testingExternalAPI.value();
163: assertEquals(2, value.length);
164: assertEquals("First API", value[0]);
165: assertEquals("Second API", value[1]);
166: }
167:
168: // --- Test @Ignore annotation --------------------------------------------
169:
170: public void testIgnoreAnnotationPresence() {
171: final Method[] annotatedMethods = this .getClass()
172: .getDeclaredMethods();
173: for (Method method : annotatedMethods) {
174: if (Modifier.isPrivate(method.getModifiers())) {
175: assertTrue(method.isAnnotationPresent(Ignore.class));
176: }
177: }
178: }
179:
180: public void testIgnoreAnnotationAbsence() {
181: final Method[] annotatedMethods = this .getClass()
182: .getDeclaredMethods();
183: for (Method method : annotatedMethods) {
184: if (Modifier.isPublic(method.getModifiers())) {
185: assertFalse(method.isAnnotationPresent(Ignore.class));
186: }
187: }
188: }
189:
190: public void testIgnoreAnnotationValues() {
191: final Properties expectedFirstIndexVales = new Properties();
192: expectedFirstIndexVales.put("prepareParameterArgumentArray",
193: "test under construction");
194: expectedFirstIndexVales.put("setParamsFromDuplicateAnnotation",
195: "test under construction");
196: expectedFirstIndexVales.put("invokeDuplicatedTestMethod",
197: "private method");
198: expectedFirstIndexVales.put("executeAnnotatedMethod",
199: "another private method");
200: final Method[] annotatedMethods = this .getClass()
201: .getDeclaredMethods();
202: for (Method method : annotatedMethods) {
203: if (Modifier.isPrivate(method.getModifiers())) {
204: final Ignore ignore = method
205: .getAnnotation(Ignore.class);
206: assertEquals("KPB", ignore.initials());
207: assertEquals(expectedFirstIndexVales.get(method
208: .getName()), ignore.reasons()[0]);
209: if (!"executeAnnotatedMethod".equals(method.getName())) {
210: assertEquals(1, ignore.reasons().length);
211: } else {
212: assertEquals(2, ignore.reasons().length);
213: assertEquals("helper method", ignore.reasons()[1]);
214: }
215: }
216: }
217: }
218:
219: // --- Test multiple class level annotations -----------------------------
220:
221: public void testMultipleClassLevelAnnotations() {
222: // Note: inner classes MUST be instantiated; do NOT use
223: // 'ClassWithMultipleClassLevelAnnotations.class'!
224: final Class<ClassWithMultipleClassLevelAnnotations> annotatedClass = ClassWithMultipleClassLevelAnnotations.class;
225: assertTrue(annotatedClass.isAnnotationPresent(Author.class));
226: assertTrue(annotatedClass
227: .isAnnotationPresent(TestingExternalAPI.class));
228:
229: final Author author = annotatedClass
230: .getAnnotation(Author.class);
231: assertEquals("Klaus P. Berg", author.name());
232: assertEquals("Klaus-Peter.berg@web.de", author.mailTo());
233:
234: final TestingExternalAPI testingExternalAPI = annotatedClass
235: .getAnnotation(TestingExternalAPI.class);
236: final String[] value = testingExternalAPI.value();
237: assertEquals(2, value.length);
238: assertEquals("First API", value[0]);
239: assertEquals("Second API", value[1]);
240: }
241:
242: // --- Test @Duplicate annotation ----------------------------------------
243:
244: public void testDuplicateAnnotationPresence() {
245: final Method[] annotatedMethods = this .getClass()
246: .getDeclaredMethods();
247: for (Method method : annotatedMethods) {
248: if (method.getName().startsWith("annotated")) {
249: assertTrue(method.isAnnotationPresent(Duplicate.class));
250: }
251: }
252:
253: final Method[] annotatedMethods2 = ClassWithDefaultMethodLevelAnnotationsOnly.class
254: .getDeclaredMethods();
255: for (Method method : annotatedMethods2) {
256: if (method.getName().startsWith("test")) {
257: assertTrue(method.isAnnotationPresent(Duplicate.class));
258: }
259: }
260: }
261:
262: public void testDuplicateAnnotationAbsence() {
263: final Method[] annotatedMethods = this .getClass()
264: .getDeclaredMethods();
265: for (Method method : annotatedMethods) {
266: if (!method.getName().startsWith("annotated")) {
267: assertFalse(method.isAnnotationPresent(Duplicate.class));
268: }
269: }
270: }
271:
272: public void testMethodsWithDuplicateAnnotation() throws Exception {
273: final Method[] annotatedMethods = this .getClass()
274: .getDeclaredMethods();
275: int nbrAnnotatedMethods = 0;
276: for (Method method : annotatedMethods) {
277: if (method.getName().startsWith("annotated")) {
278: nbrAnnotatedMethods++;
279: duplicateAnnotatedMethod = method;
280: setParamsFromDuplicateAnnotation();
281: prepareParameterArgumentArray();
282: invokeDuplicatedTestMethod();
283: }
284: }
285: // if the invocation type is not set specifically to Async or Sync,
286: // every annotated method is executed twice, once for Async and once for Sync
287: // because we have two times specified an explicit invocation type in the method
288: // annotation we will get the following assert:
289: assertEquals((nbrAnnotatedMethods * 2) - 2,
290: nbrAnnotatedMethodsSuccessfullyExcecuted);
291: }
292:
293: // --- Test multiple method level annotations ----------------------------
294: public void testMultipleMethodLevelAnnotations()
295: throws SecurityException, NoSuchMethodException,
296: IllegalArgumentException, IllegalAccessException,
297: InvocationTargetException {
298: final ClassWithMultipleMethodLevelAnnotations classWithMultipleMethodLevelAnnotations = new ClassWithMultipleMethodLevelAnnotations();
299: final Method method1 = classWithMultipleMethodLevelAnnotations
300: .getClass()
301: .getDeclaredMethod("method1", (Class[]) null);
302: final Ignore ignore1 = method1.getAnnotation(Ignore.class);
303: assertTrue(method1.isAnnotationPresent(Ignore.class));
304: assertEquals("KPB", ignore1.initials());
305:
306: final Method method2 = classWithMultipleMethodLevelAnnotations
307: .getClass().getDeclaredMethod(
308: "method2",
309: new Class[] { InvocationTypes.class,
310: String[].class, int[].class,
311: char[].class, boolean[].class });
312:
313: assertTrue(method2.isAnnotationPresent(Ignore.class));
314: final Ignore ignore2 = method2.getAnnotation(Ignore.class);
315: assertEquals("KPB", ignore2.initials());
316: assertEquals("test under construction", ignore2.reasons()[0]);
317: assertTrue(method2.isAnnotationPresent(Duplicate.class));
318: final Duplicate duplicate = method2
319: .getAnnotation(Duplicate.class);
320: // out.println("duplicate.toString():\n" + duplicate.toString());
321: // assertEquals(
322: // '@'
323: // + Duplicate.class.getName()
324: // + "(stringArgs=[1, 2, 3, 1], "
325: // + "intArgs=[1, 2, 3, 1], booleanArgs=[true, false, false, true], "
326: // + "charArgs=[1, 2, 3, 1], invocationTypes=[Sync])",
327: // duplicate.toString());
328: method2
329: .invoke(classWithMultipleMethodLevelAnnotations,
330: new Object[] { duplicate.invocationTypes()[0],
331: duplicate.stringArgs(),
332: duplicate.intArgs(),
333: duplicate.charArgs(),
334: duplicate.booleanArgs() });
335: }
336:
337: public void testTotalNumberOfDifferentAnnotationsPerClass() {
338: final Class<? extends AnnotationProcessingTestCase> annotatedClass = this
339: .getClass();
340: final Annotation[] allAnnotations = annotatedClass
341: .getDeclaredAnnotations();
342: out.println("\nAll annotations for class "
343: + this .getClass().getName() + ':');
344: for (Annotation annotation : allAnnotations) {
345: out.println(annotation);
346: }
347: assertEquals(2, allAnnotations.length);
348: }
349:
350: public void testTotalNumberOfDifferentAnnotationsPerClass2() {
351: final Class<ClassWithMultipleClassLevelAnnotations> annotatedClass = ClassWithMultipleClassLevelAnnotations.class;
352: final Annotation[] allAnnotations = annotatedClass
353: .getDeclaredAnnotations();
354: out
355: .println("\nAll annotations for class ClassWithMultipleMethodLevelAnnotations:");
356: for (Annotation annotation : allAnnotations) {
357: out.println(annotation);
358: }
359: assertEquals(2, allAnnotations.length);
360: }
361:
362: // --- Helper methods ----------------------------------------------------
363:
364: @Ignore(initials="KPB")
365: private void prepareParameterArgumentArray() {
366: final Class[] paramTypes = duplicateAnnotatedMethod
367: .getParameterTypes();
368: numParams = 1;
369: final int actualNumParams = paramTypes.length;
370: if (stringArgs.length > 0) {
371: numParams++;
372: }
373: if (intArgs.length > 0) {
374: numParams++;
375: }
376: if (charArgs.length > 0) {
377: numParams++;
378: }
379: if (booleanArgs.length > 0) {
380: numParams++;
381: }
382:
383: if (actualNumParams != numParams) {
384: throw new RuntimeException(duplicateAnnotatedMethod
385: + ": Duplicated test case must have exactly "
386: + numParams + " parameter(s)");
387: }
388: if (paramTypes[0] != InvocationTypes.class) {
389: throw new RuntimeException(duplicateAnnotatedMethod
390: + ": Duplicated test case's parameter #1 must "
391: + "be of type 'InvocationTypes'");
392: }
393: }
394:
395: @Ignore(initials="KPB")
396: private void setParamsFromDuplicateAnnotation() {
397: final Duplicate duplicate = duplicateAnnotatedMethod
398: .getAnnotation(Duplicate.class);
399: invocationTypes = duplicate.invocationTypes();
400: stringArgs = duplicate.stringArgs();
401: intArgs = duplicate.intArgs();
402: charArgs = duplicate.charArgs();
403: booleanArgs = duplicate.booleanArgs();
404: }
405:
406: @Ignore(initials="KPB",reasons={"private method"})
407: private void invokeDuplicatedTestMethod() throws Exception {
408: final Object[] args = new Object[numParams];
409: for (InvocationTypes invocationType : invocationTypes) {
410: args[0] = invocationType;
411: executeAnnotatedMethod(args);
412: duplicateAnnotatedMethod.invoke(this , args);
413: }
414: }
415:
416: @Ignore(initials="KPB",reasons={"another private method","helper method"})
417: private void executeAnnotatedMethod(final Object[] args) {
418: int i = 1;
419: // Include each additional parameter that was specified in the
420: // Duplicate annotation
421: if (stringArgs.length > 0) {
422: args[i++] = stringArgs;
423: }
424: if (intArgs.length > 0) {
425: args[i++] = intArgs;
426: }
427: if (charArgs.length > 0) {
428: args[i++] = charArgs;
429: }
430: if (booleanArgs.length > 0) {
431: args[i] = booleanArgs;
432: }
433: }
434:
435: // /////////////////////////////////////////////////////////////////////////
436:
437: @Duplicate
438: public void annotatedMethodWithDefaultDuplicate(
439: final InvocationTypes type) {
440: out
441: .println("*** duplicated method 'annotatedMethodWithDefaultDuplicate' called with type "
442: + type);
443: nbrAnnotatedMethodsSuccessfullyExcecuted++;
444: }
445:
446: @Duplicate(stringArgs={"1","2","3","1"})
447: public void annotatedStringArgs(final InvocationTypes type,
448: final String[] strArgs) {
449: assertEquals(InvocationTypes.values()[invocationCount--], type);
450: assertEquals("1", strArgs[0]);
451: assertEquals("2", strArgs[1]);
452: assertEquals("3", strArgs[2]);
453: assertEquals("1", strArgs[3]);
454: nbrAnnotatedMethodsSuccessfullyExcecuted++;
455: }
456:
457: @Duplicate(intArgs={1,2,3,1})
458: public void annotatedIntArgs(@SuppressWarnings("unused")
459: final InvocationTypes type, final int[] intArgs1) {
460: assertEquals(1, intArgs1[0]);
461: assertEquals(2, intArgs1[1]);
462: assertEquals(3, intArgs1[2]);
463: assertEquals(1, intArgs1[3]);
464: nbrAnnotatedMethodsSuccessfullyExcecuted++;
465: }
466:
467: @Duplicate(charArgs={'1','2','3','1'})
468: public void annotatedCharArgs(@SuppressWarnings("unused")
469: final InvocationTypes type, final char[] charArgs1) {
470: assertEquals('1', charArgs1[0]);
471: assertEquals('2', charArgs1[1]);
472: assertEquals('3', charArgs1[2]);
473: assertEquals('1', charArgs1[3]);
474: nbrAnnotatedMethodsSuccessfullyExcecuted++;
475: }
476:
477: @Duplicate(booleanArgs={true,false,false,true})
478: public void annotatedBooleanArgs(@SuppressWarnings("unused")
479: final InvocationTypes type, final boolean[] booleanArgs1) {
480: assertTrue(booleanArgs1[0]);
481: assertFalse(booleanArgs1[1]);
482: assertFalse(booleanArgs1[2]);
483: assertTrue(booleanArgs1[3]);
484: nbrAnnotatedMethodsSuccessfullyExcecuted++;
485: }
486:
487: @Duplicate(stringArgs={"1","2","3","1"},intArgs={1,2,3,1})
488: public void annotatedMixedArgs1(@SuppressWarnings("unused")
489: final InvocationTypes type, final String[] strArgs,
490: final int[] intArgs1) {
491: assertEquals(1, intArgs1[0]);
492: assertEquals(2, intArgs1[1]);
493: assertEquals(3, intArgs1[2]);
494: assertEquals(1, intArgs1[3]);
495: assertEquals("1", strArgs[0]);
496: assertEquals("2", strArgs[1]);
497: assertEquals("3", strArgs[2]);
498: assertEquals("1", strArgs[3]);
499: nbrAnnotatedMethodsSuccessfullyExcecuted++;
500: }
501:
502: @Duplicate(stringArgs={"1","2","3","1"},charArgs={'1','2','3','1'})
503: public void annotatedMixedArgs2(@SuppressWarnings("unused")
504: final InvocationTypes type, final String[] strArgs,
505: final char[] charArgs1) {
506: assertEquals("1", strArgs[0]);
507: assertEquals("2", strArgs[1]);
508: assertEquals("3", strArgs[2]);
509: assertEquals("1", strArgs[3]);
510: assertEquals('1', charArgs1[0]);
511: assertEquals('2', charArgs1[1]);
512: assertEquals('3', charArgs1[2]);
513: assertEquals('1', charArgs1[3]);
514: nbrAnnotatedMethodsSuccessfullyExcecuted++;
515: }
516:
517: @Duplicate(stringArgs={"1","2","3","1"},booleanArgs={true,false,false,true})
518: public void annotatedMixedArgs3(@SuppressWarnings("unused")
519: final InvocationTypes type, final String[] strArgs,
520: final boolean[] booleanArgs1) {
521: assertTrue(booleanArgs1[0]);
522: assertFalse(booleanArgs1[1]);
523: assertFalse(booleanArgs1[2]);
524: assertTrue(booleanArgs1[3]);
525: assertEquals("1", strArgs[0]);
526: assertEquals("2", strArgs[1]);
527: assertEquals("3", strArgs[2]);
528: assertEquals("1", strArgs[3]);
529: nbrAnnotatedMethodsSuccessfullyExcecuted++;
530: }
531:
532: @Duplicate(intArgs={1,2,3,1},charArgs={'1','2','3','1'})
533: public void annotatedMixedArgs4(@SuppressWarnings("unused")
534: final InvocationTypes type, @SuppressWarnings("hiding")
535: final int[] intArgs1, final char[] charArgs1) {
536: assertEquals('1', charArgs1[0]);
537: assertEquals('2', charArgs1[1]);
538: assertEquals('3', charArgs1[2]);
539: assertEquals('1', charArgs1[3]);
540: assertEquals(1, intArgs1[0]);
541: assertEquals(2, intArgs1[1]);
542: assertEquals(3, intArgs1[2]);
543: assertEquals(1, intArgs1[3]);
544: nbrAnnotatedMethodsSuccessfullyExcecuted++;
545: }
546:
547: @Duplicate(intArgs={1,2,3,1},booleanArgs={true,false,false,true})
548: public void annotatedMixedArgs5(@SuppressWarnings("unused")
549: final InvocationTypes type, final int[] intArgs1,
550: final boolean[] booleanArgs1) {
551: assertTrue(booleanArgs1[0]);
552: assertFalse(booleanArgs1[1]);
553: assertFalse(booleanArgs1[2]);
554: assertTrue(booleanArgs1[3]);
555: assertEquals(1, intArgs1[0]);
556: assertEquals(2, intArgs1[1]);
557: assertEquals(3, intArgs1[2]);
558: assertEquals(1, intArgs1[3]);
559: nbrAnnotatedMethodsSuccessfullyExcecuted++;
560: }
561:
562: @Duplicate(charArgs={'1','2','3','1'},booleanArgs={true,false,false,true})
563: public void annotatedMixedArgs6(@SuppressWarnings("unused")
564: final InvocationTypes type, final char[] charArgs1,
565: final boolean[] booleanArgs1) {
566: assertTrue(booleanArgs1[0]);
567: assertFalse(booleanArgs1[1]);
568: assertFalse(booleanArgs1[2]);
569: assertTrue(booleanArgs1[3]);
570: assertEquals('1', charArgs1[0]);
571: assertEquals('2', charArgs1[1]);
572: assertEquals('3', charArgs1[2]);
573: assertEquals('1', charArgs1[3]);
574: nbrAnnotatedMethodsSuccessfullyExcecuted++;
575: }
576:
577: @Duplicate(stringArgs={"1","2","3","1"},intArgs={1,2,3,1},charArgs={'1','2','3','1'})
578: public void annotatedMixedArgs7(@SuppressWarnings("unused")
579: final InvocationTypes type, final String[] strArgs,
580: final int[] intArgs1, final char[] charArgs1) {
581: assertEquals("1", strArgs[0]);
582: assertEquals("2", strArgs[1]);
583: assertEquals("3", strArgs[2]);
584: assertEquals("1", strArgs[3]);
585: assertEquals(1, intArgs1[0]);
586: assertEquals(2, intArgs1[1]);
587: assertEquals(3, intArgs1[2]);
588: assertEquals(1, intArgs1[3]);
589: assertEquals('1', charArgs1[0]);
590: assertEquals('2', charArgs1[1]);
591: assertEquals('3', charArgs1[2]);
592: assertEquals('1', charArgs1[3]);
593: nbrAnnotatedMethodsSuccessfullyExcecuted++;
594: }
595:
596: @Duplicate(stringArgs={"1","2","3","1"},intArgs={1,2,3,1},booleanArgs={true,false,false,true})
597: public void annotatedMixedArgs8(@SuppressWarnings("unused")
598: final InvocationTypes type, final String[] strArgs,
599: final int[] intArgs1, final boolean[] booleanArgs1) {
600: assertTrue(booleanArgs1[0]);
601: assertFalse(booleanArgs1[1]);
602: assertFalse(booleanArgs1[2]);
603: assertTrue(booleanArgs1[3]);
604: assertEquals("1", strArgs[0]);
605: assertEquals("2", strArgs[1]);
606: assertEquals("3", strArgs[2]);
607: assertEquals("1", strArgs[3]);
608: assertEquals(1, intArgs1[0]);
609: assertEquals(2, intArgs1[1]);
610: assertEquals(3, intArgs1[2]);
611: assertEquals(1, intArgs1[3]);
612: nbrAnnotatedMethodsSuccessfullyExcecuted++;
613: }
614:
615: @Duplicate(stringArgs={"1","2","3","1"},charArgs={'1','2','3','1'},booleanArgs={true,false,false,true})
616: public void annotatedMixedArgs9(@SuppressWarnings("unused")
617: final InvocationTypes type, final String[] strArgs,
618: final char[] charArgs1, final boolean[] booleanArgs1) {
619: assertTrue(booleanArgs1[0]);
620: assertFalse(booleanArgs1[1]);
621: assertFalse(booleanArgs1[2]);
622: assertTrue(booleanArgs1[3]);
623: assertEquals("1", strArgs[0]);
624: assertEquals("2", strArgs[1]);
625: assertEquals("3", strArgs[2]);
626: assertEquals("1", strArgs[3]);
627: assertEquals('1', charArgs1[0]);
628: assertEquals('2', charArgs1[1]);
629: assertEquals('3', charArgs1[2]);
630: assertEquals('1', charArgs1[3]);
631: nbrAnnotatedMethodsSuccessfullyExcecuted++;
632: }
633:
634: @Duplicate(invocationTypes={InvocationTypes.Async},intArgs={1,2,3,1},charArgs={'1','2','3','1'},booleanArgs={true,false,false,true})
635: public void annotatedMixedArgs10(final InvocationTypes type,
636: final int[] intArgs1, final char[] charArgs1,
637: final boolean[] booleanArgs1) {
638: assertEquals(InvocationTypes.Async, type);
639: assertTrue(booleanArgs1[0]);
640: assertFalse(booleanArgs1[1]);
641: assertFalse(booleanArgs1[2]);
642: assertTrue(booleanArgs1[3]);
643: assertEquals('1', charArgs1[0]);
644: assertEquals('2', charArgs1[1]);
645: assertEquals('3', charArgs1[2]);
646: assertEquals('1', charArgs1[3]);
647: assertEquals(1, intArgs1[0]);
648: assertEquals(2, intArgs1[1]);
649: assertEquals(3, intArgs1[2]);
650: assertEquals(1, intArgs1[3]);
651: nbrAnnotatedMethodsSuccessfullyExcecuted++;
652: }
653:
654: @Duplicate(invocationTypes={InvocationTypes.Sync},stringArgs={"1","2","3","1"},intArgs={1,2,3,1},charArgs={'1','2','3','1'},booleanArgs={true,false,false,true})
655: public void annotatedAllArgs(final InvocationTypes type,
656: final String[] strArgs, final int[] intArgs1,
657: final char[] charArgs1, final boolean[] booleanArgs1) {
658: assertEquals(InvocationTypes.Sync, type);
659: assertTrue(booleanArgs1[0]);
660: assertFalse(booleanArgs1[1]);
661: assertFalse(booleanArgs1[2]);
662: assertTrue(booleanArgs1[3]);
663: assertEquals("1", strArgs[0]);
664: assertEquals("2", strArgs[1]);
665: assertEquals("3", strArgs[2]);
666: assertEquals("1", strArgs[3]);
667: assertEquals('1', charArgs1[0]);
668: assertEquals('2', charArgs1[1]);
669: assertEquals('3', charArgs1[2]);
670: assertEquals('1', charArgs1[3]);
671: assertEquals(1, intArgs1[0]);
672: assertEquals(2, intArgs1[1]);
673: assertEquals(3, intArgs1[2]);
674: assertEquals(1, intArgs1[3]);
675: nbrAnnotatedMethodsSuccessfullyExcecuted++;
676: }
677:
678: @TestingExternalAPI({"First API","Second API"})
679: private static class ClassWithTestingApiAnnotation {
680: // no methods
681: }
682:
683: @Author(name="Klaus P. Berg",mailTo="Klaus-Peter.berg@web.de")
684: @TestingExternalAPI({"First API","Second API"})
685: private static class ClassWithMultipleClassLevelAnnotations {
686: // no methods
687: }
688:
689: // This class has NO class level annotations!
690: private static class ClassWithMultipleMethodLevelAnnotations {
691:
692: @Ignore(initials="KPB")
693: public void method1() {
694: // no code necessary
695: }
696:
697: @Ignore(initials="KPB")
698: @Duplicate(invocationTypes={InvocationTypes.Sync},stringArgs={"1","2","3","1"},intArgs={1,2,3,1},charArgs={'1','2','3','1'},booleanArgs={true,false,false,true})
699: public void method2(final InvocationTypes type,
700: final String[] strArgs, final int[] intArgs1,
701: final char[] charArgs1, final boolean[] booleanArgs1) {
702: assertEquals(InvocationTypes.Sync, type);
703: assertTrue(booleanArgs1[0]);
704: assertFalse(booleanArgs1[1]);
705: assertFalse(booleanArgs1[2]);
706: assertTrue(booleanArgs1[3]);
707: assertEquals("1", strArgs[0]);
708: assertEquals("2", strArgs[1]);
709: assertEquals("3", strArgs[2]);
710: assertEquals("1", strArgs[3]);
711: assertEquals('1', charArgs1[0]);
712: assertEquals('2', charArgs1[1]);
713: assertEquals('3', charArgs1[2]);
714: assertEquals('1', charArgs1[3]);
715: assertEquals(1, intArgs1[0]);
716: assertEquals(2, intArgs1[1]);
717: assertEquals(3, intArgs1[2]);
718: assertEquals(1, intArgs1[3]);
719: }
720: }
721:
722: // This class has no class level annotations and the method annotations have default values only
723: private static class ClassWithDefaultMethodLevelAnnotationsOnly {
724:
725: @Duplicate
726: public void testMethod1(final InvocationTypes type) {
727: assertTrue(type.equals(InvocationTypes.Async)
728: || type.equals(InvocationTypes.Sync));
729: }
730:
731: @Duplicate
732: public void testMethod2(final InvocationTypes type) {
733: assertTrue(type.equals(InvocationTypes.Async)
734: || type.equals(InvocationTypes.Sync));
735: }
736: }
737:
738: ///////////////////////////////////////////////////////////////////////////////
739:
740: /* Annotation classes */
741:
742: /**
743: * Author name annotation.
744: *
745: * @author Klaus Berg
746: */
747:
748: @Documented
749: @Target(ElementType.TYPE)
750: @Retention(RetentionPolicy.RUNTIME)
751: @interface Author {
752: /** the responsible author's name */
753: String name();
754:
755: /** the responsible author's mail address */
756: String mailTo();
757: }
758:
759: /**
760: * Duplicate annotation specifies that a particular test case will be duplicated for each
761: * parameter type specified. Primarily, this annotation can be used to mark
762: * tests that should be invoked in sync & async mode. But the same annotation
763: * can also be used to provide additional arguments of type String, int, char,
764: * and boolean to a test method. In general, these arguments will be used to
765: * specify 'invalid' input arguments specific to a test method.
766: *
767: * @author Klaus Berg, Mike Stone
768: */
769: @Documented
770: @Target(ElementType.METHOD)
771: @Retention(RetentionPolicy.RUNTIME)
772: @interface Duplicate {
773: /** the test method invocation type(s) */
774: InvocationTypes[] invocationTypes() default {
775: InvocationTypes.Async, InvocationTypes.Sync };
776:
777: /** invalid String args handed over as method parameters */
778: String[] stringArgs() default {};
779:
780: /** invalid int args handed over as method parameters */
781: int[] intArgs() default {};
782:
783: /** invalid char args handed over as method parameters */
784: char[] charArgs() default {};
785:
786: /** invalid boolean args handed over as method parameters */
787: boolean[] booleanArgs() default {};
788: }
789:
790: /**
791: * Ignore functional test annotation.
792: *
793: * @author Klaus Berg
794: */
795: @Documented
796: @Target(ElementType.METHOD)
797: @Retention(RetentionPolicy.RUNTIME)
798: @interface Ignore {
799: /** the reasons why a test method should be ignored */
800: String[] reasons() default { "test under construction" };
801:
802: /** the initials of the person who decided that the test method should be ignored */
803: String initials();
804: }
805:
806: /**
807: * Test method invocation types.
808: *
809: * @author Klaus P. Berg
810: */
811: enum InvocationTypes {
812: Sync, /**
813: * Specifies a synchronous duplicated test.
814: */
815: Async
816: /** Specifies an asynchronous duplicated test. */
817: }
818:
819: /**
820: * Declare external API classes that should be tested.
821: *
822: * @author Klaus Berg
823: */
824:
825: @Documented
826: @Target(ElementType.TYPE)
827: @Retention(RetentionPolicy.RUNTIME)
828: @interface TestingExternalAPI {
829: /** A list of all 'external interfaces' tested by the annotated class */
830: String[] value() default { "" };
831: }
832: }
|