/** * Copyright (C) 2014-2017 Xavier Witdouck * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.zavtech.morpheus.range; import java.time.DayOfWeek; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Period; import java.time.ZoneId; import java.time.ZonedDateTime; import com.zavtech.morpheus.array.Array; import com.zavtech.morpheus.array.ArrayType; import com.zavtech.morpheus.array.ArrayValue; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Unit test for the Range class with filters applied * * <p><strong>This is open source software released under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a></strong></p> * * @author Xavier Witdouck */ public class RangeFilterTests { @DataProvider(name="IntRanges") public Object[][] intRanges() { return new Object[][] { { 0, 100000, 1, false }, { 0, 100000, 5, false }, { 100000, 6, 1, false }, { 100000, 6, 6, false }, { 0, 100000, 1, true }, { 0, 100000, 5, true }, { 100000, 6, 1, true }, { 100000, 6, 6, true }, }; } @DataProvider(name="LongRanges") public Object[][] longRanges() { return new Object[][] { { 0L, 100000L, 1L, false }, { 0L, 100000L, 5L, false }, { 100000L, 6L, 1L, false }, { 100000L, 6L, 6L, false }, { 0L, 100000L, 1L, true }, { 0L, 100000L, 5L, true }, { 100000L, 6L, 1L, true }, { 100000L, 6L, 6L, true }, }; } @DataProvider(name="DoubleRanges") public Object[][] doubleRanges() { return new Object[][] { { 0d, 100000d, 1d, false }, { 0d, 100000d, 5d, false }, { 100000d, 6d, 1d, false }, { 100000d, 6d, 6d, false }, { 0d, 100000d, 1d, true }, { 0d, 100000d, 5d, true }, { 100000d, 6d, 1d, true }, { 100000d, 6d, 6d, true }, }; } @DataProvider(name="LocalDateRanges") public Object[][] localDateRanges() { return new Object[][] { { LocalDate.of(1990, 1, 1), LocalDate.of(1990, 12, 31), Period.ofDays(1), false }, { LocalDate.of(1990, 1, 1), LocalDate.of(1990, 12, 31), Period.ofDays(5), false }, { LocalDate.of(2014, 12, 1), LocalDate.of(2013, 1, 1), Period.ofDays(3), false }, { LocalDate.of(2014, 12, 1), LocalDate.of(2014, 1, 1), Period.ofDays(6), false }, { LocalDate.of(1990, 1, 1), LocalDate.of(1990, 12, 31), Period.ofDays(1), true }, { LocalDate.of(1990, 1, 1), LocalDate.of(1990, 12, 31), Period.ofDays(5), true }, { LocalDate.of(2014, 12, 1), LocalDate.of(2013, 1, 1), Period.ofDays(3), true }, { LocalDate.of(2014, 12, 1), LocalDate.of(2014, 1, 1), Period.ofDays(6), true }, }; } @DataProvider(name="LocalTimeRanges") public Object[][] localTimeRanges() { return new Object[][] { { LocalTime.of(9, 0), LocalTime.of(13, 0), Duration.ofSeconds(1), false }, { LocalTime.of(9, 0), LocalTime.of(13, 0), Duration.ofSeconds(5), false }, { LocalTime.of(20, 0), LocalTime.of(13, 0), Duration.ofSeconds(1), false }, { LocalTime.of(20, 0), LocalTime.of(13, 0), Duration.ofSeconds(7), false }, { LocalTime.of(9, 0), LocalTime.of(13, 0), Duration.ofSeconds(1), true }, { LocalTime.of(9, 0), LocalTime.of(13, 0), Duration.ofSeconds(5), true }, { LocalTime.of(20, 0), LocalTime.of(13, 0), Duration.ofSeconds(1), true }, { LocalTime.of(20, 0), LocalTime.of(13, 0), Duration.ofSeconds(7), true }, }; } @DataProvider(name="LocalDateTimeRanges") public Object[][] localDateTimeRanges() { return new Object[][] { { LocalDateTime.of(1990, 1, 1, 9, 0), LocalDateTime.of(1990, 12, 31, 13, 0), Duration.ofMinutes(1), false }, { LocalDateTime.of(1990, 1, 1, 9, 0), LocalDateTime.of(1990, 12, 31, 15, 30), Duration.ofMinutes(5), false }, { LocalDateTime.of(2014, 12, 1, 7 ,25), LocalDateTime.of(2013, 1, 1, 9, 15), Duration.ofMinutes(1), false }, { LocalDateTime.of(2014, 12, 1, 6, 30), LocalDateTime.of(2014, 1, 1, 10, 45), Duration.ofMinutes(7), false }, { LocalDateTime.of(1990, 1, 1, 9, 0), LocalDateTime.of(1990, 12, 31, 13, 0), Duration.ofMinutes(1), true }, { LocalDateTime.of(1990, 1, 1, 9, 0), LocalDateTime.of(1990, 12, 31, 15, 30), Duration.ofMinutes(5), true }, { LocalDateTime.of(2014, 12, 1, 7 ,25), LocalDateTime.of(2013, 1, 1, 9, 15), Duration.ofMinutes(1), true }, { LocalDateTime.of(2014, 12, 1, 6, 30), LocalDateTime.of(2014, 1, 1, 10, 45), Duration.ofMinutes(7), true }, }; } @DataProvider(name="ZonedDateTimeRanges") public Object[][] zonedDateTimeRanges() { final ZoneId gmt = ZoneId.of("GMT"); return new Object[][] { { ZonedDateTime.of(1990, 1, 1, 9, 0, 0, 0, gmt), ZonedDateTime.of(1990, 12, 31, 13, 0, 0, 0, gmt), Duration.ofMinutes(1), false }, { ZonedDateTime.of(1990, 1, 1, 9, 0, 0, 0, gmt), ZonedDateTime.of(1990, 12, 31, 15, 30, 0, 0, gmt), Duration.ofMinutes(5), false }, { ZonedDateTime.of(2014, 12, 1, 7 ,25, 0, 0, gmt), ZonedDateTime.of(2013, 1, 1, 9, 15, 0, 0, gmt), Duration.ofMinutes(1), false }, { ZonedDateTime.of(2014, 12, 1, 6, 30, 0, 0, gmt), ZonedDateTime.of(2014, 1, 1, 10, 45, 0, 0, gmt), Duration.ofMinutes(7), false }, { ZonedDateTime.of(1990, 1, 1, 9, 0, 0, 0, gmt), ZonedDateTime.of(1990, 12, 31, 13, 0, 0, 0, gmt), Duration.ofMinutes(1), true }, { ZonedDateTime.of(1990, 1, 1, 9, 0, 0, 0, gmt), ZonedDateTime.of(1990, 12, 31, 15, 30, 0, 0, gmt), Duration.ofMinutes(5), true }, { ZonedDateTime.of(2014, 12, 1, 7 ,25, 0, 0, gmt), ZonedDateTime.of(2013, 1, 1, 9, 15, 0, 0, gmt), Duration.ofMinutes(1), true }, { ZonedDateTime.of(2014, 12, 1, 6, 30, 0, 0, gmt), ZonedDateTime.of(2014, 1, 1, 10, 45, 0, 0, gmt), Duration.ofMinutes(7), true }, }; } @Test(dataProvider = "IntRanges") public void testRangeOfInts(int start, int end, int step, boolean parallel) { final boolean ascend = start < end; final Range<Integer> range = Range.of(start, end, step, (int v) -> v < 10); final Array<Integer> array = range.toArray(parallel); final int first = array.first(v -> true).map(ArrayValue::getValue).get(); final int last = array.last(v -> true).map(ArrayValue::getValue).get(); Assert.assertTrue(array.length() > 0, "There are elements in the array"); Assert.assertEquals(array.typeCode(), ArrayType.INTEGER); Assert.assertTrue(!array.style().isSparse()); Assert.assertEquals(range.start().intValue(), start, "The range start"); Assert.assertEquals(range.end().intValue(), end, "The range end"); int index = 0; int value = first; while (ascend ? value < last : value > last) { final int actual = array.getInt(index); Assert.assertEquals(actual, value, "Value matches at " + index); Assert.assertTrue(ascend ? actual >= start && actual < end : actual <= start && actual > end, "Value in bounds at " + index); value = ascend ? value + step : value - step; index++; } } @Test(dataProvider = "LongRanges") public void testRangeOfLongs(long start, long end, long step, boolean parallel) { final boolean ascend = start < end; final Range<Long> range = Range.of(start, end, step, (long v) -> v < 10); final Array<Long> array = range.toArray(parallel); final long first = array.first(v -> true).map(ArrayValue::getValue).get(); final long last = array.last(v -> true).map(ArrayValue::getValue).get(); Assert.assertTrue(array.length() > 0, "There are elements in the array"); Assert.assertEquals(array.typeCode(), ArrayType.LONG); Assert.assertTrue(!array.style().isSparse()); Assert.assertEquals(range.start().intValue(), start, "The range start"); Assert.assertEquals(range.end().intValue(), end, "The range end"); int index = 0; long value = first; while (ascend ? value < last : value > last) { final long actual = array.getLong(index); Assert.assertEquals(actual, value, "Value matches at " + index); Assert.assertTrue(ascend ? actual >= start && actual < end : actual <= start && actual > end, "Value in bounds at " + index); value = ascend ? value + step : value - step; index++; } } @Test(dataProvider = "DoubleRanges") public void testRangeOfDoubles(double start, double end, double step, boolean parallel) { final boolean ascend = start < end; final Range<Double> range = Range.of(start, end, step, (double v) -> v < 10); final Array<Double> array = range.toArray(parallel); final double first = array.first(v -> true).map(ArrayValue::getValue).get(); final double last = array.last(v -> true).map(ArrayValue::getValue).get(); Assert.assertTrue(array.length() > 0, "There are elements in the array"); Assert.assertEquals(array.typeCode(), ArrayType.DOUBLE); Assert.assertTrue(!array.style().isSparse()); Assert.assertEquals(range.start(), start, "The range start"); Assert.assertEquals(range.end(), end, "The range end"); int index = 0; double value = first; while (ascend ? value < last : value > last) { final double actual = array.getDouble(index); Assert.assertEquals(actual, value, "Value matches at " + index); Assert.assertTrue(ascend ? actual >= start && actual < end : actual <= start && actual > end, "Value in bounds at " + index); value = ascend ? value + step : value - step; index++; } } @Test(dataProvider = "LocalDateRanges") public void testRangeOfLocalDates(LocalDate start, LocalDate end, Period step, boolean parallel) { final boolean ascend = start.isBefore(end); final Range<LocalDate> range = Range.of(start, end, step, v -> v.getDayOfWeek() == DayOfWeek.MONDAY); final Array<LocalDate> array = range.toArray(parallel); final LocalDate first = array.first(v -> true).map(ArrayValue::getValue).get(); final LocalDate last = array.last(v -> true).map(ArrayValue::getValue).get(); Assert.assertEquals(array.typeCode(), ArrayType.LOCAL_DATE); Assert.assertTrue(!array.style().isSparse()); Assert.assertEquals(range.start(), start, "The range start"); Assert.assertEquals(range.end(), end, "The range end"); int index = 0; LocalDate value = first; while (ascend ? value.isBefore(last) : value.isAfter(last)) { final LocalDate actual = array.getValue(index); Assert.assertEquals(actual, value, "Value matches at " + index); Assert.assertTrue(ascend ? actual.compareTo(start) >= 0 && actual.isBefore(end) : actual.compareTo(start) <= 0 && actual.isAfter(end), "Value in bounds at " + index); value = ascend ? value.plus(step) : value.minus(step); while (value.getDayOfWeek() == DayOfWeek.MONDAY) value = ascend ? value.plus(step) : value.minus(step); index++; } } @Test(dataProvider = "LocalTimeRanges") public void testRangeOfLocalTimes(LocalTime start, LocalTime end, Duration step, boolean parallel) { final boolean ascend = start.isBefore(end); final Range<LocalTime> range = Range.of(start, end, step, v -> v.getHour() == 6); final Array<LocalTime> array = range.toArray(parallel); final LocalTime first = array.first(v -> true).map(ArrayValue::getValue).get(); final LocalTime last = array.last(v -> true).map(ArrayValue::getValue).get(); Assert.assertEquals(array.typeCode(), ArrayType.LOCAL_TIME); Assert.assertTrue(!array.style().isSparse()); Assert.assertEquals(range.start(), start, "The range start"); Assert.assertEquals(range.end(), end, "The range end"); int index = 0; LocalTime value = first; while (ascend ? value.isBefore(last) : value.isAfter(last)) { final LocalTime actual = array.getValue(index); Assert.assertEquals(actual, value, "Value matches at " + index); Assert.assertTrue(ascend ? actual.compareTo(start) >= 0 && actual.isBefore(end) : actual.compareTo(start) <= 0 && actual.isAfter(end), "Value in bounds at " + index); value = ascend ? value.plus(step) : value.minus(step); while (value.getHour() == 6) value = ascend ? value.plus(step) : value.minus(step); index++; } } @Test(dataProvider = "LocalDateTimeRanges") public void testRangeOfLocalDateTimes(LocalDateTime start, LocalDateTime end, Duration step, boolean parallel) { final boolean ascend = start.isBefore(end); final Range<LocalDateTime> range = Range.of(start, end, step, v -> v.getHour() == 6); final Array<LocalDateTime> array = range.toArray(parallel); final LocalDateTime first = array.first(v -> true).map(ArrayValue::getValue).get(); final LocalDateTime last = array.last(v -> true).map(ArrayValue::getValue).get(); Assert.assertEquals(array.typeCode(), ArrayType.LOCAL_DATETIME); Assert.assertTrue(!array.style().isSparse()); Assert.assertEquals(range.start(), start, "The range start"); Assert.assertEquals(range.end(), end, "The range end"); int index = 0; LocalDateTime value = first; while (ascend ? value.isBefore(last) : value.isAfter(last)) { final LocalDateTime actual = array.getValue(index); Assert.assertEquals(actual, value, "Value matches at " + index); Assert.assertTrue(ascend ? actual.compareTo(start) >= 0 && actual.isBefore(end) : actual.compareTo(start) <= 0 && actual.isAfter(end), "Value in bounds at " + index); value = ascend ? value.plus(step) : value.minus(step); while (value.getHour() == 6) value = ascend ? value.plus(step) : value.minus(step); index++; } } @Test(dataProvider = "ZonedDateTimeRanges") public void testRangeOfZonedDateTimes(ZonedDateTime start, ZonedDateTime end, Duration step, boolean parallel) { final boolean ascend = start.isBefore(end); final Range<ZonedDateTime> range = Range.of(start, end, step, v -> v.getHour() == 6); final Array<ZonedDateTime> array = range.toArray(parallel); final ZonedDateTime first = array.first(v -> true).map(ArrayValue::getValue).get(); final ZonedDateTime last = array.last(v -> true).map(ArrayValue::getValue).get(); Assert.assertEquals(array.typeCode(), ArrayType.ZONED_DATETIME); Assert.assertTrue(!array.style().isSparse()); Assert.assertEquals(range.start(), start, "The range start"); Assert.assertEquals(range.end(), end, "The range end"); int index = 0; ZonedDateTime value = first; while (ascend ? value.isBefore(last) : value.isAfter(last)) { final ZonedDateTime actual = array.getValue(index); Assert.assertEquals(actual, value, "Value matches at " + index); Assert.assertTrue(ascend ? actual.compareTo(start) >= 0 && actual.isBefore(end) : actual.compareTo(start) <= 0 && actual.isAfter(end), "Value in bounds at " + index); value = ascend ? value.plus(step) : value.minus(step); while (value.getHour() == 6) value = ascend ? value.plus(step) : value.minus(step); index++; } } }