HashtableTest.java revision 2ad60cfc28e14ee8f0bb038720836a4696c478ad
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 tests.api.java.util;
19
20import java.util.ArrayList;
21import java.util.Arrays;
22import java.util.Collection;
23import java.util.ConcurrentModificationException;
24import java.util.Enumeration;
25import java.util.HashSet;
26import java.util.Hashtable;
27import java.util.Iterator;
28import java.util.Map;
29import java.util.NoSuchElementException;
30import java.util.Set;
31import java.util.TreeMap;
32import java.util.Vector;
33
34import tests.api.java.util.HashMapTest.ReusableKey;
35import tests.support.Support_MapTest2;
36import tests.support.Support_UnmodifiableCollectionTest;
37
38public class HashtableTest extends junit.framework.TestCase {
39
40    private Hashtable ht10;
41
42    private Hashtable ht100;
43
44    private Hashtable htfull;
45
46    private Vector keyVector;
47
48    private Vector elmVector;
49
50    private String h10sVal;
51
52    /**
53     * @tests java.util.Hashtable#Hashtable()
54     */
55    public void test_Constructor() {
56        // Test for method java.util.Hashtable()
57        new Support_MapTest2(new Hashtable()).runTest();
58
59        Hashtable h = new Hashtable();
60
61        assertEquals("Created incorrect hashtable", 0, h.size());
62    }
63
64    /**
65     * @tests java.util.Hashtable#Hashtable(int)
66     */
67    public void test_ConstructorI() {
68        // Test for method java.util.Hashtable(int)
69        Hashtable h = new Hashtable(9);
70
71        assertEquals("Created incorrect hashtable", 0, h.size());
72
73        Hashtable empty = new Hashtable(0);
74        assertNull("Empty hashtable access", empty.get("nothing"));
75        empty.put("something", "here");
76        assertTrue("cannot get element", empty.get("something") == "here");
77    }
78
79    /**
80     * @tests java.util.Hashtable#Hashtable(int, float)
81     */
82    public void test_ConstructorIF() {
83        // Test for method java.util.Hashtable(int, float)
84        Hashtable h = new java.util.Hashtable(10, 0.5f);
85        assertEquals("Created incorrect hashtable", 0, h.size());
86
87        Hashtable empty = new Hashtable(0, 0.75f);
88        assertNull("Empty hashtable access", empty.get("nothing"));
89        empty.put("something", "here");
90        assertTrue("cannot get element", empty.get("something") == "here");
91    }
92
93    /**
94     * @tests java.util.Hashtable#Hashtable(java.util.Map)
95     */
96    public void test_ConstructorLjava_util_Map() {
97        // Test for method java.util.Hashtable(java.util.Map)
98        Map map = new TreeMap();
99        Object firstVal = "Gabba";
100        Object secondVal = new Integer(5);
101        map.put("Gah", firstVal);
102        map.put("Ooga", secondVal);
103        Hashtable ht = new Hashtable(map);
104        assertTrue("a) Incorrect Hashtable constructed",
105                ht.get("Gah") == firstVal);
106        assertTrue("b) Incorrect Hashtable constructed",
107                ht.get("Ooga") == secondVal);
108    }
109
110    /**
111     * @tests java.util.Hashtable#clear()
112     */
113    public void test_clear() {
114        // Test for method void java.util.Hashtable.clear()
115        Hashtable h = hashtableClone(htfull);
116        h.clear();
117        assertEquals("Hashtable was not cleared", 0, h.size());
118        Enumeration el = h.elements();
119        Enumeration keys = h.keys();
120        assertTrue("Hashtable improperly cleared", !el.hasMoreElements()
121                && !(keys.hasMoreElements()));
122    }
123
124    /**
125     * @tests java.util.Hashtable#clone()
126     */
127    public void test_clone() {
128        // Test for method java.lang.Object java.util.Hashtable.clone()
129
130        Hashtable h = (Hashtable) htfull.clone();
131        assertTrue("Clone different size than original", h.size() == htfull
132                .size());
133
134        Enumeration org = htfull.keys();
135        Enumeration cpy = h.keys();
136
137        String okey, ckey;
138        while (org.hasMoreElements()) {
139            assertTrue("Key comparison failed", (okey = (String) org
140                    .nextElement()).equals(ckey = (String) cpy.nextElement()));
141            assertTrue("Value comparison failed", ((String) htfull.get(okey))
142                    .equals((String) h.get(ckey)));
143        }
144        assertTrue("Copy has more keys than original", !cpy.hasMoreElements());
145    }
146
147    /**
148     * @tests java.util.Hashtable#contains(java.lang.Object)
149     */
150    public void test_containsLjava_lang_Object() {
151        // Test for method boolean
152        // java.util.Hashtable.contains(java.lang.Object)
153        assertTrue("Element not found", ht10.contains("Val 7"));
154        assertTrue("Invalid element found", !ht10.contains("ZZZZZZZZZZZZZZZZ"));
155    }
156
157    /**
158     * @tests java.util.Hashtable#containsKey(java.lang.Object)
159     */
160    public void test_containsKeyLjava_lang_Object() {
161        // Test for method boolean
162        // java.util.Hashtable.containsKey(java.lang.Object)
163
164        assertTrue("Failed to find key", htfull.containsKey("FKey 4"));
165        assertTrue("Failed to find key", !htfull.containsKey("FKey 99"));
166    }
167
168    /**
169     * @tests java.util.Hashtable#containsValue(java.lang.Object)
170     */
171    public void test_containsValueLjava_lang_Object() {
172        // Test for method boolean
173        // java.util.Hashtable.containsValue(java.lang.Object)
174        Enumeration e = elmVector.elements();
175        while (e.hasMoreElements())
176            assertTrue("Returned false for valid value", ht10.containsValue(e
177                    .nextElement()));
178        assertTrue("Returned true for invalid value", !ht10
179                .containsValue(new Object()));
180    }
181
182    /**
183     * @tests java.util.Hashtable#elements()
184     */
185    public void test_elements() {
186        // Test for method java.util.Enumeration java.util.Hashtable.elements()
187        Enumeration elms = ht10.elements();
188        int i = 0;
189        while (elms.hasMoreElements()) {
190            String s = (String) elms.nextElement();
191            assertTrue("Missing key from enumeration", elmVector.contains(s));
192            ++i;
193        }
194
195        assertEquals("All keys not retrieved", 10, ht10.size());
196    }
197
198    /**
199     * @tests java.util.Hashtable#elements()
200     */
201    public void test_elements_subtest0() {
202        // this is the reference implementation behavior
203        final Hashtable ht = new Hashtable(7);
204        ht.put("1", "a");
205        // these three elements hash to the same bucket in a 7 element Hashtable
206        ht.put("2", "b");
207        ht.put("9", "c");
208        ht.put("12", "d");
209        // Hashtable looks like:
210        // 0: "1"
211        // 1: "12" -> "9" -> "2"
212        Enumeration en = ht.elements();
213        // cache the first entry
214        en.hasMoreElements();
215        ht.remove("12");
216        ht.remove("9");
217        boolean exception = false;
218        try {
219            // cached "12"
220            Object result = en.nextElement();
221            assertNull("unexpected: " + result, result);
222            // next is removed "9"
223            result = en.nextElement();
224            assertNull("unexpected: " + result, result);
225            result = en.nextElement();
226            assertTrue("unexpected: " + result, "b".equals(result));
227        } catch (NoSuchElementException e) {
228            exception = true;
229        }
230        assertTrue("unexpected NoSuchElementException", !exception);
231    }
232
233    /**
234     * @tests java.util.Hashtable#entrySet()
235     */
236    public void test_entrySet() {
237        // Test for method java.util.Set java.util.Hashtable.entrySet()
238        Set s = ht10.entrySet();
239        Set s2 = new HashSet();
240        Iterator i = s.iterator();
241        while (i.hasNext())
242            s2.add(((Map.Entry) i.next()).getValue());
243        Enumeration e = elmVector.elements();
244        while (e.hasMoreElements())
245            assertTrue("Returned incorrect entry set", s2.contains(e
246                    .nextElement()));
247
248        assertEquals("Not synchronized",
249                "java.util.Collections$SynchronizedSet", s.getClass().getName());
250
251        boolean exception = false;
252        try {
253            ((Map.Entry) ht10.entrySet().iterator().next()).setValue(null);
254        } catch (NullPointerException e1) {
255            exception = true;
256        }
257        assertTrue(
258                "Should not be able to assign null to a Hashtable entrySet() Map.Entry",
259                exception);
260    }
261
262    /**
263     * @tests java.util.Hashtable#equals(java.lang.Object)
264     */
265    public void test_equalsLjava_lang_Object() {
266        // Test for method boolean java.util.Hashtable.equals(java.lang.Object)
267        Hashtable h = hashtableClone(ht10);
268        assertTrue("Returned false for equal tables", ht10.equals(h));
269        assertTrue("Returned true for unequal tables", !ht10.equals(htfull));
270    }
271
272    /**
273     * @tests java.util.Hashtable#get(java.lang.Object)
274     */
275    public void test_getLjava_lang_Object() {
276        // Test for method java.lang.Object
277        // java.util.Hashtable.get(java.lang.Object)
278        Hashtable h = hashtableClone(htfull);
279        assertEquals("Could not retrieve element", "FVal 2", ((String) h.get("FKey 2"))
280                );
281
282
283        // Regression for HARMONY-262
284        ReusableKey k = new ReusableKey();
285        Hashtable h2 = new Hashtable();
286        k.setKey(1);
287        h2.put(k, "value1");
288
289        k.setKey(13);
290        assertNull(h2.get(k));
291
292        k.setKey(12);
293        assertNull(h2.get(k));
294    }
295
296    /**
297     * @tests java.util.Hashtable#hashCode()
298     */
299    public void test_hashCode() {
300        // Test for method int java.util.Hashtable.hashCode()
301        Set entrySet = ht10.entrySet();
302        Iterator iterator = entrySet.iterator();
303        int expectedHash;
304        for (expectedHash = 0; iterator.hasNext(); expectedHash += iterator
305                .next().hashCode())
306            ;
307        assertTrue("Incorrect hashCode returned.  Wanted: " + expectedHash
308                + " got: " + ht10.hashCode(), expectedHash == ht10.hashCode());
309    }
310
311    /**
312     * @tests java.util.Hashtable#isEmpty()
313     */
314    public void test_isEmpty() {
315        // Test for method boolean java.util.Hashtable.isEmpty()
316
317        assertTrue("isEmpty returned incorrect value", !ht10.isEmpty());
318        assertTrue("isEmpty returned incorrect value",
319                new java.util.Hashtable().isEmpty());
320
321        final Hashtable ht = new Hashtable();
322        ht.put("0", "");
323        Thread t1 = new Thread() {
324            public void run() {
325                while (!ht.isEmpty())
326                    ;
327                ht.put("final", "");
328            }
329        };
330        t1.start();
331        for (int i = 1; i < 10000; i++) {
332            synchronized (ht) {
333                ht.remove(String.valueOf(i - 1));
334                ht.put(String.valueOf(i), "");
335            }
336            int size;
337            if ((size = ht.size()) != 1) {
338                String result = "Size is not 1: " + size + " " + ht;
339                // terminate the thread
340                ht.clear();
341                fail(result);
342            }
343        }
344        // terminate the thread
345        ht.clear();
346    }
347
348    /**
349     * @tests java.util.Hashtable#keys()
350     */
351    public void test_keys() {
352        // Test for method java.util.Enumeration java.util.Hashtable.keys()
353
354        Enumeration keys = ht10.keys();
355        int i = 0;
356        while (keys.hasMoreElements()) {
357            String s = (String) keys.nextElement();
358            assertTrue("Missing key from enumeration", keyVector.contains(s));
359            ++i;
360        }
361
362        assertEquals("All keys not retrieved", 10, ht10.size());
363    }
364
365    /**
366     * @tests java.util.Hashtable#keys()
367     */
368    public void test_keys_subtest0() {
369        // this is the reference implementation behavior
370        final Hashtable ht = new Hashtable(3);
371        ht.put("initial", "");
372        Enumeration en = ht.keys();
373        en.hasMoreElements();
374        ht.remove("initial");
375        boolean exception = false;
376        try {
377            Object result = en.nextElement();
378            assertTrue("unexpected: " + result, "initial".equals(result));
379        } catch (NoSuchElementException e) {
380            exception = true;
381        }
382        assertTrue("unexpected NoSuchElementException", !exception);
383    }
384
385    /**
386     * @tests java.util.Hashtable#keySet()
387     */
388    public void test_keySet() {
389        // Test for method java.util.Set java.util.Hashtable.keySet()
390        Set s = ht10.keySet();
391        Enumeration e = keyVector.elements();
392        while (e.hasMoreElements())
393            assertTrue("Returned incorrect key set", s
394                    .contains(e.nextElement()));
395
396        assertEquals("Not synchronized",
397                "java.util.Collections$SynchronizedSet", s.getClass().getName());
398
399        Map map = new Hashtable(101);
400        map.put(new Integer(1), "1");
401        map.put(new Integer(102), "102");
402        map.put(new Integer(203), "203");
403        Iterator it = map.keySet().iterator();
404        Integer remove1 = (Integer) it.next();
405        it.remove();
406        Integer remove2 = (Integer) it.next();
407        it.remove();
408        ArrayList list = new ArrayList(Arrays.asList(new Integer[] {
409                new Integer(1), new Integer(102), new Integer(203) }));
410        list.remove(remove1);
411        list.remove(remove2);
412        assertTrue("Wrong result", it.next().equals(list.get(0)));
413        assertEquals("Wrong size", 1, map.size());
414        assertTrue("Wrong contents", map.keySet().iterator().next().equals(
415                list.get(0)));
416
417        Map map2 = new Hashtable(101);
418        map2.put(new Integer(1), "1");
419        map2.put(new Integer(4), "4");
420        Iterator it2 = map2.keySet().iterator();
421        Integer remove3 = (Integer) it2.next();
422        Integer next;
423        if (remove3.intValue() == 1)
424            next = new Integer(4);
425        else
426            next = new Integer(1);
427        it2.hasNext();
428        it2.remove();
429        assertTrue("Wrong result 2", it2.next().equals(next));
430        assertEquals("Wrong size 2", 1, map2.size());
431        assertTrue("Wrong contents 2", map2.keySet().iterator().next().equals(
432                next));
433    }
434
435    /**
436     * @tests java.util.Hashtable#keySet()
437     */
438    public void test_keySet_subtest0() {
439        Set s1 = ht10.keySet();
440        assertTrue("should contain key", s1.remove("Key 0"));
441        assertTrue("should not contain key", !s1.remove("Key 0"));
442
443        final int iterations = 10000;
444        final Hashtable ht = new Hashtable();
445        Thread t1 = new Thread() {
446            public void run() {
447                for (int i = 0; i < iterations; i++) {
448                    ht.put(String.valueOf(i), "");
449                    ht.remove(String.valueOf(i));
450                }
451            }
452        };
453        t1.start();
454        Set set = ht.keySet();
455        for (int i = 0; i < iterations; i++) {
456            Iterator it = set.iterator();
457            try {
458                it.next();
459                it.remove();
460                int size;
461                // ensure removing with the iterator doesn't corrupt the
462                // Hashtable
463                if ((size = ht.size()) < 0) {
464                    fail("invalid size: " + size);
465                }
466            } catch (NoSuchElementException e) {
467            } catch (ConcurrentModificationException e) {
468            }
469        }
470    }
471
472    /**
473     * @tests java.util.Hashtable#keySet()
474     */
475    public void test_keySet_subtest1() {
476        // this is the reference implementation behavior
477        final Hashtable ht = new Hashtable(7);
478        ht.put("1", "a");
479        // these three elements hash to the same bucket in a 7 element Hashtable
480        ht.put("2", "b");
481        ht.put("9", "c");
482        ht.put("12", "d");
483        // Hashtable looks like:
484        // 0: "1"
485        // 1: "12" -> "9" -> "2"
486        Enumeration en = ht.elements();
487        // cache the first entry
488        en.hasMoreElements();
489        Iterator it = ht.keySet().iterator();
490        // this is mostly a copy of the test in test_elements_subtest0()
491        // test removing with the iterator does not null the values
492        while (it.hasNext()) {
493            String key = (String) it.next();
494            if ("12".equals(key) || "9".equals(key)) {
495                it.remove();
496            }
497        }
498        it.remove();
499        boolean exception = false;
500        try {
501            // cached "12"
502            Object result = en.nextElement();
503            assertTrue("unexpected: " + result, "d".equals(result));
504            // next is removed "9"
505            result = en.nextElement();
506            assertTrue("unexpected: " + result, "c".equals(result));
507            result = en.nextElement();
508            assertTrue("unexpected: " + result, "b".equals(result));
509        } catch (NoSuchElementException e) {
510            exception = true;
511        }
512        assertTrue("unexpected NoSuchElementException", !exception);
513    }
514
515    /**
516     * @tests java.util.Hashtable#put(java.lang.Object, java.lang.Object)
517     */
518    public void test_putLjava_lang_ObjectLjava_lang_Object() {
519        // Test for method java.lang.Object
520        // java.util.Hashtable.put(java.lang.Object, java.lang.Object)
521        Hashtable h = hashtableClone(ht100);
522        Integer key = new Integer(100);
523        h.put("Value 100", key);
524        assertTrue("Key/Value not inserted", h.size() == 1 && (h.contains(key)));
525
526        // Put into "full" table
527        h = hashtableClone(htfull);
528        h.put("Value 100", key);
529        assertTrue("Key/Value not inserted into full table", h.size() == 8
530                && (h.contains(key)));
531    }
532
533    /**
534     * @tests java.util.Hashtable#putAll(java.util.Map)
535     */
536    public void test_putAllLjava_util_Map() {
537        // Test for method void java.util.Hashtable.putAll(java.util.Map)
538        Hashtable h = new Hashtable();
539        h.putAll(ht10);
540        Enumeration e = keyVector.elements();
541        while (e.hasMoreElements()) {
542            Object x = e.nextElement();
543            assertTrue("Failed to put all elements", h.get(x).equals(
544                    ht10.get(x)));
545        }
546    }
547
548    /**
549     * @tests java.util.Hashtable#remove(java.lang.Object)
550     */
551    public void test_removeLjava_lang_Object() {
552        // Test for method java.lang.Object
553        // java.util.Hashtable.remove(java.lang.Object)
554        Hashtable h = hashtableClone(htfull);
555        Object k = h.remove("FKey 0");
556        assertTrue("Remove failed", !h.containsKey("FKey 0") || k == null);
557    }
558
559    /**
560     * @tests java.util.Hashtable#size()
561     */
562    public void test_size() {
563        // Test for method int java.util.Hashtable.size()
564        assertTrue("Returned invalid size", ht10.size() == 10
565                && (ht100.size() == 0));
566
567        final Hashtable ht = new Hashtable();
568        ht.put("0", "");
569        Thread t1 = new Thread() {
570            public void run() {
571                while (ht.size() > 0)
572                    ;
573                ht.put("final", "");
574            }
575        };
576        t1.start();
577        for (int i = 1; i < 10000; i++) {
578            synchronized (ht) {
579                ht.remove(String.valueOf(i - 1));
580                ht.put(String.valueOf(i), "");
581            }
582            int size;
583            if ((size = ht.size()) != 1) {
584                String result = "Size is not 1: " + size + " " + ht;
585                // terminate the thread
586                ht.clear();
587                fail(result);
588            }
589        }
590        // terminate the thread
591        ht.clear();
592    }
593
594    /**
595     * @tests java.util.Hashtable#toString()
596     */
597    public void test_toString() {
598        // Test for method java.lang.String java.util.Hashtable.toString()
599        Hashtable h = new Hashtable();
600        assertEquals("Incorrect toString for Empty table",
601                "{}", h.toString());
602
603        h.put("one", "1");
604        h.put("two", h);
605        h.put(h, "3");
606        h.put(h, h);
607        String result = h.toString();
608        assertTrue("should contain self ref", result.indexOf("(this") > -1);
609    }
610
611    /**
612     * @tests java.util.Hashtable#values()
613     */
614    public void test_values() {
615        // Test for method java.util.Collection java.util.Hashtable.values()
616        Collection c = ht10.values();
617        Enumeration e = elmVector.elements();
618        while (e.hasMoreElements())
619            assertTrue("Returned incorrect values", c.contains(e.nextElement()));
620
621        assertEquals("Not synchronized",
622                "java.util.Collections$SynchronizedCollection", c.getClass().getName());
623
624        Hashtable myHashtable = new Hashtable();
625        for (int i = 0; i < 100; i++)
626            myHashtable.put(new Integer(i), new Integer(i));
627        Collection values = myHashtable.values();
628        new Support_UnmodifiableCollectionTest(
629                "Test Returned Collection From Hashtable.values()", values)
630                .runTest();
631        values.remove(new Integer(0));
632        assertTrue(
633                "Removing from the values collection should remove from the original map",
634                !myHashtable.containsValue(new Integer(0)));
635    }
636
637    /**
638     * Regression Test for JIRA 2181
639     */
640    public void test_entrySet_remove()
641    {
642        Hashtable<String,String> hashtable = new Hashtable<String,String>();
643        hashtable.put("my.nonexistent.prop", "AAA");
644        hashtable.put( "parse.error", "BBB" );
645        Iterator<Map.Entry<String,String>> iterator =
646            hashtable.entrySet().iterator();
647        while(iterator.hasNext())
648        {
649            Map.Entry entry = iterator.next();
650            final Object value = entry.getValue();
651            if(value.equals("AAA"))
652            {
653               iterator.remove();
654            }
655        }
656        assertFalse(hashtable.containsKey("my.nonexistent.prop"));
657    }
658
659    protected Hashtable hashtableClone(Hashtable s) {
660        return (Hashtable) s.clone();
661    }
662
663    /**
664     * Sets up the fixture, for example, open a network connection. This method
665     * is called before a test is executed.
666     */
667    protected void setUp() {
668
669        ht10 = new Hashtable(10);
670        ht100 = new Hashtable(100);
671        htfull = new Hashtable(10);
672        keyVector = new Vector(10);
673        elmVector = new Vector(10);
674
675        for (int i = 0; i < 10; i++) {
676            ht10.put("Key " + i, "Val " + i);
677            keyVector.addElement("Key " + i);
678            elmVector.addElement("Val " + i);
679        }
680
681        for (int i = 0; i < 7; i++)
682            htfull.put("FKey " + i, "FVal " + i);
683    }
684
685    /**
686     * Tears down the fixture, for example, close a network connection. This
687     * method is called after a test is executed.
688     */
689    protected void tearDown() {
690    }
691}
692