/*
 * SmodelsWrapperTest.java
 * JUnit based test
 *
 * Copyright (C) 2006 - 2007 Martin Slota
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/*
 * History:
 * v0.1 (2007-03-06): initial version
 * v0.2 (2007-03-06):
 * - testSetSmodelsPath, testSimpleInput, testSetModelLimit added
 * v1.0.0 (2007-05-05):
 * - tests adapted to suit the new version of SmodelsWrapper
 */

package lp.wrap;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Pattern;
import junit.framework.*;

/**
 * Contains tests of the {@link SmodelsWrapper} class.
 *
 * @author Martin Slota
 * @version 1.0.0
 * @see SmodelsWrapper
 */
public class SmodelsWrapperTest extends TestCase {
	/**
	 * The {@link SmodelsWrapper} instance used in the tests.
	 */
	private final SmodelsWrapper sw = new SmodelsWrapper();
	
	/**
	 * A default test case constructor.
	 *
	 * @param testName the name of the test case
	 */
	public SmodelsWrapperTest(String testName) {
		super(testName);
	}
	
	/**
	 * Tests the {@link SmodelsWrapper#setSmodelsPath(String)} method.
	 */
	public void testSetSmodelsPath() throws IOException {
		try {
			sw.setSmodelsPath(null);
			fail("An IllegalArgumentException expected!");
		} catch (IllegalArgumentException e) {
			// as expected
		}
		
		try {
			sw.setSmodelsPath("");
			fail("An IllegalArgumentException expected!");
		} catch (IllegalArgumentException e) {
			// as expected
		}
		
		sw.setSmodelsPath("some_nonsense");
		try {
			sw.exec();
			fail("A WrapperException expected!");
		} catch (WrapperException e) {
			assertEquals("The error message not as expected!",
					"some_nonsense could not be executed (path " +
					"`some_nonsense' is probably invalid)", e.getMessage());
		}
	}
	
	/**
	 * Tests the {@link SmodelsWrapper#exec()} method&#8212;sets a simple input
	 * string and tests if the correct output is produced by smodels.
	 *
	 * This test can only pass if the smodels binary can be executed by issuing
	 * a simple {@code "smodels"} command.
	 *
	 * @throws WrapperException if an {@link IOException} occurs while creating
	 * the process or if an {@link InterruptedException} occurs while waiting
	 * for the process instance to finish execution.
	 * @throws IOException if an I/O error occurs while setting its standard
	 * input or while reading the output of the process (should never happen)
	 */
	public void testSimpleInput() throws IOException {
		String input = "1 2 0 0\n" +
				"1 3 0 0\n" +
				"1 4 0 0\n" +
				"0\n" +
				"2 c\n" +
				"3 b\n" +
				"4 a\n" +
				"0\n" +
				"B+\n" +
				"0\n" +
				"B-\n" +
				"1\n" +
				"0\n" +
				"1";
		sw.setModelLimit(0);
		sw.exec();
		
		WrapperUtils.getInstance().transfer(input, sw.getStdin());
		sw.closeStdin();
		
		sw.waitFor();
		String expected = "smodels version 2.32. Reading...done\n" +
				"Answer: 1\n" +
				"Stable Model: c b a \n" +
				"False\n" +
				"Duration: [0-9].[0-9]{3}\n" +
				"Number of choice points: 0\n" +
				"Number of wrong choices: 0\n" +
				"Number of atoms: 4\n" +
				"Number of rules: 3\n" +
				"Number of picked atoms: 0\n" +
				"Number of forced atoms: 0\n" +
				"Number of truth assignments: 3\n" +
				"Size of searchspace \\(removed\\): 0 \\(0\\)";
		
		BufferedReader outputReader = new BufferedReader(
				new InputStreamReader(sw.getStdout()));
		StringBuilder outputBuilder = new StringBuilder();
		String line = outputReader.readLine();
		while (line != null) {
			outputBuilder.append(line + "\n");
			line = outputReader.readLine();
		}
		assertTrue("Smodels output not as expected!",
				Pattern.matches(expected, outputBuilder.toString().trim()));
	}
	
	/**
	 * Tests the {@link SmodelsWrapper#setModelLimit(int)} and
	 * {@link SmodelsWrapper#exec()} methods&#8212;sets a maximum model count
	 * limit and a simple input string and tests if the correct output is
	 * produced by smodels.
	 *
	 * This test can only pass if the smodels binary can be executed by issuing
	 * a simple {@code "smodels"} command.
	 *
	 * @throws WrapperException if an {@link IOException} occurs while creating
	 * the process or if an {@link InterruptedException} occurs while waiting
	 * for the process instance to finish execution.
	 * @throws IOException if an I/O error occurs while setting its standard
	 * input or while reading the output of the process (should never happen)
	 */
	public void testSetModelLimit() throws IOException {
		String input = "1 2 1 1 3\n" +
				"1 3 1 1 2\n" +
				"0\n" +
				"2 b\n" +
				"3 a\n" +
				"0\n" +
				"B+\n" +
				"0\n" +
				"B-\n" +
				"1\n" +
				"0\n" +
				"1";
		sw.setModelLimit(1);
		sw.exec();
		
		WrapperUtils.getInstance().transfer(input, sw.getStdin());
		sw.closeStdin();
		
		sw.waitFor();
		String expected = "smodels version 2.32. Reading...done\n" +
				"Answer: 1\n" +
				"Stable Model: a \n" +
				"True\n" +
				"Duration: [0-9].[0-9]{3}\n" +
				"Number of choice points: 1\n" +
				"Number of wrong choices: 0\n" +
				"Number of atoms: 3\n" +
				"Number of rules: 2\n" +
				"Number of picked atoms: 3\n" +
				"Number of forced atoms: 0\n" +
				"Number of truth assignments: 5\n" +
				"Size of searchspace \\(removed\\): 2 \\(0\\)";
		
		BufferedReader outputReader = new BufferedReader(
				new InputStreamReader(sw.getStdout()));
		StringBuilder outputBuilder = new StringBuilder();
		String line = outputReader.readLine();
		while (line != null) {
			outputBuilder.append(line + "\n");
			line = outputReader.readLine();
		}
		assertTrue("Smodels output not as expected!",
				Pattern.matches(expected, outputBuilder.toString().trim()));
	}
}