1/*
2 * Written by Doug Lea and Martin Buchholz with assistance from
3 * members of JCP JSR-166 Expert Group and released to the public
4 * domain, as explained at
5 * http://creativecommons.org/publicdomain/zero/1.0/
6 */
7
8/*
9 * Source:
10 * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/tck-jsr166e/AtomicDoubleArrayTest.java?revision=1.13
11 * (Modified to adapt to guava coding conventions)
12 */
13
14package com.google.common.util.concurrent;
15
16import junit.framework.*;
17
18import java.util.Arrays;
19
20/**
21 * Unit test for {@link AtomicDoubleArray}.
22 */
23public class AtomicDoubleArrayTest extends JSR166TestCase {
24
25  private static final double[] VALUES = {
26    Double.NEGATIVE_INFINITY,
27    -Double.MAX_VALUE,
28    (double) Long.MIN_VALUE,
29    (double) Integer.MIN_VALUE,
30    -Math.PI,
31    -1.0,
32    -Double.MIN_VALUE,
33    -0.0,
34    +0.0,
35    Double.MIN_VALUE,
36    1.0,
37    Math.PI,
38    (double) Integer.MAX_VALUE,
39    (double) Long.MAX_VALUE,
40    Double.MAX_VALUE,
41    Double.POSITIVE_INFINITY,
42    Double.NaN,
43    Float.MAX_VALUE,
44  };
45
46  /** The notion of equality used by AtomicDoubleArray */
47  static boolean bitEquals(double x, double y) {
48    return Double.doubleToRawLongBits(x) == Double.doubleToRawLongBits(y);
49  }
50
51  static void assertBitEquals(double x, double y) {
52    assertEquals(Double.doubleToRawLongBits(x),
53                 Double.doubleToRawLongBits(y));
54  }
55
56  /**
57   * constructor creates array of given size with all elements zero
58   */
59  public void testConstructor() {
60    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
61    for (int i = 0; i < SIZE; i++) {
62      assertBitEquals(0.0, aa.get(i));
63    }
64  }
65
66  /**
67   * constructor with null array throws NPE
68   */
69  public void testConstructor2NPE() {
70    try {
71      double[] a = null;
72      AtomicDoubleArray aa = new AtomicDoubleArray(a);
73      shouldThrow();
74    } catch (NullPointerException success) {}
75  }
76
77  /**
78   * constructor with array is of same size and has all elements
79   */
80  public void testConstructor2() {
81    AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
82    assertEquals(VALUES.length, aa.length());
83    for (int i = 0; i < VALUES.length; i++) {
84      assertBitEquals(VALUES[i], aa.get(i));
85    }
86  }
87
88  /**
89   * constructor with empty array has size 0 and contains no elements
90   */
91  public void testConstructorEmptyArray() {
92    AtomicDoubleArray aa = new AtomicDoubleArray(new double[0]);
93    assertEquals(0, aa.length());
94    try {
95      aa.get(0);
96      shouldThrow();
97    } catch (IndexOutOfBoundsException success) {}
98  }
99
100  /**
101   * constructor with length zero has size 0 and contains no elements
102   */
103  public void testConstructorZeroLength() {
104    AtomicDoubleArray aa = new AtomicDoubleArray(0);
105    assertEquals(0, aa.length());
106    try {
107      aa.get(0);
108      shouldThrow();
109    } catch (IndexOutOfBoundsException success) {}
110  }
111
112  /**
113   * get and set for out of bound indices throw IndexOutOfBoundsException
114   */
115  public void testIndexing() {
116    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
117    for (int index : new int[] { -1, SIZE }) {
118      try {
119        aa.get(index);
120        shouldThrow();
121      } catch (IndexOutOfBoundsException success) {}
122      try {
123        aa.set(index, 1.0);
124        shouldThrow();
125      } catch (IndexOutOfBoundsException success) {}
126      try {
127        aa.lazySet(index, 1.0);
128        shouldThrow();
129      } catch (IndexOutOfBoundsException success) {}
130      try {
131        aa.compareAndSet(index, 1.0, 2.0);
132        shouldThrow();
133      } catch (IndexOutOfBoundsException success) {}
134      try {
135        aa.weakCompareAndSet(index, 1.0, 2.0);
136        shouldThrow();
137      } catch (IndexOutOfBoundsException success) {}
138      try {
139        aa.getAndAdd(index, 1.0);
140        shouldThrow();
141      } catch (IndexOutOfBoundsException success) {}
142      try {
143        aa.addAndGet(index, 1.0);
144        shouldThrow();
145      } catch (IndexOutOfBoundsException success) {}
146    }
147  }
148
149  /**
150   * get returns the last value set at index
151   */
152  public void testGetSet() {
153    AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
154    for (int i = 0; i < VALUES.length; i++) {
155      assertBitEquals(0.0, aa.get(i));
156      aa.set(i, VALUES[i]);
157      assertBitEquals(VALUES[i], aa.get(i));
158      aa.set(i, -3.0);
159      assertBitEquals(-3.0, aa.get(i));
160    }
161  }
162
163  /**
164   * get returns the last value lazySet at index by same thread
165   */
166  public void testGetLazySet() {
167    AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
168    for (int i = 0; i < VALUES.length; i++) {
169      assertBitEquals(0.0, aa.get(i));
170      aa.lazySet(i, VALUES[i]);
171      assertBitEquals(VALUES[i], aa.get(i));
172      aa.lazySet(i, -3.0);
173      assertBitEquals(-3.0, aa.get(i));
174    }
175  }
176
177  /**
178   * compareAndSet succeeds in changing value if equal to expected else fails
179   */
180  public void testCompareAndSet() {
181    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
182    for (int i : new int[] { 0, SIZE - 1}) {
183      double prev = 0.0;
184      double unused = Math.E + Math.PI;
185      for (double x : VALUES) {
186        assertBitEquals(prev, aa.get(i));
187        assertFalse(aa.compareAndSet(i, unused, x));
188        assertBitEquals(prev, aa.get(i));
189        assertTrue(aa.compareAndSet(i, prev, x));
190        assertBitEquals(x, aa.get(i));
191        prev = x;
192      }
193    }
194  }
195
196  /**
197   * compareAndSet in one thread enables another waiting for value
198   * to succeed
199   */
200
201      public void testCompareAndSetInMultipleThreads() throws InterruptedException {
202    final AtomicDoubleArray a = new AtomicDoubleArray(1);
203    a.set(0, 1.0);
204    Thread t = newStartedThread(new CheckedRunnable() {
205        public void realRun() {
206          while (!a.compareAndSet(0, 2.0, 3.0)) {
207            Thread.yield();
208          }
209        }});
210
211    assertTrue(a.compareAndSet(0, 1.0, 2.0));
212    awaitTermination(t);
213    assertBitEquals(3.0, a.get(0));
214  }
215
216  /**
217   * repeated weakCompareAndSet succeeds in changing value when equal
218   * to expected
219   */
220  public void testWeakCompareAndSet() {
221    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
222    for (int i : new int[] { 0, SIZE - 1}) {
223      double prev = 0.0;
224      double unused = Math.E + Math.PI;
225      for (double x : VALUES) {
226        assertBitEquals(prev, aa.get(i));
227        assertFalse(aa.weakCompareAndSet(i, unused, x));
228        assertBitEquals(prev, aa.get(i));
229        while (!aa.weakCompareAndSet(i, prev, x)) {
230          ;
231        }
232        assertBitEquals(x, aa.get(i));
233        prev = x;
234      }
235    }
236  }
237
238  /**
239   * getAndSet returns previous value and sets to given value at given index
240   */
241  public void testGetAndSet() {
242    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
243    for (int i : new int[] { 0, SIZE - 1}) {
244      double prev = 0.0;
245      for (double x : VALUES) {
246        assertBitEquals(prev, aa.getAndSet(i, x));
247        prev = x;
248      }
249    }
250  }
251
252  /**
253   * getAndAdd returns previous value and adds given value
254   */
255  public void testGetAndAdd() {
256    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
257    for (int i : new int[] { 0, SIZE - 1}) {
258      for (double x : VALUES) {
259        for (double y : VALUES) {
260          aa.set(i, x);
261          double z = aa.getAndAdd(i, y);
262          assertBitEquals(x, z);
263          assertBitEquals(x + y, aa.get(i));
264        }
265      }
266    }
267  }
268
269  /**
270   * addAndGet adds given value to current, and returns current value
271   */
272  public void testAddAndGet() {
273    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
274    for (int i : new int[] { 0, SIZE - 1}) {
275      for (double x : VALUES) {
276        for (double y : VALUES) {
277          aa.set(i, x);
278          double z = aa.addAndGet(i, y);
279          assertBitEquals(x + y, z);
280          assertBitEquals(x + y, aa.get(i));
281        }
282      }
283    }
284  }
285
286  static final long COUNTDOWN = 100000;
287
288  class Counter extends CheckedRunnable {
289    final AtomicDoubleArray aa;
290    volatile long counts;
291    Counter(AtomicDoubleArray a) { aa = a; }
292    public void realRun() {
293      for (;;) {
294        boolean done = true;
295        for (int i = 0; i < aa.length(); i++) {
296          double v = aa.get(i);
297          assertTrue(v >= 0);
298          if (v != 0) {
299            done = false;
300            if (aa.compareAndSet(i, v, v - 1.0)) {
301              ++counts;
302            }
303          }
304        }
305        if (done) {
306          break;
307        }
308      }
309    }
310  }
311
312  /**
313   * Multiple threads using same array of counters successfully
314   * update a number of times equal to total count
315   */
316
317      public void testCountingInMultipleThreads() throws InterruptedException {
318    final AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
319    for (int i = 0; i < SIZE; i++) {
320      aa.set(i, (double) COUNTDOWN);
321    }
322    Counter c1 = new Counter(aa);
323    Counter c2 = new Counter(aa);
324    Thread t1 = newStartedThread(c1);
325    Thread t2 = newStartedThread(c2);
326    awaitTermination(t1);
327    awaitTermination(t2);
328    assertEquals(c1.counts + c2.counts, SIZE * COUNTDOWN);
329  }
330
331  /**
332   * a deserialized serialized array holds same values
333   */
334  public void testSerialization() throws Exception {
335    AtomicDoubleArray x = new AtomicDoubleArray(SIZE);
336    for (int i = 0; i < SIZE; i++) {
337      x.set(i, (double) -i);
338    }
339    AtomicDoubleArray y = serialClone(x);
340    assertTrue(x != y);
341    assertEquals(x.length(), y.length());
342    for (int i = 0; i < SIZE; i++) {
343      assertBitEquals(x.get(i), y.get(i));
344    }
345
346    AtomicDoubleArray a = new AtomicDoubleArray(VALUES);
347    AtomicDoubleArray b = serialClone(a);
348    assertFalse(a.equals(b));
349    assertFalse(b.equals(a));
350    assertEquals(a.length(), b.length());
351    for (int i = 0; i < VALUES.length; i++) {
352      assertBitEquals(a.get(i), b.get(i));
353    }
354  }
355
356  /**
357   * toString returns current value
358   */
359  public void testToString() {
360    AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
361    assertEquals(Arrays.toString(VALUES), aa.toString());
362    assertEquals("[]", new AtomicDoubleArray(0).toString());
363    assertEquals("[]", new AtomicDoubleArray(new double[0]).toString());
364  }
365
366  /**
367   * compareAndSet treats +0.0 and -0.0 as distinct values
368   */
369  public void testDistinctZeros() {
370    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
371    for (int i : new int[] { 0, SIZE - 1}) {
372      assertFalse(aa.compareAndSet(i, -0.0, 7.0));
373      assertFalse(aa.weakCompareAndSet(i, -0.0, 7.0));
374      assertBitEquals(+0.0, aa.get(i));
375      assertTrue(aa.compareAndSet(i, +0.0, -0.0));
376      assertBitEquals(-0.0, aa.get(i));
377      assertFalse(aa.compareAndSet(i, +0.0, 7.0));
378      assertFalse(aa.weakCompareAndSet(i, +0.0, 7.0));
379      assertBitEquals(-0.0, aa.get(i));
380    }
381  }
382}
383