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.9 by jsr166, Sun Sep 29 20:40:48 2019 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines