Organize Imports to be Checkstyle compliant in utils
[yangtools.git] / common / util / src / test / java / org / opendaylight / yangtools / util / OffsetMapTest.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.util;
9
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
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;
30 import java.util.Map;
31 import java.util.Map.Entry;
32 import java.util.NoSuchElementException;
33 import java.util.Set;
34 import org.junit.Before;
35 import org.junit.Test;
36
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");
40
41     private ImmutableOffsetMap<String, String> createMap() {
42         return (ImmutableOffsetMap<String, String>) ImmutableOffsetMap.orderedCopyOf(twoEntryMap);
43     }
44
45     private ImmutableOffsetMap<String, String> unorderedMap() {
46         return (ImmutableOffsetMap<String, String>) ImmutableOffsetMap.unorderedCopyOf(twoEntryMap);
47     }
48
49     @Before
50     public void setup() {
51         OffsetMapCache.invalidateCache();
52     }
53
54     @Test(expected=IllegalArgumentException.class)
55     public void testWrongImmutableConstruction() {
56         new ImmutableOffsetMap.Ordered<>(Collections.<String, Integer>emptyMap(), new String[1]);
57     }
58
59     @Test
60     public void testCopyEmptyMap() {
61         final Map<String, String> source = Collections.emptyMap();
62         final Map<String, String> result = ImmutableOffsetMap.orderedCopyOf(source);
63
64         assertEquals(source, result);
65         assertTrue(result instanceof ImmutableMap);
66     }
67
68     @Test
69     public void testCopySingletonMap() {
70         final Map<String, String> source = Collections.singletonMap("a", "b");
71         final Map<String, String> result = ImmutableOffsetMap.orderedCopyOf(source);
72
73         assertEquals(source, result);
74         assertTrue(result instanceof SharedSingletonMap);
75     }
76
77     @Test
78     public void testCopyMap() {
79         final ImmutableOffsetMap<String, String> map = createMap();
80
81         // Equality in both directions
82         assertEquals(twoEntryMap, map);
83         assertEquals(map, twoEntryMap);
84
85         // hashcode has to match
86         assertEquals(twoEntryMap.hashCode(), map.hashCode());
87
88         // Iterator order needs to be preserved
89         assertTrue(Iterators.elementsEqual(twoEntryMap.entrySet().iterator(), map.entrySet().iterator()));
90
91         // Should result in the same object
92         assertSame(map, ImmutableOffsetMap.orderedCopyOf(map));
93
94         final Map<String, String> mutable = map.toModifiableMap();
95         final Map<String, String> copy = ImmutableOffsetMap.orderedCopyOf(mutable);
96
97         assertEquals(mutable, copy);
98         assertEquals(map, copy);
99         assertNotSame(mutable, copy);
100         assertNotSame(map, copy);
101     }
102
103     @Test
104     public void testImmutableSimpleEquals() {
105         final Map<String, String> map = createMap();
106
107         assertTrue(map.equals(map));
108         assertFalse(map.equals(null));
109         assertFalse(map.equals("string"));
110     }
111
112     @Test
113     public void testImmutableGet() {
114         final Map<String, String> map = createMap();
115
116         assertEquals("v1", map.get("k1"));
117         assertEquals("v2", map.get("k2"));
118         assertNull(map.get("non-existent"));
119         assertNull(map.get(null));
120     }
121
122     @Test
123     public void testImmutableGuards() {
124         final Map<String, String> map = createMap();
125
126         try {
127             map.values().add("v1");
128             fail();
129         } catch (UnsupportedOperationException e) {
130         }
131
132         try {
133             map.values().remove("v1");
134             fail();
135         } catch (UnsupportedOperationException e) {
136         }
137
138         try {
139             map.values().clear();
140             fail();
141         } catch (UnsupportedOperationException e) {
142         }
143
144         try {
145             final Iterator<String> it = map.values().iterator();
146             it.next();
147             it.remove();
148             fail();
149         } catch (UnsupportedOperationException e) {
150         }
151
152         try {
153             map.keySet().add("k1");
154             fail();
155         } catch (UnsupportedOperationException e) {
156         }
157
158         try {
159             map.keySet().clear();
160             fail();
161         } catch (UnsupportedOperationException e) {
162         }
163
164         try {
165             map.keySet().remove("k1");
166             fail();
167         } catch (UnsupportedOperationException e) {
168         }
169
170         try {
171             final Iterator<String> it = map.keySet().iterator();
172             it.next();
173             it.remove();
174             fail();
175         } catch (UnsupportedOperationException e) {
176         }
177
178         try {
179             map.entrySet().clear();
180             fail();
181         } catch (UnsupportedOperationException e) {
182         }
183
184         try {
185             map.entrySet().add(new SimpleEntry<>("k1", "v1"));
186             fail();
187         } catch (UnsupportedOperationException e) {
188         }
189
190         try {
191             map.entrySet().remove(new SimpleEntry<>("k1", "v1"));
192             fail();
193         } catch (UnsupportedOperationException e) {
194         }
195
196         try {
197             final Iterator<Entry<String, String>> it = map.entrySet().iterator();
198             it.next();
199             it.remove();
200             fail();
201         } catch (UnsupportedOperationException e) {
202         }
203
204         try {
205             map.clear();
206             fail();
207         } catch (UnsupportedOperationException e) {
208         }
209
210         try {
211             map.put("k1", "fail");
212             fail();
213         } catch (UnsupportedOperationException e) {
214         }
215
216         try {
217             map.putAll(ImmutableMap.of("k1", "fail"));
218             fail();
219         } catch (UnsupportedOperationException e) {
220         }
221
222         try {
223             map.remove("k1");
224             fail();
225         } catch (UnsupportedOperationException e) {
226         }
227     }
228
229     @Test
230     public void testMutableGet() {
231         final Map<String, String> map = createMap().toModifiableMap();
232
233         map.put("k3", "v3");
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));
239     }
240
241     @Test
242     public void testImmutableSize() {
243         final Map<String, String> map = createMap();
244         assertEquals(2, map.size());
245     }
246
247     @Test
248     public void testImmutableIsEmpty() {
249         final Map<String, String> map = createMap();
250         assertFalse(map.isEmpty());
251     }
252
253     @Test
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"));
262     }
263
264     @Test
265     public void testImmutableEquals() {
266         final Map<String, String> map = createMap();
267
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")));
271     }
272
273     @Test
274     public void testMutableContains() {
275         final Map<String, String> map = createMap().toModifiableMap();
276         map.put("k3", "v3");
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));
282     }
283
284     @Test
285     public void testtoModifiableMap() {
286         final ImmutableOffsetMap<String, String> source = createMap();
287         final Map<String, String> result = source.toModifiableMap();
288
289         // The two maps should be equal, but isolated
290         assertTrue(result instanceof MutableOffsetMap);
291         assertEquals(source, result);
292         assertEquals(result, source);
293
294         // Quick test for clearing MutableOffsetMap
295         result.clear();
296         assertEquals(0, result.size());
297         assertEquals(Collections.emptyMap(), result);
298
299         // The two maps should differ now
300         assertFalse(source.equals(result));
301         assertFalse(result.equals(source));
302
303         // The source map should still equal the template
304         assertEquals(twoEntryMap, source);
305         assertEquals(source, twoEntryMap);
306     }
307
308     @Test
309     public void testReusedFields() {
310         final ImmutableOffsetMap<String, String> source = createMap();
311         final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
312
313         // Should not affect the result
314         mutable.remove("non-existent");
315
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);
320
321         // Internal fields should be reused
322         assertSame(source.offsets(), result.offsets());
323         assertSame(source.objects(), result.objects());
324     }
325
326     @Test
327     public void testReusedOffsets() {
328         final ImmutableOffsetMap<String, String> source = createMap();
329         final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
330
331         mutable.remove("k1");
332         mutable.put("k1", "v1");
333
334         final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
335         assertTrue(source.equals(result));
336         assertTrue(result.equals(source));
337
338         // Iterator order must not be preserved
339         assertFalse(Iterators.elementsEqual(source.entrySet().iterator(), result.entrySet().iterator()));
340     }
341
342     @Test
343     public void testReusedOffsetsUnordered() {
344         final ImmutableOffsetMap<String, String> source = unorderedMap();
345         final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
346
347         mutable.remove("k1");
348         mutable.put("k1", "v1");
349
350         final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
351         assertEquals(source, result);
352
353         // Only offsets should be shared
354         assertSame(source.offsets(), result.offsets());
355         assertNotSame(source.objects(), result.objects());
356
357         // Iterator order needs to be preserved
358         assertTrue(Iterators.elementsEqual(source.entrySet().iterator(), result.entrySet().iterator()));
359     }
360
361     @Test
362     public void testEmptyMutable() throws CloneNotSupportedException {
363         final MutableOffsetMap<String, String> map = MutableOffsetMap.ordered();
364         assertTrue(map.isEmpty());
365
366         final Map<String, String> other = map.clone();
367         assertEquals(other, map);
368         assertNotSame(other, map);
369     }
370
371     @Test
372     public void testMutableToEmpty() {
373         final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
374
375         mutable.remove("k1");
376         mutable.remove("k2");
377
378         assertTrue(mutable.isEmpty());
379         assertSame(ImmutableMap.of(), mutable.toUnmodifiableMap());
380     }
381
382     @Test
383     public void testMutableToSingleton() {
384         final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
385
386         mutable.remove("k1");
387
388         final Map<String, String> result = mutable.toUnmodifiableMap();
389
390         // Should devolve to a singleton
391         assertTrue(result instanceof SharedSingletonMap);
392         assertEquals(ImmutableMap.of("k2", "v2"), result);
393     }
394
395     @Test
396     public void testMutableToNewSingleton() {
397         final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
398
399         mutable.remove("k1");
400         mutable.put("k3", "v3");
401
402         final Map<String, String> result = mutable.toUnmodifiableMap();
403
404         assertTrue(result instanceof ImmutableOffsetMap);
405         assertEquals(ImmutableMap.of("k2", "v2", "k3", "v3"), result);
406     }
407
408     @Test
409     public void testMutableSize() {
410         final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
411         assertEquals(2, mutable.size());
412
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());
419     }
420
421     @Test
422     public void testExpansionWithOrder() {
423         final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
424
425         mutable.remove("k1");
426         mutable.put("k3", "v3");
427         mutable.put("k1", "v1");
428
429         assertEquals(ImmutableMap.of("k1", "v1", "k3", "v3"), mutable.newKeys());
430
431         final Map<String, String> result = mutable.toUnmodifiableMap();
432
433         assertTrue(result instanceof ImmutableOffsetMap);
434         assertEquals(threeEntryMap, result);
435         assertEquals(result, threeEntryMap);
436         assertFalse(Iterators.elementsEqual(threeEntryMap.entrySet().iterator(), result.entrySet().iterator()));
437     }
438
439     @Test
440     public void testExpansionWithoutOrder() {
441         final MutableOffsetMap<String, String> mutable = unorderedMap().toModifiableMap();
442
443         mutable.remove("k1");
444         mutable.put("k3", "v3");
445         mutable.put("k1", "v1");
446
447         assertEquals(ImmutableMap.of("k3", "v3"), mutable.newKeys());
448
449         final Map<String, String> result = mutable.toUnmodifiableMap();
450
451         assertTrue(result instanceof ImmutableOffsetMap);
452         assertEquals(threeEntryMap, result);
453         assertEquals(result, threeEntryMap);
454         assertTrue(Iterators.elementsEqual(threeEntryMap.entrySet().iterator(), result.entrySet().iterator()));
455     }
456
457     @Test
458     public void testReplacedValue() {
459         final ImmutableOffsetMap<String, String> source = createMap();
460         final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
461
462         mutable.put("k1", "replaced");
463
464         final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
465         final Map<String, String> reference = ImmutableMap.of("k1", "replaced", "k2", "v2");
466
467         assertEquals(reference, result);
468         assertEquals(result, reference);
469         assertSame(source.offsets(), result.offsets());
470         assertNotSame(source.objects(), result.objects());
471     }
472
473     @Test
474     public void testCloneableFlipping() throws CloneNotSupportedException {
475         final MutableOffsetMap<String, String> source = createMap().toModifiableMap();
476
477         // Must clone before mutation
478         assertTrue(source.needClone());
479
480         // Non-existent entry, should not clone
481         source.remove("non-existent");
482         assertTrue(source.needClone());
483
484         // Changes the array, should clone
485         source.remove("k1");
486         assertFalse(source.needClone());
487
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());
493
494         // Changes the array, should clone
495         source.put("k1", "v2");
496         assertFalse(source.needClone());
497         assertTrue(result.needClone());
498
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()));
505     }
506
507     @Test
508     public void testCloneableFlippingUnordered() throws CloneNotSupportedException {
509         final MutableOffsetMap<String, String> source = unorderedMap().toModifiableMap();
510
511         // Must clone before mutation
512         assertTrue(source.needClone());
513
514         // Non-existent entry, should not clone
515         source.remove("non-existent");
516         assertTrue(source.needClone());
517
518         // Changes the array, should clone
519         source.remove("k1");
520         assertFalse(source.needClone());
521
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());
527
528         // Changes the array, should clone
529         source.put("k1", "v2");
530         assertFalse(source.needClone());
531         assertTrue(result.needClone());
532
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());
537     }
538
539     @Test
540     public void testMutableEntrySet() {
541         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
542
543         assertTrue(map.entrySet().add(new SimpleEntry<>("k3", "v3")));
544         assertTrue(map.containsKey("k3"));
545         assertEquals("v3", map.get("k3"));
546
547         // null is not an Entry: ignore
548         assertFalse(map.entrySet().remove(null));
549
550         // non-matching value: ignore
551         assertFalse(map.entrySet().remove(new SimpleEntry<>("k1", "other")));
552         assertTrue(map.containsKey("k1"));
553
554         // ignore null values
555         assertFalse(map.entrySet().remove(new SimpleEntry<>("k1", null)));
556         assertTrue(map.containsKey("k1"));
557
558         assertTrue(map.entrySet().remove(new SimpleEntry<>("k1", "v1")));
559         assertFalse(map.containsKey("k1"));
560     }
561
562     private static void assertIteratorBroken(final Iterator<?> it) {
563         try {
564             it.hasNext();
565             fail();
566         } catch (ConcurrentModificationException e) {
567         }
568         try {
569             it.next();
570             fail();
571         } catch (ConcurrentModificationException e) {
572         }
573         try {
574             it.remove();
575             fail();
576         } catch (ConcurrentModificationException e) {
577         }
578     }
579
580     @Test
581     public void testMutableSimpleEquals() {
582         final ImmutableOffsetMap<String, String> source = createMap();
583         final Map<String, String> map = source.toModifiableMap();
584
585         assertTrue(map.equals(map));
586         assertFalse(map.equals(null));
587         assertFalse(map.equals("string"));
588         assertTrue(map.equals(source));
589     }
590
591     @Test
592     public void testMutableSimpleHashCode() {
593         final Map<String, String> map = createMap().toModifiableMap();
594
595         assertEquals(twoEntryMap.hashCode(), map.hashCode());
596     }
597
598     @Test
599     public void testMutableIteratorBasics() {
600         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
601         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
602
603         // Not advanced, remove should fail
604         try {
605             it.remove();
606             fail();
607         } catch (IllegalStateException e) {
608         }
609
610         assertTrue(it.hasNext());
611         assertEquals("k1", it.next().getKey());
612         assertTrue(it.hasNext());
613         assertEquals("k2", it.next().getKey());
614         assertFalse(it.hasNext());
615
616         // Check end-of-iteration throw
617         try {
618             it.next();
619             fail();
620         } catch (NoSuchElementException e) {
621         }
622     }
623
624     @Test
625     public void testMutableIteratorWithRemove() {
626         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
627         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
628
629         // Advance one element
630         assertTrue(it.hasNext());
631         assertEquals("k1", it.next().getKey());
632
633         // Remove k1
634         it.remove();
635         assertEquals(1, map.size());
636         assertFalse(map.containsKey("k1"));
637
638         // Iterator should still work
639         assertTrue(it.hasNext());
640         assertEquals("k2", it.next().getKey());
641         assertFalse(it.hasNext());
642     }
643
644     @Test
645     public void testMutableIteratorOffsetReplaceWorks() {
646         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
647         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
648         it.next();
649
650         map.put("k1", "new-v1");
651         assertTrue(it.hasNext());
652     }
653
654     @Test
655     public void testMutableIteratorNewReplaceWorks() {
656         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
657         map.put("k3", "v3");
658         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
659         it.next();
660
661         map.put("k3", "new-v3");
662         assertTrue(it.hasNext());
663     }
664
665     @Test
666     public void testMutableIteratorOffsetAddBreaks() {
667         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
668         map.put("k3", "v3");
669         map.remove("k1");
670
671         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
672         it.next();
673
674         map.put("k1", "new-v1");
675         assertIteratorBroken(it);
676     }
677
678     @Test
679     public void testMutableIteratorNewAddBreaks() {
680         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
681         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
682         it.next();
683
684         map.put("k3", "v3");
685         assertIteratorBroken(it);
686     }
687
688     @Test
689     public void testMutableIteratorOffsetRemoveBreaks() {
690         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
691         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
692         it.next();
693
694         map.remove("k1");
695         assertIteratorBroken(it);
696     }
697
698     @Test
699     public void testMutableIteratorNewRemoveBreaks() {
700         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
701         map.put("k3", "v3");
702         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
703         it.next();
704
705         map.remove("k3");
706         assertIteratorBroken(it);
707     }
708
709     @Test
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();
715
716         // Remove k1 via it1
717         it1.next();
718         it2.next();
719         it1.remove();
720         assertEquals(1, map.size());
721
722         // Check it2 was broken
723         assertIteratorBroken(it2);
724     }
725
726     @Test
727     public void testImmutableSerialization() throws IOException, ClassNotFoundException {
728         final Map<String, String> source = createMap();
729
730         final ByteArrayOutputStream bos = new ByteArrayOutputStream();
731         try (final ObjectOutputStream oos = new ObjectOutputStream(bos)) {
732             oos.writeObject(source);
733         }
734
735         final ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
736         @SuppressWarnings("unchecked")
737         final Map<String, String> result = (Map<String, String>) ois.readObject();
738
739         assertEquals(source, result);
740     }
741 }