• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 7121314
27  * @summary AbstractCollection.toArray(T[]) doesn't return the given array
28  *           in concurrent modification.
29  * @author Ulf Zibis, David Holmes
30  */
31 
32 package test.java.util.AbstractCollection;
33 
34 import java.util.AbstractCollection;
35 import java.util.Arrays;
36 import java.util.Iterator;
37 
38 public class ToArrayTest {
39 
40     static class TestCollection<E> extends AbstractCollection<E> {
41         private final E[] elements;
42         private int[] sizes;
43         private int nextSize;
44 
TestCollection(E[] elements)45         public TestCollection(E[] elements) {
46             this.elements = elements;
47             setSizeSequence(new int[] { elements.length });
48         }
49 
50         /*
51          * Sets the values that size() will return on each use. The next
52          * call to size will return sizes[0], then sizes[1] etc. This allows us
53          * to emulate a concurrent change to the contents of the collection
54          * without having to perform concurrent changes. If sizes[n+1] contains
55          * a larger value, the collection will appear to have shrunk when
56          * iterated; if a smaller value then the collection will appear to have
57          * grown when iterated.
58          */
setSizeSequence(int... sizes)59         void setSizeSequence(int... sizes) {
60             this.sizes = sizes;
61             nextSize = 0;
62         }
63 
64         /* can change collection's size after each invocation */
65         @Override
size()66         public int size() {
67             return sizes[nextSize == sizes.length - 1 ? nextSize : nextSize++];
68         }
69 
70         @Override
iterator()71         public Iterator<E> iterator() {
72             return new Iterator<E>() {
73                 int pos = 0;
74 
75                 public boolean hasNext() {
76                     return pos < sizes[nextSize];
77                 }
78                 public E next() {
79                     return elements[pos++];
80                 }
81                 public void remove() {
82                     throw new UnsupportedOperationException(
83                             "Not supported yet.");
84                 }
85             };
86         }
87     }
88 
89     static final Object[] OBJECTS = { new Object(), new Object(), new Object() };
90     static final TestCollection<?> CANDIDATE = new TestCollection<Object>(OBJECTS);
91     static final int CAP = OBJECTS.length; // capacity of the CANDIDATE
92     static final int LAST = CAP - 1; // last possible array index
93     Object[] a;
94     Object[] res;
95 
last()96     int last() {
97         return a.length - 1;
98     }
99 
test()100     protected void test() throws Throwable {
101         // Check array type conversion
102         res = new TestCollection<>(new Object[] { "1", "2" }).toArray(new String[0]);
103         check(res instanceof String[]);
104         check(res.length == 2);
105         check(res[1] == "2");
106 
107         // Check incompatible type of target array
108         try {
109             res = CANDIDATE.toArray(new String[CAP]);
110             check(false);
111         } catch (Throwable t) {
112             check(t instanceof ArrayStoreException);
113         }
114 
115         // Check more elements than a.length
116         a = new Object[CAP - 1]; // appears too small
117         res = CANDIDATE.toArray(a);
118         check(res != a);
119         check(res[LAST] != null);
120 
121         // Check equal elements as a.length
122         a = new Object[CAP]; // appears to match
123         res = CANDIDATE.toArray(a);
124         check(res == a);
125         check(res[last()] != null);
126 
127         // Check equal elements as a.length
128         a = new Object[CAP + 1]; // appears too big
129         res = CANDIDATE.toArray(a);
130         check(res == a);
131         check(res[last()] == null);
132 
133         // Check less elements than expected, but more than a.length
134         a = new Object[CAP - 2]; // appears too small
135         CANDIDATE.setSizeSequence(CAP, CAP - 1);
136         res = CANDIDATE.toArray(a);
137         check(res != a);
138         check(res.length == CAP - 1);
139         check(res[LAST - 1] != null);
140 
141         // Check less elements than expected, but equal as a.length
142         a = Arrays.copyOf(OBJECTS, CAP); // appears to match
143         CANDIDATE.setSizeSequence(CAP, CAP - 1);
144         res = CANDIDATE.toArray(a);
145         check(res == a);
146         check(res[last()] == null);
147 
148         // Check more elements than expected and more than a.length
149         a = new Object[CAP - 1]; // appears to match
150         CANDIDATE.setSizeSequence(CAP - 1, CAP);
151         res = CANDIDATE.toArray(a);
152         check(res != a);
153         check(res[LAST] != null);
154 
155         // Check more elements than expected, but equal as a.length
156         a = new Object[CAP - 1]; // appears to match
157         CANDIDATE.setSizeSequence(CAP - 2, CAP - 1);
158         res = CANDIDATE.toArray(a);
159         check(res == a);
160         check(res[last()] != null);
161 
162         // Check more elements than expected, but less than a.length
163         a = Arrays.copyOf(OBJECTS, CAP); // appears to match
164         CANDIDATE.setSizeSequence(CAP - 2, CAP - 1);
165         res = CANDIDATE.toArray(a);
166         check(res == a);
167         check(res[last()] == null);
168 
169         test_7121314();
170     }
171 
172     /*
173      * Major target of this testcase, bug 7121314.
174      */
test_7121314()175     protected void test_7121314() throws Throwable {
176         // Check equal elements as a.length, but less than expected
177         a = new Object[CAP - 1]; // appears too small
178         CANDIDATE.setSizeSequence(CAP, CAP - 1);
179         res = CANDIDATE.toArray(a);
180         check(res == a);
181         check(res[last()] != null);
182 
183         // Check less elements than a.length and less than expected
184         a = Arrays.copyOf(OBJECTS, CAP - 1); // appears too small
185         CANDIDATE.setSizeSequence(CAP, CAP - 2);
186         res = CANDIDATE.toArray(a);
187         check(res == a);
188         check(res[last()] == null);
189 
190     }
191 
main(String[] args)192     public static void main(String[] args) throws Throwable {
193         ToArrayTest testcase = new ToArrayTest();
194         try {
195             testcase.test();
196         } catch (Throwable t) {
197             unexpected(t);
198         }
199 
200         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
201         if (failed > 0) throw new Exception("Some tests failed");
202     }
203 
204     //--------------------- Infrastructure ---------------------------
205     static volatile int passed = 0, failed = 0;
pass()206     static void pass() { passed++; }
fail()207     static void fail() { failed++; Thread.dumpStack(); }
fail(String msg)208     static void fail(String msg) { System.out.println(msg); fail(); }
unexpected(Throwable t)209     static void unexpected(Throwable t) { failed++; t.printStackTrace(); }
check(boolean cond)210     static void check(boolean cond) { if (cond) pass(); else fail(); }
equal(Object x, Object y)211     static void equal(Object x, Object y) {
212         if (x == null ? y == null : x.equals(y)) pass();
213         else {System.out.println(x + " not equal to " + y); fail(); }
214     }
215 }
216