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.Iterators;
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.ObjectInputStream;
23 import java.io.ObjectOutputStream;
24 import java.util.AbstractMap.SimpleEntry;
25 import java.util.Collections;
26 import java.util.ConcurrentModificationException;
27 import java.util.Iterator;
29 import java.util.Map.Entry;
30 import java.util.NoSuchElementException;
32 import org.junit.Test;
34 public class OffsetMapTest {
35 private final Map<String, String> twoEntryMap = ImmutableMap.of("k1", "v1", "k2", "v2");
36 private final Map<String, String> threeEntryMap = ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3");
38 private ImmutableOffsetMap<String, String> createMap() {
39 return (ImmutableOffsetMap<String, String>) ImmutableOffsetMap.copyOf(twoEntryMap);
42 @Test(expected=IllegalArgumentException.class)
43 public void testWrongImmutableConstruction() {
44 new ImmutableOffsetMap.Ordered<String, String>(Collections.<String, Integer>emptyMap(), new String[1]);
48 public void testCopyEmptyMap() {
49 final Map<String, String> source = Collections.emptyMap();
50 final Map<String, String> result = ImmutableOffsetMap.copyOf(source);
52 assertEquals(source, result);
53 assertTrue(result instanceof ImmutableMap);
57 public void testCopySingletonMap() {
58 final Map<String, String> source = Collections.singletonMap("a", "b");
59 final Map<String, String> result = ImmutableOffsetMap.copyOf(source);
61 assertEquals(source, result);
62 assertTrue(result instanceof SharedSingletonMap);
66 public void testCopyMap() {
67 final ImmutableOffsetMap<String, String> map = createMap();
69 // Equality in both directions
70 assertEquals(twoEntryMap, map);
71 assertEquals(map, twoEntryMap);
73 // hashcode has to match
74 assertEquals(twoEntryMap.hashCode(), map.hashCode());
76 // Iterator order needs to be preserved
77 assertTrue(Iterators.elementsEqual(twoEntryMap.entrySet().iterator(), map.entrySet().iterator()));
79 // Should result in the same object
80 assertSame(map, ImmutableOffsetMap.copyOf(map));
82 final Map<String, String> mutable = map.toModifiableMap();
83 final Map<String, String> copy = ImmutableOffsetMap.copyOf(mutable);
85 assertEquals(mutable, copy);
86 assertEquals(map, copy);
87 assertNotSame(mutable, copy);
88 assertNotSame(map, copy);
92 public void testImmutableSimpleEquals() {
93 final Map<String, String> map = createMap();
95 assertTrue(map.equals(map));
96 assertFalse(map.equals(null));
97 assertFalse(map.equals("string"));
101 public void testImmutableGet() {
102 final Map<String, String> map = createMap();
104 assertEquals("v1", map.get("k1"));
105 assertEquals("v2", map.get("k2"));
106 assertNull(map.get("non-existent"));
107 assertNull(map.get(null));
111 public void testImmutableGuards() {
112 final Map<String, String> map = createMap();
115 map.values().add("v1");
117 } catch (UnsupportedOperationException e) {
121 map.values().remove("v1");
123 } catch (UnsupportedOperationException e) {
127 map.values().clear();
129 } catch (UnsupportedOperationException e) {
133 final Iterator<String> it = map.values().iterator();
137 } catch (UnsupportedOperationException e) {
141 map.keySet().add("k1");
143 } catch (UnsupportedOperationException e) {
147 map.keySet().clear();
149 } catch (UnsupportedOperationException e) {
153 map.keySet().remove("k1");
155 } catch (UnsupportedOperationException e) {
159 final Iterator<String> it = map.keySet().iterator();
163 } catch (UnsupportedOperationException e) {
167 map.entrySet().clear();
169 } catch (UnsupportedOperationException e) {
173 map.entrySet().add(new SimpleEntry<>("k1", "v1"));
175 } catch (UnsupportedOperationException e) {
179 map.entrySet().remove(new SimpleEntry<>("k1", "v1"));
181 } catch (UnsupportedOperationException e) {
185 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
189 } catch (UnsupportedOperationException e) {
195 } catch (UnsupportedOperationException e) {
199 map.put("k1", "fail");
201 } catch (UnsupportedOperationException e) {
205 map.putAll(ImmutableMap.of("k1", "fail"));
207 } catch (UnsupportedOperationException e) {
213 } catch (UnsupportedOperationException e) {
218 public void testMutableGet() {
219 final Map<String, String> map = createMap().toModifiableMap();
222 assertEquals("v1", map.get("k1"));
223 assertEquals("v2", map.get("k2"));
224 assertEquals("v3", map.get("k3"));
225 assertNull(map.get("non-existent"));
226 assertNull(map.get(null));
230 public void testImmutableSize() {
231 final Map<String, String> map = createMap();
232 assertEquals(2, map.size());
236 public void testImmutableIsEmpty() {
237 final Map<String, String> map = createMap();
238 assertFalse(map.isEmpty());
242 public void testImmutableContains() {
243 final Map<String, String> map = createMap();
244 assertTrue(map.containsKey("k1"));
245 assertTrue(map.containsKey("k2"));
246 assertFalse(map.containsKey("non-existent"));
247 assertFalse(map.containsKey(null));
248 assertTrue(map.containsValue("v1"));
249 assertFalse(map.containsValue("non-existent"));
253 public void testImmutableEquals() {
254 final Map<String, String> map = createMap();
256 assertFalse(map.equals(threeEntryMap));
257 assertFalse(map.equals(ImmutableMap.of("k1", "v1", "k3", "v3")));
258 assertFalse(map.equals(ImmutableMap.of("k1", "v1", "k2", "different-value")));
262 public void testMutableContains() {
263 final Map<String, String> map = createMap().toModifiableMap();
265 assertTrue(map.containsKey("k1"));
266 assertTrue(map.containsKey("k2"));
267 assertTrue(map.containsKey("k3"));
268 assertFalse(map.containsKey("non-existent"));
269 assertFalse(map.containsKey(null));
273 public void testtoModifiableMap() {
274 final ImmutableOffsetMap<String, String> source = createMap();
275 final Map<String, String> result = source.toModifiableMap();
277 // The two maps should be equal, but isolated
278 assertTrue(result instanceof MutableOffsetMap);
279 assertEquals(source, result);
280 assertEquals(result, source);
282 // Quick test for clearing MutableOffsetMap
284 assertEquals(0, result.size());
285 assertEquals(Collections.emptyMap(), result);
287 // The two maps should differ now
288 assertFalse(source.equals(result));
289 assertFalse(result.equals(source));
291 // The source map should still equal the template
292 assertEquals(twoEntryMap, source);
293 assertEquals(source, twoEntryMap);
297 public void testReusedFields() {
298 final ImmutableOffsetMap<String, String> source = createMap();
299 final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
301 // Should not affect the result
302 mutable.remove("non-existent");
304 // Resulting map should be equal, but not the same object
305 final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
306 assertNotSame(source, result);
307 assertEquals(source, result);
309 // Internal fields should be reused
310 assertSame(source.offsets(), result.offsets());
311 assertSame(source.objects(), result.objects());
315 public void testReusedOffsets() {
316 final ImmutableOffsetMap<String, String> source = createMap();
317 final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
319 mutable.remove("k1");
320 mutable.put("k1", "v1");
322 final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
323 assertEquals(source, result);
325 // Only offsets should be shared
326 assertSame(source.offsets(), result.offsets());
327 assertNotSame(source.objects(), result.objects());
329 // Iterator order needs to be preserved
330 assertTrue(Iterators.elementsEqual(source.entrySet().iterator(), result.entrySet().iterator()));
334 public void testEmptyMutable() throws CloneNotSupportedException {
335 final MutableOffsetMap<String, String> map = MutableOffsetMap.of();
336 assertTrue(map.isEmpty());
338 final Map<String, String> other = map.clone();
339 assertEquals(other, map);
340 assertNotSame(other, map);
344 public void testMutableToEmpty() {
345 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
347 mutable.remove("k1");
348 mutable.remove("k2");
350 assertTrue(mutable.isEmpty());
351 assertSame(ImmutableMap.of(), mutable.toUnmodifiableMap());
355 public void testMutableToSingleton() {
356 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
358 mutable.remove("k1");
360 final Map<String, String> result = mutable.toUnmodifiableMap();
362 // Should devolve to a singleton
363 assertTrue(result instanceof ImmutableMap);
364 assertEquals(ImmutableMap.of("k2", "v2"), result);
368 public void testMutableToNewSingleton() {
369 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
371 mutable.remove("k1");
372 mutable.put("k3", "v3");
374 final Map<String, String> result = mutable.toUnmodifiableMap();
376 assertTrue(result instanceof ImmutableOffsetMap);
377 assertEquals(ImmutableMap.of("k2", "v2", "k3", "v3"), result);
381 public void testMutableSize() {
382 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
383 assertEquals(2, mutable.size());
385 mutable.put("k3", "v3");
386 assertEquals(3, mutable.size());
387 mutable.remove("k2");
388 assertEquals(2, mutable.size());
389 mutable.put("k1", "new-v1");
390 assertEquals(2, mutable.size());
394 public void testExpansionWithOrder() {
395 final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
397 mutable.remove("k1");
398 mutable.put("k3", "v3");
399 mutable.put("k1", "v1");
401 assertEquals(ImmutableMap.of("k3", "v3"), mutable.newKeys());
403 final Map<String, String> result = mutable.toUnmodifiableMap();
405 assertTrue(result instanceof ImmutableOffsetMap);
406 assertEquals(threeEntryMap, result);
407 assertEquals(result, threeEntryMap);
408 assertTrue(Iterators.elementsEqual(threeEntryMap.entrySet().iterator(), result.entrySet().iterator()));
412 public void testReplacedValue() {
413 final ImmutableOffsetMap<String, String> source = createMap();
414 final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
416 mutable.put("k1", "replaced");
418 final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
419 final Map<String, String> reference = ImmutableMap.of("k1", "replaced", "k2", "v2");
421 assertEquals(reference, result);
422 assertEquals(result, reference);
423 assertSame(source.offsets(), result.offsets());
424 assertNotSame(source.objects(), result.objects());
428 public void testCloneableFlipping() throws CloneNotSupportedException {
429 final MutableOffsetMap<String, String> source = createMap().toModifiableMap();
431 // Must clone before mutation
432 assertTrue(source.needClone());
434 // Non-existent entry, should not clone
435 source.remove("non-existent");
436 assertTrue(source.needClone());
438 // Changes the array, should clone
440 assertFalse(source.needClone());
442 // Create a clone of the map, which shares the array
443 final MutableOffsetMap<String, String> result = source.clone();
444 assertFalse(source.needClone());
445 assertTrue(result.needClone());
446 assertSame(source.array(), result.array());
448 // Changes the array, should clone
449 source.put("k1", "v2");
450 assertFalse(source.needClone());
451 assertTrue(result.needClone());
453 // Creates a immutable view, which shares the array
454 final ImmutableOffsetMap<String, String> immutable = (ImmutableOffsetMap<String, String>) source.toUnmodifiableMap();
455 assertTrue(source.needClone());
456 assertSame(source.array(), immutable.objects());
460 public void testMutableEntrySet() {
461 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
463 assertTrue(map.entrySet().add(new SimpleEntry<>("k3", "v3")));
464 assertTrue(map.containsKey("k3"));
465 assertEquals("v3", map.get("k3"));
467 // null is not an Entry: ignore
468 assertFalse(map.entrySet().remove(null));
470 // non-matching value: ignore
471 assertFalse(map.entrySet().remove(new SimpleEntry<>("k1", "other")));
472 assertTrue(map.containsKey("k1"));
474 // ignore null values
475 assertFalse(map.entrySet().remove(new SimpleEntry<>("k1", null)));
476 assertTrue(map.containsKey("k1"));
478 assertTrue(map.entrySet().remove(new SimpleEntry<>("k1", "v1")));
479 assertFalse(map.containsKey("k1"));
482 private static void assertIteratorBroken(final Iterator<?> it) {
486 } catch (ConcurrentModificationException e) {
491 } catch (ConcurrentModificationException e) {
496 } catch (ConcurrentModificationException e) {
501 public void testMutableSimpleEquals() {
502 final ImmutableOffsetMap<String, String> source = createMap();
503 final Map<String, String> map = source.toModifiableMap();
505 assertTrue(map.equals(map));
506 assertFalse(map.equals(null));
507 assertFalse(map.equals("string"));
508 assertTrue(map.equals(source));
512 public void testMutableSimpleHashCode() {
513 final Map<String, String> map = createMap().toModifiableMap();
515 assertEquals(twoEntryMap.hashCode(), map.hashCode());
519 public void testMutableIteratorBasics() {
520 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
521 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
523 // Not advanced, remove should fail
527 } catch (IllegalStateException e) {
530 assertTrue(it.hasNext());
531 assertEquals("k1", it.next().getKey());
532 assertTrue(it.hasNext());
533 assertEquals("k2", it.next().getKey());
534 assertFalse(it.hasNext());
536 // Check end-of-iteration throw
540 } catch (NoSuchElementException e) {
545 public void testMutableIteratorWithRemove() {
546 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
547 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
549 // Advance one element
550 assertTrue(it.hasNext());
551 assertEquals("k1", it.next().getKey());
555 assertEquals(1, map.size());
556 assertFalse(map.containsKey("k1"));
558 // Iterator should still work
559 assertTrue(it.hasNext());
560 assertEquals("k2", it.next().getKey());
561 assertFalse(it.hasNext());
565 public void testMutableIteratorOffsetReplaceWorks() {
566 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
567 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
570 map.put("k1", "new-v1");
571 assertTrue(it.hasNext());
575 public void testMutableIteratorNewReplaceWorks() {
576 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
578 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
581 map.put("k3", "new-v3");
582 assertTrue(it.hasNext());
586 public void testMutableIteratorOffsetAddBreaks() {
587 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
591 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
594 map.put("k1", "new-v1");
595 assertIteratorBroken(it);
599 public void testMutableIteratorNewAddBreaks() {
600 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
601 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
605 assertIteratorBroken(it);
609 public void testMutableIteratorOffsetRemoveBreaks() {
610 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
611 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
615 assertIteratorBroken(it);
619 public void testMutableIteratorNewRemoveBreaks() {
620 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
622 final Iterator<Entry<String, String>> it = map.entrySet().iterator();
626 assertIteratorBroken(it);
630 public void testMutableCrossIteratorRemove() {
631 final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
632 final Set<Entry<String, String>> es = map.entrySet();
633 final Iterator<Entry<String, String>> it1 = es.iterator();
634 final Iterator<Entry<String, String>> it2 = es.iterator();
640 assertEquals(1, map.size());
642 // Check it2 was broken
643 assertIteratorBroken(it2);
647 public void testImmutableSerialization() throws IOException, ClassNotFoundException {
648 final Map<String, String> source = createMap();
650 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
651 try (final ObjectOutputStream oos = new ObjectOutputStream(bos)) {
652 oos.writeObject(source);
655 final ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
656 @SuppressWarnings("unchecked")
657 final Map<String, String> result = (Map<String, String>) ois.readObject();
659 assertEquals(source, result);