| /* | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| /* | |
| * This file is available under and governed by the GNU General Public | |
| * License version 2 only, as published by the Free Software Foundation. | |
| * However, the following notice accompanied the original version of this | |
| * file: | |
| * | |
| * Written by 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/ | |
| */ | |
| /* | |
| * @test | |
| * @modules java.base/java.util:open | |
| * @run testng WhiteBox | |
| * @summary White box tests of implementation details | |
| */ | |
| import static org.testng.Assert.*; | |
| import org.testng.annotations.Test; | |
| import java.io.ByteArrayInputStream; | |
| import java.io.ByteArrayOutputStream; | |
| import java.io.ObjectInputStream; | |
| import java.io.ObjectOutputStream; | |
| import java.lang.invoke.MethodHandles; | |
| import java.lang.invoke.VarHandle; | |
| import java.util.ArrayDeque; | |
| import java.util.concurrent.ThreadLocalRandom; | |
| @Test | |
| public class WhiteBox { | |
| final ThreadLocalRandom rnd = ThreadLocalRandom.current(); | |
| final VarHandle ELEMENTS, HEAD, TAIL; | |
| WhiteBox() throws ReflectiveOperationException { | |
| Class<?> klazz = ArrayDeque.class; | |
| MethodHandles.Lookup lookup | |
| = MethodHandles.privateLookupIn(klazz, MethodHandles.lookup()); | |
| ELEMENTS = lookup.findVarHandle(klazz, "elements", Object[].class); | |
| HEAD = lookup.findVarHandle(klazz, "head", int.class); | |
| TAIL = lookup.findVarHandle(klazz, "tail", int.class); | |
| } | |
| Object[] elements(ArrayDeque d) { return (Object[]) ELEMENTS.get(d); } | |
| int head(ArrayDeque d) { return (int) HEAD.get(d); } | |
| int tail(ArrayDeque d) { return (int) TAIL.get(d); } | |
| void checkCapacity(ArrayDeque d, int capacity) { | |
| assertTrue(d.isEmpty()); | |
| assertEquals(0, head(d)); | |
| assertEquals(0, tail(d)); | |
| Object[] initialElements = elements(d); | |
| assertInvariants(d); | |
| for (int i = capacity; i--> 0; ) { | |
| d.add(rnd.nextInt(42)); | |
| assertSame(elements(d), initialElements); | |
| assertInvariants(d); | |
| } | |
| d.add(rnd.nextInt(42)); | |
| assertNotSame(elements(d), initialElements); | |
| assertInvariants(d); | |
| } | |
| @Test | |
| public void defaultConstructor() { | |
| checkCapacity(new ArrayDeque(), 16); | |
| } | |
| @Test | |
| public void shouldNotResizeWhenInitialCapacityProvided() { | |
| int initialCapacity = rnd.nextInt(20); | |
| checkCapacity(new ArrayDeque(initialCapacity), initialCapacity); | |
| } | |
| byte[] serialBytes(Object o) { | |
| try { | |
| ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
| ObjectOutputStream oos = new ObjectOutputStream(bos); | |
| oos.writeObject(o); | |
| oos.flush(); | |
| oos.close(); | |
| return bos.toByteArray(); | |
| } catch (Exception fail) { | |
| throw new AssertionError(fail); | |
| } | |
| } | |
| @SuppressWarnings("unchecked") | |
| <T> T serialClone(T o) { | |
| try { | |
| ObjectInputStream ois = new ObjectInputStream | |
| (new ByteArrayInputStream(serialBytes(o))); | |
| T clone = (T) ois.readObject(); | |
| assertNotSame(o, clone); | |
| assertSame(o.getClass(), clone.getClass()); | |
| return clone; | |
| } catch (Exception fail) { | |
| throw new AssertionError(fail); | |
| } | |
| } | |
| @Test | |
| public void testSerialization() { | |
| ArrayDeque[] ds = { new ArrayDeque(), new ArrayDeque(rnd.nextInt(20)) }; | |
| for (ArrayDeque d : ds) { | |
| if (rnd.nextBoolean()) d.add(99); | |
| ArrayDeque clone = serialClone(d); | |
| assertInvariants(clone); | |
| assertNotSame(elements(d), elements(clone)); | |
| assertEquals(d, clone); | |
| } | |
| } | |
| /** Checks conditions which should always be true. */ | |
| void assertInvariants(ArrayDeque d) { | |
| final Object[] elements = elements(d); | |
| final int head = head(d); | |
| final int tail = tail(d); | |
| final int capacity = elements.length; | |
| assertTrue(0 <= head && head < capacity); | |
| assertTrue(0 <= tail && tail < capacity); | |
| assertTrue(capacity > 0); | |
| assertTrue(d.size() < capacity); | |
| assertTrue((head == tail) ^ (elements[head] != null)); | |
| assertNull(elements[tail]); | |
| assertTrue((head == tail) ^ (elements[Math.floorMod(tail - 1, capacity)] != null)); | |
| } | |
| } |