View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections4.map;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertNull;
22  import static org.junit.jupiter.api.Assertions.assertSame;
23  import static org.junit.jupiter.api.Assertions.assertThrows;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  import static org.junit.jupiter.api.Assertions.fail;
26  
27  import java.util.Map;
28  
29  import org.apache.commons.collections4.MapIterator;
30  import org.apache.commons.collections4.keyvalue.MultiKey;
31  import org.junit.jupiter.api.Test;
32  
33  /**
34   * JUnit tests.
35   */
36  public class MultiKeyMapTest<K, V> extends AbstractIterableMapTest<MultiKey<? extends K>, V> {
37  
38      static final Integer I1 = Integer.valueOf(1);
39      static final Integer I2 = Integer.valueOf(2);
40      static final Integer I3 = Integer.valueOf(3);
41      static final Integer I4 = Integer.valueOf(4);
42      static final Integer I5 = Integer.valueOf(5);
43      static final Integer I6 = Integer.valueOf(6);
44      static final Integer I7 = Integer.valueOf(7);
45      static final Integer I8 = Integer.valueOf(8);
46  
47      public MultiKeyMapTest() {
48          super(MultiKeyMapTest.class.getSimpleName());
49      }
50  
51      @Override
52      public String getCompatibilityVersion() {
53          return "4";
54      }
55  
56      /**
57       * {@inheritDoc}
58       */
59      @Override
60      public MultiKeyMap<K, V> getMap() {
61          return (MultiKeyMap<K, V>) super.getMap();
62      }
63  
64      @SuppressWarnings("unchecked")
65      private MultiKey<K>[] getMultiKeyKeys() {
66          return new MultiKey[] {
67              new MultiKey<>(I1, I2),
68              new MultiKey<>(I2, I3),
69              new MultiKey<>(I3, I4),
70              new MultiKey<>(I1, I1, I2),
71              new MultiKey<>(I2, I3, I4),
72              new MultiKey<>(I3, I7, I6),
73              new MultiKey<>(I1, I1, I2, I3),
74              new MultiKey<>(I2, I4, I5, I6),
75              new MultiKey<>(I3, I6, I7, I8),
76              new MultiKey<>(I1, I1, I2, I3, I4),
77              new MultiKey<>(I2, I3, I4, I5, I6),
78              new MultiKey<>(I3, I5, I6, I7, I8),
79          };
80      }
81  
82      @Override
83      @SuppressWarnings("unchecked")
84      public V[] getNewSampleValues() {
85          return (V[]) new Object[] {
86              "1a", "1b", "1c",
87              "2d", "2e", "2f",
88              "3g", "3h", "3i",
89              "4j", "4k", "4l",
90          };
91      }
92  
93      @Override
94      @SuppressWarnings("unchecked")
95      public MultiKey<K>[] getOtherKeys() {
96          return new MultiKey[] {
97              new MultiKey<>(I1, I7),
98              new MultiKey<>(I1, I8),
99              new MultiKey<>(I2, I4),
100             new MultiKey<>(I2, I5),
101         };
102     }
103 
104     @Override
105     public MultiKey<K>[] getSampleKeys() {
106         return getMultiKeyKeys();
107     }
108 
109     @Override
110     @SuppressWarnings("unchecked")
111     public V[] getSampleValues() {
112         return (V[]) new Object[] {
113             "2A", "2B", "2C",
114             "3D", "3E", "3F",
115             "4G", "4H", "4I",
116             "5J", "5K", "5L",
117         };
118     }
119 
120     @Override
121     public boolean isAllowNullKey() {
122         return false;
123     }
124 
125     @Override
126     public MultiKeyMap<K, V> makeObject() {
127         return new MultiKeyMap<>();
128     }
129 
130     @Test
131     @SuppressWarnings("unchecked")
132     public void testClone() {
133         final MultiKeyMap<K, V> map = new MultiKeyMap<>();
134         map.put(new MultiKey<>((K) I1, (K) I2), (V) "1-2");
135         final Map<MultiKey<? extends K>, V> cloned = map.clone();
136         assertEquals(map.size(), cloned.size());
137         assertSame(map.get(new MultiKey<>((K) I1, (K) I2)), cloned.get(new MultiKey<>((K) I1, (K) I2)));
138     }
139 
140     @Test
141     @SuppressWarnings("unchecked")
142     public void testLRUMultiKeyMap() {
143         final MultiKeyMap<K, V> map = MultiKeyMap.multiKeyMap(new LRUMap<>(2));
144         map.put((K) I1, (K) I2, (V) "1-2");
145         map.put((K) I1, (K) I3, (V) "1-1");
146         assertEquals(2, map.size());
147         map.put((K) I1, (K) I4, (V) "1-4");
148         assertEquals(2, map.size());
149         assertTrue(map.containsKey(I1, I3));
150         assertTrue(map.containsKey(I1, I4));
151         assertFalse(map.containsKey(I1, I2));
152 
153         final MultiKeyMap<K, V> cloned = map.clone();
154         assertEquals(2, map.size());
155         assertTrue(cloned.containsKey(I1, I3));
156         assertTrue(cloned.containsKey(I1, I4));
157         assertFalse(cloned.containsKey(I1, I2));
158         cloned.put((K) I1, (K) I5, (V) "1-5");
159         assertEquals(2, cloned.size());
160         assertTrue(cloned.containsKey(I1, I4));
161         assertTrue(cloned.containsKey(I1, I5));
162     }
163 
164     @Test
165     public void testMultiKeyContainsKey() {
166         resetFull();
167         final MultiKeyMap<K, V> multimap = getMap();
168         final MultiKey<K>[] keys = getMultiKeyKeys();
169 
170         for (final MultiKey<K> key : keys) {
171             switch (key.size()) {
172             case 2:
173                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1)));
174                 assertFalse(multimap.containsKey(null, key.getKey(1)));
175                 assertFalse(multimap.containsKey(key.getKey(0), null));
176                 assertFalse(multimap.containsKey(null, null));
177                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), null));
178                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), null, null));
179                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), null, null, null));
180                 break;
181             case 3:
182                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
183                 assertFalse(multimap.containsKey(null, key.getKey(1), key.getKey(2)));
184                 assertFalse(multimap.containsKey(key.getKey(0), null, key.getKey(2)));
185                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), null));
186                 assertFalse(multimap.containsKey(null, null, null));
187                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null));
188                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null, null));
189                 break;
190             case 4:
191                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
192                 assertFalse(multimap.containsKey(null, key.getKey(1), key.getKey(2), key.getKey(3)));
193                 assertFalse(multimap.containsKey(key.getKey(0), null, key.getKey(2), key.getKey(3)));
194                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), null, key.getKey(3)));
195                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null));
196                 assertFalse(multimap.containsKey(null, null, null, null));
197                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
198                 break;
199             case 5:
200                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
201                 assertFalse(multimap.containsKey(null, key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
202                 assertFalse(multimap.containsKey(key.getKey(0), null, key.getKey(2), key.getKey(3), key.getKey(4)));
203                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), null, key.getKey(3), key.getKey(4)));
204                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null, key.getKey(4)));
205                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
206                 assertFalse(multimap.containsKey(null, null, null, null, null));
207                 break;
208             default:
209                 fail("Invalid key size");
210             }
211         }
212     }
213 
214     @Test
215     public void testMultiKeyGet() {
216         resetFull();
217         final MultiKeyMap<K, V> multimap = getMap();
218         final MultiKey<K>[] keys = getMultiKeyKeys();
219         final V[] values = getSampleValues();
220 
221         for (int i = 0; i < keys.length; i++) {
222             final MultiKey<K> key = keys[i];
223             final V value = values[i];
224 
225             switch (key.size()) {
226             case 2:
227                 assertEquals(value, multimap.get(key.getKey(0), key.getKey(1)));
228                 assertNull(multimap.get(null, key.getKey(1)));
229                 assertNull(multimap.get(key.getKey(0), null));
230                 assertNull(multimap.get(null, null));
231                 assertNull(multimap.get(key.getKey(0), key.getKey(1), null));
232                 assertNull(multimap.get(key.getKey(0), key.getKey(1), null, null));
233                 assertNull(multimap.get(key.getKey(0), key.getKey(1), null, null, null));
234                 break;
235             case 3:
236                 assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2)));
237                 assertNull(multimap.get(null, key.getKey(1), key.getKey(2)));
238                 assertNull(multimap.get(key.getKey(0), null, key.getKey(2)));
239                 assertNull(multimap.get(key.getKey(0), key.getKey(1), null));
240                 assertNull(multimap.get(null, null, null));
241                 assertNull(multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null));
242                 assertNull(multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null, null));
243                 break;
244             case 4:
245                 assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
246                 assertNull(multimap.get(null, key.getKey(1), key.getKey(2), key.getKey(3)));
247                 assertNull(multimap.get(key.getKey(0), null, key.getKey(2), key.getKey(3)));
248                 assertNull(multimap.get(key.getKey(0), key.getKey(1), null, key.getKey(3)));
249                 assertNull(multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null));
250                 assertNull(multimap.get(null, null, null, null));
251                 assertNull(multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
252                 break;
253             case 5:
254                 assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
255                 assertNull(multimap.get(null, key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
256                 assertNull(multimap.get(key.getKey(0), null, key.getKey(2), key.getKey(3), key.getKey(4)));
257                 assertNull(multimap.get(key.getKey(0), key.getKey(1), null, key.getKey(3), key.getKey(4)));
258                 assertNull(multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null, key.getKey(4)));
259                 assertNull(multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
260                 assertNull(multimap.get(null, null, null, null, null));
261                 break;
262             default:
263                 fail("Invalid key size");
264             }
265         }
266     }
267 
268     @Test
269     public void testMultiKeyPut() {
270         final MultiKey<K>[] keys = getMultiKeyKeys();
271         final V[] values = getSampleValues();
272 
273         for (int i = 0; i < keys.length; i++) {
274             final MultiKeyMap<K, V> multimap = new MultiKeyMap<>();
275 
276             final MultiKey<K> key = keys[i];
277             final V value = values[i];
278 
279             switch (key.size()) {
280             case 2:
281                 assertNull(multimap.put(key.getKey(0), key.getKey(1), value));
282                 assertEquals(1, multimap.size());
283                 assertEquals(value, multimap.get(key.getKey(0), key.getKey(1)));
284                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1)));
285                 assertTrue(multimap.containsKey(new MultiKey<>(key.getKey(0), key.getKey(1))));
286                 assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), null));
287                 assertEquals(1, multimap.size());
288                 assertNull(multimap.get(key.getKey(0), key.getKey(1)));
289                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1)));
290                 break;
291             case 3:
292                 assertNull(multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), value));
293                 assertEquals(1, multimap.size());
294                 assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2)));
295                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
296                 assertTrue(multimap.containsKey(new MultiKey<>(key.getKey(0), key.getKey(1), key.getKey(2))));
297                 assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), null));
298                 assertEquals(1, multimap.size());
299                 assertNull(multimap.get(key.getKey(0), key.getKey(1), key.getKey(2)));
300                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
301                 break;
302             case 4:
303                 assertNull(multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), value));
304                 assertEquals(1, multimap.size());
305                 assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
306                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
307                 assertTrue(multimap.containsKey(new MultiKey<>(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3))));
308                 assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
309                 assertEquals(1, multimap.size());
310                 assertNull(multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
311                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
312                 break;
313             case 5:
314                 assertNull(multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4), value));
315                 assertEquals(1, multimap.size());
316                 assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
317                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
318                 assertTrue(multimap.containsKey(new MultiKey<>(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4))));
319                 assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4), null));
320                 assertEquals(1, multimap.size());
321                 assertNull(multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
322                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
323                 break;
324             default:
325                 fail("Invalid key size");
326             }
327         }
328     }
329 
330     @Test
331     public void testMultiKeyPutWithNullKey() {
332         final MultiKeyMap<String, String> map = new MultiKeyMap<>();
333         map.put("a", null, "value1");
334         map.put("b", null, "value2");
335         map.put("c", null, "value3");
336         map.put("a", "z",  "value4");
337         map.put("a", null, "value5");
338         map.put(null, "a", "value6");
339         map.put(null, null, "value7");
340 
341         assertEquals(6, map.size());
342         assertEquals("value5", map.get("a", null));
343         assertEquals("value4", map.get("a", "z"));
344         assertEquals("value6", map.get(null, "a"));
345     }
346 
347     @Test
348     public void testMultiKeyRemove() {
349         final MultiKey<K>[] keys = getMultiKeyKeys();
350         final V[] values = getSampleValues();
351 
352         for (int i = 0; i < keys.length; i++) {
353             resetFull();
354             final MultiKeyMap<K, V> multimap = getMap();
355             final int size = multimap.size();
356 
357             final MultiKey<K> key = keys[i];
358             final V value = values[i];
359 
360             switch (key.size()) {
361             case 2:
362                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1)));
363                 assertEquals(value, multimap.removeMultiKey(key.getKey(0), key.getKey(1)));
364                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1)));
365                 assertEquals(size - 1, multimap.size());
366                 assertNull(multimap.removeMultiKey(key.getKey(0), key.getKey(1)));
367                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1)));
368                 break;
369             case 3:
370                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
371                 assertEquals(value, multimap.removeMultiKey(key.getKey(0), key.getKey(1), key.getKey(2)));
372                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
373                 assertEquals(size - 1, multimap.size());
374                 assertNull(multimap.removeMultiKey(key.getKey(0), key.getKey(1), key.getKey(2)));
375                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
376                 break;
377             case 4:
378                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
379                 assertEquals(value, multimap.removeMultiKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
380                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
381                 assertEquals(size - 1, multimap.size());
382                 assertNull(multimap.removeMultiKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
383                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
384                 break;
385             case 5:
386                 assertTrue(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
387                 assertEquals(value, multimap.removeMultiKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
388                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
389                 assertEquals(size - 1, multimap.size());
390                 assertNull(multimap.removeMultiKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
391                 assertFalse(multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
392                 break;
393             default:
394                 fail("Invalid key size");
395             }
396         }
397     }
398 
399     @Test
400     public void testMultiKeyRemoveAll1() {
401         resetFull();
402         final MultiKeyMap<K, V> multimap = getMap();
403         assertEquals(12, multimap.size());
404 
405         multimap.removeAll(I1);
406         assertEquals(8, multimap.size());
407         for (final MapIterator<MultiKey<? extends K>, V> it = multimap.mapIterator(); it.hasNext();) {
408             final MultiKey<? extends K> key = it.next();
409             assertFalse(I1.equals(key.getKey(0)));
410         }
411     }
412 
413     @Test
414     public void testMultiKeyRemoveAll2() {
415         resetFull();
416         final MultiKeyMap<K, V> multimap = getMap();
417         assertEquals(12, multimap.size());
418 
419         multimap.removeAll(I2, I3);
420         assertEquals(9, multimap.size());
421         for (final MapIterator<MultiKey<? extends K>, V> it = multimap.mapIterator(); it.hasNext();) {
422             final MultiKey<? extends K> key = it.next();
423             assertFalse(I2.equals(key.getKey(0)) && I3.equals(key.getKey(1)));
424         }
425     }
426 
427     @Test
428     public void testMultiKeyRemoveAll3() {
429         resetFull();
430         final MultiKeyMap<K, V> multimap = getMap();
431         assertEquals(12, multimap.size());
432 
433         multimap.removeAll(I1, I1, I2);
434         assertEquals(9, multimap.size());
435         for (final MapIterator<MultiKey<? extends K>, V> it = multimap.mapIterator(); it.hasNext();) {
436             final MultiKey<? extends K> key = it.next();
437             assertFalse(I1.equals(key.getKey(0)) && I1.equals(key.getKey(1)) && I2.equals(key.getKey(2)));
438         }
439     }
440 
441     @Test
442     public void testMultiKeyRemoveAll4() {
443         resetFull();
444         final MultiKeyMap<K, V> multimap = getMap();
445         assertEquals(12, multimap.size());
446 
447         multimap.removeAll(I1, I1, I2, I3);
448         assertEquals(10, multimap.size());
449         for (final MapIterator<MultiKey<? extends K>, V> it = multimap.mapIterator(); it.hasNext();) {
450             final MultiKey<? extends K> key = it.next();
451             assertFalse(I1.equals(key.getKey(0)) && I1.equals(key.getKey(1)) && I2.equals(key.getKey(2)) && key.size() >= 4 && I3.equals(key.getKey(3)));
452         }
453     }
454 
455 //    public void testCreate() throws Exception {
456 //        resetEmpty();
457 //        writeExternalFormToDisk(
458 //            (java.io.Serializable) map,
459 //            "src/test/resources/data/test/MultiKeyMap.emptyCollection.version4.obj");
460 //        resetFull();
461 //        writeExternalFormToDisk(
462 //            (java.io.Serializable) map,
463 //            "src/test/resources/data/test/MultiKeyMap.fullCollection.version4.obj");
464 //    }
465 
466     @Test
467     @SuppressWarnings("unchecked")
468     public void testNullHandling() {
469         resetFull();
470         assertNull(map.get(null));
471         assertFalse(map.containsKey(null));
472         assertFalse(map.containsValue(null));
473         assertNull(map.remove(null));
474         assertFalse(map.entrySet().contains(null));
475         assertFalse(map.containsKey(null));
476         assertFalse(map.containsValue(null));
477 
478         assertThrows(NullPointerException.class, () -> map.put(null, null));
479 
480         assertNull(map.put(new MultiKey<>(null, null), null));
481 
482         assertThrows(NullPointerException.class, () -> map.put(null, (V) new Object()));
483     }
484 }