001 package ps6.test;
002
003 import java.io.ByteArrayOutputStream;
004 import java.io.InputStream;
005 import java.io.PrintStream;
006 import java.lang.reflect.InvocationTargetException;
007 import java.lang.reflect.Method;
008 import java.lang.reflect.Modifier;
009
010 import junit.framework.TestCase;
011
012 /**
013 * An immutable TextUI test case for PS6. Runs the TextUI main method
014 * on a given input and compared the actual output to the expected
015 * output
016 *
017 * @author tws
018 */
019 public class PS6TextUiTestCase extends TestCase {
020 private static final int INITIAL_BUFFER_SIZE = 10240; // 10 kilobytes
021
022 private final InputStream testInput;
023 private final String expected;
024 private final Method mainMethod;
025 private final String[] mainParams;
026
027 private static Class<?> convertToNewLoader(Class<?> mainClass) {
028 try {
029 junit.runner.TestCaseClassLoader loader = new junit.runner.TestCaseClassLoader();
030 return loader.loadClass(mainClass.getName());
031 } catch (Exception mue) {
032 throw new RuntimeException("Can't load class", mue);
033 }
034
035 }
036
037 /**
038 * @param mainClass
039 * class that defines a main() that reads from System.in and
040 * writes to System.out
041 * @param testInput
042 * test input for the filter
043 * @param expected
044 * expected test output
045 */
046 public PS6TextUiTestCase(String description, String mainParams[], Class<?> iMainClass,
047 InputStream testInput, String expected) {
048 super(description);
049 Class<?> mainClass = convertToNewLoader(iMainClass);
050 assertNotNull(mainClass);
051 assertNotNull(testInput);
052 assertNotNull(expected);
053 assertNotNull(mainParams);
054
055 this.mainParams = mainParams;
056 this.testInput = testInput;
057 this.expected = expected;
058
059 // grab the "main" method from mainClass
060 try {
061 this.mainMethod = mainClass.getMethod("main",
062 new Class[] { String[].class });
063 } catch (NoSuchMethodException e) {
064 throw new IllegalArgumentException(mainClass.getName()
065 + " does not define main()");
066 }
067 if (!Modifier.isPublic(mainMethod.getModifiers())
068 || !Modifier.isStatic(mainMethod.getModifiers()))
069 throw new IllegalArgumentException(mainClass.getName()
070 + " main() is not public and static");
071
072 }
073
074 /**
075 * Runs the this.mainMethod, piping this.testInput into its
076 * standard input. Standard output is captured and compared to this.expected
077 *
078 */
079 @Override
080 protected void runTest() {
081 // save the old streams
082 PrintStream savedSystemOut = System.out;
083 InputStream savedSystemIn = System.in;
084
085 // read input from testInput and capture output in buffers
086 ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(
087 INITIAL_BUFFER_SIZE);
088
089 PrintStream testOutput = new PrintStream(outBuffer, true); // autoflush
090
091 System.setIn(testInput);
092 System.setOut(testOutput);
093
094 try {
095 mainMethod.invoke(null, new Object[]{mainParams});
096 } catch (IllegalArgumentException e) {
097 fail("Internal Invocation Error:" + e.getMessage());
098 } catch (IllegalAccessException e) {
099 fail("Internal Invocation Error:" + e.getMessage());
100 } catch (InvocationTargetException e) {
101 fail("Internal Invocation Error:" + e.getMessage());
102 }
103
104 // flush streams
105 System.out.flush();
106 System.err.flush();
107
108 // compare actual output to expected
109 assertEquals(expected,outBuffer.toString());
110
111 // restore the old streams
112 System.setIn(savedSystemIn);
113 System.setOut(savedSystemOut);
114 }
115 }