/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.citrus.util.collection;
import static com.alibaba.citrus.util.CollectionUtil.*;
import static org.junit.Assert.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.junit.Before;
import org.junit.Test;
/**
* <code>MapTest</code>测试<code>java.util.Map</code>的基本行为。
*
* @author Michael Zhou
*/
public abstract class AbstractMapTests extends AbstractTests {
private Map<Object, Object> map1;
private Map<Object, Object> map2;
private Map<Object, Object> map3;
@Before
public void init() {
// map1测试一般情况.
map1 = createMap();
map1.put("aaa", "111");
map1.put("bbb", "222");
map1.put("ccc", "333");
// map2测试key和value为null的情况.
map2 = createMap();
map2.put(null, "111");
map2.put("aaa", null);
// map3为空.
map3 = createMap();
}
private Map<Object, Object> newMap() {
return createHashMap();
}
@Test
public void clear() {
map1.clear();
assertEquals(0, map1.size());
assertTrue(map1.isEmpty());
map2.clear();
assertEquals(0, map2.size());
assertTrue(map2.isEmpty());
map3.clear();
assertEquals(0, map3.size());
assertTrue(map3.isEmpty());
}
@Test
public void containsKey() {
assertTrue(map1.containsKey("aaa"));
assertTrue(map1.containsKey("bbb"));
assertTrue(map1.containsKey("ccc"));
assertTrue(map2.containsKey(null));
assertTrue(map2.containsKey("aaa"));
}
@Test
public void containsValue() {
assertTrue(map1.containsValue("111"));
assertTrue(map1.containsValue("222"));
assertTrue(map1.containsValue("333"));
assertTrue(map2.containsValue(null));
assertTrue(map2.containsValue("111"));
}
@Test
public void equals_() {
Map<Object, Object> newMap;
newMap = newMap();
newMap.put("aaa", "111");
newMap.put("bbb", "222");
newMap.put("ccc", "333");
assertEquals(newMap, map1);
newMap = newMap();
newMap.put(null, "111");
newMap.put("aaa", null);
assertEquals(newMap, map2);
newMap = newMap();
assertEquals(newMap, map3);
assertFalse(map1.equals(map2));
assertFalse(map1.equals(map3));
assertFalse(map2.equals(map3));
}
@Test
public void get() {
assertEquals("111", map1.get("aaa"));
assertEquals("222", map1.get("bbb"));
assertEquals("333", map1.get("ccc"));
assertEquals("111", map2.get(null));
assertEquals(null, map2.get("aaa"));
}
@Test
public void hashCode_() {
Map<Object, Object> newMap;
newMap = newMap();
newMap.put("aaa", "111");
newMap.put("bbb", "222");
newMap.put("ccc", "333");
assertEquals(newMap.hashCode(), map1.hashCode());
newMap = newMap();
newMap.put(null, "111");
newMap.put("aaa", null);
assertEquals(newMap.hashCode(), map2.hashCode());
newMap = newMap();
assertEquals(newMap.hashCode(), map3.hashCode());
assertFalse(map1.hashCode() == map2.hashCode());
assertFalse(map1.hashCode() == map3.hashCode());
assertFalse(map2.hashCode() == map3.hashCode());
}
@Test
public void isEmpty() {
assertFalse(map1.isEmpty());
assertFalse(map2.isEmpty());
assertTrue(map3.isEmpty());
}
@Test
public void put() {
assertEquals("111", map1.put("aaa", "111+111")); // 替换aaa
assertEquals(null, map1.put("ddd", "222+222")); // 新增ddd
assertEquals("111+111", map1.get("aaa"));
assertEquals("222+222", map1.get("ddd"));
assertEquals(4, map1.size());
assertEquals("111", map2.put(null, "111+111")); // 替换null
assertEquals(null, map2.put("aaa", "222+222")); // 替换aaa
assertEquals(null, map2.put("ccc", "333+333")); // 新增ccc
assertEquals("111+111", map2.get(null));
assertEquals("222+222", map2.get("aaa"));
assertEquals("333+333", map2.get("ccc"));
assertEquals(3, map2.size());
assertEquals(null, map3.put("aaa", "111+111")); // 新增aaa
assertEquals("111+111", map3.get("aaa"));
assertEquals(1, map3.size());
}
@Test
public void putAll() {
Map<Object, Object> newMap;
// 加入空map.
newMap = newMap();
map1.putAll(newMap);
map2.putAll(newMap);
map3.putAll(newMap);
assertEquals(3, map1.size());
assertEquals(2, map2.size());
assertEquals(0, map3.size());
assertEquals("111", map1.get("aaa"));
assertEquals("222", map1.get("bbb"));
assertEquals("333", map1.get("ccc"));
assertEquals(null, map2.get("aaa"));
assertEquals("111", map2.get(null));
// 加入非空的map.
newMap = newMap();
newMap.put("aaa", "111+111");
newMap.put("ddd", "444+444");
newMap.put(null, "111+111");
newMap.put("eee", null);
map1.putAll(newMap);
map2.putAll(newMap);
map3.putAll(newMap);
assertEquals(6, map1.size());
assertEquals(4, map2.size());
assertEquals(4, map3.size());
assertEquals("111+111", map1.get("aaa")); // 被替换
assertEquals("222", map1.get("bbb")); // 不变
assertEquals("333", map1.get("ccc")); // 不变
assertEquals("444+444", map1.get("ddd")); // 新增ddd
assertEquals(null, map1.get("eee")); // 新增eee
assertEquals("111+111", map1.get(null)); // 新增null
assertEquals("111+111", map2.get("aaa")); // 被替换
assertEquals("111+111", map2.get(null)); // 被替换
assertEquals("444+444", map2.get("ddd")); // 新增ddd
assertEquals(null, map2.get("eee")); // 新增eee
assertEquals("111+111", map3.get("aaa")); // 新增aaa
assertEquals("111+111", map3.get(null)); // 新增null
assertEquals("444+444", map3.get("ddd")); // 新增ddd
assertEquals(null, map3.get("eee")); // 新增eee
}
@Test
public void remove() {
map1.remove("aaa");
assertFalse(map1.containsKey("aaa"));
assertEquals(2, map1.size());
map2.remove("aaa");
assertFalse(map2.containsKey("aaa"));
map2.remove(null);
assertFalse(map2.containsKey(null));
assertEquals(0, map2.size());
map3.remove("not exists");
assertFalse(map3.containsKey("not exists"));
assertEquals(0, map3.size());
}
@Test
public void size() {
assertEquals(3, map1.size());
assertEquals(2, map2.size());
assertEquals(0, map3.size());
}
@Test
public void clone_() {
Map<Object, Object> copy;
try {
copy = cloneMap(map1);
assertNotSame(map1, copy); // 不同
assertEquals(map1, copy); // 但相等
assertEquals(map1.hashCode(), copy.hashCode());
assertEquals(3, copy.size());
assertEquals("111", copy.get("aaa"));
assertEquals("222", copy.get("bbb"));
assertEquals("333", copy.get("ccc"));
copy = cloneMap(map2);
assertNotSame(map2, copy); // 不同
assertEquals(map2, copy); // 但相等
assertEquals(map2.hashCode(), copy.hashCode());
assertEquals(2, copy.size());
assertEquals("111", copy.get(null));
assertEquals(null, copy.get("aaa"));
assertTrue(copy.containsKey("aaa"));
copy = cloneMap(map3);
assertNotSame(map3, copy); // 不同
assertEquals(map3, copy); // 但相等
assertEquals(map3.hashCode(), copy.hashCode());
assertEquals(0, copy.size());
} catch (UnsupportedOperationException e) {
// 被测试的Map不支持clone
}
}
@Test
public void toString_() {
List<String> list;
assertNotNull(list = parseToString(map1));
assertEquals("aaa=111", list.get(0));
assertEquals("bbb=222", list.get(1));
assertEquals("ccc=333", list.get(2));
assertNotNull(list = parseToString(map2));
assertEquals("aaa=null", list.get(0));
assertEquals("null=111", list.get(1));
assertNotNull(list = parseToString(map3));
assertEquals(0, list.size());
}
/**
* 将map.toString()的结果重新排序后输出.
*
* @param map 要处理的map
* @return 重新排序后的结果
*/
private List<String> parseToString(Map<Object, Object> map) {
List<String> list = createArrayList();
String str = map.toString();
try {
str = str.substring(1, str.length() - 1);
} catch (IndexOutOfBoundsException e) {
return null;
}
StringTokenizer st = new StringTokenizer(str, ", ");
while (st.hasMoreTokens()) {
list.add(st.nextToken());
}
Collections.sort(list);
return list;
}
@Test
public void serialize() throws Exception {
Map<Object, Object> copy;
try {
copy = cloneBySerialization(map1);
assertNotSame(map1, copy); // 不同
assertEquals(map1, copy); // 但相等
assertEquals(map1.hashCode(), copy.hashCode());
assertEquals(3, copy.size());
assertEquals("111", copy.get("aaa"));
assertEquals("222", copy.get("bbb"));
assertEquals("333", copy.get("ccc"));
copy = cloneBySerialization(map2);
assertNotSame(map2, copy); // 不同
assertEquals(map2, copy); // 但相等
assertEquals(map2.hashCode(), copy.hashCode());
assertEquals(2, copy.size());
assertEquals("111", copy.get(null));
assertEquals(null, copy.get("aaa"));
assertTrue(copy.containsKey("aaa"));
copy = cloneBySerialization(map3);
assertNotSame(map3, copy); // 不同
assertEquals(map3, copy); // 但相等
assertEquals(map3.hashCode(), copy.hashCode());
assertEquals(0, copy.size());
} catch (UnsupportedOperationException e) {
// 被测试的Map不支持serialize
}
}
/** 测试当hash表中的项数超过阈值时的表现. */
@Test
public void resize() {
int capacity = 0;
int threshold = 0;
// 取得初始容量和阈值, 如果掷出exception, 则不测试此项.
try {
capacity = getCapacity(map3);
threshold = getThreshold(map3);
} catch (UnsupportedOperationException e) {
return;
}
// 预计扩容三次.
int max = threshold * 4 + 1;
/** 放入足够多的项到hash表中, 确保项数超过阈值. */
String key = "";
for (int i = 0; i < max; i++) {
key += "a";
map3.put(key, new Integer(i));
if (map3.size() > threshold) { // 扩容!
threshold *= 2;
capacity *= 2;
}
assertEquals(capacity, getCapacity(map3));
assertEquals(threshold, getThreshold(map3));
}
/** 读出所有项, 并排序测试正确性. */
List<String> list;
assertNotNull(list = parseToString(map3));
assertEquals(max, list.size());
key = "";
for (int i = 0; i < max; i++) {
key += "a";
assertEquals(key + "=" + i, list.get(i));
}
}
protected abstract Map<Object, Object> createMap();
protected abstract Map<Object, Object> cloneMap(Map<Object, Object> map);
protected abstract int getThreshold(Map<Object, Object> map);
protected abstract int getCapacity(Map<Object, Object> map);
}