/*
 * 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;

import java.beans.PropertyDescriptor;
import java.io.Reader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;

import javax.sql.DataSource;

import junit.framework.TestCase;

import org.w3c.dom.Node;

import woolpack.acquirable.Acquirable;
import woolpack.acquirable.AcquirableChain;
import woolpack.acquirable.AcquirableUtils;
import woolpack.acquirable.DoLock;
import woolpack.acquirable.DoSemaphore;
import woolpack.acquirable.DoSemaphoreFactory;
import woolpack.acquirable.TryLock;
import woolpack.acquirable.TrySemaphore;
import woolpack.acquirable.TrySemaphoreFactory;
import woolpack.action.ActionDef;
import woolpack.action.ActionInvoker;
import woolpack.action.ActionResult;
import woolpack.action.ForwardDef;
import woolpack.adapter.ConvertableTypeConverter;
import woolpack.adapter.JXE;
import woolpack.adapter.OGE;
import woolpack.bool.BoolUtils;
import woolpack.config.ConfigContext;
import woolpack.config.ConfigUtils;
import woolpack.container.ContainerContext;
import woolpack.convert.ConvertUtils;
import woolpack.ee.ActionBuilder;
import woolpack.ee.EEContext;
import woolpack.ee.ValidatorBuilder;
import woolpack.el.ArrayPathEL;
import woolpack.el.CachePropertyELFactory;
import woolpack.el.ELUtils;
import woolpack.el.FixEL;
import woolpack.el.GettingEL;
import woolpack.el.MapEL;
import woolpack.el.MapPropertyELFactory;
import woolpack.el.MapSimilarPropertyELFactory;
import woolpack.el.MaybeEL;
import woolpack.el.MaybePropertyELFactory;
import woolpack.el.PathEL;
import woolpack.el.PropertyEL;
import woolpack.el.ReflectionPropertyELFactory;
import woolpack.el.SimilarPropertyELFactory;
import woolpack.el.ThisEL;
import woolpack.factory.FactoryUtils;
import woolpack.fn.Fn;
import woolpack.fn.FnUtils;
import woolpack.html.HtmlUtils;
import woolpack.id.IdContext;
import woolpack.id.IdUtils;
import woolpack.idnode.IdNodeUtils;
import woolpack.idnode.SimpleIdNodeContext;
import woolpack.misc.MiscUtils;
import woolpack.sql.adapter.DataSourceAdapter;
import woolpack.sql.convert.ParamBindInfo;
import woolpack.sql.convert.SqlOperator;
import woolpack.sql.fn.PreparedStatementInfo;
import woolpack.sql.fn.SqlFnUtils;
import woolpack.sql.meta.ColumnInfo;
import woolpack.sql.meta.ReferenceInfo;
import woolpack.sql.meta.TableInfo;
import woolpack.sql.tx.SqlTxUtils;
import woolpack.sql.tx.TxBuilder;
import woolpack.sql.tx.TxFn;
import woolpack.typeconvert.ConvertContext;
import woolpack.typeconvert.Converter;
import woolpack.typeconvert.DelegationIfNecessityConverter;
import woolpack.typeconvert.SettingFnConverter;
import woolpack.typeconvert.ToArrayConverter;
import woolpack.typeconvert.ToCollectionDecompositionConverter;
import woolpack.typeconvert.ToCollectionViewConverter;
import woolpack.typeconvert.ToMapViewConverter;
import woolpack.typeconvert.ToTypeConverter;
import woolpack.utils.AppendableWriter;
import woolpack.utils.BeanUtils;
import woolpack.utils.DelegationCollection;
import woolpack.utils.DelegationMap;
import woolpack.utils.MapIterableMap;
import woolpack.utils.Utils;
import woolpack.validator.AddressedMessage;
import woolpack.validator.SimpleMessageCollector;
import woolpack.validator.ValidatorContext;
import woolpack.validator.ValidatorUtils;
import woolpack.visitor.Visitor;
import woolpack.web.WebContext;
import woolpack.web.WebUtils;
import woolpack.xml.NodeContext;
import woolpack.xml.XPathUtils;
import woolpack.xml.XmlTransformerUtils;
import woolpack.xml.XmlUtils;

/**
 * コンストラクタとアクセサをテストします。
 * @author nakamura
 *
 */
public class AccessorTest extends TestCase {
	
	/**
	 * 以下の観点をテストします。
	 * コンストラクタすべて null でもよい。
	 * @param o
	 * @throws IllegalArgumentException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	private void checkNullConsructors(final Object o) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
		final Class<?> clazz = o.getClass();
		final Constructor[] array = clazz.getConstructors();
		for(final Constructor c : array) {
			final Class[] paramTypes = c.getParameterTypes();
			final Object[] params = new Object[paramTypes.length];
			for(int i = 0; i < paramTypes.length; i++) {
				final Class paramType = paramTypes[i];
				if (paramType.isPrimitive()) {
					Object param = null;
					if (boolean.class.equals(paramType)) {
						param = false;
					} else if (char.class.equals(paramType)) {
						param = 'c';
					} else if (byte.class.equals(paramType)) {
						param = (byte)0;
					} else if (short.class.equals(paramType)) {
						param = (short)0;
					} else if (int.class.equals(paramType)) {
						param = (int)0;
					} else if (long.class.equals(paramType)) {
						param = (long)0;
					} else if (float.class.equals(paramType)) {
						param = (float)0;
					} else if (double.class.equals(paramType)) {
						param = (double)0;
					}
					params[i] = param;
				}
			}
			c.newInstance(params);
		}
	}
	
	/**
	 * 以下の観点をテストします。
	 * コンストラクタとゲッターメソッドの対応({@link BeanUtils#getConstructorGetterList}で試験される)。
	 * @param o
	 */
	public void checkGC(final Object o) {
		BeanUtils.getConstructorGetterList(o);
	}
	
	/**
	 * 以下の観点をテストします。
	 * コンストラクタとゲッターメソッドの対応({@link BeanUtils#getConstructorGetterList}で試験される)。
	 * ゲッターメソッドに対するセッターメソッドが存在する。
	 * @param o
	 * @throws IllegalArgumentException
	 * @throws SecurityException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	private void checkSC(final Object o) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		final List<PropertyDescriptor> list = BeanUtils.getConstructorGetterList(o);
		final Object[] params = new Object[list.size()];
		final Class[] paramTypes = new Class[params.length];
		for (int i = 0; i < params.length; i++) {
			final PropertyDescriptor d = list.get(i);
			params[i] = d.getReadMethod().invoke(o, new Object[0]);
			paramTypes[i] = d.getPropertyType();
		}
		final Object o2 = o.getClass().getConstructor(paramTypes).newInstance(params);
		for (int i = 0; i < params.length; i++) {
			final PropertyDescriptor d = list.get(i);
			assertEquals(params[i], d.getReadMethod().invoke(o2, new Object[0]));
			d.getWriteMethod().invoke(o2, new Object[]{params[i]});
			assertEquals(params[i], d.getReadMethod().invoke(o2, new Object[0]));
		}
	}
	
	/**
	 * 以下の観点をテストします。
	 * ゲッターメソッドに対するセッターメソッドが存在する。
	 * 
	 * @param o
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	private void checkS(final Object o) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		final List<PropertyDescriptor> list = BeanUtils.getGetterList(o.getClass());
		for (final PropertyDescriptor d : list) {
			final Object v = d.getReadMethod().invoke(o, new Object[0]);
			d.getWriteMethod().invoke(o, new Object[]{v});
			assertEquals(v, d.getReadMethod().invoke(o, new Object[0]));
		}
	}
	
//	private void checkGCN(final Object o) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
//		checkNullConsructors(o);
//		checkGC(o);
//	}
	
	private void checkSCN(final Object o) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
		checkNullConsructors(o);
		checkSC(o);
	}
	
	public void testAccessor() throws Exception {
		
		// base
		checkSCN(FnUtils.castTo(Integer.class));
		checkSCN(FnUtils.delegate(FnUtils.fix(null)));
		checkSCN(FnUtils.exec(FnUtils.<Integer, Fn<? super Integer, ? extends String, RuntimeException>>fix(null)));
		checkSCN(FnUtils.fix("a"));
		checkSCN(FnUtils.ifTrue(
				FnUtils.fix(null),
				FnUtils.fix(null),
				FnUtils.fix(null)
		));
		checkSCN(FnUtils.join(
				FnUtils.fix(null),
				FnUtils.fix(null)
		));
		checkSCN(FnUtils.recode(
				FnUtils.fix(null),
				"a",
				new ArrayList<String>(),
				new ArrayList<Object>(),
				new ArrayList<Object>()
		));
		checkSCN(FnUtils.seq(Utils
				.list(FnUtils.fix(null))
				.list(FnUtils.fix(null))
		));
		checkSCN(FnUtils.switching(Utils.map(3, "a").map(5, "a"), "a"));
		checkSCN(FnUtils.throwing(new RuntimeException()));
		checkSCN(FnUtils.trying(
				FnUtils.fix(null),
				FnUtils.<Throwable, Object>fix(null),
				FnUtils.fix(null)
		));
		
		// bool
		checkSCN(BoolUtils.boolSeq(
				BoolUtils.AND,
				Utils
				.list(FnUtils.<Object, Boolean>fix(null))
				.list(FnUtils.<Object, Boolean>fix(null))
		));
		checkSCN(BoolUtils.compare(3));
		checkSCN(BoolUtils.containsAll(new ArrayList<Integer>()));
		checkSCN(BoolUtils.contains(new ArrayList<Integer>()));
		checkSCN(BoolUtils.checkEquals(new Object()));
		checkSCN(BoolUtils.checkMax(3));
		checkSCN(BoolUtils.checkMaxLength(3));
		checkSCN(BoolUtils.checkMin(3));
		checkSCN(BoolUtils.checkMinLength(3));
		checkSCN(BoolUtils.not(FnUtils.<Integer, Boolean>fix(null)));
		checkSCN(BoolUtils.matchObject(new Object()));
		checkSCN(BoolUtils.checkRegExp(Pattern.compile(".*")));
		
		// convert
		checkSCN(ConvertUtils.formatFactory(new DecimalFormat()));
		checkSCN(ConvertUtils.format(ConvertUtils.formatFactory(new DecimalFormat())));
		checkSCN(ConvertUtils.netMask("255.255.255.0"));
		checkSCN(ConvertUtils.parse(ConvertUtils.formatFactory(new DecimalFormat())));
		checkSCN(ConvertUtils.convertRegExp(Pattern.compile("(.*)"), "$1"));
		checkSCN(ConvertUtils.trys(Utils
				.list(FnUtils.fix(null))
				.list(FnUtils.fix(null)),
				FnUtils.fix(null),
				FnUtils.fix(null)));
		checkSCN(ConvertUtils.retainKeys(new ArrayList<String>()));
		
		// id
		checkSCN(IdUtils.convertId(FnUtils.<String, String>fix(null)));
		checkSCN(IdUtils.localId(FnUtils.<IdContext, Boolean>fix(null)));
		
		// xml
		checkSCN(XmlUtils.branchByAttrValue(
				Arrays.asList("a"),
				FnUtils.<String, Fn<NodeContext, Void, RuntimeException>>fix(null)
		));
		checkSCN(XmlUtils.findNode(
				XPathUtils.list("a"),
				FnUtils.<NodeContext, Void>fix(null),
				FnUtils.<NodeContext, Void>fix(null)
		));
		checkSCN(XmlUtils.getAttrValue("a"));
		checkSCN(XmlUtils.insertElementToChild("a", FnUtils.<NodeContext, Void>fix(null)));
		checkSCN(XmlUtils.insertElementToParent("a", FnUtils.<NodeContext, Void>fix(null)));
		checkSCN(XmlUtils.copyTemplate(ELUtils.NULL, new PathEL("a"), FnUtils.<NodeContext, Void>fix(null)));
		checkSCN(XmlUtils.nodeFactory(FnUtils.<String, Reader>fix(null), XmlTransformerUtils.TRANSFORMER));
		checkSCN(XmlUtils.removeAttr("a"));
		checkSCN(XmlUtils.replaceText(FnUtils.<NodeContext, String>fix(null)));
		checkSCN(XmlUtils.replaceTextToChild(FnUtils.<NodeContext, String>fix(null)));
		checkSCN(XmlUtils.seekNode(FnUtils.<NodeContext, Void>fix(null)));
		checkSCN(XmlUtils.setNode(FnUtils.<NodeContext, Node>fix(null)));
		checkSCN(XmlUtils.updateAttrValue("a", FnUtils.<NodeContext, String>fix(null)));

		// validator
		checkSCN(new AddressedMessage("a", 0, "b", "c"));
		checkSCN(ValidatorUtils.branchByName(
				BoolUtils.AND,
				new HashMap<String, Fn<ValidatorContext, Boolean, RuntimeException>>()));
		checkSCN(ValidatorUtils.branchByNameIfExists(
				BoolUtils.AND,
				new HashMap<String, Fn<ValidatorContext, Boolean, RuntimeException>>()));
		checkSCN(ValidatorUtils.convertValue(FnUtils.<Object, Object>fix(null)));
		checkSCN(ValidatorUtils.message("a"));
		checkSCN(ValidatorUtils.localIndex(0, FnUtils.<ValidatorContext, Boolean>fix(null)));
		checkSCN(ValidatorUtils.localKey("a", FnUtils.<ValidatorContext, Boolean>fix(null)));
		checkSCN(ValidatorUtils.loopValue(
				BoolUtils.AND,
				FnUtils.<ValidatorContext, Boolean>fix(null)));
		{
			// getValueがあるので個別対応
			final ValidatorContext o = new ValidatorContext();
			final SimpleMessageCollector c = new SimpleMessageCollector();
			o.setCollectable(c);
			assertEquals(c, o.getCollectable());
		}
		
		// html
		checkSCN(HtmlUtils.updateAuto(
				Arrays.asList("a"),
				new PathEL("a"),
				new PathEL("a")));
		checkSCN(HtmlUtils.branchPropertyCount(
				new PathEL("a"),
				Arrays.asList("a"),
				FnUtils.<NodeContext, Void>fix(null),
				FnUtils.<NodeContext, Void>fix(null)));
		checkSCN(HtmlUtils.convertRowAttr("a", new String[]{"a"}));
		checkSCN(HtmlUtils.hiddenAllToChild(new PathEL("a"), Arrays.asList("a")));
		checkSCN(HtmlUtils.insertRowIndex("a"));
		checkSCN(HtmlUtils.makeRadio(new PathEL("a")));
		checkSCN(HtmlUtils.makeSelect(new PathEL("a")));
		checkSCN(HtmlUtils.mergeCell(0));
		checkSCN(HtmlUtils.updateToSelectedValue(new PathEL("a"), new PathEL("a")));
		checkSCN(HtmlUtils.updateValue(new PathEL("a"), new PathEL("a"), false));
		
		// typeconvert
		checkSCN(new Converter(FnUtils.<Object, String>fix(null)));
		checkSCN(new DelegationIfNecessityConverter(FnUtils.<ConvertContext, Void>fix(null)));
		checkSCN(new SettingFnConverter(FnUtils.<ConvertContext, Void>fix(null)));
		checkSCN(new ToArrayConverter(FnUtils.<ConvertContext, Void>fix(null)));
		checkSCN(new ToCollectionDecompositionConverter(FnUtils.<ConvertContext, Void>fix(null)));
		checkSCN(new ToCollectionViewConverter(FnUtils.<ConvertContext, Void>fix(null)));
		checkSCN(new ToMapViewConverter(FnUtils.<ConvertContext, Void>fix(null)));
		checkSCN(new ToTypeConverter(FnUtils.<Class, Class>fix(null)));
		
		
		// el
		checkSC(new ArrayPathEL(new GettingEL[]{new PathEL("a")}, new PathEL("a")));
		checkSCN(new CachePropertyELFactory(ELUtils.PROPERTY_EL_FACTORY));
		checkSCN(new FixEL(new Object()));
		checkSCN(new MapEL("a", FnUtils.<ConvertContext, Void>fix(null)));
		checkSCN(new MapPropertyELFactory(
				FnUtils.<ConvertContext, Void>fix(null),
				ELUtils.PROPERTY_EL_FACTORY));
		checkSC(new PathEL(
				"a",
				ELUtils.PROPERTY_EL_FACTORY,
				true));
		checkSCN(new PropertyEL(
				"a",
				ELUtils.PROPERTY_EL_FACTORY));
		checkSCN(new ReflectionPropertyELFactory(FnUtils.<ConvertContext, Void>fix(null)));
		checkSCN(new MapSimilarPropertyELFactory(
				FnUtils.<ConvertContext, Void>fix(null),
				ELUtils.PROPERTY_EL_FACTORY,
				FnUtils.<String, Iterable<String>>fix(null)));
		checkSCN(new SimilarPropertyELFactory(
				ELUtils.PROPERTY_EL_FACTORY,
				FnUtils.<String, Iterable<String>>fix(null)));
		checkSCN(new ThisEL(FnUtils.<ConvertContext, Void>fix(null), ""));
		checkSCN(new MaybeEL(new FixEL(new Object())));
		checkSCN(new MaybePropertyELFactory(
				true,
				ELUtils.PROPERTY_EL_FACTORY));
		
		// acquirable
		checkSCN(new AcquirableChain<RuntimeException>(new ArrayList<Acquirable<RuntimeException>>()));
		checkSCN(AcquirableUtils.acquire(
				FnUtils.<Integer, Acquirable<RuntimeException>>fix(null),
				FnUtils.fix(null),
				FnUtils.fix(null)
		));
		checkSCN(new DoLock(new ReentrantLock()));
		checkSCN(new DoSemaphore(new Semaphore(1)));
		checkSCN(new DoSemaphoreFactory(1, false));
		checkSCN(new TryLock(new ReentrantLock()));
		checkSCN(new TrySemaphore(new Semaphore(1)));
		checkSCN(new TrySemaphoreFactory(1, false));
		
		// action
		checkSC(new ActionDef(new PathEL("a"), new PathEL("a"), new ArrayList<ForwardDef>()));
		checkSC(new ActionInvoker(FnUtils.<String, ActionDef>fix(null), new ForwardDef[]{}));
		checkSCN(new ActionResult(new ForwardDef("id0"), "a"));
		checkSCN(new ForwardDef("id0"));
		checkSCN(new ForwardDef("id0", new PathEL("a")));
		checkSCN(new ForwardDef("id0", BoolUtils.NOT_THROWABLE));
		
		// adapter
		checkSCN(new ConvertableTypeConverter(FnUtils.<ConvertContext, Void>fix(null)));
		checkGC(new JXE("a"));
		checkGC(new OGE("a"));
		
		// config
		checkSCN(ConfigUtils.setConfig(FnUtils.<ConfigContext, Map<String, Object>>fix(null)));
		checkSCN(ConfigUtils.putResourceBundle(FnUtils.<ConfigContext, ResourceBundle>fix(null)));
		checkSCN(ConfigUtils.resourceBundleFactory("a", new ThreadLocal<Locale>()));
		checkSCN(ConfigUtils.toLinkedHashMap("a", "b", "c", "d"));
		
		// container
		{
			final ContainerContext<Object> o = new ContainerContext<Object>();
			o.setKey(new Object());
			o.setSubContext(new Object());
			o.setFn(FnUtils.<ContainerContext, Object>fix(null));
			checkS(o);
		}
		
		// ee
		{
			// Fnを返す関数がアクセサと誤解されるので個別対応
			final ActionInvoker invoker = new ActionInvoker(FnUtils.<String, ActionDef>fix(null), new ForwardDef[]{});
			final Fn<GettingEL, Fn<? super EEContext, Void, ? extends RuntimeException>, RuntimeException> factory = FnUtils.fix(null);
			final PathEL el0 = new PathEL("a");
			final PathEL el1 = new PathEL("b");
			final ActionBuilder builder = new ActionBuilder(invoker, factory, el0, el1);
			assertEquals(invoker, builder.getActionDefs());
			assertEquals(factory, builder.getAutoUpdaterFactory());
			assertEquals(el0, builder.getForwardComponentELEL());
			assertEquals(el1, builder.getReturnEL());
			builder.setActionDefs(invoker);
			builder.setAutoUpdaterFactory(factory);
			builder.setForwardComponentELEL(el0);
			builder.setReturnEL(el1);
			assertEquals(invoker, builder.getActionDefs());
			assertEquals(factory, builder.getAutoUpdaterFactory());
			assertEquals(el0, builder.getForwardComponentELEL());
			assertEquals(el1, builder.getReturnEL());
		}
		{
			// Fnを返す関数がアクセサと誤解されるので個別対応
			final Fn<ValidatorContext, Boolean, RuntimeException> fn = FnUtils.fix(null);
			final PathEL el = new PathEL("a");
			final ValidatorBuilder<RuntimeException> builder = new ValidatorBuilder<RuntimeException>(fn, el, true);
			assertEquals(fn, builder.getValidatorFn());
			assertEquals(el, builder.getMessagesEL());
			assertTrue(builder.isValueNotFoundIgnoreFlag());
			builder.setValidatorFn(fn);
			builder.setMessagesEL(el);
			builder.setValueNotFoundIgnoreFlag(true);
			assertEquals(fn, builder.getValidatorFn());
			assertEquals(el, builder.getMessagesEL());
			assertTrue(builder.isValueNotFoundIgnoreFlag());
		}
		
		// misc
		checkGC(MiscUtils.loadBalancer(FnUtils.<Object, Fn<Integer, String, RuntimeException>>fix(null), 3));
		checkSCN(MiscUtils.tryLocales(FnUtils.<String, Object>fix(null), new ThreadLocal<Locale>()));
		checkSCN(MiscUtils.lapTime(
				FnUtils.fix(null),
				FnUtils.fix(null)
		));
		checkSCN(MiscUtils.fnRunnable(FnUtils.<Object, Object>fix(null), 1));
		checkSCN(MiscUtils.runnableFn(MiscUtils.fnRunnable(FnUtils.<Integer, String>fix(null), 1)));
		checkSCN(MiscUtils.sleep(3L));
		checkSCN(MiscUtils.switchNearLocale(FnUtils.switching(Utils.map(Locale.ENGLISH, "a"))));
		checkSCN(MiscUtils.threadLocal(new ThreadLocal<String>()));
		checkSCN(MiscUtils.retry(FnUtils.fix(5), 3));
		
		// factory
		checkSCN(FactoryUtils.doEL(new PathEL("a")));
		checkSCN(FactoryUtils.inputStreamReaderFactory(
				FactoryUtils.stringInputStreamFactory("Shift_JIS", "a"),
				"Shift_JIS"
		));
		checkSCN(FactoryUtils.stringInputStreamFactory("Shift_JIS", "a"));
		checkSCN(FactoryUtils.stringReaderFactory("a"));
		checkSCN(FactoryUtils.concurrentCache(
				FnUtils.<Object, ConcurrentMap<String, Object>>fix(null),
				FnUtils.<Object, String>fix(null),
				FnUtils.<Object, Object>fix(null)));
		checkSCN(FactoryUtils.cache(
				FnUtils.<Object, Map<String, Object>>fix(null),
				FnUtils.<Object, String>fix(null),
				FnUtils.<Object, Object>fix(null)));
		checkSCN(FactoryUtils.newInstance(Object.class));
		checkSCN(FactoryUtils.concurrentCache(
				FnUtils.<Object, ConcurrentMap<String, Object>>fix(null),
				FnUtils.<Object, String>fix(null),
				FnUtils.<Object, Object>fix(null),
				new PathEL("a")));
		checkSCN(FactoryUtils.cache(
				FnUtils.<Object, Map<String, Object>>fix(null),
				FnUtils.<Object, String>fix(null),
				FnUtils.<Object, Object>fix(null),
				new PathEL("a")));
		
		// web
		checkSCN(WebUtils.setContainerContext(FnUtils.<ContainerContext<WebContext>, Object>fix(null)));
		
		// idnode
		checkSCN(IdNodeUtils.insertIFrame("frameId", "targetName", FnUtils.<SimpleIdNodeContext, Void>fix(null), FnUtils.<String, String>fix(null)));
		
		// test
	}
	
	public void testUtils() throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		checkSCN(new AppendableWriter(new StringBuilder()));
		{
			// isEmptyがアクセサと誤解されるので個別対応
			final ArrayList<Object> list = new ArrayList<Object>();
			final DelegationCollection<Object> target = new DelegationCollection<Object>(list);
			assertEquals(list, target.getCollection());
			target.setCollection(list);
			assertEquals(list, target.getCollection());
		}
		{
			// isEmptyがアクセサと誤解されるので個別対応
			final HashMap<Object, Object> map = new HashMap<Object, Object>();
			final DelegationMap<Object, Object> target = new DelegationMap<Object, Object>(map);
			assertEquals(map, target.getMap());
			target.setMap(map);
			assertEquals(map, target.getMap());
		}
		{
			// isEmptyがアクセサと誤解されるので個別対応
			final ArrayList<Map<Object, Object>> list = new ArrayList<Map<Object, Object>>();
			final MapIterableMap<Object, Object> target = new MapIterableMap<Object, Object>(list);
			assertEquals(list, target.getIterable());
			target.setIterable(list);
			assertEquals(list, target.getIterable());
		}
	}
	
	public void testVisitor() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		final Visitor<Object, RuntimeException> visitor = new Visitor<Object, RuntimeException>();
		visitor.setSubContext(new Object());
		visitor.setElement(new Object());
		visitor.setMap(new HashMap<Object, Fn<Visitor<Object, RuntimeException>, Void, RuntimeException>>());
		checkS(visitor);
	}
	
	public void testSql() throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		checkSCN(SqlTxUtils.commit(new DataSourceAdapter(null)));
		checkSCN(SqlTxUtils.rollback(new DataSourceAdapter(null)));
		{
			// アクセサと誤解されるので個別対応
			final DataSource dataSource = new DataSourceAdapter(null);
			final TxBuilder builder = new TxBuilder(dataSource);
			assertEquals(dataSource, builder.getDataSource());
			builder.setDataSource(dataSource);
			assertEquals(dataSource, builder.getDataSource());
		}
		checkSCN(new TxFn<Object, Object>(
				new DataSourceAdapter(null),
				FnUtils.<Object, Object>fix(null)));
		
		checkSCN(SqlFnUtils.getList(FnUtils.fix(null), FnUtils.fix(null)));
		checkSCN(SqlFnUtils.inputBean(
				new DataSourceAdapter(null),
				FnUtils.<Object, PreparedStatementInfo>fix(null),
				FnUtils.<Object, Object>fix(null), FnUtils.fix(null)));
		checkSCN(SqlFnUtils.getOne(
				FnUtils.<Object, Object>fix(null),
				FnUtils.<Object, Object>fix(null)));
		checkSCN(new PreparedStatementInfo(
				"",
				Arrays.asList("")));
		checkSCN(SqlFnUtils.inputSingle(
				new DataSourceAdapter(null),
				FnUtils.<Object, String>fix(null),
				FnUtils.<Object, Object>fix(null),
				FnUtils.fix(null)));
		checkSCN(SqlFnUtils.inputStatement(
				new DataSourceAdapter(null),
				FnUtils.<Object, String>fix(null),
				FnUtils.<Object, Object>fix(null),
				FnUtils.fix(null)));
		checkSCN(SqlFnUtils.getBeanResult(FactoryUtils.newInstance(Object.class)));
		
		checkSCN(new ColumnInfo(0, "a", 1, 2, false));
		// TODO djUnitで固まる
//		checkSCN(new ReferenceInfo(
//				"a", "b", "c", "d", Arrays.asList("e"),
//				"f", "g", "h", "i", Arrays.asList("j")));
		checkSCN(new TableInfo(
				"a", "b", "c",
				Arrays.asList("d"),
				Arrays.asList("e"),
				new HashMap<String, ColumnInfo>(),
				Arrays.asList(new ReferenceInfo(
						"a", "b", "c", "d", Arrays.asList("e"),
						"f", "g", "h", "i", Arrays.asList("j"))),
				Arrays.asList(new ReferenceInfo(
						"a1", "b", "c", "d", Arrays.asList("e"),
						"f", "g", "h", "i", Arrays.asList("j")))));

		checkSCN(new ParamBindInfo("name", 2, 3, "bind", SqlOperator.EQ, false));
	}
}
