Add ImmutableMapTemplate
[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<>(ImmutableMap.of(), 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             // OK
131         }
132
133         try {
134             map.values().remove("v1");
135             fail();
136         } catch (UnsupportedOperationException e) {
137             // OK
138         }
139
140         try {
141             map.values().clear();
142             fail();
143         } catch (UnsupportedOperationException e) {
144             // OK
145         }
146
147         try {
148             final Iterator<String> it = map.values().iterator();
149             it.next();
150             it.remove();
151             fail();
152         } catch (UnsupportedOperationException e) {
153             // OK
154         }
155
156         try {
157             map.keySet().add("k1");
158             fail();
159         } catch (UnsupportedOperationException e) {
160             // OK
161         }
162
163         try {
164             map.keySet().clear();
165             fail();
166         } catch (UnsupportedOperationException e) {
167             // OK
168         }
169
170         try {
171             map.keySet().remove("k1");
172             fail();
173         } catch (UnsupportedOperationException e) {
174             // OK
175         }
176
177         try {
178             final Iterator<String> it = map.keySet().iterator();
179             it.next();
180             it.remove();
181             fail();
182         } catch (UnsupportedOperationException e) {
183             // OK
184         }
185
186         try {
187             map.entrySet().clear();
188             fail();
189         } catch (UnsupportedOperationException e) {
190             // OK
191         }
192
193         try {
194             map.entrySet().add(new SimpleEntry<>("k1", "v1"));
195             fail();
196         } catch (UnsupportedOperationException e) {
197             // OK
198         }
199
200         try {
201             map.entrySet().remove(new SimpleEntry<>("k1", "v1"));
202             fail();
203         } catch (UnsupportedOperationException e) {
204             // OK
205         }
206
207         try {
208             final Iterator<Entry<String, String>> it = map.entrySet().iterator();
209             it.next();
210             it.remove();
211             fail();
212         } catch (UnsupportedOperationException e) {
213             // OK
214         }
215
216         try {
217             map.clear();
218             fail();
219         } catch (UnsupportedOperationException e) {
220             // OK
221         }
222
223         try {
224             map.put("k1", "fail");
225             fail();
226         } catch (UnsupportedOperationException e) {
227             // OK
228         }
229
230         try {
231             map.putAll(ImmutableMap.of("k1", "fail"));
232             fail();
233         } catch (UnsupportedOperationException e) {
234             // OK
235         }
236
237         try {
238             map.remove("k1");
239             fail();
240         } catch (UnsupportedOperationException e) {
241             // OK
242         }
243     }
244
245     @Test
246     public void testMutableGet() {
247         final Map<String, String> map = createMap().toModifiableMap();
248
249         map.put("k3", "v3");
250         assertEquals("v1", map.get("k1"));
251         assertEquals("v2", map.get("k2"));
252         assertEquals("v3", map.get("k3"));
253         assertNull(map.get("non-existent"));
254         assertNull(map.get(null));
255     }
256
257     @Test
258     public void testImmutableSize() {
259         final Map<String, String> map = createMap();
260         assertEquals(2, map.size());
261     }
262
263     @Test
264     public void testImmutableIsEmpty() {
265         final Map<String, String> map = createMap();
266         assertFalse(map.isEmpty());
267     }
268
269     @Test
270     public void testImmutableContains() {
271         final Map<String, String> map = createMap();
272         assertTrue(map.containsKey("k1"));
273         assertTrue(map.containsKey("k2"));
274         assertFalse(map.containsKey("non-existent"));
275         assertFalse(map.containsKey(null));
276         assertTrue(map.containsValue("v1"));
277         assertFalse(map.containsValue("non-existent"));
278     }
279
280     @Test
281     public void testImmutableEquals() {
282         final Map<String, String> map = createMap();
283
284         assertFalse(map.equals(threeEntryMap));
285         assertFalse(map.equals(ImmutableMap.of("k1", "v1", "k3", "v3")));
286         assertFalse(map.equals(ImmutableMap.of("k1", "v1", "k2", "different-value")));
287     }
288
289     @Test
290     public void testMutableContains() {
291         final Map<String, String> map = createMap().toModifiableMap();
292         map.put("k3", "v3");
293         assertTrue(map.containsKey("k1"));
294         assertTrue(map.containsKey("k2"));
295         assertTrue(map.containsKey("k3"));
296         assertFalse(map.containsKey("non-existent"));
297         assertFalse(map.containsKey(null));
298     }
299
300     @Test
301     public void testtoModifiableMap() {
302         final ImmutableOffsetMap<String, String> source = createMap();
303         final Map<String, String> result = source.toModifiableMap();
304
305         // The two maps should be equal, but isolated
306         assertTrue(result instanceof MutableOffsetMap);
307         assertEquals(source, result);
308         assertEquals(result, source);
309
310         // Quick test for clearing MutableOffsetMap
311         result.clear();
312         assertEquals(0, result.size());
313         assertEquals(Collections.emptyMap(), result);
314
315         // The two maps should differ now
316         assertFalse(source.equals(result));
317         assertFalse(result.equals(source));
318
319         // The source map should still equal the template
320         assertEquals(twoEntryMap, source);
321         assertEquals(source, twoEntryMap);
322     }
323
324     @Test
325     public void testReusedFields() {
326         final ImmutableOffsetMap<String, String> source = createMap();
327         final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
328
329         // Should not affect the result
330         mutable.remove("non-existent");
331
332         // Resulting map should be equal, but not the same object
333         final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable
334                 .toUnmodifiableMap();
335         assertNotSame(source, result);
336         assertEquals(source, result);
337
338         // Internal fields should be reused
339         assertSame(source.offsets(), result.offsets());
340         assertSame(source.objects(), result.objects());
341     }
342
343     @Test
344     public void testReusedOffsets() {
345         final ImmutableOffsetMap<String, String> source = createMap();
346         final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
347
348         mutable.remove("k1");
349         mutable.put("k1", "v1");
350
351         final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable
352                 .toUnmodifiableMap();
353         assertTrue(source.equals(result));
354         assertTrue(result.equals(source));
355
356         // Iterator order must not be preserved
357         assertFalse(Iterators.elementsEqual(source.entrySet().iterator(), result.entrySet().iterator()));
358     }
359
360     @Test
361     public void testReusedOffsetsUnordered() {
362         final ImmutableOffsetMap<String, String> source = unorderedMap();
363         final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
364
365         mutable.remove("k1");
366         mutable.put("k1", "v1");
367
368         final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable
369                 .toUnmodifiableMap();
370         assertEquals(source, result);
371
372         // Only offsets should be shared
373         assertSame(source.offsets(), result.offsets());
374         assertNotSame(source.objects(), result.objects());
375
376         // Iterator order needs to be preserved
377         assertTrue(Iterators.elementsEqual(source.entrySet().iterator(), result.entrySet().iterator()));
378     }
379
380     @Test
381     public void testEmptyMutable() throws CloneNotSupportedException {
382         final MutableOffsetMap<String, String> map = MutableOffsetMap.ordered();
383         assertTrue(map.isEmpty());
384
385         final Map<String, String> other = map.clone();
386         assertEquals(other, map);
387         assertNotSame(other, map);
388     }
389
390     @Test
391     public void testMutableToEmpty() {
392         final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
393
394         mutable.remove("k1");
395         mutable.remove("k2");
396
397         assertTrue(mutable.isEmpty());
398         assertSame(ImmutableMap.of(), mutable.toUnmodifiableMap());
399     }
400
401     @Test
402     public void testMutableToSingleton() {
403         final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
404
405         mutable.remove("k1");
406
407         final Map<String, String> result = mutable.toUnmodifiableMap();
408
409         // Should devolve to a singleton
410         assertTrue(result instanceof SharedSingletonMap);
411         assertEquals(ImmutableMap.of("k2", "v2"), result);
412     }
413
414     @Test
415     public void testMutableToNewSingleton() {
416         final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
417
418         mutable.remove("k1");
419         mutable.put("k3", "v3");
420
421         final Map<String, String> result = mutable.toUnmodifiableMap();
422
423         assertTrue(result instanceof ImmutableOffsetMap);
424         assertEquals(ImmutableMap.of("k2", "v2", "k3", "v3"), result);
425     }
426
427     @Test
428     public void testMutableSize() {
429         final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
430         assertEquals(2, mutable.size());
431
432         mutable.put("k3", "v3");
433         assertEquals(3, mutable.size());
434         mutable.remove("k2");
435         assertEquals(2, mutable.size());
436         mutable.put("k1", "new-v1");
437         assertEquals(2, mutable.size());
438     }
439
440     @Test
441     public void testExpansionWithOrder() {
442         final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
443
444         mutable.remove("k1");
445         mutable.put("k3", "v3");
446         mutable.put("k1", "v1");
447
448         assertEquals(ImmutableMap.of("k1", "v1", "k3", "v3"), mutable.newKeys());
449
450         final Map<String, String> result = mutable.toUnmodifiableMap();
451
452         assertTrue(result instanceof ImmutableOffsetMap);
453         assertEquals(threeEntryMap, result);
454         assertEquals(result, threeEntryMap);
455         assertFalse(Iterators.elementsEqual(threeEntryMap.entrySet().iterator(), result.entrySet().iterator()));
456     }
457
458     @Test
459     public void testExpansionWithoutOrder() {
460         final MutableOffsetMap<String, String> mutable = unorderedMap().toModifiableMap();
461
462         mutable.remove("k1");
463         mutable.put("k3", "v3");
464         mutable.put("k1", "v1");
465
466         assertEquals(ImmutableMap.of("k3", "v3"), mutable.newKeys());
467
468         final Map<String, String> result = mutable.toUnmodifiableMap();
469
470         assertTrue(result instanceof ImmutableOffsetMap);
471         assertEquals(threeEntryMap, result);
472         assertEquals(result, threeEntryMap);
473         assertTrue(Iterators.elementsEqual(threeEntryMap.entrySet().iterator(), result.entrySet().iterator()));
474     }
475
476     @Test
477     public void testReplacedValue() {
478         final ImmutableOffsetMap<String, String> source = createMap();
479         final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
480
481         mutable.put("k1", "replaced");
482
483         final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable
484                 .toUnmodifiableMap();
485         final Map<String, String> reference = ImmutableMap.of("k1", "replaced", "k2", "v2");
486
487         assertEquals(reference, result);
488         assertEquals(result, reference);
489         assertSame(source.offsets(), result.offsets());
490         assertNotSame(source.objects(), result.objects());
491     }
492
493     @Test
494     public void testCloneableFlipping() throws CloneNotSupportedException {
495         final MutableOffsetMap<String, String> source = createMap().toModifiableMap();
496
497         // Must clone before mutation
498         assertTrue(source.needClone());
499
500         // Non-existent entry, should not clone
501         source.remove("non-existent");
502         assertTrue(source.needClone());
503
504         // Changes the array, should clone
505         source.remove("k1");
506         assertFalse(source.needClone());
507
508         // Create a clone of the map, which shares the array
509         final MutableOffsetMap<String, String> result = source.clone();
510         assertFalse(source.needClone());
511         assertTrue(result.needClone());
512         assertSame(source.array(), result.array());
513
514         // Changes the array, should clone
515         source.put("k1", "v2");
516         assertFalse(source.needClone());
517         assertTrue(result.needClone());
518
519         // Forced copy, no cloning needed, but maps are equal
520         final ImmutableOffsetMap<String, String> immutable = (ImmutableOffsetMap<String, String>) source
521                 .toUnmodifiableMap();
522         assertFalse(source.needClone());
523         assertTrue(source.equals(immutable));
524         assertTrue(immutable.equals(source));
525         assertTrue(Iterables.elementsEqual(source.entrySet(), immutable.entrySet()));
526     }
527
528     @Test
529     public void testCloneableFlippingUnordered() throws CloneNotSupportedException {
530         final MutableOffsetMap<String, String> source = unorderedMap().toModifiableMap();
531
532         // Must clone before mutation
533         assertTrue(source.needClone());
534
535         // Non-existent entry, should not clone
536         source.remove("non-existent");
537         assertTrue(source.needClone());
538
539         // Changes the array, should clone
540         source.remove("k1");
541         assertFalse(source.needClone());
542
543         // Create a clone of the map, which shares the array
544         final MutableOffsetMap<String, String> result = source.clone();
545         assertFalse(source.needClone());
546         assertTrue(result.needClone());
547         assertSame(source.array(), result.array());
548
549         // Changes the array, should clone
550         source.put("k1", "v2");
551         assertFalse(source.needClone());
552         assertTrue(result.needClone());
553
554         // Creates a immutable view, which shares the array
555         final ImmutableOffsetMap<String, String> immutable = (ImmutableOffsetMap<String, String>) source
556                 .toUnmodifiableMap();
557         assertTrue(source.needClone());
558         assertSame(source.array(), immutable.objects());
559     }
560
561     @Test
562     public void testMutableEntrySet() {
563         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
564
565         assertTrue(map.entrySet().add(new SimpleEntry<>("k3", "v3")));
566         assertTrue(map.containsKey("k3"));
567         assertEquals("v3", map.get("k3"));
568
569         // null is not an Entry: ignore
570         assertFalse(map.entrySet().remove(null));
571
572         // non-matching value: ignore
573         assertFalse(map.entrySet().remove(new SimpleEntry<>("k1", "other")));
574         assertTrue(map.containsKey("k1"));
575
576         // ignore null values
577         assertFalse(map.entrySet().remove(new SimpleEntry<>("k1", null)));
578         assertTrue(map.containsKey("k1"));
579
580         assertTrue(map.entrySet().remove(new SimpleEntry<>("k1", "v1")));
581         assertFalse(map.containsKey("k1"));
582     }
583
584     private static void assertIteratorBroken(final Iterator<?> it) {
585         try {
586             it.hasNext();
587             fail();
588         } catch (ConcurrentModificationException e) {
589             // OK
590         }
591         try {
592             it.next();
593             fail();
594         } catch (ConcurrentModificationException e) {
595             // OK
596         }
597         try {
598             it.remove();
599             fail();
600         } catch (ConcurrentModificationException e) {
601             // OK
602         }
603     }
604
605     @Test
606     public void testMutableSimpleEquals() {
607         final ImmutableOffsetMap<String, String> source = createMap();
608         final Map<String, String> map = source.toModifiableMap();
609
610         assertTrue(map.equals(map));
611         assertFalse(map.equals(null));
612         assertFalse(map.equals("string"));
613         assertTrue(map.equals(source));
614     }
615
616     @Test
617     public void testMutableSimpleHashCode() {
618         final Map<String, String> map = createMap().toModifiableMap();
619
620         assertEquals(twoEntryMap.hashCode(), map.hashCode());
621     }
622
623     @Test
624     public void testMutableIteratorBasics() {
625         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
626         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
627
628         // Not advanced, remove should fail
629         try {
630             it.remove();
631             fail();
632         } catch (IllegalStateException e) {
633             // OK
634         }
635
636         assertTrue(it.hasNext());
637         assertEquals("k1", it.next().getKey());
638         assertTrue(it.hasNext());
639         assertEquals("k2", it.next().getKey());
640         assertFalse(it.hasNext());
641
642         // Check end-of-iteration throw
643         try {
644             it.next();
645             fail();
646         } catch (NoSuchElementException e) {
647             // OK
648         }
649     }
650
651     @Test
652     public void testMutableIteratorWithRemove() {
653         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
654         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
655
656         // Advance one element
657         assertTrue(it.hasNext());
658         assertEquals("k1", it.next().getKey());
659
660         // Remove k1
661         it.remove();
662         assertEquals(1, map.size());
663         assertFalse(map.containsKey("k1"));
664
665         // Iterator should still work
666         assertTrue(it.hasNext());
667         assertEquals("k2", it.next().getKey());
668         assertFalse(it.hasNext());
669     }
670
671     @Test
672     public void testMutableIteratorOffsetReplaceWorks() {
673         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
674         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
675         it.next();
676
677         map.put("k1", "new-v1");
678         assertTrue(it.hasNext());
679     }
680
681     @Test
682     public void testMutableIteratorNewReplaceWorks() {
683         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
684         map.put("k3", "v3");
685         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
686         it.next();
687
688         map.put("k3", "new-v3");
689         assertTrue(it.hasNext());
690     }
691
692     @Test
693     public void testMutableIteratorOffsetAddBreaks() {
694         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
695         map.put("k3", "v3");
696         map.remove("k1");
697
698         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
699         it.next();
700
701         map.put("k1", "new-v1");
702         assertIteratorBroken(it);
703     }
704
705     @Test
706     public void testMutableIteratorNewAddBreaks() {
707         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
708         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
709         it.next();
710
711         map.put("k3", "v3");
712         assertIteratorBroken(it);
713     }
714
715     @Test
716     public void testMutableIteratorOffsetRemoveBreaks() {
717         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
718         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
719         it.next();
720
721         map.remove("k1");
722         assertIteratorBroken(it);
723     }
724
725     @Test
726     public void testMutableIteratorNewRemoveBreaks() {
727         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
728         map.put("k3", "v3");
729         final Iterator<Entry<String, String>> it = map.entrySet().iterator();
730         it.next();
731
732         map.remove("k3");
733         assertIteratorBroken(it);
734     }
735
736     @Test
737     public void testMutableCrossIteratorRemove() {
738         final MutableOffsetMap<String, String> map = createMap().toModifiableMap();
739         final Set<Entry<String, String>> es = map.entrySet();
740         final Iterator<Entry<String, String>> it1 = es.iterator();
741         final Iterator<Entry<String, String>> it2 = es.iterator();
742
743         // Remove k1 via it1
744         it1.next();
745         it2.next();
746         it1.remove();
747         assertEquals(1, map.size());
748
749         // Check it2 was broken
750         assertIteratorBroken(it2);
751     }
752
753     @Test
754     public void testImmutableSerialization() throws IOException, ClassNotFoundException {
755         final Map<String, String> source = createMap();
756
757         final ByteArrayOutputStream bos = new ByteArrayOutputStream();
758         try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
759             oos.writeObject(source);
760         }
761
762         final ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
763         @SuppressWarnings("unchecked")
764         final Map<String, String> result = (Map<String, String>) ois.readObject();
765
766         assertEquals(source, result);
767     }
768 }