package org.arefgard.icerya.container;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.List;
import java.util.Map;

import org.junit.Test;

public class IceryaContainerTest {
	
	/**
	 * Bean定義ファイルをパースして、空のオブジェクトを生成できる
	 * ことを確認する。
	 */
	@Test
	public void getSimpleBean() {
		try {
			// IceryaContainerを直接使用
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			
			// 従来の呼び方
			String userId = (String)container.getBean("userId");
			assertNotNull(userId);
			assertEquals("", userId);
			
			// ジェネリックを使った呼び方
			userId = container.getBean("userId", String.class);
			assertNotNull(userId);
			assertEquals("", userId);
			
			
			// ApplicationContextを利用
			ApplicationContext context = new ApplicationContext("sample");
			
			// 従来の呼び方
			userId = (String)context.getBean("userId");
			assertNotNull(userId);
			assertEquals("", userId);
			
			// ジェネリックを使った呼び方
			userId = context.getBean("userId", String.class);
			assertNotNull(userId);
			assertEquals("", userId);
			
		}catch(ContainerException e) {
			fail("error occurred." + e);
		}
	}
	
	/**
	 * Bean定義ファイルをパースして、プロパティを設定したオブジェクトを
	 * 生成できることを確認する。
	 */
	@Test
	public void getBeanWithProperty01() {
		try {
			// IceryaContainerを直接使用
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			
			// 従来の呼び方
			TestObject01 obj = (TestObject01)container.getBean("testObject01");
			assertEquals("abc", obj.getField01());
			assertEquals("def", obj.getField02());
			assertEquals("ghi", obj.getField03());
			
			// ジェネリックを使った呼び方
			obj = container.getBean("testObject01", TestObject01.class);
			assertEquals("abc", obj.getField01());
			assertEquals("def", obj.getField02());
			assertEquals("ghi", obj.getField03());
			
			// ApplicationContextを利用
			ApplicationContext context = new ApplicationContext("sample");
			
			// 従来の呼び方
			obj = (TestObject01)context.getBean("testObject01");
			assertEquals("abc", obj.getField01());
			assertEquals("def", obj.getField02());
			assertEquals("ghi", obj.getField03());
			
			// ジェネリックを使った呼び方
			obj = context.getBean("testObject01", TestObject01.class);
			assertEquals("abc", obj.getField01());
			assertEquals("def", obj.getField02());
			assertEquals("ghi", obj.getField03());
			
			
		}catch(ContainerException e) {
			fail("error occurred." + e);
		}
	}
	
	/**
	 * Bean定義ファイルをパースして、プロパティを設定したオブジェクトを
	 * 生成できることを確認する。
	 * 
	 * インタフェースを実装しているクラスの場合。
	 */
	@Test
	public void getBeanWithProperty02() {
		try {
			// IceryaContainerを直接使用
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			
			// 従来の呼び方
			TestObject02 obj = (TestObject02)container.getBean("testObject02");
			assertEquals("123", obj.getField01());
			assertEquals("456", obj.getField02());
			assertEquals("789", obj.getField03());
			
			// ジェネリックを使った呼び方
			obj = container.getBean("testObject02", TestObject02.class);
			assertEquals("123", obj.getField01());
			assertEquals("456", obj.getField02());
			assertEquals("789", obj.getField03());
			
			// ApplicationContextを利用
			ApplicationContext context = new ApplicationContext("sample");
			
			// 従来の呼び方
			obj = (TestObject02)context.getBean("testObject02");
			assertEquals("123", obj.getField01());
			assertEquals("456", obj.getField02());
			assertEquals("789", obj.getField03());
			
			// ジェネリックを使った呼び方
			obj = context.getBean("testObject02", TestObject02.class);
			assertEquals("123", obj.getField01());
			assertEquals("456", obj.getField02());
			assertEquals("789", obj.getField03());
			
		}catch(ContainerException e) {
			fail("error occurred." + e);
		}
	}
	
	/**
	 * Bean定義ファイルをパースして、プロパティを設定したオブジェクトを
	 * 生成できることを確認する。
	 * 
	 * 抽象クラスを継承しているクラスの場合。
	 */
	@Test
	public void getBeanWithProperty03() {
		try {
			// IceryaContainerを直接使用
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			
			// 従来の呼び方
			TestObject03 obj = (TestObject03)container.getBean("testObject03");
			assertEquals("ABC", obj.getField01());
			assertEquals("DEF", obj.getField02());
			assertEquals("GHI", obj.getField03());
			
			// ジェネリックを使った呼び方
			obj = container.getBean("testObject03", TestObject03.class);
			assertEquals("ABC", obj.getField01());
			assertEquals("DEF", obj.getField02());
			assertEquals("GHI", obj.getField03());
			
			// ApplicationContextを利用
			ApplicationContext context = new ApplicationContext("sample");
			
			// 従来の呼び方
			obj = (TestObject03)context.getBean("testObject03");
			assertEquals("ABC", obj.getField01());
			assertEquals("DEF", obj.getField02());
			assertEquals("GHI", obj.getField03());
			
			// ジェネリックを使った呼び方
			obj = context.getBean("testObject03", TestObject03.class);
			assertEquals("ABC", obj.getField01());
			assertEquals("DEF", obj.getField02());
			assertEquals("GHI", obj.getField03());
		}catch(ContainerException e) {
			fail("error occurred." + e);
		}
	}
	
	/**
	 * Bean定義ファイルをパースして、プロパティを設定したオブジェクトを
	 * 生成できることを確認する。
	 * 
	 * ジェネレーションギャップパターンの場合。
	 */
	@Test
	public void getBeanWithProperty04() {
		try {
			// IceryaContainerを直接使用
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			
			// 従来の呼び方
			TestObject04 obj = (TestObject04)container.getBean("testObject04");
			assertEquals("987", obj.getField01());
			assertEquals("654", obj.getField02());
			assertEquals("321", obj.getField03());
			
			// ジェネリックを使った呼び方
			obj = container.getBean("testObject04", TestObject04.class);
			assertEquals("987", obj.getField01());
			assertEquals("654", obj.getField02());
			assertEquals("321", obj.getField03());
			
			// ApplicationContextを利用
			ApplicationContext context = new ApplicationContext("sample");
			
			// 従来の呼び方
			obj = (TestObject04)context.getBean("testObject04");
			assertEquals("987", obj.getField01());
			assertEquals("654", obj.getField02());
			assertEquals("321", obj.getField03());
			
			// ジェネリックを使った呼び方
			obj = context.getBean("testObject04", TestObject04.class);
			assertEquals("987", obj.getField01());
			assertEquals("654", obj.getField02());
			assertEquals("321", obj.getField03());
		}catch(ContainerException e) {
			fail("error occurred." + e);
		}
	}
	
	/**
	 * Bean定義ファイルをパースして、プロパティを設定したオブジェクトを
	 * 生成できることを確認する。
	 * 
	 * 他のオブジェクトを参照した場合。
	 */
	@Test
	public void getBeanWithRefProperty() {
		try {
			// IceryaContainerを直接使用
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			
			// 従来の呼び方
			TestObject05 obj = (TestObject05)container.getBean("testObject05");
			assertEquals("abc", obj.getField01().getField01());
			assertEquals("def", obj.getField01().getField02());
			assertEquals("ghi", obj.getField01().getField03());
			assertEquals("123", obj.getField02().getField01());
			assertEquals("456", obj.getField02().getField02());
			assertEquals("789", obj.getField02().getField03());
			assertEquals("ABC", obj.getField03().getField01());
			assertEquals("DEF", obj.getField03().getField02());
			assertEquals("GHI", obj.getField03().getField03());
			
			// ジェネリックを使った呼び方
			obj = container.getBean("testObject05", TestObject05.class);
			assertEquals("abc", obj.getField01().getField01());
			assertEquals("def", obj.getField01().getField02());
			assertEquals("ghi", obj.getField01().getField03());
			assertEquals("123", obj.getField02().getField01());
			assertEquals("456", obj.getField02().getField02());
			assertEquals("789", obj.getField02().getField03());
			assertEquals("ABC", obj.getField03().getField01());
			assertEquals("DEF", obj.getField03().getField02());
			assertEquals("GHI", obj.getField03().getField03());
			
			// ApplicationContextを利用
			ApplicationContext context = new ApplicationContext("sample");
			
			// 従来の呼び方
			obj = (TestObject05)context.getBean("testObject05");
			assertEquals("abc", obj.getField01().getField01());
			assertEquals("def", obj.getField01().getField02());
			assertEquals("ghi", obj.getField01().getField03());
			assertEquals("123", obj.getField02().getField01());
			assertEquals("456", obj.getField02().getField02());
			assertEquals("789", obj.getField02().getField03());
			assertEquals("ABC", obj.getField03().getField01());
			assertEquals("DEF", obj.getField03().getField02());
			assertEquals("GHI", obj.getField03().getField03());
			
			// ジェネリックを使った呼び方
			obj = context.getBean("testObject05", TestObject05.class);
			assertEquals("abc", obj.getField01().getField01());
			assertEquals("def", obj.getField01().getField02());
			assertEquals("ghi", obj.getField01().getField03());
			assertEquals("123", obj.getField02().getField01());
			assertEquals("456", obj.getField02().getField02());
			assertEquals("789", obj.getField02().getField03());
			assertEquals("ABC", obj.getField03().getField01());
			assertEquals("DEF", obj.getField03().getField02());
			assertEquals("GHI", obj.getField03().getField03());
			
		}catch(ContainerException e) {
			fail("error occurred." + e);
		}
	}
	
	/**
	 * Bean定義ファイルをパースして、リストオブジェクトを生成できることを
	 * 確認する。
	 */
	@Test
	public void getList01() {
		try {
			// IceryaContainerを直接使用
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			
			// 従来の呼び方
			List list = (List)container.getBean("list1");
			assertNotNull(list);
			assertEquals("value1", list.get(0));
			assertEquals("value2", list.get(1));
			assertEquals(true, list.get(2) instanceof TestObject01);
			assertEquals(true, list.get(3) instanceof TestObject05);
			assertEquals(true, list.get(4) instanceof TestObject01);
			assertEquals(true, list.get(5) instanceof TestObject05);
			
			// ジェネリックを使った呼び方
			list = container.getBean("list1", List.class);
			assertNotNull(list);
			assertEquals("value1", list.get(0));
			assertEquals("value2", list.get(1));
			assertEquals(true, list.get(2) instanceof TestObject01);
			assertEquals(true, list.get(3) instanceof TestObject05);
			assertEquals(true, list.get(4) instanceof TestObject01);
			assertEquals(true, list.get(5) instanceof TestObject05);
			
			
			// ApplicationContextを利用
			ApplicationContext context = new ApplicationContext("sample");
			
			// 従来の呼び方
			list = (List)context.getBean("list1");
			assertNotNull(list);
			assertEquals("value1", list.get(0));
			assertEquals("value2", list.get(1));
			assertEquals(true, list.get(2) instanceof TestObject01);
			assertEquals(true, list.get(3) instanceof TestObject05);
			assertEquals(true, list.get(4) instanceof TestObject01);
			assertEquals(true, list.get(5) instanceof TestObject05);
			
			// ジェネリックを使った呼び方
			list = context.getBean("list1", List.class);
			assertNotNull(list);
			assertEquals("value1", list.get(0));
			assertEquals("value2", list.get(1));
			assertEquals(true, list.get(2) instanceof TestObject01);
			assertEquals(true, list.get(3) instanceof TestObject05);
			assertEquals(true, list.get(4) instanceof TestObject01);
			assertEquals(true, list.get(5) instanceof TestObject05);
			
		}catch(ContainerException e) {
			fail("error occurred." + e);
		}
	}
	
	/**
	 * Bean定義ファイルをパースして、マップオブジェクトを生成できることを
	 * 確認する。
	 */
	@Test
	public void getMap01() {
		try {
			// IceryaContainerを直接使用
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			
			// 従来の呼び方
			Map map = (Map)container.getBean("map1");
			assertNotNull(map);
			assertEquals("value1", map.get("key1"));
			assertEquals("value2", map.get("key2"));
			assertEquals(true, map.get("key3") instanceof TestObject01);
			assertEquals(true, map.get("key4") instanceof TestObject05);
			assertEquals(true, map.get("key5") instanceof TestObject01);
			assertEquals(true, map.get("key6") instanceof TestObject05);
			
			// ジェネリックを使った呼び方
			map = container.getBean("map1", Map.class);
			assertNotNull(map);
			assertEquals("value1", map.get("key1"));
			assertEquals("value2", map.get("key2"));
			assertEquals(true, map.get("key3") instanceof TestObject01);
			assertEquals(true, map.get("key4") instanceof TestObject05);
			assertEquals(true, map.get("key5") instanceof TestObject01);
			assertEquals(true, map.get("key6") instanceof TestObject05);
			
			
			// ApplicationContextを利用
			ApplicationContext context = new ApplicationContext("sample");
			
			// 従来の呼び方
			map = (Map)context.getBean("map1");
			assertNotNull(map);
			assertEquals("value1", map.get("key1"));
			assertEquals("value2", map.get("key2"));
			assertEquals(true, map.get("key3") instanceof TestObject01);
			assertEquals(true, map.get("key4") instanceof TestObject05);
			assertEquals(true, map.get("key5") instanceof TestObject01);
			assertEquals(true, map.get("key6") instanceof TestObject05);
			
			// ジェネリックを使った呼び方
			map = context.getBean("map1", Map.class);
			assertNotNull(map);
			assertEquals("value1", map.get("key1"));
			assertEquals("value2", map.get("key2"));
			assertEquals(true, map.get("key3") instanceof TestObject01);
			assertEquals(true, map.get("key4") instanceof TestObject05);
			assertEquals(true, map.get("key5") instanceof TestObject01);
			assertEquals(true, map.get("key6") instanceof TestObject05);
			
		}catch(ContainerException e) {
			fail("error occurred." + e);
		}
	}
	
	/**
	 * Bean定義ファイルをパースして、アウターインジェクションをできることを
	 * 確認する。
	 */
	@Test
	public void outerInjection() {
		try {
			// IceryaContainerを直接使用
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			
			TestObject01 obj = new TestObject01();
			
			container.injectDependency("testObject01", obj);
			assertEquals("abc", obj.getField01());
			assertEquals("def", obj.getField02());
			assertEquals("ghi", obj.getField03());
			
			// ApplicationContextを利用
			ApplicationContext context = new ApplicationContext("sample");
			
			obj = new TestObject01();
			
			context.injectDependency("testObject01", obj);
			assertEquals("abc", obj.getField01());
			assertEquals("def", obj.getField02());
			assertEquals("ghi", obj.getField03());	
			
		}catch(ContainerException e) {
			fail("error occurred." + e);
		}
	}
	
	/**
	 * Bean定義ファイルをパースして、アウターインジェクションをできることを
	 * 確認する。
	 */
	@Test
	public void constructorArg() {
		try {
			// IceryaContainerを直接使用
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			
			TestObject06 obj = (TestObject06)container.getBean("testObject06");
			assertEquals("123", obj.getField01());
			assertEquals("456", obj.getField02());
			assertEquals("789", obj.getField03());
			
		}catch(ContainerException e) {
			fail("error occurred." + e);
		}
	}
	
	/**
	 * Bean定義ファイルをパースして、AOPが利用可能なことを確認する。
	 */
	@Test
	public void aopInjection() {
		try {
			// IceryaContainerを直接使用
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			
			TestObject07 obj = (TestObject07)container.getBean("testObject07");
			assertEquals("123", obj.getField01());
			assertEquals("456", obj.getField02());
			assertEquals("789", obj.getField03());
			
		}catch(ContainerException e) {
			fail("error occurred." + e);
		}
	}
	
	
	
//	@Test
//	public void getBeanUsingInitMethodAndDestroyMethod() {
//		try {
//			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container05.xml");
//			Object01 obj = (Object01)container.getBean("obj01");
//			assertEquals("INIT", obj.getField01());
//		}catch(ContainerException e) {
//			e.printStackTrace();
//			fail("" + e);
//		}
//	}
//	
//	@Test
//	public void getBeanInIncludedContainer() {
//		try {
//			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container05.xml");
//			Object02 obj = (Object02)container.getBean("obj02");
//			assertEquals("hoge", obj.getField01());
//		}catch(ContainerException e) {
//			e.printStackTrace();
//			fail("" + e);
//		}
//	}
//	/*
//	@Test
//	public void getBeanUsingEJBInjection() {
//		try {
//			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container06.xml");
//			HelloStateless hello = (HelloStateless)container.getBean("hello");
//			assertEquals("Hello hoge!", hello.sayHello("hoge"));
//		}catch(Exception e) {
//			
//		}
//	}
//	*/
	
	/**
	 * IDにnullを指定した場合に、例外が発生することを確認する。
	 */
	@Test
	public void setNullID() {
		try {
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			container.getBean(null);
			fail("failed.");
		}catch(ContainerException e) {
			assertTrue(true);
			return;
		}catch(Exception e) {
			fail("unexpected exception occurred." + e);
		}
	}
	
	/**
	 * IDに空文字を指定した場合に、例外が発生することを確認する。
	 */
	@Test
	public void setEmptyID() {
		try {
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			container.getBean("");
			fail("failed.");
		}catch(ContainerException e) {
			assertTrue(true);
			return;
		}catch(Exception e) {
			fail("unexpected exception occurred." + e);
		}
	}
	
	/**
	 * IDに存在しないIDを指定した場合に、例外が発生することを確認する。
	 */
	@Test
	public void setNotExistsID() {
		try {
			IceryaContainer container = ContainerFactory.create("org/arefgard/icerya/container/container.xml");
			container.getBean("hoge");
			fail("failed.");
		}catch(ContainerException e) {
			assertTrue(true);
			return;
		}catch(Exception e) {
			fail("unexpected exception occurred." + e);
		}
	}
	
	/**
	 * 存在しないパスを指定した場合に、例外が発生することを確認する。
	 */
	@Test
	public void setIllegalPath() {
		try {
			IceryaContainer container = ContainerFactory.create("notfound");
			fail("failed.");
		}catch(ContainerException e) {
			assertTrue(true);
			return;
		}catch(Exception e) {
			fail("unexpected exception occurred." + e);
		}
	}
	
}
