/** * Test Harness cs200 l7 * * @author Pete Nordquist * @version Nov. 12, 2006 Sample AutoGrader test harness - Copyright (C) 2006 Pete Nordquist (nordquip at sou.edu) 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. */ import java.io.*; import java.net.*; public class PUT { // Lab specific global variables public static Student stu; // 100 tests max private static final int MAXTESTS = 100; // timeout -- in milliseconds private static final long TIMEOUT = 40; // globals needed by PUT private static final String DELIM = ((char) 0) + ", "; private static ByteArrayInputStream bais; public static ByteArrayOutputStream baos; private static DataOutputStream dos; private static String LS = System.getProperty("line.separator"); public static String[] sparams = new String[MAXTESTS]; public static String[] sin = new String[MAXTESTS]; private static String[] sexp = new String[MAXTESTS]; public static int testIndex = 0; public static void resetStdIO() { baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); // When using IO.java -- static initialization of the instream reader // must gather all inputs into a single stream before the whole program // When Lab code uses a single scanner object to read inputs, can // reset stdin for every test // collect all inputs into a single string String inputs = sin[testIndex]; bais = new ByteArrayInputStream(inputs.getBytes()); System.setIn(bais); //IO.resetStdIn(); // load in the IO class, so we reset stdin -- nope, once loaded, doesn't look // like it will reload // clazz = cl.loadClass(PUTCLASSNAME); } /** * Runs a test and reports results */ private static void test(String threadClassName, String methName, String params, String inputs, String expOuts, String points) throws Exception { // set inputs and expected outputs sparams[testIndex] = params; // replace all '|'s with line separators // must escape the | in the RE passed to replaceAll() sin[testIndex] = inputs.replaceAll("\\|",LS); sexp[testIndex] = expOuts; resetStdIO(); // Print results header String descr = methName + "(" + params + ")"; System.err.println(descr + ":\n" + "inputs : " + inputs); // create a thread Thread t = (Thread) Class.forName(threadClassName).newInstance(); t.start(); try { Thread.sleep(TIMEOUT); } catch (Exception sleepe) {} if (t.isAlive()) { t.stop(); System.err.println("\n?Method ran longer than " + TIMEOUT + "ms -- killed."); } check(points, descr); testIndex++; } /** * Checks the results of a test */ private static void check(String points, String descr) throws Exception { // replace all line separators with '|', // elimate white space and convert all to lower case String fixedActual = baos.toString().replaceAll(LS,"|").replaceAll("[ \t]","").toLowerCase(); String fixedInputs = sin[testIndex].replaceAll(LS,"|"); String fixedExpected = sexp[testIndex].replaceAll(LS,"|").replaceAll("[ \t]","").toLowerCase(); if (fixedExpected.equals(fixedActual)) { // passed dos.writeBytes("-0" + DELIM + descr + ": inputs: " + fixedInputs + " outputs: " + sexp[testIndex] + " PASSED\n"); System.err.println( "ouputs : " + fixedActual + "\n" + "expected: " + fixedExpected + "\n" + "PASSED\n"); } else { dos.writeBytes("-" + points + DELIM + descr + ": inputs: " + fixedInputs + " outputs: " + sexp[testIndex] + " FAILED\n"); System.err.println( "ouputs : " + fixedActual + "\n" + "expected: " + fixedExpected + "\n" + "FAILED\n"); } } /** * main method for the test harness * @param args[0] the grade file name */ public static void main(String args[]) { System.err.println("\nPUT starting ...\n"); // instructions System.err.println("Read the '|' characters in messages below and in the grading " + "window as " + "end-of-line characters:\n" + " For inputs, the same as if you had typed 'Enter' on the keyboard.\n" + " For outputs, the same as the end of the line printed by println().\n"); System.err.println( "Before checking, all outputs are converted to lowercase " + "and have spaces and tabs removed."); System.err.println("Inputs, actual outputs, and expected outputs shown in " + "failure messages below have been modified as described here.\n"); try { // init data grade file dos = new DataOutputStream(new BufferedOutputStream( new FileOutputStream(args[0]),128)); /* start tests*/ System.err.println("\nStart tests of Student.isLegalName():\n"); // Thread class, method name, params, inputs, expectedOutputs, points test("T0","stu = new Student", "\"McGee, Jimbob\", \"123\"", "", "McGee, Jimbob", "2.0"); test("T1","stu.isLegalName", "", "", "true", "2.0"); test("T2","stu.changeName", "Jane Doe", "", "Jane Doe", "2.0"); test("T1","stu.isLegalName", "", "", "false", "2.0"); test("T2","stu.changeName", ",Bob", "", ",Bob", "2.0"); test("T1","stu.isLegalName", "", "", "true", "2.0"); test("T2","stu.changeName", "Bob,", "", "Bob,", "2.0"); test("T1","stu.isLegalName", "", "", "true", "2.0"); System.err.println("\nStart tests of Student.hasLegalCredits():\n"); test("T3","stu.hasLegalCredits", "", "", "true", "2.0"); test("T4","stu.addCredits", "-1", "", "-1", "2.0"); test("T3","stu.hasLegalCredits", "", "", "false", "2.0"); test("T4","stu.addCredits", "1", "", "0", "2.0"); test("T3","stu.hasLegalCredits", "", "", "true", "2.0"); System.err.println("\nStart tests of Student.getAndClearCredits():\n"); test("T6","stu.getCredits","","","0","2.0"); test("T5","stu.getAndClearCredits", "", "", "0", "2.0"); test("T6","stu.getCredits","","","0","2.0"); test("T4","stu.addCredits", "1", "", "1", "2.0"); test("T5","stu.getAndClearCredits", "", "", "1", "2.0"); test("T6","stu.getCredits","","","0","2.0"); test("T4","stu.addCredits", "-1", "", "-1", "2.0"); test("T5","stu.getAndClearCredits", "", "", "-1", "2.0"); test("T6","stu.getCredits","","","0","2.0"); System.err.println("\nStart tests of Student.print():\n"); test("T0","stu = new Student", "\"McGee, Jimbob\", \"123\"", "", "McGee, Jimbob", "2.0"); test("T7","stu.print","","","contain \"lower class\"","2.0"); test("T4","stu.addCredits", "-90", "", "-90", "2.0"); test("T7","stu.print","","","contain \"lower class\"","2.0"); test("T0","stu = new Student", "\"McGee, Jimbob\", \"123\"", "", "McGee, Jimbob", "2.0"); test("T4","stu.addCredits", "89", "", "89", "2.0"); test("T7","stu.print","","","contain \"lower class\"","2.0"); test("T0","stu = new Student", "\"McGee, Jimbob\", \"123\"", "", "McGee, Jimbob", "2.0"); test("T4","stu.addCredits", "90", "", "90", "2.0"); test("T7","stu.print","","","contain \"upper class\"","2.0"); test("T0","stu = new Student", "\"McGee, Jimbob\", \"123\"", "", "McGee, Jimbob", "2.0"); test("T4","stu.addCredits", "190", "", "190", "2.0"); test("T7","stu.print","","","contain \"upper class\"","2.0"); System.err.println("\nStart tests of Extra Credit:\n"); test("T8","stu.print","","JM","contain \"JM\"","1.0"); test("T2","stu.changeName", "D, J", "", "D, J", "0"); test("T8","stu.print","","JD","contain \"JD\"","1.0"); /* end tests */ dos.flush(); System.err.println("\nPUT finished successfully ...\n"); } catch (Exception e) { e.printStackTrace(); } } } class T0 extends Thread { public void run() { PUT.stu = new Student("McGee, Jimbob", "123"); System.out.print(PUT.stu.getName()); } } class T1 extends Thread { public void run() { System.out.print(PUT.stu.isLegalName()); } } class T2 extends Thread { public void run() { PUT.stu.changeName(PUT.sparams[PUT.testIndex]); System.out.print(PUT.stu.getName()); } } class T3 extends Thread { public void run() { System.out.print(PUT.stu.hasLegalCredits()); } } class T4 extends Thread { public void run() { PUT.stu.addCredits(Integer.parseInt(PUT.sparams[PUT.testIndex])); System.out.print(PUT.stu.getCredits()); } } class T5 extends Thread { public void run() { System.out.print(PUT.stu.getAndClearCredits()); } } class T6 extends Thread { public void run() { System.out.print(PUT.stu.getCredits()); } } class T7 extends Thread { public void run() { PUT.stu.print(); String out = PUT.baos.toString(); System.err.println(out); PUT.resetStdIO(); out = out.replaceAll("[ \t]","").toLowerCase(); try { if (out.contains("lowerclass")) PUT.baos.write("contain \"lower class\"".getBytes()); else if (out.contains("upperclass")) PUT.baos.write("contain \"upper class\"".getBytes()); } catch (java.io.IOException e) { System.err.println("?Caught IOException when trying to write"); } } } class T8 extends Thread { public void run() { PUT.stu.print(); String out = PUT.baos.toString(); System.err.println(out); PUT.resetStdIO(); out = out.replaceAll("[ \t]","").toLowerCase(); try { if (out.contains(PUT.sin[PUT.testIndex].toLowerCase())) PUT.baos.write(("contain \"" + PUT.sin[PUT.testIndex] + "\"").getBytes()); } catch (java.io.IOException e) { System.err.println("?Caught IOException when trying to write"); } } }