diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | fdb2704414a9ed92394ada0d1395e4db86889465 (patch) | |
tree | 9b591a4a50054274a197f02b3ccb51313681879f /junit | |
download | libcore-fdb2704414a9ed92394ada0d1395e4db86889465.zip libcore-fdb2704414a9ed92394ada0d1395e4db86889465.tar.gz libcore-fdb2704414a9ed92394ada0d1395e4db86889465.tar.bz2 |
Initial Contribution
Diffstat (limited to 'junit')
18 files changed, 1341 insertions, 0 deletions
diff --git a/junit/MODULE_LICENSE_CPL b/junit/MODULE_LICENSE_CPL new file mode 100644 index 0000000..541dbb5 --- /dev/null +++ b/junit/MODULE_LICENSE_CPL @@ -0,0 +1 @@ +http://www.opensource.org/licenses/cpl1.0.php diff --git a/junit/src/main/java/junit/extensions/ActiveTestSuite.java b/junit/src/main/java/junit/extensions/ActiveTestSuite.java new file mode 100644 index 0000000..073e6f3 --- /dev/null +++ b/junit/src/main/java/junit/extensions/ActiveTestSuite.java @@ -0,0 +1,64 @@ +package junit.extensions; + +import junit.framework.*; + +/** + * A TestSuite for active Tests. It runs each + * test in a separate thread and waits until all + * threads have terminated. + * -- Aarhus Radisson Scandinavian Center 11th floor + */ +public class ActiveTestSuite extends TestSuite { + private volatile int fActiveTestDeathCount; + + public ActiveTestSuite() { + } + + public ActiveTestSuite(Class theClass) { + super(theClass); + } + + public ActiveTestSuite(String name) { + super (name); + } + + public ActiveTestSuite(Class theClass, String name) { + super(theClass, name); + } + + public void run(TestResult result) { + fActiveTestDeathCount= 0; + super.run(result); + waitUntilFinished(); + } + + public void runTest(final Test test, final TestResult result) { + Thread t= new Thread() { + public void run() { + try { + // inlined due to limitation in VA/Java + //ActiveTestSuite.super.runTest(test, result); + test.run(result); + } finally { + ActiveTestSuite.this.runFinished(test); + } + } + }; + t.start(); + } + + synchronized void waitUntilFinished() { + while (fActiveTestDeathCount < testCount()) { + try { + wait(); + } catch (InterruptedException e) { + return; // ignore + } + } + } + + synchronized public void runFinished(Test test) { + fActiveTestDeathCount++; + notifyAll(); + } +} diff --git a/junit/src/main/java/junit/extensions/ExceptionTestCase.java b/junit/src/main/java/junit/extensions/ExceptionTestCase.java new file mode 100644 index 0000000..de64b5b --- /dev/null +++ b/junit/src/main/java/junit/extensions/ExceptionTestCase.java @@ -0,0 +1,46 @@ +package junit.extensions; + +import junit.framework.*; + +/** + * A TestCase that expects an Exception of class fExpected to be thrown. + * The other way to check that an expected exception is thrown is: + * <pre> + * try { + * shouldThrow(); + * } + * catch (SpecialException e) { + * return; + * } + * fail("Expected SpecialException"); + * </pre> + * + * To use ExceptionTestCase, create a TestCase like: + * <pre> + * new ExceptionTestCase("testShouldThrow", SpecialException.class); + * </pre> + */ +public class ExceptionTestCase extends TestCase { + Class fExpected; + + public ExceptionTestCase(String name, Class exception) { + super(name); + fExpected= exception; + } + /** + * Execute the test method expecting that an Exception of + * class fExpected or one of its subclasses will be thrown + */ + protected void runTest() throws Throwable { + try { + super.runTest(); + } + catch (Exception e) { + if (fExpected.isAssignableFrom(e.getClass())) + return; + else + throw e; + } + fail("Expected exception " + fExpected); + } +} diff --git a/junit/src/main/java/junit/extensions/RepeatedTest.java b/junit/src/main/java/junit/extensions/RepeatedTest.java new file mode 100644 index 0000000..34f2541 --- /dev/null +++ b/junit/src/main/java/junit/extensions/RepeatedTest.java @@ -0,0 +1,31 @@ +package junit.extensions; + +import junit.framework.*; + +/** + * A Decorator that runs a test repeatedly. + * + */ +public class RepeatedTest extends TestDecorator { + private int fTimesRepeat; + + public RepeatedTest(Test test, int repeat) { + super(test); + if (repeat < 0) + throw new IllegalArgumentException("Repetition count must be > 0"); + fTimesRepeat= repeat; + } + public int countTestCases() { + return super.countTestCases()*fTimesRepeat; + } + public void run(TestResult result) { + for (int i= 0; i < fTimesRepeat; i++) { + if (result.shouldStop()) + break; + super.run(result); + } + } + public String toString() { + return super.toString()+"(repeated)"; + } +} diff --git a/junit/src/main/java/junit/extensions/TestDecorator.java b/junit/src/main/java/junit/extensions/TestDecorator.java new file mode 100644 index 0000000..6b5144a --- /dev/null +++ b/junit/src/main/java/junit/extensions/TestDecorator.java @@ -0,0 +1,38 @@ +package junit.extensions; + +import junit.framework.*; + +/** + * A Decorator for Tests. Use TestDecorator as the base class + * for defining new test decorators. Test decorator subclasses + * can be introduced to add behaviour before or after a test + * is run. + * + */ +public class TestDecorator extends Assert implements Test { + protected Test fTest; + + public TestDecorator(Test test) { + fTest= test; + } + /** + * The basic run behaviour. + */ + public void basicRun(TestResult result) { + fTest.run(result); + } + public int countTestCases() { + return fTest.countTestCases(); + } + public void run(TestResult result) { + basicRun(result); + } + + public String toString() { + return fTest.toString(); + } + + public Test getTest() { + return fTest; + } +} diff --git a/junit/src/main/java/junit/extensions/TestSetup.java b/junit/src/main/java/junit/extensions/TestSetup.java new file mode 100644 index 0000000..3651501 --- /dev/null +++ b/junit/src/main/java/junit/extensions/TestSetup.java @@ -0,0 +1,37 @@ +package junit.extensions; + +import junit.framework.*; + +/** + * A Decorator to set up and tear down additional fixture state. + * Subclass TestSetup and insert it into your tests when you want + * to set up additional state once before the tests are run. + */ +public class TestSetup extends TestDecorator { + + public TestSetup(Test test) { + super(test); + } + public void run(final TestResult result) { + Protectable p= new Protectable() { + public void protect() throws Exception { + setUp(); + basicRun(result); + tearDown(); + } + }; + result.runProtected(this, p); + } + /** + * Sets up the fixture. Override to set up additional fixture + * state. + */ + protected void setUp() throws Exception { + } + /** + * Tears down the fixture. Override to tear down the additional + * fixture state. + */ + protected void tearDown() throws Exception { + } +} diff --git a/junit/src/main/java/junit/extensions/package.html b/junit/src/main/java/junit/extensions/package.html new file mode 100644 index 0000000..6b4be72 --- /dev/null +++ b/junit/src/main/java/junit/extensions/package.html @@ -0,0 +1,6 @@ +<HTML> +<BODY> +Utility classes supporting the junit test framework. +{@hide} - Not needed for 1.0 SDK +</BODY> +</HTML> diff --git a/junit/src/main/java/junit/framework/Assert.java b/junit/src/main/java/junit/framework/Assert.java new file mode 100644 index 0000000..c1bc7b2 --- /dev/null +++ b/junit/src/main/java/junit/framework/Assert.java @@ -0,0 +1,291 @@ +package junit.framework; + +/** + * A set of assert methods. Messages are only displayed when an assert fails. + */ + +public class Assert { + /** + * Protect constructor since it is a static only class + */ + protected Assert() { + } + + /** + * Asserts that a condition is true. If it isn't it throws + * an AssertionFailedError with the given message. + */ + static public void assertTrue(String message, boolean condition) { + if (!condition) + fail(message); + } + /** + * Asserts that a condition is true. If it isn't it throws + * an AssertionFailedError. + */ + static public void assertTrue(boolean condition) { + assertTrue(null, condition); + } + /** + * Asserts that a condition is false. If it isn't it throws + * an AssertionFailedError with the given message. + */ + static public void assertFalse(String message, boolean condition) { + assertTrue(message, !condition); + } + /** + * Asserts that a condition is false. If it isn't it throws + * an AssertionFailedError. + */ + static public void assertFalse(boolean condition) { + assertFalse(null, condition); + } + /** + * Fails a test with the given message. + */ + static public void fail(String message) { + throw new AssertionFailedError(message); + } + /** + * Fails a test with no message. + */ + static public void fail() { + fail(null); + } + /** + * Asserts that two objects are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, Object expected, Object actual) { + if (expected == null && actual == null) + return; + if (expected != null && expected.equals(actual)) + return; + failNotEquals(message, expected, actual); + } + /** + * Asserts that two objects are equal. If they are not + * an AssertionFailedError is thrown. + */ + static public void assertEquals(Object expected, Object actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two Strings are equal. + */ + static public void assertEquals(String message, String expected, String actual) { + if (expected == null && actual == null) + return; + if (expected != null && expected.equals(actual)) + return; + throw new ComparisonFailure(message, expected, actual); + } + /** + * Asserts that two Strings are equal. + */ + static public void assertEquals(String expected, String actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two doubles are equal concerning a delta. If they are not + * an AssertionFailedError is thrown with the given message. If the expected + * value is infinity then the delta value is ignored. + */ + static public void assertEquals(String message, double expected, double actual, double delta) { + // handle infinity specially since subtracting to infinite values gives NaN and the + // the following test fails + if (Double.isInfinite(expected)) { + if (!(expected == actual)) + failNotEquals(message, new Double(expected), new Double(actual)); + } else if (!(Math.abs(expected-actual) <= delta)) // Because comparison with NaN always returns false + failNotEquals(message, new Double(expected), new Double(actual)); + } + /** + * Asserts that two doubles are equal concerning a delta. If the expected + * value is infinity then the delta value is ignored. + */ + static public void assertEquals(double expected, double actual, double delta) { + assertEquals(null, expected, actual, delta); + } + /** + * Asserts that two floats are equal concerning a delta. If they are not + * an AssertionFailedError is thrown with the given message. If the expected + * value is infinity then the delta value is ignored. + */ + static public void assertEquals(String message, float expected, float actual, float delta) { + // handle infinity specially since subtracting to infinite values gives NaN and the + // the following test fails + if (Float.isInfinite(expected)) { + if (!(expected == actual)) + failNotEquals(message, new Float(expected), new Float(actual)); + } else if (!(Math.abs(expected-actual) <= delta)) + failNotEquals(message, new Float(expected), new Float(actual)); + } + /** + * Asserts that two floats are equal concerning a delta. If the expected + * value is infinity then the delta value is ignored. + */ + static public void assertEquals(float expected, float actual, float delta) { + assertEquals(null, expected, actual, delta); + } + /** + * Asserts that two longs are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, long expected, long actual) { + assertEquals(message, new Long(expected), new Long(actual)); + } + /** + * Asserts that two longs are equal. + */ + static public void assertEquals(long expected, long actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two booleans are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, boolean expected, boolean actual) { + assertEquals(message, new Boolean(expected), new Boolean(actual)); + } + /** + * Asserts that two booleans are equal. + */ + static public void assertEquals(boolean expected, boolean actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two bytes are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, byte expected, byte actual) { + assertEquals(message, new Byte(expected), new Byte(actual)); + } + /** + * Asserts that two bytes are equal. + */ + static public void assertEquals(byte expected, byte actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two chars are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, char expected, char actual) { + assertEquals(message, new Character(expected), new Character(actual)); + } + /** + * Asserts that two chars are equal. + */ + static public void assertEquals(char expected, char actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two shorts are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, short expected, short actual) { + assertEquals(message, new Short(expected), new Short(actual)); + } + /** + * Asserts that two shorts are equal. + */ + static public void assertEquals(short expected, short actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that two ints are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, int expected, int actual) { + assertEquals(message, new Integer(expected), new Integer(actual)); + } + /** + * Asserts that two ints are equal. + */ + static public void assertEquals(int expected, int actual) { + assertEquals(null, expected, actual); + } + /** + * Asserts that an object isn't null. + */ + static public void assertNotNull(Object object) { + assertNotNull(null, object); + } + /** + * Asserts that an object isn't null. If it is + * an AssertionFailedError is thrown with the given message. + */ + static public void assertNotNull(String message, Object object) { + assertTrue(message, object != null); + } + /** + * Asserts that an object is null. + */ + static public void assertNull(Object object) { + assertNull(null, object); + } + /** + * Asserts that an object is null. If it is not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertNull(String message, Object object) { + assertTrue(message, object == null); + } + /** + * Asserts that two objects refer to the same object. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertSame(String message, Object expected, Object actual) { + if (expected == actual) + return; + failNotSame(message, expected, actual); + } + /** + * Asserts that two objects refer to the same object. If they are not + * the same an AssertionFailedError is thrown. + */ + static public void assertSame(Object expected, Object actual) { + assertSame(null, expected, actual); + } + /** + * Asserts that two objects refer to the same object. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertNotSame(String message, Object expected, Object actual) { + if (expected == actual) + failSame(message); + } + /** + * Asserts that two objects refer to the same object. If they are not + * the same an AssertionFailedError is thrown. + */ + static public void assertNotSame(Object expected, Object actual) { + assertNotSame(null, expected, actual); + } + + static private void failSame(String message) { + String formatted= ""; + if (message != null) + formatted= message+" "; + fail(formatted+"expected not same"); + } + + static private void failNotSame(String message, Object expected, Object actual) { + String formatted= ""; + if (message != null) + formatted= message+" "; + fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">"); + } + + static private void failNotEquals(String message, Object expected, Object actual) { + fail(format(message, expected, actual)); + } + + static String format(String message, Object expected, Object actual) { + String formatted= ""; + if (message != null) + formatted= message+" "; + return formatted+"expected:<"+expected+"> but was:<"+actual+">"; + } +} diff --git a/junit/src/main/java/junit/framework/AssertionFailedError.java b/junit/src/main/java/junit/framework/AssertionFailedError.java new file mode 100644 index 0000000..e9cb3a3 --- /dev/null +++ b/junit/src/main/java/junit/framework/AssertionFailedError.java @@ -0,0 +1,13 @@ +package junit.framework; + +/** + * Thrown when an assertion failed. + */ +public class AssertionFailedError extends Error { + + public AssertionFailedError () { + } + public AssertionFailedError (String message) { + super (message); + } +} diff --git a/junit/src/main/java/junit/framework/ComparisonFailure.java b/junit/src/main/java/junit/framework/ComparisonFailure.java new file mode 100644 index 0000000..a0ad176 --- /dev/null +++ b/junit/src/main/java/junit/framework/ComparisonFailure.java @@ -0,0 +1,68 @@ +package junit.framework; + +/** + * Thrown when an assert equals for Strings failed. + * + * Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com + */ +public class ComparisonFailure extends AssertionFailedError { + private String fExpected; + private String fActual; + + /** + * Constructs a comparison failure. + * @param message the identifying message or null + * @param expected the expected string value + * @param actual the actual string value + */ + public ComparisonFailure (String message, String expected, String actual) { + super (message); + fExpected= expected; + fActual= actual; + } + + /** + * Returns "..." in place of common prefix and "..." in + * place of common suffix between expected and actual. + * + * @see java.lang.Throwable#getMessage() + */ + public String getMessage() { + if (fExpected == null || fActual == null) + return Assert.format(super.getMessage(), fExpected, fActual); + + int end= Math.min(fExpected.length(), fActual.length()); + + int i= 0; + for(; i < end; i++) { + if (fExpected.charAt(i) != fActual.charAt(i)) + break; + } + int j= fExpected.length()-1; + int k= fActual.length()-1; + for (; k >= i && j >= i; k--,j--) { + if (fExpected.charAt(j) != fActual.charAt(k)) + break; + } + String actual, expected; + + // equal strings + if (j < i && k < i) { + expected= fExpected; + actual= fActual; + } else { + expected= fExpected.substring(i, j+1); + actual= fActual.substring(i, k+1); + if (i <= end && i > 0) { + expected= "..."+expected; + actual= "..."+actual; + } + + if (j < fExpected.length()-1) + expected= expected+"..."; + if (k < fActual.length()-1) + actual= actual+"..."; + } + return Assert.format(super.getMessage(), expected, actual); + } +} diff --git a/junit/src/main/java/junit/framework/Protectable.java b/junit/src/main/java/junit/framework/Protectable.java new file mode 100644 index 0000000..9a63c96 --- /dev/null +++ b/junit/src/main/java/junit/framework/Protectable.java @@ -0,0 +1,14 @@ +package junit.framework; + +/** + * A <em>Protectable</em> can be run and can throw a Throwable. + * + * @see TestResult + */ +public interface Protectable { + + /** + * Run the the following method protected. + */ + public abstract void protect() throws Throwable; +} diff --git a/junit/src/main/java/junit/framework/Test.java b/junit/src/main/java/junit/framework/Test.java new file mode 100644 index 0000000..94f25cf --- /dev/null +++ b/junit/src/main/java/junit/framework/Test.java @@ -0,0 +1,17 @@ +package junit.framework; + +/** + * A <em>Test</em> can be run and collect its results. + * + * @see TestResult + */ +public interface Test { + /** + * Counts the number of test cases that will be run by this test. + */ + public abstract int countTestCases(); + /** + * Runs a test and collects its result in a TestResult instance. + */ + public abstract void run(TestResult result); +} diff --git a/junit/src/main/java/junit/framework/TestCase.java b/junit/src/main/java/junit/framework/TestCase.java new file mode 100644 index 0000000..f29e8d2 --- /dev/null +++ b/junit/src/main/java/junit/framework/TestCase.java @@ -0,0 +1,197 @@ +package junit.framework; + +import java.lang.reflect.*; + +/** + * A test case defines the fixture to run multiple tests. To define a test case<br> + * 1) implement a subclass of TestCase<br> + * 2) define instance variables that store the state of the fixture<br> + * 3) initialize the fixture state by overriding <code>setUp</code><br> + * 4) clean-up after a test by overriding <code>tearDown</code>.<br> + * Each test runs in its own fixture so there + * can be no side effects among test runs. + * Here is an example: + * <pre> + * public class MathTest extends TestCase { + * protected double fValue1; + * protected double fValue2; + * + * protected void setUp() { + * fValue1= 2.0; + * fValue2= 3.0; + * } + * } + * </pre> + * + * For each test implement a method which interacts + * with the fixture. Verify the expected results with assertions specified + * by calling <code>assertTrue</code> with a boolean. + * <pre> + * public void testAdd() { + * double result= fValue1 + fValue2; + * assertTrue(result == 5.0); + * } + * </pre> + * Once the methods are defined you can run them. The framework supports + * both a static type safe and more dynamic way to run a test. + * In the static way you override the runTest method and define the method to + * be invoked. A convenient way to do so is with an anonymous inner class. + * <pre> + * TestCase test= new MathTest("add") { + * public void runTest() { + * testAdd(); + * } + * }; + * test.run(); + * </pre> + * The dynamic way uses reflection to implement <code>runTest</code>. It dynamically finds + * and invokes a method. + * In this case the name of the test case has to correspond to the test method + * to be run. + * <pre> + * TestCase= new MathTest("testAdd"); + * test.run(); + * </pre> + * The tests to be run can be collected into a TestSuite. JUnit provides + * different <i>test runners</i> which can run a test suite and collect the results. + * A test runner either expects a static method <code>suite</code> as the entry + * point to get a test to run or it will extract the suite automatically. + * <pre> + * public static Test suite() { + * suite.addTest(new MathTest("testAdd")); + * suite.addTest(new MathTest("testDivideByZero")); + * return suite; + * } + * </pre> + * @see TestResult + * @see TestSuite + */ + +public abstract class TestCase extends Assert implements Test { + /** + * the name of the test case + */ + private String fName; + + /** + * No-arg constructor to enable serialization. This method + * is not intended to be used by mere mortals without calling setName(). + */ + public TestCase() { + fName= null; + } + /** + * Constructs a test case with the given name. + */ + public TestCase(String name) { + fName= name; + } + /** + * Counts the number of test cases executed by run(TestResult result). + */ + public int countTestCases() { + return 1; + } + /** + * Creates a default TestResult object + * + * @see TestResult + */ + protected TestResult createResult() { + return new TestResult(); + } + /** + * A convenience method to run this test, collecting the results with a + * default TestResult object. + * + * @see TestResult + */ + public TestResult run() { + TestResult result= createResult(); + run(result); + return result; + } + /** + * Runs the test case and collects the results in TestResult. + */ + public void run(TestResult result) { + result.run(this); + } + /** + * Runs the bare test sequence. + * @exception Throwable if any exception is thrown + */ + public void runBare() throws Throwable { + setUp(); + try { + runTest(); + } + finally { + tearDown(); + } + } + /** + * Override to run the test and assert its state. + * @exception Throwable if any exception is thrown + */ + protected void runTest() throws Throwable { + assertNotNull(fName); + Method runMethod= null; + try { + // use getMethod to get all public inherited + // methods. getDeclaredMethods returns all + // methods of this class but excludes the + // inherited ones. + runMethod= getClass().getMethod(fName, (Class[]) null); + } catch (NoSuchMethodException e) { + fail("Method \""+fName+"\" not found"); + } + if (!Modifier.isPublic(runMethod.getModifiers())) { + fail("Method \""+fName+"\" should be public"); + } + + try { + runMethod.invoke(this, (Object[]) null); + } + catch (InvocationTargetException e) { + e.fillInStackTrace(); + throw e.getTargetException(); + } + catch (IllegalAccessException e) { + e.fillInStackTrace(); + throw e; + } + } + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + */ + protected void setUp() throws Exception { + } + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + */ + protected void tearDown() throws Exception { + } + /** + * Returns a string representation of the test case + */ + public String toString() { + return getName() + "(" + getClass().getName() + ")"; + } + /** + * Gets the name of a TestCase + * @return returns a String + */ + public String getName() { + return fName; + } + /** + * Sets the name of a TestCase + * @param name The name to set + */ + public void setName(String name) { + fName= name; + } +} diff --git a/junit/src/main/java/junit/framework/TestFailure.java b/junit/src/main/java/junit/framework/TestFailure.java new file mode 100644 index 0000000..ace2dbe --- /dev/null +++ b/junit/src/main/java/junit/framework/TestFailure.java @@ -0,0 +1,57 @@ +package junit.framework; + +import java.io.PrintWriter; +import java.io.StringWriter; + + +/** + * A <code>TestFailure</code> collects a failed test together with + * the caught exception. + * @see TestResult + */ +public class TestFailure extends Object { + protected Test fFailedTest; + protected Throwable fThrownException; + + + /** + * Constructs a TestFailure with the given test and exception. + */ + public TestFailure(Test failedTest, Throwable thrownException) { + fFailedTest= failedTest; + fThrownException= thrownException; + } + /** + * Gets the failed test. + */ + public Test failedTest() { + return fFailedTest; + } + /** + * Gets the thrown exception. + */ + public Throwable thrownException() { + return fThrownException; + } + /** + * Returns a short description of the failure. + */ + public String toString() { + StringBuffer buffer= new StringBuffer(); + buffer.append(fFailedTest+": "+fThrownException.getMessage()); + return buffer.toString(); + } + public String trace() { + StringWriter stringWriter= new StringWriter(); + PrintWriter writer= new PrintWriter(stringWriter); + thrownException().printStackTrace(writer); + StringBuffer buffer= stringWriter.getBuffer(); + return buffer.toString(); + } + public String exceptionMessage() { + return thrownException().getMessage(); + } + public boolean isFailure() { + return thrownException() instanceof AssertionFailedError; + } +} diff --git a/junit/src/main/java/junit/framework/TestListener.java b/junit/src/main/java/junit/framework/TestListener.java new file mode 100644 index 0000000..3ef3e33 --- /dev/null +++ b/junit/src/main/java/junit/framework/TestListener.java @@ -0,0 +1,23 @@ +package junit.framework; + +/** + * A Listener for test progress + */ +public interface TestListener { + /** + * An error occurred. + */ + public void addError(Test test, Throwable t); + /** + * A failure occurred. + */ + public void addFailure(Test test, AssertionFailedError t); + /** + * A test ended. + */ + public void endTest(Test test); + /** + * A test started. + */ + public void startTest(Test test); +} diff --git a/junit/src/main/java/junit/framework/TestResult.java b/junit/src/main/java/junit/framework/TestResult.java new file mode 100644 index 0000000..153a77b --- /dev/null +++ b/junit/src/main/java/junit/framework/TestResult.java @@ -0,0 +1,166 @@ +package junit.framework; + +import java.util.Vector; +import java.util.Enumeration; + +/** + * A <code>TestResult</code> collects the results of executing + * a test case. It is an instance of the Collecting Parameter pattern. + * The test framework distinguishes between <i>failures</i> and <i>errors</i>. + * A failure is anticipated and checked for with assertions. Errors are + * unanticipated problems like an <code>ArrayIndexOutOfBoundsException</code>. + * + * @see Test + */ +public class TestResult extends Object { + protected Vector fFailures; + protected Vector fErrors; + protected Vector fListeners; + protected int fRunTests; + private boolean fStop; + + public TestResult() { + fFailures= new Vector(); + fErrors= new Vector(); + fListeners= new Vector(); + fRunTests= 0; + fStop= false; + } + /** + * Adds an error to the list of errors. The passed in exception + * caused the error. + */ + public synchronized void addError(Test test, Throwable t) { + fErrors.addElement(new TestFailure(test, t)); + for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { + ((TestListener)e.nextElement()).addError(test, t); + } + } + /** + * Adds a failure to the list of failures. The passed in exception + * caused the failure. + */ + public synchronized void addFailure(Test test, AssertionFailedError t) { + fFailures.addElement(new TestFailure(test, t)); + for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { + ((TestListener)e.nextElement()).addFailure(test, t); + } + } + /** + * Registers a TestListener + */ + public synchronized void addListener(TestListener listener) { + fListeners.addElement(listener); + } + /** + * Unregisters a TestListener + */ + public synchronized void removeListener(TestListener listener) { + fListeners.removeElement(listener); + } + /** + * Returns a copy of the listeners. + */ + private synchronized Vector cloneListeners() { + return (Vector)fListeners.clone(); + } + /** + * Informs the result that a test was completed. + */ + public void endTest(Test test) { + for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { + ((TestListener)e.nextElement()).endTest(test); + } + } + /** + * Gets the number of detected errors. + */ + public synchronized int errorCount() { + return fErrors.size(); + } + /** + * Returns an Enumeration for the errors + */ + public synchronized Enumeration errors() { + return fErrors.elements(); + } + /** + * Gets the number of detected failures. + */ + public synchronized int failureCount() { + return fFailures.size(); + } + /** + * Returns an Enumeration for the failures + */ + public synchronized Enumeration failures() { + return fFailures.elements(); + } + /** + * Runs a TestCase. + */ + protected void run(final TestCase test) { + startTest(test); + Protectable p= new Protectable() { + public void protect() throws Throwable { + test.runBare(); + } + }; + runProtected(test, p); + + endTest(test); + } + /** + * Gets the number of run tests. + */ + public synchronized int runCount() { + return fRunTests; + } + /** + * Runs a TestCase. + */ + public void runProtected(final Test test, Protectable p) { + try { + p.protect(); + } + catch (AssertionFailedError e) { + addFailure(test, e); + } + catch (ThreadDeath e) { // don't catch ThreadDeath by accident + throw e; + } + catch (Throwable e) { + addError(test, e); + } + } + /** + * Checks whether the test run should stop + */ + public synchronized boolean shouldStop() { + return fStop; + } + /** + * Informs the result that a test will be started. + */ + public void startTest(Test test) { + final int count= test.countTestCases(); + synchronized(this) { + fRunTests+= count; + } + for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { + ((TestListener)e.nextElement()).startTest(test); + } + } + /** + * Marks that the test run should stop. + */ + public synchronized void stop() { + fStop= true; + } + /** + * Returns whether the entire test was successful or not. + */ + public synchronized boolean wasSuccessful() { + return failureCount() == 0 && errorCount() == 0; + } +} diff --git a/junit/src/main/java/junit/framework/TestSuite.java b/junit/src/main/java/junit/framework/TestSuite.java new file mode 100644 index 0000000..bf23198 --- /dev/null +++ b/junit/src/main/java/junit/framework/TestSuite.java @@ -0,0 +1,267 @@ +package junit.framework; + +import java.util.Vector; +import java.util.Enumeration; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.*; +import java.lang.reflect.Constructor; + +/** + * A <code>TestSuite</code> is a <code>Composite</code> of Tests. + * It runs a collection of test cases. Here is an example using + * the dynamic test definition. + * <pre> + * TestSuite suite= new TestSuite(); + * suite.addTest(new MathTest("testAdd")); + * suite.addTest(new MathTest("testDivideByZero")); + * </pre> + * Alternatively, a TestSuite can extract the tests to be run automatically. + * To do so you pass the class of your TestCase class to the + * TestSuite constructor. + * <pre> + * TestSuite suite= new TestSuite(MathTest.class); + * </pre> + * This constructor creates a suite with all the methods + * starting with "test" that take no arguments. + * + * @see Test + */ +public class TestSuite implements Test { + + private Vector fTests= new Vector(10); + private String fName; + + /** + * Constructs an empty TestSuite. + */ + public TestSuite() { + } + + /** + * Constructs a TestSuite from the given class with the given name. + * @see TestSuite#TestSuite(Class) + */ + public TestSuite(Class theClass, String name) { + this(theClass); + setName(name); + } + + /** + * Constructs a TestSuite from the given class. Adds all the methods + * starting with "test" as test cases to the suite. + * Parts of this method was written at 2337 meters in the Huffihutte, + * Kanton Uri + */ + public TestSuite(final Class theClass) { + fName= theClass.getName(); + try { + getTestConstructor(theClass); // Avoid generating multiple error messages + } catch (NoSuchMethodException e) { + addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()")); + return; + } + + if (!Modifier.isPublic(theClass.getModifiers())) { + addTest(warning("Class "+theClass.getName()+" is not public")); + return; + } + + Class superClass= theClass; + Vector names= new Vector(); + while (Test.class.isAssignableFrom(superClass)) { + Method[] methods= superClass.getDeclaredMethods(); + for (int i= 0; i < methods.length; i++) { + addTestMethod(methods[i], names, theClass); + } + superClass= superClass.getSuperclass(); + } + if (fTests.size() == 0) + addTest(warning("No tests found in "+theClass.getName())); + } + + /** + * Constructs an empty TestSuite. + */ + public TestSuite(String name) { + setName(name); + } + + /** + * Adds a test to the suite. + */ + public void addTest(Test test) { + fTests.addElement(test); + } + + /** + * Adds the tests from the given class to the suite + */ + public void addTestSuite(Class testClass) { + addTest(new TestSuite(testClass)); + } + + private void addTestMethod(Method m, Vector names, Class theClass) { + String name= m.getName(); + if (names.contains(name)) + return; + if (! isPublicTestMethod(m)) { + if (isTestMethod(m)) + addTest(warning("Test method isn't public: "+m.getName())); + return; + } + names.addElement(name); + addTest(createTest(theClass, name)); + } + + /** + * ...as the moon sets over the early morning Merlin, Oregon + * mountains, our intrepid adventurers type... + */ + static public Test createTest(Class theClass, String name) { + Constructor constructor; + try { + constructor= getTestConstructor(theClass); + } catch (NoSuchMethodException e) { + return warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()"); + } + Object test; + try { + if (constructor.getParameterTypes().length == 0) { + test= constructor.newInstance(new Object[0]); + if (test instanceof TestCase) + ((TestCase) test).setName(name); + } else { + test= constructor.newInstance(new Object[]{name}); + } + } catch (InstantiationException e) { + return(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")")); + } catch (InvocationTargetException e) { + return(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")")); + } catch (IllegalAccessException e) { + return(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")")); + } + return (Test) test; + } + + /** + * Converts the stack trace into a string + */ + private static String exceptionToString(Throwable t) { + StringWriter stringWriter= new StringWriter(); + PrintWriter writer= new PrintWriter(stringWriter); + t.printStackTrace(writer); + return stringWriter.toString(); + + } + + /** + * Counts the number of test cases that will be run by this test. + */ + public int countTestCases() { + int count= 0; + for (Enumeration e= tests(); e.hasMoreElements(); ) { + Test test= (Test)e.nextElement(); + count= count + test.countTestCases(); + } + return count; + } + + /** + * Gets a constructor which takes a single String as + * its argument or a no arg constructor. + */ + public static Constructor getTestConstructor(Class theClass) throws NoSuchMethodException { + Class[] args= { String.class }; + try { + return theClass.getConstructor(args); + } catch (NoSuchMethodException e) { + // fall through + } + return theClass.getConstructor(new Class[0]); + } + + private boolean isPublicTestMethod(Method m) { + return isTestMethod(m) && Modifier.isPublic(m.getModifiers()); + } + + private boolean isTestMethod(Method m) { + String name= m.getName(); + Class[] parameters= m.getParameterTypes(); + Class returnType= m.getReturnType(); + return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE); + } + + /** + * Runs the tests and collects their result in a TestResult. + */ + public void run(TestResult result) { + for (Enumeration e= tests(); e.hasMoreElements(); ) { + if (result.shouldStop() ) + break; + Test test= (Test)e.nextElement(); + runTest(test, result); + } + } + + public void runTest(Test test, TestResult result) { + test.run(result); + } + + /** + * Returns the test at the given index + */ + public Test testAt(int index) { + return (Test)fTests.elementAt(index); + } + + /** + * Returns the number of tests in this suite + */ + public int testCount() { + return fTests.size(); + } + + /** + * Returns the tests as an enumeration + */ + public Enumeration tests() { + return fTests.elements(); + } + + /** + */ + public String toString() { + if (getName() != null) + return getName(); + return super.toString(); + } + + /** + * Sets the name of the suite. + * @param name The name to set + */ + public void setName(String name) { + fName= name; + } + + /** + * Returns the name of the suite. Not all + * test suites have a name and this method + * can return null. + */ + public String getName() { + return fName; + } + + /** + * Returns a test which will fail and log a warning message. + */ + private static Test warning(final String message) { + return new TestCase("warning") { + protected void runTest() { + fail(message); + } + }; + } +} diff --git a/junit/src/main/java/junit/framework/package.html b/junit/src/main/java/junit/framework/package.html new file mode 100644 index 0000000..770d470 --- /dev/null +++ b/junit/src/main/java/junit/framework/package.html @@ -0,0 +1,5 @@ +<HTML> +<BODY> +The junit test framework. +</BODY> +</HTML> |