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 }