001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.i3test;
028:
029: import com.sun.midp.security.SecurityInitializer;
030: import com.sun.midp.security.SecurityToken;
031: import com.sun.midp.security.ImplicitlyTrustedClass;
032:
033: /**
034: * The main class for writing integrated internal interface (i3) tests. Tests
035: * should create a subclass of TestCase and implement the runTests() method.
036: * This method is responsible for running all of the tests. Tests consist of
037: * a test declaration followed by one or more assertions. The declaration is
038: * a call to the declare() method, which simply establishes a name for the set
039: * of assertions to follow. The assertions are made through calls to the
040: * assert*() family of methods. The framework considers it an error if any
041: * assertions are made prior to a call to declare(), or if there is a call to
042: * declare() with no subsequent calls to assert().
043: *
044: * <p>The TestCase class and its assert() methods are loosely based on the
045: * JUnit TestCase class. JUnit uses reflection to find test methods. Since
046: * reflection isn't present in CLDC, we need to have a runTests() method that
047: * calls them explicitly.
048: *
049: * <p>JUnit, in contrast to other test frameworks, doesn't return a result
050: * from each test. Instead, each test simply makes assertions, and only
051: * assertions that fail are flagged. The i3 tests follow the JUnit approach.
052: * For this reason, there is no pass() method one might expect to see
053: * corresponding to the fail() method.
054: *
055: * <p>While it's not a requirement, it's conventional for the TestCase
056: * subclass to reside in the same package as the code under test. This will
057: * allow the tests access to package-private variables and methods.
058: *
059: * <p>Each of the different assert() calls has an optional
060: * <code>message</code> parameter. This message is emitted only when the
061: * assertion fails and should be written with this in mind.
062: *
063: * <p>For "negative tests" that require an exception to be thrown, a suggested
064: * style is to record the fact that the correct exception was thrown in a
065: * boolean variable. This variable can then be tested using one of the
066: * assert() calls. This is probably preferable to placing calls to fail() in
067: * the midst of the test method. See testThree() in the example below.
068: *
069: * <p>The framework will catch any Throwable thrown by the tests and will log
070: * a message and count the occurrence as an error. This allows tests to be
071: * written more simply, because they can rely on the framework to catch
072: * everything. In support of this, the runTests() method has been defined with
073: * a 'throws Throwable' clause.
074: *
075: * <p>A general rule is that tests should run independently of each other.
076: * That is, tests should not leave any side effects that other tests rely on
077: * or that could cause them to fail. Typically, tests should create fresh
078: * objects for testing instead of reusing objects from other tests. If a test
079: * has any external side effects, such as creating threads or opening files,
080: * the test should be coded with a 'finally' clause that attempts to clean up
081: * after itself. See testFour() in the example below.
082: *
083: * <p>Example:
084: * <pre><code>
085: * import com.sun.midp.i3test;
086: * package java.lang;
087: *
088: * public class SampleTest extends TestCase {
089: * void testOne() {
090: * int i = 1 + 1;
091: * assertEquals("integer addition failed", 2, i);
092: * }
093: *
094: * void testTwo() {
095: * Object x = new Object();
096: * assertNotNull("Object constructor returned null", x);
097: * }
098: *
099: * void testThree() {
100: * StringBuffer sb;
101: * boolean caught = false;
102: * try {
103: * sb = new StringBuffer(-1);
104: * } catch (NegativeArraySizeException e) {
105: * caught = true;
106: * }
107: * assertTrue("no exception thrown", caught);
108: * }
109: *
110: * void testFour() {
111: * Thread thr = new Thread(...).start();
112: * try {
113: * // ...
114: * } finally {
115: * thr.interrupt();
116: * }
117: * }
118: *
119: * public void runTests() {
120: * declare("testOne");
121: * testOne();
122: * declare("testTwo");
123: * testTwo();
124: * declare("testThree");
125: * testThree();
126: * declare("testFour");
127: * testFour();
128: * }
129: * }
130: * </code></pre>
131: */
132: public abstract class TestCase {
133:
134: // the lone constructor
135:
136: /**
137: * Constructs a TestCase. Since TestCase is an abstract class, this
138: * constructor is called only at the time a TestCase subclass is being
139: * constructed.
140: */
141: public TestCase() {
142: if (verbose) {
143: p("## TestCase " + this .getClass().getName());
144: }
145: currentTestCase = this ;
146: currentTest = null;
147: totalCases++;
148: currentNumAsserts = 0;
149: }
150:
151: // ==================== public methods ====================
152:
153: /**
154: * Runs all the tests for this TestCase. This is an abstract method that
155: * must be implemented by the subclass. The implementation of this method
156: * should run all of the tests provided in this TestCase. This method can
157: * also be used to initialize and tear down any state that might need to
158: * be shared among all the tests.
159: *
160: * <p>A suggested organization is to have runTests() alternate calling
161: * declare() and an internal method that implements the test. One could
162: * write the declare() method as part of the internal test method, but
163: * consolidating all calls in runTests() makes it a little easier to
164: * ensure that each test has its own call to declare(). See the example
165: * in the class documentation.
166: */
167: public abstract void runTests() throws Throwable;
168:
169: /**
170: * Declares that the set of assertions that follow this call belong to a
171: * test named <code>testName</code>. The framework considers it an error
172: * if no calls to any of the assert() methods follow a call to declare().
173: *
174: * @param testName the name of the test
175: */
176: public void declare(String testName) {
177: if (testName == null) {
178: throw new NullPointerException("test name is null");
179: }
180:
181: if (verbose) {
182: p("## test " + testName);
183: }
184:
185: if (currentNumAsserts == 0 && currentTest != null) {
186: p("ERROR no asserts in test case " + currentTestCaseName()
187: + " test " + currentTest);
188: errorTestWithoutAssert++;
189: }
190:
191: currentTest = testName;
192: totalTests++;
193: currentNumAsserts = 0;
194: }
195:
196: /**
197: * Tests the assertion that the boolean <code>condition</code> is true.
198: * If the condition is true, this method simply updates some statistics
199: * and returns. If the condition is false, the failure is noted and the
200: * message is emitted, along with an indication of the current TestCase
201: * and the name of the test currently being run. The
202: * <code>message</code> string should be phrased in a way that makes sense
203: * when the test fails. See the example in the class documentation.
204: *
205: * @param message the message to be emitted if the assertion fails
206: * @param condition the condition asserted to be true
207: */
208: public void assertTrue(String message, boolean condition) {
209: if (currentTest == null) {
210: p("ERROR assert \"" + message + "\" not part of any test");
211: errorAssertWithoutTest++;
212: return;
213: }
214:
215: currentNumAsserts++;
216: totalAsserts++;
217:
218: if (verbose) {
219: p("## " + totalAsserts + ": " + message);
220: }
221:
222: if (!condition) {
223: totalFailures++;
224: String m = "FAIL " + currentTestCaseName();
225: if (currentTest != null) {
226: m += "#" + currentTest;
227: }
228: if (message != null) {
229: m += ": " + message;
230: }
231: p(m);
232: }
233: }
234:
235: /**
236: * Asserts that <code>condition</code> is true.
237: *
238: * @param condition the condition to be tested
239: */
240: public void assertTrue(boolean condition) {
241: assertTrue(null, condition);
242: }
243:
244: /**
245: * Asserts that two objects are equal according to the equals() method.
246: *
247: * @param expected an object containing the expected value
248: * @param actual an object containing the actual value
249: */
250: public void assertEquals(Object expected, Object actual) {
251: assertEquals(null, expected, actual);
252: }
253:
254: /**
255: * Asserts that two objects are equal according to the equals() method.
256: * Two null references are considered to be equal.
257: *
258: * @param message the message to be emitted if the assertion fails
259: * @param expected an object containing the expected value
260: * @param actual an object containing the actual value
261: */
262: public void assertEquals(String message, Object expected,
263: Object actual) {
264: boolean isequal = (expected == actual);
265:
266: // If references aren't identical, call equals() only when
267: // both references are non-null.
268:
269: if (!isequal && expected != null && actual != null) {
270: isequal = expected.equals(actual);
271: }
272: assertTrue(message, isequal);
273: if (!isequal) {
274: p(" expected: " + expected + "; actual: " + actual);
275: }
276: }
277:
278: /**
279: * Asserts that two integer values are equal.
280: *
281: * @param expected the expected value
282: * @param actual the actual value
283: */
284: public void assertEquals(int expected, int actual) {
285: assertEquals(null, expected, actual);
286: }
287:
288: /**
289: * Asserts that two integer values are equal.
290: *
291: * @param message the message to be emitted if the assertion fails
292: * @param expected the expected value
293: * @param actual the actual value
294: */
295: public void assertEquals(String message, int expected, int actual) {
296: assertTrue(message, expected == actual);
297: if (expected != actual) {
298: p(" expected: " + expected + "; actual: " + actual);
299: }
300: }
301:
302: /**
303: * Asserts that <code>condition</code> is false.
304: *
305: * @param condition the condition asserted to be false
306: */
307: public void assertFalse(boolean condition) {
308: assertTrue(null, !condition);
309: }
310:
311: /**
312: * Asserts that <code>condition</code> is false.
313: *
314: * @param message the message to be emitted if the assertion fails
315: * @param condition the condition asserted to be false
316: */
317: public void assertFalse(String message, boolean condition) {
318: assertTrue(message, !condition);
319: }
320:
321: /**
322: * Asserts that the object reference is not null.
323: *
324: * @param object the reference to be tested
325: */
326: public void assertNotNull(Object object) {
327: assertTrue(null, object != null);
328: }
329:
330: /**
331: * Asserts that the object reference is not null.
332: *
333: * @param message the message to be emitted if the assertion fails
334: * @param object the reference to be tested
335: */
336: public void assertNotNull(String message, Object object) {
337: assertTrue(message, object != null);
338: }
339:
340: /**
341: * Asserts that two references do not point to the same object,
342: * using the == operator.
343: *
344: * @param expected a reference to the expected object
345: * @param actual a reference to the actual object
346: */
347: public void assertNotSame(Object expected, Object actual) {
348: assertNotSame(null, expected, actual);
349: }
350:
351: /**
352: * Asserts that two references do not point to the same object,
353: * using the == operator.
354: *
355: * @param message the message to be emitted if the assertion fails
356: * @param expected a reference to the expected object
357: * @param actual a reference to the actual object
358: */
359: public void assertNotSame(String message, Object expected,
360: Object actual) {
361: assertTrue(message, expected != actual);
362: if (expected == actual) {
363: p(" expected: " + expected + "; actual: " + actual);
364: }
365: }
366:
367: /**
368: * Asserts that the object reference is null.
369: *
370: * @param object the reference to be tested
371: */
372: public void assertNull(Object object) {
373: assertNull(null, object);
374: }
375:
376: /**
377: * Asserts that the object reference is null.
378: *
379: * @param message the message to be emitted if the assertion fails
380: * @param object the reference to be tested
381: */
382: public void assertNull(String message, Object object) {
383: assertTrue(message, object == null);
384: if (object != null) {
385: p(" actual: " + object);
386: }
387: }
388:
389: /**
390: * Asserts that two references point to the same object, using the
391: * == operator.
392: *
393: * @param expected a reference to the expected object
394: * @param actual a reference to the actual object
395: */
396: public void assertSame(Object expected, Object actual) {
397: assertSame(null, expected, actual);
398: }
399:
400: /**
401: * Asserts that two references point to the same object, using the
402: * == operator.
403: *
404: * @param message the message to be emitted if the assertion fails
405: * @param expected a reference to the expected object
406: * @param actual a reference to the actual object
407: */
408: public void assertSame(String message, Object expected,
409: Object actual) {
410: assertTrue(message, expected == actual);
411: if (expected != actual) {
412: p(" expected: " + expected + "; actual: " + actual);
413: }
414: }
415:
416: /**
417: * Signals an unconditional assertion failure.
418: */
419: public void fail() {
420: assertTrue(null, false);
421: }
422:
423: /**
424: * Signals an unconditional assertion failure.
425: *
426: * @param message the message to be emitted, explaining the failure
427: */
428: public void fail(String message) {
429: assertTrue(message, false);
430: }
431:
432: /**
433: * Gets the system's internal security token. This is useful for testing
434: * sensitive interfaces that require a security token parameter. This
435: * returns a valid security token only when called within the context of a
436: * call to runTests() inside a TestCase. At other times it will throw a
437: * SecurityException.
438: *
439: * @return the internal security token
440: * @throws SecurityException if not called from within runTests()
441: */
442: protected SecurityToken getSecurityToken() {
443: if (tokenEnabled) {
444: return internalSecurityToken;
445: } else {
446: throw new SecurityException();
447: }
448: }
449:
450: // ==================== static variables ====================
451:
452: static boolean verbose = false;
453:
454: static private class SecurityTrusted implements
455: ImplicitlyTrustedClass {
456: };
457:
458: private static SecurityToken internalSecurityToken = SecurityInitializer
459: .requestToken(new SecurityTrusted());
460:
461: static boolean tokenEnabled = false;
462:
463: // general statistics
464:
465: static int totalCases = 0; // total number of test cases
466: static int totalTests = 0; // total number of tests declared
467: static int totalAsserts = 0; // total number of asserts called
468: static int totalFailures = 0; // total number of assertion failures
469:
470: // error counts
471:
472: static int errorClassNotFound = 0;
473: static int errorConstructorException = 0;
474: static int errorNotTestCase = 0;
475: static int errorTestRunThrows = 0;
476: static int errorNoTests = 0;
477: static int errorAssertWithoutTest = 0;
478: static int errorTestWithoutAssert = 0;
479:
480: // state information about the currently running test
481:
482: static TestCase currentTestCase;
483: static String currentTest;
484: static int currentNumAsserts;
485:
486: // ==================== static implementation ====================
487:
488: /**
489: * Run the named test case.
490: * @param testCaseName the class name of the test case
491: */
492: static void runTestCase(String testCaseName) {
493: Class clazz;
494: Object obj;
495: TestCase tc;
496:
497: if (verbose) {
498: System.out.println("## running test case " + testCaseName);
499: }
500:
501: try {
502: clazz = Class.forName(testCaseName);
503: } catch (ClassNotFoundException cnfe) {
504: System.out.println("ERROR test class " + testCaseName
505: + " not found");
506: errorClassNotFound++;
507: return;
508: }
509:
510: try {
511: obj = clazz.newInstance();
512: } catch (Throwable t) {
513: System.out.println("ERROR test class " + testCaseName
514: + " constructor threw " + t);
515: errorConstructorException++;
516: return;
517: }
518:
519: try {
520: tc = (TestCase) obj;
521: } catch (ClassCastException cce) {
522: System.out.println("ERROR test class " + testCaseName
523: + " not a subclass of TestCase");
524: errorNotTestCase++;
525: return;
526: }
527:
528: try {
529: tokenEnabled = true;
530: tc.runTests();
531: } catch (Throwable t) {
532: String m = "ERROR " + currentTestCaseName();
533: if (currentTest != null) {
534: m += "#" + currentTest;
535: }
536: m += " threw " + t;
537: p(m);
538: t.printStackTrace();
539: errorTestRunThrows++;
540: }
541:
542: tokenEnabled = false;
543: cleanup();
544: }
545:
546: /**
547: * Return the name of the current test case.
548: * @return the name of the class for the current test case.
549: */
550: static String currentTestCaseName() {
551: return currentTestCase.getClass().getName();
552: }
553:
554: /**
555: * Cleanup after running a test.
556: */
557: static void cleanup() {
558: if (currentTest == null) {
559: p("ERROR " + currentTestCaseName() + " has no tests");
560: errorNoTests++;
561: } else if (currentNumAsserts == 0) {
562: p("ERROR no asserts in test case " + currentTestCaseName()
563: + " test " + currentTest);
564: errorTestWithoutAssert++;
565: }
566:
567: currentTestCase = null;
568: currentTest = null;
569: }
570:
571: /**
572: * Set the verbose output flag.
573: * @param v true to enable verbose output
574: */
575: static void setVerbose(boolean v) {
576: verbose = v;
577: }
578:
579: /**
580: * Print the string.
581: * @param s the string to print on a new line.
582: */
583: static void p(String s) {
584: System.out.println(s);
585: }
586:
587: /**
588: * Print the number of errors with the category.
589: * @param nerr the number of errors in the category
590: * @param errstr the description of the errors
591: */
592: static void perror(int nerr, String errstr) {
593: if (nerr != 0) {
594: System.out.println(" " + nerr + " " + errstr);
595: }
596: }
597:
598: // print out a report of all statistics
599:
600: static void report() {
601: System.out.print("Test run complete: ");
602: System.out.print(totalCases
603: + (totalCases == 1 ? " testcase " : " testcases "));
604: System.out.print(totalTests
605: + (totalTests == 1 ? " test " : " tests "));
606: System.out.println(totalAsserts
607: + (totalAsserts == 1 ? " assertion" : " assertions"));
608:
609: if (totalFailures != 0) {
610: System.out.println(totalFailures
611: + (totalFailures == 1 ? " FAILURE!!!"
612: : " FAILURES!!!"));
613: }
614:
615: int totalErrors = errorClassNotFound + errorNotTestCase
616: + errorConstructorException + errorTestRunThrows
617: + errorNoTests + errorAssertWithoutTest
618: + errorTestWithoutAssert;
619:
620: if (totalErrors != 0) {
621: System.out.println(totalErrors
622: + (totalErrors == 1 ? " ERROR!!!" : " ERRORS!!!"));
623: perror(errorClassNotFound, "test class not found");
624: perror(errorConstructorException,
625: "constructor threw exception");
626: perror(errorNotTestCase, "class not subclass of TestCase");
627: perror(errorTestRunThrows, "test run threw exception");
628: perror(errorNoTests, "no tests declared");
629: perror(errorAssertWithoutTest,
630: "asserts outside of any test");
631: perror(errorTestWithoutAssert, "tests with no asserts");
632: }
633: }
634:
635: /**
636: * Reset the counters of all errors and exceptions.
637: */
638: static void reset() {
639: totalCases = 0;
640: totalTests = 0;
641: totalAsserts = 0;
642: totalFailures = 0;
643: currentNumAsserts = 0;
644:
645: errorClassNotFound = 0;
646: errorConstructorException = 0;
647: errorNotTestCase = 0;
648: errorTestRunThrows = 0;
649: errorNoTests = 0;
650: errorAssertWithoutTest = 0;
651: errorTestWithoutAssert = 0;
652: }
653:
654: /**
655: * If in verbose mode, print information.
656: */
657: public void info(String s) {
658: if (verbose) {
659: p(".# " + s);
660: }
661: }
662:
663: /**
664: * Reads the verbose flag.
665: * @return true if in verbose mode
666: */
667: protected boolean getVerbose() {
668: return verbose;
669: }
670: }
|