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.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 141 | Line 146 | public class MapTest extends JSR166TestC
146  
147      /**
148       * "Missing" test found while investigating JDK-8210280.
149 <     * See discussion on mailing list.
145 <     * TODO: randomize
149 >     * ant -Djsr166.tckTestClass=HashMapTest -Djsr166.methodFilter=testBug8210280 -Djsr166.runsPerTest=1000000 tck
150       */
151      public void testBug8210280() {
152 <        Map m = impl.emptyMap();
153 <        for (int i = 0; i < 4; i++) m.put(7 + i * 16, 0);
154 <        Map more = impl.emptyMap();
155 <        for (int i = 0; i < 128; i++) more.put(-i, 42);
156 <        m.putAll(more);
157 <        for (int i = 0; i < 4; i++) assertEquals(0, m.get(7 + i * 16));
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() {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines