From 57ddce119516f451168f4489f55f399fd9309b53 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 17 Oct 2022 08:08:59 -0400 Subject: Add NumberRange, DoubleRange, IntegerRange, LongRange. Fix changes.xml --- src/changes/changes.xml | 3 +- .../java/org/apache/commons/lang3/DoubleRange.java | 85 ++++ .../org/apache/commons/lang3/IntegerRange.java | 85 ++++ .../java/org/apache/commons/lang3/LongRange.java | 85 ++++ .../java/org/apache/commons/lang3/NumberRange.java | 48 +++ src/main/java/org/apache/commons/lang3/Range.java | 77 +++- .../apache/commons/lang3/time/DurationUtils.java | 5 +- .../org/apache/commons/lang3/DoubleRangeTest.java | 412 ++++++++++++++++++++ .../org/apache/commons/lang3/IntegerRangeTest.java | 411 ++++++++++++++++++++ .../org/apache/commons/lang3/LongRangeTest.java | 426 +++++++++++++++++++++ .../java/org/apache/commons/lang3/RangeTest.java | 56 ++- 11 files changed, 1662 insertions(+), 31 deletions(-) create mode 100644 src/main/java/org/apache/commons/lang3/DoubleRange.java create mode 100644 src/main/java/org/apache/commons/lang3/IntegerRange.java create mode 100644 src/main/java/org/apache/commons/lang3/LongRange.java create mode 100644 src/main/java/org/apache/commons/lang3/NumberRange.java create mode 100644 src/test/java/org/apache/commons/lang3/DoubleRangeTest.java create mode 100644 src/test/java/org/apache/commons/lang3/IntegerRangeTest.java create mode 100644 src/test/java/org/apache/commons/lang3/LongRangeTest.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 21c646fd9..876ee71c3 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -103,7 +103,7 @@ The type attribute can be add,update,fix,remove. Added docs regarding week year support #924. ClassUtils.getShortCanonicalName doesn't use the canonicalName #949. Validate: Get error messages without using String.format when varargs is empty. - Simplify expression (length is never < 0) #962. + Simplify expression (length is never < 0) #962. Add GitHub coverage.yml. Add EnumUtils.getEnumSystemProperty(...). @@ -182,6 +182,7 @@ The type attribute can be add,update,fix,remove. Add BooleanUtils.values() and forEach(). Add ClassPathUtils.packageToPath(String) and pathToPackage(String) Add CalendarUtils#getDayOfYear() #968 + Add NumberRange, DoubleRange, IntegerRange, LongRange. Bump actions/cache from 2.1.4 to 3.0.10 #742, #752, #764, #833, #867, #959, #964. Bump actions/checkout from 2 to 3.1.0 #819, #825, #859, #963. diff --git a/src/main/java/org/apache/commons/lang3/DoubleRange.java b/src/main/java/org/apache/commons/lang3/DoubleRange.java new file mode 100644 index 000000000..0c6d5a971 --- /dev/null +++ b/src/main/java/org/apache/commons/lang3/DoubleRange.java @@ -0,0 +1,85 @@ +/* + * 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; + +/** + * Specializes {@link NumberRange} for {@link Double}s. + * + *

+ * This class is not designed to interoperate with other NumberRanges + *

+ * + * @since 3.13.0 + */ +public final class DoubleRange extends NumberRange { + + private static final long serialVersionUID = 1L; + + /** + * Creates a range with the specified minimum and maximum values (both inclusive). + * + *

+ * The range uses the natural ordering of the elements to determine where values lie in the range. + *

+ * + *

+ * The arguments may be passed in the order (min,max) or (max,min). The getMinimum and getMaximum methods will return the correct values. + *

+ * + * @param fromInclusive the first value that defines the edge of the range, inclusive. + * @param toInclusive the second value that defines the edge of the range, inclusive. + * @return the range object, not null. + */ + public static DoubleRange of(final double fromInclusive, final double toInclusive) { + return of(Double.valueOf(fromInclusive), Double.valueOf(toInclusive)); + } + + /** + * Creates a range with the specified minimum and maximum values (both inclusive). + * + *

+ * The range uses the natural ordering of the elements to determine where values lie in the range. + *

+ * + *

+ * The arguments may be passed in the order (min,max) or (max,min). The getMinimum and getMaximum methods will return the correct values. + *

+ * + * @param fromInclusive the first value that defines the edge of the range, inclusive. + * @param toInclusive the second value that defines the edge of the range, inclusive. + * @return the range object, not null. + * @throws IllegalArgumentException if either element is null. + */ + public static DoubleRange of(final Double fromInclusive, final Double toInclusive) { + return new DoubleRange(fromInclusive, toInclusive); + } + + /** + * Creates an instance. + * + * @param number1 the first element, not null + * @param number2 the second element, not null + * @param comp the comparator to be used, null for natural ordering + * @throws NullPointerException when element1 is null. + * @throws NullPointerException when element2 is null. + */ + private DoubleRange(final Double number1, final Double number2) { + super(number1, number2, null); + } + +} diff --git a/src/main/java/org/apache/commons/lang3/IntegerRange.java b/src/main/java/org/apache/commons/lang3/IntegerRange.java new file mode 100644 index 000000000..3bc320cb9 --- /dev/null +++ b/src/main/java/org/apache/commons/lang3/IntegerRange.java @@ -0,0 +1,85 @@ +/* + * 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; + +/** + * Specializes {@link NumberRange} for {@link Integer}s. + * + *

+ * This class is not designed to interoperate with other NumberRanges + *

+ * + * @since 3.13.0 + */ +public final class IntegerRange extends NumberRange { + + private static final long serialVersionUID = 1L; + + /** + * Creates a range with the specified minimum and maximum values (both inclusive). + * + *

+ * The range uses the natural ordering of the elements to determine where values lie in the range. + *

+ * + *

+ * The arguments may be passed in the order (min,max) or (max,min). The getMinimum and getMaximum methods will return the correct values. + *

+ * + * @param fromInclusive the first value that defines the edge of the range, inclusive. + * @param toInclusive the second value that defines the edge of the range, inclusive. + * @return the range object, not null. + */ + public static IntegerRange of(final int fromInclusive, final int toInclusive) { + return of(Integer.valueOf(fromInclusive), Integer.valueOf(toInclusive)); + } + + /** + * Creates a range with the specified minimum and maximum values (both inclusive). + * + *

+ * The range uses the natural ordering of the elements to determine where values lie in the range. + *

+ * + *

+ * The arguments may be passed in the order (min,max) or (max,min). The getMinimum and getMaximum methods will return the correct values. + *

+ * + * @param fromInclusive the first value that defines the edge of the range, inclusive. + * @param toInclusive the second value that defines the edge of the range, inclusive. + * @return the range object, not null. + * @throws IllegalArgumentException if either element is null. + */ + public static IntegerRange of(final Integer fromInclusive, final Integer toInclusive) { + return new IntegerRange(fromInclusive, toInclusive); + } + + /** + * Creates an instance. + * + * @param number1 the first element, not null + * @param number2 the second element, not null + * @param comp the comparator to be used, null for natural ordering + * @throws NullPointerException when element1 is null. + * @throws NullPointerException when element2 is null. + */ + private IntegerRange(final Integer number1, final Integer number2) { + super(number1, number2, null); + } + +} diff --git a/src/main/java/org/apache/commons/lang3/LongRange.java b/src/main/java/org/apache/commons/lang3/LongRange.java new file mode 100644 index 000000000..55efe88ab --- /dev/null +++ b/src/main/java/org/apache/commons/lang3/LongRange.java @@ -0,0 +1,85 @@ +/* + * 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; + +/** + * Specializes {@link NumberRange} for {@link Long}s. + * + *

+ * This class is not designed to interoperate with other NumberRanges + *

+ * + * @since 3.13.0 + */ +public final class LongRange extends NumberRange { + + private static final long serialVersionUID = 1L; + + /** + * Creates a range with the specified minimum and maximum values (both inclusive). + * + *

+ * The range uses the natural ordering of the elements to determine where values lie in the range. + *

+ * + *

+ * The arguments may be passed in the order (min,max) or (max,min). The getMinimum and getMaximum methods will return the correct values. + *

+ * + * @param fromInclusive the first value that defines the edge of the range, inclusive. + * @param toInclusive the second value that defines the edge of the range, inclusive. + * @return the range object, not null. + */ + public static LongRange of(final long fromInclusive, final long toInclusive) { + return of(Long.valueOf(fromInclusive), Long.valueOf(toInclusive)); + } + + /** + * Creates a range with the specified minimum and maximum values (both inclusive). + * + *

+ * The range uses the natural ordering of the elements to determine where values lie in the range. + *

+ * + *

+ * The arguments may be passed in the order (min,max) or (max,min). The getMinimum and getMaximum methods will return the correct values. + *

+ * + * @param fromInclusive the first value that defines the edge of the range, inclusive. + * @param toInclusive the second value that defines the edge of the range, inclusive. + * @return the range object, not null. + * @throws IllegalArgumentException if either element is null. + */ + public static LongRange of(final Long fromInclusive, final Long toInclusive) { + return new LongRange(fromInclusive, toInclusive); + } + + /** + * Creates an instance. + * + * @param number1 the first element, not null + * @param number2 the second element, not null + * @param comp the comparator to be used, null for natural ordering + * @throws NullPointerException when element1 is null. + * @throws NullPointerException when element2 is null. + */ + private LongRange(final Long number1, final Long number2) { + super(number1, number2, null); + } + +} diff --git a/src/main/java/org/apache/commons/lang3/NumberRange.java b/src/main/java/org/apache/commons/lang3/NumberRange.java new file mode 100644 index 000000000..96afc3a5d --- /dev/null +++ b/src/main/java/org/apache/commons/lang3/NumberRange.java @@ -0,0 +1,48 @@ +/* + * 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.Comparator; + +/** + * Specializes {@link Range} for {@link Number}s. + *

+ * We only offer specializations for Integer, Long, and Double (like Java Streams). + *

+ * + * @param The Number class. + * @since 3.13.0 + */ +public class NumberRange extends Range { + + private static final long serialVersionUID = 1L; + + /** + * Creates an instance. + * + * @param number1 the first element, not null + * @param number2 the second element, not null + * @param comp the comparator to be used, null for natural ordering + * @throws NullPointerException when element1 is null. + * @throws NullPointerException when element2 is null. + */ + public NumberRange(final N number1, final N number2, final Comparator comp) { + super(number1, number2, comp); + } + +} diff --git a/src/main/java/org/apache/commons/lang3/Range.java b/src/main/java/org/apache/commons/lang3/Range.java index f34277828..4318fb6bf 100644 --- a/src/main/java/org/apache/commons/lang3/Range.java +++ b/src/main/java/org/apache/commons/lang3/Range.java @@ -18,6 +18,7 @@ package org.apache.commons.lang3; import java.io.Serializable; import java.util.Comparator; +import java.util.Objects; /** * An immutable range of objects from a minimum to maximum point inclusive. @@ -30,7 +31,7 @@ import java.util.Comparator; * @param The type of range values. * @since 3.0 */ -public final class Range implements Serializable { +public class Range implements Serializable { @SuppressWarnings({"rawtypes", "unchecked"}) private enum ComparableComparator implements Comparator { @@ -69,11 +70,14 @@ public final class Range implements Serializable { * @param fromInclusive the first value that defines the edge of the range, inclusive * @param toInclusive the second value that defines the edge of the range, inclusive * @return the range object, not null - * @throws IllegalArgumentException if either element is null + * @throws NullPointerException when fromInclusive is null. + * @throws NullPointerException when toInclusive is null. * @throws ClassCastException if the elements are not {@link Comparable} + * @deprecated Use {@link #of(Comparable, Comparable)}. */ + @Deprecated public static > Range between(final T fromInclusive, final T toInclusive) { - return between(fromInclusive, toInclusive, null); + return of(fromInclusive, toInclusive, null); } /** @@ -90,9 +94,12 @@ public final class Range implements Serializable { * @param toInclusive the second value that defines the edge of the range, inclusive * @param comparator the comparator to be used, null for natural ordering * @return the range object, not null - * @throws IllegalArgumentException if either element is null + * @throws NullPointerException when fromInclusive is null. + * @throws NullPointerException when toInclusive is null. * @throws ClassCastException if using natural ordering and the elements are not {@link Comparable} + * @deprecated Use {@link #of(Object, Object, Comparator)}. */ + @Deprecated public static Range between(final T fromInclusive, final T toInclusive, final Comparator comparator) { return new Range<>(fromInclusive, toInclusive, comparator); } @@ -107,11 +114,11 @@ public final class Range implements Serializable { * @param the type of the elements in this range * @param element the value to use for this range, not null * @return the range object, not null - * @throws IllegalArgumentException if the element is null + * @throws NullPointerException if the element is null * @throws ClassCastException if the element is not {@link Comparable} */ public static > Range is(final T element) { - return between(element, element, null); + return of(element, element, null); } /** @@ -125,11 +132,55 @@ public final class Range implements Serializable { * @param element the value to use for this range, must not be {@code null} * @param comparator the comparator to be used, null for natural ordering * @return the range object, not null - * @throws IllegalArgumentException if the element is null + * @throws NullPointerException if the element is null * @throws ClassCastException if using natural ordering and the elements are not {@link Comparable} */ public static Range is(final T element, final Comparator comparator) { - return between(element, element, comparator); + return of(element, element, comparator); + } + + /** + * Creates a range with the specified minimum and maximum values (both inclusive). + * + *

The range uses the natural ordering of the elements to determine where + * values lie in the range.

+ * + *

The arguments may be passed in the order (min,max) or (max,min). + * The getMinimum and getMaximum methods will return the correct values.

+ * + * @param the type of the elements in this range + * @param fromInclusive the first value that defines the edge of the range, inclusive + * @param toInclusive the second value that defines the edge of the range, inclusive + * @return the range object, not null + * @throws NullPointerException if either element is null + * @throws ClassCastException if the elements are not {@link Comparable} + * @since 3.13.0 + */ + public static > Range of(final T fromInclusive, final T toInclusive) { + return of(fromInclusive, toInclusive, null); + } + + /** + * Creates a range with the specified minimum and maximum values (both inclusive). + * + *

The range uses the specified {@link Comparator} to determine where + * values lie in the range.

+ * + *

The arguments may be passed in the order (min,max) or (max,min). + * The getMinimum and getMaximum methods will return the correct values.

+ * + * @param the type of the elements in this range + * @param fromInclusive the first value that defines the edge of the range, inclusive + * @param toInclusive the second value that defines the edge of the range, inclusive + * @param comparator the comparator to be used, null for natural ordering + * @return the range object, not null + * @throws NullPointerException when fromInclusive is null. + * @throws NullPointerException when toInclusive is null. + * @throws ClassCastException if using natural ordering and the elements are not {@link Comparable} + * @since 3.13.0 + */ + public static Range of(final T fromInclusive, final T toInclusive, final Comparator comparator) { + return new Range<>(fromInclusive, toInclusive, comparator); } /** @@ -163,13 +214,13 @@ public final class Range implements Serializable { * @param element1 the first element, not null * @param element2 the second element, not null * @param comp the comparator to be used, null for natural ordering + * @throws NullPointerException when element1 is null. + * @throws NullPointerException when element2 is null. */ @SuppressWarnings("unchecked") Range(final T element1, final T element2, final Comparator comp) { - if (element1 == null || element2 == null) { - throw new IllegalArgumentException("Elements in a range must not be null: element1=" + - element1 + ", element2=" + element2); - } + Objects.requireNonNull(element1, "element1"); + Objects.requireNonNull(element2, "element2"); if (comp == null) { this.comparator = ComparableComparator.INSTANCE; } else { @@ -357,7 +408,7 @@ public final class Range implements Serializable { } final T min = getComparator().compare(minimum, other.minimum) < 0 ? other.minimum : minimum; final T max = getComparator().compare(maximum, other.maximum) < 0 ? maximum : other.maximum; - return between(min, max, getComparator()); + return of(min, max, getComparator()); } /** diff --git a/src/main/java/org/apache/commons/lang3/time/DurationUtils.java b/src/main/java/org/apache/commons/lang3/time/DurationUtils.java index afb3804a5..2a6d7ebd7 100644 --- a/src/main/java/org/apache/commons/lang3/time/DurationUtils.java +++ b/src/main/java/org/apache/commons/lang3/time/DurationUtils.java @@ -24,8 +24,8 @@ import java.time.temporal.Temporal; import java.util.Objects; import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.LongRange; import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.Range; import org.apache.commons.lang3.function.FailableBiConsumer; import org.apache.commons.lang3.function.FailableConsumer; import org.apache.commons.lang3.function.FailableRunnable; @@ -41,8 +41,7 @@ public class DurationUtils { /** * An Integer Range that accepts Longs. */ - static final Range LONG_TO_INT_RANGE = Range.between(NumberUtils.LONG_INT_MIN_VALUE, - NumberUtils.LONG_INT_MAX_VALUE); + static final LongRange LONG_TO_INT_RANGE = LongRange.of(NumberUtils.LONG_INT_MIN_VALUE, NumberUtils.LONG_INT_MAX_VALUE); /** * Accepts the function with the duration as a long milliseconds and int nanoseconds. diff --git a/src/test/java/org/apache/commons/lang3/DoubleRangeTest.java b/src/test/java/org/apache/commons/lang3/DoubleRangeTest.java new file mode 100644 index 000000000..75b9ab66a --- /dev/null +++ b/src/test/java/org/apache/commons/lang3/DoubleRangeTest.java @@ -0,0 +1,412 @@ +/* + * 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 static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Comparator; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Tests {@link DoubleRange}. + */ +@SuppressWarnings("boxing") +public class DoubleRangeTest extends AbstractLangTest { + + private static DoubleRange of(final double min, final double max) { + return DoubleRange.of(min, max); + } + + private static DoubleRange of(final Double min, final Double max) { + return DoubleRange.of(min, max); + } + + private DoubleRange range1; + + private DoubleRange range2; + + private DoubleRange range3; + + private DoubleRange rangeFull; + + @BeforeEach + public void setUp() { + range1 = of(10, 20); + range2 = of(10, 20); + range3 = of(-2, -1); + rangeFull = of(Double.MIN_VALUE, Double.MAX_VALUE); + } + + @Test + public void testContainsInt() { + assertFalse(range1.contains(null)); + + assertTrue(rangeFull.contains(Double.MIN_VALUE)); + assertTrue(rangeFull.contains(Double.MAX_VALUE)); + + assertFalse(range1.contains(5d)); + assertTrue(range1.contains(10d)); + assertTrue(range1.contains(15d)); + assertTrue(range1.contains(20d)); + assertFalse(range1.contains(25d)); + } + + @Test + public void testContainsRange() { + + // null handling + assertFalse(range1.containsRange(null)); + + // easy inside range + assertTrue(range1.containsRange(Range.of(12d, 18d))); + assertTrue(range1.containsRange(of(12, 18))); + + // outside range on each side + assertFalse(range1.containsRange(Range.of(32d, 45d))); + assertFalse(range1.containsRange(of(32, 45))); + assertFalse(range1.containsRange(Range.of(2d, 8d))); + assertFalse(range1.containsRange(of(2, 8))); + + // equals range + assertTrue(range1.containsRange(Range.of(10d, 20d))); + assertTrue(range1.containsRange(of(10, 20))); + + // overlaps + assertFalse(range1.containsRange(Range.of(9d, 14d))); + assertFalse(range1.containsRange(of(9, 14))); + assertFalse(range1.containsRange(Range.of(16d, 21d))); + assertFalse(range1.containsRange(of(16, 21))); + + // touches lower boundary + assertTrue(range1.containsRange(Range.of(10d, 19d))); + assertTrue(range1.containsRange(of(10, 19))); + assertFalse(range1.containsRange(Range.of(10d, 21d))); + assertFalse(range1.containsRange(of(10, 21))); + + // touches upper boundary + assertTrue(range1.containsRange(Range.of(11d, 20d))); + assertTrue(range1.containsRange(of(11, 20))); + assertFalse(range1.containsRange(Range.of(9d, 20d))); + assertFalse(range1.containsRange(of(9, 20))); + + // negative + assertFalse(range1.containsRange(Range.of(-11d, -18d))); + assertFalse(range1.containsRange(of(-11, -18))); + } + + @Test + public void testElementCompareTo() { + assertThrows(NullPointerException.class, () -> range1.elementCompareTo(null)); + + assertEquals(-1, range1.elementCompareTo(5d)); + assertEquals(0, range1.elementCompareTo(10d)); + assertEquals(0, range1.elementCompareTo(15d)); + assertEquals(0, range1.elementCompareTo(20d)); + assertEquals(1, range1.elementCompareTo(25d)); + } + + @Test + public void testEqualsObject() { + assertEquals(range1, range1); + assertEquals(range1, range2); + assertEquals(range2, range2); + assertEquals(range1, range1); + assertEquals(range2, range2); + assertEquals(range3, range3); + assertNotEquals(range2, range3); + assertNotEquals(null, range2); + assertNotEquals("Ni!", range2); + } + + @Test + public void testFit() { + assertEquals(range1.getMinimum(), range1.fit(Double.MIN_VALUE)); + assertEquals(range1.getMinimum(), range1.fit(range1.getMinimum())); + assertEquals(range1.getMaximum(), range1.fit(Double.MAX_VALUE)); + assertEquals(range1.getMaximum(), range1.fit(range1.getMaximum())); + assertEquals(15, range1.fit(15d)); + } + + @Test + public void testFitNull() { + assertThrows(NullPointerException.class, () -> { + range1.fit(null); + }); + } + + @Test + public void testGetMaximum() { + assertEquals(20d, range1.getMaximum()); + } + + @Test + public void testGetMinimum() { + assertEquals(10d, range1.getMinimum()); + } + + @Test + public void testHashCode() { + assertEquals(range1.hashCode(), range2.hashCode()); + assertNotEquals(range1.hashCode(), range3.hashCode()); + + assertEquals(range1.hashCode(), range1.hashCode()); + assertTrue(range1.hashCode() != 0); + } + + @Test + public void testIntersectionWith() { + assertSame(range1, range1.intersectionWith(range1)); + + assertEquals(Range.of(10d, 15d), range1.intersectionWith(Range.of(5d, 15d))); + } + + @Test + public void testIntersectionWithNonOverlapping() { + assertThrows(IllegalArgumentException.class, () -> range1.intersectionWith(Range.of(0d, 9d))); + } + + @Test + public void testIntersectionWithNull() { + assertThrows(IllegalArgumentException.class, () -> range1.intersectionWith(null)); + } + + @Test + public void testIsAfter() { + assertFalse(range1.isAfter(null)); + + assertTrue(range1.isAfter(5d)); + assertFalse(range1.isAfter(10d)); + assertFalse(range1.isAfter(15d)); + assertFalse(range1.isAfter(20d)); + assertFalse(range1.isAfter(25d)); + } + + @Test + public void testIsAfterRange() { + assertFalse(range1.isAfterRange(null)); + + assertTrue(range1.isAfterRange(Range.of(5d, 9d))); + + assertFalse(range1.isAfterRange(Range.of(5d, 10d))); + assertFalse(range1.isAfterRange(Range.of(5d, 20d))); + assertFalse(range1.isAfterRange(Range.of(5d, 25d))); + assertFalse(range1.isAfterRange(Range.of(15d, 25d))); + + assertFalse(range1.isAfterRange(Range.of(21d, 25d))); + + assertFalse(range1.isAfterRange(Range.of(10d, 20d))); + } + + @Test + public void testIsBefore() { + assertFalse(range1.isBefore(null)); + + assertFalse(range1.isBefore(5d)); + assertFalse(range1.isBefore(10d)); + assertFalse(range1.isBefore(15d)); + assertFalse(range1.isBefore(20d)); + assertTrue(range1.isBefore(25d)); + } + + @Test + public void testIsBeforeIntegerRange() { + assertFalse(range1.isBeforeRange(null)); + + assertFalse(range1.isBeforeRange(of(5, 9))); + + assertFalse(range1.isBeforeRange(of(5, 10))); + assertFalse(range1.isBeforeRange(of(5, 20))); + assertFalse(range1.isBeforeRange(of(5, 25))); + assertFalse(range1.isBeforeRange(of(15, 25))); + + assertTrue(range1.isBeforeRange(of(21, 25))); + + assertFalse(range1.isBeforeRange(of(10, 20))); + } + + @Test + public void testIsBeforeRange() { + assertFalse(range1.isBeforeRange(null)); + + assertFalse(range1.isBeforeRange(Range.of(5d, 9d))); + + assertFalse(range1.isBeforeRange(Range.of(5d, 10d))); + assertFalse(range1.isBeforeRange(Range.of(5d, 20d))); + assertFalse(range1.isBeforeRange(Range.of(5d, 25d))); + assertFalse(range1.isBeforeRange(Range.of(15d, 25d))); + + assertTrue(range1.isBeforeRange(Range.of(21d, 25d))); + + assertFalse(range1.isBeforeRange(Range.of(10d, 20d))); + } + + @Test + public void testIsEndedBy() { + assertFalse(range1.isEndedBy(null)); + + assertFalse(range1.isEndedBy(5d)); + assertFalse(range1.isEndedBy(10d)); + assertFalse(range1.isEndedBy(15d)); + assertTrue(range1.isEndedBy(20d)); + assertFalse(range1.isEndedBy(25d)); + } + + @Test + public void testIsOverlappedByIntegerRange() { + + // null handling + assertFalse(range1.isOverlappedBy(null)); + + // easy inside range + assertTrue(range1.isOverlappedBy(of(12, 18))); + + // outside range on each side + assertFalse(range1.isOverlappedBy(of(32, 45))); + assertFalse(range1.isOverlappedBy(of(2, 8))); + + // equals range + assertTrue(range1.isOverlappedBy(of(10, 20))); + + // overlaps + assertTrue(range1.isOverlappedBy(of(9, 14))); + assertTrue(range1.isOverlappedBy(of(16, 21))); + + // touches lower boundary + assertTrue(range1.isOverlappedBy(of(10, 19))); + assertTrue(range1.isOverlappedBy(of(10, 21))); + + // touches upper boundary + assertTrue(range1.isOverlappedBy(of(11, 20))); + assertTrue(range1.isOverlappedBy(of(9, 20))); + + // negative + assertFalse(range1.isOverlappedBy(of(-11, -18))); + + // outside range whole range + assertTrue(range1.isOverlappedBy(of(9, 21))); + } + + @Test + public void testIsOverlappedByRange() { + + // null handling + assertFalse(range1.isOverlappedBy(null)); + + // easy inside range + assertTrue(range1.isOverlappedBy(Range.of(12d, 18d))); + + // outside range on each side + assertFalse(range1.isOverlappedBy(Range.of(32d, 45d))); + assertFalse(range1.isOverlappedBy(Range.of(2d, 8d))); + + // equals range + assertTrue(range1.isOverlappedBy(Range.of(10d, 20d))); + + // overlaps + assertTrue(range1.isOverlappedBy(Range.of(9d, 14d))); + assertTrue(range1.isOverlappedBy(Range.of(16d, 21d))); + + // touches lower boundary + assertTrue(range1.isOverlappedBy(Range.of(10d, 19d))); + assertTrue(range1.isOverlappedBy(Range.of(10d, 21d))); + + // touches upper boundary + assertTrue(range1.isOverlappedBy(Range.of(11d, 20d))); + assertTrue(range1.isOverlappedBy(Range.of(9d, 20d))); + + // negative + assertFalse(range1.isOverlappedBy(Range.of(-11d, -18d))); + + // outside range whole range + assertTrue(range1.isOverlappedBy(Range.of(9d, 21d))); + } + + @Test + public void testIsStartedBy() { + assertFalse(range1.isStartedBy(null)); + + assertFalse(range1.isStartedBy(5d)); + assertTrue(range1.isStartedBy(10d)); + assertFalse(range1.isStartedBy(15d)); + assertFalse(range1.isStartedBy(20d)); + assertFalse(range1.isStartedBy(25d)); + } + + @Test + public void testIsWithCompareRange() { + // all integers are equal + final Comparator c = (o1, o2) -> 0; + Range ri = Range.is(10); + assertFalse(ri.contains(null), "should not contain null"); + assertTrue(ri.contains(10), "should contain 10"); + assertFalse(ri.contains(11), "should not contain 11"); + ri = Range.is(10, c); + assertFalse(ri.contains(null), "should not contain null"); + assertTrue(ri.contains(10), "should contain 10"); + assertTrue(ri.contains(11), "should contain 11"); + } + + @Test + public void testOfWithContains() { + // all integers are equal + final DoubleRange rb = of(-10, 20); + assertFalse(rb.contains(null), "should not contain null"); + assertTrue(rb.contains(10d), "should contain 10"); + assertTrue(rb.contains(-10d), "should contain -10"); + assertFalse(rb.contains(21d), "should not contain 21"); + assertFalse(rb.contains(-11d), "should not contain -11"); + + assertThrows(NullPointerException.class, () -> of(null, null)); + } + + @Test + public void testRangeOfChars() { + final DoubleRange chars = of('a', 'z'); + assertTrue(chars.contains((double) 'b')); + assertFalse(chars.contains((double) 'B')); + } + + @Test + public void testSerializing() { + SerializationUtils.clone(range1); + } + + @Test + public void testToString() { + assertNotNull(range1.toString()); + + final String str = range1.toString(); + assertEquals("[10.0..20.0]", str); + assertEquals("[-20.0..-10.0]", Range.of(-20d, -10d).toString()); + assertEquals("[-20.0..-10.0]", DoubleRange.of(-20d, -10d).toString()); + } + + @Test + public void testToStringFormat() { + final String str = range1.toString("From %1$s to %2$s"); + assertEquals("From 10.0 to 20.0", str); + } +} diff --git a/src/test/java/org/apache/commons/lang3/IntegerRangeTest.java b/src/test/java/org/apache/commons/lang3/IntegerRangeTest.java new file mode 100644 index 000000000..7c894f298 --- /dev/null +++ b/src/test/java/org/apache/commons/lang3/IntegerRangeTest.java @@ -0,0 +1,411 @@ +/* + * 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 static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Comparator; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Tests {@link IntegerRange}. + */ +@SuppressWarnings("boxing") +public class IntegerRangeTest extends AbstractLangTest { + + private static IntegerRange of(final int min, final int max) { + return IntegerRange.of(min, max); + } + + private static IntegerRange of(final Integer min, final Integer max) { + return IntegerRange.of(min, max); + } + + private IntegerRange range1; + + private IntegerRange range2; + + private IntegerRange range3; + + private IntegerRange rangeFull; + + @BeforeEach + public void setUp() { + range1 = of(10, 20); + range2 = of(10, 20); + range3 = of(-2, -1); + rangeFull = of(Integer.MIN_VALUE, Integer.MAX_VALUE); + } + + @Test + public void testContainsInt() { + assertFalse(range1.contains(null)); + + assertTrue(rangeFull.contains(Integer.MIN_VALUE)); + assertTrue(rangeFull.contains(Integer.MAX_VALUE)); + + assertFalse(range1.contains(5)); + assertTrue(range1.contains(10)); + assertTrue(range1.contains(15)); + assertTrue(range1.contains(20)); + assertFalse(range1.contains(25)); + } + + @Test + public void testContainsRange() { + + // null handling + assertFalse(range1.containsRange(null)); + + // easy inside range + assertTrue(range1.containsRange(Range.of(12, 18))); + assertTrue(range1.containsRange(of(12, 18))); + + // outside range on each side + assertFalse(range1.containsRange(Range.of(32, 45))); + assertFalse(range1.containsRange(of(32, 45))); + assertFalse(range1.containsRange(Range.of(2, 8))); + assertFalse(range1.containsRange(of(2, 8))); + + // equals range + assertTrue(range1.containsRange(Range.of(10, 20))); + assertTrue(range1.containsRange(of(10, 20))); + + // overlaps + assertFalse(range1.containsRange(Range.of(9, 14))); + assertFalse(range1.containsRange(of(9, 14))); + assertFalse(range1.containsRange(Range.of(16, 21))); + assertFalse(range1.containsRange(of(16, 21))); + + // touches lower boundary + assertTrue(range1.containsRange(Range.of(10, 19))); + assertTrue(range1.containsRange(of(10, 19))); + assertFalse(range1.containsRange(Range.of(10, 21))); + assertFalse(range1.containsRange(of(10, 21))); + + // touches upper boundary + assertTrue(range1.containsRange(Range.of(11, 20))); + assertTrue(range1.containsRange(of(11, 20))); + assertFalse(range1.containsRange(Range.of(9, 20))); + assertFalse(range1.containsRange(of(9, 20))); + + // negative + assertFalse(range1.containsRange(Range.of(-11, -18))); + assertFalse(range1.containsRange(of(-11, -18))); + } + + @Test + public void testElementCompareTo() { + assertThrows(NullPointerException.class, () -> range1.elementCompareTo(null)); + + assertEquals(-1, range1.elementCompareTo(5)); + assertEquals(0, range1.elementCompareTo(10)); + assertEquals(0, range1.elementCompareTo(15)); + assertEquals(0, range1.elementCompareTo(20)); + assertEquals(1, range1.elementCompareTo(25)); + } + + @Test + public void testEqualsObject() { + assertEquals(range1, range1); + assertEquals(range1, range2); + assertEquals(range2, range2); + assertEquals(range1, range1); + assertEquals(range2, range2); + assertEquals(range3, range3); + assertNotEquals(range2, range3); + assertNotEquals(null, range2); + assertNotEquals("Ni!", range2); + } + + @Test + public void testFit() { + assertEquals(range1.getMinimum(), range1.fit(Integer.MIN_VALUE)); + assertEquals(range1.getMinimum(), range1.fit(range1.getMinimum())); + assertEquals(range1.getMaximum(), range1.fit(Integer.MAX_VALUE)); + assertEquals(range1.getMaximum(), range1.fit(range1.getMaximum())); + assertEquals(15, range1.fit(15)); + } + + @Test + public void testFitNull() { + assertThrows(NullPointerException.class, () -> { + range1.fit(null); + }); + } + + @Test + public void testGetMaximum() { + assertEquals(20, (int) range1.getMaximum()); + } + + @Test + public void testGetMinimum() { + assertEquals(10, (int) range1.getMinimum()); + } + + @Test + public void testHashCode() { + assertEquals(range1.hashCode(), range2.hashCode()); + assertNotEquals(range1.hashCode(), range3.hashCode()); + + assertEquals(range1.hashCode(), range1.hashCode()); + assertTrue(range1.hashCode() != 0); + } + + @Test + public void testIntersectionWith() { + assertSame(range1, range1.intersectionWith(range1)); + + assertEquals(Range.of(10, 15), range1.intersectionWith(Range.of(5, 15))); + } + + @Test + public void testIntersectionWithNonOverlapping() { + assertThrows(IllegalArgumentException.class, () -> range1.intersectionWith(Range.of(0, 9))); + } + + @Test + public void testIntersectionWithNull() { + assertThrows(IllegalArgumentException.class, () -> range1.intersectionWith(null)); + } + + @Test + public void testIsAfter() { + assertFalse(range1.isAfter(null)); + + assertTrue(range1.isAfter(5)); + assertFalse(range1.isAfter(10)); + assertFalse(range1.isAfter(15)); + assertFalse(range1.isAfter(20)); + assertFalse(range1.isAfter(25)); + } + + @Test + public void testIsAfterRange() { + assertFalse(range1.isAfterRange(null)); + + assertTrue(range1.isAfterRange(Range.of(5, 9))); + + assertFalse(range1.isAfterRange(Range.of(5, 10))); + assertFalse(range1.isAfterRange(Range.of(5, 20))); + assertFalse(range1.isAfterRange(Range.of(5, 25))); + assertFalse(range1.isAfterRange(Range.of(15, 25))); + + assertFalse(range1.isAfterRange(Range.of(21, 25))); + + assertFalse(range1.isAfterRange(Range.of(10, 20))); + } + + @Test + public void testIsBefore() { + assertFalse(range1.isBefore(null)); + + assertFalse(range1.isBefore(5)); + assertFalse(range1.isBefore(10)); + assertFalse(range1.isBefore(15)); + assertFalse(range1.isBefore(20)); + assertTrue(range1.isBefore(25)); + } + + @Test + public void testIsBeforeIntegerRange() { + assertFalse(range1.isBeforeRange(null)); + + assertFalse(range1.isBeforeRange(of(5, 9))); + + assertFalse(range1.isBeforeRange(of(5, 10))); + assertFalse(range1.isBeforeRange(of(5, 20))); + assertFalse(range1.isBeforeRange(of(5, 25))); + assertFalse(range1.isBeforeRange(of(15, 25))); + + assertTrue(range1.isBeforeRange(of(21, 25))); + + assertFalse(range1.isBeforeRange(of(10, 20))); + } + + @Test + public void testIsBeforeRange() { + assertFalse(range1.isBeforeRange(null)); + + assertFalse(range1.isBeforeRange(Range.of(5, 9))); + + assertFalse(range1.isBeforeRange(Range.of(5, 10))); + assertFalse(range1.isBeforeRange(Range.of(5, 20))); + assertFalse(range1.isBeforeRange(Range.of(5, 25))); + assertFalse(range1.isBeforeRange(Range.of(15, 25))); + + assertTrue(range1.isBeforeRange(Range.of(21, 25))); + + assertFalse(range1.isBeforeRange(Range.of(10, 20))); + } + + @Test + public void testIsEndedBy() { + assertFalse(range1.isEndedBy(null)); + + assertFalse(range1.isEndedBy(5)); + assertFalse(range1.isEndedBy(10)); + assertFalse(range1.isEndedBy(15)); + assertTrue(range1.isEndedBy(20)); + assertFalse(range1.isEndedBy(25)); + } + + @Test + public void testIsOverlappedByIntegerRange() { + + // null handling + assertFalse(range1.isOverlappedBy(null)); + + // easy inside range + assertTrue(range1.isOverlappedBy(of(12, 18))); + + // outside range on each side + assertFalse(range1.isOverlappedBy(of(32, 45))); + assertFalse(range1.isOverlappedBy(of(2, 8))); + + // equals range + assertTrue(range1.isOverlappedBy(of(10, 20))); + + // overlaps + assertTrue(range1.isOverlappedBy(of(9, 14))); + assertTrue(range1.isOverlappedBy(of(16, 21))); + + // touches lower boundary + assertTrue(range1.isOverlappedBy(of(10, 19))); + assertTrue(range1.isOverlappedBy(of(10, 21))); + + // touches upper boundary + assertTrue(range1.isOverlappedBy(of(11, 20))); + assertTrue(range1.isOverlappedBy(of(9, 20))); + + // negative + assertFalse(range1.isOverlappedBy(of(-11, -18))); + + // outside range whole range + assertTrue(range1.isOverlappedBy(of(9, 21))); + } + + @Test + public void testIsOverlappedByRange() { + + // null handling + assertFalse(range1.isOverlappedBy(null)); + + // easy inside range + assertTrue(range1.isOverlappedBy(Range.of(12, 18))); + + // outside range on each side + assertFalse(range1.isOverlappedBy(Range.of(32, 45))); + assertFalse(range1.isOverlappedBy(Range.of(2, 8))); + + // equals range + assertTrue(range1.isOverlappedBy(Range.of(10, 20))); + + // overlaps + assertTrue(range1.isOverlappedBy(Range.of(9, 14))); + assertTrue(range1.isOverlappedBy(Range.of(16, 21))); + + // touches lower boundary + assertTrue(range1.isOverlappedBy(Range.of(10, 19))); + assertTrue(range1.isOverlappedBy(Range.of(10, 21))); + + // touches upper boundary + assertTrue(range1.isOverlappedBy(Range.of(11, 20))); + assertTrue(range1.isOverlappedBy(Range.of(9, 20))); + + // negative + assertFalse(range1.isOverlappedBy(Range.of(-11, -18))); + + // outside range whole range + assertTrue(range1.isOverlappedBy(Range.of(9, 21))); + } + + @Test + public void testIsStartedBy() { + assertFalse(range1.isStartedBy(null)); + + assertFalse(range1.isStartedBy(5)); + assertTrue(range1.isStartedBy(10)); + assertFalse(range1.isStartedBy(15)); + assertFalse(range1.isStartedBy(20)); + assertFalse(range1.isStartedBy(25)); + } + + @Test + public void testIsWithCompareRange() { + // all integers are equal + final Comparator c = (o1, o2) -> 0; + Range ri = Range.is(10); + assertFalse(ri.contains(null), "should not contain null"); + assertTrue(ri.contains(10), "should contain 10"); + assertFalse(ri.contains(11), "should not contain 11"); + ri = Range.is(10, c); + assertFalse(ri.contains(null), "should not contain null"); + assertTrue(ri.contains(10), "should contain 10"); + assertTrue(ri.contains(11), "should contain 11"); + } + + @Test + public void testOfWithContains() { + // all integers are equal + final IntegerRange rb = of(-10, 20); + assertFalse(rb.contains(null), "should not contain null"); + assertTrue(rb.contains(10), "should contain 10"); + assertTrue(rb.contains(-10), "should contain -10"); + assertFalse(rb.contains(21), "should not contain 21"); + assertFalse(rb.contains(-11), "should not contain -11"); + + assertThrows(NullPointerException.class, () -> of(null, null)); + } + + @Test + public void testRangeOfChars() { + final IntegerRange chars = of('a', 'z'); + assertTrue(chars.contains((int) 'b')); + assertFalse(chars.contains((int) 'B')); + } + + @Test + public void testSerializing() { + SerializationUtils.clone(range1); + } + + @Test + public void testToString() { + assertNotNull(range1.toString()); + + final String str = range1.toString(); + assertEquals("[10..20]", str); + assertEquals("[-20..-10]", Range.of(-20, -10).toString()); + } + + @Test + public void testToStringFormat() { + final String str = range1.toString("From %1$s to %2$s"); + assertEquals("From 10 to 20", str); + } +} diff --git a/src/test/java/org/apache/commons/lang3/LongRangeTest.java b/src/test/java/org/apache/commons/lang3/LongRangeTest.java new file mode 100644 index 000000000..290ce8a00 --- /dev/null +++ b/src/test/java/org/apache/commons/lang3/LongRangeTest.java @@ -0,0 +1,426 @@ +/* + * 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 static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Comparator; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Tests {@link LongRange}. + */ +@SuppressWarnings("boxing") +public class LongRangeTest extends AbstractLangTest { + + private static LongRange of(final int min, final int max) { + return LongRange.of(min, max); + } + + private static LongRange of(final Long min, final Long max) { + return LongRange.of(min, max); + } + + private LongRange range1; + + private LongRange range2; + + private LongRange range3; + + private LongRange rangeFull; + + @BeforeEach + public void setUp() { + range1 = of(10, 20); + range2 = of(10, 20); + range3 = of(-2, -1); + rangeFull = of(Long.MIN_VALUE, Long.MAX_VALUE); + } + + @Test + public void testContainsInt() { + assertFalse(range1.contains(null)); + + assertFalse(range1.contains(5L)); + assertTrue(range1.contains(10L)); + assertTrue(range1.contains(15L)); + assertTrue(range1.contains(20L)); + assertFalse(range1.contains(25L)); + } + + @Test + public void testContainsLong() { + assertFalse(range1.contains(null)); + + assertTrue(rangeFull.contains(Long.MAX_VALUE)); + assertTrue(rangeFull.contains(Long.MIN_VALUE)); + assertTrue(rangeFull.contains((long) Integer.MAX_VALUE + 1)); + assertTrue(rangeFull.contains((long) Integer.MIN_VALUE - 1)); + assertTrue(rangeFull.contains((long) Integer.MAX_VALUE)); + assertTrue(rangeFull.contains((long) Integer.MIN_VALUE)); + + assertFalse(range1.contains(5L)); + assertTrue(range1.contains(10L)); + assertTrue(range1.contains(15L)); + assertTrue(range1.contains(20L)); + assertFalse(range1.contains(25L)); + } + + @Test + public void testContainsRange() { + + // null handling + assertFalse(range1.containsRange(null)); + + // easy inside range + assertTrue(range1.containsRange(Range.of(12L, 18L))); + assertTrue(range1.containsRange(of(12, 18))); + + // outside range on each side + assertFalse(range1.containsRange(Range.of(32L, 45L))); + assertFalse(range1.containsRange(of(32, 45))); + assertFalse(range1.containsRange(Range.of(2L, 8L))); + assertFalse(range1.containsRange(of(2, 8))); + + // equals range + assertTrue(range1.containsRange(Range.of(10L, 20L))); + assertTrue(range1.containsRange(of(10, 20))); + + // overlaps + assertFalse(range1.containsRange(Range.of(9L, 14L))); + assertFalse(range1.containsRange(of(9, 14))); + assertFalse(range1.containsRange(Range.of(16L, 21L))); + assertFalse(range1.containsRange(of(16, 21))); + + // touches lower boundary + assertTrue(range1.containsRange(Range.of(10L, 19L))); + assertTrue(range1.containsRange(of(10, 19))); + assertFalse(range1.containsRange(Range.of(10L, 21L))); + assertFalse(range1.containsRange(of(10, 21))); + + // touches upper boundary + assertTrue(range1.containsRange(Range.of(11L, 20L))); + assertTrue(range1.containsRange(of(11, 20))); + assertFalse(range1.containsRange(Range.of(9L, 20L))); + assertFalse(range1.containsRange(of(9, 20))); + + // negative + assertFalse(range1.containsRange(Range.of(-11L, -18L))); + assertFalse(range1.containsRange(of(-11, -18))); + } + + @Test + public void testElementCompareTo() { + assertThrows(NullPointerException.class, () -> range1.elementCompareTo(null)); + + assertEquals(-1, range1.elementCompareTo(5L)); + assertEquals(0, range1.elementCompareTo(10L)); + assertEquals(0, range1.elementCompareTo(15L)); + assertEquals(0, range1.elementCompareTo(20L)); + assertEquals(1, range1.elementCompareTo(25L)); + } + + @Test + public void testEqualsObject() { + assertEquals(range1, range1); + assertEquals(range1, range2); + assertEquals(range2, range2); + assertEquals(range1, range1); + assertEquals(range2, range2); + assertEquals(range3, range3); + assertNotEquals(range2, range3); + assertNotEquals(null, range2); + assertNotEquals("Ni!", range2); + } + + @Test + public void testFit() { + assertEquals(range1.getMinimum(), range1.fit((long) Integer.MIN_VALUE)); + assertEquals(range1.getMinimum(), range1.fit(range1.getMinimum())); + assertEquals(range1.getMaximum(), range1.fit((long) Integer.MAX_VALUE)); + assertEquals(range1.getMaximum(), range1.fit(range1.getMaximum())); + assertEquals(15, range1.fit(15L)); + } + + @Test + public void testFitNull() { + assertThrows(NullPointerException.class, () -> { + range1.fit(null); + }); + } + + @Test + public void testGetMaximum() { + assertEquals(20, range1.getMaximum()); + } + + @Test + public void testGetMinimum() { + assertEquals(10, range1.getMinimum()); + } + + @Test + public void testHashCode() { + assertEquals(range1.hashCode(), range2.hashCode()); + assertNotEquals(range1.hashCode(), range3.hashCode()); + + assertEquals(range1.hashCode(), range1.hashCode()); + assertTrue(range1.hashCode() != 0); + } + + @Test + public void testIntersectionWith() { + assertSame(range1, range1.intersectionWith(range1)); + + assertEquals(Range.of(10L, 15L), range1.intersectionWith(Range.of(5L, 15L))); + } + + @Test + public void testIntersectionWithNonOverlapping() { + assertThrows(IllegalArgumentException.class, () -> range1.intersectionWith(Range.of(0L, 9L))); + } + + @Test + public void testIntersectionWithNull() { + assertThrows(IllegalArgumentException.class, () -> range1.intersectionWith(null)); + } + + @Test + public void testIsAfter() { + assertFalse(range1.isAfter(null)); + + assertTrue(range1.isAfter(5L)); + assertFalse(range1.isAfter(10L)); + assertFalse(range1.isAfter(15L)); + assertFalse(range1.isAfter(20L)); + assertFalse(range1.isAfter(25L)); + } + + @Test + public void testIsAfterRange() { + assertFalse(range1.isAfterRange(null)); + + assertTrue(range1.isAfterRange(Range.of(5L, 9L))); + + assertFalse(range1.isAfterRange(Range.of(5L, 10L))); + assertFalse(range1.isAfterRange(Range.of(5L, 20L))); + assertFalse(range1.isAfterRange(Range.of(5L, 25L))); + assertFalse(range1.isAfterRange(Range.of(15L, 25L))); + + assertFalse(range1.isAfterRange(Range.of(21L, 25L))); + + assertFalse(range1.isAfterRange(Range.of(10L, 20L))); + } + + @Test + public void testIsBefore() { + assertFalse(range1.isBefore(null)); + + assertFalse(range1.isBefore(5L)); + assertFalse(range1.isBefore(10L)); + assertFalse(range1.isBefore(15L)); + assertFalse(range1.isBefore(20L)); + assertTrue(range1.isBefore(25L)); + } + + @Test + public void testIsBeforeIntegerRange() { + assertFalse(range1.isBeforeRange(null)); + + assertFalse(range1.isBeforeRange(of(5, 9))); + + assertFalse(range1.isBeforeRange(of(5, 10))); + assertFalse(range1.isBeforeRange(of(5, 20))); + assertFalse(range1.isBeforeRange(of(5, 25))); + assertFalse(range1.isBeforeRange(of(15, 25))); + + assertTrue(range1.isBeforeRange(of(21, 25))); + + assertFalse(range1.isBeforeRange(of(10, 20))); + } + + @Test + public void testIsBeforeRange() { + assertFalse(range1.isBeforeRange(null)); + + assertFalse(range1.isBeforeRange(Range.of(5L, 9L))); + + assertFalse(range1.isBeforeRange(Range.of(5L, 10L))); + assertFalse(range1.isBeforeRange(Range.of(5L, 20L))); + assertFalse(range1.isBeforeRange(Range.of(5L, 25L))); + assertFalse(range1.isBeforeRange(Range.of(15L, 25L))); + + assertTrue(range1.isBeforeRange(Range.of(21L, 25L))); + + assertFalse(range1.isBeforeRange(Range.of(10L, 20L))); + } + + @Test + public void testIsEndedBy() { + assertFalse(range1.isEndedBy(null)); + + assertFalse(range1.isEndedBy(5L)); + assertFalse(range1.isEndedBy(10L)); + assertFalse(range1.isEndedBy(15L)); + assertTrue(range1.isEndedBy(20L)); + assertFalse(range1.isEndedBy(25L)); + } + + @Test + public void testIsOverlappedByIntegerRange() { + + // null handling + assertFalse(range1.isOverlappedBy(null)); + + // easy inside range + assertTrue(range1.isOverlappedBy(of(12, 18))); + + // outside range on each side + assertFalse(range1.isOverlappedBy(of(32, 45))); + assertFalse(range1.isOverlappedBy(of(2, 8))); + + // equals range + assertTrue(range1.isOverlappedBy(of(10, 20))); + + // overlaps + assertTrue(range1.isOverlappedBy(of(9, 14))); + assertTrue(range1.isOverlappedBy(of(16, 21))); + + // touches lower boundary + assertTrue(range1.isOverlappedBy(of(10, 19))); + assertTrue(range1.isOverlappedBy(of(10, 21))); + + // touches upper boundary + assertTrue(range1.isOverlappedBy(of(11, 20))); + assertTrue(range1.isOverlappedBy(of(9, 20))); + + // negative + assertFalse(range1.isOverlappedBy(of(-11, -18))); + + // outside range whole range + assertTrue(range1.isOverlappedBy(of(9, 21))); + } + + @Test + public void testIsOverlappedByRange() { + + // null handling + assertFalse(range1.isOverlappedBy(null)); + + // easy inside range + assertTrue(range1.isOverlappedBy(Range.of(12L, 18L))); + + // outside range on each side + assertFalse(range1.isOverlappedBy(Range.of(32L, 45L))); + assertFalse(range1.isOverlappedBy(Range.of(2L, 8L))); + + // equals range + assertTrue(range1.isOverlappedBy(Range.of(10L, 20L))); + + // overlaps + assertTrue(range1.isOverlappedBy(Range.of(9L, 14L))); + assertTrue(range1.isOverlappedBy(Range.of(16L, 21L))); + + // touches lower boundary + assertTrue(range1.isOverlappedBy(Range.of(10L, 19L))); + assertTrue(range1.isOverlappedBy(Range.of(10L, 21L))); + + // touches upper boundary + assertTrue(range1.isOverlappedBy(Range.of(11L, 20L))); + assertTrue(range1.isOverlappedBy(Range.of(9L, 20L))); + + // negative + assertFalse(range1.isOverlappedBy(Range.of(-11L, -18L))); + + // outside range whole range + assertTrue(range1.isOverlappedBy(Range.of(9L, 21L))); + } + + @Test + public void testIsStartedBy() { + assertFalse(range1.isStartedBy(null)); + + assertFalse(range1.isStartedBy(5L)); + assertTrue(range1.isStartedBy(10L)); + assertFalse(range1.isStartedBy(15L)); + assertFalse(range1.isStartedBy(20L)); + assertFalse(range1.isStartedBy(25L)); + } + + @Test + public void testIsWithCompareRange() { + // all integers are equal + final Comparator c = (o1, o2) -> 0; + Range ri = Range.is(10); + assertFalse(ri.contains(null), "should not contain null"); + assertTrue(ri.contains(10), "should contain 10"); + assertFalse(ri.contains(11), "should not contain 11"); + ri = Range.is(10, c); + assertFalse(ri.contains(null), "should not contain null"); + assertTrue(ri.contains(10), "should contain 10"); + assertTrue(ri.contains(11), "should contain 11"); + } + + @Test + public void testOfWithContains() { + // all integers are equal + final LongRange rb = of(-10, 20); + assertFalse(rb.contains(null), "should not contain null"); + assertTrue(rb.contains(10L), "should contain 10"); + assertTrue(rb.contains(-10L), "should contain -10"); + assertFalse(rb.contains(21L), "should not contain 21"); + assertFalse(rb.contains(-11L), "should not contain -11"); + + assertThrows(NullPointerException.class, () -> of(null, null)); + } + + @Test + public void testRangeOfChars() { + final LongRange chars = of((long) 'a', (long) 'z'); + assertTrue(chars.contains((long) 'b')); + assertFalse(chars.contains((long) 'B')); + } + + @Test + public void testSerializing() { + SerializationUtils.clone(range1); + } + + @Test + public void testToString() { + assertNotNull(range1.toString()); + + final String str = range1.toString(); + assertEquals("[10..20]", str); + assertEquals("[-20..-10]", Range.of(-20, -10).toString()); + } + + @Test + public void testToStringFormat() { + final String str = range1.toString("From %1$s to %2$s"); + assertEquals("From 10 to 20", str); + } +} diff --git a/src/test/java/org/apache/commons/lang3/RangeTest.java b/src/test/java/org/apache/commons/lang3/RangeTest.java index 4ed18cdf4..8b477c354 100644 --- a/src/test/java/org/apache/commons/lang3/RangeTest.java +++ b/src/test/java/org/apache/commons/lang3/RangeTest.java @@ -53,23 +53,20 @@ public class RangeTest extends AbstractLangTest { private Range byteRange2; private Range byteRange3; private Range doubleRange; - private Range floatRange; - private Range intRange; - private Range longRange; @BeforeEach public void setUp() { - byteRange = Range.between((byte) 0, (byte) 5); - byteRange2 = Range.between((byte) 0, (byte) 5); - byteRange3 = Range.between((byte) 0, (byte) 10); - - intRange = Range.between(10, 20); - longRange = Range.between(10L, 20L); - floatRange = Range.between((float) 10, (float) 20); - doubleRange = Range.between((double) 10, (double) 20); + byteRange = Range.of((byte) 0, (byte) 5); + byteRange2 = Range.of((byte) 0, (byte) 5); + byteRange3 = Range.of((byte) 0, (byte) 10); + + intRange = Range.of(10, 20); + longRange = Range.of(10L, 20L); + floatRange = Range.of((float) 10, (float) 20); + doubleRange = Range.of((double) 10, (double) 20); } @Test @@ -102,9 +99,40 @@ public class RangeTest extends AbstractLangTest { assertFalse(rbstr.contains("houses"), "should not contain houses"); assertFalse(rbstr.contains(""), "should not contain ''"); - assertThrows( - IllegalArgumentException.class, - () -> Range.between(null, null, lengthComp)); + assertThrows(NullPointerException.class, () -> Range.between(null, null, lengthComp)); + } + + @Test + public void testOfWithCompare() { + // all integers are equal + final Comparator c = (o1, o2) -> 0; + final Comparator lengthComp = Comparator.comparingInt(String::length); + Range rb = Range.of(-10, 20); + assertFalse(rb.contains(null), "should not contain null"); + assertTrue(rb.contains(10), "should contain 10"); + assertTrue(rb.contains(-10), "should contain -10"); + assertFalse(rb.contains(21), "should not contain 21"); + assertFalse(rb.contains(-11), "should not contain -11"); + rb = Range.of(-10, 20, c); + assertFalse(rb.contains(null), "should not contain null"); + assertTrue(rb.contains(10), "should contain 10"); + assertTrue(rb.contains(-10), "should contain -10"); + assertTrue(rb.contains(21), "should contain 21"); + assertTrue(rb.contains(-11), "should contain -11"); + Range rbstr = Range.of("house", "i"); + assertFalse(rbstr.contains(null), "should not contain null"); + assertTrue(rbstr.contains("house"), "should contain house"); + assertTrue(rbstr.contains("i"), "should contain i"); + assertFalse(rbstr.contains("hose"), "should not contain hose"); + assertFalse(rbstr.contains("ice"), "should not contain ice"); + rbstr = Range.of("house", "i", lengthComp); + assertFalse(rbstr.contains(null), "should not contain null"); + assertTrue(rbstr.contains("house"), "should contain house"); + assertTrue(rbstr.contains("i"), "should contain i"); + assertFalse(rbstr.contains("houses"), "should not contain houses"); + assertFalse(rbstr.contains(""), "should not contain ''"); + + assertThrows(NullPointerException.class, () -> Range.of(null, null, lengthComp)); } @SuppressWarnings({"rawtypes", "unchecked"}) -- cgit v1.2.3