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.2 by jsr166, Mon Jan 8 03:56:32 2018 UTC vs.
Revision 1.10 by jsr166, Mon Oct 7 21:06:02 2019 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.
# Line 95 | Line 99 | public class MapTest extends JSR166TestC
99       */
100      public void testBug8186171() {
101          if (!impl.supportsSetValue()) return;
102 +        if (!atLeastJava10()) return; // jdk9 is no longer maintained
103          final ThreadLocalRandom rnd = ThreadLocalRandom.current();
104          final boolean permitsNullValues = impl.permitsNullValues();
105          final Object v1 = (permitsNullValues && rnd.nextBoolean())
# Line 139 | Line 144 | public class MapTest extends JSR166TestC
144          assertEquals(1, m.size());
145      }
146  
147 +    /**
148 +     * "Missing" test found while investigating JDK-8210280.
149 +     * ant -Djsr166.tckTestClass=HashMapTest -Djsr166.methodFilter=testBug8210280 -Djsr166.runsPerTest=1000000 tck
150 +     */
151 +    public void testBug8210280() {
152 +        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 +    }
180 +
181 +    /**
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 +        for (int i = 0; i < size; i++)
189 +            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 +    /**
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   //     public void testFailsIntentionallyForDebugging() {
273   //         fail(impl.klazz().getSimpleName());
274   //     }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines