package test.org.seasar.framework.util;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.seasar.framework.util.ArrayMap;
import org.seasar.framework.util.SerializeUtil;

public class ArrayMapTest extends TestCase {

	private ArrayMap _map;

	public ArrayMapTest(String name) {
		super(name);
	}

	public void testSize() throws Exception {
		assertEquals("1", 3, _map.size());
		_map.put("3", "test3");
		assertEquals("2", 4, _map.size());
	}

	public void testIsEmpty() throws Exception {
		assertTrue("1", !_map.isEmpty());
		_map.clear();
		assertTrue("2", _map.isEmpty());
	}

	public void testContainsValue() throws Exception {
		assertTrue("1", _map.containsValue("test2"));
		assertTrue("2", !_map.containsValue("test3"));
	}

	public void testContainsKey() throws Exception {
		assertTrue("1", _map.containsKey("2"));
		assertTrue("2", !_map.containsKey("3"));
		_map.put("3", null);
		assertTrue("3", _map.containsKey("3"));
	}

	public void testIndexOf() throws Exception {
		assertEquals("1", 1, _map.indexOf("test"));
		assertEquals("1", 0, _map.indexOf(null));
		assertEquals("2", -1, _map.indexOf("test3"));
	}

	public void testGet() throws Exception {
		assertEquals("1", "test", _map.get("1"));
		assertEquals("2", null, _map.get(null));
		assertEquals("3", null, _map.get("test3"));
		assertEquals("4", null, _map.get(0));
	}

	public void testPut() throws Exception {
		assertEquals("1", "test", _map.put("1", "test3"));
		assertEquals("2", "test3", _map.get("1"));
		assertEquals("3", "test3", _map.get(1));
		_map.put(null, "test4");
		_map.put(null, "test5");
	}

	public void testRemove() throws Exception {
		assertEquals("1", "test", _map.remove("1"));
		assertEquals("2", 2, _map.size());
		assertEquals("3", null, _map.remove("dummy"));
		assertEquals("4", null, _map.remove(0));
	}

	public void testRemove2() throws Exception {
		Map m = new ArrayMap();
		m.put("1", "d");
		m.remove("1");
		assertEquals("1", false, m.containsKey("1"));
		m.put("1", "d");
		m.remove("1");
		assertEquals("2", false, m.containsKey("1"));
	}

	public void testRemove3() throws Exception {
		Map m = new ArrayMap();
		m.put(new MyKey("1"), "d");
		m.put(new MyKey("2"), "d");
		m.remove(new MyKey("1"));
		assertEquals("1", false, m.containsKey(new MyKey("1")));
	}

	public void testRemove4() throws Exception {
		ArrayMap m = new ArrayMap();
		m.put("1", "d");
		m.put("2", "d");
		System.out.println("remove before:" + m);
		m.remove("2");
		System.out.println("remove after:" + m);
		assertEquals("1", false, m.containsKey("2"));
		assertEquals("2", true, m.containsKey("1"));
		assertEquals("3", "d", m.get("1"));
		assertEquals("4", null, m.get("2"));
		assertEquals("5", "d", m.get(0));
	}

	public void testPutAll() throws Exception {
		Map m = new HashMap();
		m.put("3", "test3");
		m.put("4", "test4");
		_map.putAll(m);
		assertEquals("1", "test3", _map.get("3"));
		assertEquals("2", "test4", _map.get("4"));
		assertEquals("3", 5, _map.size());
	}

	public void testEqaulas() throws Exception {
		Map copy = (ArrayMap) _map.clone();
		assertTrue("1", _map.equals(copy));
		assertTrue("2", !_map.equals(null));
		_map.put("3", "test3");
		assertTrue("3", !_map.equals(copy));
	}

	public void testToString() throws Exception {
		assertNotNull("1", _map.toString());
	}

	public void testClear() throws Exception {
		_map.clear();
		assertEquals("1", 0, _map.size());
	}

	public void testEntrySet() throws Exception {
		Iterator i = _map.entrySet().iterator();
		assertEquals("1", null, ((Map.Entry) i.next()).getKey());
		assertEquals("2", "1", ((Map.Entry) i.next()).getKey());
		assertEquals("1", "2", ((Map.Entry) i.next()).getKey());
	}

	public void testSerialize() throws Exception {
		ArrayMap copy = (ArrayMap) SerializeUtil.serialize(_map);
		assertEquals("1", null, copy.get(0));
		assertEquals("2", "test", copy.get(1));
		assertEquals("3", "test2", copy.get(2));
		_map.equals(copy);
	}

	public void testPerformance() throws Exception {
		int num = 100000;
		Map hmap = new HashMap();
		Map amap = new ArrayMap();

		long start = System.currentTimeMillis();
		for (int i = 0; i < num; i++) {
			hmap.put(String.valueOf(i), null);
		}
		System.out.println(
			"HashMap.put:" + (System.currentTimeMillis() - start));

		start = System.currentTimeMillis();
		for (int i = 0; i < num; i++) {
			amap.put(String.valueOf(i), null);
		}
		System.out.println(
			"ArrayMap.put:" + (System.currentTimeMillis() - start));

		start = System.currentTimeMillis();
		for (int i = 0; i < num; i++) {
			hmap.get(String.valueOf(i));
		}
		System.out.println(
			"HashMap.get:" + (System.currentTimeMillis() - start));

		start = System.currentTimeMillis();
		for (int i = 0; i < num; i++) {
			amap.get(String.valueOf(i));
		}
		System.out.println(
			"ArrayMap.get:" + (System.currentTimeMillis() - start));

		start = System.currentTimeMillis();
		for (Iterator i = hmap.entrySet().iterator(); i.hasNext();) {
			i.next();
		}
		System.out.println(
			"HashMap iteration:" + (System.currentTimeMillis() - start));

		start = System.currentTimeMillis();
		for (Iterator i = amap.entrySet().iterator(); i.hasNext();) {
			i.next();
		}
		System.out.println(
			"ArrayMap iteration:" + (System.currentTimeMillis() - start));

		start = System.currentTimeMillis();
		SerializeUtil.serialize(hmap);
		System.out.println(
			"HashMap serialize:" + (System.currentTimeMillis() - start));

		start = System.currentTimeMillis();
		SerializeUtil.serialize(amap);
		System.out.println(
			"ArrayMap serialize:" + (System.currentTimeMillis() - start));
	}

	protected void setUp() throws Exception {
		_map = new ArrayMap();
		_map.put(null, null);
		_map.put("1", "test");
		_map.put("2", "test2");
	}

	protected void tearDown() throws Exception {
		_map = null;
	}

	public static Test suite() {
		return new TestSuite(ArrayMapTest.class);
	}

	public static void main(String[] args) {
		junit.textui.TestRunner.main(
			new String[] { ArrayMapTest.class.getName()});
	}

	private static class MyKey {
		Object _key;
		MyKey(Object key) {
			_key = key;
		}

		public int hashCode() {
			return 0;
		}

		public boolean equals(Object o) {
			if (o == this) {
				return true;
			}
			if (o == null || !(o instanceof MyKey)) {
				return false;
			}
			return _key.equals(((MyKey) o)._key);
		}
	}
}