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