1/*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 * Other contributors include Andrew Wright, Jeffrey Hayes,
6 * Pat Fisher, Mike Judd.
7 */
8
9package jsr166;
10
11import java.util.Arrays;
12import java.util.concurrent.atomic.AtomicIntegerArray;
13
14import junit.framework.Test;
15import junit.framework.TestSuite;
16
17public class AtomicIntegerArrayTest extends JSR166TestCase {
18    // android-note: Removed because the CTS runner does a bad job of
19    // retrying tests that have suite() declarations.
20    //
21    // public static void main(String[] args) {
22    //     main(suite(), args);
23    // }
24    // public static Test suite() {
25    //     return new TestSuite(...);
26    // }
27
28    /**
29     * constructor creates array of given size with all elements zero
30     */
31    public void testConstructor() {
32        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
33        for (int i = 0; i < SIZE; i++)
34            assertEquals(0, aa.get(i));
35    }
36
37    /**
38     * constructor with null array throws NPE
39     */
40    public void testConstructor2NPE() {
41        try {
42            int[] a = null;
43            new AtomicIntegerArray(a);
44            shouldThrow();
45        } catch (NullPointerException success) {}
46    }
47
48    /**
49     * constructor with array is of same size and has all elements
50     */
51    public void testConstructor2() {
52        int[] a = { 17, 3, -42, 99, -7 };
53        AtomicIntegerArray aa = new AtomicIntegerArray(a);
54        assertEquals(a.length, aa.length());
55        for (int i = 0; i < a.length; i++)
56            assertEquals(a[i], aa.get(i));
57    }
58
59    /**
60     * get and set for out of bound indices throw IndexOutOfBoundsException
61     */
62    public void testIndexing() {
63        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
64        for (int index : new int[] { -1, SIZE }) {
65            try {
66                aa.get(index);
67                shouldThrow();
68            } catch (IndexOutOfBoundsException success) {}
69            try {
70                aa.set(index, 1);
71                shouldThrow();
72            } catch (IndexOutOfBoundsException success) {}
73            try {
74                aa.lazySet(index, 1);
75                shouldThrow();
76            } catch (IndexOutOfBoundsException success) {}
77            try {
78                aa.compareAndSet(index, 1, 2);
79                shouldThrow();
80            } catch (IndexOutOfBoundsException success) {}
81            try {
82                aa.weakCompareAndSet(index, 1, 2);
83                shouldThrow();
84            } catch (IndexOutOfBoundsException success) {}
85            try {
86                aa.getAndAdd(index, 1);
87                shouldThrow();
88            } catch (IndexOutOfBoundsException success) {}
89            try {
90                aa.addAndGet(index, 1);
91                shouldThrow();
92            } catch (IndexOutOfBoundsException success) {}
93        }
94    }
95
96    /**
97     * get returns the last value set at index
98     */
99    public void testGetSet() {
100        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
101        for (int i = 0; i < SIZE; i++) {
102            aa.set(i, 1);
103            assertEquals(1, aa.get(i));
104            aa.set(i, 2);
105            assertEquals(2, aa.get(i));
106            aa.set(i, -3);
107            assertEquals(-3, aa.get(i));
108        }
109    }
110
111    /**
112     * get returns the last value lazySet at index by same thread
113     */
114    public void testGetLazySet() {
115        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
116        for (int i = 0; i < SIZE; i++) {
117            aa.lazySet(i, 1);
118            assertEquals(1, aa.get(i));
119            aa.lazySet(i, 2);
120            assertEquals(2, aa.get(i));
121            aa.lazySet(i, -3);
122            assertEquals(-3, aa.get(i));
123        }
124    }
125
126    /**
127     * compareAndSet succeeds in changing value if equal to expected else fails
128     */
129    public void testCompareAndSet() {
130        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
131        for (int i = 0; i < SIZE; i++) {
132            aa.set(i, 1);
133            assertTrue(aa.compareAndSet(i, 1, 2));
134            assertTrue(aa.compareAndSet(i, 2, -4));
135            assertEquals(-4, aa.get(i));
136            assertFalse(aa.compareAndSet(i, -5, 7));
137            assertEquals(-4, aa.get(i));
138            assertTrue(aa.compareAndSet(i, -4, 7));
139            assertEquals(7, aa.get(i));
140        }
141    }
142
143    /**
144     * compareAndSet in one thread enables another waiting for value
145     * to succeed
146     */
147    public void testCompareAndSetInMultipleThreads() throws Exception {
148        final AtomicIntegerArray a = new AtomicIntegerArray(1);
149        a.set(0, 1);
150        Thread t = new Thread(new CheckedRunnable() {
151            public void realRun() {
152                while (!a.compareAndSet(0, 2, 3))
153                    Thread.yield();
154            }});
155
156        t.start();
157        assertTrue(a.compareAndSet(0, 1, 2));
158        t.join(LONG_DELAY_MS);
159        assertFalse(t.isAlive());
160        assertEquals(3, a.get(0));
161    }
162
163    /**
164     * repeated weakCompareAndSet succeeds in changing value when equal
165     * to expected
166     */
167    public void testWeakCompareAndSet() {
168        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
169        for (int i = 0; i < SIZE; i++) {
170            aa.set(i, 1);
171            do {} while (!aa.weakCompareAndSet(i, 1, 2));
172            do {} while (!aa.weakCompareAndSet(i, 2, -4));
173            assertEquals(-4, aa.get(i));
174            do {} while (!aa.weakCompareAndSet(i, -4, 7));
175            assertEquals(7, aa.get(i));
176        }
177    }
178
179    /**
180     * getAndSet returns previous value and sets to given value at given index
181     */
182    public void testGetAndSet() {
183        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
184        for (int i = 0; i < SIZE; i++) {
185            aa.set(i, 1);
186            assertEquals(1, aa.getAndSet(i, 0));
187            assertEquals(0, aa.getAndSet(i, -10));
188            assertEquals(-10, aa.getAndSet(i, 1));
189        }
190    }
191
192    /**
193     * getAndAdd returns previous value and adds given value
194     */
195    public void testGetAndAdd() {
196        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
197        for (int i = 0; i < SIZE; i++) {
198            aa.set(i, 1);
199            assertEquals(1, aa.getAndAdd(i, 2));
200            assertEquals(3, aa.get(i));
201            assertEquals(3, aa.getAndAdd(i, -4));
202            assertEquals(-1, aa.get(i));
203        }
204    }
205
206    /**
207     * getAndDecrement returns previous value and decrements
208     */
209    public void testGetAndDecrement() {
210        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
211        for (int i = 0; i < SIZE; i++) {
212            aa.set(i, 1);
213            assertEquals(1, aa.getAndDecrement(i));
214            assertEquals(0, aa.getAndDecrement(i));
215            assertEquals(-1, aa.getAndDecrement(i));
216        }
217    }
218
219    /**
220     * getAndIncrement returns previous value and increments
221     */
222    public void testGetAndIncrement() {
223        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
224        for (int i = 0; i < SIZE; i++) {
225            aa.set(i, 1);
226            assertEquals(1, aa.getAndIncrement(i));
227            assertEquals(2, aa.get(i));
228            aa.set(i, -2);
229            assertEquals(-2, aa.getAndIncrement(i));
230            assertEquals(-1, aa.getAndIncrement(i));
231            assertEquals(0, aa.getAndIncrement(i));
232            assertEquals(1, aa.get(i));
233        }
234    }
235
236    /**
237     * addAndGet adds given value to current, and returns current value
238     */
239    public void testAddAndGet() {
240        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
241        for (int i = 0; i < SIZE; i++) {
242            aa.set(i, 1);
243            assertEquals(3, aa.addAndGet(i, 2));
244            assertEquals(3, aa.get(i));
245            assertEquals(-1, aa.addAndGet(i, -4));
246            assertEquals(-1, aa.get(i));
247        }
248    }
249
250    /**
251     * decrementAndGet decrements and returns current value
252     */
253    public void testDecrementAndGet() {
254        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
255        for (int i = 0; i < SIZE; i++) {
256            aa.set(i, 1);
257            assertEquals(0, aa.decrementAndGet(i));
258            assertEquals(-1, aa.decrementAndGet(i));
259            assertEquals(-2, aa.decrementAndGet(i));
260            assertEquals(-2, aa.get(i));
261        }
262    }
263
264    /**
265     * incrementAndGet increments and returns current value
266     */
267    public void testIncrementAndGet() {
268        AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
269        for (int i = 0; i < SIZE; i++) {
270            aa.set(i, 1);
271            assertEquals(2, aa.incrementAndGet(i));
272            assertEquals(2, aa.get(i));
273            aa.set(i, -2);
274            assertEquals(-1, aa.incrementAndGet(i));
275            assertEquals(0, aa.incrementAndGet(i));
276            assertEquals(1, aa.incrementAndGet(i));
277            assertEquals(1, aa.get(i));
278        }
279    }
280
281    class Counter extends CheckedRunnable {
282        final AtomicIntegerArray aa;
283        volatile int counts;
284        Counter(AtomicIntegerArray a) { aa = a; }
285        public void realRun() {
286            for (;;) {
287                boolean done = true;
288                for (int i = 0; i < aa.length(); i++) {
289                    int v = aa.get(i);
290                    assertTrue(v >= 0);
291                    if (v != 0) {
292                        done = false;
293                        if (aa.compareAndSet(i, v, v-1))
294                            ++counts;
295                    }
296                }
297                if (done)
298                    break;
299            }
300        }
301    }
302
303    /**
304     * Multiple threads using same array of counters successfully
305     * update a number of times equal to total count
306     */
307    public void testCountingInMultipleThreads() throws InterruptedException {
308        final AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
309        int countdown = 10000;
310        for (int i = 0; i < SIZE; i++)
311            aa.set(i, countdown);
312        Counter c1 = new Counter(aa);
313        Counter c2 = new Counter(aa);
314        Thread t1 = new Thread(c1);
315        Thread t2 = new Thread(c2);
316        t1.start();
317        t2.start();
318        t1.join();
319        t2.join();
320        assertEquals(c1.counts+c2.counts, SIZE * countdown);
321    }
322
323    /**
324     * a deserialized serialized array holds same values
325     */
326    public void testSerialization() throws Exception {
327        AtomicIntegerArray x = new AtomicIntegerArray(SIZE);
328        for (int i = 0; i < SIZE; i++)
329            x.set(i, -i);
330        AtomicIntegerArray y = serialClone(x);
331        assertNotSame(x, y);
332        assertEquals(x.length(), y.length());
333        for (int i = 0; i < SIZE; i++) {
334            assertEquals(x.get(i), y.get(i));
335        }
336    }
337
338    /**
339     * toString returns current value.
340     */
341    public void testToString() {
342        int[] a = { 17, 3, -42, 99, -7 };
343        AtomicIntegerArray aa = new AtomicIntegerArray(a);
344        assertEquals(Arrays.toString(a), aa.toString());
345    }
346
347}
348