From: <fko...@us...> - 2010-09-08 20:09:19
|
Revision: 3521 http://bigdata.svn.sourceforge.net/bigdata/?rev=3521&view=rev Author: fkoliver Date: 2010-09-08 20:09:11 +0000 (Wed, 08 Sep 2010) Log Message: ----------- Remove dependency on cweb-junit-*.jar by copying the sources into this project. This is a temporary step: the extensions should be eventually be removed as we move to junit 4.x. Modified Paths: -------------- branches/maven_scaleout/bigdata-core/pom.xml branches/maven_scaleout/bigdata-core/src/test/deploy/testing/conf/standalone/ServerStarter.config branches/maven_scaleout/bigdata-core/thirdparty/maven.xml Added Paths: ----------- branches/maven_scaleout/bigdata-core/src/test/java/junit/ branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/ branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/ branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/IProxyTest.java branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/ProxyTestSuite.java branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/package.html branches/maven_scaleout/bigdata-core/src/test/java/junit/framework/ branches/maven_scaleout/bigdata-core/src/test/java/junit/framework/TestCase2.java branches/maven_scaleout/bigdata-core/src/test/java/junit/framework/package.html Removed Paths: ------------- branches/maven_scaleout/bigdata-core/thirdparty/lib/cweb-junit-ext-1.1-b3-dev.jar Property Changed: ---------------- branches/maven_scaleout/bigdata-core/ Property changes on: branches/maven_scaleout/bigdata-core ___________________________________________________________________ Added: svn:ignore + target Modified: branches/maven_scaleout/bigdata-core/pom.xml =================================================================== --- branches/maven_scaleout/bigdata-core/pom.xml 2010-09-08 14:52:29 UTC (rev 3520) +++ branches/maven_scaleout/bigdata-core/pom.xml 2010-09-08 20:09:11 UTC (rev 3521) @@ -216,12 +216,6 @@ </dependency> <dependency> <groupId>${thirdParty.groupId}</groupId> - <artifactId>cweb-junit-ext</artifactId> - <version>1.1.0-b3-dev</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>${thirdParty.groupId}</groupId> <artifactId>cweb-commons</artifactId> <version>1.1.0-b2-dev</version> </dependency> Modified: branches/maven_scaleout/bigdata-core/src/test/deploy/testing/conf/standalone/ServerStarter.config =================================================================== --- branches/maven_scaleout/bigdata-core/src/test/deploy/testing/conf/standalone/ServerStarter.config 2010-09-08 14:52:29 UTC (rev 3520) +++ branches/maven_scaleout/bigdata-core/src/test/deploy/testing/conf/standalone/ServerStarter.config 2010-09-08 20:09:11 UTC (rev 3521) @@ -59,7 +59,6 @@ libdir+"icu4j-3_6.jar"+File.pathSeparator+ // test suites only! libdir+"junit-3.8.1.jar"+File.pathSeparator+ - libdir+"cweb-junit-ext-1.1-b2-dev.jar"+File.pathSeparator+ // main bigdata JAR. //libdir+ "bigdata-core.jar" Added: branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/IProxyTest.java =================================================================== --- branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/IProxyTest.java (rev 0) +++ branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/IProxyTest.java 2010-09-08 20:09:11 UTC (rev 3521) @@ -0,0 +1,77 @@ +/** + +The Notice below must appear in each file of the Source Code of any +copy you distribute of the Licensed Product. Contributors to any +Modifications may add their own copyright notices to identify their +own contributions. + +License: + +The contents of this file are subject to the CognitiveWeb Open Source +License Version 1.1 (the License). You may not copy or use this file, +in either source code or executable form, except in compliance with +the License. You may obtain a copy of the License from + + http://www.CognitiveWeb.org/legal/license/ + +Software distributed under the License is distributed on an AS IS +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +Copyrights: + +Portions created by or assigned to CognitiveWeb are Copyright +(c) 2003-2003 CognitiveWeb. All Rights Reserved. Contact +information for CognitiveWeb is available at + + http://www.CognitiveWeb.org + +Portions Copyright (c) 2002-2003 Bryan Thompson. + +Acknowledgements: + +Special thanks to the developers of the Jabber Open Source License 1.0 +(JOSL), from which this License was derived. This License contains +terms that differ from JOSL. + +Special thanks to the CognitiveWeb Open Source Contributors for their +suggestions and support of the Cognitive Web. + +Modifications: + +*/ + +package junit.extensions.proxy; + +import junit.framework.*; + +/** + * A {@link Test} that holds a reference to a delegate. Normally the + * delegate will extend {@link TestCase} to provide, possibly + * persistent, implementation specific logic for establishing test + * fixtures. The delegate is normally an instance of your concrete + * implementation specific test harness with access to any required + * configuration data, e.g., a properties file. + */ + +public interface IProxyTest + extends Test +{ + + /** + * Sets the delegate. {@link ProxyTestSuite} uses this method to + * set the delegate on each test class instance that it creates + * that implements the {@link IProxyTest} interface. + */ + + public void setDelegate( Test delegate ); + + /** + * Returns the reference to the delegate or <code>null</code> if + * the delegate was not established. + */ + + public Test getDelegate(); + +} Property changes on: branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/IProxyTest.java ___________________________________________________________________ Added: svn:keywords + Id Date Revision Author HeadURL Added: branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/ProxyTestSuite.java =================================================================== --- branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/ProxyTestSuite.java (rev 0) +++ branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/ProxyTestSuite.java 2010-09-08 20:09:11 UTC (rev 3521) @@ -0,0 +1,395 @@ +/** + +The Notice below must appear in each file of the Source Code of any +copy you distribute of the Licensed Product. Contributors to any +Modifications may add their own copyright notices to identify their +own contributions. + +License: + +The contents of this file are subject to the CognitiveWeb Open Source +License Version 1.1 (the License). You may not copy or use this file, +in either source code or executable form, except in compliance with +the License. You may obtain a copy of the License from + + http://www.CognitiveWeb.org/legal/license/ + +Software distributed under the License is distributed on an AS IS +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +Copyrights: + +Portions created by or assigned to CognitiveWeb are Copyright +(c) 2003-2003 CognitiveWeb. All Rights Reserved. Contact +information for CognitiveWeb is available at + + http://www.CognitiveWeb.org + +Portions Copyright (c) 2002-2003 Bryan Thompson. + +Acknowledgements: + +Special thanks to the developers of the Jabber Open Source License 1.0 +(JOSL), from which this License was derived. This License contains +terms that differ from JOSL. + +Special thanks to the CognitiveWeb Open Source Contributors for their +suggestions and support of the Cognitive Web. + +Modifications: + +*/ + +package junit.extensions.proxy; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.apache.log4j.Logger; + +/** + * <p> + * A simple wrapper around {@link TestSuite} that permits the caller to specify + * the delegate {@link Test} for either directly or recursively contained + * {@link IProxyTest}s added to a {@link ProxyTestSuite}. There are three cases + * for junit: + * <ol> + * <li>An instantiated test. This is an instance of some class that extends + * {@link TestCase}. If the class implements {@link IProxyTest} then the + * <i>delegate </i> will be set on the test instance and will be available when + * that test runs.</li> + * <li>A test case. This is a class named to + * {@link TestSuite#addTestSuite(java.lang.Class)}. That method scans the test + * case class and generates an instantiated test for each conforming test method + * identified in the test case. The delegate is then set per above.</li> + * <li>A test suite. The delegate declared in a {@link ProxyTestSuite} + * constructor will be flowed down to each test added either directly or + * indirectly to that {@link ProxyTestSuite}. The various constructors all + * invoke this method to flow down the delegate. In addition, the + * {@link #addTest(Test)} and {@link #addTestSuite(Class)} methods also + * invoke this method to flow down the delegate to instantiated tests that + * implement {@link IProxyTest}.</li> + * </ol> + * </p> + * <p> + * The only case when flow down does not occur is when you have created a + * standard test suite, addeded it to a proxy test suite, and <em>then</em> + * you add additional tests to the standard test suite. There is no event + * notification model in junit and this action is not noticed by the {@link + * ProxyTestSuite}. + * </p> + */ + +public class ProxyTestSuite + extends TestSuite +{ + + /** + * The {@link Logger} is named for this class. + */ + + protected static final Logger log = Logger.getLogger + ( ProxyTestSuite.class + ); + + /** + * The delegate that will be used by each {@link IProxyTest}added to this + * {@link ProxyTestSuite}. + */ + + private final Test m_delegate; + + /** + * <p> + * Invoked automatically by the constructors. + * </p> + * + * @exception IllegalArgumentException + * if the <i>delegate </i> is <code>null</code>. + */ + + final private void checkDelegate( Test delegate ) + { + + if (delegate == null) { + + throw new IllegalArgumentException("The delegate is null."); + + } + +// if (m_delegate != null) { +// +// throw new IllegalStateException("The delegate is already set."); +// +// } + + log.debug + ( "Delegate is "+delegate.getClass().getName() + ); + + } + + /** + * Returns the <i>delegate </i> supplied to the constructor. + */ + + public Test getDelegate() { + + return m_delegate; + + } + + /** + * Creates an empty unnamed test suite. The <i>delegate </i> will be + * assigned to tests added to this test suite that implement + * {@link IProxyTest}. + * + * @param delegate + * The delegate (non-null). + */ + + public ProxyTestSuite( Test delegate ) + { + + super(); + + checkDelegate( delegate ); + + m_delegate = delegate; + + } + + /** + * Creates a named test suite and populates it with test instances + * identified by scanning the <i>testClass </i>. The <i>delegate </i> will + * be assigned to tests added to this test suite that implement + * {@link IProxyTest}, including those created from <i>testClass </i>. + * + * @param delegate + * The delegate (non-null). + * @param testClass + * A class containing one or more tests. + * @param name + * The name of the test suite (optional). + */ + + public ProxyTestSuite( Test delegate, Class testClass, String name ) + { + + /* + * Let the super class do all the heavy lifting. Note that it can not set + * the delegate for us since we can not set our private fields until after + * we have invoked the super class constructor. + */ + + super( testClass, name ); + + checkDelegate( delegate ); + + m_delegate = delegate; + + /* + * Apply delegate to all instantiated tests that were created by + * junit from testClass and which implement IProxyTest. + */ + flowDown(this); + + } + + /** + * Creates an unnamed test suite and populates it with test instances + * identified by scanning the <i>testClass </i>. The <i>delegate </i> will + * be assigned to tests added to this test suite that implement + * {@link IProxyTest}, including those created from <i>testClass </i>. + * + * @param delegate + * The delegate (non-null). + * @param testClass + * A class containing one or more tests. + */ + + public ProxyTestSuite( Test delegate, Class testClass ) + { + + /* + * Let the super class do all the heavy lifting. Note that it can not set + * the delegate for us since we can not set our private fields until after + * we have invoked the super class constructor. + */ + + super( testClass ); + + // Remember the delegate. + + checkDelegate( delegate ); + + m_delegate = delegate; + + /* + * Apply delegate to all instantiated tests that were created by + * junit from testClass and which implement IProxyTest. + */ + flowDown(this); + + } + + /** + * Creates an empty named test suite. The declared will be assigned to tests + * added to this test suite that implement {@link IProxyTest}. + * + * @param delegate + * The delegate (non-null). + * @param name + * The test suite name (optional). + */ + public ProxyTestSuite( Test delegate, String name ) + { + + super( name ); + + checkDelegate( delegate ); + + m_delegate = delegate; + + } + + /** + * We override the implementation of {@link + * TestSuite#addTestSuite( Class theClass )} to wrap the + * <i>testClass</i> in another instance of this {@link + * ProxyTestSuite} class using the same delegate that was provided + * to our constructor. This causes the delegation to be inherited + * by any recursively contained <i>testClass</i> which implements + * {@link IProxyTest}. + */ + + public void addTestSuite( Class testClass ) + { + + if( m_delegate == null ) { + + /* + * The delegate will be null if this method gets invoked from the + * super class constructor since that will happen before we have a + * chance to set the [m_delegate] field. The constructors handle + * this situation by explictly flowing down the delegate after the + * super class constructor has been invoked. + */ + + super.addTestSuite( testClass ); + + return; + + } + + // This is the default implementation from TestSuite: + // + // addTest(new TestSuite(testClass)); + // + // Our implementation just substitutes new ProxyTestSuite( + // delegate, testClass ) for new TestSuite( testClass ). + // + + ProxyTestSuite proxyTestSuite = new ProxyTestSuite + ( m_delegate, + testClass + ); + + addTest( proxyTestSuite ); + + } + + /** + * If the suite is not a {@link ProxyTestSuite}, then the tests in the + * suite are recursively enumerated and a proxy test suite is created with + * the same name and tests. This ensures that the common delegate flows down + * through all tests even when using the traditional + * <code>static Test suite() {...}</code> construction. + * + * @param test + * A test. + */ + public void addTest(Test test) { + + if( m_delegate == null ) { + + /* + * The delegate will be null if this method gets invoked from the + * super class constructor since that will happen before we have a + * chance to set the [m_delegate] field. The constructors handle + * this situation by explictly flowing down the delegate after the + * super class constructor has been invoked. + */ + + super.addTest( test ); + + return; + + } + + if ( ! (test instanceof ProxyTestSuite)) { + + /* + * Flow down the delegate to any container IProxyTest instances. + */ + + flowDown( test ); + + } + + super.addTest( test ); + + } + + protected void flowDown(Test t) { + + if (m_delegate == null) { + + throw new AssertionError("delegate is not set."); + + } + + if ( t instanceof TestSuite ) { + + flowDown( (TestSuite) t ); + + } else if (t instanceof IProxyTest) { + + log.debug("Setting delegate on " + t.getClass() + " to " + + m_delegate.getClass()); + + ((IProxyTest) t).setDelegate(m_delegate); + + } + + } + + /** + * <p> + * Sets the delegate on each instantiated {@link Test} that implements + * {@link IProxyTest}. + * </p> + */ + + protected void flowDown( TestSuite suite ) { + + if( m_delegate == null ) { + + throw new AssertionError("delegate is not set."); + + } + + for( java.util.Enumeration e= suite.tests(); e.hasMoreElements(); ) { + + Test t = (Test)e.nextElement(); + + flowDown( t ); + + } + + } + +} Property changes on: branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/ProxyTestSuite.java ___________________________________________________________________ Added: svn:keywords + Id Date Revision Author HeadURL Added: branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/package.html =================================================================== --- branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/package.html (rev 0) +++ branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/package.html 2010-09-08 20:09:11 UTC (rev 3521) @@ -0,0 +1,146 @@ +<HTML> +<HEAD> +<TITLE>Proxy test suites</TITLE> +</HEAD> +<BODY> +<H1>Integration testing with proxy test suites.</H1> +<P>This package provides support for suites of <EM>proxy</EM> tests that +share a common test <EM>delegate</EM>. Normally the proxy tests and the +delegate will implement a common interface. The implementation of the +interface on the proxy test base class should route the behaviors to the +delegate test. This mechanism can be used to run an entire test suite +against a specific configuration for integration testing. Since the same +delegate instance is used for all tests in the suite, you can do things +such as establish a shared database connection that is used for the +entire test suite, i.e., you can do <EM>integration testing</EM>.</P> +<H2>Defining a configuration using getProperties()</H2> +<P>The pattern that I have found to be most useful for integration +testing of different configurations is to define a <CODE>public +Properties getProperties()</CODE> method that is implemented by the <EM>delegate</EM> +and accessed by various integration test set up and tear down methods +implemented by the delegate. For example:</P> +<PRE> + public Properties getProperties() { + if( m_properties == null ) { + /* + * Read and cache System properties. + */ + m_properties = System.getProperties(); + } + /* + * Wrap up the cached properties so that they are not modifable by the + * caller (no side effects between calls). + */ + return new Properties( m_properties ); + } +</PRE> +<p>This approach reads properties from the environement, so you can +define property values using JVM command line arguments <CODE>-Dname=value</CODE>. +You can also extend the {@link junit.framework.TestCase2} class and use +its <CODE>getProperties()</CODE> method, in which case properties are +read from a hierarchy of sources, including a file with a <CODE>.properties</CODE> +extension and the same base name as the delegate test class.</p> +<H2>Sharing a connection</H2> +<P>In order to setup variables, such as a JDBC connection, that are +reused by each test in the suite, you need to declare those variables as +fields on the <EM>delegate</EM> implementation class and wrap the test +suite in a {@link junit.framework.TestDecorator} as follows.</P> +<pre> + public static Test suite() { + + /* + * Create the delegate instance that will be reused by all proxy tests in + * the test suite. The variable is declared as 'final' so that we can + * access it from the anonymous TestDecorator class, below. + */ + final DefaultTestCase delegate = new DefaultTestCase(); // !!!! THIS CLASS !!!! + + /* + * Use a proxy test suite and specify the delegate. + */ + + ProxyTestSuite suite = new ProxyTestSuite(delegate); + + /* + * Add some tests to the test suite. The setDelegate() method will be + * called on each test that implements IProxyTest and passed the value + * provided to the ProxyTestSuite constructor above. + */ + suite.addTestCase( MyTestCase1.class ); + + // ... more tests. + + /* + * Wrap up in decorator that connects to the database before the test + * suite is run and then disconnects from the database afterwards. + */ + return new TestDecorator(suite) { + + private boolean disconnectAfter = false; + + public void basicRun(TestResult result) { + if (!delegate.isConnected()) { + delegate.connect(); + disconnectAfter = true; + } + super.basicRun(result); + if (disconnectAfter) { + delegate.disconnect(); + } + } + + }; +</pre> +<P>While the life span of the <EM>delegate</EM> spans that of the test +suite, the <CODE>setUp</CODE> and <CODE>tearDown</CODE> methods of the +delegate are invoked before and after each test <EM>implemented by the +delegate</EM>. Since the delegate does not generally implement tests +directly, those set up and tear down methods can not be used to perform +integration testing.</P> +<H2>Running or debugging a single test</H2> +<P>By its nature, a test that implements {@link IProxyTest} requires a <em>delegate</em> +in order to run. This works fine when you are running an entire test +suite defined by the delegate, but you have to take an extra step in +order to be able to run or debug a single test. The following code gives +an example of how you can deal with this problem. It defines a property +<em>testClass</em> whose value is the name of the delegate class. If the +delegate was not set (as will be the case if you try to run a single +test directly), then this property must be specified as a JVM argument +using <code>-DtestClass=....</code> and an instance of your delegate +will be created and used to run the proxy test.</P> +<P>If you test relies on a shared variable such as a JDBC connection, +then you still have to provide for that. One way to handle this is to +delegate the <code>setUp</code> and <code>tearDown</code> methods on the +proxy test. The delegate implementation of those methods would then +establish and close the Connection iff the Connection was not already +established.</P> + +<pre> + public Test getDelegate() { + + if (m_delegate == null) { + + /* + * This property gives the class name of the concrete instance of + * testClass that we need to instantiate so that we can run or debug + * a single test at a time. + */ + String testClass = getProperties().getProperty("testClass"); + if (testClass == null) { + + throw new IllegalStateException( + "testClass: property not defined, could not configure delegate."); + + } + try { + Class cl = Class.forName(testClass); + m_delegate = (Test) cl.newInstance(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + } + } +</pre> +</BODY> +</HTML> Property changes on: branches/maven_scaleout/bigdata-core/src/test/java/junit/extensions/proxy/package.html ___________________________________________________________________ Added: svn:keywords + Id Date Revision Author HeadURL Added: branches/maven_scaleout/bigdata-core/src/test/java/junit/framework/TestCase2.java =================================================================== --- branches/maven_scaleout/bigdata-core/src/test/java/junit/framework/TestCase2.java (rev 0) +++ branches/maven_scaleout/bigdata-core/src/test/java/junit/framework/TestCase2.java 2010-09-08 20:09:11 UTC (rev 3521) @@ -0,0 +1,2230 @@ +/** + +The Notice below must appear in each file of the Source Code of any +copy you distribute of the Licensed Product. Contributors to any +Modifications may add their own copyright notices to identify their +own contributions. + +License: + +The contents of this file are subject to the CognitiveWeb Open Source +License Version 1.1 (the License). You may not copy or use this file, +in either source code or executable form, except in compliance with +the License. You may obtain a copy of the License from + + http://www.CognitiveWeb.org/legal/license/ + +Software distributed under the License is distributed on an AS IS +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +Copyrights: + +Portions created by or assigned to CognitiveWeb are Copyright +(c) 2003-2003 CognitiveWeb. All Rights Reserved. Contact +information for CognitiveWeb is available at + + http://www.CognitiveWeb.org + +Portions Copyright (c) 2002-2003 Bryan Thompson. + +Acknowledgements: + +Special thanks to the developers of the Jabber Open Source License 1.0 +(JOSL), from which this License was derived. This License contains +terms that differ from JOSL. + +Special thanks to the CognitiveWeb Open Source Contributors for their +suggestions and support of the Cognitive Web. + +Modifications: + +*/ + +package junit.framework; + +// Test resource loader. +import java.io.Externalizable; +import java.io.Reader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Serializable; + +// Properties hierarchy loader. +import java.io.File; +import java.io.FileInputStream; +import java.util.Properties; +import java.util.Random; +import java.util.TreeMap; +import java.util.Map; +import java.util.Iterator; + +// Logger. +import org.CognitiveWeb.util.PropertyUtil; +import org.apache.log4j.Logger; +import org.apache.log4j.Level; + +/** + * Extension of {@link TestCase} that supports logging, loading test + * resources, and hierarchical properties.<p> + * + * Note: When using Maven (or Ant), you need to be aware that that + * your <code>project.xml</code> has an impact on which files are + * recognized as tests to be submitted to a test runner. For example, + * it is common practice that all files beginning or ending with + * "Test" will be submitted to JUnit, though I suggest that the + * practice of naming things "FooTestCase" will serve you better. + * Also note that the maven test plugin explictly skips files whose + * name matches the pattern "*AbstractTestSuite".<p> + */ + +abstract public class TestCase2 + extends TestCase +{ + + public TestCase2() { + super(); + } + + public TestCase2(String name) { + super(name); + } + + /** + * The default {@link Logger} for this class, which is named + * "junit.framework.Test". + */ + + protected static final Logger log = Logger.getLogger + ( junit.framework.Test.class + ); + + /** + * This convenience method provides a version of {@link #fail( + * String Message )} that also excepts a {@link Throwable} cause + * for the test failure.<p> + */ + + static public void fail + ( String message, + Throwable t + ) + { + + AssertionFailedError ex = new AssertionFailedError + ( message + ); + + ex.initCause( t ); + + throw ex; + + } + + //************************************************************ + //************************************************************ + //************************************************************ + + static public void assertEquals( boolean[] expected, boolean[] actual ) + { + assertEquals( null, expected, actual ); + } + + /** + * Compares arrays of primitive values. + */ + + static public void assertEquals( String msg, boolean[] expected, boolean[] actual ) + { + + if( msg == null ) { + msg = ""; + } else { + msg = msg + " : "; + } + + if( expected == null && actual == null ) { + + return; + + } + + if( expected == null && actual != null ) { + + fail( msg+"Expected a null array." ); + + } + + if( expected != null && actual == null ) { + + fail( msg+"Not expecting a null array." ); + + } + + if (expected.length != actual.length) { + /* + * Only do message construction if we know that the assert will + * fail. + */ + assertEquals(msg + "length differs.", expected.length, + actual.length); + } + + for( int i=0; i<expected.length; i++ ) { + + if (expected[i] != actual[i]) { + /* + * Only do message construction if we know that the assert will + * fail. + */ + assertEquals(msg + "values differ: index=" + i, expected[i], + actual[i]); + } + + } + + } + + /** + * <p> + * Compares byte[]s by value (not reference). + * </p> + * <p> + * Note: This method will only be invoked if both arguments can be typed as + * byte[] by the compiler. If either argument is not strongly typed, you + * MUST case it to a byte[] or {@link #assertEquals(Object, Object)} will be + * invoked instead. + * </p> + * + * @param expected + * @param actual + */ + static public void assertEquals( byte[] expected, byte[] actual ) + { + + assertEquals( null, expected, actual ); + + } + + /** + * <p> + * Compares byte[]s by value (not reference). + * </p> + * <p> + * Note: This method will only be invoked if both arguments can be typed as + * byte[] by the compiler. If either argument is not strongly typed, you + * MUST case it to a byte[] or {@link #assertEquals(Object, Object)} will be + * invoked instead. + * </p> + * + * @param msg + * @param expected + * @param actual + */ + static public void assertEquals( String msg, byte[] expected, byte[] actual ) + { + + if( msg == null ) { + msg = ""; + } else { + msg = msg + " : "; + } + + if( expected == null && actual == null ) { + + return; + + } + + if( expected == null && actual != null ) { + + fail( msg+"Expected a null array." ); + + } + + if( expected != null && actual == null ) { + + fail( msg+"Not expecting a null array." ); + + } + + if (expected.length != actual.length) { + /* + * Only do message construction if we know that the assert will + * fail. + */ + assertEquals(msg + "length differs.", expected.length, + actual.length); + } + + for( int i=0; i<expected.length; i++ ) { + + if (expected[i] != actual[i]) { + /* + * Only do the message construction if we know that the assert + * will fail. + */ + assertEquals(msg + "values differ: index=" + i, expected[i], + actual[i]); + } + + } + + } + + static public void assertEquals( char[] expected, char[] actual ) + { + assertEquals( null, expected, actual ); + } + + static public void assertEquals( String msg, char[] expected, char[] actual ) + { + + if( msg == null ) { + msg = ""; + } else { + msg = msg + " : "; + } + + if( expected == null && actual == null ) { + + return; + + } + + if( expected == null && actual != null ) { + + fail( msg+"Expected a null array." ); + + } + + if( expected != null && actual == null ) { + + fail( msg+"Not expecting a null array." ); + + } + + if (expected.length != actual.length) { + /* + * Only do message construction if we know that the assert will + * fail. + */ + assertEquals(msg + "length differs.", expected.length, + actual.length); + } + + for( int i=0; i<expected.length; i++ ) { + + if (expected[i] != actual[i]) { + /* + * Only do the message construction if we know that the assert + * will fail. + */ + assertEquals(msg + "values differ: index=" + i, expected[i], + actual[i]); + } + + } + + } + + static public void assertEquals( short[] expected, short[] actual ) + { + assertEquals( null, expected, actual ); + } + + static public void assertEquals( String msg, short[] expected, short[] actual ) + { + + if( msg == null ) { + msg = ""; + } else { + msg = msg + " : "; + } + + if( expected == null && actual == null ) { + + return; + + } + + if( expected == null && actual != null ) { + + fail( msg+"Expected a null array." ); + + } + + if( expected != null && actual == null ) { + + fail( msg+"Not expecting a null array." ); + + } + + if (expected.length != actual.length) { + /* + * Only do message construction if we know that the assert will + * fail. + */ + assertEquals(msg + "length differs.", expected.length, + actual.length); + } + + for( int i=0; i<expected.length; i++ ) { + + if (expected[i] != actual[i]) { + /* + * Only do the message construction if we know that the assert + * will fail. + */ + assertEquals(msg + "values differ: index=" + i, expected[i], + actual[i]); + } + + } + + } + + static public void assertEquals( int[] expected, int[] actual ) + { + + assertEquals( null, expected, actual ); + + } + + static public void assertEquals( String msg, int[] expected, int[] actual ) + { + + if( msg == null ) { + msg = ""; + } else { + msg = msg + " : "; + } + + if( expected == null && actual == null ) { + + return; + + } + + if( expected == null && actual != null ) { + + fail( msg+"Expected a null array." ); + + } + + if( expected != null && actual == null ) { + + fail( msg+"Not expecting a null array." ); + + } + + if (expected.length != actual.length) { + /* + * Only do message construction if we know that the assert will + * fail. + */ + assertEquals(msg + "length differs.", expected.length, + actual.length); + } + + for( int i=0; i<expected.length; i++ ) { + + if (expected[i] != actual[i]) { + /* + * Only do the message construction if we know that the assert + * will fail. + */ + assertEquals(msg + "values differ: index=" + i, expected[i], + actual[i]); + } + + } + + } + + static public void assertEquals( long[] expected, long[] actual ) + { + assertEquals( null, expected, actual ); + } + + static public void assertEquals( String msg, long[] expected, long[] actual ) + { + + if( msg == null ) { + msg = ""; + } else { + msg = msg + " : "; + } + + if( expected == null && actual == null ) { + + return; + + } + + if( expected == null && actual != null ) { + + fail( msg+"Expected a null array." ); + + } + + if( expected != null && actual == null ) { + + fail( msg+"Not expecting a null array." ); + + } + + if (expected.length != actual.length) { + /* + * Only do message construction if we know that the assert will + * fail. + */ + assertEquals(msg + "length differs.", expected.length, + actual.length); + } + + for( int i=0; i<expected.length; i++ ) { + + if (expected[i] != actual[i]) { + /* + * Only do the message construction if we know that the assert + * will fail. + */ + assertEquals(msg + "values differ: index=" + i, expected[i], + actual[i]); + + } + + } + + } + + static public void assertEquals( float[] expected, float[] actual ) + { + assertEquals( null, expected, actual ); + } + + /** + * @todo Use smarter floating point comparison and offer parameter + * for controlling the floating point comparison. + */ + static public void assertEquals( String msg, float[] expected, float[] actual ) + { + + if( msg == null ) { + msg = ""; + } else { + msg = msg + " : "; + } + + if( expected == null && actual == null ) { + + return; + + } + + if( expected == null && actual != null ) { + + fail( msg+"Expected a null array." ); + + } + + if( expected != null && actual == null ) { + + fail( msg+"Not expecting a null array." ); + + } + + if (expected.length != actual.length) { + /* + * Only do message construction if we know that the assert will + * fail. + */ + assertEquals(msg + "length differs.", expected.length, + actual.length); + } + + for( int i=0; i<expected.length; i++ ) { + + float delta = 0f; + + try { + + assertEquals(expected[i], actual[i], delta); + + } catch (AssertionFailedError ex) { + + /* + * Only do the message construction once the assertion is known + * to fail. + */ + fail(msg + "values differ: index=" + i, ex); + + } + + } + + } + + static public void assertEquals( double[] expected, double[] actual ) + { + assertEquals( null, expected, actual ); + } + + /** + * @todo Use smarter floating point comparison and offer parameter + * for controlling the floating point comparison. + */ + static public void assertEquals( String msg, double[] expected, double[] actual ) + { + + if( msg == null ) { + msg = ""; + } else { + msg = msg + " : "; + } + + if( expected == null && actual == null ) { + + return; + + } + + if( expected == null && actual != null ) { + + fail( msg+"Expected a null array." ); + + } + + if( expected != null && actual == null ) { + + fail( msg+"Not expecting a null array." ); + + } + + if (expected.length != actual.length) { + /* + * Only do message construction if we know that the assert will + * fail. + */ + assertEquals(msg + "length differs.", expected.length, + actual.length); + } + + for( int i=0; i<expected.length; i++ ) { + + double delta = 0.0d; + + try { + + assertEquals(expected[i], actual[i], delta); + + } catch (AssertionFailedError ex) { + + /* + * Only do the message construction once the assertion is known + * to fail. + */ + fail(msg + "values differ: index=" + i, ex); + + } + + } + + } + + static public void assertEquals( Object[] expected, Object[] actual ) + { + assertEquals( null, expected, actual ); + } + + /** + * Compares arrays of {@link Object}s. The length of the arrays + * must agree, and each array element must agree. However the + * class of the arrays does NOT need to agree, e.g., an Object[] + * MAY compare as equals with a String[]. + */ + + static public void assertEquals( String msg, Object[] expected, Object[] actual ) + { + + if( msg == null ) { + msg = ""; + } else { + msg = msg + " : "; + } + + if( expected == null && actual == null ) { + + return; + + } + + if( expected == null && actual != null ) { + + fail( msg+"Expected a null array." ); + + } + + if( expected != null && actual == null ) { + + fail( msg+"Not expecting a null array." ); + + } + + if (expected.length != actual.length) { + /* + * Only do message construction if we know that the assert will + * fail. + */ + assertEquals(msg + "length differs.", expected.length, + actual.length); + } + + for( int i=0; i<expected.length; i++ ) { + + try { + + assertEquals(expected[i], actual[i]); + + } catch (AssertionFailedError ex) { + + /* + * Only do the message construction once the assertion is known + * to fail. + */ + + fail(msg + "values differ: index=" + i, ex); + + } + + } + + } + + //************************************************************ + //************************************************************ + //************************************************************ + + /** + * Test helper that can correctly compare arrays of primitives and + * arrays of objects as well as primitives and objects. + */ + static public void assertSameValue( Object expected, Object actual ) + { + assertSameValue( null, expected, actual ); + } + + /** + * Test helper that can correctly compare arrays of primitives and + * arrays of objects as well as primitives and objects. + * + * @todo This will throw a {@link ClassCastException} if + * <i>actual</i> is of a different primitive array type. Change + * the code to throw {@link AssertionFailedError} instead. + */ + static public void assertSameValue( String msg, Object expected, Object actual ) + { + + if( expected != null && expected.getClass().isArray() ) { + + if( expected.getClass().getComponentType().isPrimitive() ) { + + Class componentType = expected.getClass().getComponentType(); + + if( componentType.equals( Boolean.TYPE ) ) { + + assertEquals + ( msg, + (boolean[]) expected, + (boolean[]) actual + ); + + } else if( componentType.equals( Byte.TYPE ) ) { + + assertEquals + ( msg, + (byte[]) expected, + (byte[]) actual + ); + + } else if( componentType.equals( Character.TYPE ) ) { + + assertEquals + ( msg, + (char[]) expected, + (char[]) actual + ); + + } else if( componentType.equals( Short.TYPE ) ) { + + assertEquals + ( msg, + (short[]) expected, + (short[]) actual + ); + + } else if( componentType.equals( Integer.TYPE ) ) { + + assertEquals + ( msg, + (int[]) expected, + (int[]) actual + ); + + } else if( componentType.equals( Long.TYPE ) ) { + + assertEquals + ( msg, + (long[]) expected, + (long[]) actual + ); + + } else if( componentType.equals( Float.TYPE ) ) { + + assertEquals + ( msg, + (float[]) expected, + (float[]) actual + ); + + } else if( componentType.equals( Double.TYPE ) ) { + + assertEquals + ( msg, + (double[]) expected, + (double[]) actual + ); + + } else { + + throw new AssertionError(); + + } + + } else { + + assertTrue + ( msg, + java.util.Arrays.equals + ( (Object[]) expected, + (Object[]) actual + ) + ); + + } + + } else { + + assertEquals + ( msg, + expected, + actual + ); + + } + + } + + //************************************************************ + //************************************************************ + //************************************************************ + + /** + * Method verifies that the <i>actual</i> {@link Iterator} + * produces the expected objects in the expected order. Objects + * are compared using {@link Object#equals( Object other )}. Errors + * are reported if too few or too many objects are produced, etc. + */ + + static public void assertSameIterator + ( Object[] expected, + Iterator actual + ) + { + + assertSameIterator + ( "", + expected, + actual + ); + + } + + /** + * Method verifies that the <i>actual</i> {@link Iterator} + * produces the expected objects in the expected order. Objects + * are compared using {@link Object#equals( Object other )}. Errors + * are reported if too few or too many objects are produced, etc. + */ + + static public void assertSameIterator + ( String msg, + Object[] expected, + Iterator actual + ) + { + + int i = 0; + + while( actual.hasNext() ) { + + if( i >= expected.length ) { + + fail( msg+": The iterator is willing to visit more than "+ + expected.length+ + " objects." + ); + + } + + Object g = actual.next(); + +// if (!expected[i].equals(g)) { + try { + assertSameValue(expected[i],g); + } catch(AssertionFailedError ex) { + /* + * Only do message construction if we know that the assert will + * fail. + */ + fail(msg + ": Different objects at index=" + i + ": expected=" + + expected[i] + ", actual=" + g); + } + + i++; + + } + + if( i < expected.length ) { + + fail( msg+": The iterator SHOULD have visited "+expected.length+ + " objects, but only visited "+i+ + " objects." + ); + + } + + } + + /** + * Verifies that the iterator visits the specified objects in some + * arbitrary ordering and that the iterator is exhausted once all + * expected objects have been visited. The implementation uses a + * selection without replacement "pattern". + */ + + static public void assertSameIteratorAnyOrder + ( Comparable[] expected, + Iterator actual + ) + { + + assertSameIteratorAnyOrder + ( "", + expected, + actual + ); + + } + + /** + * Verifies that the iterator visits the specified objects in some + * arbitrary ordering and that the iterator is exhausted once all + * expected objects have been visited. The implementation uses a + * selection without replacement "pattern". + * + * FIXME Write test cases for this one. + * + * FIXME Can we we this without requiring the objects to implement + * {@link Comparable}? + */ + + static public void assertSameIteratorAnyOrder + ( String msg, + Comparable[] expected, + Iterator actual + ) + { + + // Populate a map that we will use to realize the match and + // selection without replacement logic. + + final int nrange = expected.length; + + java.util.Map range = new java.util.TreeMap(); + + for( int j=0; j<nrange; j++ ) { + + range.put + ( expected[ j ], + expected[ j ] + ); + + } + + // Do selection without replacement for the objects visited by + // iterator. + + for( int j=0; j<nrange; j++ ) { + + if( ! actual.hasNext() ) { + + fail( msg+": Index exhausted while expecting more object(s)"+ + ": index="+j + ); + + } + + Object actualObject = actual.next(); + + if( range.remove( actualObject ) == null ) { + + fail( "Object not expected"+ + ": index="+j+ + ", object="+actualObject + ); + + } + + } + + if( actual.hasNext() ) { + + fail( "Iterator will deliver too many objects." + ); + + } + + } + + //************************************************************ + //************************************************************ + //************************************************************ + + /** + * Test helper produces a random sequence of indices in the range [0:n-1] + * suitable for visiting the elements of an array of n elements in a random + * order. This is useful when you want to randomize the presentation of + * elements from two or more arrays. For example, known keys and values can + * be generated and their presentation order randomized by indexing with the + * returned array. + */ + + public static int[] getRandomOrder( final int n ) + { + + final class Pair + implements Comparable + { + public double r = Math.random(); + public int val; + public Pair( int val ) {this.val = val;} + public int compareTo(Object other) + { + if( this == other ) return 0; + if( this.r < ((Pair)other).r ) return -1; + else return 1; + } + + } + + Pair[] pairs = new Pair[ n ]; + + for( int i=0; i<n; i++ ) { + + pairs[ i ] = new Pair( i ); + + } + + java.util.Arrays.sort( pairs ); + + int order[] = new int[ n ]; + + for( int i=0; i<n; i++ ) { + + order[ i ] = pairs[ i ].val; + + } + + return order; + + } + + /** + * Random number generator used by {@link #getNormalInt( int range + * )}. + */ + + private Random m_random = new Random(); + + /** + * Returns a random integer normally distributed in [0:range]. + */ + + public int getNormalInt( int range ) + { + + final double bound = 3d; + + double rand = m_random.nextGaussian(); + + if( rand < -bound ) rand = -bound; + else if( rand > bound ) rand = bound; + + rand = ( rand + bound ) / ( 2 * bound ); + // normal distribution in [0:1]. + + if( rand < 0d ) rand = 0d; + // make sure it is not slightly + // negative + + int r = (int)( rand * range ); + + if( r > range ) { + + throw new AssertionError(); + + } + + return r; + + // @todo develop a test case for this method based on the code + // in comments below and migrate into TestCase2 (junit-ext + // package). + +// int[] r = new int[10000]; + +// for( int i=0; i<r.length; i++ ) { + +// r[ i ] = getNormalInt( len ); + +// } + +// java.util.Arrays.sort( r ); + + + } + + /** + * Returns a random but unique string of Unicode characters with a + * maximum length of len and a minimum length. + * + * @param len The maximum length of the string. Each generated + * literal will have a mean length of <code>len/2</code> and the + * lengths will be distributed using a normal distribution (bell + * curve). + * + * @param id A unique index used to obtain a unique string. + * Typically this is a one up identifier. + */ + + public String getRandomString( int len, int id ) + { + +// final String data = "0123456789!@#$%^&*()`~-_=+[{]}\\|;:'\",<.>/?QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; + final String data = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; + + int[] order = getRandomOrder( data.length() ); + + int n = getNormalInt( len ); + + StringBuffer sb = new StringBuffer( n ); + + int index = 0; + + for( int i=0; i<n; i++ ) { + + sb.append( data.charAt( order[ index++ ] ) ); + + if( index == order.length ) { + + index = 0; + + } + + } + + sb.append( id ); + + return sb.toString(); + + } + + /** + * Used to create objects of random type. + * + * @todo support generation of random array types and dates. + * + * @author thompsonbry + */ + protected class RandomType + { + + /** + * An explicit NULL property value. + */ + + final public static short NULL = 0; + +// /** +// * A directed link to another generic object in the same store. +// * +// * @see LinkValue +// */ +// +// final public static short LINK = 1; +// +// /** +// * A BLOB (metadata that supports access to very large binary +// * objects using a stream oriented API). +// */ +// +// final public static short BLOB = 2; + + /** + * The Java primitive type <em>boolean</em>. + * + * Note: Support for primitives recognizes the corresponding + * objects, e.g., {@link Boolean}, and special cases their + * serialization. This significantly reduces their the storage + * requirements. + */ + + final public static short BOOLEAN = 20; + final public static short BYTE = 21; + final public static short CHAR = 22; + final public static short SHORT = 23; + final public static short INT = 24; + final public static short LONG = 25; + final public static short FLOAT = 26; + final public static short DOUBLE = 27; + + /** + * Java Object (must implement {@link Serializable} or {@link + * Externalizable}). + */ + + final public static short OBJECT = 30; + + /** + * Array of Java objects (but not Java primitives). + */ + + final public static short OBJECT_ARRAY = 31; + + /** + * Array of Java primitives. + */ + + final public static short BOOLEAN_ARRAY = 40; + final public static short BYTE_ARRAY = 41; + final public static short CHAR_ARRAY = 42; + final public static short SHORT_ARRAY = 43; + final public static short INT_ARRAY = 44; + final public static short LONG_ARRAY = 45; + final public static short FLOAT_ARRAY = 46; + final public static short DOUBLE_ARRAY = 47; + + final public int[] randomType = new int[] { +// LINK, +// BLOB, + BOOLEAN, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, + OBJECT, +// OBJECT_ARRAY, +// BOOLEAN_ARRAY, +// BYTE_ARRAY, +// CHAR_ARRAY, +// SHORT_ARRAY, +// INT_ARRAY, +// LONG_ARRAY, +// FLOAT_ARRAY, +// DOUBLE_ARRAY, + NULL // Note: null at end to make easy to exclude. + }; + + /** + * For random characters. + */ + static final private String alphabet = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; + + /** + * Returns an object with a random type and random value. + * + * @param rnd The random# generator to use. + * + * @param allowNull When true, a null object reference may be + * returned. + * + * @return The random object. + */ + + public Object nextObject( Random rnd, boolean allowNull ) + { + + int[] types = randomType; + + int range = types.length; + + if( ! allowNull ) range--; // exclude null from types. + + int type = types[ rnd.nextInt( range ) ]; + + Object obj = null; + + switch( type ) { + + case NULL: { + return null; + } + case BOOLEAN: { + obj = ( rnd.nextBoolean() + ? Boolean.TRUE + : Boolean.FALSE + ); + break; + } + case BYTE: { + obj = new Byte( (byte) ( rnd.nextInt( 255 ) - 127 ) ); + break; + } + case CHAR: { + obj = new Character( alphabet.charAt( rnd.nextInt( alphabet.length() ) ) ); + break; + } + case SHORT: { + obj = new Short( (short) rnd.nextInt() ); + break; + } + case INT: { + obj = new Integer( rnd.nextInt() ); + break; + } + case LONG: { + obj = new Long( rnd.nextLong() ); + break; + } + case FLOAT: { + obj = new Float( rnd.nextFloat() ); + break; + } + case DOUBLE: { + obj = new Double( rnd.nextDouble() ); + break; + } + case OBJECT: { + obj = getRandomString( 40, rnd.nextInt() ); + break; + } +// OBJECT_ARRAY, +// BOOLEAN_ARRAY, +// BYTE_ARRAY, +// CHAR_ARRAY, +// SHORT_ARRAY, +// INT_ARRAY, +// LONG_ARRAY, +// FLOAT_ARRAY, +// DOUBLE_ARRAY + default: { + throw new AssertionError( "unknown type="+type ); + } + + } + + return obj; + + } + + } + + private RandomType _randomType = new RandomType(); + + /** + * Returns an object with a random type and random value. + * + * @param allowNull When true, a null object reference may be + * returned. + * + * @return The random object. + */ + + public Object getRandomObject( boolean allowNull ) + { + + return _randomType.nextObject( m_random, allowNull ); + + } + + /** + * Returns an object with a random type and random value. + * + * @param rnd The random generator. ... [truncated message content] |