From a4562f4da1de88c66916f652659414a6d8db5bb1 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 17 Mar 2011 09:59:34 -0500 Subject: [PATCH] HHH-5942 - Migrate to JUnit 4 --- .../connections/SuppliedConnectionTest.java | 29 ++- .../cache/SQLFunctionsInterSystemsTest.java | 2 +- .../test/hql/ASTParserLoadingTest.java | 2 + .../readonly/ReadOnlyCriteriaQueryTest.java | 2 + .../org/hibernate/test/rowid/RowIdTest.java | 6 +- .../hibernate/type/BasicTypeRegistryTest.java | 8 +- .../junit4/AfterClassCallbackHandler.java | 45 +++++ .../junit4/BaseCoreFunctionalTestCase.java | 10 +- .../testing/junit4/BaseUnitTestCase.java | 6 +- .../junit4/BeforeClassCallbackHandler.java | 45 +++++ .../testing/junit4/CustomRunner.java | 172 ++++++++++-------- .../junit4/ExtendedFrameworkMethod.java | 65 ++----- .../org/hibernate/testing/junit4/Helper.java | 2 +- .../hibernate/testing/junit4/Processor.java | 118 ------------ ...ckMetadata.java => TestClassMetadata.java} | 129 ++++++++----- .../testing/junit4/TestMethodInvoker.java | 84 +++++++++ 16 files changed, 420 insertions(+), 305 deletions(-) create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/junit4/AfterClassCallbackHandler.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/junit4/BeforeClassCallbackHandler.java delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/junit4/Processor.java rename hibernate-testing/src/main/java/org/hibernate/testing/junit4/{TestClassCallbackMetadata.java => TestClassMetadata.java} (72%) create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/junit4/TestMethodInvoker.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/connections/SuppliedConnectionTest.java b/hibernate-core/src/test/java/org/hibernate/test/connections/SuppliedConnectionTest.java index 190f228792..feaa7c9b0c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/connections/SuppliedConnectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/connections/SuppliedConnectionTest.java @@ -35,6 +35,10 @@ import org.hibernate.service.jdbc.connections.spi.ConnectionProvider; import org.hibernate.service.spi.Stoppable; import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.junit.Before; + +import org.hibernate.testing.AfterClassOnce; +import org.hibernate.testing.BeforeClassOnce; import org.hibernate.testing.env.ConnectionProviderBuilder; /** @@ -46,6 +50,23 @@ public class SuppliedConnectionTest extends ConnectionManagementTestCase { private ConnectionProvider cp = ConnectionProviderBuilder.buildConnectionProvider(); private Connection connectionUnderTest; + @BeforeClassOnce + private void prepareConnectionProvider() { + cp = ConnectionProviderBuilder.buildConnectionProvider(); + } + + @AfterClassOnce + private void releaseConnectionProvider() { + try { + if ( cp instanceof Stoppable ) { + ( ( Stoppable ) cp ).stop(); + } + cp = null; + } + catch( Throwable ignore ) { + } + } + @Override protected Session getSessionUnderTest() throws Throwable { connectionUnderTest = cp.getConnection(); @@ -131,14 +152,6 @@ public class SuppliedConnectionTest extends ConnectionManagementTestCase { } } } - try { - if ( cp instanceof Stoppable ) { - ( ( Stoppable ) cp ).stop(); - } - cp = null; - } - catch( Throwable ignore ) { - } super.cleanupTest(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/cache/SQLFunctionsInterSystemsTest.java b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/cache/SQLFunctionsInterSystemsTest.java index b8cc91ffc8..68c50ff0cb 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/cache/SQLFunctionsInterSystemsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/cache/SQLFunctionsInterSystemsTest.java @@ -71,7 +71,7 @@ public class SQLFunctionsInterSystemsTest extends BaseCoreFunctionalTestCase { "legacy/AltSimple.hbm.xml", "legacy/Broken.hbm.xml", "legacy/Blobber.hbm.xml", - "dialect/cache/TestInterSystemsFunctionsClass.hbm.xml" + "dialect/functional/cache/TestInterSystemsFunctionsClass.hbm.xml" }; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java index 68d5aed8db..9bba8f3df6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java @@ -2060,6 +2060,8 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase { txn.commit(); session.close(); + + createdAnimalIds.clear(); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/readonly/ReadOnlyCriteriaQueryTest.java b/hibernate-core/src/test/java/org/hibernate/test/readonly/ReadOnlyCriteriaQueryTest.java index 90c0ff99bb..d7a47f6edf 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/readonly/ReadOnlyCriteriaQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/readonly/ReadOnlyCriteriaQueryTest.java @@ -72,6 +72,8 @@ public class ReadOnlyCriteriaQueryTest extends AbstractReadOnlyTest { @Test public void testModifiableSessionDefaultCriteria() { + clearCounts(); + Session s = openSession(); Transaction t = s.beginTransaction(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/rowid/RowIdTest.java b/hibernate-core/src/test/java/org/hibernate/test/rowid/RowIdTest.java index 431ef1fc9e..98058f5a27 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/rowid/RowIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/rowid/RowIdTest.java @@ -63,7 +63,11 @@ public class RowIdTest extends BaseCoreFunctionalTestCase { @Override public void execute(Connection connection) throws SQLException { Statement st = connection.createStatement(); - st.execute( "drop table Point"); + try { + st.execute( "drop table Point"); + } + catch (Exception ignored) { + } st.execute("create table Point (\"x\" number(19,2) not null, \"y\" number(19,2) not null, description varchar2(255) )"); st.close(); } diff --git a/hibernate-core/src/test/java/org/hibernate/type/BasicTypeRegistryTest.java b/hibernate-core/src/test/java/org/hibernate/type/BasicTypeRegistryTest.java index 485a582488..ec517de67c 100644 --- a/hibernate-core/src/test/java/org/hibernate/type/BasicTypeRegistryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/type/BasicTypeRegistryTest.java @@ -47,10 +47,10 @@ import org.hibernate.usertype.UserType; * @author Steve Ebersole */ public class BasicTypeRegistryTest extends BaseUnitTestCase { - private final BasicTypeRegistry registry = new BasicTypeRegistry(); - @Test public void testOverriding() { + BasicTypeRegistry registry = new BasicTypeRegistry(); + BasicType type = registry.getRegisteredType( "uuid-binary" ); assertSame( UUIDBinaryType.INSTANCE, type ); type = registry.getRegisteredType( UUID.class.getName() ); @@ -70,6 +70,8 @@ public class BasicTypeRegistryTest extends BaseUnitTestCase { @Test public void testExpanding() { + BasicTypeRegistry registry = new BasicTypeRegistry(); + BasicType type = registry.getRegisteredType( SomeNoopType.INSTANCE.getName() ); assertNull( type ); @@ -81,6 +83,8 @@ public class BasicTypeRegistryTest extends BaseUnitTestCase { @Test public void testRegisteringUserTypes() { + BasicTypeRegistry registry = new BasicTypeRegistry(); + registry.register( new TotallyIrrelevantUserType(), new String[] { "key" } ); BasicType type = registry.getRegisteredType( "key" ); assertNotNull( type ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/AfterClassCallbackHandler.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/AfterClassCallbackHandler.java new file mode 100644 index 0000000000..5437a2a959 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/AfterClassCallbackHandler.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.testing.junit4; + +import org.junit.runners.model.Statement; + +/** + * @author Steve Ebersole + */ +public class AfterClassCallbackHandler extends Statement { + private final CustomRunner runner; + private final Statement wrappedStatement; + + public AfterClassCallbackHandler(CustomRunner runner, Statement wrappedStatement) { + this.runner = runner; + this.wrappedStatement = wrappedStatement; + } + + @Override + public void evaluate() throws Throwable { + wrappedStatement.evaluate(); + runner.getTestClassMetadata().performAfterClassCallbacks( runner.getTestInstance() ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java index 066889d7b8..a4cc77c16b 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java @@ -43,6 +43,7 @@ import org.hibernate.cfg.Environment; import org.hibernate.cfg.Mappings; import org.hibernate.dialect.Dialect; import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.engine.SessionImplementor; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.jdbc.Work; import org.hibernate.mapping.Collection; @@ -53,7 +54,6 @@ import org.hibernate.service.internal.ServiceRegistryImpl; import org.junit.After; import org.junit.Before; -import org.junit.runner.RunWith; import org.hibernate.testing.AfterClassOnce; import org.hibernate.testing.BeforeClassOnce; @@ -73,9 +73,9 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase { public static final String VALIDATE_DATA_CLEANUP = "hibernate.test.validateDataCleanup"; public static final Dialect DIALECT = Dialect.getDialect(); - private static Configuration configuration; - private static ServiceRegistryImpl serviceRegistry; - private static SessionFactoryImplementor sessionFactory; + private Configuration configuration; + private ServiceRegistryImpl serviceRegistry; + private SessionFactoryImplementor sessionFactory; private org.hibernate.classic.Session session; @@ -317,7 +317,7 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase { public final void afterTest() throws Exception { cleanupTest(); - if ( session != null && session.isOpen() ) { + if ( session != null && ! ( (SessionImplementor) session ).isClosed() ) { if ( session.isConnected() ) { session.doWork( new RollbackWork() ); } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseUnitTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseUnitTestCase.java index 7000d78eb2..92af171bfe 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseUnitTestCase.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseUnitTestCase.java @@ -28,22 +28,18 @@ import javax.transaction.SystemException; import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper; import org.junit.After; -import org.junit.Rule; import org.junit.runner.RunWith; import org.hibernate.testing.TestLogger; import org.hibernate.testing.jta.TestingJtaBootstrap; /** - * The most test adapter. Applies both the {@link CustomRunner} and {@link Processor} rule. + * The base unit test adapter. * * @author Steve Ebersole */ @RunWith( CustomRunner.class ) public abstract class BaseUnitTestCase { - @Rule - public Processor processor = new Processor(); - @After public void releaseTransactions() { if ( JtaStatusHelper.isActive( TestingJtaBootstrap.INSTANCE.getTransactionManager() ) ) { diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BeforeClassCallbackHandler.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BeforeClassCallbackHandler.java new file mode 100644 index 0000000000..d24466d62b --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BeforeClassCallbackHandler.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.testing.junit4; + +import org.junit.runners.model.Statement; + +/** + * @author Steve Ebersole + */ +public class BeforeClassCallbackHandler extends Statement { + private final CustomRunner runner; + private final Statement wrappedStatement; + + public BeforeClassCallbackHandler(CustomRunner runner, Statement wrappedStatement) { + this.runner = runner; + this.wrappedStatement = wrappedStatement; + } + + @Override + public void evaluate() throws Throwable { + runner.getTestClassMetadata().performBeforeClassCallbacks( runner.getTestInstance() ); + wrappedStatement.evaluate(); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/CustomRunner.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/CustomRunner.java index ada8c82868..6efd925966 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/CustomRunner.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/CustomRunner.java @@ -23,6 +23,7 @@ */ package org.hibernate.testing.junit4; +import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; @@ -32,12 +33,12 @@ import org.slf4j.LoggerFactory; import org.hibernate.dialect.Dialect; import org.hibernate.internal.util.StringHelper; -import org.junit.After; -import org.junit.Before; +import org.junit.Ignore; import org.junit.runner.manipulation.NoTestsRemainException; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; +import org.junit.runners.model.Statement; import org.hibernate.testing.DialectCheck; import org.hibernate.testing.FailureExpected; @@ -45,7 +46,6 @@ import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.Skip; import org.hibernate.testing.SkipForDialect; -import org.hibernate.testing.SkipLog; /** * The Hibernate-specific {@link org.junit.runner.Runner} implementation which layers {@link ExtendedFrameworkMethod} @@ -53,25 +53,75 @@ import org.hibernate.testing.SkipLog; * test should be run. * * @author Steve Ebersole - * @see Processor */ public class CustomRunner extends BlockJUnit4ClassRunner { private static final Logger log = LoggerFactory.getLogger( CustomRunner.class ); - private List computedTestMethods; + private TestClassMetadata testClassMetadata; public CustomRunner(Class clazz) throws InitializationError, NoTestsRemainException { super( clazz ); } - public List getComputedTestMethods() { - return computedTestMethods; + @Override + protected void collectInitializationErrors(List errors) { + super.collectInitializationErrors( errors ); + this.testClassMetadata = new TestClassMetadata( getTestClass().getJavaClass() ); + testClassMetadata.validate( errors ); } - public int getNumberOfComputedTestMethods() { - return getComputedTestMethods().size(); + public TestClassMetadata getTestClassMetadata() { + return testClassMetadata; } + @Override + protected Statement withBeforeClasses(Statement statement) { + return new BeforeClassCallbackHandler( + this, + super.withBeforeClasses( statement ) + ); + } + + @Override + protected Statement withAfterClasses(Statement statement) { + return new AfterClassCallbackHandler( + this, + super.withAfterClasses( statement ) + ); + } + + @Override + protected Statement methodInvoker(FrameworkMethod method, final Object test) { + final ExtendedFrameworkMethod extendedFrameworkMethod = (ExtendedFrameworkMethod) method; + + + final Statement invoker = super.methodInvoker( method, test ); + + return new TestMethodInvoker( invoker, testClassMetadata, extendedFrameworkMethod, test ); + } + + public static class FailureExpectedTestPassedException extends Exception { + public FailureExpectedTestPassedException(FrameworkMethod frameworkMethod) { + super( "Test marked as FailureExpected, but did not fail : " + Helper.extractTestName( frameworkMethod ) ); + } + } + + private Object testInstance; + + protected Object getTestInstance() throws Exception { + if ( testInstance == null ) { + testInstance = super.createTest(); + } + return testInstance; + } + + @Override + protected Object createTest() throws Exception { + return getTestInstance(); + } + + private List computedTestMethods; + @Override protected List computeTestMethods() { if ( computedTestMethods == null ) { @@ -80,67 +130,61 @@ public class CustomRunner extends BlockJUnit4ClassRunner { return computedTestMethods; } - /** - * Override the JUnit method in order to circumvent the validation check for no matching methods - */ - @Override - protected void validateInstanceMethods(List errors) { - validatePublicVoidNoArgMethods(After.class, false, errors); - validatePublicVoidNoArgMethods(Before.class, false, errors); - validateTestMethods(errors); - - computeTestMethods(); - if ( !hadAnyTests ) { - errors.add( new Exception( "No runnable methods" ) ); - } - } - - boolean hadAnyTests; - protected List doComputation() { - // First, build the callback metadata for the test class... - TestClassCallbackMetadata callbackMetadata = new TestClassCallbackMetadata( getTestClass().getJavaClass() ); - // Next, get all the test methods as understood by JUnit final List methods = super.computeTestMethods(); - hadAnyTests = methods.size() > 0; - // Now process that full list of test methods and build our custom result final List result = new ArrayList(); final boolean doValidation = Boolean.getBoolean( Helper.VALIDATE_FAILURE_EXPECTED ); int testCount = 0; + Ignore virtualIgnore; + for ( FrameworkMethod frameworkMethod : methods ) { // potentially ignore based on expected failure final FailureExpected failureExpected = Helper.locateAnnotation( FailureExpected.class, frameworkMethod, getTestClass() ); if ( failureExpected != null && !doValidation ) { - log.info( Helper.extractIgnoreMessage( failureExpected, frameworkMethod ) ); - continue; + virtualIgnore = new IgnoreImpl( Helper.extractIgnoreMessage( failureExpected, frameworkMethod ) ); } - - // see if the test should be run based on skip/requires annotations - final SkipMarker skipMarker = getSkipInfoIfSkipped( frameworkMethod ); - if ( skipMarker != null ) { - SkipLog.reportSkip( skipMarker ); - continue; + else { + virtualIgnore = convertSkipToIgnore( frameworkMethod ); } testCount++; log.trace( "adding test " + Helper.extractTestName( frameworkMethod ) + " [#" + testCount + "]" ); - result.add( new ExtendedFrameworkMethod( frameworkMethod, testCount, skipMarker, failureExpected, callbackMetadata, this ) ); + result.add( new ExtendedFrameworkMethod( frameworkMethod, virtualIgnore, failureExpected ) ); } return result; } + @SuppressWarnings( {"ClassExplicitlyAnnotation"}) + public static class IgnoreImpl implements Ignore { + private final String value; + + public IgnoreImpl(String value) { + this.value = value; + } + + @Override + public String value() { + return value; + } + + @Override + public Class annotationType() { + return Ignore.class; + } + } + private static Dialect dialect = Dialect.getDialect(); - protected SkipMarker getSkipInfoIfSkipped(FrameworkMethod frameworkMethod) { + protected Ignore convertSkipToIgnore(FrameworkMethod frameworkMethod) { // @Skip Skip skip = Helper.locateAnnotation( Skip.class, frameworkMethod, getTestClass() ); if ( skip != null ) { if ( isMatch( skip.condition() ) ) { - return buildSkipMarker( skip, frameworkMethod ); + return buildIgnore( skip ); } } @@ -150,12 +194,12 @@ public class CustomRunner extends BlockJUnit4ClassRunner { for ( Class dialectClass : skipForDialectAnn.value() ) { if ( skipForDialectAnn.strictMatching() ) { if ( dialectClass.equals( dialect.getClass() ) ) { - return buildSkipMarker( skipForDialectAnn, frameworkMethod ); + return buildIgnore( skipForDialectAnn ); } } else { if ( dialectClass.isInstance( dialect ) ) { - return buildSkipMarker( skipForDialectAnn, frameworkMethod ); + return buildIgnore( skipForDialectAnn ); } } } @@ -174,7 +218,7 @@ public class CustomRunner extends BlockJUnit4ClassRunner { } } if ( !foundMatch ) { - return buildSkipMarker( requiresDialectAnn, frameworkMethod ); + return buildIgnore( requiresDialectAnn ); } } @@ -185,7 +229,7 @@ public class CustomRunner extends BlockJUnit4ClassRunner { try { DialectCheck check = checkClass.newInstance(); if ( !check.isMatch( dialect ) ) { - return buildSkipMarker( requiresDialectFeatureAnn, frameworkMethod ); + return buildIgnore( requiresDialectFeatureAnn ); } } catch (RuntimeException e) { @@ -199,20 +243,15 @@ public class CustomRunner extends BlockJUnit4ClassRunner { return null; } - private SkipMarker buildSkipMarker(Skip skip, FrameworkMethod frameworkMethod) { - return new SkipMarker( Helper.extractTestName( frameworkMethod ), "@Skip : " + skip.message() ); + private Ignore buildIgnore(Skip skip) { + return new IgnoreImpl( "@Skip : " + skip.message() ); } - private SkipMarker buildSkipMarker(SkipForDialect skip, FrameworkMethod frameworkMethod) { - return buildSkipMarker( - frameworkMethod, - "@SkipForDialect match", - skip.comment(), - skip.jiraKey() - ); + private Ignore buildIgnore(SkipForDialect skip) { + return buildIgnore( "@SkipForDialect match", skip.comment(), skip.jiraKey() ); } - private SkipMarker buildSkipMarker(FrameworkMethod frameworkMethod, String reason, String comment, String jiraKey) { + private Ignore buildIgnore(String reason, String comment, String jiraKey) { StringBuilder buffer = new StringBuilder( reason ); if ( StringHelper.isNotEmpty( comment ) ) { buffer.append( "; " ).append( comment ); @@ -222,25 +261,15 @@ public class CustomRunner extends BlockJUnit4ClassRunner { buffer.append( " (" ).append( jiraKey ).append( ')' ); } - return new SkipMarker( Helper.extractTestName( frameworkMethod ), buffer.toString() ); + return new IgnoreImpl( buffer.toString() ); } - private SkipMarker buildSkipMarker(RequiresDialect requiresDialect, FrameworkMethod frameworkMethod) { - return buildSkipMarker( - frameworkMethod, - "@RequiresDialect non-match", - requiresDialect.comment(), - requiresDialect.jiraKey() - ); + private Ignore buildIgnore(RequiresDialect requiresDialect) { + return buildIgnore( "@RequiresDialect non-match", requiresDialect.comment(), requiresDialect.jiraKey() ); } - private SkipMarker buildSkipMarker(RequiresDialectFeature requiresDialectFeature, FrameworkMethod frameworkMethod) { - return buildSkipMarker( - frameworkMethod, - "@RequiresDialectFeature non-match", - requiresDialectFeature.comment(), - requiresDialectFeature.jiraKey() - ); + private Ignore buildIgnore(RequiresDialectFeature requiresDialectFeature) { + return buildIgnore( "@RequiresDialectFeature non-match", requiresDialectFeature.comment(), requiresDialectFeature.jiraKey() ); } private boolean isMatch(Class condition) { @@ -258,4 +287,5 @@ public class CustomRunner extends BlockJUnit4ClassRunner { super( "Unable to instantiate specified Matcher [" + matcherClass.getName(), cause ); } } + } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/ExtendedFrameworkMethod.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/ExtendedFrameworkMethod.java index 86f68c026d..089e5acea6 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/ExtendedFrameworkMethod.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/ExtendedFrameworkMethod.java @@ -23,73 +23,37 @@ */ package org.hibernate.testing.junit4; -import org.hibernate.testing.FailureExpected; -import org.junit.runners.model.FrameworkMethod; - import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.List; +import org.junit.Ignore; +import org.junit.runners.model.FrameworkMethod; + +import org.hibernate.testing.FailureExpected; + /** * Defines an extension to the standard JUnit {@link FrameworkMethod} information about a test method. * * @author Steve Ebersole */ public class ExtendedFrameworkMethod extends FrameworkMethod { - private static final Object[] NO_ARGS = new Object[0]; - private final FrameworkMethod delegatee; - private final int runPosition; - private final SkipMarker skipMarker; - private final FailureExpected failureExpectedAnnotation; - private final TestClassCallbackMetadata callbackMetadata; - private final CustomRunner unitRunner; + private final Ignore virtualIgnore; + private final FailureExpected failureExpectedAnnotation; - public ExtendedFrameworkMethod( - FrameworkMethod delegatee, - int runPosition, - SkipMarker skipMarker, - FailureExpected failureExpectedAnnotation, - TestClassCallbackMetadata callbackMetadata, - CustomRunner unitRunner) { + public ExtendedFrameworkMethod(FrameworkMethod delegatee, Ignore virtualIgnore, FailureExpected failureExpectedAnnotation) { super( delegatee.getMethod() ); this.delegatee = delegatee; - this.runPosition = runPosition; - this.skipMarker = skipMarker; + this.virtualIgnore = virtualIgnore; this.failureExpectedAnnotation = failureExpectedAnnotation; - this.callbackMetadata = callbackMetadata; - this.unitRunner = unitRunner; } - public CustomRunner getUnitRunner() { - return unitRunner; + public FailureExpected getFailureExpectedAnnotation() { + return failureExpectedAnnotation; } - public SkipMarker getSkipMarker() { - return skipMarker; - } - - public boolean isFirstInTestClass() { - return runPosition == 1; - } - - public boolean isLastInTestClass() { - return runPosition >= unitRunner.getNumberOfComputedTestMethods(); - } - - public boolean isMarkedAsFailureExpected() { - return failureExpectedAnnotation != null; - } - - public FailureExpected getFailureExpectedAnnotation() { - return failureExpectedAnnotation; - } - - public TestClassCallbackMetadata getCallbackMetadata() { - return callbackMetadata; - } - - @Override + @Override public Method getMethod() { return delegatee.getMethod(); } @@ -120,6 +84,7 @@ public class ExtendedFrameworkMethod extends FrameworkMethod { } @Override + @SuppressWarnings( {"EqualsWhichDoesntCheckParameterClass"}) public boolean equals(Object obj) { return delegatee.equals( obj ); } @@ -140,7 +105,11 @@ public class ExtendedFrameworkMethod extends FrameworkMethod { } @Override + @SuppressWarnings( {"unchecked"}) public T getAnnotation(Class annotationType) { + if ( Ignore.class.equals( annotationType ) && virtualIgnore != null ) { + return (T) virtualIgnore; + } return delegatee.getAnnotation( annotationType ); } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/Helper.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/Helper.java index 6a540f2b1f..bcd0975166 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/Helper.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/Helper.java @@ -91,7 +91,7 @@ public class Helper { } public static String extractIgnoreMessage(FailureExpected failureExpected, FrameworkMethod frameworkMethod) { - return new StringBuilder( "Not adding test [" ) + return new StringBuilder( "Ignoring test [" ) .append( Helper.extractTestName( frameworkMethod ) ) .append( "] due to @FailureExpected - " ) .append( extractMessage( failureExpected ) ) diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/Processor.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/Processor.java deleted file mode 100644 index 80e60ac458..0000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/Processor.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2011, Red Hat Inc. or third-party contributors as - * indicated by the @author tags or express copyright attribution - * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Inc. - * - * This copyrighted material is made available to anyone wishing to use, modify, - * copy, or redistribute it subject to the terms and conditions of the GNU - * Lesser General Public License, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this distribution; if not, write to: - * Free Software Foundation, Inc. - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301 USA - */ -package org.hibernate.testing.junit4; - -import org.junit.rules.MethodRule; -import org.junit.runners.model.FrameworkMethod; -import org.junit.runners.model.Statement; - -import org.hibernate.testing.FailureExpected; -import org.hibernate.testing.SkipLog; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A custom JUnit {@link MethodRule} which essentially acts as "around advice" for test method execution. Works - * in conjunction with the information collected as part of {@link CustomRunner}. - * - * @author Steve Ebersole - * @see CustomRunner - */ -public class Processor implements MethodRule { - private static final Logger log = LoggerFactory.getLogger( Processor.class ); - - public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object target) { - log.trace( "Preparing to start test {}", Helper.extractTestName( frameworkMethod ) ); - if ( ! ExtendedFrameworkMethod.class.isInstance( frameworkMethod ) ) { - throw new IllegalStateException( - "Use of " + getClass().getName() + " only supported in combination with use of " - + CustomRunner.class.getName() - ); - } - - final ExtendedFrameworkMethod extendedFrameworkMethod = (ExtendedFrameworkMethod) frameworkMethod; - - final SkipMarker skipMarker = extendedFrameworkMethod.getSkipMarker(); - if ( skipMarker != null ) { - SkipLog.reportSkip( skipMarker ); - return new Statement() { - @Override - public void evaluate() throws Throwable { - } - }; - } - - final FailureExpected failureExpected = extendedFrameworkMethod.getFailureExpectedAnnotation(); - - return new Statement() { - @Override - public void evaluate() throws Throwable { - if ( extendedFrameworkMethod.isFirstInTestClass() ) { - extendedFrameworkMethod.getCallbackMetadata().performBeforeClassCallbacks( target ); - } - try { - statement.evaluate(); - // reaching here is expected, unless the test is marked as an expected failure - if ( failureExpected != null ) { - throw new FailureExpectedTestPassedException( extendedFrameworkMethod ); - } - } - catch ( FailureExpectedTestPassedException e ) { - // just pass this along - throw e; - } - catch ( Throwable e ) { - // on error handling is very different based on whether the test was marked as an expected failure - if ( failureExpected != null ) { - // handle the expected failure case - log.info( - "Ignoring expected failure [{}] : {}", - Helper.extractTestName( frameworkMethod ), - Helper.extractMessage( failureExpected ) - ); - extendedFrameworkMethod.getCallbackMetadata().performOnExpectedFailureCallback( target ); - // most importantly, do not propagate exception... - } - else { - // handle the non-expected failure case - extendedFrameworkMethod.getCallbackMetadata().performOnFailureCallback( target ); - throw e; - } - } - finally { - if ( extendedFrameworkMethod.isLastInTestClass() ) { - extendedFrameworkMethod.getCallbackMetadata().performAfterClassCallbacks( target ); - } - } - } - }; - } - - public static class FailureExpectedTestPassedException extends Exception { - public FailureExpectedTestPassedException(FrameworkMethod frameworkMethod) { - super( "Test marked as FailureExpected, but did not fail : " + Helper.extractTestName( frameworkMethod ) ); - } - } -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/TestClassCallbackMetadata.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/TestClassMetadata.java similarity index 72% rename from hibernate-testing/src/main/java/org/hibernate/testing/junit4/TestClassCallbackMetadata.java rename to hibernate-testing/src/main/java/org/hibernate/testing/junit4/TestClassMetadata.java index da2d7c8a29..a03d9b586f 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/TestClassCallbackMetadata.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/TestClassMetadata.java @@ -32,13 +32,14 @@ import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.LinkedHashSet; +import java.util.List; /** * Metadata about various types of callback methods on a given test class. * * @author Steve Ebersole */ -public class TestClassCallbackMetadata { +public class TestClassMetadata { private static final Object[] NO_ARGS = new Object[0]; private LinkedHashSet beforeClassOnceMethods; @@ -46,7 +47,7 @@ public class TestClassCallbackMetadata { private LinkedHashSet onFailureCallbacks; private LinkedHashSet onExpectedFailureCallbacks; - public TestClassCallbackMetadata(Class testClass) { + public TestClassMetadata(Class testClass) { processClassHierarchy( testClass ); } @@ -73,6 +74,87 @@ public class TestClassCallbackMetadata { } } + private void addBeforeClassOnceCallback(Method method) { + if ( beforeClassOnceMethods == null ) { + beforeClassOnceMethods = new LinkedHashSet(); + } + ensureAccessibility( method ); + beforeClassOnceMethods.add( method ); + } + + private void ensureAccessibility(Method method) { + if ( !method.isAccessible() ) { + try { + method.setAccessible( true ); + } + catch (Exception ignored) { + // ignore for now + } + } + } + + private void addAfterClassOnceCallback(Method method) { + if ( afterClassOnceMethods == null ) { + afterClassOnceMethods = new LinkedHashSet(); + } + ensureAccessibility( method ); + afterClassOnceMethods.add( method ); + } + + private void addOnFailureCallback(Method method) { + if ( onFailureCallbacks == null ) { + onFailureCallbacks = new LinkedHashSet(); + } + ensureAccessibility( method ); + onFailureCallbacks.add( method ); + } + + private void addOnExpectedFailureCallback(Method method) { + if ( onExpectedFailureCallbacks == null ) { + onExpectedFailureCallbacks = new LinkedHashSet(); + } + ensureAccessibility( method ); + onExpectedFailureCallbacks.add( method ); + } + + public void validate(List errors) { + validate( beforeClassOnceMethods, CallbackType.BEFORE_CLASS_ONCE, errors ); + validate( afterClassOnceMethods,CallbackType.AFTER_CLASS_ONCE, errors ); + validate( onFailureCallbacks, CallbackType.ON_FAILURE, errors ); + validate( onExpectedFailureCallbacks, CallbackType.ON_EXPECTED_FAILURE, errors ); + } + + private void validate(LinkedHashSet callbackMethods, CallbackType callbackType, List errors) { + if ( callbackMethods != null ) { + for ( Method method : callbackMethods ) { + validateCallbackMethod( method, callbackType, errors ); + } + } + } + + private void validateCallbackMethod(Method method, CallbackType type, List errors) { + if ( method.getParameterTypes().length > 0 ) { + errors.add( + new InvalidMethodForAnnotationException( + type.buildTypeMarker() + " callback only valid on no-arg methods : " + + Helper.extractMethodName( method ) + ) + ); + } + if ( !method.isAccessible() ) { + try { + method.setAccessible( true ); + } + catch (Exception e) { + errors.add( + new InvalidMethodForAnnotationException( + type.buildTypeMarker() + " attached to inaccessible method and unable to make accessible" + ) + ); + } + } + } + private static enum CallbackType { BEFORE_CLASS_ONCE( BeforeClassOnce.class ), AFTER_CLASS_ONCE( AfterClassOnce.class ), @@ -94,49 +176,6 @@ public class TestClassCallbackMetadata { } } - private void addBeforeClassOnceCallback(Method method) { - validateCallbackMethod( method, CallbackType.BEFORE_CLASS_ONCE ); - beforeClassOnceMethods = new LinkedHashSet(); - beforeClassOnceMethods.add( method ); - } - - private void validateCallbackMethod(Method method, CallbackType type) { - if ( method.getParameterTypes().length > 0 ) { - throw new InvalidMethodForAnnotationException( - type.buildTypeMarker() + " callback only valid on no-arg methods : " - + Helper.extractMethodName( method ) - ); - } - if ( !method.isAccessible() ) { - try { - method.setAccessible( true ); - } - catch (Exception e) { - throw new InvalidMethodForAnnotationException( - type.buildTypeMarker() + " attached to inaccessible method and unable to make accessible" - ); - } - } - } - - private void addAfterClassOnceCallback(Method method) { - validateCallbackMethod( method, TestClassCallbackMetadata.CallbackType.AFTER_CLASS_ONCE ); - afterClassOnceMethods = new LinkedHashSet(); - afterClassOnceMethods.add( method ); - } - - private void addOnFailureCallback(Method method) { - validateCallbackMethod( method, TestClassCallbackMetadata.CallbackType.ON_FAILURE ); - onFailureCallbacks = new LinkedHashSet(); - onFailureCallbacks.add( method ); - } - - private void addOnExpectedFailureCallback(Method method) { - validateCallbackMethod( method, TestClassCallbackMetadata.CallbackType.ON_EXPECTED_FAILURE ); - onExpectedFailureCallbacks = new LinkedHashSet(); - onExpectedFailureCallbacks.add( method ); - } - public void performBeforeClassCallbacks(Object target) { performCallbacks( beforeClassOnceMethods, target ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/TestMethodInvoker.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/TestMethodInvoker.java new file mode 100644 index 0000000000..ce2fda5b0e --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/TestMethodInvoker.java @@ -0,0 +1,84 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.testing.junit4; + +import org.junit.runners.model.Statement; + +import org.hibernate.testing.FailureExpected; +import org.hibernate.testing.TestLogger; + +/** +* @author Steve Ebersole +*/ +class TestMethodInvoker extends Statement { + private final TestClassMetadata testClassMetadata; + private final ExtendedFrameworkMethod extendedFrameworkMethod; + private final Statement realInvoker; + private final Object testInstance; + + public TestMethodInvoker( + Statement realInvoker, + TestClassMetadata testClassMetadata, + ExtendedFrameworkMethod extendedFrameworkMethod, + Object testInstance) { + this.realInvoker = realInvoker; + this.testClassMetadata = testClassMetadata; + this.extendedFrameworkMethod = extendedFrameworkMethod; + this.testInstance = testInstance; + } + + @Override + public void evaluate() throws Throwable { + final FailureExpected failureExpected = extendedFrameworkMethod.getFailureExpectedAnnotation(); + try { + realInvoker.evaluate(); + // reaching here is expected, unless the test is marked as an expected failure + if ( failureExpected != null ) { + throw new CustomRunner.FailureExpectedTestPassedException( extendedFrameworkMethod ); + } + } + catch (CustomRunner.FailureExpectedTestPassedException e) { + // just pass this along + throw e; + } + catch (Throwable e) { + // on error handling is very different based on whether the test was marked as an expected failure + if ( failureExpected != null ) { + // handle the expected failure case + TestLogger.LOG.infof( + "Ignoring expected failure [{}] : {}", + Helper.extractTestName( extendedFrameworkMethod ), + Helper.extractMessage( failureExpected ) + ); + testClassMetadata.performOnExpectedFailureCallback( testInstance ); + // most importantly, do not propagate exception... + } + else { + // handle the non-expected failure case + testClassMetadata.performOnFailureCallback( testInstance ); + throw e; + } + } + } +}