1 |
/* |
2 |
* Written by Martin Buchholz with assistance from members of JCP |
3 |
* JSR-166 Expert Group and released to the public domain, as |
4 |
* explained at http://creativecommons.org/publicdomain/zero/1.0/ |
5 |
*/ |
6 |
|
7 |
/* |
8 |
* @test |
9 |
* @modules java.base/java.util:open |
10 |
* @run testng WhiteBox |
11 |
* @summary White box tests of implementation details |
12 |
*/ |
13 |
|
14 |
import static org.testng.Assert.*; |
15 |
import org.testng.annotations.Test; |
16 |
|
17 |
import java.io.ByteArrayInputStream; |
18 |
import java.io.ByteArrayOutputStream; |
19 |
import java.io.ObjectInputStream; |
20 |
import java.io.ObjectOutputStream; |
21 |
import java.lang.invoke.MethodHandles; |
22 |
import java.lang.invoke.VarHandle; |
23 |
import java.util.ArrayDeque; |
24 |
import java.util.concurrent.ThreadLocalRandom; |
25 |
|
26 |
@Test |
27 |
public class WhiteBox { |
28 |
final ThreadLocalRandom rnd = ThreadLocalRandom.current(); |
29 |
final VarHandle ELEMENTS, HEAD, TAIL; |
30 |
|
31 |
WhiteBox() throws ReflectiveOperationException { |
32 |
Class<?> klazz = ArrayDeque.class; |
33 |
MethodHandles.Lookup lookup |
34 |
= MethodHandles.privateLookupIn(klazz, MethodHandles.lookup()); |
35 |
ELEMENTS = lookup.findVarHandle(klazz, "elements", Object[].class); |
36 |
HEAD = lookup.findVarHandle(klazz, "head", int.class); |
37 |
TAIL = lookup.findVarHandle(klazz, "tail", int.class); |
38 |
} |
39 |
|
40 |
Object[] elements(ArrayDeque d) { return (Object[]) ELEMENTS.get(d); } |
41 |
int head(ArrayDeque d) { return (int) HEAD.get(d); } |
42 |
int tail(ArrayDeque d) { return (int) TAIL.get(d); } |
43 |
|
44 |
void checkCapacity(ArrayDeque d, int capacity) { |
45 |
assertTrue(d.isEmpty()); |
46 |
assertEquals(0, head(d)); |
47 |
assertEquals(0, tail(d)); |
48 |
Object[] initialElements = elements(d); |
49 |
|
50 |
assertInvariants(d); |
51 |
for (int i = capacity; i--> 0; ) { |
52 |
d.add(rnd.nextInt(42)); |
53 |
assertSame(elements(d), initialElements); |
54 |
assertInvariants(d); |
55 |
} |
56 |
|
57 |
d.add(rnd.nextInt(42)); |
58 |
assertNotSame(elements(d), initialElements); |
59 |
assertInvariants(d); |
60 |
} |
61 |
|
62 |
@Test |
63 |
public void defaultConstructor() { |
64 |
checkCapacity(new ArrayDeque(), 16); |
65 |
} |
66 |
|
67 |
@Test |
68 |
public void shouldNotResizeWhenInitialCapacityProvided() { |
69 |
int initialCapacity = rnd.nextInt(20); |
70 |
checkCapacity(new ArrayDeque(initialCapacity), initialCapacity); |
71 |
} |
72 |
|
73 |
byte[] serialBytes(Object o) { |
74 |
try { |
75 |
ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
76 |
ObjectOutputStream oos = new ObjectOutputStream(bos); |
77 |
oos.writeObject(o); |
78 |
oos.flush(); |
79 |
oos.close(); |
80 |
return bos.toByteArray(); |
81 |
} catch (Exception fail) { |
82 |
throw new AssertionError(fail); |
83 |
} |
84 |
} |
85 |
|
86 |
@SuppressWarnings("unchecked") |
87 |
<T> T serialClone(T o) { |
88 |
try { |
89 |
ObjectInputStream ois = new ObjectInputStream |
90 |
(new ByteArrayInputStream(serialBytes(o))); |
91 |
T clone = (T) ois.readObject(); |
92 |
assertNotSame(o, clone); |
93 |
assertSame(o.getClass(), clone.getClass()); |
94 |
return clone; |
95 |
} catch (Exception fail) { |
96 |
throw new AssertionError(fail); |
97 |
} |
98 |
} |
99 |
|
100 |
@Test |
101 |
public void testSerialization() { |
102 |
ArrayDeque[] ds = { new ArrayDeque(), new ArrayDeque(rnd.nextInt(20)) }; |
103 |
for (ArrayDeque d : ds) { |
104 |
if (rnd.nextBoolean()) d.add(99); |
105 |
ArrayDeque clone = serialClone(d); |
106 |
assertInvariants(clone); |
107 |
assertNotSame(elements(d), elements(clone)); |
108 |
assertEquals(d, clone); |
109 |
} |
110 |
} |
111 |
|
112 |
/** Checks conditions which should always be true. */ |
113 |
void assertInvariants(ArrayDeque d) { |
114 |
final Object[] elements = elements(d); |
115 |
final int head = head(d); |
116 |
final int tail = tail(d); |
117 |
final int capacity = elements.length; |
118 |
assertTrue(0 <= head && head < capacity); |
119 |
assertTrue(0 <= tail && tail < capacity); |
120 |
assertTrue(capacity > 0); |
121 |
assertTrue(d.size() < capacity); |
122 |
assertTrue((head == tail) ^ (elements[head] != null)); |
123 |
assertNull(elements[tail]); |
124 |
assertTrue((head == tail) ^ (elements[Math.floorMod(tail - 1, capacity)] != null)); |
125 |
} |
126 |
} |