• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.google.common.collect;
16 
17 import static com.google.common.collect.BoundType.OPEN;
18 import static com.google.common.collect.testing.Helpers.mapEntry;
19 import static org.junit.Assert.assertThrows;
20 
21 import com.google.common.annotations.GwtIncompatible;
22 import com.google.common.collect.testing.MapTestSuiteBuilder;
23 import com.google.common.collect.testing.SampleElements;
24 import com.google.common.collect.testing.TestMapGenerator;
25 import com.google.common.collect.testing.features.CollectionFeature;
26 import com.google.common.collect.testing.features.CollectionSize;
27 import com.google.common.collect.testing.features.MapFeature;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import java.util.NoSuchElementException;
32 import java.util.function.BiFunction;
33 import junit.framework.Test;
34 import junit.framework.TestCase;
35 import junit.framework.TestSuite;
36 
37 /**
38  * Tests for {@code TreeRangeMap}.
39  *
40  * @author Louis Wasserman
41  */
42 @GwtIncompatible // NavigableMap
43 public class TreeRangeMapTest extends TestCase {
suite()44   public static Test suite() {
45     TestSuite suite = new TestSuite();
46     suite.addTestSuite(TreeRangeMapTest.class);
47     suite.addTest(
48         MapTestSuiteBuilder.using(
49                 new TestMapGenerator<Range<Integer>, String>() {
50                   @Override
51                   public SampleElements<Entry<Range<Integer>, String>> samples() {
52                     return new SampleElements<>(
53                         mapEntry(Range.singleton(0), "banana"),
54                         mapEntry(Range.closedOpen(3, 5), "frisbee"),
55                         mapEntry(Range.atMost(-1), "fruitcake"),
56                         mapEntry(Range.open(10, 15), "elephant"),
57                         mapEntry(Range.closed(20, 22), "umbrella"));
58                   }
59 
60                   @Override
61                   public Map<Range<Integer>, String> create(Object... elements) {
62                     RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
63                     for (Object o : elements) {
64                       @SuppressWarnings("unchecked")
65                       Entry<Range<Integer>, String> entry = (Entry<Range<Integer>, String>) o;
66                       rangeMap.put(entry.getKey(), entry.getValue());
67                     }
68                     return rangeMap.asMapOfRanges();
69                   }
70 
71                   @SuppressWarnings("unchecked")
72                   @Override
73                   public Entry<Range<Integer>, String>[] createArray(int length) {
74                     return new Entry[length];
75                   }
76 
77                   @Override
78                   public Iterable<Entry<Range<Integer>, String>> order(
79                       List<Entry<Range<Integer>, String>> insertionOrder) {
80                     return Range.<Integer>rangeLexOrdering().onKeys().sortedCopy(insertionOrder);
81                   }
82 
83                   @SuppressWarnings("unchecked")
84                   @Override
85                   public Range<Integer>[] createKeyArray(int length) {
86                     return new Range[length];
87                   }
88 
89                   @Override
90                   public String[] createValueArray(int length) {
91                     return new String[length];
92                   }
93                 })
94             .named("TreeRangeMap.asMapOfRanges")
95             .withFeatures(
96                 CollectionSize.ANY,
97                 MapFeature.SUPPORTS_REMOVE,
98                 MapFeature.ALLOWS_ANY_NULL_QUERIES,
99                 CollectionFeature.KNOWN_ORDER,
100                 CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
101             .createTestSuite());
102 
103     suite.addTest(
104         MapTestSuiteBuilder.using(
105                 new TestMapGenerator<Range<Integer>, String>() {
106                   @Override
107                   public SampleElements<Entry<Range<Integer>, String>> samples() {
108                     return new SampleElements<>(
109                         mapEntry(Range.singleton(0), "banana"),
110                         mapEntry(Range.closedOpen(3, 5), "frisbee"),
111                         mapEntry(Range.atMost(-1), "fruitcake"),
112                         mapEntry(Range.open(10, 15), "elephant"),
113                         mapEntry(Range.closed(20, 22), "umbrella"));
114                   }
115 
116                   @Override
117                   public Map<Range<Integer>, String> create(Object... elements) {
118                     RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
119                     for (Object o : elements) {
120                       @SuppressWarnings("unchecked")
121                       Entry<Range<Integer>, String> entry = (Entry<Range<Integer>, String>) o;
122                       rangeMap.put(entry.getKey(), entry.getValue());
123                     }
124                     return rangeMap.subRangeMap(Range.atMost(22)).asMapOfRanges();
125                   }
126 
127                   @SuppressWarnings("unchecked")
128                   @Override
129                   public Entry<Range<Integer>, String>[] createArray(int length) {
130                     return new Entry[length];
131                   }
132 
133                   @Override
134                   public Iterable<Entry<Range<Integer>, String>> order(
135                       List<Entry<Range<Integer>, String>> insertionOrder) {
136                     return Range.<Integer>rangeLexOrdering().onKeys().sortedCopy(insertionOrder);
137                   }
138 
139                   @SuppressWarnings("unchecked")
140                   @Override
141                   public Range<Integer>[] createKeyArray(int length) {
142                     return new Range[length];
143                   }
144 
145                   @Override
146                   public String[] createValueArray(int length) {
147                     return new String[length];
148                   }
149                 })
150             .named("TreeRangeMap.subRangeMap.asMapOfRanges")
151             .withFeatures(
152                 CollectionSize.ANY,
153                 MapFeature.SUPPORTS_REMOVE,
154                 MapFeature.ALLOWS_ANY_NULL_QUERIES,
155                 CollectionFeature.KNOWN_ORDER)
156             .createTestSuite());
157 
158     suite.addTest(
159         MapTestSuiteBuilder.using(
160                 new TestMapGenerator<Range<Integer>, String>() {
161                   @Override
162                   public SampleElements<Entry<Range<Integer>, String>> samples() {
163                     return new SampleElements<>(
164                         mapEntry(Range.singleton(0), "banana"),
165                         mapEntry(Range.closedOpen(3, 5), "frisbee"),
166                         mapEntry(Range.atMost(-1), "fruitcake"),
167                         mapEntry(Range.open(10, 15), "elephant"),
168                         mapEntry(Range.closed(20, 22), "umbrella"));
169                   }
170 
171                   @Override
172                   public Map<Range<Integer>, String> create(Object... elements) {
173                     RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
174                     for (Object o : elements) {
175                       @SuppressWarnings("unchecked")
176                       Entry<Range<Integer>, String> entry = (Entry<Range<Integer>, String>) o;
177                       rangeMap.put(entry.getKey(), entry.getValue());
178                     }
179                     return rangeMap.asDescendingMapOfRanges();
180                   }
181 
182                   @SuppressWarnings("unchecked")
183                   @Override
184                   public Entry<Range<Integer>, String>[] createArray(int length) {
185                     return new Entry[length];
186                   }
187 
188                   @Override
189                   public Iterable<Entry<Range<Integer>, String>> order(
190                       List<Entry<Range<Integer>, String>> insertionOrder) {
191                     return Range.<Integer>rangeLexOrdering()
192                         .reverse()
193                         .onKeys()
194                         .sortedCopy(insertionOrder);
195                   }
196 
197                   @SuppressWarnings("unchecked")
198                   @Override
199                   public Range<Integer>[] createKeyArray(int length) {
200                     return new Range[length];
201                   }
202 
203                   @Override
204                   public String[] createValueArray(int length) {
205                     return new String[length];
206                   }
207                 })
208             .named("TreeRangeMap.asDescendingMapOfRanges")
209             .withFeatures(
210                 CollectionSize.ANY,
211                 MapFeature.SUPPORTS_REMOVE,
212                 MapFeature.ALLOWS_ANY_NULL_QUERIES,
213                 CollectionFeature.KNOWN_ORDER,
214                 CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
215             .createTestSuite());
216 
217     suite.addTest(
218         MapTestSuiteBuilder.using(
219                 new TestMapGenerator<Range<Integer>, String>() {
220                   @Override
221                   public SampleElements<Entry<Range<Integer>, String>> samples() {
222                     return new SampleElements<>(
223                         mapEntry(Range.singleton(0), "banana"),
224                         mapEntry(Range.closedOpen(3, 5), "frisbee"),
225                         mapEntry(Range.atMost(-1), "fruitcake"),
226                         mapEntry(Range.open(10, 15), "elephant"),
227                         mapEntry(Range.closed(20, 22), "umbrella"));
228                   }
229 
230                   @Override
231                   public Map<Range<Integer>, String> create(Object... elements) {
232                     RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
233                     for (Object o : elements) {
234                       @SuppressWarnings("unchecked")
235                       Entry<Range<Integer>, String> entry = (Entry<Range<Integer>, String>) o;
236                       rangeMap.put(entry.getKey(), entry.getValue());
237                     }
238                     return rangeMap.subRangeMap(Range.atMost(22)).asDescendingMapOfRanges();
239                   }
240 
241                   @SuppressWarnings("unchecked")
242                   @Override
243                   public Entry<Range<Integer>, String>[] createArray(int length) {
244                     return new Entry[length];
245                   }
246 
247                   @Override
248                   public Iterable<Entry<Range<Integer>, String>> order(
249                       List<Entry<Range<Integer>, String>> insertionOrder) {
250                     return Range.<Integer>rangeLexOrdering()
251                         .reverse()
252                         .onKeys()
253                         .sortedCopy(insertionOrder);
254                   }
255 
256                   @SuppressWarnings("unchecked")
257                   @Override
258                   public Range<Integer>[] createKeyArray(int length) {
259                     return new Range[length];
260                   }
261 
262                   @Override
263                   public String[] createValueArray(int length) {
264                     return new String[length];
265                   }
266                 })
267             .named("TreeRangeMap.subRangeMap.asDescendingMapOfRanges")
268             .withFeatures(
269                 CollectionSize.ANY,
270                 MapFeature.SUPPORTS_REMOVE,
271                 MapFeature.ALLOWS_ANY_NULL_QUERIES,
272                 CollectionFeature.KNOWN_ORDER)
273             .createTestSuite());
274     return suite;
275   }
276 
277   private static final ImmutableList<Range<Integer>> RANGES;
278   private static final int MIN_BOUND = -2;
279   private static final int MAX_BOUND = 2;
280 
281   static {
282     ImmutableList.Builder<Range<Integer>> builder = ImmutableList.builder();
283 
all()284     builder.add(Range.<Integer>all());
285 
286     // Add one-ended ranges
287     for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
288       for (BoundType type : BoundType.values()) {
Range.upTo(i, type)289         builder.add(Range.upTo(i, type));
Range.downTo(i, type)290         builder.add(Range.downTo(i, type));
291       }
292     }
293 
294     // Add two-ended ranges
295     for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
296       for (int j = i; j <= MAX_BOUND; j++) {
297         for (BoundType lowerType : BoundType.values()) {
298           for (BoundType upperType : BoundType.values()) {
299             if (i == j & lowerType == OPEN & upperType == OPEN) {
300               continue;
301             }
Range.range(i, lowerType, j, upperType)302             builder.add(Range.range(i, lowerType, j, upperType));
303           }
304         }
305       }
306     }
307     RANGES = builder.build();
308   }
309 
testSpanSingleRange()310   public void testSpanSingleRange() {
311     for (Range<Integer> range : RANGES) {
312       RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
313       rangeMap.put(range, 1);
314 
315       try {
316         assertEquals(range, rangeMap.span());
317         assertFalse(range.isEmpty());
318       } catch (NoSuchElementException e) {
319         assertTrue(range.isEmpty());
320       }
321     }
322   }
323 
testSpanTwoRanges()324   public void testSpanTwoRanges() {
325     for (Range<Integer> range1 : RANGES) {
326       for (Range<Integer> range2 : RANGES) {
327         RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
328         rangeMap.put(range1, 1);
329         rangeMap.put(range2, 2);
330 
331         Range<Integer> expected;
332         if (range1.isEmpty()) {
333           if (range2.isEmpty()) {
334             expected = null;
335           } else {
336             expected = range2;
337           }
338         } else {
339           if (range2.isEmpty()) {
340             expected = range1;
341           } else {
342             expected = range1.span(range2);
343           }
344         }
345 
346         try {
347           assertEquals(expected, rangeMap.span());
348           assertNotNull(expected);
349         } catch (NoSuchElementException e) {
350           assertNull(expected);
351         }
352       }
353     }
354   }
355 
testAllRangesAlone()356   public void testAllRangesAlone() {
357     for (Range<Integer> range : RANGES) {
358       Map<Integer, Integer> model = Maps.newHashMap();
359       putModel(model, range, 1);
360       RangeMap<Integer, Integer> test = TreeRangeMap.create();
361       test.put(range, 1);
362       verify(model, test);
363     }
364   }
365 
testAllRangePairs()366   public void testAllRangePairs() {
367     for (Range<Integer> range1 : RANGES) {
368       for (Range<Integer> range2 : RANGES) {
369         Map<Integer, Integer> model = Maps.newHashMap();
370         putModel(model, range1, 1);
371         putModel(model, range2, 2);
372         RangeMap<Integer, Integer> test = TreeRangeMap.create();
373         test.put(range1, 1);
374         test.put(range2, 2);
375         verify(model, test);
376       }
377     }
378   }
379 
testAllRangeTriples()380   public void testAllRangeTriples() {
381     for (Range<Integer> range1 : RANGES) {
382       for (Range<Integer> range2 : RANGES) {
383         for (Range<Integer> range3 : RANGES) {
384           Map<Integer, Integer> model = Maps.newHashMap();
385           putModel(model, range1, 1);
386           putModel(model, range2, 2);
387           putModel(model, range3, 3);
388           RangeMap<Integer, Integer> test = TreeRangeMap.create();
389           test.put(range1, 1);
390           test.put(range2, 2);
391           test.put(range3, 3);
392           verify(model, test);
393         }
394       }
395     }
396   }
397 
testPutAll()398   public void testPutAll() {
399     for (Range<Integer> range1 : RANGES) {
400       for (Range<Integer> range2 : RANGES) {
401         for (Range<Integer> range3 : RANGES) {
402           Map<Integer, Integer> model = Maps.newHashMap();
403           putModel(model, range1, 1);
404           putModel(model, range2, 2);
405           putModel(model, range3, 3);
406           RangeMap<Integer, Integer> test = TreeRangeMap.create();
407           RangeMap<Integer, Integer> test2 = TreeRangeMap.create();
408           // put range2 and range3 into test2, and then put test2 into test
409           test.put(range1, 1);
410           test2.put(range2, 2);
411           test2.put(range3, 3);
412           test.putAll(test2);
413           verify(model, test);
414         }
415       }
416     }
417   }
418 
testPutAndRemove()419   public void testPutAndRemove() {
420     for (Range<Integer> rangeToPut : RANGES) {
421       for (Range<Integer> rangeToRemove : RANGES) {
422         Map<Integer, Integer> model = Maps.newHashMap();
423         putModel(model, rangeToPut, 1);
424         removeModel(model, rangeToRemove);
425         RangeMap<Integer, Integer> test = TreeRangeMap.create();
426         test.put(rangeToPut, 1);
427         test.remove(rangeToRemove);
428         verify(model, test);
429       }
430     }
431   }
432 
testPutTwoAndRemove()433   public void testPutTwoAndRemove() {
434     for (Range<Integer> rangeToPut1 : RANGES) {
435       for (Range<Integer> rangeToPut2 : RANGES) {
436         for (Range<Integer> rangeToRemove : RANGES) {
437           Map<Integer, Integer> model = Maps.newHashMap();
438           putModel(model, rangeToPut1, 1);
439           putModel(model, rangeToPut2, 2);
440           removeModel(model, rangeToRemove);
441           RangeMap<Integer, Integer> test = TreeRangeMap.create();
442           test.put(rangeToPut1, 1);
443           test.put(rangeToPut2, 2);
444           test.remove(rangeToRemove);
445           verify(model, test);
446         }
447       }
448     }
449   }
450 
451   // identical to testPutTwoAndRemove,
452   // verifies that putCoalescing() doesn't cause any mappings to change relative to put()
testPutCoalescingTwoAndRemove()453   public void testPutCoalescingTwoAndRemove() {
454     for (Range<Integer> rangeToPut1 : RANGES) {
455       for (Range<Integer> rangeToPut2 : RANGES) {
456         for (Range<Integer> rangeToRemove : RANGES) {
457           Map<Integer, Integer> model = Maps.newHashMap();
458           putModel(model, rangeToPut1, 1);
459           putModel(model, rangeToPut2, 2);
460           removeModel(model, rangeToRemove);
461           RangeMap<Integer, Integer> test = TreeRangeMap.create();
462           test.putCoalescing(rangeToPut1, 1);
463           test.putCoalescing(rangeToPut2, 2);
464           test.remove(rangeToRemove);
465           verify(model, test);
466         }
467       }
468     }
469   }
470 
testPutCoalescing()471   public void testPutCoalescing() {
472     // {[0..1): 1, [1..2): 1, [2..3): 2} -> {[0..2): 1, [2..3): 2}
473     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
474     rangeMap.putCoalescing(Range.closedOpen(0, 1), 1);
475     rangeMap.putCoalescing(Range.closedOpen(1, 2), 1);
476     rangeMap.putCoalescing(Range.closedOpen(2, 3), 2);
477     assertEquals(
478         ImmutableMap.of(Range.closedOpen(0, 2), 1, Range.closedOpen(2, 3), 2),
479         rangeMap.asMapOfRanges());
480   }
481 
testPutCoalescingEmpty()482   public void testPutCoalescingEmpty() {
483     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
484     rangeMap.put(Range.closedOpen(0, 1), 1);
485     rangeMap.put(Range.closedOpen(1, 2), 1);
486     assertEquals(
487         ImmutableMap.of(Range.closedOpen(0, 1), 1, Range.closedOpen(1, 2), 1),
488         rangeMap.asMapOfRanges());
489 
490     rangeMap.putCoalescing(Range.closedOpen(1, 1), 1); // empty range coalesces connected ranges
491     assertEquals(ImmutableMap.of(Range.closedOpen(0, 2), 1), rangeMap.asMapOfRanges());
492   }
493 
testPutCoalescingSubmapEmpty()494   public void testPutCoalescingSubmapEmpty() {
495     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
496     rangeMap.put(Range.closedOpen(0, 1), 1);
497     rangeMap.put(Range.closedOpen(1, 2), 1);
498     assertEquals(
499         ImmutableMap.of(Range.closedOpen(0, 1), 1, Range.closedOpen(1, 2), 1),
500         rangeMap.asMapOfRanges());
501 
502     RangeMap<Integer, Integer> subRangeMap = rangeMap.subRangeMap(Range.closedOpen(0, 2));
503     subRangeMap.putCoalescing(Range.closedOpen(1, 1), 1); // empty range coalesces connected ranges
504     assertEquals(ImmutableMap.of(Range.closedOpen(0, 2), 1), subRangeMap.asMapOfRanges());
505     assertEquals(ImmutableMap.of(Range.closedOpen(0, 2), 1), rangeMap.asMapOfRanges());
506   }
507 
testPutCoalescingComplex()508   public void testPutCoalescingComplex() {
509     // {[0..1): 1, [1..3): 1, [3..5): 1, [7..10): 2, [12..15): 2, [18..19): 3}
510     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
511     rangeMap.put(Range.closedOpen(0, 1), 1);
512     rangeMap.put(Range.closedOpen(1, 3), 1);
513     rangeMap.put(Range.closedOpen(3, 5), 1);
514     rangeMap.put(Range.closedOpen(7, 10), 2);
515     rangeMap.put(Range.closedOpen(12, 15), 2);
516     rangeMap.put(Range.closedOpen(18, 19), 3);
517 
518     rangeMap.putCoalescing(Range.closedOpen(-5, -4), 0); // disconnected
519     rangeMap.putCoalescing(Range.closedOpen(-6, -5), 0); // lower than minimum
520 
521     rangeMap.putCoalescing(Range.closedOpen(2, 4), 1); // between
522     rangeMap.putCoalescing(Range.closedOpen(9, 14), 0); // different value
523     rangeMap.putCoalescing(Range.closedOpen(17, 20), 3); // enclosing
524 
525     rangeMap.putCoalescing(Range.closedOpen(22, 23), 4); // disconnected
526     rangeMap.putCoalescing(Range.closedOpen(23, 25), 4); // greater than minimum
527 
528     // {[-6..-4): 0, [0..1): 1, [1..5): 1, [7..9): 2,
529     //  [9..14): 0, [14..15): 2, [17..20): 3, [22..25): 4}
530     assertEquals(
531         new ImmutableMap.Builder<>()
532             .put(Range.closedOpen(-6, -4), 0)
533             .put(Range.closedOpen(0, 1), 1) // not coalesced
534             .put(Range.closedOpen(1, 5), 1)
535             .put(Range.closedOpen(7, 9), 2)
536             .put(Range.closedOpen(9, 14), 0)
537             .put(Range.closedOpen(14, 15), 2)
538             .put(Range.closedOpen(17, 20), 3)
539             .put(Range.closedOpen(22, 25), 4)
540             .build(),
541         rangeMap.asMapOfRanges());
542   }
543 
testMergeOntoRangeOverlappingLowerBound()544   public void testMergeOntoRangeOverlappingLowerBound() {
545     // {[0..2): 1}
546     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
547     rangeMap.put(Range.closedOpen(0, 2), 1);
548 
549     rangeMap.merge(Range.closedOpen(1, 3), 2, Integer::sum);
550 
551     // {[0..1): 1, [1..2): 3, [2, 3): 2}
552     assertEquals(
553         new ImmutableMap.Builder<>()
554             .put(Range.closedOpen(0, 1), 1)
555             .put(Range.closedOpen(1, 2), 3)
556             .put(Range.closedOpen(2, 3), 2)
557             .build(),
558         rangeMap.asMapOfRanges());
559   }
560 
testMergeOntoRangeOverlappingUpperBound()561   public void testMergeOntoRangeOverlappingUpperBound() {
562     // {[1..3): 1}
563     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
564     rangeMap.put(Range.closedOpen(1, 3), 1);
565 
566     rangeMap.merge(Range.closedOpen(0, 2), 2, Integer::sum);
567 
568     // {[0..1): 2, [1..2): 3, [2, 3): 1}
569     assertEquals(
570         new ImmutableMap.Builder<>()
571             .put(Range.closedOpen(0, 1), 2)
572             .put(Range.closedOpen(1, 2), 3)
573             .put(Range.closedOpen(2, 3), 1)
574             .build(),
575         rangeMap.asMapOfRanges());
576   }
577 
testMergeOntoIdenticalRange()578   public void testMergeOntoIdenticalRange() {
579     // {[0..1): 1}
580     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
581     rangeMap.put(Range.closedOpen(0, 1), 1);
582 
583     rangeMap.merge(Range.closedOpen(0, 1), 2, Integer::sum);
584 
585     // {[0..1): 3}
586     assertEquals(ImmutableMap.of(Range.closedOpen(0, 1), 3), rangeMap.asMapOfRanges());
587   }
588 
testMergeOntoSuperRange()589   public void testMergeOntoSuperRange() {
590     // {[0..3): 1}
591     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
592     rangeMap.put(Range.closedOpen(0, 3), 1);
593 
594     rangeMap.merge(Range.closedOpen(1, 2), 2, Integer::sum);
595 
596     // {[0..1): 1, [1..2): 3, [2..3): 1}
597     assertEquals(
598         new ImmutableMap.Builder<>()
599             .put(Range.closedOpen(0, 1), 1)
600             .put(Range.closedOpen(1, 2), 3)
601             .put(Range.closedOpen(2, 3), 1)
602             .build(),
603         rangeMap.asMapOfRanges());
604   }
605 
testMergeOntoSubRange()606   public void testMergeOntoSubRange() {
607     // {[1..2): 1}
608     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
609     rangeMap.put(Range.closedOpen(1, 2), 1);
610 
611     rangeMap.merge(Range.closedOpen(0, 3), 2, Integer::sum);
612 
613     // {[0..1): 2, [1..2): 3, [2..3): 2}
614     assertEquals(
615         new ImmutableMap.Builder<>()
616             .put(Range.closedOpen(0, 1), 2)
617             .put(Range.closedOpen(1, 2), 3)
618             .put(Range.closedOpen(2, 3), 2)
619             .build(),
620         rangeMap.asMapOfRanges());
621   }
622 
testMergeOntoDisconnectedRanges()623   public void testMergeOntoDisconnectedRanges() {
624     // {[0..1): 1, [2, 3): 2}
625     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
626     rangeMap.put(Range.closedOpen(0, 1), 1);
627     rangeMap.put(Range.closedOpen(2, 3), 2);
628 
629     rangeMap.merge(Range.closedOpen(0, 3), 3, Integer::sum);
630 
631     // {[0..1): 4, [1..2): 3, [2..3): 5}
632     assertEquals(
633         new ImmutableMap.Builder<>()
634             .put(Range.closedOpen(0, 1), 4)
635             .put(Range.closedOpen(1, 2), 3)
636             .put(Range.closedOpen(2, 3), 5)
637             .build(),
638         rangeMap.asMapOfRanges());
639   }
640 
testMergeNullValue()641   public void testMergeNullValue() {
642     // {[1..2): 1, [3, 4): 2}
643     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
644     rangeMap.put(Range.closedOpen(1, 2), 1);
645     rangeMap.put(Range.closedOpen(3, 4), 2);
646 
647     rangeMap.merge(Range.closedOpen(0, 5), null, (v1, v2) -> v1 + 1);
648 
649     // {[1..2): 2, [3..4): 3}
650     assertEquals(
651         new ImmutableMap.Builder<>()
652             .put(Range.closedOpen(1, 2), 2)
653             .put(Range.closedOpen(3, 4), 3)
654             .build(),
655         rangeMap.asMapOfRanges());
656   }
657 
testMergeWithRemappingFunctionReturningNullValue()658   public void testMergeWithRemappingFunctionReturningNullValue() {
659     // {[1..2): 1, [3, 4): 2}
660     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
661     rangeMap.put(Range.closedOpen(1, 2), 1);
662     rangeMap.put(Range.closedOpen(3, 4), 2);
663 
664     rangeMap.merge(Range.closedOpen(0, 5), 3, (v1, v2) -> null);
665 
666     // {[0..1): 3, [2..3): 3, [4, 5): 3}
667     assertEquals(
668         new ImmutableMap.Builder<>()
669             .put(Range.closedOpen(0, 1), 3)
670             .put(Range.closedOpen(2, 3), 3)
671             .put(Range.closedOpen(4, 5), 3)
672             .build(),
673         rangeMap.asMapOfRanges());
674   }
675 
testMergeAllRangeTriples()676   public void testMergeAllRangeTriples() {
677     for (Range<Integer> range1 : RANGES) {
678       for (Range<Integer> range2 : RANGES) {
679         for (Range<Integer> range3 : RANGES) {
680           Map<Integer, Integer> model = Maps.newHashMap();
681           mergeModel(model, range1, 1, Integer::sum);
682           mergeModel(model, range2, 2, Integer::sum);
683           mergeModel(model, range3, 3, Integer::sum);
684           RangeMap<Integer, Integer> test = TreeRangeMap.create();
685           test.merge(range1, 1, Integer::sum);
686           test.merge(range2, 2, Integer::sum);
687           test.merge(range3, 3, Integer::sum);
688           verify(model, test);
689         }
690       }
691     }
692   }
693 
694 
testSubRangeMapExhaustive()695   public void testSubRangeMapExhaustive() {
696     for (Range<Integer> range1 : RANGES) {
697       for (Range<Integer> range2 : RANGES) {
698         RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
699         rangeMap.put(range1, 1);
700         rangeMap.put(range2, 2);
701 
702         for (Range<Integer> subRange : RANGES) {
703           RangeMap<Integer, Integer> expected = TreeRangeMap.create();
704           for (Entry<Range<Integer>, Integer> entry : rangeMap.asMapOfRanges().entrySet()) {
705             if (entry.getKey().isConnected(subRange)) {
706               expected.put(entry.getKey().intersection(subRange), entry.getValue());
707             }
708           }
709           RangeMap<Integer, Integer> subRangeMap = rangeMap.subRangeMap(subRange);
710           assertEquals(expected, subRangeMap);
711           assertEquals(expected.asMapOfRanges(), subRangeMap.asMapOfRanges());
712           assertEquals(expected.asDescendingMapOfRanges(), subRangeMap.asDescendingMapOfRanges());
713           assertEquals(
714               ImmutableList.copyOf(subRangeMap.asMapOfRanges().entrySet()).reverse(),
715               ImmutableList.copyOf(subRangeMap.asDescendingMapOfRanges().entrySet()));
716 
717           if (!expected.asMapOfRanges().isEmpty()) {
718             assertEquals(expected.span(), subRangeMap.span());
719           }
720 
721           for (int i = MIN_BOUND; i <= MAX_BOUND; i++) {
722             assertEquals(expected.get(i), subRangeMap.get(i));
723           }
724 
725           for (Range<Integer> query : RANGES) {
726             assertEquals(
727                 expected.asMapOfRanges().get(query), subRangeMap.asMapOfRanges().get(query));
728           }
729         }
730       }
731     }
732   }
733 
testSubSubRangeMap()734   public void testSubSubRangeMap() {
735     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
736     rangeMap.put(Range.open(3, 7), 1);
737     rangeMap.put(Range.closed(9, 10), 2);
738     rangeMap.put(Range.closed(12, 16), 3);
739     RangeMap<Integer, Integer> sub1 = rangeMap.subRangeMap(Range.closed(5, 11));
740     assertEquals(
741         ImmutableMap.of(Range.closedOpen(5, 7), 1, Range.closed(9, 10), 2), sub1.asMapOfRanges());
742     RangeMap<Integer, Integer> sub2 = sub1.subRangeMap(Range.open(6, 15));
743     assertEquals(
744         ImmutableMap.of(Range.open(6, 7), 1, Range.closed(9, 10), 2), sub2.asMapOfRanges());
745   }
746 
testSubRangeMapPut()747   public void testSubRangeMapPut() {
748     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
749     rangeMap.put(Range.open(3, 7), 1);
750     rangeMap.put(Range.closed(9, 10), 2);
751     rangeMap.put(Range.closed(12, 16), 3);
752     RangeMap<Integer, Integer> sub = rangeMap.subRangeMap(Range.closed(5, 11));
753     assertEquals(
754         ImmutableMap.of(Range.closedOpen(5, 7), 1, Range.closed(9, 10), 2), sub.asMapOfRanges());
755     sub.put(Range.closed(7, 9), 4);
756     assertEquals(
757         ImmutableMap.of(
758             Range.closedOpen(5, 7), 1, Range.closed(7, 9), 4, Range.openClosed(9, 10), 2),
759         sub.asMapOfRanges());
760     assertEquals(
761         ImmutableMap.of(
762             Range.open(3, 7),
763             1,
764             Range.closed(7, 9),
765             4,
766             Range.openClosed(9, 10),
767             2,
768             Range.closed(12, 16),
769             3),
770         rangeMap.asMapOfRanges());
771 
772     assertThrows(IllegalArgumentException.class, () -> sub.put(Range.open(9, 12), 5));
773 
774     RangeMap<Integer, Integer> subSub = sub.subRangeMap(Range.closedOpen(5, 5));
775     subSub.put(Range.closedOpen(5, 5), 6); // should be a no-op
776     assertEquals(
777         ImmutableMap.of(
778             Range.open(3, 7),
779             1,
780             Range.closed(7, 9),
781             4,
782             Range.openClosed(9, 10),
783             2,
784             Range.closed(12, 16),
785             3),
786         rangeMap.asMapOfRanges());
787   }
788 
testSubRangeMapPutCoalescing()789   public void testSubRangeMapPutCoalescing() {
790     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
791     rangeMap.put(Range.open(3, 7), 1);
792     rangeMap.put(Range.closed(9, 10), 2);
793     rangeMap.put(Range.closed(12, 16), 3);
794     RangeMap<Integer, Integer> sub = rangeMap.subRangeMap(Range.closed(5, 11));
795     assertEquals(
796         ImmutableMap.of(Range.closedOpen(5, 7), 1, Range.closed(9, 10), 2), sub.asMapOfRanges());
797     sub.putCoalescing(Range.closed(7, 9), 2);
798     assertEquals(
799         ImmutableMap.of(Range.closedOpen(5, 7), 1, Range.closed(7, 10), 2), sub.asMapOfRanges());
800     assertEquals(
801         ImmutableMap.of(Range.open(3, 7), 1, Range.closed(7, 10), 2, Range.closed(12, 16), 3),
802         rangeMap.asMapOfRanges());
803 
804     sub.putCoalescing(Range.singleton(7), 1);
805     assertEquals(
806         ImmutableMap.of(Range.closed(5, 7), 1, Range.openClosed(7, 10), 2), sub.asMapOfRanges());
807     assertEquals(
808         ImmutableMap.of(
809             Range.open(3, 5),
810             1,
811             Range.closed(5, 7),
812             1,
813             Range.openClosed(7, 10),
814             2,
815             Range.closed(12, 16),
816             3),
817         rangeMap.asMapOfRanges());
818 
819     assertThrows(IllegalArgumentException.class, () -> sub.putCoalescing(Range.open(9, 12), 5));
820   }
821 
testSubRangeMapRemove()822   public void testSubRangeMapRemove() {
823     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
824     rangeMap.put(Range.open(3, 7), 1);
825     rangeMap.put(Range.closed(9, 10), 2);
826     rangeMap.put(Range.closed(12, 16), 3);
827     RangeMap<Integer, Integer> sub = rangeMap.subRangeMap(Range.closed(5, 11));
828     assertEquals(
829         ImmutableMap.of(Range.closedOpen(5, 7), 1, Range.closed(9, 10), 2), sub.asMapOfRanges());
830     sub.remove(Range.closed(7, 9));
831     assertEquals(
832         ImmutableMap.of(Range.closedOpen(5, 7), 1, Range.openClosed(9, 10), 2),
833         sub.asMapOfRanges());
834     assertEquals(
835         ImmutableMap.of(Range.open(3, 7), 1, Range.openClosed(9, 10), 2, Range.closed(12, 16), 3),
836         rangeMap.asMapOfRanges());
837 
838     sub.remove(Range.closed(3, 9));
839     assertEquals(ImmutableMap.of(Range.openClosed(9, 10), 2), sub.asMapOfRanges());
840     assertEquals(
841         ImmutableMap.of(Range.open(3, 5), 1, Range.openClosed(9, 10), 2, Range.closed(12, 16), 3),
842         rangeMap.asMapOfRanges());
843   }
844 
testSubRangeMapClear()845   public void testSubRangeMapClear() {
846     RangeMap<Integer, Integer> rangeMap = TreeRangeMap.create();
847     rangeMap.put(Range.open(3, 7), 1);
848     rangeMap.put(Range.closed(9, 10), 2);
849     rangeMap.put(Range.closed(12, 16), 3);
850     RangeMap<Integer, Integer> sub = rangeMap.subRangeMap(Range.closed(5, 11));
851     sub.clear();
852     assertEquals(
853         ImmutableMap.of(Range.open(3, 5), 1, Range.closed(12, 16), 3), rangeMap.asMapOfRanges());
854   }
855 
verify(Map<Integer, Integer> model, RangeMap<Integer, Integer> test)856   private void verify(Map<Integer, Integer> model, RangeMap<Integer, Integer> test) {
857     for (int i = MIN_BOUND - 1; i <= MAX_BOUND + 1; i++) {
858       assertEquals(model.get(i), test.get(i));
859 
860       Entry<Range<Integer>, Integer> entry = test.getEntry(i);
861       assertEquals(model.containsKey(i), entry != null);
862       if (entry != null) {
863         assertTrue(test.asMapOfRanges().entrySet().contains(entry));
864       }
865     }
866     for (Range<Integer> range : test.asMapOfRanges().keySet()) {
867       assertFalse(range.isEmpty());
868     }
869   }
870 
putModel(Map<Integer, Integer> model, Range<Integer> range, int value)871   private static void putModel(Map<Integer, Integer> model, Range<Integer> range, int value) {
872     for (int i = MIN_BOUND - 1; i <= MAX_BOUND + 1; i++) {
873       if (range.contains(i)) {
874         model.put(i, value);
875       }
876     }
877   }
878 
removeModel(Map<Integer, Integer> model, Range<Integer> range)879   private static void removeModel(Map<Integer, Integer> model, Range<Integer> range) {
880     for (int i = MIN_BOUND - 1; i <= MAX_BOUND + 1; i++) {
881       if (range.contains(i)) {
882         model.remove(i);
883       }
884     }
885   }
886 
mergeModel( Map<Integer, Integer> model, Range<Integer> range, int value, BiFunction<? super Integer, ? super Integer, ? extends Integer> remappingFunction)887   private static void mergeModel(
888       Map<Integer, Integer> model,
889       Range<Integer> range,
890       int value,
891       BiFunction<? super Integer, ? super Integer, ? extends Integer> remappingFunction) {
892     for (int i = MIN_BOUND - 1; i <= MAX_BOUND + 1; i++) {
893       if (range.contains(i)) {
894         model.merge(i, value, remappingFunction);
895       }
896     }
897   }
898 }
899