diff --git a/annotations/src/test/java/org/hibernate/test/annotations/cid/CompositeIdTest.java b/annotations/src/test/java/org/hibernate/test/annotations/cid/CompositeIdTest.java index 4e896eb63f..03715d035e 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/cid/CompositeIdTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/cid/CompositeIdTest.java @@ -9,11 +9,10 @@ import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.Criteria; -import org.hibernate.dialect.HSQLDialect; import org.hibernate.criterion.Disjunction; import org.hibernate.criterion.Restrictions; +import org.hibernate.junit.SkipForDialect; import org.hibernate.test.annotations.TestCase; -import org.hibernate.test.annotations.SkipForDialect; /** * test some composite id functionalities diff --git a/annotations/src/test/java/org/hibernate/test/annotations/idclass/xml/IdClassXmlTest.java b/annotations/src/test/java/org/hibernate/test/annotations/idclass/xml/IdClassXmlTest.java index 6d7828455a..1d4756e189 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/idclass/xml/IdClassXmlTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/idclass/xml/IdClassXmlTest.java @@ -22,20 +22,17 @@ */ package org.hibernate.test.annotations.idclass.xml; -import org.hibernate.Query; -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.test.annotations.FailureExpected; +import org.hibernate.junit.FailureExpected; import org.hibernate.test.annotations.TestCase; /** - * HHH-4282 + * A test for HHH-4282 * * @author Hardy Ferentschik */ +@FailureExpected( jiraKey = "HHH-4282" ) public class IdClassXmlTest extends TestCase { - @FailureExpected public void testEntityMappningPropertiesAreNotIgnored() { throw new RuntimeException(); // Session s = openSession(); diff --git a/annotations/src/test/java/org/hibernate/test/annotations/idclassgeneratedvalue/IdClassGeneratedValueTest.java b/annotations/src/test/java/org/hibernate/test/annotations/idclassgeneratedvalue/IdClassGeneratedValueTest.java index 76eb23a092..c8dc10fb52 100755 --- a/annotations/src/test/java/org/hibernate/test/annotations/idclassgeneratedvalue/IdClassGeneratedValueTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/idclassgeneratedvalue/IdClassGeneratedValueTest.java @@ -27,7 +27,7 @@ import java.util.List; import org.hibernate.Session; -import org.hibernate.test.annotations.FailureExpected; +import org.hibernate.junit.FailureExpected; import org.hibernate.test.annotations.TestCase; /** @@ -60,7 +60,7 @@ public void testBaseLine() { s.close(); } - @FailureExpected(message = "Not yet implemented", issueNumber = "HHH-4552") + @FailureExpected(message = "Not yet implemented", jiraKey = "HHH-4552") @SuppressWarnings({ "unchecked" }) public void testSingleGeneratedValue() { Session s = openSession(); @@ -85,7 +85,7 @@ public void testSingleGeneratedValue() { s.close(); } - @FailureExpected(message = "Not yet implemented", issueNumber = "HHH-4552") + @FailureExpected(message = "Not yet implemented", jiraKey = "HHH-4552") @SuppressWarnings({ "unchecked" }) public void testMultipleGeneratedValue() { Session s = openSession(); diff --git a/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java b/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java index 56c82da89b..c99bed5a2d 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/indexcoll/IndexedCollectionTest.java @@ -12,9 +12,9 @@ import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.dialect.HSQLDialect; +import org.hibernate.junit.RequiresDialect; import org.hibernate.mapping.Collection; import org.hibernate.mapping.Column; -import org.hibernate.test.annotations.RequiresDialect; import org.hibernate.test.annotations.TestCase; /** diff --git a/annotations/src/test/java/org/hibernate/test/annotations/lob/ImageTest.java b/annotations/src/test/java/org/hibernate/test/annotations/lob/ImageTest.java index a24cb75a45..dba0a7becc 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/lob/ImageTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/lob/ImageTest.java @@ -32,7 +32,7 @@ import org.hibernate.dialect.Sybase11Dialect; import org.hibernate.dialect.SybaseASE15Dialect; import org.hibernate.dialect.SybaseDialect; -import org.hibernate.test.annotations.RequiresDialect; +import org.hibernate.junit.RequiresDialect; import org.hibernate.test.annotations.TestCase; import org.hibernate.util.ArrayHelper; diff --git a/annotations/src/test/java/org/hibernate/test/annotations/lob/TextTest.java b/annotations/src/test/java/org/hibernate/test/annotations/lob/TextTest.java index 46414cceb7..e942ce6e62 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/lob/TextTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/lob/TextTest.java @@ -32,7 +32,7 @@ import org.hibernate.dialect.Sybase11Dialect; import org.hibernate.dialect.SybaseASE15Dialect; import org.hibernate.dialect.SybaseDialect; -import org.hibernate.test.annotations.RequiresDialect; +import org.hibernate.junit.RequiresDialect; import org.hibernate.test.annotations.TestCase; import org.hibernate.util.ArrayHelper; diff --git a/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/ManyToOneWithFormulaTest.java b/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/ManyToOneWithFormulaTest.java index f6fa232511..521ae93f6b 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/ManyToOneWithFormulaTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/ManyToOneWithFormulaTest.java @@ -29,7 +29,7 @@ import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.dialect.HSQLDialect; -import org.hibernate.test.annotations.SkipForDialect; +import org.hibernate.junit.SkipForDialect; import org.hibernate.test.annotations.TestCase; /** diff --git a/annotations/src/test/java/org/hibernate/test/annotations/onetomany/OneToManyTest.java b/annotations/src/test/java/org/hibernate/test/annotations/onetomany/OneToManyTest.java index 03447e7dff..fb8da6710e 100644 --- a/annotations/src/test/java/org/hibernate/test/annotations/onetomany/OneToManyTest.java +++ b/annotations/src/test/java/org/hibernate/test/annotations/onetomany/OneToManyTest.java @@ -12,11 +12,9 @@ import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; -import org.hibernate.dialect.HSQLDialect; import org.hibernate.test.annotations.Customer; import org.hibernate.test.annotations.Discount; import org.hibernate.test.annotations.Passport; -import org.hibernate.test.annotations.RequiresDialect; import org.hibernate.test.annotations.TestCase; import org.hibernate.test.annotations.Ticket; import org.hibernate.test.annotations.TicketComparator; diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/callbacks/CallbacksTest.java b/entitymanager/src/test/java/org/hibernate/ejb/test/callbacks/CallbacksTest.java index b918bc0e56..f5f74c8744 100644 --- a/entitymanager/src/test/java/org/hibernate/ejb/test/callbacks/CallbacksTest.java +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/callbacks/CallbacksTest.java @@ -10,7 +10,7 @@ import org.hibernate.ejb.test.Cat; import org.hibernate.ejb.test.Kitten; import org.hibernate.ejb.test.TestCase; -import org.hibernate.test.annotations.FailureExpected; +import org.hibernate.junit.FailureExpected; /** * @author Emmanuel Bernard @@ -168,7 +168,7 @@ public void testIdNullSetByPrePersist() throws Exception { em.close(); } - @FailureExpected(message = "collection change does not trigger an event", issueNumber = "EJB-288") + @FailureExpected(message = "collection change does not trigger an event", jiraKey = "EJB-288") public void testPostUpdateCollection() throws Exception { // create a cat EntityManager em = getOrCreateEntityManager(); diff --git a/entitymanager/src/test/java/org/hibernate/ejb/test/lob/BlobTest.java b/entitymanager/src/test/java/org/hibernate/ejb/test/lob/BlobTest.java index d3e99aa1fb..5abeec3085 100644 --- a/entitymanager/src/test/java/org/hibernate/ejb/test/lob/BlobTest.java +++ b/entitymanager/src/test/java/org/hibernate/ejb/test/lob/BlobTest.java @@ -12,7 +12,6 @@ import org.hibernate.Hibernate; import org.hibernate.dialect.Dialect; import org.hibernate.ejb.test.TestCase; -import org.hibernate.test.annotations.FailureExpected; /** * @author Emmanuel Bernard diff --git a/testing/src/main/java/org/hibernate/test/annotations/FailureExpected.java b/testing/src/main/java/org/hibernate/junit/FailureExpected.java similarity index 80% rename from testing/src/main/java/org/hibernate/test/annotations/FailureExpected.java rename to testing/src/main/java/org/hibernate/junit/FailureExpected.java index d9149604eb..e05bdadc6f 100644 --- a/testing/src/main/java/org/hibernate/test/annotations/FailureExpected.java +++ b/testing/src/main/java/org/hibernate/junit/FailureExpected.java @@ -1,4 +1,3 @@ -// $Id$ /* * Hibernate, Relational Persistence for Idiomatic Java * @@ -22,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.test.annotations; +package org.hibernate.junit; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -30,13 +29,23 @@ import java.lang.annotation.Target; /** - * Annotations used to mark a expected test failure. + * Annotations used to mark a test as an expected failure. * * @author Hardy Ferentschik + * @author Steve Ebersole */ -@Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE }) public @interface FailureExpected { + /** + * The key of a JIRA issue which covers this expected failure. + * @return The jira issue key + */ + String jiraKey(); + + /** + * A message explaining the reason for the expected failure. Optional. + * @return The reason + */ String message() default ""; - String issueNumber() default ""; } \ No newline at end of file diff --git a/testing/src/main/java/org/hibernate/test/annotations/RequiresDialect.java b/testing/src/main/java/org/hibernate/junit/RequiresDialect.java similarity index 77% rename from testing/src/main/java/org/hibernate/test/annotations/RequiresDialect.java rename to testing/src/main/java/org/hibernate/junit/RequiresDialect.java index c31af23225..d0ecb3cd20 100644 --- a/testing/src/main/java/org/hibernate/test/annotations/RequiresDialect.java +++ b/testing/src/main/java/org/hibernate/junit/RequiresDialect.java @@ -1,4 +1,3 @@ -// $Id$ /* * Hibernate, Relational Persistence for Idiomatic Java * @@ -22,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.test.annotations; +package org.hibernate.junit; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -32,12 +31,24 @@ import org.hibernate.dialect.Dialect; /** - * Annotations used to mark a test to be specific to a given dialect. + * Annotation used to indicate that a test should be run only when run against the + * indicated dialects. * * @author Hardy Ferentschik */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface RequiresDialect { + /** + * The dialects against which to run the test + * @return The dialects + */ Class[] value(); + + /** + * Used to indicate if the dialects should be matched strictly (classes equal) or + * non-strictly (instanceof). + * @return Should strict matching be used? + */ + boolean strictMatching() default false; } diff --git a/testing/src/main/java/org/hibernate/test/annotations/SkipForDialect.java b/testing/src/main/java/org/hibernate/junit/SkipForDialect.java similarity index 65% rename from testing/src/main/java/org/hibernate/test/annotations/SkipForDialect.java rename to testing/src/main/java/org/hibernate/junit/SkipForDialect.java index 86f3b1f0c7..a2392704d5 100644 --- a/testing/src/main/java/org/hibernate/test/annotations/SkipForDialect.java +++ b/testing/src/main/java/org/hibernate/junit/SkipForDialect.java @@ -1,4 +1,3 @@ -// $Id$ /* * Hibernate, Relational Persistence for Idiomatic Java * @@ -22,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.test.annotations; +package org.hibernate.junit; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -32,14 +31,38 @@ import org.hibernate.dialect.Dialect; /** - * Annotations used to mark a test to be specific to a given dialect. + * Annotation used to indicate that a test should be skipped when run against the + * indicated dialects. * * @author Hardy Ferentschik + * @author Steve Ebersole */ -@Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE }) public @interface SkipForDialect { + /** + * The dialects against which to skip the test + * @return The dialects + */ Class[] value(); - String comment(); + /** + * Used to indicate if the dialects should be matched strictly (classes equal) or + * non-strictly (instanceof). + * @return Should strict matching be used? + */ + boolean strictMatching() default false; + + /** + * Comment describing the reason for the skip. + * @return The comment + */ + String comment() default ""; + + /** + * The key of a JIRA issue which covers the reason for this skip. Eventually we should make this + * a requirement. + * @return The jira issue key + */ + String jiraKey() default ""; } \ No newline at end of file diff --git a/testing/src/main/java/org/hibernate/test/annotations/HibernateTestCase.java b/testing/src/main/java/org/hibernate/test/annotations/HibernateTestCase.java index 89a267ed93..7fbe41e939 100644 --- a/testing/src/main/java/org/hibernate/test/annotations/HibernateTestCase.java +++ b/testing/src/main/java/org/hibernate/test/annotations/HibernateTestCase.java @@ -1,4 +1,3 @@ -// $Id:$ /* * Hibernate, Relational Persistence for Idiomatic Java * @@ -24,6 +23,7 @@ */ package org.hibernate.test.annotations; +import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -40,6 +40,9 @@ import org.hibernate.cfg.Configuration; import org.hibernate.dialect.Dialect; import org.hibernate.jdbc.Work; +import org.hibernate.junit.FailureExpected; +import org.hibernate.junit.RequiresDialect; +import org.hibernate.junit.SkipForDialect; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.util.StringHelper; @@ -57,11 +60,6 @@ public abstract class HibernateTestCase extends TestCase { private static Class lastTestClass; - /** - * The test method. - */ - private Method runMethod = null; - /** * Flag indicating whether the test should be run or skipped. */ @@ -87,78 +85,162 @@ public HibernateTestCase(String x) { } @Override - protected void setUp() throws Exception { - runMethod = findTestMethod(); - setRunTestFlag( runMethod ); - if ( runTest ) { - if ( cfg == null || lastTestClass != getClass() ) { - buildConfiguration(); - lastTestClass = getClass(); + public void runBare() throws Throwable { + Method runMethod = findTestMethod(); + + final Skip skip = determineSkipByDialect( Dialect.getDialect(), runMethod ); + if ( skip != null ) { + reportSkip( skip ); + return; + } + + setUp(); + try { + runTest(); + } + finally { + tearDown(); + } + } + + @Override + protected void runTest() throws Throwable { + Method runMethod = findTestMethod(); + FailureExpected failureExpected = locateAnnotation( FailureExpected.class, runMethod ); + try { + super.runTest(); + if ( failureExpected != null ) { + throw new FailureExpectedTestPassedException(); + } + } + catch ( FailureExpectedTestPassedException t ) { + closeResources(); + throw t; + } + catch ( Throwable t ) { + if ( t instanceof InvocationTargetException ) { + t = ( ( InvocationTargetException ) t ).getTargetException(); + } + if ( t instanceof IllegalAccessException ) { + t.fillInStackTrace(); + } + closeResources(); + if ( failureExpected != null) { + StringBuilder builder = new StringBuilder(); + if ( StringHelper.isNotEmpty( failureExpected.message() ) ) { + builder.append( failureExpected.message() ); + } + else { + builder.append( "ignoring @FailureExpected test" ); + } + builder.append( " (" ) + .append( failureExpected.jiraKey() ) + .append( ")" ); + reportSkip( "Failed with: " + t.toString(), builder.toString() ); } else { - runSchemaGeneration(); + throw t; } } } + @Override + protected void setUp() throws Exception { + if ( cfg == null || lastTestClass != getClass() ) { + buildConfiguration(); + lastTestClass = getClass(); + } + else { + runSchemaGeneration(); + } + } + @Override protected void tearDown() throws Exception { runSchemaDrop(); handleUnclosedResources(); } - protected void runTest() throws Throwable { - if ( runTest ) { - runTestMethod( runMethod ); + protected static class Skip { + private final String reason; + private final String testDescription; + + public Skip(String reason, String testDescription) { + this.reason = reason; + this.testDescription = testDescription; } } - private void setRunTestFlag(Method runMethod) { - updateRequiredDialectList( runMethod ); - updateSkipForDialectList( runMethod ); + protected final Skip determineSkipByDialect(Dialect dialect, Method runMethod) { + // skips have precedence, so check them first + SkipForDialect skipForDialectAnn = locateAnnotation( SkipForDialect.class, runMethod ); + if ( skipForDialectAnn != null ) { + for ( Class dialectClass : skipForDialectAnn.value() ) { + if ( skipForDialectAnn.strictMatching() ) { + if ( dialectClass.equals( dialect.getClass() ) ) { + return buildSkip( dialect, skipForDialectAnn.comment(), skipForDialectAnn.jiraKey() ); + } + } + else { + if ( dialectClass.isInstance( dialect ) ) { + return buildSkip( dialect, skipForDialectAnn.comment(), skipForDialectAnn.jiraKey() ); + } + } + } + } - if ( runForCurrentDialect() ) { - runTest = true; - } - else { - log.warn( - "Skipping test {}, because test does not apply for dialect {}", runMethod.getName(), Dialect - .getDialect().getClass() - ); - runTest = false; + // then check against the requires + RequiresDialect requiresDialectAnn = locateAnnotation( RequiresDialect.class, runMethod ); + if ( requiresDialectAnn != null ) { + for ( Class dialectClass : requiresDialectAnn.value() ) { + if ( requiresDialectAnn.strictMatching() ) { + if ( dialectClass.equals( dialect.getClass() ) ) { + return buildSkip( dialect, null, null ); + } + } + else { + if ( dialectClass.isInstance( dialect ) ) { + return buildSkip( dialect, null, null ); + } + } + } } + + return null; } - private void updateRequiredDialectList(Method runMethod) { - requiredDialectList.clear(); - - RequiresDialect requiresDialectMethodAnn = runMethod.getAnnotation( RequiresDialect.class ); - if ( requiresDialectMethodAnn != null ) { - Class[] requiredDialects = requiresDialectMethodAnn.value(); - requiredDialectList.addAll( Arrays.asList( requiredDialects ) ); + protected T locateAnnotation(Class annotationClass, Method runMethod) { + T annotation = runMethod.getAnnotation( annotationClass ); + if ( annotation == null ) { + annotation = getClass().getAnnotation( annotationClass ); } - - RequiresDialect requiresDialectClassAnn = getClass().getAnnotation( RequiresDialect.class ); - if ( requiresDialectClassAnn != null ) { - Class[] requiredDialects = requiresDialectClassAnn.value(); - requiredDialectList.addAll( Arrays.asList( requiredDialects ) ); + if ( annotation == null ) { + annotation = runMethod.getDeclaringClass().getAnnotation( annotationClass ); } + return annotation; } - private void updateSkipForDialectList(Method runMethod) { - skipForDialectList.clear(); + protected Skip buildSkip(Dialect dialect, String comment, String jiraKey) { + StringBuilder buffer = new StringBuilder(); + buffer.append( "skipping database-specific test [" ); + buffer.append( fullTestName() ); + buffer.append( "] for dialect [" ); + buffer.append( dialect.getClass().getName() ); + buffer.append( ']' ); - SkipForDialect skipForDialectMethodAnn = runMethod.getAnnotation( SkipForDialect.class ); - if ( skipForDialectMethodAnn != null ) { - Class[] skipDialects = skipForDialectMethodAnn.value(); - skipForDialectList.addAll( Arrays.asList( skipDialects ) ); + if ( StringHelper.isNotEmpty( comment ) ) { + buffer.append( "; " ).append( comment ); } - SkipForDialect skipForDialectClassAnn = getClass().getAnnotation( SkipForDialect.class ); - if ( skipForDialectClassAnn != null ) { - Class[] skipDialects = skipForDialectClassAnn.value(); - skipForDialectList.addAll( Arrays.asList( skipDialects ) ); + if ( StringHelper.isNotEmpty( jiraKey ) ) { + buffer.append( " (" ).append( jiraKey ).append( ')' ); } + + return new Skip( buffer.toString(), null ); + } + + public String fullTestName() { + return this.getClass().getName() + "#" + this.getName(); } protected boolean runForCurrentDialect() { @@ -185,48 +267,6 @@ protected boolean runForCurrentDialect() { return runTestForCurrentDialect; } - private void runTestMethod(Method runMethod) throws Throwable { - boolean failureExpected = runMethod.getAnnotation( FailureExpected.class ) != null; - try { - runMethod.invoke( this, new Class[0] ); - if ( failureExpected ) { - throw new FailureExpectedTestPassedException(); - } - } - catch ( FailureExpectedTestPassedException t ) { - closeResources(); - throw t; - } - catch ( Throwable t ) { - if ( t instanceof InvocationTargetException ) { - t = ( ( InvocationTargetException ) t ).getTargetException(); - } - if ( t instanceof IllegalAccessException ) { - t.fillInStackTrace(); - } - closeResources(); - if ( failureExpected ) { - FailureExpected ann = runMethod.getAnnotation( FailureExpected.class ); - StringBuilder builder = new StringBuilder(); - if ( StringHelper.isNotEmpty( ann.message() ) ) { - builder.append( ann.message() ); - } - else { - builder.append( "ignoring test methods annoated with @FailureExpected" ); - } - if ( StringHelper.isNotEmpty( ann.issueNumber() ) ) { - builder.append( " (" ); - builder.append( ann.issueNumber() ); - builder.append( ")" ); - } - reportSkip( builder.toString(), "Failed with: " + t.toString() ); - } - else { - throw t; - } - } - } - private Method findTestMethod() { String fName = getName(); assertNotNull( fName ); @@ -288,12 +328,14 @@ protected void runSchemaDrop() { export.drop( true, true ); } + private void reportSkip(Skip skip) { + reportSkip( skip.reason, skip.testDescription ); + } + protected void reportSkip(String reason, String testDescription) { StringBuilder builder = new StringBuilder(); builder.append( "*** skipping test [" ); - builder.append( runMethod.getDeclaringClass().getName() ); - builder.append( "." ); - builder.append( runMethod.getName() ); + builder.append( fullTestName() ); builder.append( "] - " ); builder.append( testDescription ); builder.append( " : " );