/*
* Written by Doug Lea and Martin Buchholz with assistance from
* members of JCP JSR-166 Expert Group and released to the public
* domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/*
* Source:
* http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/tck-jsr166e/AtomicDoubleArrayTest.java?revision=1.13
* (Modified to adapt to guava coding conventions)
*/
package com.google.common.util.concurrent;
import junit.framework.*;
import java.util.Arrays;
/**
* Unit test for {@link AtomicDoubleArray}.
*/
public class AtomicDoubleArrayTest extends JSR166TestCase {
private static final double[] VALUES = {
Double.NEGATIVE_INFINITY,
-Double.MAX_VALUE,
(double) Long.MIN_VALUE,
(double) Integer.MIN_VALUE,
-Math.PI,
-1.0,
-Double.MIN_VALUE,
-0.0,
+0.0,
Double.MIN_VALUE,
1.0,
Math.PI,
(double) Integer.MAX_VALUE,
(double) Long.MAX_VALUE,
Double.MAX_VALUE,
Double.POSITIVE_INFINITY,
Double.NaN,
Float.MAX_VALUE,
};
/** The notion of equality used by AtomicDoubleArray */
static boolean bitEquals(double x, double y) {
return Double.doubleToRawLongBits(x) == Double.doubleToRawLongBits(y);
}
static void assertBitEquals(double x, double y) {
assertEquals(Double.doubleToRawLongBits(x),
Double.doubleToRawLongBits(y));
}
/**
* constructor creates array of given size with all elements zero
*/
public void testConstructor() {
AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
for (int i = 0; i < SIZE; i++) {
assertBitEquals(0.0, aa.get(i));
}
}
/**
* constructor with null array throws NPE
*/
public void testConstructor2NPE() {
try {
double[] a = null;
AtomicDoubleArray aa = new AtomicDoubleArray(a);
shouldThrow();
} catch (NullPointerException success) {}
}
/**
* constructor with array is of same size and has all elements
*/
public void testConstructor2() {
AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
assertEquals(VALUES.length, aa.length());
for (int i = 0; i < VALUES.length; i++) {
assertBitEquals(VALUES[i], aa.get(i));
}
}
/**
* constructor with empty array has size 0 and contains no elements
*/
public void testConstructorEmptyArray() {
AtomicDoubleArray aa = new AtomicDoubleArray(new double[0]);
assertEquals(0, aa.length());
try {
aa.get(0);
shouldThrow();
} catch (IndexOutOfBoundsException success) {}
}
/**
* constructor with length zero has size 0 and contains no elements
*/
public void testConstructorZeroLength() {
AtomicDoubleArray aa = new AtomicDoubleArray(0);
assertEquals(0, aa.length());
try {
aa.get(0);
shouldThrow();
} catch (IndexOutOfBoundsException success) {}
}
/**
* get and set for out of bound indices throw IndexOutOfBoundsException
*/
public void testIndexing() {
AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
for (int index : new int[] { -1, SIZE }) {
try {
aa.get(index);
shouldThrow();
} catch (IndexOutOfBoundsException success) {}
try {
aa.set(index, 1.0);
shouldThrow();
} catch (IndexOutOfBoundsException success) {}
try {
aa.lazySet(index, 1.0);
shouldThrow();
} catch (IndexOutOfBoundsException success) {}
try {
aa.compareAndSet(index, 1.0, 2.0);
shouldThrow();
} catch (IndexOutOfBoundsException success) {}
try {
aa.weakCompareAndSet(index, 1.0, 2.0);
shouldThrow();
} catch (IndexOutOfBoundsException success) {}
try {
aa.getAndAdd(index, 1.0);
shouldThrow();
} catch (IndexOutOfBoundsException success) {}
try {
aa.addAndGet(index, 1.0);
shouldThrow();
} catch (IndexOutOfBoundsException success) {}
}
}
/**
* get returns the last value set at index
*/
public void testGetSet() {
AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
for (int i = 0; i < VALUES.length; i++) {
assertBitEquals(0.0, aa.get(i));
aa.set(i, VALUES[i]);
assertBitEquals(VALUES[i], aa.get(i));
aa.set(i, -3.0);
assertBitEquals(-3.0, aa.get(i));
}
}
/**
* get returns the last value lazySet at index by same thread
*/
public void testGetLazySet() {
AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
for (int i = 0; i < VALUES.length; i++) {
assertBitEquals(0.0, aa.get(i));
aa.lazySet(i, VALUES[i]);
assertBitEquals(VALUES[i], aa.get(i));
aa.lazySet(i, -3.0);
assertBitEquals(-3.0, aa.get(i));
}
}
/**
* compareAndSet succeeds in changing value if equal to expected else fails
*/
public void testCompareAndSet() {
AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
for (int i : new int[] { 0, SIZE - 1}) {
double prev = 0.0;
double unused = Math.E + Math.PI;
for (double x : VALUES) {
assertBitEquals(prev, aa.get(i));
assertFalse(aa.compareAndSet(i, unused, x));
assertBitEquals(prev, aa.get(i));
assertTrue(aa.compareAndSet(i, prev, x));
assertBitEquals(x, aa.get(i));
prev = x;
}
}
}
/**
* compareAndSet in one thread enables another waiting for value
* to succeed
*/
public void testCompareAndSetInMultipleThreads() throws InterruptedException {
final AtomicDoubleArray a = new AtomicDoubleArray(1);
a.set(0, 1.0);
Thread t = newStartedThread(new CheckedRunnable() {
public void realRun() {
while (!a.compareAndSet(0, 2.0, 3.0)) {
Thread.yield();
}
}});
assertTrue(a.compareAndSet(0, 1.0, 2.0));
awaitTermination(t);
assertBitEquals(3.0, a.get(0));
}
/**
* repeated weakCompareAndSet succeeds in changing value when equal
* to expected
*/
public void testWeakCompareAndSet() {
AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
for (int i : new int[] { 0, SIZE - 1}) {
double prev = 0.0;
double unused = Math.E + Math.PI;
for (double x : VALUES) {
assertBitEquals(prev, aa.get(i));
assertFalse(aa.weakCompareAndSet(i, unused, x));
assertBitEquals(prev, aa.get(i));
while (!aa.weakCompareAndSet(i, prev, x)) {
;
}
assertBitEquals(x, aa.get(i));
prev = x;
}
}
}
/**
* getAndSet returns previous value and sets to given value at given index
*/
public void testGetAndSet() {
AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
for (int i : new int[] { 0, SIZE - 1}) {
double prev = 0.0;
for (double x : VALUES) {
assertBitEquals(prev, aa.getAndSet(i, x));
prev = x;
}
}
}
/**
* getAndAdd returns previous value and adds given value
*/
public void testGetAndAdd() {
AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
for (int i : new int[] { 0, SIZE - 1}) {
for (double x : VALUES) {
for (double y : VALUES) {
aa.set(i, x);
double z = aa.getAndAdd(i, y);
assertBitEquals(x, z);
assertBitEquals(x + y, aa.get(i));
}
}
}
}
/**
* addAndGet adds given value to current, and returns current value
*/
public void testAddAndGet() {
AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
for (int i : new int[] { 0, SIZE - 1}) {
for (double x : VALUES) {
for (double y : VALUES) {
aa.set(i, x);
double z = aa.addAndGet(i, y);
assertBitEquals(x + y, z);
assertBitEquals(x + y, aa.get(i));
}
}
}
}
static final long COUNTDOWN = 100000;
class Counter extends CheckedRunnable {
final AtomicDoubleArray aa;
volatile long counts;
Counter(AtomicDoubleArray a) { aa = a; }
public void realRun() {
for (;;) {
boolean done = true;
for (int i = 0; i < aa.length(); i++) {
double v = aa.get(i);
assertTrue(v >= 0);
if (v != 0) {
done = false;
if (aa.compareAndSet(i, v, v - 1.0)) {
++counts;
}
}
}
if (done) {
break;
}
}
}
}
/**
* Multiple threads using same array of counters successfully
* update a number of times equal to total count
*/
public void testCountingInMultipleThreads() throws InterruptedException {
final AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
for (int i = 0; i < SIZE; i++) {
aa.set(i, (double) COUNTDOWN);
}
Counter c1 = new Counter(aa);
Counter c2 = new Counter(aa);
Thread t1 = newStartedThread(c1);
Thread t2 = newStartedThread(c2);
awaitTermination(t1);
awaitTermination(t2);
assertEquals(c1.counts + c2.counts, SIZE * COUNTDOWN);
}
/**
* a deserialized serialized array holds same values
*/
public void testSerialization() throws Exception {
AtomicDoubleArray x = new AtomicDoubleArray(SIZE);
for (int i = 0; i < SIZE; i++) {
x.set(i, (double) -i);
}
AtomicDoubleArray y = serialClone(x);
assertTrue(x != y);
assertEquals(x.length(), y.length());
for (int i = 0; i < SIZE; i++) {
assertBitEquals(x.get(i), y.get(i));
}
AtomicDoubleArray a = new AtomicDoubleArray(VALUES);
AtomicDoubleArray b = serialClone(a);
assertFalse(a.equals(b));
assertFalse(b.equals(a));
assertEquals(a.length(), b.length());
for (int i = 0; i < VALUES.length; i++) {
assertBitEquals(a.get(i), b.get(i));
}
}
/**
* toString returns current value
*/
public void testToString() {
AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
assertEquals(Arrays.toString(VALUES), aa.toString());
assertEquals("[]", new AtomicDoubleArray(0).toString());
assertEquals("[]", new AtomicDoubleArray(new double[0]).toString());
}
/**
* compareAndSet treats +0.0 and -0.0 as distinct values
*/
public void testDistinctZeros() {
AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
for (int i : new int[] { 0, SIZE - 1}) {
assertFalse(aa.compareAndSet(i, -0.0, 7.0));
assertFalse(aa.weakCompareAndSet(i, -0.0, 7.0));
assertBitEquals(+0.0, aa.get(i));
assertTrue(aa.compareAndSet(i, +0.0, -0.0));
assertBitEquals(-0.0, aa.get(i));
assertFalse(aa.compareAndSet(i, +0.0, 7.0));
assertFalse(aa.weakCompareAndSet(i, +0.0, 7.0));
assertBitEquals(-0.0, aa.get(i));
}
}
}