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

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;

import junit.framework.TestCase;

import woolpack.LoadAllTests;
import woolpack.test.DomExpressionRunnable;
import woolpack.test.RunnableDomExpression;
import woolpack.test.RunnableGate;
import woolpack.test.RunnableGate.Context;
import woolpack.test.TestUtils;
import woolpack.utils.UtilsConstants;

public class JoinProcessTest extends TestCase {

	public void testConstructor() {
		try {
			new JoinProcess(null, DomConstants.NULL);
			fail();
		} catch (final NullPointerException expected) {
		}
		try {
			new JoinProcess("", DomConstants.NULL);
			fail();
		} catch (final StringIndexOutOfBoundsException expected) {
		}
		try {
			new JoinProcess("key0", null);
			fail();
		} catch (final NullPointerException expected) {
		}
	}

	public void testNormal() throws InterruptedException {
		final RunnableGate gate = new RunnableGate(LoadAllTests.THREAD_POOL);
		final DomExpression expression = new JoinProcess(
				new Serial(
						TestUtils
								.getToNodeForm("<INPUT type=\"text\" name=\"name0\" value=\"value0\" />"),
						new RunnableDomExpression(gate.getPause("true_start",
								"true_end"))));

		// 処理が委譲される。
		final DomContext c0 = new DomContext();
		c0.setId("id0");
		c0.setSession(UtilsConstants.concurrentMap(
				new HashMap<String, Object>(), new Object()));
		final Context t0 = gate.execute(new DomExpressionRunnable(expression,
				c0));
		assertTrue(t0.waitFor("true_start"));
		assertFalse(t0.waitFor("true_end"));

		// Dom ノードを取得する処理でブロックする。
		final DomContext c1 = new DomContext();
		c1.setId("id0");
		c1.setSession(c0.getSession());
		final Context t1 = gate.execute(new DomExpressionRunnable(expression,
				c1));
		assertTrue(t1.waitForStart());
		assertFalse(t1.waitFor("true_start"));

		{
			// 関係ないidのリクエストとは干渉しない。
			final Context t;
			{
				final DomContext c = new DomContext();
				c.setId("id1");
				c.setSession(UtilsConstants.concurrentMap(
						new HashMap<String, Object>(), new Object()));
				t = gate.execute(new DomExpressionRunnable(expression, c));
			}
			assertTrue(t.waitFor("true_start"));
			assertFalse(t.waitFor("true_end"));
			t.resume();
			assertTrue(TestUtils.equals(
					Arrays.asList("true_start", "true_end"), t.getEndList()));
		}

		// 取得したセマフォを開放する。
		t0.resume();
		assertTrue(TestUtils.equals(Arrays.asList("true_start", "true_end"), t0
				.getEndList()));

		// ブロックされていたスレッドはDom ノードを再利用する。
		assertTrue(TestUtils.equals(Collections.emptyList(), t1.getEndList()));
		assertSame(c0.getNode(), c1.getNode());
	}
}
