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.support;
19
20import java.lang.reflect.Array;
21import java.util.Arrays;
22import java.util.Collections;
23import java.util.HashSet;
24import java.util.Iterator;
25import java.util.Map;
26import java.util.Set;
27import junit.framework.TestCase;
28
29public class Support_MapTest extends TestCase {
30
31    // must be a map containing the string keys "0"-"99" paired with the Integer
32    // values Integer(0) to Integer(99)
33    private final Map<String, Integer> modifiableMap;
34    private final Map<String, Integer> unmodifiableMap;
35
36    public Support_MapTest(String p1, Map<String, Integer> modifiableMap) {
37        super(p1);
38        this.modifiableMap = modifiableMap;
39        unmodifiableMap = Collections.unmodifiableMap(modifiableMap);
40    }
41
42    @Override
43    public void runTest() {
44        testContents(modifiableMap);
45        testContents(unmodifiableMap);
46
47        // values()
48        new Support_UnmodifiableCollectionTest("values() from map test", modifiableMap.values())
49                .runTest();
50        new Support_UnmodifiableCollectionTest("values() from unmodifiable map test",
51                unmodifiableMap.values()).runTest();
52
53        // entrySet()
54        testEntrySet(modifiableMap.entrySet(), unmodifiableMap.entrySet());
55
56        // keySet()
57        testKeySet(modifiableMap.keySet(), unmodifiableMap.keySet());
58    }
59
60    private void testContents(Map<String, Integer> map) {
61        // size
62        assertTrue("Size should return 100, returned: " + map.size(), map.size() == 100);
63
64        // containsKey
65        assertTrue("Should contain the key \"0\"", map.containsKey("0"));
66        assertTrue("Should contain the key \"50\"", map.containsKey("50"));
67        assertTrue("Should not contain the key \"100\"", !map.containsKey("100"));
68
69        // containsValue
70        assertTrue("Should contain the value 0", map.containsValue(0));
71        assertTrue("Should contain the value 50", map.containsValue(50));
72        assertTrue("Should not contain value 100", !map.containsValue(100));
73
74        // get
75        assertTrue("getting \"0\" didn't return 0", map.get("0") == 0);
76        assertTrue("getting \"50\" didn't return 50", map.get("50") == 50);
77        assertNull("getting \"100\" didn't return null", map.get("100"));
78
79        // isEmpty
80        assertTrue("should have returned false to isEmpty", !map.isEmpty());
81    }
82
83    private static void testEntrySet(
84            Set<Map.Entry<String, Integer>> referenceEntrySet,
85            Set<Map.Entry<String, Integer>> entrySet) {
86        // entrySet should be a set of mappings {"0", 0}, {"1",1}... {"99", 99}
87        assertEquals(100, referenceEntrySet.size());
88        assertEquals(100, entrySet.size());
89
90        // The ordering may be undefined for a map implementation but the ordering must be the
91        // same across iterator(), toArray() and toArray(T[]) for a given map *and* the same for the
92        // modifiable and unmodifiable map.
93        crossCheckOrdering(referenceEntrySet, entrySet, Map.Entry.class);
94    }
95
96    private static void testKeySet(Set<String> referenceKeySet, Set<String> keySet) {
97        // keySet should be a set of the strings "0" to "99"
98        testKeySetContents(referenceKeySet);
99        testKeySetContents(keySet);
100
101        // The ordering may be undefined for a map implementation but the ordering must be the
102        // same across iterator(), toArray() and toArray(T[]) for a given map *and* the same for the
103        // modifiable and unmodifiable map.
104        crossCheckOrdering(referenceKeySet, keySet, String.class);
105    }
106
107    private static void testKeySetContents(Set<String> keySet) {
108        // contains
109        assertTrue("should contain \"0\"", keySet.contains("0"));
110        assertTrue("should contain \"50\"", keySet.contains("50"));
111        assertTrue("should not contain \"100\"", !keySet.contains("100"));
112
113        // containsAll
114        HashSet<String> hs = new HashSet<String>();
115        hs.add("0");
116        hs.add("25");
117        hs.add("99");
118        assertTrue("Should contain set of \"0\", \"25\", and \"99\"", keySet.containsAll(hs));
119        hs.add("100");
120        assertTrue("Should not contain set of \"0\", \"25\", \"99\" and \"100\"",
121                !keySet.containsAll(hs));
122
123        // isEmpty
124        assertTrue("Should not be empty", !keySet.isEmpty());
125
126        // size
127        assertEquals("Returned wrong size.", 100, keySet.size());
128    }
129
130    private static <T> void crossCheckOrdering(Set<T> set1, Set<T> set2, Class<?> elementType) {
131        Iterator<T> set1Iterator = set1.iterator();
132        Iterator<T> set2Iterator = set2.iterator();
133
134        T[] zeroLengthArray = createArray(elementType, 0);
135        T[] set1TypedArray1 = set1.toArray(zeroLengthArray);
136        assertEquals(set1.size(), set1TypedArray1.length);
137
138        // Compare set1.iterator(), set2.iterator() and set1.toArray(new T[0])
139        int entryCount = 0;
140        while (set1Iterator.hasNext()) {
141            T set1Entry = set1Iterator.next();
142            T set2Entry = set2Iterator.next();
143
144            // Compare set1 with set2
145            assertEquals(set1Entry, set2Entry);
146
147            // Compare the iterator with the array. The arrays will be checked against each other.
148            assertEquals(set1Entry, set1TypedArray1[entryCount]);
149
150            entryCount++;
151        }
152        assertFalse(set2Iterator.hasNext());
153        assertEquals(set1.size(), entryCount);
154
155        // Compare the various arrays with each other.
156
157        // set1.toArray(new T[size])
158        T[] parameterArray1 = createArray(elementType, set1.size());
159        T[] set1TypedArray2 = set1.toArray(parameterArray1);
160        assertSame(set1TypedArray2, parameterArray1);
161        assertArrayEquals(set1TypedArray1, set1TypedArray2);
162
163        // set1.toArray()
164        Object[] set1UntypedArray = set1.toArray();
165        assertEquals(set1.size(), set1UntypedArray.length);
166        assertArrayEquals(set1TypedArray1, set1UntypedArray);
167
168        // set2.toArray(new T[0])
169        T[] set2TypedArray1 = set2.toArray(zeroLengthArray);
170        assertEquals(set1.size(), set2TypedArray1.length);
171        assertArrayEquals(set1TypedArray1, set2TypedArray1);
172
173        // set2.toArray(new T[size])
174        T[] parameterArray2 = createArray(elementType, set2.size());
175        T[] set2TypedArray2 = set1.toArray(parameterArray2);
176        assertSame(set2TypedArray2, parameterArray2);
177        assertArrayEquals(set1TypedArray1, set1TypedArray2);
178
179        // set2.toArray()
180        Object[] set2UntypedArray = set2.toArray();
181        assertArrayEquals(set1TypedArray1, set2UntypedArray);
182    }
183
184    private static <T> void assertArrayEquals(T[] array1, T[] array2) {
185        assertTrue(Arrays.equals(array1, array2));
186    }
187
188    private static <T> T[] createArray(Class<?> elementType, int size) {
189        return (T[]) Array.newInstance(elementType, size);
190    }
191}
192