/* * Copyright (C) 2011 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.collect.BoundType.OPEN; import static com.google.common.collect.Range.range; import static com.google.common.truth.Truth.assertThat; import com.google.common.annotations.GwtIncompatible; import com.google.common.testing.SerializableTester; import java.util.Arrays; import java.util.List; import java.util.NavigableMap; /** * Tests for {@link TreeRangeSet}. * * @author Louis Wasserman * @author Chris Povirk */ @GwtIncompatible // TreeRangeSet public class TreeRangeSetTest extends AbstractRangeSetTest { // TODO(cpovirk): test all of these with the ranges added in the reverse order private static final ImmutableList<Range<Integer>> QUERY_RANGES; private static final int MIN_BOUND = -1; private static final int MAX_BOUND = 1; static { ImmutableList.Builder<Range<Integer>> queryBuilder = ImmutableList.builder(); queryBuilder.add(Range.<Integer>all()); for (int i = MIN_BOUND; i <= MAX_BOUND; i++) { for (BoundType boundType : BoundType.values()) { queryBuilder.add(Range.upTo(i, boundType)); queryBuilder.add(Range.downTo(i, boundType)); } queryBuilder.add(Range.singleton(i)); queryBuilder.add(Range.openClosed(i, i)); queryBuilder.add(Range.closedOpen(i, i)); for (BoundType lowerBoundType : BoundType.values()) { for (int j = i + 1; j <= MAX_BOUND; j++) { for (BoundType upperBoundType : BoundType.values()) { queryBuilder.add(Range.range(i, lowerBoundType, j, upperBoundType)); } } } } QUERY_RANGES = queryBuilder.build(); } void testViewAgainstExpected(RangeSet<Integer> expected, RangeSet<Integer> view) { assertEquals(expected, view); assertEquals(expected.asRanges(), view.asRanges()); assertEquals(expected.isEmpty(), view.isEmpty()); if (!expected.isEmpty()) { assertEquals(expected.span(), view.span()); } for (int i = MIN_BOUND - 1; i <= MAX_BOUND + 1; i++) { assertEquals(expected.contains(i), view.contains(i)); assertEquals(expected.rangeContaining(i), view.rangeContaining(i)); } testEnclosing(view); if (view instanceof TreeRangeSet) { testRangesByLowerBounds((TreeRangeSet<Integer>) view, expected.asRanges()); } } private static final ImmutableList<Cut<Integer>> CUTS_TO_TEST; static { List<Cut<Integer>> cutsToTest = Lists.newArrayList(); for (int i = MIN_BOUND - 1; i <= MAX_BOUND + 1; i++) { cutsToTest.add(Cut.belowValue(i)); cutsToTest.add(Cut.aboveValue(i)); } cutsToTest.add(Cut.<Integer>aboveAll()); cutsToTest.add(Cut.<Integer>belowAll()); CUTS_TO_TEST = ImmutableList.copyOf(cutsToTest); } private void testRangesByLowerBounds( TreeRangeSet<Integer> rangeSet, Iterable<Range<Integer>> expectedRanges) { NavigableMap<Cut<Integer>, Range<Integer>> expectedRangesByLowerBound = Maps.newTreeMap(); for (Range<Integer> range : expectedRanges) { expectedRangesByLowerBound.put(range.lowerBound, range); } NavigableMap<Cut<Integer>, Range<Integer>> rangesByLowerBound = rangeSet.rangesByLowerBound; testNavigationAgainstExpected(expectedRangesByLowerBound, rangesByLowerBound, CUTS_TO_TEST); } <K, V> void testNavigationAgainstExpected( NavigableMap<K, V> expected, NavigableMap<K, V> navigableMap, Iterable<K> keysToTest) { for (K key : keysToTest) { assertEquals(expected.lowerEntry(key), navigableMap.lowerEntry(key)); assertEquals(expected.floorEntry(key), navigableMap.floorEntry(key)); assertEquals(expected.ceilingEntry(key), navigableMap.ceilingEntry(key)); assertEquals(expected.higherEntry(key), navigableMap.higherEntry(key)); for (boolean inclusive : new boolean[] {false, true}) { assertThat(navigableMap.headMap(key, inclusive).entrySet()) .containsExactlyElementsIn(expected.headMap(key, inclusive).entrySet()) .inOrder(); assertThat(navigableMap.tailMap(key, inclusive).entrySet()) .containsExactlyElementsIn(expected.tailMap(key, inclusive).entrySet()) .inOrder(); assertThat(navigableMap.headMap(key, inclusive).descendingMap().entrySet()) .containsExactlyElementsIn(expected.headMap(key, inclusive).descendingMap().entrySet()) .inOrder(); assertThat(navigableMap.tailMap(key, inclusive).descendingMap().entrySet()) .containsExactlyElementsIn(expected.tailMap(key, inclusive).descendingMap().entrySet()) .inOrder(); } } } public void testIntersects(RangeSet<Integer> rangeSet) { for (Range<Integer> query : QUERY_RANGES) { boolean expectIntersect = false; for (Range<Integer> expectedRange : rangeSet.asRanges()) { if (expectedRange.isConnected(query) && !expectedRange.intersection(query).isEmpty()) { expectIntersect = true; break; } } assertEquals(rangeSet + " was incorrect on intersects(" + query + ")", expectIntersect, rangeSet.intersects(query)); } } public void testEnclosing(RangeSet<Integer> rangeSet) { assertTrue(rangeSet.enclosesAll(ImmutableList.<Range<Integer>>of())); for (Range<Integer> query : QUERY_RANGES) { boolean expectEnclose = false; for (Range<Integer> expectedRange : rangeSet.asRanges()) { if (expectedRange.encloses(query)) { expectEnclose = true; break; } } assertEquals(rangeSet + " was incorrect on encloses(" + query + ")", expectEnclose, rangeSet.encloses(query)); assertEquals( rangeSet + " was incorrect on enclosesAll([" + query + "])", expectEnclose, rangeSet.enclosesAll(ImmutableList.of(query))); } } public void testAllSingleRangesComplementAgainstRemove() { for (Range<Integer> range : QUERY_RANGES) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(range); TreeRangeSet<Integer> complement = TreeRangeSet.create(); complement.add(Range.<Integer>all()); complement.remove(range); assertEquals(complement, rangeSet.complement()); assertThat(rangeSet.complement().asRanges()) .containsExactlyElementsIn(complement.asRanges()) .inOrder(); } } public void testInvariantsEmpty() { testInvariants(TreeRangeSet.create()); } public void testEmptyIntersecting() { testIntersects(TreeRangeSet.<Integer>create()); testIntersects(TreeRangeSet.<Integer>create().complement()); } public void testAllSingleRangesIntersecting() { for (Range<Integer> range : QUERY_RANGES) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(range); testIntersects(rangeSet); testIntersects(rangeSet.complement()); } } public void testAllTwoRangesIntersecting() { for (Range<Integer> range1 : QUERY_RANGES) { for (Range<Integer> range2 : QUERY_RANGES) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(range1); rangeSet.add(range2); testIntersects(rangeSet); testIntersects(rangeSet.complement()); } } } public void testEmptyEnclosing() { testEnclosing(TreeRangeSet.<Integer>create()); testEnclosing(TreeRangeSet.<Integer>create().complement()); } public void testAllSingleRangesEnclosing() { for (Range<Integer> range : QUERY_RANGES) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(range); testEnclosing(rangeSet); testEnclosing(rangeSet.complement()); } } public void testAllTwoRangesEnclosing() { for (Range<Integer> range1 : QUERY_RANGES) { for (Range<Integer> range2 : QUERY_RANGES) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(range1); rangeSet.add(range2); testEnclosing(rangeSet); testEnclosing(rangeSet.complement()); } } } public void testCreateCopy() { for (Range<Integer> range1 : QUERY_RANGES) { for (Range<Integer> range2 : QUERY_RANGES) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(range1); rangeSet.add(range2); assertEquals(rangeSet, TreeRangeSet.create(rangeSet)); } } } private RangeSet<Integer> expectedSubRangeSet( RangeSet<Integer> rangeSet, Range<Integer> subRange) { RangeSet<Integer> expected = TreeRangeSet.create(); for (Range<Integer> range : rangeSet.asRanges()) { if (range.isConnected(subRange)) { expected.add(range.intersection(subRange)); } } return expected; } private RangeSet<Integer> expectedComplement(RangeSet<Integer> rangeSet) { RangeSet<Integer> expected = TreeRangeSet.create(); expected.add(Range.<Integer>all()); expected.removeAll(rangeSet); return expected; } public void testSubRangeSet() { for (Range<Integer> range1 : QUERY_RANGES) { for (Range<Integer> range2 : QUERY_RANGES) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(range1); rangeSet.add(range2); for (Range<Integer> subRange : QUERY_RANGES) { testViewAgainstExpected( expectedSubRangeSet(rangeSet, subRange), rangeSet.subRangeSet(subRange)); } } } } public void testComplement() { for (Range<Integer> range1 : QUERY_RANGES) { for (Range<Integer> range2 : QUERY_RANGES) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(range1); rangeSet.add(range2); testViewAgainstExpected(expectedComplement(rangeSet), rangeSet.complement()); } } } public void testSubRangeSetOfComplement() { for (Range<Integer> range1 : QUERY_RANGES) { for (Range<Integer> range2 : QUERY_RANGES) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(range1); rangeSet.add(range2); for (Range<Integer> subRange : QUERY_RANGES) { testViewAgainstExpected( expectedSubRangeSet(expectedComplement(rangeSet), subRange), rangeSet.complement().subRangeSet(subRange)); } } } } public void testComplementOfSubRangeSet() { for (Range<Integer> range1 : QUERY_RANGES) { for (Range<Integer> range2 : QUERY_RANGES) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(range1); rangeSet.add(range2); for (Range<Integer> subRange : QUERY_RANGES) { testViewAgainstExpected( expectedComplement(expectedSubRangeSet(rangeSet, subRange)), rangeSet.subRangeSet(subRange).complement()); } } } } public void testRangesByUpperBound() { for (Range<Integer> range1 : QUERY_RANGES) { for (Range<Integer> range2 : QUERY_RANGES) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(range1); rangeSet.add(range2); NavigableMap<Cut<Integer>, Range<Integer>> expectedRangesByUpperBound = Maps.newTreeMap(); for (Range<Integer> range : rangeSet.asRanges()) { expectedRangesByUpperBound.put(range.upperBound, range); } testNavigationAgainstExpected(expectedRangesByUpperBound, new TreeRangeSet.RangesByUpperBound<Integer>(rangeSet.rangesByLowerBound), CUTS_TO_TEST); } } } public void testMergesConnectedWithOverlap() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 4)); rangeSet.add(Range.open(2, 6)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closedOpen(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.atLeast(6)) .inOrder(); } public void testMergesConnectedDisjoint() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 4)); rangeSet.add(Range.open(4, 6)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closedOpen(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.atLeast(6)) .inOrder(); } public void testIgnoresSmallerSharingNoBound() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 6)); rangeSet.add(Range.open(2, 4)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closed(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.greaterThan(6)) .inOrder(); } public void testIgnoresSmallerSharingLowerBound() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 6)); rangeSet.add(Range.closed(1, 4)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closed(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.greaterThan(6)) .inOrder(); } public void testIgnoresSmallerSharingUpperBound() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 6)); rangeSet.add(Range.closed(3, 6)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closed(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.greaterThan(6)) .inOrder(); } public void testIgnoresEqual() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 6)); rangeSet.add(Range.closed(1, 6)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closed(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.greaterThan(6)) .inOrder(); } public void testExtendSameLowerBound() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 4)); rangeSet.add(Range.closed(1, 6)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closed(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.greaterThan(6)) .inOrder(); } public void testExtendSameUpperBound() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 6)); rangeSet.add(Range.closed(1, 6)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closed(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.greaterThan(6)) .inOrder(); } public void testExtendBothDirections() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 4)); rangeSet.add(Range.closed(1, 6)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closed(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.greaterThan(6)) .inOrder(); } public void testAddEmpty() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closedOpen(3, 3)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).isEmpty(); assertThat(rangeSet.complement().asRanges()).containsExactly(Range.<Integer>all()); } public void testFillHoleExactly() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closedOpen(1, 3)); rangeSet.add(Range.closedOpen(4, 6)); rangeSet.add(Range.closedOpen(3, 4)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closedOpen(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.atLeast(6)) .inOrder(); } public void testFillHoleWithOverlap() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closedOpen(1, 3)); rangeSet.add(Range.closedOpen(4, 6)); rangeSet.add(Range.closedOpen(2, 5)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closedOpen(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.atLeast(6)) .inOrder(); } public void testAddManyPairs() { for (int aLow = 0; aLow < 6; aLow++) { for (int aHigh = 0; aHigh < 6; aHigh++) { for (BoundType aLowType : BoundType.values()) { for (BoundType aHighType : BoundType.values()) { if ((aLow == aHigh && aLowType == OPEN && aHighType == OPEN) || aLow > aHigh) { continue; } for (int bLow = 0; bLow < 6; bLow++) { for (int bHigh = 0; bHigh < 6; bHigh++) { for (BoundType bLowType : BoundType.values()) { for (BoundType bHighType : BoundType.values()) { if ((bLow == bHigh && bLowType == OPEN && bHighType == OPEN) || bLow > bHigh) { continue; } doPairTest(range(aLow, aLowType, aHigh, aHighType), range(bLow, bLowType, bHigh, bHighType)); } } } } } } } } } private static void doPairTest(Range<Integer> a, Range<Integer> b) { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(a); rangeSet.add(b); if (a.isEmpty() && b.isEmpty()) { assertThat(rangeSet.asRanges()).isEmpty(); } else if (a.isEmpty()) { assertThat(rangeSet.asRanges()).contains(b); } else if (b.isEmpty()) { assertThat(rangeSet.asRanges()).contains(a); } else if (a.isConnected(b)) { assertThat(rangeSet.asRanges()).containsExactly(a.span(b)); } else { if (a.lowerEndpoint() < b.lowerEndpoint()) { assertThat(rangeSet.asRanges()).containsExactly(a, b).inOrder(); } else { assertThat(rangeSet.asRanges()).containsExactly(b, a).inOrder(); } } } public void testRemoveEmpty() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 6)); rangeSet.remove(Range.closedOpen(3, 3)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.closed(1, 6)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(1), Range.greaterThan(6)) .inOrder(); } public void testRemovePartSharingLowerBound() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 5)); rangeSet.remove(Range.closedOpen(3, 5)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.singleton(5)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(5), Range.greaterThan(5)) .inOrder(); } public void testRemovePartSharingUpperBound() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 5)); rangeSet.remove(Range.openClosed(3, 5)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).contains(Range.singleton(3)); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.lessThan(3), Range.greaterThan(3)) .inOrder(); } public void testRemoveMiddle() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.atMost(6)); rangeSet.remove(Range.closedOpen(3, 4)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()) .containsExactly(Range.lessThan(3), Range.closed(4, 6)).inOrder(); assertThat(rangeSet.complement().asRanges()) .containsExactly(Range.closedOpen(3, 4), Range.greaterThan(6)).inOrder(); } public void testRemoveNoOverlap() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 6)); rangeSet.remove(Range.closedOpen(1, 3)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).containsExactly(Range.closed(3, 6)); } public void testRemovePartFromBelowLowerBound() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 6)); rangeSet.remove(Range.closed(1, 3)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).containsExactly(Range.openClosed(3, 6)); } public void testRemovePartFromAboveUpperBound() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 6)); rangeSet.remove(Range.closed(6, 9)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).containsExactly(Range.closedOpen(3, 6)); } public void testRemoveExact() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 6)); rangeSet.remove(Range.closed(3, 6)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).isEmpty(); } public void testRemoveAllFromBelowLowerBound() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 6)); rangeSet.remove(Range.closed(2, 6)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).isEmpty(); } public void testRemoveAllFromAboveUpperBound() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 6)); rangeSet.remove(Range.closed(3, 7)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).isEmpty(); } public void testRemoveAllExtendingBothDirections() { TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 6)); rangeSet.remove(Range.closed(2, 7)); testInvariants(rangeSet); assertThat(rangeSet.asRanges()).isEmpty(); } public void testRangeContaining1() { RangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 10)); assertEquals(Range.closed(3, 10), rangeSet.rangeContaining(5)); assertTrue(rangeSet.contains(5)); assertNull(rangeSet.rangeContaining(1)); assertFalse(rangeSet.contains(1)); } public void testRangeContaining2() { RangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 10)); rangeSet.remove(Range.open(5, 7)); assertEquals(Range.closed(3, 5), rangeSet.rangeContaining(5)); assertTrue(rangeSet.contains(5)); assertEquals(Range.closed(7, 10), rangeSet.rangeContaining(8)); assertTrue(rangeSet.contains(8)); assertNull(rangeSet.rangeContaining(6)); assertFalse(rangeSet.contains(6)); } public void testAddAll() { RangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 10)); rangeSet.addAll(Arrays.asList(Range.open(1, 3), Range.closed(5, 8), Range.closed(9, 11))); assertThat(rangeSet.asRanges()) .containsExactly(Range.openClosed(1, 11)) .inOrder(); } public void testRemoveAll() { RangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 10)); rangeSet.removeAll(Arrays.asList(Range.open(1, 3), Range.closed(5, 8), Range.closed(9, 11))); assertThat(rangeSet.asRanges()) .containsExactly(Range.closedOpen(3, 5), Range.open(8, 9)) .inOrder(); } @GwtIncompatible // SerializableTester public void testSerialization() { RangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(3, 10)); rangeSet.remove(Range.open(5, 7)); SerializableTester.reserializeAndAssert(rangeSet); } }