/*
* Licensed to the SYSTAP, LLC under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* SYSTAP, LLC licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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>
*/
@SuppressWarnings("unchecked")
protected void flowDown( final 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 );
}
}
}