From 6257fd06ce082305158676ad561e960a3bc79160 Mon Sep 17 00:00:00 2001 From: Artem Vegera Date: Tue, 16 Jul 2024 15:09:38 +0200 Subject: [PATCH] #15 - Introduced number predicates --- .../avegera/predicate4j/Predicates.java | 34 ++ .../api/RichPredicateConjunction.java | 2 + .../avegera/predicate4j/api/WhereNumber.java | 20 + .../avegera/predicate4j/api/WhereType.java | 2 + .../impl/RichPredicateConjunctionImpl.java | 16 +- .../predicate4j/impl/WhereNumberImpl.java | 58 +++ .../predicate4j/impl/WhereTypeImpl.java | 10 +- .../avegera/predicate4j/PredicatesTest.java | 370 ++++++++++++++++ .../github/avegera/predicate4j/WhereTest.java | 397 +++++++++++++++++- .../avegera/predicate4j/test/Price.java | 14 + 10 files changed, 913 insertions(+), 10 deletions(-) create mode 100644 src/main/java/io/github/avegera/predicate4j/api/WhereNumber.java create mode 100644 src/main/java/io/github/avegera/predicate4j/impl/WhereNumberImpl.java create mode 100644 src/test/java/io/github/avegera/predicate4j/test/Price.java diff --git a/src/main/java/io/github/avegera/predicate4j/Predicates.java b/src/main/java/io/github/avegera/predicate4j/Predicates.java index 613a084..7f2417e 100644 --- a/src/main/java/io/github/avegera/predicate4j/Predicates.java +++ b/src/main/java/io/github/avegera/predicate4j/Predicates.java @@ -91,6 +91,40 @@ public static , R> Predicate notContainsElement(R ele return collection -> collection == null || !collection.contains(element); } + //Number predicates + + public static > Predicate isGreaterThan(N value) { + return number -> number != null && number.compareTo(value) > 0; + } + + public static > Predicate isLessThan(N value) { + return number -> number != null && number.compareTo(value) < 0; + } + + public static > Predicate isGreaterThanOrEqualTo(N value) { + return number -> number != null && number.compareTo(value) >= 0; + } + + public static > Predicate isLessThanOrEqualTo(N value) { + return number -> number != null && number.compareTo(value) <= 0; + } + + public static > Predicate isBetween(N startInclusive, N endInclusive) { + return number -> number != null && number.compareTo(startInclusive) >= 0 && number.compareTo(endInclusive) <= 0; + } + + public static > Predicate notBetween(N startInclusive, N endInclusive) { + return number -> number == null || number.compareTo(startInclusive) < 0 || number.compareTo(endInclusive) > 0; + } + + public static Predicate isEven() { + return number -> number != null && number.longValue() % 2 == 0; + } + + public static Predicate isOdd() { + return number -> number != null && number.longValue() % 2 != 0; + } + //String predicates public static Predicate isEmptyString() { diff --git a/src/main/java/io/github/avegera/predicate4j/api/RichPredicateConjunction.java b/src/main/java/io/github/avegera/predicate4j/api/RichPredicateConjunction.java index d1e88c7..9864932 100644 --- a/src/main/java/io/github/avegera/predicate4j/api/RichPredicateConjunction.java +++ b/src/main/java/io/github/avegera/predicate4j/api/RichPredicateConjunction.java @@ -9,5 +9,7 @@ public interface RichPredicateConjunction { WhereList list(Function> mapper); + > WhereNumber number(Function mapper); + WhereString string(Function mapper); } \ No newline at end of file diff --git a/src/main/java/io/github/avegera/predicate4j/api/WhereNumber.java b/src/main/java/io/github/avegera/predicate4j/api/WhereNumber.java new file mode 100644 index 0000000..e177f7f --- /dev/null +++ b/src/main/java/io/github/avegera/predicate4j/api/WhereNumber.java @@ -0,0 +1,20 @@ +package io.github.avegera.predicate4j.api; + +public interface WhereNumber extends WhereObject { + + RichPredicate isGreaterThan(N value); + + RichPredicate isGreaterThanOrEqualTo(N value); + + RichPredicate isLessThan(N value); + + RichPredicate isLessThanOrEqualTo(N value); + + RichPredicate isBetween(N startInclusive, N endInclusive); + + RichPredicate notBetween(N startInclusive, N endInclusive); + + RichPredicate isEven(); + + RichPredicate isOdd(); +} \ No newline at end of file diff --git a/src/main/java/io/github/avegera/predicate4j/api/WhereType.java b/src/main/java/io/github/avegera/predicate4j/api/WhereType.java index c2df1f6..774ff45 100644 --- a/src/main/java/io/github/avegera/predicate4j/api/WhereType.java +++ b/src/main/java/io/github/avegera/predicate4j/api/WhereType.java @@ -9,5 +9,7 @@ public interface WhereType { WhereList list(Function> mapper); + > WhereNumber number(Function mapper); + WhereString string(Function mapper); } \ No newline at end of file diff --git a/src/main/java/io/github/avegera/predicate4j/impl/RichPredicateConjunctionImpl.java b/src/main/java/io/github/avegera/predicate4j/impl/RichPredicateConjunctionImpl.java index b48e4ee..bc269aa 100644 --- a/src/main/java/io/github/avegera/predicate4j/impl/RichPredicateConjunctionImpl.java +++ b/src/main/java/io/github/avegera/predicate4j/impl/RichPredicateConjunctionImpl.java @@ -3,6 +3,7 @@ import io.github.avegera.predicate4j.api.*; import java.util.List; +import java.util.function.BiFunction; import java.util.function.Function; public class RichPredicateConjunctionImpl implements RichPredicateConjunction { @@ -15,16 +16,25 @@ public RichPredicateConjunctionImpl(RichPredicate previousPredicate) { @Override public WhereBoolean booleanValue(Function mapper) { - return new WhereBooleanImpl<>(mapper, previousPredicate); + return getWhere(WhereBooleanImpl::new, mapper); } @Override public WhereList list(Function> mapper) { - return new WhereListImpl<>(mapper, previousPredicate); + return getWhere(WhereListImpl::new, mapper); + } + + @Override + public > WhereNumber number(Function mapper) { + return getWhere(WhereNumberImpl::new, mapper); } @Override public WhereString string(Function mapper) { - return new WhereStringImpl<>(mapper, previousPredicate); + return getWhere(WhereStringImpl::new, mapper); + } + + private > W getWhere(BiFunction, RichPredicate, W> constructor, Function mapper) { + return constructor.apply(mapper, previousPredicate); } } \ No newline at end of file diff --git a/src/main/java/io/github/avegera/predicate4j/impl/WhereNumberImpl.java b/src/main/java/io/github/avegera/predicate4j/impl/WhereNumberImpl.java new file mode 100644 index 0000000..17569bb --- /dev/null +++ b/src/main/java/io/github/avegera/predicate4j/impl/WhereNumberImpl.java @@ -0,0 +1,58 @@ +package io.github.avegera.predicate4j.impl; + +import io.github.avegera.predicate4j.Predicates; +import io.github.avegera.predicate4j.api.RichPredicate; +import io.github.avegera.predicate4j.api.WhereNumber; + +import java.util.function.Function; + +public class WhereNumberImpl> extends WhereObjectImpl implements WhereNumber { + + public WhereNumberImpl(Function mapper) { + super(mapper); + } + + public WhereNumberImpl(Function mapper, RichPredicate previousPredicate) { + super(mapper, previousPredicate); + } + + @Override + public RichPredicate isGreaterThan(N value) { + return getPredicate(Predicates.isGreaterThan(value)); + } + + @Override + public RichPredicate isLessThan(N value) { + return getPredicate(Predicates.isLessThan(value)); + } + + @Override + public RichPredicate isGreaterThanOrEqualTo(N value) { + return getPredicate(Predicates.isGreaterThanOrEqualTo(value)); + } + + @Override + public RichPredicate isLessThanOrEqualTo(N value) { + return getPredicate(Predicates.isLessThanOrEqualTo(value)); + } + + @Override + public RichPredicate isBetween(N startInclusive, N endInclusive) { + return getPredicate(Predicates.isBetween(startInclusive, endInclusive)); + } + + @Override + public RichPredicate notBetween(N startInclusive, N endInclusive) { + return getPredicate(Predicates.notBetween(startInclusive, endInclusive)); + } + + @Override + public RichPredicate isEven() { + return getPredicate(Predicates.isEven()); + } + + @Override + public RichPredicate isOdd() { + return getPredicate(Predicates.isOdd()); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/avegera/predicate4j/impl/WhereTypeImpl.java b/src/main/java/io/github/avegera/predicate4j/impl/WhereTypeImpl.java index 896f441..96de37f 100644 --- a/src/main/java/io/github/avegera/predicate4j/impl/WhereTypeImpl.java +++ b/src/main/java/io/github/avegera/predicate4j/impl/WhereTypeImpl.java @@ -1,9 +1,6 @@ package io.github.avegera.predicate4j.impl; -import io.github.avegera.predicate4j.api.WhereBoolean; -import io.github.avegera.predicate4j.api.WhereList; -import io.github.avegera.predicate4j.api.WhereString; -import io.github.avegera.predicate4j.api.WhereType; +import io.github.avegera.predicate4j.api.*; import java.util.List; import java.util.function.Function; @@ -20,6 +17,11 @@ public WhereList list(Function> mapper) { return new WhereListImpl<>(mapper); } + @Override + public > WhereNumber number(Function mapper) { + return new WhereNumberImpl<>(mapper); + } + @Override public WhereString string(Function mapper) { return new WhereStringImpl<>(mapper); diff --git a/src/test/java/io/github/avegera/predicate4j/PredicatesTest.java b/src/test/java/io/github/avegera/predicate4j/PredicatesTest.java index 3825b89..4b727c5 100644 --- a/src/test/java/io/github/avegera/predicate4j/PredicatesTest.java +++ b/src/test/java/io/github/avegera/predicate4j/PredicatesTest.java @@ -762,6 +762,376 @@ void listContainsSpecifiedElement() { } } + @Nested + @DisplayName("Number predicate") + class NumberPredicate { + + @Nested + @DisplayName("isGreaterThan()") + class IsGreaterThan { + + @Nested + @DisplayName("returns true when") + class ReturnsTrue { + + @Test + @DisplayName("number is greater than the provided value") + void numberIsGreaterThanProvidedValue() { + Predicate predicate = isGreaterThan(10); + assertThat(predicate).accepts(15); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalse { + + @Test + @DisplayName("number is less than the provided value") + void numberIsLessThanProvidedValue() { + Predicate predicate = isGreaterThan(10); + assertThat(predicate).rejects(5); + } + + @Test + @DisplayName("number is equal to the provided value") + void numberIsEqualToProvidedValue() { + Predicate predicate = isGreaterThan(10); + assertThat(predicate).rejects(10); + } + + @Test + @DisplayName("number is null") + void numberIsNull() { + Predicate predicate = isGreaterThan(10); + assertThat(predicate).rejects((Integer) null); + } + } + } + + @Nested + @DisplayName("isLessThan()") + class IsLessThan { + + @Nested + @DisplayName("returns true when") + class ReturnsTrue { + + @Test + @DisplayName("number is less than the provided value") + void numberIsLessThanProvidedValue() { + Predicate predicate = isLessThan(10); + assertThat(predicate).accepts(5); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalse { + + @Test + @DisplayName("number is greater than the provided value") + void numberIsGreaterThanProvidedValue() { + Predicate predicate = isLessThan(10); + assertThat(predicate).rejects(15); + } + + @Test + @DisplayName("number is equal to the provided value") + void numberIsEqualToProvidedValue() { + Predicate predicate = isLessThan(10); + assertThat(predicate).rejects(10); + } + + @Test + @DisplayName("number is null") + void numberIsNull() { + Predicate predicate = isLessThan(10); + assertThat(predicate).rejects((Integer) null); + } + } + } + + @Nested + @DisplayName("isGreaterThanOrEqualTo()") + class IsGreaterThanOrEqualTo { + + @Nested + @DisplayName("returns true when") + class ReturnsTrue { + + @Test + @DisplayName("number is greater than the provided value") + void numberIsGreaterThanProvidedValue() { + Predicate predicate = isGreaterThanOrEqualTo(10); + assertThat(predicate).accepts(15); + } + + @Test + @DisplayName("number is equal to the provided value") + void numberIsEqualToProvidedValue() { + Predicate predicate = isGreaterThanOrEqualTo(10); + assertThat(predicate).accepts(10); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalse { + + @Test + @DisplayName("number is less than the provided value") + void numberIsLessThanProvidedValue() { + Predicate predicate = isGreaterThanOrEqualTo(10); + assertThat(predicate).rejects(5); + } + + @Test + @DisplayName("number is null") + void numberIsNull() { + Predicate predicate = isGreaterThanOrEqualTo(10); + assertThat(predicate).rejects((Integer) null); + } + } + } + + @Nested + @DisplayName("isLessThanOrEqualTo()") + class IsLessThanOrEqualTo { + + @Nested + @DisplayName("returns true when") + class ReturnsTrue { + + @Test + @DisplayName("number is less than the provided value") + void numberIsLessThanProvidedValue() { + Predicate predicate = isLessThanOrEqualTo(10); + assertThat(predicate).accepts(5); + } + + @Test + @DisplayName("number is equal to the provided value") + void numberIsEqualToProvidedValue() { + Predicate predicate = isLessThanOrEqualTo(10); + assertThat(predicate).accepts(10); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalse { + + @Test + @DisplayName("number is greater than the provided value") + void numberIsGreaterThanProvidedValue() { + Predicate predicate = isLessThanOrEqualTo(10); + assertThat(predicate).rejects(15); + } + + @Test + @DisplayName("number is null") + void numberIsNull() { + Predicate predicate = isLessThanOrEqualTo(10); + assertThat(predicate).rejects((Integer) null); + } + } + } + + @Nested + @DisplayName("isBetween()") + class IsBetween { + + @Nested + @DisplayName("returns true when") + class ReturnsTrue { + + @Test + @DisplayName("number is within the range") + void numberIsWithinRange() { + Predicate predicate = isBetween(10, 20); + assertThat(predicate).accepts(15); + } + + @Test + @DisplayName("number is equal to the start of the range") + void numberIsEqualToStartOfRange() { + Predicate predicate = isBetween(10, 20); + assertThat(predicate).accepts(10); + } + + @Test + @DisplayName("number is equal to the end of the range") + void numberIsEqualToEndOfRange() { + Predicate predicate = isBetween(10, 20); + assertThat(predicate).accepts(20); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalse { + + @Test + @DisplayName("number is less than the start of the range") + void numberIsLessThanStartOfRange() { + Predicate predicate = isBetween(10, 20); + assertThat(predicate).rejects(5); + } + + @Test + @DisplayName("number is greater than the end of the range") + void numberIsGreaterThanEndOfRange() { + Predicate predicate = isBetween(10, 20); + assertThat(predicate).rejects(25); + } + + @Test + @DisplayName("number is null") + void numberIsNull() { + Predicate predicate = isBetween(10, 20); + assertThat(predicate).rejects((Integer) null); + } + } + } + + @Nested + @DisplayName("notBetween()") + class NotBetween { + + @Nested + @DisplayName("returns true when") + class ReturnsTrue { + + @Test + @DisplayName("number is less than the start of the range") + void numberIsLessThanStartOfRange() { + Predicate predicate = notBetween(10, 20); + assertThat(predicate).accepts(5); + } + + @Test + @DisplayName("number is greater than the end of the range") + void numberIsGreaterThanEndOfRange() { + Predicate predicate = notBetween(10, 20); + assertThat(predicate).accepts(25); + } + + @Test + @DisplayName("number is null") + void numberIsNull() { + Predicate predicate = notBetween(10, 20); + assertThat(predicate).accepts((Integer) null); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalse { + + @Test + @DisplayName("number is within the range") + void numberIsWithinRange() { + Predicate predicate = notBetween(10, 20); + assertThat(predicate).rejects(15); + } + + @Test + @DisplayName("number is equal to the start of the range") + void numberIsEqualToStartOfRange() { + Predicate predicate = notBetween(10, 20); + assertThat(predicate).rejects(10); + } + + @Test + @DisplayName("number is equal to the end of the range") + void numberIsEqualToEndOfRange() { + Predicate predicate = notBetween(10, 20); + assertThat(predicate).rejects(20); + } + } + } + + @Nested + @DisplayName("isEven()") + class IsEven { + + @Nested + @DisplayName("returns true when") + class ReturnsTrue { + + @Test + @DisplayName("number is even") + void numberIsEven() { + Predicate predicate = isEven(); + assertThat(predicate).accepts(4); + } + + @Test + @DisplayName("number is zero") + void numberIsZero() { + Predicate predicate = isEven(); + assertThat(predicate).accepts(0); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalse { + + @Test + @DisplayName("number is odd") + void numberIsOdd() { + Predicate predicate = isEven(); + assertThat(predicate).rejects(3); + } + + @Test + @DisplayName("number is null") + void numberIsNull() { + Predicate predicate = isEven(); + assertThat(predicate).rejects((Number) null); + } + } + } + + @Nested + @DisplayName("isOdd()") + class IsOdd { + + @Nested + @DisplayName("returns true when") + class ReturnsTrue { + + @Test + @DisplayName("number is odd") + void numberIsOdd() { + Predicate predicate = isOdd(); + assertThat(predicate).accepts(3); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalse { + + @Test + @DisplayName("number is even") + void numberIsEven() { + Predicate predicate = isOdd(); + assertThat(predicate).rejects(4); + } + + @Test + @DisplayName("number is null") + void numberIsNull() { + Predicate predicate = isOdd(); + assertThat(predicate).rejects((Number) null); + } + } + } + } + @Nested @DisplayName("String predicate") class StringPredicate { diff --git a/src/test/java/io/github/avegera/predicate4j/WhereTest.java b/src/test/java/io/github/avegera/predicate4j/WhereTest.java index 41506fe..0156ad6 100644 --- a/src/test/java/io/github/avegera/predicate4j/WhereTest.java +++ b/src/test/java/io/github/avegera/predicate4j/WhereTest.java @@ -1418,6 +1418,397 @@ void mappedListContainsSpecifiedElement() { } } + @Nested + @DisplayName("Predicate from method where().number(mapper)") + class WhereNumberImpl { + + @Nested + @DisplayName(".isGreaterThan(value)") + class IsGreaterThan { + + @Nested + @DisplayName("returns true when") + class ReturnsTrueWhen { + + @Test + @DisplayName("mapped value is greater than provided value") + void mappedValueIsGreaterThanProvidedValue() { + Predicate predicate = where().number(Price::value).isGreaterThan(100); + assertThat(predicate).accepts(new Price(150)); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalseWhen { + + @Test + @DisplayName("mapped value is less than provided value") + void mappedValueIsLessThanProvidedValue() { + Predicate predicate = where().number(Price::value).isGreaterThan(100); + assertThat(predicate).rejects(new Price(50)); + } + + @Test + @DisplayName("mapped value is equal to provided value") + void mappedValueIsEqualToProvidedValue() { + Predicate predicate = where().number(Price::value).isGreaterThan(100); + assertThat(predicate).rejects(new Price(100)); + } + + @Test + @DisplayName("mapped value is null") + void mappedValueIsNull() { + Predicate predicate = where().number(Price::value).isGreaterThan(100); + assertThat(predicate).rejects(new Price(null)); + } + } + } + + @Nested + @DisplayName(".isGreaterThanOrEqualTo(value)") + class IsGreaterThanOrEqualTo { + + @Nested + @DisplayName("returns true when") + class ReturnsTrueWhen { + + @Test + @DisplayName("mapped value is greater than provided value") + void mappedValueIsGreaterThanProvidedValue() { + Predicate predicate = where().number(Price::value).isGreaterThanOrEqualTo(100); + assertThat(predicate).accepts(new Price(150)); + } + + @Test + @DisplayName("mapped value is equal to provided value") + void mappedValueIsEqualToProvidedValue() { + Predicate predicate = where().number(Price::value).isGreaterThanOrEqualTo(100); + assertThat(predicate).accepts(new Price(100)); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalseWhen { + + @Test + @DisplayName("mapped value is less than provided value") + void mappedValueIsLessThanProvidedValue() { + Predicate predicate = where().number(Price::value).isGreaterThanOrEqualTo(100); + assertThat(predicate).rejects(new Price(50)); + } + + @Test + @DisplayName("mapped value is null") + void mappedValueIsNull() { + Predicate predicate = where().number(Price::value).isGreaterThanOrEqualTo(100); + assertThat(predicate).rejects(new Price(null)); + } + } + } + + @Nested + @DisplayName(".isLessThan(value)") + class IsLessThan { + + @Nested + @DisplayName("returns true when") + class ReturnsTrueWhen { + + @Test + @DisplayName("mapped value is less than provided value") + void mappedValueIsLessThanProvidedValue() { + Predicate predicate = where().number(Price::value).isLessThan(100); + assertThat(predicate).accepts(new Price(50)); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalseWhen { + + @Test + @DisplayName("mapped value is greater than provided value") + void mappedValueIsGreaterThanProvidedValue() { + Predicate predicate = where().number(Price::value).isLessThan(100); + assertThat(predicate).rejects(new Price(150)); + } + + @Test + @DisplayName("mapped value is equal to provided value") + void mappedValueIsEqualToProvidedValue() { + Predicate predicate = where().number(Price::value).isLessThan(100); + assertThat(predicate).rejects(new Price(100)); + } + + @Test + @DisplayName("mapped value is null") + void mappedValueIsNull() { + Predicate predicate = where().number(Price::value).isLessThan(100); + assertThat(predicate).rejects(new Price(null)); + } + } + } + + @Nested + @DisplayName(".isLessThanOrEqualTo(value)") + class IsLessThanOrEqualTo { + + @Nested + @DisplayName("returns true when") + class ReturnsTrueWhen { + + @Test + @DisplayName("mapped value is less than provided value") + void mappedValueIsLessThanProvidedValue() { + Predicate predicate = where().number(Price::value).isLessThanOrEqualTo(100); + assertThat(predicate).accepts(new Price(50)); + } + + @Test + @DisplayName("mapped value is equal to provided value") + void mappedValueIsEqualToProvidedValue() { + Predicate predicate = where().number(Price::value).isLessThanOrEqualTo(100); + assertThat(predicate).accepts(new Price(100)); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalseWhen { + + @Test + @DisplayName("mapped value is greater than provided value") + void mappedValueIsGreaterThanProvidedValue() { + Predicate predicate = where().number(Price::value).isLessThanOrEqualTo(100); + assertThat(predicate).rejects(new Price(150)); + } + + @Test + @DisplayName("mapped value is null") + void mappedValueIsNull() { + Predicate predicate = where().number(Price::value).isLessThanOrEqualTo(100); + assertThat(predicate).rejects(new Price(null)); + } + } + } + + @Nested + @DisplayName(".isBetween(start, end)") + class IsBetween { + + @Nested + @DisplayName("returns true when") + class ReturnsTrueWhen { + + @Test + @DisplayName("mapped value is within the range") + void mappedValueIsWithinRange() { + Predicate predicate = where().number(Price::value).isBetween(50, 150); + assertThat(predicate).accepts(new Price(100)); + } + + @Test + @DisplayName("mapped value is equal to start of the range") + void mappedValueIsEqualToStartOfRange() { + Predicate predicate = where().number(Price::value).isBetween(50, 150); + assertThat(predicate).accepts(new Price(50)); + } + + @Test + @DisplayName("mapped value is equal to end of the range") + void mappedValueIsEqualToEndOfRange() { + Predicate predicate = where().number(Price::value).isBetween(50, 150); + assertThat(predicate).accepts(new Price(150)); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalseWhen { + + @Test + @DisplayName("mapped value is less than start of the range") + void mappedValueIsLessThanStartOfRange() { + Predicate predicate = where().number(Price::value).isBetween(50, 150); + assertThat(predicate).rejects(new Price(25)); + } + + @Test + @DisplayName("mapped value is greater than end of the range") + void mappedValueIsGreaterThanEndOfRange() { + Predicate predicate = where().number(Price::value).isBetween(50, 150); + assertThat(predicate).rejects(new Price(175)); + } + + @Test + @DisplayName("mapped value is null") + void mappedValueIsNull() { + Predicate predicate = where().number(Price::value).isBetween(50, 150); + assertThat(predicate).rejects(new Price(null)); + } + } + } + + @Nested + @DisplayName(".notBetween(start, end)") + class NotBetween { + + @Nested + @DisplayName("returns true when") + class ReturnsTrueWhen { + + @Test + @DisplayName("mapped value is less than start of the range") + void mappedValueIsLessThanStartOfRange() { + Predicate predicate = where().number(Price::value).notBetween(50, 150); + assertThat(predicate).accepts(new Price(25)); + } + + @Test + @DisplayName("mapped value is greater than end of the range") + void mappedValueIsGreaterThanEndOfRange() { + Predicate predicate = where().number(Price::value).notBetween(50, 150); + assertThat(predicate).accepts(new Price(175)); + } + + @Test + @DisplayName("mapped value is null") + void mappedValueIsNull() { + Predicate predicate = where().number(Price::value).notBetween(50, 150); + assertThat(predicate).accepts(new Price(null)); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalseWhen { + + @Test + @DisplayName("mapped value is within the range") + void mappedValueIsWithinRange() { + Predicate predicate = where().number(Price::value).notBetween(50, 150); + assertThat(predicate).rejects(new Price(100)); + } + + @Test + @DisplayName("mapped value is equal to start of the range") + void mappedValueIsEqualToStartOfRange() { + Predicate predicate = where().number(Price::value).notBetween(50, 150); + assertThat(predicate).rejects(new Price(50)); + } + + @Test + @DisplayName("mapped value is equal to end of the range") + void mappedValueIsEqualToEndOfRange() { + Predicate predicate = where().number(Price::value).notBetween(50, 150); + assertThat(predicate).rejects(new Price(150)); + } + } + } + + @Nested + @DisplayName(".isOdd()") + class IsOdd { + + @Nested + @DisplayName("returns true when") + class ReturnsTrueWhen { + + @Test + @DisplayName("mapped value is odd") + void mappedValueIsOdd() { + Predicate predicate = where().number(Price::value).isOdd(); + assertThat(predicate).accepts(new Price(3)); + } + + @Test + @DisplayName("mapped value is negative odd") + void mappedValueIsNegativeOdd() { + Predicate predicate = where().number(Price::value).isOdd(); + assertThat(predicate).accepts(new Price(-3)); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalseWhen { + + @Test + @DisplayName("mapped value is even") + void mappedValueIsEven() { + Predicate predicate = where().number(Price::value).isOdd(); + assertThat(predicate).rejects(new Price(4)); + } + + @Test + @DisplayName("mapped value is zero") + void mappedValueIsZero() { + Predicate predicate = where().number(Price::value).isOdd(); + assertThat(predicate).rejects(new Price(0)); + } + + @Test + @DisplayName("mapped value is null") + void mappedValueIsNull() { + Predicate predicate = where().number(Price::value).isOdd(); + assertThat(predicate).rejects(new Price(null)); + } + } + } + + @Nested + @DisplayName(".isEven()") + class IsEven { + + @Nested + @DisplayName("returns true when") + class ReturnsTrueWhen { + + @Test + @DisplayName("mapped value is even") + void mappedValueIsEven() { + Predicate predicate = where().number(Price::value).isEven(); + assertThat(predicate).accepts(new Price(4)); + } + + @Test + @DisplayName("mapped value is zero") + void mappedValueIsZero() { + Predicate predicate = where().number(Price::value).isEven(); + assertThat(predicate).accepts(new Price(0)); + } + + @Test + @DisplayName("mapped value is negative even") + void mappedValueIsNegativeEven() { + Predicate predicate = where().number(Price::value).isEven(); + assertThat(predicate).accepts(new Price(-4)); + } + } + + @Nested + @DisplayName("returns false when") + class ReturnsFalseWhen { + + @Test + @DisplayName("mapped value is odd") + void mappedValueIsOdd() { + Predicate predicate = where().number(Price::value).isEven(); + assertThat(predicate).rejects(new Price(3)); + } + + @Test + @DisplayName("mapped value is null") + void mappedValueIsNull() { + Predicate predicate = where().number(Price::value).isEven(); + assertThat(predicate).rejects(new Price(null)); + } + } + } + } + @Nested @DisplayName("Predicate from method where().string(mapper)") class WhereStringImpl { @@ -2113,7 +2504,7 @@ class SevenPredicates { .and(Address::state).notNull() .and().string(Address::street).notStartsWith("str.") .and().string(Address::building).notEqualTo("xyz") - .and(Address::zipCode).isEqualTo(123) + .and().number(Address::zipCode).isGreaterThan(100) .and().list(Address::tenants).contains("Tenant1") .and().booleanValue(Address::active).isTrue(); @@ -2169,7 +2560,7 @@ void fourthPredicateIsFalse() { @Test @DisplayName("fifth predicate is false") void fifthPredicateIsFalse() { - Address address = new Address("USA", "testValue", "someStreet", "abc", 456, asList("Tenant1", "Tenant2"), true); + Address address = new Address("USA", "testValue", "someStreet", "abc", 45, asList("Tenant1", "Tenant2"), true); assertThat(predicateConjunction).rejects(address); } @@ -2204,7 +2595,7 @@ void fourPredicatesAreFalse() { @Test @DisplayName("all predicates are false") void allPredicatesAreFalse() { - Address address = new Address("USA", "testValue", "someStreet", "abc", 123, asList("Tenant1", "Tenant2"), null); + Address address = new Address("USA", "testValue", "someStreet", "abc", 10, asList("Tenant1", "Tenant2"), null); assertThat(predicateConjunction).rejects(address); } } diff --git a/src/test/java/io/github/avegera/predicate4j/test/Price.java b/src/test/java/io/github/avegera/predicate4j/test/Price.java new file mode 100644 index 0000000..ee51f25 --- /dev/null +++ b/src/test/java/io/github/avegera/predicate4j/test/Price.java @@ -0,0 +1,14 @@ +package io.github.avegera.predicate4j.test; + +public class Price { + + private final Integer value; + + public Price(Integer value) { + this.value = value; + } + + public Integer value() { + return value; + } +} \ No newline at end of file