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 tests.support.Support_MapTest2;
21import tests.support.Support_UnmodifiableCollectionTest;
22import java.util.ArrayList;
23import java.util.Arrays;
24import java.util.Collection;
25import java.util.ConcurrentModificationException;
26import java.util.Enumeration;
27import java.util.HashSet;
28import java.util.Hashtable;
29import java.util.Iterator;
30import java.util.Map;
31import java.util.NoSuchElementException;
32import java.util.Set;
33import java.util.TreeMap;
34import java.util.Vector;
35
36public class HashtableTest extends junit.framework.TestCase {
37
38    private Hashtable ht10;
39
40    private Hashtable ht100;
41
42    private Hashtable htfull;
43
44    private Vector keyVector;
45
46    private Vector elmVector;
47
48    private String h10sVal;
49
50    /**
51     * java.util.Hashtable#Hashtable()
52     */
53    public void test_Constructor() {
54        // Test for method java.util.Hashtable()
55        new Support_MapTest2(new Hashtable()).runTest();
56
57        Hashtable h = new Hashtable();
58
59        assertEquals("Created incorrect hashtable", 0, h.size());
60    }
61
62    /**
63     * java.util.Hashtable#Hashtable(int)
64     */
65    public void test_ConstructorI() {
66        // Test for method java.util.Hashtable(int)
67        Hashtable h = new Hashtable(9);
68
69        assertEquals("Created incorrect hashtable", 0, h.size());
70
71        Hashtable empty = new Hashtable(0);
72        assertNull("Empty hashtable access", empty.get("nothing"));
73        empty.put("something", "here");
74        assertTrue("cannot get element", empty.get("something") == "here");
75    }
76
77    /**
78     * java.util.Hashtable#Hashtable(int, float)
79     */
80    public void test_ConstructorIF() {
81        // Test for method java.util.Hashtable(int, float)
82        Hashtable h = new java.util.Hashtable(10, 0.5f);
83        assertEquals("Created incorrect hashtable", 0, h.size());
84
85        Hashtable empty = new Hashtable(0, 0.75f);
86        assertNull("Empty hashtable access", empty.get("nothing"));
87        empty.put("something", "here");
88        assertTrue("cannot get element", empty.get("something") == "here");
89
90        try {
91            new Hashtable(-1, 0.75f);
92            fail("IllegalArgumentException expected");
93        } catch (IllegalArgumentException e) {
94            //expected
95        }
96
97        try {
98            new Hashtable(0, -0.75f);
99            fail("IllegalArgumentException expected");
100        } catch (IllegalArgumentException e) {
101            //expected
102        }
103    }
104
105    /**
106     * java.util.Hashtable#Hashtable(java.util.Map)
107     */
108    public void test_ConstructorLjava_util_Map() {
109        // Test for method java.util.Hashtable(java.util.Map)
110        Map map = new TreeMap();
111        Object firstVal = "Gabba";
112        Object secondVal = new Integer(5);
113        map.put("Gah", firstVal);
114        map.put("Ooga", secondVal);
115        Hashtable ht = new Hashtable(map);
116        assertTrue("a) Incorrect Hashtable constructed",
117                ht.get("Gah") == firstVal);
118        assertTrue("b) Incorrect Hashtable constructed",
119                ht.get("Ooga") == secondVal);
120
121        try {
122            new Hashtable(null);
123            fail("NullPointerException expected");
124        } catch (NullPointerException e) {
125            //expected
126        }
127    }
128
129    public void test_HashTable_Constructor() {
130        Hashtable hashTable = new Hashtable();
131        hashTable.put(hashTable, hashTable.keySet());
132        new Hashtable(hashTable);
133    }
134
135    /**
136     * java.util.Hashtable#clear()
137     */
138    public void test_clear() {
139        // Test for method void java.util.Hashtable.clear()
140        Hashtable h = hashtableClone(htfull);
141        h.clear();
142        assertEquals("Hashtable was not cleared", 0, h.size());
143        Enumeration el = h.elements();
144        Enumeration keys = h.keys();
145        assertTrue("Hashtable improperly cleared", !el.hasMoreElements()
146                && !(keys.hasMoreElements()));
147    }
148
149    /**
150     * java.util.Hashtable#clone()
151     */
152    public void test_clone() {
153        // Test for method java.lang.Object java.util.Hashtable.clone()
154
155        Hashtable h = (Hashtable) htfull.clone();
156        assertTrue("Clone different size than original", h.size() == htfull
157                .size());
158
159        Enumeration org = htfull.keys();
160        Enumeration cpy = h.keys();
161
162        String okey, ckey;
163        while (org.hasMoreElements()) {
164            assertTrue("Key comparison failed", (okey = (String) org
165                    .nextElement()).equals(ckey = (String) cpy.nextElement()));
166            assertTrue("Value comparison failed", ((String) htfull.get(okey))
167                    .equals((String) h.get(ckey)));
168        }
169        assertTrue("Copy has more keys than original", !cpy.hasMoreElements());
170    }
171
172    /**
173     * java.util.Hashtable#contains(java.lang.Object)
174     */
175    public void test_containsLjava_lang_Object() {
176        // Test for method boolean
177        // java.util.Hashtable.contains(java.lang.Object)
178        assertTrue("Element not found", ht10.contains("Val 7"));
179        assertTrue("Invalid element found", !ht10.contains("ZZZZZZZZZZZZZZZZ"));
180
181        try {
182            ht10.contains(null);
183            fail("NullPointerException expected");
184        } catch (NullPointerException e) {
185            //expected
186        }
187    }
188
189    /**
190     * java.util.Hashtable#containsKey(java.lang.Object)
191     */
192    public void test_containsKeyLjava_lang_Object() {
193        // Test for method boolean
194        // java.util.Hashtable.containsKey(java.lang.Object)
195
196        assertTrue("Failed to find key", htfull.containsKey("FKey 4"));
197        assertTrue("Failed to find key", !htfull.containsKey("FKey 99"));
198
199        try {
200            htfull.containsKey(null);
201            fail("NullPointerException expected");
202        } catch (NullPointerException e) {
203            //expected
204        }
205    }
206
207    /**
208     * java.util.Hashtable#containsValue(java.lang.Object)
209     */
210    public void test_containsValueLjava_lang_Object() {
211        // Test for method boolean
212        // java.util.Hashtable.containsValue(java.lang.Object)
213        Enumeration e = elmVector.elements();
214        while (e.hasMoreElements())
215            assertTrue("Returned false for valid value", ht10.containsValue(e
216                    .nextElement()));
217        assertTrue("Returned true for invalid value", !ht10
218                .containsValue(new Object()));
219
220        try {
221            ht10.containsValue(null);
222            fail("NullPointerException expected");
223        } catch (NullPointerException ee) {
224            //expected
225        }
226    }
227
228    /**
229     * java.util.Hashtable#elements()
230     */
231    public void test_elements() {
232        // Test for method java.util.Enumeration java.util.Hashtable.elements()
233        Enumeration elms = ht10.elements();
234        int i = 0;
235        while (elms.hasMoreElements()) {
236            String s = (String) elms.nextElement();
237            assertTrue("Missing key from enumeration", elmVector.contains(s));
238            ++i;
239        }
240
241        assertEquals("All keys not retrieved", 10, ht10.size());
242
243        assertFalse(elms.hasMoreElements());
244        try {
245            elms.nextElement();
246            fail("should throw NoSuchElementException");
247        } catch (NoSuchElementException e) {
248            // Expected
249        }
250    }
251
252// BEGIN android-removed
253// implementation dependent
254//    /**
255//     * java.util.Hashtable#elements()
256//     */
257//    public void test_elements_subtest0() {
258//        // this is the reference implementation behavior
259//        final Hashtable ht = new Hashtable(7);
260//        ht.put("1", "a");
261//        // these three elements hash to the same bucket in a 7 element Hashtable
262//        ht.put("2", "b");
263//        ht.put("9", "c");
264//        ht.put("12", "d");
265//        // Hashtable looks like:
266//        // 0: "1"
267//        // 1: "12" -> "9" -> "2"
268//        Enumeration en = ht.elements();
269//        // cache the first entry
270//        en.hasMoreElements();
271//        ht.remove("12");
272//        ht.remove("9");
273//        boolean exception = false;
274//        try {
275//            // cached "12"
276//            Object result = en.nextElement();
277//            assertNull("unexpected: " + result, result);
278//            // next is removed "9"
279//            result = en.nextElement();
280//            assertNull("unexpected: " + result, result);
281//            result = en.nextElement();
282//            assertTrue("unexpected: " + result, "b".equals(result));
283//        } catch (NoSuchElementException e) {
284//            exception = true;
285//        }
286//        assertTrue("unexpected NoSuchElementException", !exception);
287//    }
288// END android-removed
289
290    /**
291     * java.util.Hashtable#entrySet()
292     */
293    public void test_entrySet() {
294        // Test for method java.util.Set java.util.Hashtable.entrySet()
295        Set s = ht10.entrySet();
296        Set s2 = new HashSet();
297        Iterator i = s.iterator();
298        while (i.hasNext())
299            s2.add(((Map.Entry) i.next()).getValue());
300        Enumeration e = elmVector.elements();
301        while (e.hasMoreElements())
302            assertTrue("Returned incorrect entry set", s2.contains(e
303                    .nextElement()));
304// BEGIN android-removed
305// implementation dependent
306//        assertEquals("Not synchronized",
307//                "java.util.Collections$SynchronizedSet", s.getClass().getName());
308// END android-removed
309
310        boolean exception = false;
311        try {
312            ((Map.Entry) ht10.entrySet().iterator().next()).setValue(null);
313        } catch (NullPointerException e1) {
314            exception = true;
315        }
316        assertTrue(
317                "Should not be able to assign null to a Hashtable entrySet() Map.Entry",
318                exception);
319    }
320
321    /**
322     * java.util.Hashtable#equals(java.lang.Object)
323     */
324    public void test_equalsLjava_lang_Object() {
325        // Test for method boolean java.util.Hashtable.equals(java.lang.Object)
326        Hashtable h = hashtableClone(ht10);
327        assertTrue("Returned false for equal tables", ht10.equals(h));
328        assertTrue("Returned true for unequal tables", !ht10.equals(htfull));
329    }
330
331    /**
332     * java.util.Hashtable#get(java.lang.Object)
333     */
334    public void test_getLjava_lang_Object() {
335        // Test for method java.lang.Object
336        // java.util.Hashtable.get(java.lang.Object)
337        Hashtable h = hashtableClone(htfull);
338        assertEquals("Could not retrieve element", "FVal 2", ((String) h.get("FKey 2"))
339                );
340
341// BEGIN android-removed
342// implementation dependent
343//        // Regression for HARMONY-262
344//        ReusableKey k = new ReusableKey();
345//        Hashtable h2 = new Hashtable();
346//        k.setKey(1);
347//        h2.put(k, "value1");
348//
349//        k.setKey(13);
350//        assertNull(h2.get(k));
351//
352//        k.setKey(12);
353//        assertNull(h2.get(k));
354//
355//        try {
356//            h2.get(null);
357//            fail("NullPointerException expected");
358//        } catch (NullPointerException e) {
359//            //expected
360//        }
361// END android-removed
362    }
363
364    /**
365     * java.util.Hashtable#hashCode()
366     */
367    public void test_hashCode() {
368        // Test for method int java.util.Hashtable.hashCode()
369        Set entrySet = ht10.entrySet();
370        Iterator iterator = entrySet.iterator();
371        int expectedHash;
372        for (expectedHash = 0; iterator.hasNext(); expectedHash += iterator
373                .next().hashCode())
374            ;
375        assertTrue("Incorrect hashCode returned.  Wanted: " + expectedHash
376                + " got: " + ht10.hashCode(), expectedHash == ht10.hashCode());
377    }
378
379    /**
380     * java.util.Hashtable#isEmpty()
381     */
382    public void test_isEmpty() {
383        // Test for method boolean java.util.Hashtable.isEmpty()
384
385        assertTrue("isEmpty returned incorrect value", !ht10.isEmpty());
386        assertTrue("isEmpty returned incorrect value",
387                new java.util.Hashtable().isEmpty());
388
389        final Hashtable ht = new Hashtable();
390        ht.put("0", "");
391        Thread t1 = new Thread() {
392            public void run() {
393                while (!ht.isEmpty())
394                    ;
395                ht.put("final", "");
396            }
397        };
398        t1.start();
399        for (int i = 1; i < 10000; i++) {
400            synchronized (ht) {
401                ht.remove(String.valueOf(i - 1));
402                ht.put(String.valueOf(i), "");
403            }
404            int size;
405            if ((size = ht.size()) != 1) {
406                String result = "Size is not 1: " + size + " " + ht;
407                // terminate the thread
408                ht.clear();
409                fail(result);
410            }
411        }
412        // terminate the thread
413        ht.clear();
414    }
415
416    /**
417     * java.util.Hashtable#keys()
418     */
419    public void test_keys() {
420        // Test for method java.util.Enumeration java.util.Hashtable.keys()
421
422        Enumeration keys = ht10.keys();
423        int i = 0;
424        while (keys.hasMoreElements()) {
425            String s = (String) keys.nextElement();
426            assertTrue("Missing key from enumeration", keyVector.contains(s));
427            ++i;
428        }
429
430        assertEquals("All keys not retrieved", 10, ht10.size());
431
432        assertFalse(keys.hasMoreElements());
433        try {
434            keys.nextElement();
435            fail("should throw NoSuchElementException");
436        } catch (NoSuchElementException e) {
437            // Expected
438        }
439    }
440
441    /**
442     * java.util.Hashtable#keys()
443     */
444    public void test_keys_subtest0() {
445        // this is the reference implementation behavior
446        final Hashtable ht = new Hashtable(3);
447        ht.put("initial", "");
448        Enumeration en = ht.keys();
449        en.hasMoreElements();
450        ht.remove("initial");
451        boolean exception = false;
452        try {
453            Object result = en.nextElement();
454            assertTrue("unexpected: " + result, "initial".equals(result));
455        } catch (NoSuchElementException e) {
456            exception = true;
457        }
458        assertTrue("unexpected NoSuchElementException", !exception);
459    }
460
461    /**
462     * java.util.Hashtable#keySet()
463     */
464    public void test_keySet() {
465        // Test for method java.util.Set java.util.Hashtable.keySet()
466        Set s = ht10.keySet();
467        Enumeration e = keyVector.elements();
468        while (e.hasMoreElements())
469            assertTrue("Returned incorrect key set", s
470                    .contains(e.nextElement()));
471
472// BEGIN android-removed
473// implementation dependent
474//        assertEquals("Not synchronized",
475//                "java.util.Collections$SynchronizedSet", s.getClass().getName());
476// END android-removed
477
478        Map map = new Hashtable(101);
479        map.put(new Integer(1), "1");
480        map.put(new Integer(102), "102");
481        map.put(new Integer(203), "203");
482        Iterator it = map.keySet().iterator();
483        Integer remove1 = (Integer) it.next();
484        it.remove();
485        Integer remove2 = (Integer) it.next();
486        it.remove();
487        ArrayList list = new ArrayList(Arrays.asList(new Integer[] {
488                new Integer(1), new Integer(102), new Integer(203) }));
489        list.remove(remove1);
490        list.remove(remove2);
491        assertTrue("Wrong result", it.next().equals(list.get(0)));
492        assertEquals("Wrong size", 1, map.size());
493        assertTrue("Wrong contents", map.keySet().iterator().next().equals(
494                list.get(0)));
495
496        Map map2 = new Hashtable(101);
497        map2.put(new Integer(1), "1");
498        map2.put(new Integer(4), "4");
499        Iterator it2 = map2.keySet().iterator();
500        Integer remove3 = (Integer) it2.next();
501        Integer next;
502        if (remove3.intValue() == 1)
503            next = new Integer(4);
504        else
505            next = new Integer(1);
506        it2.hasNext();
507        it2.remove();
508        assertTrue("Wrong result 2", it2.next().equals(next));
509        assertEquals("Wrong size 2", 1, map2.size());
510        assertTrue("Wrong contents 2", map2.keySet().iterator().next().equals(
511                next));
512    }
513
514    /**
515     * java.util.Hashtable#keySet()
516     */
517    public void test_keySet_subtest0() {
518        Set s1 = ht10.keySet();
519        assertTrue("should contain key", s1.remove("Key 0"));
520        assertTrue("should not contain key", !s1.remove("Key 0"));
521
522        final int iterations = 10000;
523        final Hashtable ht = new Hashtable();
524        Thread t1 = new Thread() {
525            public void run() {
526                for (int i = 0; i < iterations; i++) {
527                    ht.put(String.valueOf(i), "");
528                    ht.remove(String.valueOf(i));
529                }
530            }
531        };
532        t1.start();
533        Set set = ht.keySet();
534        for (int i = 0; i < iterations; i++) {
535            Iterator it = set.iterator();
536            try {
537                it.next();
538                it.remove();
539                int size;
540                // ensure removing with the iterator doesn't corrupt the
541                // Hashtable
542                if ((size = ht.size()) < 0) {
543                    fail("invalid size: " + size);
544                }
545            } catch (NoSuchElementException e) {
546            } catch (ConcurrentModificationException e) {
547            }
548        }
549    }
550
551// BEGIN android-removed
552// implementation dependent
553//    /**
554//     * java.util.Hashtable#keySet()
555//     */
556//    public void test_keySet_subtest1() {
557//        // this is the reference implementation behavior
558//        final Hashtable ht = new Hashtable(7);
559//        ht.put("1", "a");
560//        // these three elements hash to the same bucket in a 7 element Hashtable
561//        ht.put("2", "b");
562//        ht.put("9", "c");
563//        ht.put("12", "d");
564//        // Hashtable looks like:
565//        // 0: "1"
566//        // 1: "12" -> "9" -> "2"
567//        Enumeration en = ht.elements();
568//        // cache the first entry
569//        en.hasMoreElements();
570//        Iterator it = ht.keySet().iterator();
571//        // this is mostly a copy of the test in test_elements_subtest0()
572//        // test removing with the iterator does not null the values
573//        while (it.hasNext()) {
574//            String key = (String) it.next();
575//            if ("12".equals(key) || "9".equals(key)) {
576//                it.remove();
577//            }
578//        }
579//        it.remove();
580//        boolean exception = false;
581//        try {
582//            // cached "12"
583//            Object result = en.nextElement();
584//            assertTrue("unexpected: " + result, "d".equals(result));
585//            // next is removed "9"
586//            result = en.nextElement();
587//            assertTrue("unexpected: " + result, "c".equals(result));
588//            result = en.nextElement();
589//            assertTrue("unexpected: " + result, "b".equals(result));
590//        } catch (NoSuchElementException e) {
591//            exception = true;
592//        }
593//        assertTrue("unexpected NoSuchElementException", !exception);
594//    }
595// END android-removed
596
597    /**
598     * java.util.Hashtable#put(java.lang.Object, java.lang.Object)
599     */
600    public void test_putLjava_lang_ObjectLjava_lang_Object() {
601        // Test for method java.lang.Object
602        // java.util.Hashtable.put(java.lang.Object, java.lang.Object)
603        Hashtable h = hashtableClone(ht100);
604        Integer key = new Integer(100);
605        h.put("Value 100", key);
606        assertTrue("Key/Value not inserted", h.size() == 1 && (h.contains(key)));
607
608        // Put into "full" table
609        h = hashtableClone(htfull);
610        h.put("Value 100", key);
611        assertTrue("Key/Value not inserted into full table", h.size() == 8
612                && (h.contains(key)));
613
614        try {
615            h.put(null, key);
616            fail("NullPointerException expected");
617        } catch (NullPointerException e) {
618            //expected
619        }
620
621        try {
622            h.put("Value 100", null);
623            fail("NullPointerException expected");
624        } catch (NullPointerException e) {
625            //expected
626        }
627    }
628
629    /**
630     * java.util.Hashtable#putAll(java.util.Map)
631     */
632    public void test_putAllLjava_util_Map() {
633        // Test for method void java.util.Hashtable.putAll(java.util.Map)
634        Hashtable h = new Hashtable();
635        h.putAll(ht10);
636        Enumeration e = keyVector.elements();
637        while (e.hasMoreElements()) {
638            Object x = e.nextElement();
639            assertTrue("Failed to put all elements", h.get(x).equals(
640                    ht10.get(x)));
641        }
642
643        try {
644            h.putAll(null);
645            fail("NullPointerException expected");
646        } catch (NullPointerException ee) {
647            //expected
648        }
649    }
650
651    /**
652     * java.util.Hashtable#remove(java.lang.Object)
653     */
654    public void test_removeLjava_lang_Object() {
655        // Test for method java.lang.Object
656        // java.util.Hashtable.remove(java.lang.Object)
657        Hashtable h = hashtableClone(htfull);
658        Object k = h.remove("FKey 0");
659        assertTrue("Remove failed", !h.containsKey("FKey 0") || k == null);
660        assertNull(h.remove("FKey 0"));
661
662        try {
663            h.remove(null);
664            fail("NullPointerException expected");
665        } catch (NullPointerException e) {
666            //expected
667        }
668    }
669
670    public void test_HashTable_remove_scenario1() {
671        Hashtable hashTable = new Hashtable();
672        Set keySet = hashTable.keySet();
673        hashTable.put(hashTable, keySet);
674        hashTable.remove(hashTable);
675    }
676
677    public void test_HashTable_remove_scenario2() {
678        Hashtable hashTable = new Hashtable();
679        Set keySet = hashTable.keySet();
680        hashTable.put(hashTable, hashTable);
681        hashTable.remove(hashTable);
682    }
683
684    public void test_HashTable_remove_scenario3() {
685        Hashtable hashTable = new Hashtable();
686        Hashtable keyHashTable = new Hashtable();
687        keyHashTable.put(hashTable, keyHashTable);
688        hashTable.put(keyHashTable, hashTable);
689        hashTable.remove(keyHashTable);
690    }
691
692    /**
693     * java.util.Hashtable#size()
694     */
695    public void test_size() {
696        // Test for method int java.util.Hashtable.size()
697        assertTrue("Returned invalid size", ht10.size() == 10
698                && (ht100.size() == 0));
699
700        final Hashtable ht = new Hashtable();
701        ht.put("0", "");
702        Thread t1 = new Thread() {
703            public void run() {
704                while (ht.size() > 0)
705                    ;
706                ht.put("final", "");
707            }
708        };
709        t1.start();
710        for (int i = 1; i < 10000; i++) {
711            synchronized (ht) {
712                ht.remove(String.valueOf(i - 1));
713                ht.put(String.valueOf(i), "");
714            }
715            int size;
716            if ((size = ht.size()) != 1) {
717                String result = "Size is not 1: " + size + " " + ht;
718                // terminate the thread
719                ht.clear();
720                fail(result);
721            }
722        }
723        // terminate the thread
724        ht.clear();
725    }
726
727    /**
728     * java.util.Hashtable#toString()
729     */
730    public void test_toString() {
731        // Test for method java.lang.String java.util.Hashtable.toString()
732        Hashtable h = new Hashtable();
733        assertEquals("Incorrect toString for Empty table",
734                "{}", h.toString());
735
736        h.put("one", "1");
737        h.put("two", h);
738        h.put(h, "3");
739        h.put(h, h);
740        String result = h.toString();
741        assertTrue("should contain self ref", result.indexOf("(this") > -1);
742    }
743
744    /**
745     * java.util.Hashtable#values()
746     */
747    public void test_values() {
748        // Test for method java.util.Collection java.util.Hashtable.values()
749        Collection c = ht10.values();
750        Enumeration e = elmVector.elements();
751        while (e.hasMoreElements())
752            assertTrue("Returned incorrect values", c.contains(e.nextElement()));
753
754// BEGIN android-removed
755// implementation dependent
756//        assertEquals("Not synchronized",
757//                "java.util.Collections$SynchronizedCollection", c.getClass().getName());
758// END android-removed
759
760        Hashtable myHashtable = new Hashtable();
761        for (int i = 0; i < 100; i++)
762            myHashtable.put(new Integer(i), new Integer(i));
763        Collection values = myHashtable.values();
764        new Support_UnmodifiableCollectionTest(
765                "Test Returned Collection From Hashtable.values()", values)
766                .runTest();
767        values.remove(new Integer(0));
768        assertTrue(
769                "Removing from the values collection should remove from the original map",
770                !myHashtable.containsValue(new Integer(0)));
771    }
772
773    /**
774     * Regression Test for JIRA 2181
775     */
776    public void test_entrySet_remove() {
777        Hashtable<String, String> hashtable = new Hashtable<String, String>();
778        hashtable.put("my.nonexistent.prop", "AAA");
779        hashtable.put("parse.error", "BBB");
780        Iterator<Map.Entry<String, String>> iterator =
781                hashtable.entrySet().iterator();
782        while (iterator.hasNext()) {
783            Map.Entry entry = iterator.next();
784            final Object value = entry.getValue();
785            if (value.equals("AAA")) {
786                iterator.remove();
787            }
788        }
789        assertFalse(hashtable.containsKey("my.nonexistent.prop"));
790    }
791
792    class Mock_Hashtable extends Hashtable {
793        boolean flag = false;
794
795        public Mock_Hashtable(int i) {
796            super(i);
797        }
798
799        @Override
800        protected void rehash() {
801            flag = true;
802            super.rehash();
803        }
804
805        public boolean isRehashed() {
806            return flag;
807        }
808    }
809
810    public void test_rehash() {
811        Mock_Hashtable mht = new Mock_Hashtable(5);
812
813        assertFalse(mht.isRehashed());
814        for(int i = 0; i < 10; i++) {
815            mht.put(i, "New value");
816        }
817        assertTrue(mht.isRehashed());
818    }
819
820    /**
821     * java.util.Hashtable#elements()
822     * java.util.Hashtable#keys()
823     * java.util.Hashtable#keySet()
824     */
825    public void test_keys_elements_keySet_Exceptions() {
826        Hashtable hashTable = new Hashtable();
827        String key = "key";
828        String value = "value";
829        hashTable.put(key, value);
830
831        Enumeration enumeration = hashTable.keys();
832        assertTrue(enumeration.hasMoreElements());
833        enumeration.nextElement();
834        assertFalse(enumeration.hasMoreElements());
835
836        enumeration = hashTable.elements();
837        assertTrue(enumeration.hasMoreElements());
838        enumeration.nextElement();
839        assertFalse(enumeration.hasMoreElements());
840
841        Iterator iterator = hashTable.keySet().iterator();
842        assertTrue(iterator.hasNext());
843        try {
844            iterator.remove();
845            fail("should throw IllegalStateException");
846        } catch (IllegalStateException e) {
847            // Expected
848        }
849        iterator.next();
850        iterator.remove();
851        assertFalse(iterator.hasNext());
852
853        hashTable.clear();
854        for (int i = 0; i < 10; i++) {
855            hashTable.put(key + i, value + i);
856        }
857
858        enumeration = hashTable.keys();
859        assertTrue(enumeration.hasMoreElements());
860        for (int i = 0; i < 10; i++) {
861            enumeration.nextElement();
862        }
863        assertFalse(enumeration.hasMoreElements());
864        try {
865            enumeration.nextElement();
866            fail("should throw NoSuchElementException");
867        } catch (NoSuchElementException e) {
868            // Expected
869        }
870
871        enumeration = hashTable.elements();
872        assertTrue(enumeration.hasMoreElements());
873        for (int i = 0; i < 10; i++) {
874            enumeration.nextElement();
875        }
876        assertFalse(enumeration.hasMoreElements());
877        try {
878            enumeration.nextElement();
879            fail("should throw NoSuchElementException");
880        } catch (NoSuchElementException e) {
881            // Expected
882        }
883
884        iterator = hashTable.keySet().iterator();
885        assertTrue(iterator.hasNext());
886        for (int i = 0; i < 10; i++) {
887            iterator.next();
888        }
889        assertFalse(iterator.hasNext());
890        try {
891            iterator.next();
892            fail("should throw NoSuchElementException");
893        } catch (NoSuchElementException e) {
894            // Expected
895        }
896    }
897
898    public void test_forEach() throws Exception {
899        Hashtable<String, String> ht = new Hashtable<>();
900        ht.put("1", "one");
901        ht.put("2", "two");
902        ht.put("3", "three");
903        Hashtable<String, String> output = new Hashtable<>();
904
905        ht.forEach((k,v) -> output.put(k,v));
906        assertEquals(ht, output);
907    }
908
909    public void test_forEach_NPE() throws Exception {
910        Hashtable<String, String> ht = new Hashtable<>();
911        try {
912            ht.forEach(null);
913            fail();
914        } catch(NullPointerException expected) {}
915    }
916
917    public void test_forEach_CME() throws Exception {
918        Hashtable<String, String> ht = new Hashtable<>();
919        ht.put("one", "1");
920        ht.put("two", "2");
921        ht.put("three", "3");
922
923        Hashtable<String, String> outputHt = new Hashtable<>();
924        try {
925            ht.forEach(new java.util.function.BiConsumer<String, String>() {
926                    @Override
927                    public void accept(String k, String v) {
928                        outputHt.put(k, v);
929                        ht.put("foo", v);
930                    }
931                });
932            fail();
933        } catch(ConcurrentModificationException expected) {}
934        // We should get a CME and DO NOT continue forEach evaluation
935        assertEquals(1, outputHt.size());
936    }
937
938    protected Hashtable hashtableClone(Hashtable s) {
939        return (Hashtable) s.clone();
940    }
941
942    /**
943     * Sets up the fixture, for example, open a network connection. This method
944     * is called before a test is executed.
945     */
946    protected void setUp() {
947
948        ht10 = new Hashtable(10);
949        ht100 = new Hashtable(100);
950        htfull = new Hashtable(10);
951        keyVector = new Vector(10);
952        elmVector = new Vector(10);
953
954        for (int i = 0; i < 10; i++) {
955            ht10.put("Key " + i, "Val " + i);
956            keyVector.addElement("Key " + i);
957            elmVector.addElement("Val " + i);
958        }
959
960        for (int i = 0; i < 7; i++)
961            htfull.put("FKey " + i, "FVal " + i);
962    }
963
964    /**
965     * Tears down the fixture, for example, close a network connection. This
966     * method is called after a test is executed.
967     */
968    protected void tearDown() {
969        ht10 = null;
970        ht100 = null;
971        htfull = null;
972        keyVector = null;
973        elmVector = null;
974    }
975}
976