You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2019/12/31 13:35:22 UTC

[commons-lang] branch master updated: [LANG-1431] Add ComparableUtils (#398)

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git


The following commit(s) were added to refs/heads/master by this push:
     new 2425853  [LANG-1431] Add ComparableUtils (#398)
2425853 is described below

commit 2425853701d6decfd3ff53c2803a9273119084be
Author: Sam Kruglov <sa...@gmail.com>
AuthorDate: Tue Dec 31 15:35:10 2019 +0200

    [LANG-1431] Add ComparableUtils (#398)
---
 .../org/apache/commons/lang3/ComparableUtils.java  | 206 +++++++++++++++
 .../apache/commons/lang3/ComparableUtilsTest.java  | 288 +++++++++++++++++++++
 2 files changed, 494 insertions(+)

diff --git a/src/main/java/org/apache/commons/lang3/ComparableUtils.java b/src/main/java/org/apache/commons/lang3/ComparableUtils.java
new file mode 100644
index 0000000..6a84a62
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/ComparableUtils.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.commons.lang3;
+
+import java.util.function.Predicate;
+
+/**
+ * <p>Utility library to provide helper methods for translating {@link Comparable#compareTo} result into a boolean.</p>
+ *
+ * <p>Example: {@code boolean x = is(myComparable).lessThanOrEqualTo(otherComparable)}</p>
+ *
+ * <p>#ThreadSafe#</p>
+ *
+ * @since 3.10
+ */
+public class ComparableUtils {
+
+    private ComparableUtils() {}
+
+    /**
+     * Provides access to the available methods
+     *
+     * @param a base object in the further comparison
+     * @param <A> type of the base object
+     * @return a builder object with further methods
+     */
+    public static <A extends Comparable<A>> ComparableCheckBuilder<A> is(A a) {
+        return new ComparableCheckBuilder<>(a);
+    }
+
+    /**
+     * Checks if the tested object is less than {@code b}
+     *
+     * @param b the object to compare to the tested object
+     * @param <A> type of the test object
+     * @return a predicate for true if the value returned by {@link Comparable#compareTo} is less than {@code 0}
+     */
+    public static <A extends Comparable<A>> Predicate<A> lt(A b) {
+        return a -> is(a).lessThan(b);
+    }
+
+    /**
+     * Checks if the tested object is less than or equal to {@code b}
+     *
+     * @param b the object to compare to the tested object
+     * @param <A> type of the test object
+     * @return a predicate for true if the value returned by {@link Comparable#compareTo}
+     * is less than or equal to {@code 0}
+     */
+    public static <A extends Comparable<A>> Predicate<A> le(A b) {
+        return a -> is(a).lessThanOrEqualTo(b);
+    }
+
+    /**
+     * Checks if the tested object is greater than {@code b}
+     *
+     * @param b the object to compare to the tested object
+     * @param <A> type of the test object
+     * @return a predicate for true if the value returned by {@link Comparable#compareTo} is greater than {@code 0}
+     */
+    public static <A extends Comparable<A>> Predicate<A> gt(A b) {
+        return a -> is(a).greaterThan(b);
+    }
+
+    /**
+     * Checks if the tested object is greater than or equal to {@code b}
+     *
+     * @param b the object to compare to the tested object
+     * @param <A> type of the test object
+     * @return a predicate for true if the value returned by {@link Comparable#compareTo}
+     * is greater than or equal to {@code 0}
+     */
+    public static <A extends Comparable<A>> Predicate<A> ge(A b) {
+        return a -> is(a).greaterThanOrEqualTo(b);
+    }
+
+    /**
+     * Checks if {@code [b <= a <= c]} or {@code [b >= a >= c]} where the {@code a} is the tested object.
+     *
+     * @param b the object to compare to the tested object
+     * @param c the object to compare to the tested object
+     * @param <A> type of the test object
+     * @return a predicate for true if the tested object is between b and c
+     */
+    public static <A extends Comparable<A>> Predicate<A> between(A b, A c) {
+        return a -> is(a).between(b, c);
+    }
+
+    /**
+     * Checks if {@code (b < a < c)} or {@code (b > a > c)} where the {@code a} is the tested object.
+     *
+     * @param b the object to compare to the tested object
+     * @param c the object to compare to the tested object
+     * @param <A> type of the test object
+     * @return a predicate for true if the tested object is between b and c and not equal to those
+     */
+    public static <A extends Comparable<A>> Predicate<A> betweenExclusive(A b, A c) {
+        return a -> is(a).betweenExclusive(b, c);
+    }
+
+    /**
+     * Provides access to the available methods
+     */
+    public static class ComparableCheckBuilder<A extends Comparable<A>> {
+
+        private final A a;
+
+        private ComparableCheckBuilder(A a) {
+            this.a = a;
+        }
+
+        /**
+         * Checks if the object passed to {@link #is} is equal to {@code b}
+         *
+         * @param b the object to compare to the base object
+         * @return true if the value returned by {@link Comparable#compareTo} is equal to {@code 0}
+         */
+        public boolean equalTo(A b) {
+            return a.compareTo(b) == 0;
+        }
+
+        /**
+         * Checks if the object passed to {@link #is} is less than {@code b}
+         *
+         * @param b the object to compare to the base object
+         * @return true if the value returned by {@link Comparable#compareTo} is less than {@code 0}
+         */
+        public boolean lessThan(A b) {
+            return a.compareTo(b) < 0;
+        }
+
+        /**
+         * Checks if the object passed to {@link #is} is less than or equal to {@code b}
+         *
+         * @param b the object to compare to the base object
+         * @return true if the value returned by {@link Comparable#compareTo} is less than or equal to {@code 0}
+         */
+        public boolean lessThanOrEqualTo(A b) {
+            return a.compareTo(b) <= 0;
+        }
+
+        /**
+         * Checks if the object passed to {@link #is} is greater than {@code b}
+         *
+         * @param b the object to compare to the base object
+         * @return true if the value returned by {@link Comparable#compareTo} is greater than {@code 0}
+         */
+        public boolean greaterThan(A b) {
+            return a.compareTo(b) > 0;
+        }
+
+        /**
+         * Checks if the object passed to {@link #is} is greater than or equal to {@code b}
+         *
+         * @param b the object to compare to the base object
+         * @return true if the value returned by {@link Comparable#compareTo} is greater than or equal to {@code 0}
+         */
+        public boolean greaterThanOrEqualTo(A b) {
+            return a.compareTo(b) >= 0;
+        }
+
+        /**
+         * Checks if {@code [b <= a <= c]} or {@code [b >= a >= c]} where the {@code a} is object passed to {@link #is}.
+         *
+         * @param b the object to compare to the base object
+         * @param c the object to compare to the base object
+         * @return true if the base object is between b and c
+         */
+        public boolean between(A b, A c) {
+            return betweenOrdered(b, c) || betweenOrdered(c, b);
+        }
+
+        /**
+         * Checks if {@code (b < a < c)} or {@code (b > a > c)} where the {@code a} is object passed to {@link #is}.
+         *
+         * @param b the object to compare to the base object
+         * @param c the object to compare to the base object
+         * @return true if the base object is between b and c and not equal to those
+         */
+        public boolean betweenExclusive(A b, A c) {
+            return betweenOrderedExclusive(b, c) || betweenOrderedExclusive(c, b);
+        }
+
+        private boolean betweenOrdered(A b, A c) {
+            return greaterThanOrEqualTo(b) && lessThanOrEqualTo(c);
+        }
+
+        private boolean betweenOrderedExclusive(A b, A c) {
+            return greaterThan(b) && lessThan(c);
+        }
+    }
+}
diff --git a/src/test/java/org/apache/commons/lang3/ComparableUtilsTest.java b/src/test/java/org/apache/commons/lang3/ComparableUtilsTest.java
new file mode 100644
index 0000000..50ec33c
--- /dev/null
+++ b/src/test/java/org/apache/commons/lang3/ComparableUtilsTest.java
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.commons.lang3;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+
+import static org.apache.commons.lang3.ComparableUtils.is;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+public class ComparableUtilsTest {
+
+    @Nested
+    class A_is_1 {
+
+        BigDecimal a = BigDecimal.ONE;
+
+        @DisplayName("B is 1 (B = A)")
+        @Nested
+        class B_is_1 {
+
+            BigDecimal b = BigDecimal.ONE;
+
+            @Test
+            void equalTo_returns_true() {
+                assertTrue(is(a).equalTo(b));
+            }
+
+            @Test
+            void lessThan_returns_false() {
+                assertFalse(is(a).lessThan(b));
+            }
+
+            @Test
+            void lessThanOrEqualTo_returns_true() {
+                assertTrue(is(a).lessThanOrEqualTo(b));
+            }
+
+            @Test
+            void greaterThan_returns_false() {
+                assertFalse(is(a).greaterThan(b));
+            }
+
+            @Test
+            void greaterThanOrEqualTo_returns_true() {
+                assertTrue(is(a).greaterThanOrEqualTo(b));
+            }
+
+            @DisplayName("C is 1 (B = A = C)")
+            @Nested
+            class C_is_1 {
+
+                BigDecimal c = BigDecimal.ONE;
+
+                @Test
+                void between_returns_true() {
+                    assertTrue(is(a).between(b, c));
+                }
+
+                @Test
+                void betweenExclusive_returns_false() {
+                    assertFalse(is(a).betweenExclusive(b, c));
+                }
+            }
+
+            @DisplayName("C is 10 (B = A < C)")
+            @Nested
+            class C_is_10 {
+
+                BigDecimal c = BigDecimal.TEN;
+
+                @Test
+                void between_returns_true() {
+                    assertTrue(is(a).between(b, c));
+                }
+
+                @Test
+                void betweenExclusive_returns_false() {
+                    assertFalse(is(a).betweenExclusive(b, c));
+                }
+            }
+
+            @DisplayName("C is 0 (B = A > C)")
+            @Nested
+            class C_is_0 {
+
+                BigDecimal c = BigDecimal.ZERO;
+
+                @Test
+                void between_returns_true() {
+                    assertTrue(is(a).between(b, c));
+                }
+
+                @Test
+                void betweenExclusive_returns_false() {
+                    assertFalse(is(a).betweenExclusive(b, c));
+                }
+            }
+        }
+
+        @DisplayName("B is 10 (B > A)")
+        @Nested
+        class B_is_10 {
+
+            BigDecimal b = BigDecimal.TEN;
+
+            @Test
+            void equalTo_returns_false() {
+                assertFalse(is(a).equalTo(b));
+            }
+
+            @Test
+            void lessThan_returns_true() {
+                assertTrue(is(a).lessThan(b));
+            }
+
+            @Test
+            void lessThanOrEqualTo_returns_true() {
+                assertTrue(is(a).lessThanOrEqualTo(b));
+            }
+
+            @Test
+            void greaterThan_returns_false() {
+                assertFalse(is(a).greaterThan(b));
+            }
+
+            @Test
+            void greaterThanOrEqualTo_returns_false() {
+                assertFalse(is(a).greaterThanOrEqualTo(b));
+            }
+
+            @DisplayName("C is 1 (B > A = C)")
+            @Nested
+            class C_is_1 {
+
+                BigDecimal c = BigDecimal.ONE;
+
+                @Test
+                void between_returns_true() {
+                    assertTrue(is(a).between(b, c));
+                }
+
+                @Test
+                void betweenExclusive_returns_false() {
+                    assertFalse(is(a).betweenExclusive(b, c));
+                }
+            }
+
+            @DisplayName("C is 10 ([B,C] > A)")
+            @Nested
+            class C_is_10 {
+
+                BigDecimal c = BigDecimal.TEN;
+
+                @Test
+                void between_returns_false() {
+                    assertFalse(is(a).between(b, c));
+                }
+
+                @Test
+                void betweenExclusive_returns_false() {
+                    assertFalse(is(a).betweenExclusive(b, c));
+                }
+            }
+
+            @DisplayName("C is 0 (B > A > C)")
+            @Nested
+            class C_is_0 {
+
+                BigDecimal c = BigDecimal.ZERO;
+
+                @Test
+                void between_returns_true() {
+                    assertTrue(is(a).between(b, c));
+                }
+
+                @Test
+                void betweenExclusive_returns_true() {
+                    assertTrue(is(a).betweenExclusive(b, c));
+                }
+            }
+        }
+
+        @DisplayName("B is 0 (B < A)")
+        @Nested
+        class B_is_0 {
+
+            BigDecimal b = BigDecimal.ZERO;
+
+            @Test
+            void equalTo_returns_false() {
+                assertFalse(is(a).equalTo(b));
+            }
+
+            @Test
+            void lessThan_returns_false() {
+                assertFalse(is(a).lessThan(b));
+            }
+
+            @Test
+            void lessThanOrEqualTo_returns_false() {
+                assertFalse(is(a).lessThanOrEqualTo(b));
+            }
+
+            @Test
+            void greaterThan_returns_true() {
+                assertTrue(is(a).greaterThan(b));
+            }
+
+            @Test
+            void greaterThanOrEqualTo_returns_true() {
+                assertTrue(is(a).greaterThanOrEqualTo(b));
+            }
+
+            @DisplayName("C is 1 (B < A = C)")
+            @Nested
+            class C_is_1 {
+
+                BigDecimal c = BigDecimal.ONE;
+
+                @Test
+                void between_returns_true() {
+                    assertTrue(is(a).between(b, c));
+                }
+
+                @Test
+                void betweenExclusive_returns_false() {
+                    assertFalse(is(a).betweenExclusive(b, c));
+                }
+            }
+
+            @DisplayName("C is 10 (B < A < C)")
+            @Nested
+            class C_is_10 {
+
+                BigDecimal c = BigDecimal.TEN;
+
+                @Test
+                void between_returns_true() {
+                    assertTrue(is(a).between(b, c));
+                }
+
+                @Test
+                void betweenExclusive_returns_true() {
+                    assertTrue(is(a).betweenExclusive(b, c));
+                }
+            }
+
+            @DisplayName("C is 0 ([B=C] < A)")
+            @Nested
+            class C_is_0 {
+
+                BigDecimal c = BigDecimal.ZERO;
+
+                @Test
+                void between_returns_false() {
+                    assertFalse(is(a).between(b, c));
+                }
+
+                @Test
+                void betweenExclusive_returns_false() {
+                    assertFalse(is(a).betweenExclusive(b, c));
+                }
+            }
+        }
+    }
+}