Add lazily-instantiated maps
[mdsal.git] / binding / mdsal-binding-dom-codec / src / test / java / org / opendaylight / mdsal / binding / dom / codec / impl / LazyBindingMapTest.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, s.r.o. 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.mdsal.binding.dom.codec.impl;
9
10 import static org.hamcrest.CoreMatchers.instanceOf;
11 import static org.hamcrest.MatcherAssert.assertThat;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertFalse;
14 import static org.junit.Assert.assertSame;
15 import static org.junit.Assert.assertThrows;
16 import static org.junit.Assert.assertTrue;
17 import static org.mockito.Mockito.mock;
18
19 import java.util.Collection;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Map.Entry;
26 import java.util.Set;
27 import org.junit.BeforeClass;
28 import org.junit.Test;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.TopBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelList;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelListBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelListKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.top.level.list.NestedListBuilder;
35 import org.opendaylight.yangtools.yang.binding.DataObject;
36 import org.opendaylight.yangtools.yang.binding.Identifiable;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38
39 public class LazyBindingMapTest extends AbstractBindingCodecTest {
40     private static Top TOP;
41
42     @BeforeClass
43     public static void prepareTop() {
44         final Map<TopLevelListKey, TopLevelList> map = new HashMap<>();
45         for (int i = 0; i < 2 * LazyBindingMap.LAZY_CUTOFF; i++) {
46             final TopLevelList item = new TopLevelListBuilder().setName(String.valueOf(i)).build();
47             map.put(item.key(), item);
48         }
49
50         TOP = new TopBuilder().setTopLevelList(map).build();
51     }
52
53     @Test
54     public void testSimpleEquals() {
55         final Top actual = prepareData();
56         assertThat(actual.getTopLevelList(), instanceOf(LazyBindingMap.class));
57         // AbstractMap.equals() goes through its entrySet and performs lookup for each key, hence it is excercising
58         // primarily LookupState
59         assertEquals(TOP, actual);
60     }
61
62     @Test
63     public void testEqualEntrySet() {
64         final Top actual = prepareData();
65         // Check equality based on entry set. This primarily exercises IterState
66         assertEquals(TOP.getTopLevelList().entrySet(), actual.getTopLevelList().entrySet());
67     }
68
69     @Test
70     public void testEqualKeySet() {
71         final Top actual = prepareData();
72         // Check equality based on key set. This primarily exercises IterState
73         assertEquals(TOP.getTopLevelList().keySet(), actual.getTopLevelList().keySet());
74     }
75
76     @Test
77     public void testIterKeySetLookup() {
78         final Top actual = prepareData();
79         // Forces IterState but then switches to key lookups
80         assertTrue(actual.getTopLevelList().keySet().containsAll(TOP.getTopLevelList().keySet()));
81     }
82
83     @Test
84     public void testIterEntrySetLookup() {
85         final Top actual = prepareData();
86         // Forces IterState but then switches to value lookups
87         assertTrue(actual.getTopLevelList().entrySet().containsAll(TOP.getTopLevelList().entrySet()));
88     }
89
90     @Test
91     public void testIterValueIteration() {
92         assertSameIteratorObjects(prepareData().getTopLevelList().values());
93     }
94
95     @Test
96     public void testLookupValueIteration() {
97         final Map<TopLevelListKey, TopLevelList> list = prepareData().getTopLevelList();
98         // Force lookup state instantiation
99         assertFalse(list.containsKey(new TopLevelListKey("blah")));
100
101         assertSameIteratorObjects(list.values());
102     }
103
104     @Test
105     public void testIterKeysetIteration() {
106         assertSameIteratorObjects(prepareData().getTopLevelList().keySet());
107     }
108
109     @Test
110     public void testLookupKeysetIteration() {
111         final Map<TopLevelListKey, TopLevelList> list = prepareData().getTopLevelList();
112         // Force lookup state instantiation
113         assertFalse(list.containsKey(new TopLevelListKey("blah")));
114
115         assertSameIteratorObjects(list.keySet());
116     }
117
118     private static void assertSameIteratorObjects(final Collection<?> collection) {
119         final Iterator<?> iter1 = collection.iterator();
120         final Iterator<?> iter2 = collection.iterator();
121
122         while (iter1.hasNext()) {
123             // Both iterators should return same values
124             assertSame(iter1.next(), iter2.next());
125         }
126         assertFalse(iter2.hasNext());
127     }
128
129     @Test
130     public void testIterSameViews() {
131         final Map<TopLevelListKey, TopLevelList> list = prepareData().getTopLevelList();
132         assertSame(list.values(), list.values());
133         assertSame(list.keySet(), list.keySet());
134         assertSame(list.entrySet(), list.entrySet());
135     }
136
137     @Test
138     public void testLookupSameViews() {
139         final Map<TopLevelListKey, TopLevelList> list = prepareData().getTopLevelList();
140         // Force lookup state instantiation
141         assertFalse(list.containsKey(new TopLevelListKey("blah")));
142
143         // Careful now ... first compare should  end up changing the iteration of keyset/entryset
144         final Set<TopLevelListKey> keySet1 = list.keySet();
145         final Set<TopLevelListKey> keySet2 = list.keySet();
146         final Set<Entry<TopLevelListKey, TopLevelList>> entrySet1 = list.entrySet();
147         final Set<Entry<TopLevelListKey, TopLevelList>> entrySet2 = list.entrySet();
148
149         // .. right here ...
150         assertSame(list.values(), list.values());
151         // ... so this should end up iterating slightly differently
152         assertEquals(new HashSet<>(list.values()), new HashSet<>(list.values()));
153
154         // ... and as we do not reuse keyset/entryset, we need to run full compare
155         assertEquals(keySet1, keySet2);
156         assertEquals(keySet1, new HashSet<>(keySet2));
157         assertEquals(entrySet1, entrySet2);
158         assertEquals(entrySet1, new HashSet<>(entrySet2));
159     }
160
161     @Test
162     public void testIterSameSize() {
163         final Map<TopLevelListKey, TopLevelList> list = prepareData().getTopLevelList();
164         // Force lookup state instantiation
165         assertFalse(list.containsKey(new TopLevelListKey("blah")));
166
167         assertEquals(list.size(), list.entrySet().size());
168         assertEquals(list.size(), list.keySet().size());
169         assertEquals(list.size(), list.values().size());
170     }
171
172     @Test
173     public void testLookupSameSize() {
174         final Map<TopLevelListKey, TopLevelList> list = prepareData().getTopLevelList();
175         assertEquals(list.size(), list.entrySet().size());
176         assertEquals(list.size(), list.keySet().size());
177         assertEquals(list.size(), list.values().size());
178     }
179
180     @Test
181     public void testImmutableThrows() {
182         final Map<TopLevelListKey, TopLevelList> list = prepareData().getTopLevelList();
183         // Various asserts for completeness' sake
184         assertThrows(UnsupportedOperationException.class, () -> list.clear());
185         assertThrows(UnsupportedOperationException.class, () -> list.remove(null));
186         assertThrows(UnsupportedOperationException.class, () -> list.putAll(null));
187     }
188
189     @Test
190     public void testLookupContainsValueThrows() {
191         final Map<TopLevelListKey, TopLevelList> list = prepareData().getTopLevelList();
192         assertThrows(NullPointerException.class, () -> list.containsValue(null));
193         assertThrows(ClassCastException.class, () -> list.containsValue(mock(DataObject.class)));
194     }
195
196     @Test
197     public void testLookupContainsKeyThrows() {
198         final Map<TopLevelListKey, TopLevelList> list = prepareData().getTopLevelList();
199         assertThrows(NullPointerException.class, () -> list.containsKey(null));
200         assertThrows(ClassCastException.class, () -> list.containsKey(mock(Identifiable.class)));
201     }
202
203     @Test
204     public void testLookupKey() {
205         final Map<TopLevelListKey, TopLevelList> list = prepareData().getTopLevelList();
206         for (TopLevelListKey key : TOP.getTopLevelList().keySet()) {
207             assertTrue(list.containsKey(key));
208         }
209
210         assertFalse(list.containsKey(new TopLevelListKey("blah")));
211     }
212
213     @Test
214     public void testLookupValue() {
215         final Map<TopLevelListKey, TopLevelList> list = prepareData().getTopLevelList();
216         for (TopLevelList val : TOP.getTopLevelList().values()) {
217             assertTrue(list.containsValue(val));
218         }
219
220         assertFalse(list.containsValue(new TopLevelListBuilder().setName("blah").build()));
221
222         // We checked this key, but this is a different object
223         assertFalse(list.containsValue(new TopLevelListBuilder(TOP.getTopLevelList().values().iterator().next())
224             .setNestedList(List.of(new NestedListBuilder().setName("foo").build()))
225             .build()));
226     }
227
228     private Top prepareData() {
229         return thereAndBackAgain(InstanceIdentifier.create(Top.class), TOP);
230     }
231 }