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.keyvalue;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertNull;
21  import static org.junit.jupiter.api.Assertions.assertSame;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  
25  import java.util.HashMap;
26  import java.util.Map;
27  
28  import org.junit.jupiter.api.Test;
29  
30  /**
31   * Abstract tests that can be extended to test any Map.Entry implementation.
32   * Subclasses must implement {@link #makeMapEntry(Object, Object)} to return
33   * a new Map.Entry of the type being tested. Subclasses must also implement
34   * {@link #testConstructors()} to test the constructors of the Map.Entry
35   * type being tested.
36   */
37  public abstract class AbstractMapEntryTest<K, V> {
38  
39      protected final String key = "name";
40      protected final String value = "duke";
41  
42      /**
43       * Makes a Map.Entry of a type that's known to work correctly.
44       */
45      public Map.Entry<K, V> makeKnownMapEntry() {
46          return makeKnownMapEntry(null, null);
47      }
48  
49      /**
50       * Makes a Map.Entry of a type that's known to work correctly.
51       */
52      public Map.Entry<K, V> makeKnownMapEntry(final K key, final V value) {
53          final Map<K, V> map = new HashMap<>(1);
54          map.put(key, value);
55          return map.entrySet().iterator().next();
56      }
57  
58      /**
59       * Make an instance of Map.Entry with the default (null) key and value.
60       * This implementation simply calls {@link #makeMapEntry(Object, Object)}
61       * with null for key and value. Subclasses can override this method if desired.
62       */
63      public Map.Entry<K, V> makeMapEntry() {
64          return makeMapEntry(null, null);
65      }
66  
67      /**
68       * Make an instance of Map.Entry with the specified key and value.
69       * Subclasses should override this method to return a Map.Entry
70       * of the type being tested.
71       */
72      public abstract Map.Entry<K, V> makeMapEntry(K key, V value);
73  
74      @Test
75      @SuppressWarnings("unchecked")
76      public void testAccessorsAndMutators() {
77          Map.Entry<K, V> entry = makeMapEntry((K) key, (V) value);
78  
79          assertSame(key, entry.getKey());
80  
81          entry.setValue((V) value);
82          assertSame(value, entry.getValue());
83  
84          // check that null doesn't do anything funny
85          entry = makeMapEntry(null, null);
86          assertNull(entry.getKey());
87  
88          entry.setValue(null);
89          assertNull(entry.getValue());
90      }
91  
92      /**
93       * Subclasses should provide tests for their constructors.
94       */
95      public abstract void testConstructors();
96  
97      @Test
98      @SuppressWarnings("unchecked")
99      public void testEqualsAndHashCode() {
100         // 1. test with object data
101         Map.Entry<K, V> e1 = makeMapEntry((K) key, (V) value);
102         Map.Entry<K, V> e2 = makeKnownMapEntry((K) key, (V) value);
103 
104         assertEquals(e1, e1);
105         assertEquals(e2, e1);
106         assertEquals(e1, e2);
107         assertEquals(e1.hashCode(), e2.hashCode());
108 
109         // 2. test with nulls
110         e1 = makeMapEntry();
111         e2 = makeKnownMapEntry();
112 
113         assertEquals(e1, e1);
114         assertEquals(e2, e1);
115         assertEquals(e1, e2);
116         assertEquals(e1.hashCode(), e2.hashCode());
117     }
118 
119     /**
120      * Subclasses should override this method to test the
121      * desired behavior of the class with respect to
122      * handling of self-references.
123      */
124 
125     @Test
126     @SuppressWarnings("unchecked")
127     public void testSelfReferenceHandling() {
128         // test that #setValue does not permit
129         //  the MapEntry to contain itself (and thus cause infinite recursion
130         //  in #hashCode and #toString)
131 
132         final Map.Entry<K, V> entry = makeMapEntry();
133 
134         assertThrows(IllegalArgumentException.class, () -> entry.setValue((V) entry));
135 
136         // check that the KVP's state has not changed
137         assertTrue(entry.getKey() == null && entry.getValue() == null);
138     }
139 
140     @Test
141     @SuppressWarnings("unchecked")
142     public void testToString() {
143         Map.Entry<K, V> entry = makeMapEntry((K) key, (V) value);
144         assertEquals(entry.toString(), entry.getKey() + "=" + entry.getValue());
145 
146         // test with nulls
147         entry = makeMapEntry();
148         assertEquals(entry.toString(), entry.getKey() + "=" + entry.getValue());
149     }
150 
151 }