1 package org.djutils.immutablecollections;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertFalse;
5 import static org.junit.Assert.assertNull;
6 import static org.junit.Assert.assertTrue;
7
8 import java.util.Collection;
9 import java.util.HashMap;
10 import java.util.Map;
11 import java.util.Map.Entry;
12 import java.util.Set;
13 import java.util.function.BiConsumer;
14
15 import org.djutils.immutablecollections.ImmutableMap.ImmutableEntry;
16 import org.junit.Assert;
17 import org.junit.Test;
18
19
20
21
22
23
24
25
26
27
28
29 public class TestImmutableHashMap
30 {
31
32
33
34
35 @SuppressWarnings({"unlikely-arg-type"})
36 @Test
37 public final void testMapEqualsAndHashCode()
38 {
39 Integer[] keys = new Integer[] {10, 20, 30, 40};
40 Map<Integer, Double> mutableMap1 = new HashMap<>();
41 Map<Integer, Double> mutableMap2 = new HashMap<>();
42 for (Integer key : keys)
43 {
44 mutableMap1.put(key, Math.PI + key);
45 mutableMap2.put(key, Math.PI + key);
46 }
47 assertEquals("maps with same content should be equal", mutableMap1, mutableMap2);
48 assertEquals("maps with same content should have same hash code", mutableMap1.hashCode(), mutableMap2.hashCode());
49
50 ImmutableMap<Integer, Double> im1 = new ImmutableHashMap<>(mutableMap1, Immutable.WRAP);
51 assertFalse(im1.isCopy());
52 ImmutableMap<Integer, Double> im2 = new ImmutableHashMap<>(mutableMap2, Immutable.WRAP);
53 assertEquals("immutable maps with same content should be equal", im1, im2);
54 assertEquals("immutable maps with same content should have same hash code", im1.hashCode(), im2.hashCode());
55 im2 = new ImmutableHashMap<>(mutableMap2, Immutable.COPY);
56 assertEquals("immutable maps with same content should be equal", im1, im2);
57 assertEquals("immutable maps with same content should be equal", im2, im1);
58 im1 = new ImmutableHashMap<>(mutableMap1, Immutable.COPY);
59 assertTrue(im1.isCopy());
60 assertEquals("immutable maps with same content should be equal", im1, im2);
61 assertEquals("immutable maps with same content should be equal", im2, im1);
62
63 assertEquals("immutable map is equal to itself", im1, im1);
64 assertFalse("immutable map is not equal to null", im1.equals(null));
65 assertFalse("immutable map is not equal to some totally different object", im1.equals("abc"));
66 mutableMap2.put(keys[0], Math.E);
67 assertFalse("altered mutable map differs", mutableMap1.equals(mutableMap2));
68 assertEquals("immutable map holding copy is not altered", im1, im2);
69 ImmutableMap<Integer, Double> im1Wrap = new ImmutableHashMap<>(mutableMap1, Immutable.WRAP);
70 assertEquals("another immutable map from the same collection is equal", im1, im1Wrap);
71 assertEquals("another immutable map from the same collection has same hash code", im1.hashCode(), im1Wrap.hashCode());
72 mutableMap1.put(keys[0], -Math.PI);
73 assertFalse("wrapped immutable map re-checks content", im1.equals(im1Wrap));
74 assertFalse("wrapped immutable map re-checks content", im1Wrap.equals(im1));
75 assertFalse("wrapped immutable map re-computes hash code", im1.hashCode() == im1Wrap.hashCode());
76 assertFalse("wrapped immutable map re-computes hash code", im1Wrap.hashCode() == im1.hashCode());
77
78 assertNull("result of get for non-existent key returns null", im1.get(-123));
79 for (Integer key : keys)
80 {
81 assertEquals("Immutable map returns same as underlying mutable map", mutableMap1.get(key), im1Wrap.get(key));
82 }
83 ImmutableMap<Integer, Double> map3 =
84 new ImmutableHashMap<>((ImmutableAbstractMap<Integer, Double>) im1Wrap, Immutable.WRAP);
85 assertEquals("immutable map constructed by wrapping another immutable map is equals", im1Wrap, map3);
86 map3 = new ImmutableHashMap<>((ImmutableAbstractMap<Integer, Double>) im1Wrap, Immutable.COPY);
87 assertEquals("immutable map constructed by copyinig another immutable map is equals", im1Wrap, map3);
88 assertTrue("toString returns something descriptive", map3.toString().startsWith("ImmutableHashMap ["));
89 assertEquals("get with default returns value for key when it exists", mutableMap1.get(keys[0]),
90 map3.getOrDefault(keys[0], Math.asin(2.0)));
91 assertEquals("get with default returns default for key when it does not exist", Math.asin(2.0),
92 map3.getOrDefault(-123, Math.asin(2.0)), 0.00001);
93 final ImmutableMap<Integer, Double> map4 =
94 new ImmutableHashMap<Integer, Double>((ImmutableAbstractMap<Integer, Double>) im1Wrap, Immutable.WRAP);
95 boolean[] tested = new boolean[keys.length];
96 map3.forEach(new BiConsumer<Integer, Double>()
97 {
98 @Override
99 public void accept(final Integer t, final Double u)
100 {
101 assertEquals("accept got a value that matches the key", u, map4.get(t), 0.0001);
102 int index = -1;
103 for (int i = 0; i < keys.length; i++)
104 {
105 if (keys[i] == t)
106 {
107 index = i;
108 }
109 }
110 assertTrue("key is contained in keys", index >= 0);
111 assertFalse("key has not appeared before", tested[index]);
112 tested[index] = true;
113 }
114 });
115 for (int index = 0; index < tested.length; index++)
116 {
117 assertTrue("each index got tested", tested[index]);
118 }
119 }
120
121
122
123
124 @Test
125 public final void testHashMap()
126 {
127 Map<Integer, Integer> isMap = new HashMap<>();
128 for (int i = 1; i <= 10; i++)
129 {
130 isMap.put(i, 100 * i);
131 }
132 Map<Integer, Integer> map = new HashMap<Integer, Integer>(isMap);
133 testIntMap(map, new ImmutableHashMap<Integer, Integer>(map, Immutable.WRAP), Immutable.WRAP);
134 map = new HashMap<Integer, Integer>(isMap);
135 testIntMap(map, new ImmutableHashMap<Integer, Integer>(map, Immutable.COPY), Immutable.COPY);
136 map = new HashMap<Integer, Integer>(isMap);
137 testIntMap(map, new ImmutableHashMap<Integer, Integer>(map), Immutable.COPY);
138 map = new HashMap<Integer, Integer>(isMap);
139 ImmutableHashMap<Integer, Integer> ihs = new ImmutableHashMap<Integer, Integer>(map);
140 testIntMap(map, new ImmutableHashMap<Integer, Integer>(ihs), Immutable.COPY);
141 }
142
143
144
145
146
147
148
149 private void testIntMap(final Map<Integer, Integer> map, final ImmutableMap<Integer, Integer> imMap,
150 final Immutable copyOrWrap)
151 {
152 Assert.assertTrue(map.size() == 10);
153 Assert.assertTrue(imMap.size() == 10);
154 for (int i = 0; i < 10; i++)
155 {
156 Assert.assertTrue(imMap.containsKey(i + 1));
157 }
158 for (int i = 0; i < 10; i++)
159 {
160 Assert.assertTrue(imMap.containsValue(100 * (i + 1)));
161 }
162 Assert.assertFalse(imMap.isEmpty());
163 Assert.assertFalse(imMap.containsKey(15));
164 Assert.assertFalse(imMap.containsValue(1500));
165
166 Assert.assertTrue(imMap.keySet().size() == 10);
167 Assert.assertTrue(imMap.values().size() == 10);
168
169 Assert.assertTrue(sameContent(map.keySet(), imMap.keySet().toSet()));
170 Assert.assertTrue(sameContent(map.values(), imMap.values().toCollection()));
171 Assert.assertTrue(sameContent(map.keySet(), imMap.keySet().toSet()));
172 Assert.assertTrue(sameContent(map.values(), imMap.values().toCollection()));
173
174 Assert.assertTrue(checkEntrySets(map.entrySet(), imMap.entrySet().toSet()));
175 Assert.assertTrue(checkEntrySets(map.entrySet(), imMap.entrySet().toSet()));
176
177 if (copyOrWrap == Immutable.COPY)
178 {
179 Assert.assertTrue(imMap.isCopy());
180 Assert.assertTrue(imMap.toMap().equals(map));
181 Assert.assertFalse(imMap.toMap() == map);
182 }
183 else
184 {
185 Assert.assertTrue(imMap.isWrap());
186 Assert.assertTrue(imMap.toMap().equals(map));
187 Assert.assertFalse(imMap.toMap() == map);
188 }
189
190 Map<Integer, Integer> to = imMap.toMap();
191 Assert.assertTrue(map.equals(to));
192
193
194 map.put(11, 1100);
195 if (copyOrWrap == Immutable.COPY)
196 {
197 Assert.assertTrue(imMap.size() == 10);
198 }
199 else
200 {
201 Assert.assertTrue(imMap.size() == 11);
202 }
203 }
204
205
206
207
208
209
210
211 private boolean sameContent(final Collection<?> a, final Collection<?> b)
212 {
213 return a.containsAll(b) && b.containsAll(a);
214 }
215
216
217
218
219
220
221
222 private boolean checkEntrySets(final Set<Entry<Integer, Integer>> es, final Set<ImmutableEntry<Integer, Integer>> ies)
223 {
224 if (es.size() != ies.size())
225 {
226 return false;
227 }
228 for (Entry<Integer, Integer> entry : es)
229 {
230 boolean found = false;
231 for (ImmutableEntry<Integer, Integer> immEntry : ies)
232 {
233 if (entry.getKey().equals(immEntry.getKey()) && entry.getValue().equals(immEntry.getValue()))
234 {
235 found = true;
236 break;
237 }
238 }
239 if (!found)
240 {
241 return false;
242 }
243 }
244 return true;
245 }
246
247 }