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    }