1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.tests.java.util;
19
20import java.util.AbstractMap;
21import java.util.AbstractSet;
22import java.util.Collection;
23import java.util.Collections;
24import java.util.Comparator;
25import java.util.HashMap;
26import java.util.HashSet;
27import java.util.Hashtable;
28import java.util.IdentityHashMap;
29import java.util.Iterator;
30import java.util.LinkedHashMap;
31import java.util.Map;
32import java.util.Set;
33import java.util.TreeMap;
34import java.util.Vector;
35import java.util.WeakHashMap;
36
37public class AbstractMapTest extends junit.framework.TestCase {
38
39    static final String specialKey = "specialKey".intern();
40
41    static final String specialValue = "specialValue".intern();
42
43    // The impl of MyMap is not realistic, but serves to create a type
44    // that uses the default remove behavior.
45    class MyMap extends AbstractMap {
46        final Set mySet = new HashSet(1);
47
48        MyMap() {
49            mySet.add(new Map.Entry() {
50                public Object getKey() {
51                    return specialKey;
52                }
53
54                public Object getValue() {
55                    return specialValue;
56                }
57
58                public Object setValue(Object object) {
59                    return null;
60                }
61            });
62        }
63
64        public Object put(Object key, Object value) {
65            return null;
66        }
67
68        public Set entrySet() {
69            return mySet;
70        }
71    }
72
73    /**
74     * java.util.AbstractMap#keySet()
75     */
76    public void test_keySet() {
77        AbstractMap map1 = new HashMap(0);
78        assertSame("HashMap(0)", map1.keySet(), map1.keySet());
79
80        AbstractMap map2 = new HashMap(10);
81        assertSame("HashMap(10)", map2.keySet(), map2.keySet());
82
83        Map map3 = Collections.EMPTY_MAP;
84        assertSame("EMPTY_MAP", map3.keySet(), map3.keySet());
85
86        AbstractMap map4 = new IdentityHashMap(1);
87        assertSame("IdentityHashMap", map4.keySet(), map4.keySet());
88
89        AbstractMap map5 = new LinkedHashMap(122);
90        assertSame("LinkedHashMap", map5.keySet(), map5.keySet());
91
92        AbstractMap map6 = new TreeMap();
93        assertSame("TreeMap", map6.keySet(), map6.keySet());
94
95        AbstractMap map7 = new WeakHashMap();
96        assertSame("WeakHashMap", map7.keySet(), map7.keySet());
97    }
98
99    /**
100     * java.util.AbstractMap#remove(java.lang.Object)
101     */
102    public void test_removeLjava_lang_Object() {
103        Object key = new Object();
104        Object value = new Object();
105
106        AbstractMap map1 = new HashMap(0);
107        map1.put("key", value);
108        assertSame("HashMap(0)", map1.remove("key"), value);
109
110        AbstractMap map4 = new IdentityHashMap(1);
111        map4.put(key, value);
112        assertSame("IdentityHashMap", map4.remove(key), value);
113
114        AbstractMap map5 = new LinkedHashMap(122);
115        map5.put(key, value);
116        assertSame("LinkedHashMap", map5.remove(key), value);
117
118        AbstractMap map6 = new TreeMap(new Comparator() {
119            // Bogus comparator
120            public int compare(Object object1, Object object2) {
121                return 0;
122            }
123        });
124        map6.put(key, value);
125        assertSame("TreeMap", map6.remove(key), value);
126
127        AbstractMap map7 = new WeakHashMap();
128        map7.put(key, value);
129        assertSame("WeakHashMap", map7.remove(key), value);
130
131        AbstractMap aSpecialMap = new MyMap();
132        aSpecialMap.put(specialKey, specialValue);
133        Object valueOut = aSpecialMap.remove(specialKey);
134        assertSame("MyMap", valueOut, specialValue);
135    }
136
137    /**
138     * java.util.AbstractMap#clear()
139     */
140    public void test_clear() {
141        // normal clear()
142        AbstractMap map = new HashMap();
143        map.put(1, 1);
144        map.clear();
145        assertTrue(map.isEmpty());
146
147        // Special entrySet return a Set with no clear method.
148        AbstractMap myMap = new MocAbstractMap();
149        try {
150            myMap.clear();
151            fail("Should throw UnsupportedOprationException");
152        } catch (UnsupportedOperationException e) {
153            // expected
154        }
155    }
156
157    class MocAbstractMap<K, V> extends AbstractMap {
158
159        public Set entrySet() {
160            Set set = new MySet();
161            return set;
162        }
163
164        class MySet extends HashSet {
165            public void clear() {
166                throw new UnsupportedOperationException();
167            }
168        }
169    }
170
171    /**
172     * java.util.AbstractMap#containsKey(Object)
173     */
174    public void test_containsKey() {
175        AbstractMap map = new AMT();
176
177        assertFalse(map.containsKey("k"));
178        assertFalse(map.containsKey(null));
179
180        map.put("k", "v");
181        map.put("key", null);
182        map.put(null, "value");
183        map.put(null, null);
184
185        assertTrue(map.containsKey("k"));
186        assertTrue(map.containsKey("key"));
187        assertTrue(map.containsKey(null));
188    }
189
190    /**
191     * java.util.AbstractMap#containsValue(Object)
192     */
193    public void test_containValue() {
194        AbstractMap map = new AMT();
195
196        assertFalse(map.containsValue("v"));
197        assertFalse(map.containsValue(null));
198
199        map.put("k", "v");
200        map.put("key", null);
201        map.put(null, "value");
202
203        assertTrue(map.containsValue("v"));
204        assertTrue(map.containsValue("value"));
205        assertTrue(map.containsValue(null));
206    }
207
208    /**
209     * java.util.AbstractMap#get(Object)
210     */
211    public void test_get() {
212        AbstractMap map = new AMT();
213        assertNull(map.get("key"));
214        assertNull(map.get(null));
215
216        map.put("k", "v");
217        map.put("key", null);
218        map.put(null, "value");
219
220        assertEquals("v", map.get("k"));
221        assertNull(map.get("key"));
222        assertEquals("value", map.get(null));
223    }
224
225    /**
226     * java.util.AbstractMap#values()
227     */
228    public void test_values() {
229        AbstractMap map1 = new HashMap(0);
230        assertSame("HashMap(0)", map1.values(), map1.values());
231
232        AbstractMap map2 = new HashMap(10);
233        assertSame("HashMap(10)", map2.values(), map2.values());
234
235        Map map3 = Collections.EMPTY_MAP;
236        assertSame("EMPTY_MAP", map3.values(), map3.values());
237
238        AbstractMap map4 = new IdentityHashMap(1);
239        assertSame("IdentityHashMap", map4.values(), map4.values());
240
241        AbstractMap map5 = new LinkedHashMap(122);
242        assertSame("IdentityHashMap", map5.values(), map5.values());
243
244        AbstractMap map6 = new TreeMap();
245        assertSame("TreeMap", map6.values(), map6.values());
246
247        AbstractMap map7 = new WeakHashMap();
248        assertSame("WeakHashMap", map7.values(), map7.values());
249    }
250
251    /**
252     * java.util.AbstractMap#clone()
253     */
254    public void test_clone() {
255        class MyMap extends AbstractMap implements Cloneable {
256            private Map map = new HashMap();
257
258            public Set entrySet() {
259                return map.entrySet();
260            }
261
262            public Object put(Object key, Object value) {
263                return map.put(key, value);
264            }
265
266            public Map getMap() {
267                return map;
268            }
269
270            public Object clone() {
271                try {
272                    return super.clone();
273                } catch (CloneNotSupportedException e) {
274                    fail("Clone must be supported");
275                    return null;
276                }
277            }
278        }
279        MyMap map = new MyMap();
280        map.put("one", "1");
281        Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
282        assertTrue("entry not added", entry.getKey() == "one"
283                && entry.getValue() == "1");
284        MyMap mapClone = (MyMap) map.clone();
285        assertTrue("clone not shallow", map.getMap() == mapClone.getMap());
286    }
287
288    public class AMT extends AbstractMap {
289
290        // Very crude AbstractMap implementation
291        Vector values = new Vector();
292        Vector keys = new Vector();
293
294        public Set entrySet() {
295            return new AbstractSet() {
296                public Iterator iterator() {
297                    return new Iterator() {
298                        int index = 0;
299
300                        public boolean hasNext() {
301                            return index < values.size();
302                        }
303
304                        public Object next() {
305                            if (index < values.size()) {
306                                Map.Entry me = new Map.Entry() {
307                                    Object v = values.elementAt(index);
308
309                                    Object k = keys.elementAt(index);
310
311                                    public Object getKey() {
312                                        return k;
313                                    }
314
315                                    public Object getValue() {
316                                        return v;
317                                    }
318
319                                    public Object setValue(Object value) {
320                                        return null;
321                                    }
322                                };
323                                index++;
324                                return me;
325                            }
326                            return null;
327                        }
328
329                        public void remove() {
330                        }
331                    };
332                }
333
334                public int size() {
335                    return values.size();
336                }
337            };
338        }
339
340        public Object put(Object k, Object v) {
341            keys.add(k);
342            values.add(v);
343            return v;
344        }
345    }
346
347    /**
348     * {@link java.util.AbstractMap#putAll(Map)}
349     */
350    public void test_putAllLMap() {
351        Hashtable ht = new Hashtable();
352        AMT amt = new AMT();
353        ht.put("this", "that");
354        amt.putAll(ht);
355
356        assertEquals("Should be equal", amt, ht);
357    }
358
359    public void testEqualsWithNullValues() {
360        Map<String, String> a = new HashMap<String, String>();
361        a.put("a", null);
362        a.put("b", null);
363
364        Map<String, String> b = new HashMap<String, String>();
365        a.put("c", "cat");
366        a.put("d", "dog");
367
368        assertFalse(a.equals(b));
369        assertFalse(b.equals(a));
370    }
371
372    public void testNullsOnViews() {
373        Map<String, String> nullHostile = new Hashtable<String, String>();
374
375        nullHostile.put("a", "apple");
376        testNullsOnView(nullHostile.entrySet());
377
378        nullHostile.put("a", "apple");
379        testNullsOnView(nullHostile.keySet());
380
381        nullHostile.put("a", "apple");
382        testNullsOnView(nullHostile.values());
383    }
384
385    private void testNullsOnView(Collection<?> view) {
386        try {
387            assertFalse(view.contains(null));
388        } catch (NullPointerException optional) {
389        }
390
391        try {
392            assertFalse(view.remove(null));
393        } catch (NullPointerException optional) {
394        }
395
396        Set<Object> setOfNull = Collections.singleton(null);
397        assertFalse(view.equals(setOfNull));
398
399        try {
400            assertFalse(view.removeAll(setOfNull));
401        } catch (NullPointerException optional) {
402        }
403
404        try {
405            assertTrue(view.retainAll(setOfNull)); // destructive
406        } catch (NullPointerException optional) {
407        }
408    }
409
410    protected void setUp() {
411    }
412
413    protected void tearDown() {
414    }
415}
416