/*
 * WrapperUtilsTest.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-01-10): initial version
 * v0.2 (2007-01-10):
 * - testExec and testExecWithInput2 added
 * - testGetCommandName and testGetShortCommandName added
 * - testTransfer1 and testTransfer2 added
 * - documentation added
 * v0.2.1 (2007-01-12):
 * - refactorization of WrapperUtils took place - became a Singleton, the tests
 *   modified to reflect this change
 * - the rest documentation and assertion messages added
 * v0.2.2 (2007-01-14):
 * - testExec and testExecWithInput2 moved to AbstractWrapperTest
 * v0.2.3 (2007-01-20):
 * - testDumpToString added
 * v0.2.4 (2007-02-14):
 * - tests from AbstractWrapperTest moved here
 * v1.0.0 (2007-05-05):
 * - tests adapted to suit the new version of WrapperUtils
 */

package lp.wrap;

import junit.framework.*;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Contains tests of the {@link WrapperUtils} class.
 *
 * @author Martin Slota
 * @version 1.0.0
 * @see WrapperUtils
 */
public class WrapperUtilsTest extends TestCase {
	/**
	 * A shortcut name for {@link File#separatorChar}.
	 */
	private static final char SEP = File.separatorChar;
	
	/**
	 * The singleton instance of {@link WrapperUtils}
	 */
	private static final WrapperUtils WU = WrapperUtils.getInstance();
	
	/**
	 * A default test case constructor.
	 *
	 * @param testName the name of the test case
	 */
	public WrapperUtilsTest(String testName) {
		super(testName);
	}
	
	/**
	 * Tests of the {@link WrapperUtils#getCommandName(String)} method.
	 */
	public void testGetCommandName() {
		// null input test
		assertNull("Null result on null input expected!",
				WU.getCommandName(null));
		
		// some normal inputs
		assertEquals("Command name not as expected!",
				"mkdir", WU.getCommandName("mkdir tmp"));
		assertEquals("Command name not as expected!",
				SEP + "bin" + SEP + "mkdir", WU.getCommandName(
				SEP + "bin" + SEP + "mkdir tmp"));
	}
	
	/**
	 * Tests of the {@link WrapperUtils#getShortCommandName(String)} method.
	 */
	public void testGetShortCommandName() {
		// null input test
		assertNull("Null result on null input expected!",
				WU.getShortCommandName(null));
		
		// some normal inputs
		assertEquals("Command name not as expected!",
				"mkdir", WU.getShortCommandName("mkdir tmp"));
		assertEquals("Command name not as expected!",
				"mkdir", WU.getShortCommandName(
				SEP + "bin" + SEP + "mkdir tmp"));
	}
	
	/**
	 * Tests of the {@link WrapperUtils#transfer(InputStream, OutputStream)}
	 * method.
	 *
	 * @throws IOException if an I/O error occurs while running the tests
	 * (should never happen)
	 */
	public void testTransfer1() throws IOException {
		InputStream from;
		OutputStream to;
		
		// first test of null input -- both arguments are null
		try {
			from = null;
			to = null;
			WU.transfer(from, to);
		} catch (Exception e) {
			fail("No exception expected!");
		}
		
		// second test of null input -- only the first argument is null
		try {
			from = null;
			to = new ByteArrayOutputStream();
			WU.transfer(from, to);
			assertEquals(
					"Nothing should have beem added to target OutputStream!",
					"", to.toString());
		} catch (Exception e) {
			fail("No exception expected!");
		}
		
		// third test of null input -- only the second argument is null but the
		// first contains no bytes
		try {
			from = new ByteArrayInputStream(new byte[0]);
			to = null;
			WU.transfer(from, to);
			assertEquals("The input stream wasn't fully read!",
					-1, from.read());
		} catch (Exception e) {
			fail("No exception expected!");
		}
		
		// fourth test of null input -- only the second argument is null and the
		// first contains something
		try {
			from = new ByteArrayInputStream("some input".getBytes());
			to = null;
			WU.transfer(from, to);
			fail("NullPointerException expected!");
		} catch (NullPointerException e) {
			// behaves as expected
		}
		
		// now a test of normal behaviour
		from = new ByteArrayInputStream("some input".getBytes());
		to = new ByteArrayOutputStream();
		to.write("blablabla".getBytes());
		WU.transfer(from, to);
		// input stream must be all read
		assertEquals("The input stream wasn't fully read!",
				-1, from.read());
		// and it's contents must be appended to the output stream
		assertEquals("The bytes weren't transferred correctly!",
				"blablablasome input", to.toString());
	}
	
	/**
	 * Tests of the {@link WrapperUtils#transfer(String, OutputStream)}
	 * method.
	 *
	 * @throws IOException if an I/O error occurs while running the tests
	 * (should never happen)
	 */
	public void testTransfer2() throws IOException {
		String from;
		OutputStream to;
		
		// first test of null input -- both arguments are null
		try {
			from = null;
			to = null;
			WU.transfer(from, to);
		} catch (Exception e) {
			fail("No exception expected!");
		}
		
		// second test of null input -- only the first argument is null
		try {
			from = null;
			to = new ByteArrayOutputStream();
			WU.transfer(from, to);
			assertEquals(
					"Nothing should have beem added to target OutputStream!",
					"", to.toString());
		} catch (Exception e) {
			fail("No exception expected!");
		}
		
		// third test of null input -- only the second argument is null but the
		// first contains no bytes
		try {
			from = "";
			to = null;
			WU.transfer(from, to);
		} catch (Exception e) {
			fail("No exception expected!");
		}
		
		// fourth test of null input -- only the second argument is null and the
		// first contains something
		try {
			from = "some input";
			to = null;
			WU.transfer(from, to);
			fail("NullPointerException expected!");
		} catch (NullPointerException e) {
			// behaves as expected
		}
		
		// now a test of normal behaviour
		from = "some input";
		to = new ByteArrayOutputStream();
		to.write("blablabla".getBytes());
		WU.transfer(from, to);
		// and it's contents must be appended to the output stream
		assertEquals("The bytes weren't transferred correctly!",
				"blablablasome input", to.toString());
	}
	
	/**
	 * Tests of the {@link WrapperUtils#transfer(InputStream, StringBuilder)}
	 * method.
	 *
	 * @throws IOException if an I/O error occurs while running the tests
	 * (should never happen)
	 */
	public void testTransfer3() throws IOException {
		InputStream from;
		StringBuilder to;
		
		// first test of null input -- both arguments are null
		try {
			from = null;
			to = null;
			WU.transfer(from, to);
		} catch (Exception e) {
			fail("No exception expected!");
		}
		
		// second test of null input -- only the first argument is null
		try {
			from = null;
			to = new StringBuilder();
			WU.transfer(from, to);
			assertEquals(
					"Nothing should have beem added to target StringBuilder!",
					"", to.toString());
		} catch (Exception e) {
			fail("No exception expected!");
		}
		
		// third test of null input -- only the second argument is null but the
		// first contains no bytes
		try {
			from = new ByteArrayInputStream(new byte[0]);
			to = null;
			WU.transfer(from, to);
			assertEquals("The input stream wasn't fully read!",
					-1, from.read());
		} catch (Exception e) {
			fail("No exception expected!");
		}
		
		// fourth test of null input -- only the second argument is null and the
		// first contains something
		try {
			from = new ByteArrayInputStream("some input".getBytes());
			to = null;
			WU.transfer(from, to);
			fail("NullPointerException expected!");
		} catch (NullPointerException e) {
			// behaves as expected
		}
		
		// now a test of normal behaviour
		from = new ByteArrayInputStream("some input".getBytes());
		to = new StringBuilder();
		to.append("blablabla");
		WU.transfer(from, to);
		// input stream must be all read (and closed but that doesn't have
		// any effect here)
		assertEquals("The input stream wasn't fully read!",
				-1, from.read());
		// it's contents must be appended to the StringBuilder
		assertEquals("The bytes weren't transferred correctly!",
				"blablablasome input", to.toString());
	}
	
	/**
	 * Tests of the {@link WrapperUtils#dumpToString(InputStream)} method.
	 *
	 * @throws IOException if an I/O error occurs while running the tests
	 * (should never happen)
	 */
	public void testDumpToString() throws IOException {
		InputStream from;
		// test of null input
		try {
			from = null;
			assertEquals("", "", WU.dumpToString(from));
		} catch (Exception e) {
			fail("No exception expected!");
		}
		
		// now a test of normal behaviour
		from = new ByteArrayInputStream("some other input".getBytes());
		// test the conversion
		assertEquals("The bytes weren't transferred correctly!",
				"some other input", WU.dumpToString(from));
		// input stream must be all read (and closed but that doesn't have
		// any effect here)
		assertEquals("The input stream wasn't fully read!",
				-1, from.read());
	}
	
	/**
	 * Tests of the {@link WrapperUtils#exec(String)} method.
	 *
	 * @throws WrapperException if an {@link java.io.IOException} occurs while
	 * running the tests (should never happen)
	 *
	 * @throws InterruptedException if an error occurs while waiting for the
	 * {@link Process} with the "cat" command to finish execution
	 *
	 * @throws IOException if an I/O error occurs while closing the standard
	 * input of the process
	 */
	public void testExec() throws WrapperException, InterruptedException,
			IOException {
		String command;
		
		// null command test
		try {
			command = null;
			WU.exec(command);
			fail("NullPointerException expected (null command test)!");
		} catch (NullPointerException e) {
			// behaves as expected
		}
		
		// empty command test
		try {
			command = "";
			WU.exec(command);
			fail("IllegalArgumentException expected (empty command test)!");
		} catch (IllegalArgumentException e) {
			// behaves as expected
		}
		
		// invalid command test
		try {
			command = SEP + "biin" + SEP + "blablabla123 bla blabla";
			WU.exec(command);
			fail("IOException expected (invalid command test)!");
		} catch (WrapperException e) {
			assertEquals("Exception message malformed!",
					"blablabla123 could not be executed (path `" +
					SEP + "biin" + SEP + "blablabla123' is probably invalid)",
					e.getMessage());
			// behaves as expected
		}
		
		// if we're on Linux, we'll also test it with the cat command
		if (System.getProperty("os.name").equals("Linux")) {
			command = "cat";
			Process p = WU.exec(command);
			WU.transfer("Hello world!", p.getOutputStream());
			p.getOutputStream().close();
			
			assertEquals("cat finished with an error!",
					0, p.waitFor());
			assertEquals("Malformed output from cat!",
					"Hello world!", WU.dumpToString(p.getInputStream()));
			assertEquals("Unexpected error from cat!",
					"", WU.dumpToString(p.getErrorStream()));
		}
	}
}