1 /*
2  * Copyright (c) 2007, 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 6409434
27  * @summary Test behavior of nulls in checked collections
28  */
29 
30 package test.java.util.Collections;
31 
32 import java.util.AbstractMap;
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.Comparator;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.Map;
40 import java.util.TreeSet;
41 
42 import static java.util.Collections.singleton;
43 import static java.util.Collections.singletonMap;
44 
45 @SuppressWarnings({"unchecked","serial"})
46 public class CheckedNull {
47 
test(String[] args)48     void test(String[] args) throws Throwable {
49         testCollection(Collections.checkedCollection(
50                            new ArrayList<String>(), String.class));
51         testCollection(Collections.checkedList(
52                            new ArrayList<String>(), String.class));
53         testCollection(Collections.checkedSet(
54                            new HashSet<String>(), String.class));
55 
56         final Comparator nullLow = new Comparator() {
57                 public int compare(Object x, Object y) {
58                     return x == y ?  0 :
59                         x == null ? -1 :
60                         y == null ?  1 :
61                         ((Comparable)x).compareTo(y); }};
62         testCollection(Collections.checkedSortedSet(
63                            new TreeSet<String>(nullLow), String.class));
64 
65         testMap(Collections.checkedMap(
66                     new HashMap<String, String>(),
67                     String.class, String.class));
68     }
69 
cce(F f)70     ClassCastException cce(F f) {
71         try { f.f(); fail(); return null; }
72         catch (ClassCastException cce) { pass(); return cce; }
73         catch (Throwable t) { unexpected(t); return null; }
74     }
75 
equalCCE(F .... fs)76     void equalCCE(F ... fs) {
77         String detailMessage = null;
78         for (F f : fs)
79             if (detailMessage == null)
80                 detailMessage = cce(f).getMessage();
81             else
82                 equal(detailMessage, cce(f).getMessage());
83     }
84 
add(Collection c, Object o)85     void add(Collection c, Object o) {
86         int s = c.size();
87         check(! c.contains(o));
88         check(c.add(o));
89         check(c.contains(o));
90         equal(c.size(), s+1);
91         check(c.remove(o));
92         check(! c.contains(o));
93         check(c.addAll(singleton(o)));
94         check(c.contains(o));
95         equal(c.size(), s+1);
96         check(c.remove(o));
97         equal(c.size(), s);
98     }
99 
testCollection(final Collection c)100     void testCollection(final Collection c) {
101         try {
102             check(c.isEmpty());
103             add(c, null);
104             add(c, "foo");
105 
106             check(c.add("bar"));
107             add(c, null);
108             add(c, "foo");
109 
110             equalCCE(
111                 new F(){void f(){ c.add(1); }},
112                 new F(){void f(){ c.addAll(singleton(1)); }});
113 
114         } catch (Throwable t) { unexpected(t); }
115     }
116 
put(Map m, Object k, Object v)117     void put(Map m, Object k, Object v) {
118         int s = m.size();
119         check(! m.containsKey(k));
120         check(! m.containsValue(v));
121         equal(null, m.put(k, v));
122         check(m.containsKey(k));
123         check(m.containsValue(v));
124         equal(m.size(), s+1);
125         equal(v, m.remove(k));
126         check(! m.containsKey(k));
127         check(! m.containsValue(v));
128         m.putAll(singletonMap(k,v));
129         check(m.containsKey(k));
130         check(m.containsValue(v));
131         equal(m.size(), s+1);
132         equal(v,m.remove(k));
133         equal(m.size(), s);
134     }
135 
testMap(final Map m)136     void testMap(final Map m) {
137         try {
138             check(m.isEmpty());
139 
140             put(m, "foo", null);
141             put(m, null, "foo");
142             put(m, null, null);
143             put(m, "foo", "bar");
144 
145             m.put("a", "b");
146 
147             put(m, "foo", null);
148             put(m, null, "foo");
149             put(m, null, null);
150             put(m, "foo", "bar");
151 
152             equalCCE(
153                 new F(){void f(){ m.put(1, "foo"); }},
154                 new F(){void f(){ m.putAll(singletonMap(1, "foo")); }});
155 
156             final Collection cheater = new ArrayList() {
157                     public boolean contains(Object o) {
158                         if (o instanceof Map.Entry)
159                             ((Map.Entry)o).setValue(1);
160                         return false; }};
161 
162             equalCCE(
163                 new F(){void f(){ m.put("foo", 1); }},
164                 new F(){void f(){ m.putAll(singletonMap("foo", 1)); }},
165                 new F(){void f(){
166                     ((Map.Entry)m.entrySet().iterator().next()).setValue(1); }},
167                 new F(){void f(){
168                     m.entrySet().removeAll(cheater);}},
169                 new F(){void f(){
170                     m.entrySet().retainAll(cheater);}});
171 
172             equalCCE(
173                 new F(){void f(){ m.put(3, 1); }},
174                 new F(){void f(){ m.putAll(singletonMap(3, 1)); }});
175 
176             equal(m.size(), 1);
177             equal(m.keySet(), singleton("a"));
178             equal(m.entrySet(),
179                   singleton(new AbstractMap.SimpleImmutableEntry("a","b")));
180 
181         } catch (Throwable t) { unexpected(t); }
182     }
183 
184     //--------------------- Infrastructure ---------------------------
185     volatile int passed = 0, failed = 0;
pass()186     void pass() {passed++;}
fail()187     void fail() {failed++; Thread.dumpStack();}
fail(String msg)188     void fail(String msg) {System.err.println(msg); fail();}
unexpected(Throwable t)189     void unexpected(Throwable t) {failed++; t.printStackTrace();}
check(boolean cond)190     void check(boolean cond) {if (cond) pass(); else fail();}
equal(Object x, Object y)191     void equal(Object x, Object y) {
192         if (x == null ? y == null : x.equals(y)) pass();
193         else fail(x + " not equal to " + y);}
main(String[] args)194     public static void main(String[] args) throws Throwable {
195         new CheckedNull().instanceMain(args);}
instanceMain(String[] args)196     void instanceMain(String[] args) throws Throwable {
197         try {test(args);} catch (Throwable t) {unexpected(t);}
198         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
199         if (failed > 0) throw new AssertionError("Some tests failed");}
f()200     abstract class F {abstract void f() throws Throwable;}
201 }
202