/*
 * Copyright 2006 Takahiro Nakamura.
 *
 * 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 woolpack.utils;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;

import junit.framework.TestCase;

public class SynchronizedConcurrentMapTest extends TestCase {
	private final Map<String, String> base = new HashMap<String, String>();

	private final ConcurrentMap<String, String> map = UtilsConstants
			.concurrentMap(base, new Object());

	public void testConstructor() {
		try {
			new DelegationMap<String, String>(null);
			fail();
		} catch (NullPointerException expected) {
		}
	}

	public void testConcurrent() {
		// TODO 同期化のテスト
		map.clear();

		assertNull(map.putIfAbsent("key0", "value0"));
		assertEquals("value0", map.get("key0"));

		assertEquals("value0", map.putIfAbsent("key0", "value1"));
		assertEquals("value0", map.get("key0"));

		assertFalse(map.replace("key0", "value1", "value2"));
		assertEquals("value0", map.get("key0"));

		assertTrue(map.replace("key0", "value0", "value1"));
		assertEquals("value1", map.get("key0"));

		assertNull(map.replace("key1", "value5"));
		assertEquals("value1", map.get("key0"));

		assertEquals("value1", map.replace("key0", "value2"));
		assertEquals("value2", map.get("key0"));

		assertFalse(map.remove("key0", "value1"));
		assertTrue(map.remove("key0", "value2"));
	}

	public void testNormal() {
		map.clear();
		map.put("key0", "value0");
		{
			final Map<String, String> tmpMap = new HashMap<String, String>();
			tmpMap.put("key1", "value1");
			tmpMap.put("key2", "value2");
			map.putAll(tmpMap);
		}

		assertEquals(base.toString(), map.toString());
		assertEquals(base.hashCode(), map.hashCode());
		assertTrue(map.equals(base));

		{
			final Set<String> expected = new HashSet<String>();
			expected.add("key0");
			expected.add("key1");
			expected.add("key2");
			assertTrue(expected.containsAll(map.keySet()));
			assertTrue(map.keySet().containsAll(expected));
		}
		{
			final Set<String> expected = new HashSet<String>();
			expected.add("value0");
			expected.add("value1");
			expected.add("value2");
			assertTrue(expected.containsAll(map.values()));
			assertTrue(map.values().containsAll(expected));
		}
		{
			final Map<String, String> tmpMap = new HashMap<String, String>();
			for (final Map.Entry<String, String> e : map.entrySet()) {
				tmpMap.put(e.getKey(), e.getValue());
			}
			final Map<String, String> expected = new HashMap<String, String>();
			expected.put("key0", "value0");
			expected.put("key1", "value1");
			expected.put("key2", "value2");
			assertEquals(expected, tmpMap);
		}
		assertFalse(map.isEmpty());
		assertEquals(3, map.size());
		assertTrue(map.containsKey("key0"));
		assertTrue(map.containsKey("key1"));
		assertTrue(map.containsKey("key2"));
		assertTrue(map.containsValue("value0"));
		assertTrue(map.containsValue("value1"));
		assertTrue(map.containsValue("value2"));
		assertEquals("value0", map.get("key0"));
		assertEquals("value1", map.get("key1"));
		assertEquals("value2", map.get("key2"));

		map.remove("key2");

		{
			final Set<String> expected = new HashSet<String>();
			expected.add("key0");
			expected.add("key1");
			assertTrue(expected.containsAll(map.keySet()));
			assertTrue(map.keySet().containsAll(expected));
		}
		{
			final Set<String> expected = new HashSet<String>();
			expected.add("value0");
			expected.add("value1");
			assertTrue(expected.containsAll(map.values()));
			assertTrue(map.values().containsAll(expected));
		}
		{
			final Map<String, String> tmpMap = new HashMap<String, String>();
			for (final Map.Entry<String, String> e : map.entrySet()) {
				tmpMap.put(e.getKey(), e.getValue());
			}
			final Map<String, String> expected = new HashMap<String, String>();
			expected.put("key0", "value0");
			expected.put("key1", "value1");
			assertEquals(expected, tmpMap);
		}
		assertFalse(map.isEmpty());
		assertEquals(2, map.size());
		assertTrue(map.containsKey("key0"));
		assertTrue(map.containsKey("key1"));
		assertFalse(map.containsKey("key2"));
		assertTrue(map.containsValue("value0"));
		assertTrue(map.containsValue("value1"));
		assertFalse(map.containsValue("value2"));
		assertEquals("value0", map.get("key0"));
		assertEquals("value1", map.get("key1"));
		assertNull(map.get("key2"));

		map.clear();

		{
			final Set<String> expected = new HashSet<String>();
			assertTrue(expected.containsAll(map.keySet()));
			assertTrue(map.keySet().containsAll(expected));
		}
		{
			final Set<String> expected = new HashSet<String>();
			assertTrue(expected.containsAll(map.values()));
			assertTrue(map.values().containsAll(expected));
		}
		{
			final Map<String, String> tmpMap = new HashMap<String, String>();
			for (final Map.Entry<String, String> e : map.entrySet()) {
				tmpMap.put(e.getKey(), e.getValue());
			}
			final Map<String, String> expected = new HashMap<String, String>();
			assertEquals(expected, tmpMap);
		}
		assertTrue(map.isEmpty());
		assertEquals(0, map.size());
		assertFalse(map.containsKey("key0"));
		assertFalse(map.containsKey("key1"));
		assertFalse(map.containsKey("key2"));
		assertFalse(map.containsValue("value0"));
		assertFalse(map.containsValue("value1"));
		assertFalse(map.containsValue("value2"));
		assertNull(map.get("key0"));
		assertNull(map.get("key1"));
		assertNull(map.get("key2"));
	}
}
