/* * Copyright (C) 2012 The Guava Authors * * 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.google.common.collect; import static com.google.common.truth.Truth.assertThat; import com.google.common.annotations.GwtIncompatible; import com.google.common.collect.testing.NavigableSetTestSuiteBuilder; import com.google.common.collect.testing.SampleElements; import com.google.common.collect.testing.TestSetGenerator; import com.google.common.collect.testing.features.CollectionFeature; import com.google.common.collect.testing.features.CollectionSize; import com.google.common.testing.SerializableTester; import java.math.BigInteger; import java.util.List; import java.util.Set; import junit.framework.Test; import junit.framework.TestSuite; /** * Tests for {@link ImmutableRangeSet}. * * @author Louis Wasserman */ @GwtIncompatible // ImmutableRangeSet public class ImmutableRangeSetTest extends AbstractRangeSetTest { static final class ImmutableRangeSetIntegerAsSetGenerator implements TestSetGenerator<Integer> { @Override public SampleElements<Integer> samples() { return new SampleElements<Integer>(1, 4, 3, 2, 5); } @Override public Integer[] createArray(int length) { return new Integer[length]; } @Override public Iterable<Integer> order(List<Integer> insertionOrder) { return Ordering.natural().sortedCopy(insertionOrder); } @Override public Set<Integer> create(Object... elements) { ImmutableRangeSet.Builder<Integer> builder = ImmutableRangeSet.builder(); for (Object o : elements) { Integer i = (Integer) o; builder.add(Range.singleton(i)); } return builder.build().asSet(DiscreteDomain.integers()); } } static final class ImmutableRangeSetBigIntegerAsSetGenerator implements TestSetGenerator<BigInteger> { @Override public SampleElements<BigInteger> samples() { return new SampleElements<BigInteger>( BigInteger.valueOf(1), BigInteger.valueOf(4), BigInteger.valueOf(3), BigInteger.valueOf(2), BigInteger.valueOf(5)); } @Override public BigInteger[] createArray(int length) { return new BigInteger[length]; } @Override public Iterable<BigInteger> order(List<BigInteger> insertionOrder) { return Ordering.natural().sortedCopy(insertionOrder); } @Override public Set<BigInteger> create(Object... elements) { ImmutableRangeSet.Builder<BigInteger> builder = ImmutableRangeSet.builder(); for (Object o : elements) { BigInteger i = (BigInteger) o; builder.add(Range.closedOpen(i, i.add(BigInteger.ONE))); } return builder.build().asSet(DiscreteDomain.bigIntegers()); } } public static Test suite() { TestSuite suite = new TestSuite(); suite.addTestSuite(ImmutableRangeSetTest.class); suite.addTest(NavigableSetTestSuiteBuilder.using(new ImmutableRangeSetIntegerAsSetGenerator()) .named("ImmutableRangeSet.asSet[DiscreteDomain.integers[]]") .withFeatures( CollectionSize.ANY, CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, CollectionFeature.ALLOWS_NULL_QUERIES, CollectionFeature.KNOWN_ORDER, CollectionFeature.NON_STANDARD_TOSTRING, CollectionFeature.SERIALIZABLE) .createTestSuite()); suite.addTest(NavigableSetTestSuiteBuilder.using( new ImmutableRangeSetBigIntegerAsSetGenerator()) .named("ImmutableRangeSet.asSet[DiscreteDomain.bigIntegers[]]") .withFeatures( CollectionSize.ANY, CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, CollectionFeature.ALLOWS_NULL_QUERIES, CollectionFeature.KNOWN_ORDER, CollectionFeature.NON_STANDARD_TOSTRING, CollectionFeature.SERIALIZABLE) .createTestSuite()); return suite; } public void testEmpty() { ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.of(); assertThat(rangeSet.asRanges()).isEmpty(); assertEquals(ImmutableRangeSet.<Integer>all(), rangeSet.complement()); assertFalse(rangeSet.contains(0)); assertFalse(rangeSet.intersects(Range.singleton(0))); assertFalse(rangeSet.encloses(Range.singleton(0))); assertTrue(rangeSet.enclosesAll(rangeSet)); assertTrue(rangeSet.isEmpty()); } public void testAll() { ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.all(); assertThat(rangeSet.asRanges()).contains(Range.<Integer>all()); assertTrue(rangeSet.contains(0)); assertTrue(rangeSet.intersects(Range.singleton(0))); assertTrue(rangeSet.intersects(Range.<Integer>all())); assertTrue(rangeSet.encloses(Range.<Integer>all())); assertTrue(rangeSet.enclosesAll(rangeSet)); assertEquals(ImmutableRangeSet.<Integer>of(), rangeSet.complement()); } public void testSingleBoundedRange() { ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.of(Range.closedOpen(1, 5)); assertThat(rangeSet.asRanges()).contains(Range.closedOpen(1, 5)); assertTrue(rangeSet.intersects(Range.closed(3, 4))); assertTrue(rangeSet.intersects(Range.closedOpen(0, 2))); assertTrue(rangeSet.intersects(Range.closedOpen(3, 7))); assertTrue(rangeSet.intersects(Range.greaterThan(2))); assertFalse(rangeSet.intersects(Range.greaterThan(7))); assertTrue(rangeSet.encloses(Range.closed(3, 4))); assertTrue(rangeSet.encloses(Range.closedOpen(1, 4))); assertTrue(rangeSet.encloses(Range.closedOpen(1, 5))); assertFalse(rangeSet.encloses(Range.greaterThan(2))); assertTrue(rangeSet.contains(3)); assertFalse(rangeSet.contains(5)); assertFalse(rangeSet.contains(0)); RangeSet<Integer> expectedComplement = TreeRangeSet.create(); expectedComplement.add(Range.lessThan(1)); expectedComplement.add(Range.atLeast(5)); assertEquals(expectedComplement, rangeSet.complement()); } public void testSingleBoundedBelowRange() { ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.of(Range.greaterThan(2)); assertThat(rangeSet.asRanges()).contains(Range.greaterThan(2)); assertTrue(rangeSet.intersects(Range.closed(3, 4))); assertTrue(rangeSet.intersects(Range.closedOpen(1, 5))); assertFalse(rangeSet.intersects(Range.lessThan(1))); assertTrue(rangeSet.intersects(Range.greaterThan(1))); assertTrue(rangeSet.intersects(Range.greaterThan(3))); assertTrue(rangeSet.encloses(Range.closed(3, 4))); assertTrue(rangeSet.encloses(Range.greaterThan(3))); assertFalse(rangeSet.encloses(Range.closedOpen(1, 5))); assertTrue(rangeSet.contains(3)); assertTrue(rangeSet.contains(5)); assertFalse(rangeSet.contains(0)); assertFalse(rangeSet.contains(2)); assertEquals(ImmutableRangeSet.of(Range.atMost(2)), rangeSet.complement()); } public void testSingleBoundedAboveRange() { ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.of(Range.atMost(3)); assertThat(rangeSet.asRanges()).contains(Range.atMost(3)); assertTrue(rangeSet.intersects(Range.closed(3, 4))); assertTrue(rangeSet.intersects(Range.closedOpen(1, 5))); assertFalse(rangeSet.intersects(Range.closedOpen(4, 5))); assertTrue(rangeSet.intersects(Range.lessThan(1))); assertTrue(rangeSet.intersects(Range.greaterThan(1))); assertFalse(rangeSet.intersects(Range.greaterThan(3))); assertTrue(rangeSet.encloses(Range.closed(2, 3))); assertTrue(rangeSet.encloses(Range.lessThan(1))); assertFalse(rangeSet.encloses(Range.closedOpen(1, 5))); assertTrue(rangeSet.contains(3)); assertTrue(rangeSet.contains(0)); assertFalse(rangeSet.contains(4)); assertFalse(rangeSet.contains(5)); assertEquals(ImmutableRangeSet.of(Range.greaterThan(3)), rangeSet.complement()); } public void testMultipleBoundedRanges() { ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder() .add(Range.closed(5, 8)).add(Range.closedOpen(1, 3)).build(); assertThat(rangeSet.asRanges()) .containsExactly(Range.closedOpen(1, 3), Range.closed(5, 8)).inOrder(); assertTrue(rangeSet.intersects(Range.closed(1, 2))); assertTrue(rangeSet.intersects(Range.open(5, 8))); assertFalse(rangeSet.intersects(Range.closed(3, 4))); assertTrue(rangeSet.intersects(Range.greaterThan(5))); assertFalse(rangeSet.intersects(Range.greaterThan(8))); assertTrue(rangeSet.encloses(Range.closed(1, 2))); assertTrue(rangeSet.encloses(Range.open(5, 8))); assertFalse(rangeSet.encloses(Range.closed(1, 8))); assertFalse(rangeSet.encloses(Range.greaterThan(5))); RangeSet<Integer> expectedComplement = ImmutableRangeSet.<Integer>builder() .add(Range.lessThan(1)) .add(Range.closedOpen(3, 5)) .add(Range.greaterThan(8)) .build(); assertEquals(expectedComplement, rangeSet.complement()); } public void testMultipleBoundedBelowRanges() { ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder() .add(Range.greaterThan(6)).add(Range.closedOpen(1, 3)).build(); assertThat(rangeSet.asRanges()) .containsExactly(Range.closedOpen(1, 3), Range.greaterThan(6)).inOrder(); assertTrue(rangeSet.intersects(Range.closed(1, 2))); assertTrue(rangeSet.intersects(Range.open(6, 8))); assertFalse(rangeSet.intersects(Range.closed(3, 6))); assertTrue(rangeSet.intersects(Range.greaterThan(5))); assertFalse(rangeSet.intersects(Range.lessThan(1))); assertTrue(rangeSet.encloses(Range.closed(1, 2))); assertTrue(rangeSet.encloses(Range.open(6, 8))); assertFalse(rangeSet.encloses(Range.closed(1, 8))); assertFalse(rangeSet.encloses(Range.greaterThan(5))); RangeSet<Integer> expectedComplement = ImmutableRangeSet.<Integer>builder() .add(Range.lessThan(1)) .add(Range.closed(3, 6)) .build(); assertEquals(expectedComplement, rangeSet.complement()); } public void testMultipleBoundedAboveRanges() { ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder() .add(Range.atMost(0)).add(Range.closedOpen(2, 5)).build(); assertThat(rangeSet.asRanges()) .containsExactly(Range.atMost(0), Range.closedOpen(2, 5)).inOrder(); assertTrue(rangeSet.intersects(Range.closed(2, 4))); assertTrue(rangeSet.intersects(Range.open(-5, -2))); assertTrue(rangeSet.intersects(Range.closed(1, 8))); assertFalse(rangeSet.intersects(Range.singleton(1))); assertFalse(rangeSet.intersects(Range.greaterThan(5))); assertTrue(rangeSet.encloses(Range.closed(2, 4))); assertTrue(rangeSet.encloses(Range.open(-5, -2))); assertFalse(rangeSet.encloses(Range.closed(1, 8))); assertFalse(rangeSet.encloses(Range.greaterThan(5))); RangeSet<Integer> expectedComplement = ImmutableRangeSet.<Integer>builder() .add(Range.open(0, 2)) .add(Range.atLeast(5)) .build(); assertEquals(expectedComplement, rangeSet.complement()); } public void testAddUnsupported() { RangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder() .add(Range.closed(5, 8)) .add(Range.closedOpen(1, 3)) .build(); try { rangeSet.add(Range.open(3, 4)); fail(); } catch (UnsupportedOperationException expected) { // success } } public void testAddAllUnsupported() { RangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder() .add(Range.closed(5, 8)) .add(Range.closedOpen(1, 3)) .build(); try { rangeSet.addAll(ImmutableRangeSet.<Integer>of()); fail(); } catch (UnsupportedOperationException expected) { // success } } public void testRemoveUnsupported() { RangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder() .add(Range.closed(5, 8)) .add(Range.closedOpen(1, 3)) .build(); try { rangeSet.remove(Range.closed(6, 7)); fail(); } catch (UnsupportedOperationException expected) { // success } } public void testRemoveAllUnsupported() { RangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder() .add(Range.closed(5, 8)) .add(Range.closedOpen(1, 3)) .build(); try { rangeSet.removeAll(ImmutableRangeSet.<Integer>of()); fail(); } catch (UnsupportedOperationException expected) { // success } try { rangeSet.removeAll(ImmutableRangeSet.of(Range.closed(6, 8))); fail(); } catch (UnsupportedOperationException expected) { // success } } @AndroidIncompatible // slow public void testExhaustive() { @SuppressWarnings("unchecked") ImmutableSet<Range<Integer>> ranges = ImmutableSet.of( Range.<Integer>all(), Range.<Integer>closedOpen(3, 5), Range.singleton(1), Range.lessThan(2), Range.greaterThan(10), Range.atMost(4), Range.atLeast(3), Range.closed(4, 6), Range.closedOpen(1, 3), Range.openClosed(5, 7), Range.open(3, 4)); subsets: for (Set<Range<Integer>> subset : Sets.powerSet(ranges)) { assertEquals(TreeRangeSet.create(subset), ImmutableRangeSet.unionOf(subset)); RangeSet<Integer> mutable = TreeRangeSet.create(); ImmutableRangeSet.Builder<Integer> builder = ImmutableRangeSet.builder(); boolean anyOverlaps = false; for (Range<Integer> range : subset) { boolean overlaps = false; for (Range<Integer> other : mutable.asRanges()) { if (other.isConnected(range) && !other.intersection(range).isEmpty()) { overlaps = true; anyOverlaps = true; break; } } try { ImmutableRangeSet<Integer> unused = builder.add(range).build(); assertFalse(overlaps); mutable.add(range); } catch (IllegalArgumentException e) { assertTrue(overlaps); continue subsets; } } if (anyOverlaps) { try { RangeSet<Integer> copy = ImmutableRangeSet.copyOf(subset); fail(); } catch (IllegalArgumentException expected) { } } else { RangeSet<Integer> copy = ImmutableRangeSet.copyOf(subset); assertEquals(mutable, copy); } ImmutableRangeSet<Integer> built = builder.build(); assertEquals(mutable, built); assertEquals(ImmutableRangeSet.copyOf(mutable), built); assertEquals(mutable.complement(), built.complement()); for (int i = 0; i <= 11; i++) { assertEquals(mutable.contains(i), built.contains(i)); } SerializableTester.reserializeAndAssert(built); SerializableTester.reserializeAndAssert(built.asRanges()); } } private static final ImmutableRangeSet<Integer> RANGE_SET_ONE = ImmutableRangeSet.<Integer>builder() .add(Range.closed(2, 4)) .add(Range.open(6, 7)) .add(Range.closedOpen(8, 10)) .add(Range.openClosed(15, 17)) .build(); private static final ImmutableRangeSet<Integer> RANGE_SET_TWO = ImmutableRangeSet.<Integer>builder() .add(Range.openClosed(0, 3)) .add(Range.closed(5, 8)) .add(Range.closedOpen(12, 15)) .add(Range.open(19, 20)) .build(); public void testUnion() { RangeSet<Integer> expected = ImmutableRangeSet.<Integer>builder() .add(Range.openClosed(0, 4)) .add(Range.closedOpen(5, 10)) .add(Range.closedOpen(12, 15)) .add(Range.openClosed(15, 17)) .add(Range.open(19, 20)) .build(); assertThat(RANGE_SET_ONE.union(RANGE_SET_TWO)).isEqualTo(expected); } public void testIntersection() { RangeSet<Integer> expected = ImmutableRangeSet.<Integer>builder() .add(Range.closed(2, 3)) .add(Range.open(6, 7)) .add(Range.singleton(8)) .build(); assertThat(RANGE_SET_ONE.intersection(RANGE_SET_TWO)).isEqualTo(expected); } public void testDifference() { RangeSet<Integer> expected = ImmutableRangeSet.<Integer>builder() .add(Range.openClosed(3, 4)) .add(Range.open(8, 10)) .add(Range.openClosed(15, 17)) .build(); assertThat(RANGE_SET_ONE.difference(RANGE_SET_TWO)).isEqualTo(expected); } public void testAsSet() { ImmutableSortedSet<Integer> expectedSet = ImmutableSortedSet.of(2, 3, 4, 8, 9, 16, 17); ImmutableSortedSet<Integer> asSet = RANGE_SET_ONE.asSet(DiscreteDomain.integers()); assertEquals(expectedSet, asSet); assertThat(asSet).containsExactlyElementsIn(expectedSet).inOrder(); assertTrue(asSet.containsAll(expectedSet)); SerializableTester.reserializeAndAssert(asSet); } public void testAsSetHeadSet() { ImmutableSortedSet<Integer> expectedSet = ImmutableSortedSet.of(2, 3, 4, 8, 9, 16, 17); ImmutableSortedSet<Integer> asSet = RANGE_SET_ONE.asSet(DiscreteDomain.integers()); for (int i = 0; i <= 20; i++) { assertEquals(asSet.headSet(i, false), expectedSet.headSet(i, false)); assertEquals(asSet.headSet(i, true), expectedSet.headSet(i, true)); } } public void testAsSetTailSet() { ImmutableSortedSet<Integer> expectedSet = ImmutableSortedSet.of(2, 3, 4, 8, 9, 16, 17); ImmutableSortedSet<Integer> asSet = RANGE_SET_ONE.asSet(DiscreteDomain.integers()); for (int i = 0; i <= 20; i++) { assertEquals(asSet.tailSet(i, false), expectedSet.tailSet(i, false)); assertEquals(asSet.tailSet(i, true), expectedSet.tailSet(i, true)); } } public void testAsSetSubSet() { ImmutableSortedSet<Integer> expectedSet = ImmutableSortedSet.of(2, 3, 4, 8, 9, 16, 17); ImmutableSortedSet<Integer> asSet = RANGE_SET_ONE.asSet(DiscreteDomain.integers()); for (int i = 0; i <= 20; i++) { for (int j = i + 1; j <= 20; j++) { assertEquals(expectedSet.subSet(i, false, j, false), asSet.subSet(i, false, j, false)); assertEquals(expectedSet.subSet(i, true, j, false), asSet.subSet(i, true, j, false)); assertEquals(expectedSet.subSet(i, false, j, true), asSet.subSet(i, false, j, true)); assertEquals(expectedSet.subSet(i, true, j, true), asSet.subSet(i, true, j, true)); } } } public void testSubRangeSet() { ImmutableList.Builder<Range<Integer>> rangesBuilder = ImmutableList.builder(); rangesBuilder.add(Range.<Integer>all()); for (int i = -2; i <= 2; i++) { for (BoundType boundType : BoundType.values()) { rangesBuilder.add(Range.upTo(i, boundType)); rangesBuilder.add(Range.downTo(i, boundType)); } for (int j = i + 1; j <= 2; j++) { for (BoundType lbType : BoundType.values()) { for (BoundType ubType : BoundType.values()) { rangesBuilder.add(Range.range(i, lbType, j, ubType)); } } } } ImmutableList<Range<Integer>> ranges = rangesBuilder.build(); for (int i = -2; i <= 2; i++) { rangesBuilder.add(Range.closedOpen(i, i)); rangesBuilder.add(Range.openClosed(i, i)); } ImmutableList<Range<Integer>> subRanges = rangesBuilder.build(); for (Range<Integer> range1 : ranges) { for (Range<Integer> range2 : ranges) { if (!range1.isConnected(range2) || range1.intersection(range2).isEmpty()) { ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder() .add(range1) .add(range2) .build(); for (Range<Integer> subRange : subRanges) { RangeSet<Integer> expected = TreeRangeSet.create(); for (Range<Integer> range : rangeSet.asRanges()) { if (range.isConnected(subRange)) { expected.add(range.intersection(subRange)); } } ImmutableRangeSet<Integer> subRangeSet = rangeSet.subRangeSet(subRange); assertEquals(expected, subRangeSet); assertEquals(expected.asRanges(), subRangeSet.asRanges()); if (!expected.isEmpty()) { assertEquals(expected.span(), subRangeSet.span()); } for (int i = -3; i <= 3; i++) { assertEquals(expected.contains(i), subRangeSet.contains(i)); } } } } } } }