From 587d8186f4274c234cfdf619672bdf924cb69aa0 Mon Sep 17 00:00:00 2001 From: Aaron Davis Date: Wed, 7 Dec 2016 16:28:09 -0800 Subject: [PATCH] Adding in verifiers for the Instant and Duration types --- README.md | 2 +- pom.xml | 2 +- .../redfin/validity/VerifiableFactory.java | 91 +++++--- .../verifiers/objects/VerifiableDuration.java | 96 +++++++++ .../verifiers/objects/VerifiableInstant.java | 47 ++++ .../objects/VerifiableDurationTest.java | 201 ++++++++++++++++++ .../objects/VerifiableInstantTest.java | 87 ++++++++ 7 files changed, 495 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/redfin/validity/verifiers/objects/VerifiableDuration.java create mode 100644 src/main/java/com/redfin/validity/verifiers/objects/VerifiableInstant.java create mode 100644 src/test/java/com/redfin/validity/verifiers/objects/VerifiableDurationTest.java create mode 100644 src/test/java/com/redfin/validity/verifiers/objects/VerifiableInstantTest.java diff --git a/README.md b/README.md index dc18368..ed7e948 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ To install, you can simply include the dependency from Maven Central: com.redfin validity - 2.1.0 + 2.2.0 ``` diff --git a/pom.xml b/pom.xml index b3de72f..1c04130 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.redfin validity - 1.0-SNAPSHOT + 2.2.0 4.0.0 jar diff --git a/src/main/java/com/redfin/validity/VerifiableFactory.java b/src/main/java/com/redfin/validity/VerifiableFactory.java index 496ebb3..fa1dcbe 100644 --- a/src/main/java/com/redfin/validity/VerifiableFactory.java +++ b/src/main/java/com/redfin/validity/VerifiableFactory.java @@ -31,7 +31,9 @@ import com.redfin.validity.verifiers.objects.VerifiableClass; import com.redfin.validity.verifiers.objects.VerifiableCollection; import com.redfin.validity.verifiers.objects.VerifiableDouble; +import com.redfin.validity.verifiers.objects.VerifiableDuration; import com.redfin.validity.verifiers.objects.VerifiableFloat; +import com.redfin.validity.verifiers.objects.VerifiableInstant; import com.redfin.validity.verifiers.objects.VerifiableInteger; import com.redfin.validity.verifiers.objects.VerifiableLong; import com.redfin.validity.verifiers.objects.VerifiableObject; @@ -45,6 +47,9 @@ import com.redfin.validity.verifiers.primitives.VerifiablePrimitiveInt; import com.redfin.validity.verifiers.primitives.VerifiablePrimitiveLong; import com.redfin.validity.verifiers.primitives.VerifiablePrimitiveShort; + +import java.time.Duration; +import java.time.Instant; import java.util.Collection; /** @@ -242,6 +247,10 @@ public VerifiablePrimitiveShort that(short subject) { // Objects // - - - - - - - - - - - - - - - - - - - - - - + // - - - - - - - - - - - - - - - - - + // Boxed Primitive Types + // - - - - - - - - - - - - - - - - - + /** * @param subject the object to perform validation on. * @return a {@link VerifiableBoolean} instance for the given subject. @@ -266,25 +275,6 @@ public VerifiableCharacter that(Character subject) { return new VerifiableCharacter<>(failedValidationExecutor, subject, message); } - /** - * @param subject the object to perform validation on. - * @param the class being validated. - * @return a {@link VerifiableClass} instance for the given subject. - */ - public VerifiableClass that(Class subject) { - return new VerifiableClass<>(failedValidationExecutor, subject, message); - } - - /** - * @param subject the object to perform validation on. - * @param the type of the objects in the collection. - * @param the type of the Collection (e.g. list, map, etc). - * @return a {@link VerifiableCollection} instance for the given subject. - */ - public > VerifiableCollection that(T subject) { - return new VerifiableCollection<>(failedValidationExecutor, subject, message); - } - /** * @param subject the object to perform validation on. * @return a {@link VerifiableDouble} instance for the given subject. @@ -318,23 +308,54 @@ public VerifiableLong that(Long subject) { } /** - * This is the default object validation for subjects that - * don't match any of the other pre-defined types. - * * @param subject the object to perform validation on. - * @param the type of the subject. - * @return a {@link VerifiableObject} instance for the given subject. + * @return a {@link VerifiableShort} instance for the given subject. */ - public VerifiableObject that(T subject) { - return new VerifiableObject<>(failedValidationExecutor, subject, message); + public VerifiableShort that(Short subject) { + return new VerifiableShort<>(failedValidationExecutor, subject, message); } + // - - - - - - - - - - - - - - - - - + // Time Object Types + // - - - - - - - - - - - - - - - - - + /** * @param subject the object to perform validation on. - * @return a {@link VerifiableShort} instance for the given subject. + * @return a {@link VerifiableDuration} instance for the given subject. */ - public VerifiableShort that(Short subject) { - return new VerifiableShort<>(failedValidationExecutor, subject, message); + public VerifiableDuration that(Duration subject) { + return new VerifiableDuration<>(failedValidationExecutor, subject, message); + } + + /** + * @param subject the object to perform validation on. + * @return a {@link VerifiableInstant} instance for the given subject. + */ + public VerifiableInstant that(Instant subject) { + return new VerifiableInstant<>(failedValidationExecutor, subject, message); + } + + // - - - - - - - - - - - - - - - - - + // Other Object Types + // - - - - - - - - - - - - - - - - - + + /** + * @param subject the object to perform validation on. + * @param the class being validated. + * @return a {@link VerifiableClass} instance for the given subject. + */ + public VerifiableClass that(Class subject) { + return new VerifiableClass<>(failedValidationExecutor, subject, message); + } + + /** + * @param subject the object to perform validation on. + * @param the type of the objects in the collection. + * @param the type of the Collection (e.g. list, map, etc). + * @return a {@link VerifiableCollection} instance for the given subject. + */ + public > VerifiableCollection that(T subject) { + return new VerifiableCollection<>(failedValidationExecutor, subject, message); } /** @@ -345,6 +366,18 @@ public VerifiableString that(String subject) { return new VerifiableString<>(failedValidationExecutor, subject, message); } + /** + * This is the default object validation for subjects that + * don't match any of the other pre-defined types. + * + * @param subject the object to perform validation on. + * @param the type of the subject. + * @return a {@link VerifiableObject} instance for the given subject. + */ + public VerifiableObject that(T subject) { + return new VerifiableObject<>(failedValidationExecutor, subject, message); + } + // -------------------------------------------------------------- // Not a value type enforcement // -------------------------------------------------------------- diff --git a/src/main/java/com/redfin/validity/verifiers/objects/VerifiableDuration.java b/src/main/java/com/redfin/validity/verifiers/objects/VerifiableDuration.java new file mode 100644 index 0000000..2bf8412 --- /dev/null +++ b/src/main/java/com/redfin/validity/verifiers/objects/VerifiableDuration.java @@ -0,0 +1,96 @@ +/* + * Copyright: (c) 2016 Redfin + * + * Licensed 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 com.redfin.validity.verifiers.objects; + +import com.redfin.validity.FailedValidationExecutor; +import com.redfin.validity.verifiers.AbstractVerifiableComparable; +import com.redfin.validity.verifiers.AbstractVerifiableObject; + +import java.time.Duration; + +/** + * Concrete class for verifying {@link Duration} subjects. + * + * @param the type of {@link Throwable} to be thrown on validation failure. + */ +public final class VerifiableDuration extends AbstractVerifiableComparable { + + /** + * Create a new {@link AbstractVerifiableObject} instance with the given values. + * + * @param failedValidationExecutor the {@link FailedValidationExecutor} to be called + * on validation failure. + * May not be null. + * @param subject the subject to be validated. + * May be null. + * @param message the String custom message to pre-pend a failure with. + * May be null. + * + * @throws NullPointerException if failedValidationExecutor is null. + */ + public VerifiableDuration(FailedValidationExecutor failedValidationExecutor, Duration subject, String message) { + super(failedValidationExecutor, subject, message); + } + + /** + * @return the subject if it is zero. + * @throws X if the subject is null or is not zero. + */ + public Duration isZero() throws X { + Duration subject = getSubject(); + if (null == subject || !subject.isZero()) { + fail("t -> t.isZero()"); + } + return subject; + } + + /** + * @return the subject if it is not zero. + * @throws X if the subject is null or is zero. + */ + public Duration isNotZero() throws X { + Duration subject = getSubject(); + if (null == subject || subject.isZero()) { + fail("t -> !t.isZero()"); + } + return subject; + } + + /** + * @return the subject if it is not zero and negative. + * @throws X if the subject is null, is zero, or is positive. + */ + public Duration isStrictlyNegative() throws X { + Duration subject = getSubject(); + if (null == subject || !subject.isNegative()) { + fail("t -> t.isNegative()"); + } + return subject; + } + + /** + * @return the subject if it is not zero and positive. + * @throws X if the subject is null, is zero, or is negative. + */ + public Duration isStrictlyPositive() throws X { + Duration subject = getSubject(); + if (null == subject || subject.isZero() || subject.isNegative()) { + fail("t -> !t.isZero() && !t.isNegative()"); + } + return subject; + } +} diff --git a/src/main/java/com/redfin/validity/verifiers/objects/VerifiableInstant.java b/src/main/java/com/redfin/validity/verifiers/objects/VerifiableInstant.java new file mode 100644 index 0000000..a627277 --- /dev/null +++ b/src/main/java/com/redfin/validity/verifiers/objects/VerifiableInstant.java @@ -0,0 +1,47 @@ +/* + * Copyright: (c) 2016 Redfin + * + * Licensed 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 com.redfin.validity.verifiers.objects; + +import com.redfin.validity.FailedValidationExecutor; +import com.redfin.validity.verifiers.AbstractVerifiableComparable; + +import java.time.Instant; + +/** + * Concrete class for verifying {@link Instant} subjects. + * + * @param the type of {@link Throwable} to be thrown on validation failure. + */ +public final class VerifiableInstant extends AbstractVerifiableComparable { + + /** + * Create a new {@link AbstractVerifiableComparable} instance with the given values. + * + * @param failedValidationExecutor the {@link FailedValidationExecutor} to be called + * on validation failure. + * May not be null. + * @param subject the subject to be validated. + * May be null. + * @param message the String custom message to pre-pend a failure with. + * May be null. + * + * @throws NullPointerException if failedValidationExecutor is null. + */ + public VerifiableInstant(FailedValidationExecutor failedValidationExecutor, Instant subject, String message) { + super(failedValidationExecutor, subject, message); + } +} diff --git a/src/test/java/com/redfin/validity/verifiers/objects/VerifiableDurationTest.java b/src/test/java/com/redfin/validity/verifiers/objects/VerifiableDurationTest.java new file mode 100644 index 0000000..6a3418d --- /dev/null +++ b/src/test/java/com/redfin/validity/verifiers/objects/VerifiableDurationTest.java @@ -0,0 +1,201 @@ +/* + * Copyright: (c) 2016 Redfin + * + * Licensed 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 com.redfin.validity.verifiers.objects; + +import com.redfin.validity.DefaultValidityFailedValidationExecutor; +import com.redfin.validity.FailedValidationExecutor; +import com.redfin.validity.verifiers.AbstractVerifiableComparableContract; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +final class VerifiableDurationTest implements AbstractVerifiableComparableContract> { + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Test values & contract implementations + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + private static final Duration SUBJECT = Duration.ofMinutes(1); + private static final Duration EQUAL = Duration.ofMinutes(1); + private static final Duration NON_EQUAL = Duration.ofMinutes(2); + private static final Duration LESS_THAN = Duration.ofMinutes(-1); + private static final Duration GREATER_THAN = Duration.ofMinutes(10); + + + @Override + public Duration getSubject() { + return SUBJECT; + } + + @Override + public Duration getEqualSubject() { + return EQUAL; + } + + @Override + public Duration getNonEqualSubject() { + return NON_EQUAL; + } + + @Override + public VerifiableDuration getVerifiableInstance(FailedValidationExecutor failedValidationExecutor, Duration subject, String message) { + return new VerifiableDuration<>(failedValidationExecutor, subject, message); + } + + @Override + public Class getThrowableClass() { + return IllegalArgumentException.class; + } + + @Override + public FailedValidationExecutor getFailedValidationExecutor() { + return new DefaultValidityFailedValidationExecutor<>(IllegalArgumentException::new); + } + + @Override + public Duration getComparableSubject() { + return EQUAL; + } + + @Override + public Duration getNonComparableSubject() { + return NON_EQUAL; + } + + @Override + public Duration getLessThanSubject() { + return LESS_THAN; + } + + @Override + public Duration getGreaterThanSubject() { + return GREATER_THAN; + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Test cases + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + @Test + void testIsZeroReturnsSubjectForZeroSubject() { + Duration subject = Duration.ZERO; + VerifiableDuration verifiable = getVerifiableInstance(subject); + Assertions.assertTrue(subject == verifiable.isZero(), + "VerifiableDuration should return it's given subject for isZero when it's zero"); + } + + @Test + void testIsZeroThrowsForNonZeroSubject() { + Duration subject = Duration.ofMinutes(1); + VerifiableDuration verifiable = getVerifiableInstance(subject); + Assertions.assertThrows(IllegalArgumentException.class, + verifiable::isZero); + } + + @Test + void testIsZeroThrowsForNullSubject() { + VerifiableDuration verifiable = getVerifiableInstance(null); + Assertions.assertThrows(IllegalArgumentException.class, + verifiable::isZero); + } + + @Test + void testIsNotZeroReturnsSubjectForNonZeroSubject() { + Duration subject = Duration.ofMinutes(1); + VerifiableDuration verifiable = getVerifiableInstance(subject); + Assertions.assertTrue(subject == verifiable.isNotZero(), + "VerifiableDuration should return it's given subject for isNotZero when it's not zero"); + } + + @Test + void testIsNotZeroThrowsForZeroSubject() { + Duration subject = Duration.ZERO; + VerifiableDuration verifiable = getVerifiableInstance(subject); + Assertions.assertThrows(IllegalArgumentException.class, + verifiable::isNotZero); + } + + @Test + void testIsNotZeroThrowsForNullSubject() { + VerifiableDuration verifiable = getVerifiableInstance(null); + Assertions.assertThrows(IllegalArgumentException.class, + verifiable::isNotZero); + } + + @Test + void testIsStrictlyPositiveReturnsSubjectForPositiveSubject() { + Duration subject = Duration.ofMinutes(1); + VerifiableDuration verifiable = getVerifiableInstance(subject); + Assertions.assertTrue(subject == verifiable.isStrictlyPositive(), + "VerifiableDuration should return it's given subject for isStrictlyPositive when it's positive"); + } + + @Test + void testIsStrictlyPositiveThrowsForZeroSubject() { + Duration subject = Duration.ZERO; + VerifiableDuration verifiable = getVerifiableInstance(subject); + Assertions.assertThrows(IllegalArgumentException.class, + verifiable::isStrictlyPositive); + } + + @Test + void testIsStrictlyPositiveThrowsForNegativeSubject() { + Duration subject = Duration.ofMinutes(-1); + VerifiableDuration verifiable = getVerifiableInstance(subject); + Assertions.assertThrows(IllegalArgumentException.class, + verifiable::isStrictlyPositive); + } + + @Test + void testIsStrictlyPositiveThrowsForNullSubject() { + VerifiableDuration verifiable = getVerifiableInstance(null); + Assertions.assertThrows(IllegalArgumentException.class, + verifiable::isStrictlyPositive); + } + + @Test + void testIsStrictlyNegativeReturnsSubjectForNegativeSubject() { + Duration subject = Duration.ofMinutes(-1); + VerifiableDuration verifiable = getVerifiableInstance(subject); + Assertions.assertTrue(subject == verifiable.isStrictlyNegative(), + "VerifiableDuration should return it's given subject for isStrictlyNegative when it's negative"); + } + + @Test + void testIsStrictlyNegativeThrowsForZeroSubject() { + Duration subject = Duration.ZERO; + VerifiableDuration verifiable = getVerifiableInstance(subject); + Assertions.assertThrows(IllegalArgumentException.class, + verifiable::isStrictlyNegative); + } + + @Test + void testIsStrictlyNegativeThrowsForPositiveSubject() { + Duration subject = Duration.ofMinutes(1); + VerifiableDuration verifiable = getVerifiableInstance(subject); + Assertions.assertThrows(IllegalArgumentException.class, + verifiable::isStrictlyNegative); + } + + @Test + void testIsStrictlyNegativeThrowsForNullSubject() { + VerifiableDuration verifiable = getVerifiableInstance(null); + Assertions.assertThrows(IllegalArgumentException.class, + verifiable::isStrictlyNegative); + } +} diff --git a/src/test/java/com/redfin/validity/verifiers/objects/VerifiableInstantTest.java b/src/test/java/com/redfin/validity/verifiers/objects/VerifiableInstantTest.java new file mode 100644 index 0000000..584f0a6 --- /dev/null +++ b/src/test/java/com/redfin/validity/verifiers/objects/VerifiableInstantTest.java @@ -0,0 +1,87 @@ +/* + * Copyright: (c) 2016 Redfin + * + * Licensed 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 com.redfin.validity.verifiers.objects; + +import com.redfin.validity.DefaultValidityFailedValidationExecutor; +import com.redfin.validity.FailedValidationExecutor; +import com.redfin.validity.verifiers.AbstractVerifiableComparableContract; + +import java.time.Duration; +import java.time.Instant; + +final class VerifiableInstantTest implements AbstractVerifiableComparableContract> { + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Test values & contract implementations + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + private static final Instant SUBJECT = Instant.now(); + private static final Instant EQUAL = Instant.ofEpochMilli(SUBJECT.toEpochMilli()); + private static final Instant NON_EQUAL = SUBJECT.minus(Duration.ofSeconds(10)); + private static final Instant LESS_THAN = SUBJECT.minus(Duration.ofMinutes(1)); + private static final Instant GREATER_THAN = SUBJECT.plus(Duration.ofMinutes(1)); + + @Override + public Instant getSubject() { + return SUBJECT; + } + + @Override + public Instant getEqualSubject() { + return EQUAL; + } + + @Override + public Instant getNonEqualSubject() { + return NON_EQUAL; + } + + @Override + public VerifiableInstant getVerifiableInstance(FailedValidationExecutor failedValidationExecutor, Instant subject, String message) { + return new VerifiableInstant<>(failedValidationExecutor, subject, message); + } + + @Override + public Class getThrowableClass() { + return IllegalArgumentException.class; + } + + @Override + public FailedValidationExecutor getFailedValidationExecutor() { + return new DefaultValidityFailedValidationExecutor<>(IllegalArgumentException::new); + } + + @Override + public Instant getComparableSubject() { + return EQUAL; + } + + @Override + public Instant getNonComparableSubject() { + return NON_EQUAL; + } + + @Override + public Instant getLessThanSubject() { + return LESS_THAN; + } + + @Override + public Instant getGreaterThanSubject() { + return GREATER_THAN; + } +}