ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/MapTest.java
(Generate patch)

Comparing jsr166/src/test/tck/MapTest.java (file contents):
Revision 1.3 by jsr166, Wed Dec 12 19:50:16 2018 UTC vs.
Revision 1.11 by dl, Tue Jan 26 13:33:06 2021 UTC

# Line 5 | Line 5
5   * http://creativecommons.org/publicdomain/zero/1.0/
6   */
7  
8 import junit.framework.Test;
9
8   import java.util.ArrayList;
9   import java.util.Iterator;
10   import java.util.List;
11   import java.util.Map;
12 + import java.util.concurrent.CompletableFuture;
13   import java.util.concurrent.ThreadLocalRandom;
14 + 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  
20   /**
21   * Contains tests applicable to all Map implementations.
22   */
23 + @SuppressWarnings("unchecked")
24   public class MapTest extends JSR166TestCase {
25      final MapImplementation impl;
26  
# Line 37 | Line 42 | public class MapTest extends JSR166TestC
42          {
43              Map m = impl.emptyMap();
44              assertTrue(m.isEmpty());
45 <            assertEquals(0, m.size());
45 >            mustEqual(0, m.size());
46              Object k = impl.makeKey(rnd.nextInt());
47              Object v = impl.makeValue(rnd.nextInt());
48              m.put(k, v);
49              assertFalse(m.isEmpty());
50 <            assertEquals(1, m.size());
50 >            mustEqual(1, m.size());
51              assertTrue(m.containsKey(k));
52              assertTrue(m.containsValue(v));
53          }
# Line 95 | Line 100 | public class MapTest extends JSR166TestC
100       */
101      public void testBug8186171() {
102          if (!impl.supportsSetValue()) return;
103 +        if (!atLeastJava10()) return; // jdk9 is no longer maintained
104          final ThreadLocalRandom rnd = ThreadLocalRandom.current();
105          final boolean permitsNullValues = impl.permitsNullValues();
106          final Object v1 = (permitsNullValues && rnd.nextBoolean())
# Line 136 | Line 142 | public class MapTest extends JSR166TestC
142          assertFalse(m.containsValue(v1));
143          assertTrue(m.containsValue(v2));
144          assertTrue(m.containsKey(keyToFrob));
145 <        assertEquals(1, m.size());
145 >        mustEqual(1, m.size());
146      }
147  
148      /**
149       * "Missing" test found while investigating JDK-8210280.
150 <     * See discussion on mailing list.
145 <     * TODO: randomize
150 >     * ant -Djsr166.tckTestClass=HashMapTest -Djsr166.methodFilter=testBug8210280 -Djsr166.runsPerTest=1000000 tck
151       */
152      public void testBug8210280() {
153 <        Map m = impl.emptyMap();
154 <        for (int i = 0; i < 4; i++) m.put(7 + i * 16, 0);
155 <        Map more = impl.emptyMap();
156 <        for (int i = 0; i < 128; i++) more.put(-i, 42);
157 <        m.putAll(more);
158 <        for (int i = 0; i < 4; i++) assertEquals(0, m.get(7 + i * 16));
153 >        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
154 >        final int size1 = rnd.nextInt(32);
155 >        final int size2 = rnd.nextInt(128);
156 >
157 >        final Map m1 = impl.emptyMap();
158 >        for (int i = 0; i < size1; i++) {
159 >            int elt = rnd.nextInt(1024 * i, 1024 * (i + 1));
160 >            assertNull(m1.put(impl.makeKey(elt), impl.makeValue(elt)));
161 >        }
162 >
163 >        final Map m2 = impl.emptyMap();
164 >        for (int i = 0; i < size2; i++) {
165 >            int elt = rnd.nextInt(Integer.MIN_VALUE + 1024 * i,
166 >                                  Integer.MIN_VALUE + 1024 * (i + 1));
167 >            assertNull(m2.put(impl.makeKey(elt), impl.makeValue(-elt)));
168 >        }
169 >
170 >        final Map m1Copy = impl.emptyMap();
171 >        m1Copy.putAll(m1);
172 >
173 >        m1.putAll(m2);
174 >
175 >        for (Object elt : m2.keySet())
176 >            mustEqual(m2.get(elt), m1.get(elt));
177 >        for (Object elt : m1Copy.keySet())
178 >            assertSame(m1Copy.get(elt), m1.get(elt));
179 >        mustEqual(size1 + size2, m1.size());
180 >    }
181 >
182 >    /**
183 >     * 8222930: ConcurrentSkipListMap.clone() shares size variable between original and clone
184 >     */
185 >    public void testClone() {
186 >        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
187 >        final int size = rnd.nextInt(4);
188 >        final Map map = impl.emptyMap();
189 >        for (int i = 0; i < size; i++)
190 >            map.put(impl.makeKey(i), impl.makeValue(i));
191 >        final Map clone = cloneableClone(map);
192 >        if (clone == null) return;      // not cloneable?
193 >
194 >        mustEqual(size, map.size());
195 >        mustEqual(size, clone.size());
196 >        mustEqual(map.isEmpty(), clone.isEmpty());
197 >
198 >        clone.put(impl.makeKey(-1), impl.makeValue(-1));
199 >        mustEqual(size, map.size());
200 >        mustEqual(size + 1, clone.size());
201 >
202 >        clone.clear();
203 >        mustEqual(size, map.size());
204 >        mustEqual(0, clone.size());
205 >        assertTrue(clone.isEmpty());
206 >    }
207 >
208 >    /**
209 >     * Concurrent access by compute methods behaves as expected
210 >     */
211 >    public void testConcurrentAccess() throws Throwable {
212 >        final Map map = impl.emptyMap();
213 >        final long testDurationMillis = expensiveTests ? 1000 : 2;
214 >        final int nTasks = impl.isConcurrent()
215 >            ? ThreadLocalRandom.current().nextInt(1, 10)
216 >            : 1;
217 >        final AtomicBoolean done = new AtomicBoolean(false);
218 >        final boolean remappingFunctionCalledAtMostOnce
219 >            = impl.remappingFunctionCalledAtMostOnce();
220 >        final List<CompletableFuture> futures = new ArrayList<>();
221 >        final AtomicLong expectedSum = new AtomicLong(0);
222 >        final Action[] tasks = {
223 >            // repeatedly increment values using compute()
224 >            () -> {
225 >                long[] invocations = new long[2];
226 >                ThreadLocalRandom rnd = ThreadLocalRandom.current();
227 >                BiFunction<Object, Object, Object> incValue = (k, v) -> {
228 >                    invocations[1]++;
229 >                    int vi = (v == null) ? 1 : impl.valueToInt(v) + 1;
230 >                    return impl.makeValue(vi);
231 >                };
232 >                while (!done.getAcquire()) {
233 >                    invocations[0]++;
234 >                    Object key = impl.makeKey(3 * rnd.nextInt(10));
235 >                    map.compute(key, incValue);
236 >                }
237 >                if (remappingFunctionCalledAtMostOnce)
238 >                    mustEqual(invocations[0], invocations[1]);
239 >                expectedSum.getAndAdd(invocations[0]);
240 >            },
241 >            // repeatedly increment values using computeIfPresent()
242 >            () -> {
243 >                long[] invocations = new long[2];
244 >                ThreadLocalRandom rnd = ThreadLocalRandom.current();
245 >                BiFunction<Object, Object, Object> incValue = (k, v) -> {
246 >                    invocations[1]++;
247 >                    int vi = impl.valueToInt(v) + 1;
248 >                    return impl.makeValue(vi);
249 >                };
250 >                while (!done.getAcquire()) {
251 >                    Object key = impl.makeKey(3 * rnd.nextInt(10));
252 >                    if (map.computeIfPresent(key, incValue) != null)
253 >                        invocations[0]++;
254 >                }
255 >                if (remappingFunctionCalledAtMostOnce)
256 >                    mustEqual(invocations[0], invocations[1]);
257 >                expectedSum.getAndAdd(invocations[0]);
258 >            },
259 >        };
260 >        for (int i = nTasks; i--> 0; ) {
261 >            Action task = chooseRandomly(tasks);
262 >            futures.add(CompletableFuture.runAsync(checkedRunnable(task)));
263 >        }
264 >        Thread.sleep(testDurationMillis);
265 >        done.setRelease(true);
266 >        for (var future : futures)
267 >            checkTimedGet(future, null);
268 >
269 >        long sum = map.values().stream().mapToLong(x -> (int) x).sum();
270 >        mustEqual(expectedSum.get(), sum);
271      }
272  
273   //     public void testFailsIntentionallyForDebugging() {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines