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