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;
18 import com.google.common.collect.ImmutableMap;
19 import com.google.common.collect.Iterables;
20 import com.google.common.collect.Iterators;
21 import java.io.ByteArrayInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.ObjectInputStream;
25 import java.io.ObjectOutputStream;
26 import java.util.AbstractMap.SimpleEntry;
27 import java.util.Collections;
28 import java.util.ConcurrentModificationException;
29 import java.util.Iterator;
31 import java.util.Map.Entry;
32 import java.util.NoSuchElementException;
34 import org.junit.Before;
35 import org.junit.Test;
37 public class OffsetMapTest {
38 private final Map<String, String> twoEntryMap = ImmutableMap.of("k1", "v1", "k2", "v2");
39 private final Map<String, String> threeEntryMap = ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3");
41 private ImmutableOffsetMap<String, String> createMap() {
42 return (ImmutableOffsetMap<String, String>) ImmutableOffsetMap.orderedCopyOf(twoEntryMap);
45 private ImmutableOffsetMap<String, String> unorderedMap() {
46 return (ImmutableOffsetMap<String, String>) ImmutableOffsetMap.unorderedCopyOf(twoEntryMap);
51 OffsetMapCache.invalidateCache();
54 @Test(expected=IllegalArgumentException.class)
55 public void testWrongImmutableConstruction() {
56 new ImmutableOffsetMap.Ordered<>(Collections.<String, Integer>emptyMap(), new String[1]);
60 public void testCopyEmptyMap() {
61 final Map<String, String> source = Collections.emptyMap();
62 final Map<String, String> result = ImmutableOffsetMap.orderedCopyOf(source);
64 assertEquals(source, result);
65 assertTrue(result instanceof ImmutableMap);
69 public void testCopySingletonMap() {
70 final Map<String, String> source = Collections.singletonMap("a", "b");
71 final Map<String, String> result = ImmutableOffsetMap.orderedCopyOf(source);
73 assertEquals(source, result);
74 assertTrue(result instanceof SharedSingletonMap);
78 public void testCopyMap() {
79 final ImmutableOffsetMap<String, String> map = createMap();
81 // Equality in both directions
82 assertEquals(twoEntryMap, map);
83 assertEquals(map, twoEntryMap);
85 // hashcode has to match
86 assertEquals(twoEntryMap.hashCode(), map.hashCode());
88 // Iterator order needs to be preserved
89 assertTrue(Iterators.elementsEqual(twoEntryMap.entrySet().iterator(), map.entrySet().iterator()));
91 // Should result in the same object
92 assertSame(map, ImmutableOffsetMap.orderedCopyOf(map));
94 final Map<String, String> mutable = map.toModifiableMap();
95 final Map<String, String> copy = ImmutableOffsetMap.orderedCopyOf(mutable);
97 assertEquals(mutable, copy);
98 assertEquals(map, copy);
99 assertNotSame(mutable, copy);
100 assertNotSame(map, copy);
104 public void testImmutableSimpleEquals() {
105 final Map<String, String> map = createMap();
107 assertTrue(map.equals(map));
108 assertFalse(map.equals(null));
109 assertFalse(map.equals("string"));
113 public void testImmutableGet() {
114 final Map<String, String> map = createMap();
116 assertEquals("v1", map.get("k1"));
117 assertEquals("v2", map.get("k2"));
118 assertNull(map.get("non-existent"));
119 assertNull(map.get(null));
123 public void testImmutableGuards() {
124 final Map<String, String> map = createMap();
127 map.values().add("v1");
129 } catch (UnsupportedOperationException e) {
133 map.values().remove("v1");
135 } catch (UnsupportedOperationException e) {
139 map.values().clear();
141 } catch (UnsupportedOperationException e) {
145 final Iterator<String> it = map.values().iterator();
149 } catch (UnsupportedOperationException e) {
153 map.keySet().add("k1");
155 } catch (UnsupportedOperationException e) {
159 map.keySet().clear();
161 } catch (UnsupportedOperationException e) {
165 map.keySet().remove("k1");
167 } catch (UnsupportedOperationException e) {
171 final Iterator<String> it = map.keySet().iterator();
175 } catch (UnsupportedOperationException e) {
179 map.entrySet().clear();
181 } catch (UnsupportedOperationException e) {
185 map.entrySet().add(new SimpleEntry<>("k1", "v1"));
187 } catch (UnsupportedOperationException e) {
191 map.entrySet().remove(new SimpleEntry<>("k1", "v1"));
193 } catch (UnsupportedOperationException e) {
197 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
201 } catch (UnsupportedOperationException e) {
207 } catch (UnsupportedOperationException e) {
211 map.put("k1", "fail");
213 } catch (UnsupportedOperationException e) {
217 map.putAll(ImmutableMap.of("k1", "fail"));
219 } catch (UnsupportedOperationException e) {
225 } catch (UnsupportedOperationException e) {
230 public void testMutableGet() {
231 final Map<String, String> map = createMap().toModifiableMap();
234 assertEquals("v1", map.get("k1"));
235 assertEquals("v2", map.get("k2"));
236 assertEquals("v3", map.get("k3"));
237 assertNull(map.get("non-existent"));
238 assertNull(map.get(null));
242 public void testImmutableSize() {
243 final Map<String, String> map = createMap();
244 assertEquals(2, map.size());
248 public void testImmutableIsEmpty() {
249 final Map<String, String> map = createMap();
250 assertFalse(map.isEmpty());
254 public void testImmutableContains() {
255 final Map<String, String> map = createMap();
256 assertTrue(map.containsKey("k1"));
257 assertTrue(map.containsKey("k2"));
258 assertFalse(map.containsKey("non-existent"));
259 assertFalse(map.containsKey(null));
260 assertTrue(map.containsValue("v1"));
261 assertFalse(map.containsValue("non-existent"));
265 public void testImmutableEquals() {
266 final Map<String, String> map = createMap();
268 assertFalse(map.equals(threeEntryMap));
269 assertFalse(map.equals(ImmutableMap.of("k1", "v1", "k3", "v3")));
270 assertFalse(map.equals(ImmutableMap.of("k1", "v1", "k2", "different-value")));
274 public void testMutableContains() {
275 final Map<String, String> map = createMap().toModifiableMap();
277 assertTrue(map.containsKey("k1"));
278 assertTrue(map.containsKey("k2"));
279 assertTrue(map.containsKey("k3"));
280 assertFalse(map.containsKey("non-existent"));
281 assertFalse(map.containsKey(null));
285 public void testtoModifiableMap() {
286 final ImmutableOffsetMap<String, String> source = createMap();
287 final Map<String, String> result = source.toModifiableMap();
289 // The two maps should be equal, but isolated
290 assertTrue(result instanceof MutableOffsetMap);
291 assertEquals(source, result);
292 assertEquals(result, source);
294 // Quick test for clearing MutableOffsetMap
296 assertEquals(0, result.size());
297 assertEquals(Collections.emptyMap(), result);
299 // The two maps should differ now
300 assertFalse(source.equals(result));
301 assertFalse(result.equals(source));
303 // The source map should still equal the template
304 assertEquals(twoEntryMap, source);
305 assertEquals(source, twoEntryMap);
309 public void testReusedFields() {
310 final ImmutableOffsetMap<String, String> source = createMap();
311 final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
313 // Should not affect the result
314 mutable.remove("non-existent");
316 // Resulting map should be equal, but not the same object
317 final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
318 assertNotSame(source, result);
319 assertEquals(source, result);
321 // Internal fields should be reused
322 assertSame(source.offsets(), result.offsets());
323 assertSame(source.objects(), result.objects());
327 public void testReusedOffsets() {
328 final ImmutableOffsetMap<String, String> source = createMap();
329 final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
331 mutable.remove("k1");
332 mutable.put("k1", "v1");
334 final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
335 assertTrue(source.equals(result));
336 assertTrue(result.equals(source));
338 // Iterator order must not be preserved
339 assertFalse(Iterators.elementsEqual(source.entrySet().iterator(), result.entrySet().iterator()));
343 public void testReusedOffsetsUnordered() {
344 final ImmutableOffsetMap<String, String> source = unorderedMap();
345 final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
347 mutable.remove("k1");
348 mutable.put("k1", "v1");
350 final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
351 assertEquals(source, result);
353 // Only offsets should be shared
354 assertSame(source.offsets(), result.offsets());
355 assertNotSame(source.objects(), result.objects());
357 // Iterator order needs to be preserved
358 assertTrue(Iterators.elementsEqual(source.entrySet().iterator(), result.entrySet().iterator()));
362 public void testEmptyMutable() throws CloneNotSupportedException {
363 final MutableOffsetMap<String, String> map = MutableOffsetMap.ordered();
364 assertTrue(map.isEmpty());
366 final Map<String, String> other = map.clone();
367 assertEquals(other, map);
368 assertNotSame(other, map);
372 public void testMutableToEmpty() {
373 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
375 mutable.remove("k1");
376 mutable.remove("k2");
378 assertTrue(mutable.isEmpty());
379 assertSame(ImmutableMap.of(), mutable.toUnmodifiableMap());
383 public void testMutableToSingleton() {
384 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
386 mutable.remove("k1");
388 final Map<String, String> result = mutable.toUnmodifiableMap();
390 // Should devolve to a singleton
391 assertTrue(result instanceof SharedSingletonMap);
392 assertEquals(ImmutableMap.of("k2", "v2"), result);
396 public void testMutableToNewSingleton() {
397 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
399 mutable.remove("k1");
400 mutable.put("k3", "v3");
402 final Map<String, String> result = mutable.toUnmodifiableMap();
404 assertTrue(result instanceof ImmutableOffsetMap);
405 assertEquals(ImmutableMap.of("k2", "v2", "k3", "v3"), result);
409 public void testMutableSize() {
410 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
411 assertEquals(2, mutable.size());
413 mutable.put("k3", "v3");
414 assertEquals(3, mutable.size());
415 mutable.remove("k2");
416 assertEquals(2, mutable.size());
417 mutable.put("k1", "new-v1");
418 assertEquals(2, mutable.size());
422 public void testExpansionWithOrder() {
423 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
425 mutable.remove("k1");
426 mutable.put("k3", "v3");
427 mutable.put("k1", "v1");
429 assertEquals(ImmutableMap.of("k1", "v1", "k3", "v3"), mutable.newKeys());
431 final Map<String, String> result = mutable.toUnmodifiableMap();
433 assertTrue(result instanceof ImmutableOffsetMap);
434 assertEquals(threeEntryMap, result);
435 assertEquals(result, threeEntryMap);
436 assertFalse(Iterators.elementsEqual(threeEntryMap.entrySet().iterator(), result.entrySet().iterator()));
440 public void testExpansionWithoutOrder() {
441 final MutableOffsetMap<String, String> mutable = unorderedMap().toModifiableMap();
443 mutable.remove("k1");
444 mutable.put("k3", "v3");
445 mutable.put("k1", "v1");
447 assertEquals(ImmutableMap.of("k3", "v3"), mutable.newKeys());
449 final Map<String, String> result = mutable.toUnmodifiableMap();
451 assertTrue(result instanceof ImmutableOffsetMap);
452 assertEquals(threeEntryMap, result);
453 assertEquals(result, threeEntryMap);
454 assertTrue(Iterators.elementsEqual(threeEntryMap.entrySet().iterator(), result.entrySet().iterator()));
458 public void testReplacedValue() {
459 final ImmutableOffsetMap<String, String> source = createMap();
460 final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
462 mutable.put("k1", "replaced");
464 final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
465 final Map<String, String> reference = ImmutableMap.of("k1", "replaced", "k2", "v2");
467 assertEquals(reference, result);
468 assertEquals(result, reference);
469 assertSame(source.offsets(), result.offsets());
470 assertNotSame(source.objects(), result.objects());
474 public void testCloneableFlipping() throws CloneNotSupportedException {
475 final MutableOffsetMap<String, String> source = createMap().toModifiableMap();
477 // Must clone before mutation
478 assertTrue(source.needClone());
480 // Non-existent entry, should not clone
481 source.remove("non-existent");
482 assertTrue(source.needClone());
484 // Changes the array, should clone
486 assertFalse(source.needClone());
488 // Create a clone of the map, which shares the array
489 final MutableOffsetMap<String, String> result = source.clone();
490 assertFalse(source.needClone());
491 assertTrue(result.needClone());
492 assertSame(source.array(), result.array());
494 // Changes the array, should clone
495 source.put("k1", "v2");
496 assertFalse(source.needClone());
497 assertTrue(result.needClone());
499 // Forced copy, no cloning needed, but maps are equal
500 final ImmutableOffsetMap<String, String> immutable = (ImmutableOffsetMap<String, String>) source.toUnmodifiableMap();
501 assertFalse(source.needClone());
502 assertTrue(source.equals(immutable));
503 assertTrue(immutable.equals(source));
504 assertTrue(Iterables.elementsEqual(source.entrySet(), immutable.entrySet()));
508 public void testCloneableFlippingUnordered() throws CloneNotSupportedException {
509 final MutableOffsetMap<String, String> source = unorderedMap().toModifiableMap();
511 // Must clone before mutation
512 assertTrue(source.needClone());
514 // Non-existent entry, should not clone
515 source.remove("non-existent");
516 assertTrue(source.needClone());
518 // Changes the array, should clone
520 assertFalse(source.needClone());
522 // Create a clone of the map, which shares the array
523 final MutableOffsetMap<String, String> result = source.clone();
524 assertFalse(source.needClone());
525 assertTrue(result.needClone());
526 assertSame(source.array(), result.array());
528 // Changes the array, should clone
529 source.put("k1", "v2");
530 assertFalse(source.needClone());
531 assertTrue(result.needClone());
533 // Creates a immutable view, which shares the array
534 final ImmutableOffsetMap<String, String> immutable = (ImmutableOffsetMap<String, String>) source.toUnmodifiableMap();
535 assertTrue(source.needClone());
536 assertSame(source.array(), immutable.objects());
540 public void testMutableEntrySet() {
541 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
543 assertTrue(map.entrySet().add(new SimpleEntry<>("k3", "v3")));
544 assertTrue(map.containsKey("k3"));
545 assertEquals("v3", map.get("k3"));
547 // null is not an Entry: ignore
548 assertFalse(map.entrySet().remove(null));
550 // non-matching value: ignore
551 assertFalse(map.entrySet().remove(new SimpleEntry<>("k1", "other")));
552 assertTrue(map.containsKey("k1"));
554 // ignore null values
555 assertFalse(map.entrySet().remove(new SimpleEntry<>("k1", null)));
556 assertTrue(map.containsKey("k1"));
558 assertTrue(map.entrySet().remove(new SimpleEntry<>("k1", "v1")));
559 assertFalse(map.containsKey("k1"));
562 private static void assertIteratorBroken(final Iterator<?> it) {
566 } catch (ConcurrentModificationException e) {
571 } catch (ConcurrentModificationException e) {
576 } catch (ConcurrentModificationException e) {
581 public void testMutableSimpleEquals() {
582 final ImmutableOffsetMap<String, String> source = createMap();
583 final Map<String, String> map = source.toModifiableMap();
585 assertTrue(map.equals(map));
586 assertFalse(map.equals(null));
587 assertFalse(map.equals("string"));
588 assertTrue(map.equals(source));
592 public void testMutableSimpleHashCode() {
593 final Map<String, String> map = createMap().toModifiableMap();
595 assertEquals(twoEntryMap.hashCode(), map.hashCode());
599 public void testMutableIteratorBasics() {
600 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
601 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
603 // Not advanced, remove should fail
607 } catch (IllegalStateException e) {
610 assertTrue(it.hasNext());
611 assertEquals("k1", it.next().getKey());
612 assertTrue(it.hasNext());
613 assertEquals("k2", it.next().getKey());
614 assertFalse(it.hasNext());
616 // Check end-of-iteration throw
620 } catch (NoSuchElementException e) {
625 public void testMutableIteratorWithRemove() {
626 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
627 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
629 // Advance one element
630 assertTrue(it.hasNext());
631 assertEquals("k1", it.next().getKey());
635 assertEquals(1, map.size());
636 assertFalse(map.containsKey("k1"));
638 // Iterator should still work
639 assertTrue(it.hasNext());
640 assertEquals("k2", it.next().getKey());
641 assertFalse(it.hasNext());
645 public void testMutableIteratorOffsetReplaceWorks() {
646 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
647 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
650 map.put("k1", "new-v1");
651 assertTrue(it.hasNext());
655 public void testMutableIteratorNewReplaceWorks() {
656 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
658 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
661 map.put("k3", "new-v3");
662 assertTrue(it.hasNext());
666 public void testMutableIteratorOffsetAddBreaks() {
667 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
671 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
674 map.put("k1", "new-v1");
675 assertIteratorBroken(it);
679 public void testMutableIteratorNewAddBreaks() {
680 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
681 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
685 assertIteratorBroken(it);
689 public void testMutableIteratorOffsetRemoveBreaks() {
690 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
691 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
695 assertIteratorBroken(it);
699 public void testMutableIteratorNewRemoveBreaks() {
700 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
702 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
706 assertIteratorBroken(it);
710 public void testMutableCrossIteratorRemove() {
711 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
712 final Set<Entry<String, String>> es = map.entrySet();
713 final Iterator<Entry<String, String>> it1 = es.iterator();
714 final Iterator<Entry<String, String>> it2 = es.iterator();
720 assertEquals(1, map.size());
722 // Check it2 was broken
723 assertIteratorBroken(it2);
727 public void testImmutableSerialization() throws IOException, ClassNotFoundException {
728 final Map<String, String> source = createMap();
730 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
731 try (final ObjectOutputStream oos = new ObjectOutputStream(bos)) {
732 oos.writeObject(source);
735 final ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
736 @SuppressWarnings("unchecked")
737 final Map<String, String> result = (Map<String, String>) ois.readObject();
739 assertEquals(source, result);