ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/MapTest.java
Revision: 1.10
Committed: Mon Oct 7 21:06:02 2019 UTC (4 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.9: +0 -2 lines
Log Message:
fix imports

File Contents

# User Rev Content
1 jsr166 1.1 /*
2     * Written by Doug Lea and Martin Buchholz with assistance from
3     * members of JCP JSR-166 Expert Group and released to the public
4     * domain, as explained at
5     * http://creativecommons.org/publicdomain/zero/1.0/
6     */
7    
8     import java.util.ArrayList;
9     import java.util.Iterator;
10     import java.util.List;
11     import java.util.Map;
12 jsr166 1.9 import java.util.concurrent.CompletableFuture;
13 jsr166 1.1 import java.util.concurrent.ThreadLocalRandom;
14 jsr166 1.9 import java.util.concurrent.atomic.AtomicBoolean;
15     import java.util.concurrent.atomic.AtomicLong;
16     import java.util.function.BiFunction;
17    
18     import junit.framework.Test;
19 jsr166 1.1
20     /**
21     * Contains tests applicable to all Map implementations.
22     */
23     public class MapTest extends JSR166TestCase {
24     final MapImplementation impl;
25    
26     /** Tests are parameterized by a Map implementation. */
27     MapTest(MapImplementation impl, String methodName) {
28     super(methodName);
29     this.impl = impl;
30     }
31    
32     public static Test testSuite(MapImplementation impl) {
33     return newTestSuite(
34     parameterizedTestSuite(MapTest.class,
35     MapImplementation.class,
36     impl));
37     }
38    
39     public void testImplSanity() {
40     final ThreadLocalRandom rnd = ThreadLocalRandom.current();
41     {
42     Map m = impl.emptyMap();
43     assertTrue(m.isEmpty());
44     assertEquals(0, m.size());
45     Object k = impl.makeKey(rnd.nextInt());
46     Object v = impl.makeValue(rnd.nextInt());
47     m.put(k, v);
48     assertFalse(m.isEmpty());
49     assertEquals(1, m.size());
50     assertTrue(m.containsKey(k));
51     assertTrue(m.containsValue(v));
52     }
53     {
54     Map m = impl.emptyMap();
55     Object v = impl.makeValue(rnd.nextInt());
56     if (impl.permitsNullKeys()) {
57     m.put(null, v);
58     assertTrue(m.containsKey(null));
59     assertTrue(m.containsValue(v));
60     } else {
61     assertThrows(NullPointerException.class, () -> m.put(null, v));
62     }
63     }
64     {
65     Map m = impl.emptyMap();
66     Object k = impl.makeKey(rnd.nextInt());
67     if (impl.permitsNullValues()) {
68     m.put(k, null);
69     assertTrue(m.containsKey(k));
70     assertTrue(m.containsValue(null));
71     } else {
72     assertThrows(NullPointerException.class, () -> m.put(k, null));
73     }
74     }
75     {
76     Map m = impl.emptyMap();
77     Object k = impl.makeKey(rnd.nextInt());
78     Object v1 = impl.makeValue(rnd.nextInt());
79     Object v2 = impl.makeValue(rnd.nextInt());
80     m.put(k, v1);
81     if (impl.supportsSetValue()) {
82     ((Map.Entry)(m.entrySet().iterator().next())).setValue(v2);
83     assertSame(v2, m.get(k));
84     assertTrue(m.containsKey(k));
85     assertTrue(m.containsValue(v2));
86     assertFalse(m.containsValue(v1));
87     } else {
88     assertThrows(UnsupportedOperationException.class,
89     () -> ((Map.Entry)(m.entrySet().iterator().next())).setValue(v2));
90     }
91     }
92     }
93    
94     /**
95     * Tests and extends the scenario reported in
96     * https://bugs.openjdk.java.net/browse/JDK-8186171
97     * HashMap: Entry.setValue may not work after Iterator.remove() called for previous entries
98     * ant -Djsr166.tckTestClass=HashMapTest -Djsr166.methodFilter=testBug8186171 -Djsr166.runsPerTest=1000 tck
99     */
100     public void testBug8186171() {
101     if (!impl.supportsSetValue()) return;
102 jsr166 1.8 if (!atLeastJava10()) return; // jdk9 is no longer maintained
103 jsr166 1.1 final ThreadLocalRandom rnd = ThreadLocalRandom.current();
104     final boolean permitsNullValues = impl.permitsNullValues();
105     final Object v1 = (permitsNullValues && rnd.nextBoolean())
106     ? null : impl.makeValue(1);
107     final Object v2 = (permitsNullValues && rnd.nextBoolean() && v1 != null)
108     ? null : impl.makeValue(2);
109    
110 jsr166 1.2 // If true, always lands in first bucket in hash tables.
111 jsr166 1.1 final boolean poorHash = rnd.nextBoolean();
112     class Key implements Comparable<Key> {
113     final int i;
114     Key(int i) { this.i = i; }
115     public int hashCode() { return poorHash ? 0 : super.hashCode(); }
116     public int compareTo(Key x) {
117     return Integer.compare(this.i, x.i);
118     }
119     }
120    
121     // Both HashMap and ConcurrentHashMap have:
122     // TREEIFY_THRESHOLD = 8; UNTREEIFY_THRESHOLD = 6;
123     final int size = rnd.nextInt(1, 25);
124    
125     List<Key> keys = new ArrayList<>();
126     for (int i = size; i-->0; ) keys.add(new Key(i));
127     Key keyToFrob = keys.get(rnd.nextInt(keys.size()));
128    
129     Map<Key, Object> m = impl.emptyMap();
130     for (Key key : keys) m.put(key, v1);
131    
132     for (Iterator<Map.Entry<Key, Object>> it = m.entrySet().iterator();
133     it.hasNext(); ) {
134     Map.Entry<Key, Object> entry = it.next();
135     if (entry.getKey() == keyToFrob)
136     entry.setValue(v2); // does this have the expected effect?
137     else
138     it.remove();
139     }
140    
141     assertFalse(m.containsValue(v1));
142     assertTrue(m.containsValue(v2));
143     assertTrue(m.containsKey(keyToFrob));
144     assertEquals(1, m.size());
145     }
146    
147 jsr166 1.3 /**
148     * "Missing" test found while investigating JDK-8210280.
149 jsr166 1.4 * ant -Djsr166.tckTestClass=HashMapTest -Djsr166.methodFilter=testBug8210280 -Djsr166.runsPerTest=1000000 tck
150 jsr166 1.3 */
151     public void testBug8210280() {
152 jsr166 1.4 final ThreadLocalRandom rnd = ThreadLocalRandom.current();
153     final int size1 = rnd.nextInt(32);
154     final int size2 = rnd.nextInt(128);
155    
156     final Map m1 = impl.emptyMap();
157     for (int i = 0; i < size1; i++) {
158     int elt = rnd.nextInt(1024 * i, 1024 * (i + 1));
159     assertNull(m1.put(impl.makeKey(elt), impl.makeValue(elt)));
160     }
161    
162     final Map m2 = impl.emptyMap();
163     for (int i = 0; i < size2; i++) {
164     int elt = rnd.nextInt(Integer.MIN_VALUE + 1024 * i,
165     Integer.MIN_VALUE + 1024 * (i + 1));
166     assertNull(m2.put(impl.makeKey(elt), impl.makeValue(-elt)));
167     }
168    
169     final Map m1Copy = impl.emptyMap();
170     m1Copy.putAll(m1);
171    
172     m1.putAll(m2);
173    
174     for (Object elt : m2.keySet())
175     assertEquals(m2.get(elt), m1.get(elt));
176     for (Object elt : m1Copy.keySet())
177     assertSame(m1Copy.get(elt), m1.get(elt));
178     assertEquals(size1 + size2, m1.size());
179 jsr166 1.3 }
180    
181 jsr166 1.5 /**
182     * 8222930: ConcurrentSkipListMap.clone() shares size variable between original and clone
183     */
184     public void testClone() {
185     final ThreadLocalRandom rnd = ThreadLocalRandom.current();
186     final int size = rnd.nextInt(4);
187     final Map map = impl.emptyMap();
188 jsr166 1.6 for (int i = 0; i < size; i++)
189 jsr166 1.5 map.put(impl.makeKey(i), impl.makeValue(i));
190     final Map clone = cloneableClone(map);
191     if (clone == null) return; // not cloneable?
192    
193     assertEquals(size, map.size());
194     assertEquals(size, clone.size());
195     assertEquals(map.isEmpty(), clone.isEmpty());
196    
197     clone.put(impl.makeKey(-1), impl.makeValue(-1));
198     assertEquals(size, map.size());
199     assertEquals(size + 1, clone.size());
200    
201     clone.clear();
202     assertEquals(size, map.size());
203     assertEquals(0, clone.size());
204     assertTrue(clone.isEmpty());
205     }
206    
207 jsr166 1.9 /**
208     * Concurrent access by compute methods behaves as expected
209     */
210     public void testConcurrentAccess() throws Throwable {
211     final Map map = impl.emptyMap();
212     final long testDurationMillis = expensiveTests ? 1000 : 2;
213     final int nTasks = impl.isConcurrent()
214     ? ThreadLocalRandom.current().nextInt(1, 10)
215     : 1;
216     final AtomicBoolean done = new AtomicBoolean(false);
217     final boolean remappingFunctionCalledAtMostOnce
218     = impl.remappingFunctionCalledAtMostOnce();
219     final List<CompletableFuture> futures = new ArrayList<>();
220     final AtomicLong expectedSum = new AtomicLong(0);
221     final Action[] tasks = {
222     // repeatedly increment values using compute()
223     () -> {
224     long[] invocations = new long[2];
225     ThreadLocalRandom rnd = ThreadLocalRandom.current();
226     BiFunction<Object, Object, Object> incValue = (k, v) -> {
227     invocations[1]++;
228     int vi = (v == null) ? 1 : impl.valueToInt(v) + 1;
229     return impl.makeValue(vi);
230     };
231     while (!done.getAcquire()) {
232     invocations[0]++;
233     Object key = impl.makeKey(3 * rnd.nextInt(10));
234     map.compute(key, incValue);
235     }
236     if (remappingFunctionCalledAtMostOnce)
237     assertEquals(invocations[0], invocations[1]);
238     expectedSum.getAndAdd(invocations[0]);
239     },
240     // repeatedly increment values using computeIfPresent()
241     () -> {
242     long[] invocations = new long[2];
243     ThreadLocalRandom rnd = ThreadLocalRandom.current();
244     BiFunction<Object, Object, Object> incValue = (k, v) -> {
245     invocations[1]++;
246     int vi = impl.valueToInt(v) + 1;
247     return impl.makeValue(vi);
248     };
249     while (!done.getAcquire()) {
250     Object key = impl.makeKey(3 * rnd.nextInt(10));
251     if (map.computeIfPresent(key, incValue) != null)
252     invocations[0]++;
253     }
254     if (remappingFunctionCalledAtMostOnce)
255     assertEquals(invocations[0], invocations[1]);
256     expectedSum.getAndAdd(invocations[0]);
257     },
258     };
259     for (int i = nTasks; i--> 0; ) {
260     Action task = chooseRandomly(tasks);
261     futures.add(CompletableFuture.runAsync(checkedRunnable(task)));
262     }
263     Thread.sleep(testDurationMillis);
264     done.setRelease(true);
265     for (var future : futures)
266     checkTimedGet(future, null);
267    
268     long sum = map.values().stream().mapToLong(x -> (int) x).sum();
269     assertEquals(expectedSum.get(), sum);
270     }
271    
272 jsr166 1.1 // public void testFailsIntentionallyForDebugging() {
273     // fail(impl.klazz().getSimpleName());
274     // }
275     }