2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.util;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotSame;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertSame;
15 import static org.junit.Assert.assertTrue;
16 import static org.junit.Assert.fail;
17 import com.google.common.collect.ImmutableMap;
18 import com.google.common.collect.Iterables;
19 import com.google.common.collect.Iterators;
20 import java.io.ByteArrayInputStream;
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.io.ObjectInputStream;
24 import java.io.ObjectOutputStream;
25 import java.util.AbstractMap.SimpleEntry;
26 import java.util.Collections;
27 import java.util.ConcurrentModificationException;
28 import java.util.Iterator;
30 import java.util.Map.Entry;
31 import java.util.NoSuchElementException;
33 import org.junit.Before;
34 import org.junit.Test;
36 public class OffsetMapTest {
37 private final Map<String, String> twoEntryMap = ImmutableMap.of("k1", "v1", "k2", "v2");
38 private final Map<String, String> threeEntryMap = ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3");
40 private ImmutableOffsetMap<String, String> createMap() {
41 return (ImmutableOffsetMap<String, String>) ImmutableOffsetMap.orderedCopyOf(twoEntryMap);
44 private ImmutableOffsetMap<String, String> unorderedMap() {
45 return (ImmutableOffsetMap<String, String>) ImmutableOffsetMap.unorderedCopyOf(twoEntryMap);
50 OffsetMapCache.invalidateCache();
53 @Test(expected=IllegalArgumentException.class)
54 public void testWrongImmutableConstruction() {
55 new ImmutableOffsetMap.Ordered<String, String>(Collections.<String, Integer>emptyMap(), new String[1]);
59 public void testCopyEmptyMap() {
60 final Map<String, String> source = Collections.emptyMap();
61 final Map<String, String> result = ImmutableOffsetMap.orderedCopyOf(source);
63 assertEquals(source, result);
64 assertTrue(result instanceof ImmutableMap);
68 public void testCopySingletonMap() {
69 final Map<String, String> source = Collections.singletonMap("a", "b");
70 final Map<String, String> result = ImmutableOffsetMap.orderedCopyOf(source);
72 assertEquals(source, result);
73 assertTrue(result instanceof SharedSingletonMap);
77 public void testCopyMap() {
78 final ImmutableOffsetMap<String, String> map = createMap();
80 // Equality in both directions
81 assertEquals(twoEntryMap, map);
82 assertEquals(map, twoEntryMap);
84 // hashcode has to match
85 assertEquals(twoEntryMap.hashCode(), map.hashCode());
87 // Iterator order needs to be preserved
88 assertTrue(Iterators.elementsEqual(twoEntryMap.entrySet().iterator(), map.entrySet().iterator()));
90 // Should result in the same object
91 assertSame(map, ImmutableOffsetMap.orderedCopyOf(map));
93 final Map<String, String> mutable = map.toModifiableMap();
94 final Map<String, String> copy = ImmutableOffsetMap.orderedCopyOf(mutable);
96 assertEquals(mutable, copy);
97 assertEquals(map, copy);
98 assertNotSame(mutable, copy);
99 assertNotSame(map, copy);
103 public void testImmutableSimpleEquals() {
104 final Map<String, String> map = createMap();
106 assertTrue(map.equals(map));
107 assertFalse(map.equals(null));
108 assertFalse(map.equals("string"));
112 public void testImmutableGet() {
113 final Map<String, String> map = createMap();
115 assertEquals("v1", map.get("k1"));
116 assertEquals("v2", map.get("k2"));
117 assertNull(map.get("non-existent"));
118 assertNull(map.get(null));
122 public void testImmutableGuards() {
123 final Map<String, String> map = createMap();
126 map.values().add("v1");
128 } catch (UnsupportedOperationException e) {
132 map.values().remove("v1");
134 } catch (UnsupportedOperationException e) {
138 map.values().clear();
140 } catch (UnsupportedOperationException e) {
144 final Iterator<String> it = map.values().iterator();
148 } catch (UnsupportedOperationException e) {
152 map.keySet().add("k1");
154 } catch (UnsupportedOperationException e) {
158 map.keySet().clear();
160 } catch (UnsupportedOperationException e) {
164 map.keySet().remove("k1");
166 } catch (UnsupportedOperationException e) {
170 final Iterator<String> it = map.keySet().iterator();
174 } catch (UnsupportedOperationException e) {
178 map.entrySet().clear();
180 } catch (UnsupportedOperationException e) {
184 map.entrySet().add(new SimpleEntry<>("k1", "v1"));
186 } catch (UnsupportedOperationException e) {
190 map.entrySet().remove(new SimpleEntry<>("k1", "v1"));
192 } catch (UnsupportedOperationException e) {
196 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
200 } catch (UnsupportedOperationException e) {
206 } catch (UnsupportedOperationException e) {
210 map.put("k1", "fail");
212 } catch (UnsupportedOperationException e) {
216 map.putAll(ImmutableMap.of("k1", "fail"));
218 } catch (UnsupportedOperationException e) {
224 } catch (UnsupportedOperationException e) {
229 public void testMutableGet() {
230 final Map<String, String> map = createMap().toModifiableMap();
233 assertEquals("v1", map.get("k1"));
234 assertEquals("v2", map.get("k2"));
235 assertEquals("v3", map.get("k3"));
236 assertNull(map.get("non-existent"));
237 assertNull(map.get(null));
241 public void testImmutableSize() {
242 final Map<String, String> map = createMap();
243 assertEquals(2, map.size());
247 public void testImmutableIsEmpty() {
248 final Map<String, String> map = createMap();
249 assertFalse(map.isEmpty());
253 public void testImmutableContains() {
254 final Map<String, String> map = createMap();
255 assertTrue(map.containsKey("k1"));
256 assertTrue(map.containsKey("k2"));
257 assertFalse(map.containsKey("non-existent"));
258 assertFalse(map.containsKey(null));
259 assertTrue(map.containsValue("v1"));
260 assertFalse(map.containsValue("non-existent"));
264 public void testImmutableEquals() {
265 final Map<String, String> map = createMap();
267 assertFalse(map.equals(threeEntryMap));
268 assertFalse(map.equals(ImmutableMap.of("k1", "v1", "k3", "v3")));
269 assertFalse(map.equals(ImmutableMap.of("k1", "v1", "k2", "different-value")));
273 public void testMutableContains() {
274 final Map<String, String> map = createMap().toModifiableMap();
276 assertTrue(map.containsKey("k1"));
277 assertTrue(map.containsKey("k2"));
278 assertTrue(map.containsKey("k3"));
279 assertFalse(map.containsKey("non-existent"));
280 assertFalse(map.containsKey(null));
284 public void testtoModifiableMap() {
285 final ImmutableOffsetMap<String, String> source = createMap();
286 final Map<String, String> result = source.toModifiableMap();
288 // The two maps should be equal, but isolated
289 assertTrue(result instanceof MutableOffsetMap);
290 assertEquals(source, result);
291 assertEquals(result, source);
293 // Quick test for clearing MutableOffsetMap
295 assertEquals(0, result.size());
296 assertEquals(Collections.emptyMap(), result);
298 // The two maps should differ now
299 assertFalse(source.equals(result));
300 assertFalse(result.equals(source));
302 // The source map should still equal the template
303 assertEquals(twoEntryMap, source);
304 assertEquals(source, twoEntryMap);
308 public void testReusedFields() {
309 final ImmutableOffsetMap<String, String> source = createMap();
310 final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
312 // Should not affect the result
313 mutable.remove("non-existent");
315 // Resulting map should be equal, but not the same object
316 final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
317 assertNotSame(source, result);
318 assertEquals(source, result);
320 // Internal fields should be reused
321 assertSame(source.offsets(), result.offsets());
322 assertSame(source.objects(), result.objects());
326 public void testReusedOffsets() {
327 final ImmutableOffsetMap<String, String> source = createMap();
328 final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
330 mutable.remove("k1");
331 mutable.put("k1", "v1");
333 final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
334 assertTrue(source.equals(result));
335 assertTrue(result.equals(source));
337 // Iterator order must not be preserved
338 assertFalse(Iterators.elementsEqual(source.entrySet().iterator(), result.entrySet().iterator()));
342 public void testReusedOffsetsUnordered() {
343 final ImmutableOffsetMap<String, String> source = unorderedMap();
344 final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
346 mutable.remove("k1");
347 mutable.put("k1", "v1");
349 final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
350 assertEquals(source, result);
352 // Only offsets should be shared
353 assertSame(source.offsets(), result.offsets());
354 assertNotSame(source.objects(), result.objects());
356 // Iterator order needs to be preserved
357 assertTrue(Iterators.elementsEqual(source.entrySet().iterator(), result.entrySet().iterator()));
361 public void testEmptyMutable() throws CloneNotSupportedException {
362 final MutableOffsetMap<String, String> map = MutableOffsetMap.ordered();
363 assertTrue(map.isEmpty());
365 final Map<String, String> other = map.clone();
366 assertEquals(other, map);
367 assertNotSame(other, map);
371 public void testMutableToEmpty() {
372 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
374 mutable.remove("k1");
375 mutable.remove("k2");
377 assertTrue(mutable.isEmpty());
378 assertSame(ImmutableMap.of(), mutable.toUnmodifiableMap());
382 public void testMutableToSingleton() {
383 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
385 mutable.remove("k1");
387 final Map<String, String> result = mutable.toUnmodifiableMap();
389 // Should devolve to a singleton
390 assertTrue(result instanceof SharedSingletonMap);
391 assertEquals(ImmutableMap.of("k2", "v2"), result);
395 public void testMutableToNewSingleton() {
396 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
398 mutable.remove("k1");
399 mutable.put("k3", "v3");
401 final Map<String, String> result = mutable.toUnmodifiableMap();
403 assertTrue(result instanceof ImmutableOffsetMap);
404 assertEquals(ImmutableMap.of("k2", "v2", "k3", "v3"), result);
408 public void testMutableSize() {
409 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
410 assertEquals(2, mutable.size());
412 mutable.put("k3", "v3");
413 assertEquals(3, mutable.size());
414 mutable.remove("k2");
415 assertEquals(2, mutable.size());
416 mutable.put("k1", "new-v1");
417 assertEquals(2, mutable.size());
421 public void testExpansionWithOrder() {
422 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
424 mutable.remove("k1");
425 mutable.put("k3", "v3");
426 mutable.put("k1", "v1");
428 assertEquals(ImmutableMap.of("k1", "v1", "k3", "v3"), mutable.newKeys());
430 final Map<String, String> result = mutable.toUnmodifiableMap();
432 assertTrue(result instanceof ImmutableOffsetMap);
433 assertEquals(threeEntryMap, result);
434 assertEquals(result, threeEntryMap);
435 assertFalse(Iterators.elementsEqual(threeEntryMap.entrySet().iterator(), result.entrySet().iterator()));
439 public void testExpansionWithoutOrder() {
440 final MutableOffsetMap<String, String> mutable = unorderedMap().toModifiableMap();
442 mutable.remove("k1");
443 mutable.put("k3", "v3");
444 mutable.put("k1", "v1");
446 assertEquals(ImmutableMap.of("k3", "v3"), mutable.newKeys());
448 final Map<String, String> result = mutable.toUnmodifiableMap();
450 assertTrue(result instanceof ImmutableOffsetMap);
451 assertEquals(threeEntryMap, result);
452 assertEquals(result, threeEntryMap);
453 assertTrue(Iterators.elementsEqual(threeEntryMap.entrySet().iterator(), result.entrySet().iterator()));
457 public void testReplacedValue() {
458 final ImmutableOffsetMap<String, String> source = createMap();
459 final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
461 mutable.put("k1", "replaced");
463 final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
464 final Map<String, String> reference = ImmutableMap.of("k1", "replaced", "k2", "v2");
466 assertEquals(reference, result);
467 assertEquals(result, reference);
468 assertSame(source.offsets(), result.offsets());
469 assertNotSame(source.objects(), result.objects());
473 public void testCloneableFlipping() throws CloneNotSupportedException {
474 final MutableOffsetMap<String, String> source = createMap().toModifiableMap();
476 // Must clone before mutation
477 assertTrue(source.needClone());
479 // Non-existent entry, should not clone
480 source.remove("non-existent");
481 assertTrue(source.needClone());
483 // Changes the array, should clone
485 assertFalse(source.needClone());
487 // Create a clone of the map, which shares the array
488 final MutableOffsetMap<String, String> result = source.clone();
489 assertFalse(source.needClone());
490 assertTrue(result.needClone());
491 assertSame(source.array(), result.array());
493 // Changes the array, should clone
494 source.put("k1", "v2");
495 assertFalse(source.needClone());
496 assertTrue(result.needClone());
498 // Forced copy, no cloning needed, but maps are equal
499 final ImmutableOffsetMap<String, String> immutable = (ImmutableOffsetMap<String, String>) source.toUnmodifiableMap();
500 assertFalse(source.needClone());
501 assertTrue(source.equals(immutable));
502 assertTrue(immutable.equals(source));
503 assertTrue(Iterables.elementsEqual(source.entrySet(), immutable.entrySet()));
507 public void testCloneableFlippingUnordered() throws CloneNotSupportedException {
508 final MutableOffsetMap<String, String> source = unorderedMap().toModifiableMap();
510 // Must clone before mutation
511 assertTrue(source.needClone());
513 // Non-existent entry, should not clone
514 source.remove("non-existent");
515 assertTrue(source.needClone());
517 // Changes the array, should clone
519 assertFalse(source.needClone());
521 // Create a clone of the map, which shares the array
522 final MutableOffsetMap<String, String> result = source.clone();
523 assertFalse(source.needClone());
524 assertTrue(result.needClone());
525 assertSame(source.array(), result.array());
527 // Changes the array, should clone
528 source.put("k1", "v2");
529 assertFalse(source.needClone());
530 assertTrue(result.needClone());
532 // Creates a immutable view, which shares the array
533 final ImmutableOffsetMap<String, String> immutable = (ImmutableOffsetMap<String, String>) source.toUnmodifiableMap();
534 assertTrue(source.needClone());
535 assertSame(source.array(), immutable.objects());
539 public void testMutableEntrySet() {
540 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
542 assertTrue(map.entrySet().add(new SimpleEntry<>("k3", "v3")));
543 assertTrue(map.containsKey("k3"));
544 assertEquals("v3", map.get("k3"));
546 // null is not an Entry: ignore
547 assertFalse(map.entrySet().remove(null));
549 // non-matching value: ignore
550 assertFalse(map.entrySet().remove(new SimpleEntry<>("k1", "other")));
551 assertTrue(map.containsKey("k1"));
553 // ignore null values
554 assertFalse(map.entrySet().remove(new SimpleEntry<>("k1", null)));
555 assertTrue(map.containsKey("k1"));
557 assertTrue(map.entrySet().remove(new SimpleEntry<>("k1", "v1")));
558 assertFalse(map.containsKey("k1"));
561 private static void assertIteratorBroken(final Iterator<?> it) {
565 } catch (ConcurrentModificationException e) {
570 } catch (ConcurrentModificationException e) {
575 } catch (ConcurrentModificationException e) {
580 public void testMutableSimpleEquals() {
581 final ImmutableOffsetMap<String, String> source = createMap();
582 final Map<String, String> map = source.toModifiableMap();
584 assertTrue(map.equals(map));
585 assertFalse(map.equals(null));
586 assertFalse(map.equals("string"));
587 assertTrue(map.equals(source));
591 public void testMutableSimpleHashCode() {
592 final Map<String, String> map = createMap().toModifiableMap();
594 assertEquals(twoEntryMap.hashCode(), map.hashCode());
598 public void testMutableIteratorBasics() {
599 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
600 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
602 // Not advanced, remove should fail
606 } catch (IllegalStateException e) {
609 assertTrue(it.hasNext());
610 assertEquals("k1", it.next().getKey());
611 assertTrue(it.hasNext());
612 assertEquals("k2", it.next().getKey());
613 assertFalse(it.hasNext());
615 // Check end-of-iteration throw
619 } catch (NoSuchElementException e) {
624 public void testMutableIteratorWithRemove() {
625 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
626 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
628 // Advance one element
629 assertTrue(it.hasNext());
630 assertEquals("k1", it.next().getKey());
634 assertEquals(1, map.size());
635 assertFalse(map.containsKey("k1"));
637 // Iterator should still work
638 assertTrue(it.hasNext());
639 assertEquals("k2", it.next().getKey());
640 assertFalse(it.hasNext());
644 public void testMutableIteratorOffsetReplaceWorks() {
645 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
646 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
649 map.put("k1", "new-v1");
650 assertTrue(it.hasNext());
654 public void testMutableIteratorNewReplaceWorks() {
655 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
657 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
660 map.put("k3", "new-v3");
661 assertTrue(it.hasNext());
665 public void testMutableIteratorOffsetAddBreaks() {
666 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
670 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
673 map.put("k1", "new-v1");
674 assertIteratorBroken(it);
678 public void testMutableIteratorNewAddBreaks() {
679 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
680 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
684 assertIteratorBroken(it);
688 public void testMutableIteratorOffsetRemoveBreaks() {
689 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
690 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
694 assertIteratorBroken(it);
698 public void testMutableIteratorNewRemoveBreaks() {
699 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
701 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
705 assertIteratorBroken(it);
709 public void testMutableCrossIteratorRemove() {
710 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
711 final Set<Entry<String, String>> es = map.entrySet();
712 final Iterator<Entry<String, String>> it1 = es.iterator();
713 final Iterator<Entry<String, String>> it2 = es.iterator();
719 assertEquals(1, map.size());
721 // Check it2 was broken
722 assertIteratorBroken(it2);
726 public void testImmutableSerialization() throws IOException, ClassNotFoundException {
727 final Map<String, String> source = createMap();
729 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
730 try (final ObjectOutputStream oos = new ObjectOutputStream(bos)) {
731 oos.writeObject(source);
734 final ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
735 @SuppressWarnings("unchecked")
736 final Map<String, String> result = (Map<String, String>) ois.readObject();
738 assertEquals(source, result);