/* * Javolution - Java(TM) Solution for Real-Time and Embedded Systems * Copyright (C) 2007 - Javolution (http://javolution.org/) * All rights reserved. * * Permission to use, copy, modify, and distribute this software is * freely granted, provided that this notice is preserved. */ package javolution.testing; import j2me.lang.CharSequence; import javolution.context.Context; import javolution.context.LogContext; import javolution.context.ObjectFactory; import javolution.lang.Configurable; import javolution.lang.MathLib; import javolution.text.Text; import javolution.util.FastTable; /** * <p> This class represents a logging context specialized for testing.</p> * * <p> A test context is necessary to run a {@link TestSuite} or * {@link TestCase}. The {@link #DEFAULT default} test context sends results * to <code>System.out</code> and errors to <code>System.err</code>.[code] * TestContext.enter(); // Enters default (logs to System.out/System.err) * try { * TestContext.run(testSuite); * TestContext.run(testSuite.tests().get(3)); // Runs specific test case. * ... * } finally { * TestContext.exit(); // Outputs test results statistics. * }[/code] </p> * * <p> Users may provide their own test context (or plugin) to output or * show test results in various form (e.g. tabular, IDE integraged).[code] * TestContext tabularLog = new TestContext() { ... } * TestContext.enter(tabularLog); * try { * TestContext.run(testSuite); // Results sent to spreadsheet. * ... * } finally { * TestContext.exit(); * }[/code] </p> * * <p> For automatic regression tests, a {@link #REGRESSION regression} * context is provided which does not perform any logging but raises an * {@link AssertionException} when an assertion fails.[code] * TestContext.enter(TestContext.REGRESSION); * try { * TestContext.run(testSuite); // AssertionError if assert fails. * ... * } finally { * TestContext.exit(); * }[/code]</p> * * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> * @version 5.3, March 8, 2009 * @see TestSuite */ public abstract class TestContext extends LogContext { /** * Holds the test context default implementation (the test report is sent to * to <code>System.out</code> and test errors are sent to <code>System.err</code>). */ public static final Configurable/*<Class<? extends TestContext>>*/ DEFAULT = new Configurable(Default.class) {}; /** * Holds a test context logging test results to the system console. */ public static final Class/*<? extends LogContext>*/ CONSOLE = Console.class; /** * Holds an implementation which does not perform any logging but raises * an {@link AssertionException} when an assertion fails. * This implementation can be used for automatic regression tests. */ public static final Class/*<? extends TestContext>*/ REGRESSION = Regression.class; /** * Enters the {@link #DEFAULT} test context. */ public static void enter() { Context.enter((Class) DEFAULT.get()); } /** * Exits the current test context. * * @throws ClassCastException if the current context is not a test context. */ public static void exit() { Context.exit(TestContext.class); } /** * Executes the specified test suite and logs the results to the * current test context. * * @param testSuite the test suite to be executed. * @throws ClassCastException if the current logging context is not a test * context. */ public static void run(TestSuite testSuite) throws Exception { TestContext testContext = (TestContext) LogContext.getCurrentLogContext(); testContext.doRun(testSuite); } /** * Executes the specified test case and logs the results to the current * test context. * * @param testCase the test case to be executed. * @throws ClassCastException if the current logging context is not a test * context. */ public static void run(TestCase testCase) throws Exception { TestContext testContext = (TestContext) LogContext.getCurrentLogContext(); testContext.doRun(testCase); } /** * Checks the equality of both objects specified. * * @param expected the expected result (can be <code>null</code>). * @param actual the actual result (can be <code>null</code>). * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if both expected and actual are equal; * <code>false</code> otherwise. */ public static boolean assertEquals(Object expected, Object actual, CharSequence message) { boolean ok = ((expected == null) && (actual == null)) || ((expected != null) && (expected.equals(actual))); message = (ok || (message != null)) ? message : // Provides error message if necessary. Text.valueOf(expected).plus(" expected but found ").plus(actual); TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); return ctx.doAssert(ok, message); } /** * Convenience method equivalent to <code>assertEquals(expected, actual, null)</code>. * * @param expected the expected result (can be <code>null</code>). * @param actual the actual result (can be <code>null</code>). */ public static boolean assertEquals(Object expected, Object actual) { return TestContext.assertEquals(expected, actual, null); } /** * Checks that both objects specified refer to the same instance. * * @param expected the expected result (can be <code>null</code>). * @param actual the actual result (can be <code>null</code>). * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if both expected and actual are the same * object; <code>false</code> otherwise. */ public static boolean assertSame(Object expected, Object actual, CharSequence message) { boolean ok = (expected == actual); message = (ok || (message != null)) ? message : // Provides error message if necessary. Text.valueOf(expected).plus(" expected but found a different instance ").plus(actual); TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); return ctx.doAssert(ok, message); } /** * Convenience method equivalent to <code>assertSame(expected, actual, null)</code>. * * @param expected the expected result (can be <code>null</code>). * @param actual the actual result (can be <code>null</code>). * @return <code>true</code> if both expected and actual are the same * object; <code>false</code> otherwise. */ public static boolean assertSame(Object expected, Object actual) { return TestContext.assertSame(expected, actual, null); } /** * Convenience method equivalent to <code>assertEquals(true, actual, message)</code>. * * @param actual the actual value. * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if actual is <code>true</code>; * <code>false</code> otherwise. */ public static boolean assertTrue(boolean actual, CharSequence message) { return TestContext.assertEquals(Boolean.TRUE, actual ? Boolean.TRUE : Boolean.FALSE, message); } /** * Convenience method equivalent to <code>assertTrue(actual, null)</code>. * * @param actual the actual value. * @return <code>true</code> if actual is <code>true</code>; * <code>false</code> otherwise. */ public static boolean assertTrue(boolean actual) { return TestContext.assertTrue(actual, null); } /** * Convenience method equivalent to <code>assertEquals(false, actual, message)</code>. * * @param actual the actual value. * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if actual is <code>false</code>; * <code>false</code> otherwise. */ public static boolean assertFalse(boolean actual, CharSequence message) { return TestContext.assertEquals(Boolean.FALSE, actual ? Boolean.TRUE : Boolean.FALSE, message); } /** * Convenience method equivalent to <code>assertFalse(actual, null)</code>. * * @param actual the actual value. * @return <code>true</code> if actual is <code>false</code>; * <code>false</code> otherwise. */ public static boolean assertFalse(boolean actual) { return TestContext.assertFalse(actual, null); } /** * Convenience method equivalent to <code>assertEquals(null, actual, message)</code>. * * @param actual the actual value. * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if actual is <code>null</code>; * <code>false</code> otherwise. */ public static boolean assertNull(Object actual, CharSequence message) { return TestContext.assertEquals(null, actual, message); } /** * Convenience method equivalent to <code>assertNull(actual, null)</code>. * * @param actual the actual value. * @return <code>true</code> if actual is <code>null</code>; * <code>false</code> otherwise. */ public static boolean assertNull(Object actual) { return TestContext.assertNull(actual, null); } /** * Convenience method equivalent to <code>assertTrue(actual != null, message)</code>. * * @param actual the actual value. * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if actual is not <code>null</code>; * <code>false</code> otherwise. */ public static boolean assertNotNull(Object actual, CharSequence message) { boolean ok = (actual != null); message = (ok || (message != null)) ? message : // Provides error message if necessary. Text.valueOf("Not null expected but found null"); TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); return ctx.doAssert(ok, message); } /** * Convenience method equivalent to <code>assertNotNull(actual, null)</code>. * * @param actual the actual value. * @return <code>true</code> if actual is <code>null</code>; * <code>false</code> otherwise. */ public static boolean assertNotNull(Object actual) { return TestContext.assertNotNull(actual, null); } /** * Convenience method equivalent to * <code>assertEquals(new Integer(expected), new Integer(actual), message)</code>. * * @param expected the expected result. * @param actual the actual result. * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if both expected and actual are equal; * <code>false</code> otherwise. */ public static boolean assertEquals(int expected, int actual, CharSequence message) { boolean ok = (expected == actual); message = (ok || (message != null)) ? message : // Provides error message if necessary. Text.valueOf(expected + " expected but found " + actual); TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); return ctx.doAssert(ok, message); } /** * Convenience method equivalent to * <code>assertEquals(expected, actual, null)</code>. * * @param expected the expected result. * @param actual the actual result. * @return <code>true</code> if both expected and actual are equal; * <code>false</code> otherwise. */ public static boolean assertEquals(int expected, int actual) { return TestContext.assertEquals(expected, actual, null); } /** * Convenience method equivalent to * <code>assertEquals(new Long(expected), new Long(actual))</code>. * * @param expected the expected result. * @param actual the actual result. * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if both expected and actual are equal; * <code>false</code> otherwise. */ public static boolean assertEquals(long expected, long actual, CharSequence message) { boolean ok = (expected == actual); message = (ok || (message != null)) ? message : // Provides error message if necessary. Text.valueOf(expected + " expected but found " + actual); TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); return ctx.doAssert(ok, message); } /** * Convenience method equivalent to * <code>assertEquals(expected, actual, null)</code>. * * @param expected the expected result. * @param actual the actual result. * @return <code>true</code> if both expected and actual are equal; * <code>false</code> otherwise. */ public static boolean assertEquals(long expected, long actual) { return TestContext.assertEquals(expected, actual, null); } /** * Convenience method equivalent to * <code>assertEquals(new Double(expected), new Double(actual), message)</code>. * * @param expected the expected result. * @param actual the actual result. * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if both expected and actual are equal; * <code>false</code> otherwise. * @deprecated Use {@link #assertEquals(double, double, double, CharSequence) * assertEquals(expected, actual, delta, message)} instead */ public static boolean assertEquals(double expected, double actual, CharSequence message) { boolean ok = (expected == actual) || (Double.isNaN(expected) && Double.isNaN(actual)); message = (ok || (message != null)) ? message : // Provides error message if necessary. Text.valueOf(expected + " expected but found " + actual); TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); return ctx.doAssert(ok, message); } /** * Convenience method equivalent to * <code>assertEquals(expected, actual, null)</code>. * * @param expected the expected result. * @param actual the actual result. * @return <code>true</code> if both expected and actual are equal; * <code>false</code> otherwise. * @deprecated Use {@link #assertEquals(double, double, double) * assertEquals(expected, actual, delta)} instead */ public static boolean assertEquals(double expected, double actual) { return TestContext.assertEquals(expected, actual, null); } /** * Asserts that two doubles or floats are equal to within a positive delta. * If the expected value is infinity then the delta value is ignored. * NaN numbers are considered equal. * * @param expected the expected result. * @param actual the actual result. * @param delta the maximum delta between expected and actual for which * both numbers are still considered equal. * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if both expected and actual are approximately * equal; <code>false</code> otherwise. */ public static boolean assertEquals(double expected, double actual, double delta, CharSequence message) { boolean ok = (expected == actual) || (Double.isNaN(expected) && Double.isNaN(actual)); message = (ok || (message != null)) ? message : // Provides error message if necessary. Text.valueOf(expected + " expected but found " + actual); TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); return ctx.doAssert(ok, message); } /** * Convenience method equivalent to <code>assertEquals(expected, actual, delta, null)</code>. * * @param expected the expected result. * @param actual the actual result. * @param delta the maximum delta between expected and actual for which * both numbers are still considered equal. * @return <code>true</code> if both expected and actual are approximately * equal; <code>false</code> otherwise. */ public static boolean assertEquals(double expected, double actual, double delta) { return TestContext.assertEquals(expected, actual, delta, null); } /** * Checks the equality of the arrays specified. * If expecteds and actuals are <code>null</code>, they are considered equal. * * @param expected the single dimension array * with expected values (can be <code>null</code>). * @param actual the single dimension array * with actual values (can be <code>null</code>). * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if both expected and actual have equals * elements; <code>false</code> otherwise. */ public static boolean assertArrayEquals(Object[] expected, Object[] actual, CharSequence message) { TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); if (expected == actual) return ctx.doAssert(true, message); if (expected == null) return ctx.doAssert(false, message != null ? message : Text.valueOf("Null array expected but found actual array not null")); if (actual == null) return ctx.doAssert(false, message != null ? message : Text.valueOf("Not null array expected but found actual array null")); if ((expected.length != actual.length)) return ctx.doAssert(false, message != null ? message : Text.valueOf("Array of size " + expected.length + " expected but found array of actual size " + actual.length)); for (int i = 0; i < expected.length; i++) { Object e = expected[i]; Object a = actual[i]; if (((e != null) && !e.equals(a)) || (e != a)) return ctx.doAssert(false, message != null ? message : Text.valueOf("Array element at " + i + ", expected " + e + " but found " + a)); } return ctx.doAssert(true, message); } /** * Convenience method equivalent to <code>assertArrayEquals(expected, actual, null)</code>. * * @param expected the single dimension array * with expected values (can be <code>null</code>). * @param actual the single dimension array * with actual values (can be <code>null</code>). */ public static boolean assertArrayEquals(Object[] expected, Object[] actual) { return TestContext.assertArrayEquals(expected, actual, null); } /** * Checks the equality of both arrays specified. * If expecteds and actuals are <code>null</code>, they are considered equal. * * @param expected array (can be <code>null</code>). * @param actual array (can be <code>null</code>). * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if both expected and actual have the same * values; <code>false</code> otherwise. */ public static boolean assertArrayEquals(boolean[] expected, boolean[] actual, CharSequence message) { TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); if (expected == actual) return ctx.doAssert(true, message); if (expected == null) return ctx.doAssert(false, message != null ? message : Text.valueOf("Null array expected but found actual array not null")); if (actual == null) return ctx.doAssert(false, message != null ? message : Text.valueOf("Not null array expected but found actual array null")); if ((expected.length != actual.length)) return ctx.doAssert(false, message != null ? message : Text.valueOf("Array of size " + expected.length + " expected but found array of actual size " + actual.length)); for (int i = 0; i < expected.length; i++) { boolean e = expected[i]; boolean a = actual[i]; if (e != a) return ctx.doAssert(false, message != null ? message : Text.valueOf("Array element at " + i + ", expected " + e + " but found " + a)); } return ctx.doAssert(true, message); } /** * Convenience method equivalent to <code>assertArrayEquals(expected, actual, null)</code>. * * @param expected array (can be <code>null</code>). * @param actual array (can be <code>null</code>). * @return <code>true</code> if both expected and actual have the same * values; <code>false</code> otherwise. */ public static boolean assertArrayEquals(boolean[] expected, boolean[] actual) { return TestContext.assertArrayEquals(expected, actual, null); } /** * Checks the equality of both arrays specified. * If expecteds and actuals are <code>null</code>, they are considered equal. * * @param expected array (can be <code>null</code>). * @param actual array (can be <code>null</code>). * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if both expected and actual have the same * values; <code>false</code> otherwise. */ public static boolean assertArrayEquals(int[] expected, int[] actual, CharSequence message) { TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); if (expected == actual) return ctx.doAssert(true, message); if (expected == null) return ctx.doAssert(false, message != null ? message : Text.valueOf("Null array expected but found actual array not null")); if (actual == null) return ctx.doAssert(false, message != null ? message : Text.valueOf("Not null array expected but found actual array null")); if ((expected.length != actual.length)) return ctx.doAssert(false, message != null ? message : Text.valueOf("Array of size " + expected.length + " expected but found array of actual size " + actual.length)); for (int i = 0; i < expected.length; i++) { int e = expected[i]; int a = actual[i]; if (e != a) return ctx.doAssert(false, message != null ? message : Text.valueOf("Array element at " + i + ", expected " + e + " but found " + a)); } return ctx.doAssert(true, message); } /** * Convenience method equivalent to <code>assertArrayEquals(expected, value, null)</code>. * * @param expected array (can be <code>null</code>). * @param actual array (can be <code>null</code>). * @return <code>true</code> if both expected and actual have the same * values; <code>false</code> otherwise. */ public static boolean assertArrayEquals(int[] expected, int[] actual) { return TestContext.assertArrayEquals(expected, actual, null); } /** * Checks the equality of both arrays specified. * If expecteds and actuals are <code>null</code>, they are considered equal. * * @param expected array (can be <code>null</code>). * @param actual array (can be <code>null</code>). * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if both expected and actual have the same * values; <code>false</code> otherwise. */ public static boolean assertArrayEquals(long[] expected, long[] actual, CharSequence message) { TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); if (expected == actual) return ctx.doAssert(true, message); if (expected == null) return ctx.doAssert(false, message != null ? message : Text.valueOf("Null array expected but found actual array not null")); if (actual == null) return ctx.doAssert(false, message != null ? message : Text.valueOf("Not null array expected but found actual array null")); if ((expected.length != actual.length)) return ctx.doAssert(false, message != null ? message : Text.valueOf("Array of size " + expected.length + " expected but found array of actual size " + actual.length)); for (int i = 0; i < expected.length; i++) { long e = expected[i]; long a = actual[i]; if (e != a) return ctx.doAssert(false, message != null ? message : Text.valueOf("Array element at " + i + ", expected " + e + " but found " + a)); } return ctx.doAssert(true, message); } /** * Convenience method equivalent to <code>assertArrayEquals(expected, value, null)</code>. * * @param expected array (can be <code>null</code>). * @param actual array (can be <code>null</code>). * @return <code>true</code> if both expected and actual have the same * values; <code>false</code> otherwise. */ public static boolean assertArrayEquals(long[] expected, long[] actual) { return TestContext.assertArrayEquals(expected, actual, null); } /** * Checks the equality of both arrays specified. * If expecteds and actuals are <code>null</code>, they are considered equal. * * @param expected array (can be <code>null</code>). * @param actual array (can be <code>null</code>). * @param delta the maximum delta between expected and actual for which * both numbers are still considered equal. * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if both expected and actual have approximately * the same values; <code>false</code> otherwise. */ public static boolean assertArrayEquals(double[] expected, double[] actual, double delta, CharSequence message) { TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); if (expected == actual) return ctx.doAssert(true, message); if (expected == null) return ctx.doAssert(false, message != null ? message : Text.valueOf("Null array expected but found actual array not null")); if (actual == null) return ctx.doAssert(false, message != null ? message : Text.valueOf("Not null array expected but found actual array null")); if ((expected.length != actual.length)) return ctx.doAssert(false, message != null ? message : Text.valueOf("Array of size " + expected.length + " expected but found array of actual size " + actual.length)); for (int i = 0; i < expected.length; i++) { double e = expected[i]; double a = actual[i]; if (MathLib.abs(e - a) > delta) return ctx.doAssert(false, message != null ? message : Text.valueOf("Array element at " + i + ", expected " + e + " but found " + a)); } return ctx.doAssert(true, message); } /** * Convenience method equivalent to * <code>assertArrayEquals(expected, actual, delta, null)</code>. * * @param expected array (can be <code>null</code>). * @param actual array (can be <code>null</code>). * @param delta the maximum delta between expected and actual for which * both numbers are still considered equal. * @return <code>true</code> if both expected and actual have the same * values; <code>false</code> otherwise. */ public static boolean assertArrayEquals(double[] expected, double[] actual, double delta) { return TestContext.assertArrayEquals(expected, actual, delta, null); } /** * Checks that the specified logic raises an instance of the specified * exception. * * @param exceptionClass the type of exception expected. * @param logic the logic supposed to produce the desired exception. * @param message the message displayed if assert fails or <code>null</code> if none. * @return <code>true</code> if the specified logic raises an exception of * specified type; <code>false</code> otherwise. */ public static boolean assertException(Class exceptionClass, Runnable logic, CharSequence message) { Throwable exception = null; try { logic.run(); } catch (Throwable e) { exception = e; } TestContext ctx = (TestContext) LogContext.getCurrentLogContext(); if (exception == null) return ctx.doAssert(false, message != null ? message : Text.valueOf("Expected exception instance of ").plus(exceptionClass.getName()).plus(" but no exception has been raised")); boolean ok = exceptionClass.isInstance(exception); message = (ok || (message != null)) ? message : // Provides error message if necessary. Text.valueOf("Expected instance of ").plus(exceptionClass.getName()).plus( " but actual exception is instance of ").plus(exception.getClass().getName()); return ctx.doAssert(ok, message); } /** * Convenience method equivalent to * <code>assertException(exceptionClass, logic, null)</code>. */ public static boolean assertException(Class exceptionClass, Runnable logic) { return TestContext.assertException(exceptionClass, logic, null); } /** * Convenience method equivalent to <code>assertTrue(false, message)</code>. */ public static boolean fail(CharSequence message) { return TestContext.assertTrue(false, message); } /** * Convenience method equivalent to <code>fail(null)</code>. */ public static boolean fail() { return TestContext.fail(null); } /** * Executes the specified test suite and logs the results. * The default implementation runs all the test cases. * * @param testSuite the test suite to be executed. * @see #doRun(javolution.testing.TestCase) */ protected void doRun(TestSuite testSuite) throws Exception { testSuite.setUp(); try { FastTable tests = testSuite._tests; for (int i = 0; i < tests.size(); i++) { doRun((TestCase) tests.get(i)); } } finally { testSuite.tearDown(); } } /** * Executes the specified test case and logs the results. * If the test case is not marked {@link TestCase#isIgnored() ignored}, * the default implementation runs {@link TestCase#setUp() setUp}, * {@link TestCase#execute() execute}, {@link TestCase#setUp() validate} * and {@link TestCase#setUp() tearDown} in sequence. * * @param testCase the test case being executed if not marked ignored. */ protected void doRun(TestCase testCase) throws Exception { if (testCase.isIgnored()) return; testCase.setUp(); try { testCase.execute(); testCase.validate(); } finally { testCase.tearDown(); } } /** * Asserts the specified value is <code>true</code>. * The default implementation logs an error message including the code * location of the assert if the assert checks fails. For example:[code] * [error] NaN expected but found Infinity * at javolution.TextTestSuite$DoubleParseDouble.validate(TextTestSuite.java:389) * [/code] * * @param value the boolean value to be tested. * @param message the message to be displayed if assert fails (can be <code>null</code>). * @return the specified value. */ protected boolean doAssert(boolean value, CharSequence message) { if (value) return true; /*@JVM-1.4+@ Throwable error = new Error(); // To get stack trace. StackTraceElement[] trace = error.getStackTrace(); javolution.text.TextBuilder tmp = javolution.text.TextBuilder.newInstance(); try { tmp.append(message); for (int i = 1; i < trace.length; i++) { if (trace[i].getMethodName().equals("validate")) { tmp.append("\n\tat "); tmp.append(trace[i]); break; } } logError(null, tmp); } finally { javolution.text.TextBuilder.recycle(tmp); } /**/ return false; } // TestContext default implementation. private static class Default extends TestContext { private int _passedCount; private int _failedCount; private int _ignoredCount; private boolean _isPassed; protected void enterAction() { _passedCount = _failedCount = _ignoredCount = 0; } protected void exitAction() { logMessage("test", Text.valueOf("---------------------------------------------------")); logMessage("test", Text.valueOf("SUMMARY - PASSED: " + _passedCount + ", FAILED: " + _failedCount + ", IGNORED: " + _ignoredCount)); } protected void doRun(TestSuite testSuite) throws Exception { logMessage("test", Text.valueOf("---------------------------------------------------")); logMessage("test", Text.valueOf("Executes Test Suite: ").plus(testSuite.getName())); logMessage("test", Text.valueOf("")); super.doRun(testSuite); } protected void doRun(TestCase testCase) { if (testCase.isIgnored()) { logWarning(Text.valueOf("Ignore ").plus(testCase.getName())); _ignoredCount++; return; } logMessage("test", Text.valueOf(testCase.getName())); _isPassed = true; try { super.doRun(testCase); } catch (Throwable error) { _isPassed = false; logError(error, null); } finally { // Updates statistics. if (_isPassed) _passedCount++; else _failedCount++; } } protected boolean doAssert(boolean value, CharSequence message) { if (!value) { _isPassed = false; return super.doAssert(value, message); // Logs error. } return value; } protected void logMessage(String category, CharSequence message) { if (category.equals("error")) { System.err.print("["); System.err.print(category); System.err.print("] "); System.err.println(message); System.err.flush(); } else { System.out.print("["); System.out.print(category); System.out.print("] "); System.out.println(message); System.out.flush(); } } } // TestContext for regression tests. private static class Console extends Default { /*@JVM-1.6+@ final java.io.PrintWriter writer; Console() { java.io.Console console = System.console(); writer = console != null ? console.writer() : null; } @Override protected void logMessage(String category, CharSequence message) { if (writer == null) { super.logMessage(category, message); } else { writer.print("["); writer.print(category); writer.print("] "); writer.println(message); } } /**/ } // TestContext for regression tests. private static class Regression extends TestContext { protected boolean doAssert(boolean value, CharSequence message) { if (!value) throw new AssertionException(message.toString()); return value; } protected boolean isLogged(String category) { return false; } protected void logMessage(String category, CharSequence message) { // Do nothing. } } // Allows instances of private classes to be factory produced. static { ObjectFactory.setInstance(new ObjectFactory() { protected Object create() { return new Default(); } }, Default.class); ObjectFactory.setInstance(new ObjectFactory() { protected Object create() { return new Console(); } }, CONSOLE); ObjectFactory.setInstance( new ObjectFactory() { protected Object create() { return new Regression(); } }, Regression.class); } }