diff --git a/README.md b/README.md index 6a89ffd..c30864a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ A collection of useful JUnit rules from Unruly's codebases ``` -## Ignore tests until a certain date. +## Ignore tests until a certain date or datetime. This allows you to write an acceptance/integration test before implementing a feature, and integrate it into your codebase before the implementation is complete. @@ -27,6 +27,12 @@ IgnoreUntilRule rule = new IgnoreUntilRule(); @Test public void example_test_ignored_until_a_date() { +} + +@IgnoreUntil("2014-10-30T17:30:00") +@Test +public void example_test_ignored_until_a_datetime() { + } ``` diff --git a/src/main/java/co/unruly/junit/IgnoreUntilRule.java b/src/main/java/co/unruly/junit/IgnoreUntilRule.java index 33048ac..bd200ba 100644 --- a/src/main/java/co/unruly/junit/IgnoreUntilRule.java +++ b/src/main/java/co/unruly/junit/IgnoreUntilRule.java @@ -5,11 +5,15 @@ import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; +import java.util.regex.Pattern; import static org.joda.time.format.DateTimeFormat.forPattern; public class IgnoreUntilRule implements TestRule { + private static final Pattern DATE_REGEX = Pattern.compile("\\d{4}-\\d{2}-\\d{2}"); + private static final Pattern DATETIME_REGEX = Pattern.compile("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}"); + @Override public Statement apply(Statement base, Description description) { @@ -24,13 +28,22 @@ public Statement apply(Statement base, Description description) { } String ignoreUntilDate = ignoreUntil.value(); - - DateTime annotationDate = forPattern("yyyy-MM-dd").parseDateTime(ignoreUntilDate); + DateTime annotationDate = parseDateTime(ignoreUntilDate); return annotationDate.isAfterNow() ? new AlwaysPassesStatement() : base; } + private DateTime parseDateTime(String datetime) { + if (DATE_REGEX.matcher(datetime).matches()) { + return forPattern("yyyy-MM-dd").parseDateTime(datetime); + } else if (DATETIME_REGEX.matcher(datetime).matches()) { + return forPattern("yyyy-MM-dd'T'HH:mm:ss").parseDateTime(datetime); + } else { + throw new IllegalArgumentException("Please provide correct datetime pattern, one of: \nyyyy-MM-dd\nyyyy-MM-ddTHH:mm:ss"); + } + } + public static class AlwaysPassesStatement extends Statement { @Override public void evaluate() throws Throwable { diff --git a/src/test/java/co/unruly/junit/IgnoreUntilRuleTest.java b/src/test/java/co/unruly/junit/IgnoreUntilRuleTest.java index a91e658..a6529ff 100644 --- a/src/test/java/co/unruly/junit/IgnoreUntilRuleTest.java +++ b/src/test/java/co/unruly/junit/IgnoreUntilRuleTest.java @@ -20,6 +20,8 @@ public class IgnoreUntilRuleTest { @Mock Statement mockStatement; @Mock IgnoreUntil mockIgnoreUntilAnnotation; @Mock Description mockDescription; + private final static String DATE_PATTERN = "yyyy-MM-dd"; + private final static String DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss"; @InjectMocks IgnoreUntilRule rule = new IgnoreUntilRule(); @@ -27,13 +29,40 @@ public class IgnoreUntilRuleTest { @Test public void shouldReturnOriginalStatementIfAnnotationNotPresent() { when(mockDescription.getAnnotation(IgnoreUntil.class)).thenReturn(null); + assertEquals(mockStatement, rule.apply(mockStatement, mockDescription)); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldThrowExceptionIfDateTimeFormatInvalid() { + when(mockDescription.getAnnotation(IgnoreUntil.class)).thenReturn(mockIgnoreUntilAnnotation); + when(mockIgnoreUntilAnnotation.value()).thenReturn("invalid"); + + rule.apply(mockStatement, mockDescription); + } + + @Test + public void shouldReturnOriginalStatementIfIgnoreUntilDateTimeIsInThePast() { + String oneSecondBefore = new DateTime().minusSeconds(1).toString(DATETIME_PATTERN); + + when(mockDescription.getAnnotation(IgnoreUntil.class)).thenReturn(mockIgnoreUntilAnnotation); + when(mockIgnoreUntilAnnotation.value()).thenReturn(oneSecondBefore); assertEquals(mockStatement, rule.apply(mockStatement, mockDescription)); } + @Test + public void shouldReturnAlwaysPassesStatementIfIgnoreUntilDateTimeIsInTheFuture() { + String oneSecondLater = new DateTime().plusSeconds(1).toString(DATETIME_PATTERN); + + when(mockDescription.getAnnotation(IgnoreUntil.class)).thenReturn(mockIgnoreUntilAnnotation); + when(mockIgnoreUntilAnnotation.value()).thenReturn(oneSecondLater); + + assertTrue(rule.apply(mockStatement, mockDescription) instanceof IgnoreUntilRule.AlwaysPassesStatement); + } + @Test public void shouldReturnOriginalStatementIfIgnoreUntilDateIsInThePast() { - String twoDaysAgo = new DateTime().minusDays(2).toString("yyyy-MM-dd"); + String twoDaysAgo = new DateTime().minusDays(2).toString(DATE_PATTERN); when(mockDescription.getAnnotation(IgnoreUntil.class)).thenReturn(mockIgnoreUntilAnnotation); when(mockIgnoreUntilAnnotation.value()).thenReturn(twoDaysAgo); @@ -41,9 +70,19 @@ public void shouldReturnOriginalStatementIfIgnoreUntilDateIsInThePast() { assertEquals(mockStatement, rule.apply(mockStatement, mockDescription)); } + @Test + public void shouldReturnOriginalStatementIfIgnoreUntilDateSameAsCurrentDate() { + String sameDay = new DateTime().toString(DATE_PATTERN); + + when(mockDescription.getAnnotation(IgnoreUntil.class)).thenReturn(mockIgnoreUntilAnnotation); + when(mockIgnoreUntilAnnotation.value()).thenReturn(sameDay); + + assertEquals(mockStatement, rule.apply(mockStatement, mockDescription)); + } + @Test public void shouldReturnAlwaysPassesStatementIfIgnoreUntilDateIsInTheFuture() { - String tomorrow = new DateTime().plusDays(1).toString("yyyy-MM-dd"); + String tomorrow = new DateTime().plusDays(1).toString(DATE_PATTERN); when(mockDescription.getAnnotation(IgnoreUntil.class)).thenReturn(mockIgnoreUntilAnnotation); when(mockIgnoreUntilAnnotation.value()).thenReturn(tomorrow);