Development Class Java

// : com:bruceeckel:simpletest:Test.java
//Simple utility for testing program output. Intercepts
//System.out to print both to the console and a buffer.
//From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002
//www.BruceEckel.com. See copyright notice in CopyRight.txt.
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.regex.Pattern;
public class Alias2 {
  private static Test monitor = new Test();
  private int i;
  public Alias2(int ii) { i = ii; }
  public static void f(Alias2 reference) { reference.i++; }
  public static void main(String[] args) {
    Alias2 x = new Alias2(7);
    System.out.println("x: " + x.i);
    System.out.println("Calling f(x)");
    f(x);
    System.out.println("x: " + x.i);
    monitor.expect(new String[] {
      "x: 7",
      "Calling f(x)",
      "x: 8"
    });
  }
} ///:~
class Test {
  // Bit-shifted so they can be added together:
  public static final int EXACT = 1 << 0, // Lines must match exactly
      AT_LEAST = 1 << 1, // Must be at least these lines
      IGNORE_ORDER = 1 << 2, // Ignore line order
      WAIT = 1 << 3; // Delay until all lines are output
  private String className;
  private TestStream testStream;
  public Test() {
    // Discover the name of the class this
    // object was created within:
    className = new Throwable().getStackTrace()[1].getClassName();
    testStream = new TestStream(className);
  }
  public static List fileToList(String fname) {
    ArrayList list = new ArrayList();
    try {
      BufferedReader in = new BufferedReader(new FileReader(fname));
      try {
        String line;
        while ((line = in.readLine()) != null) {
          if (fname.endsWith(".txt"))
            list.add(line);
          else
            list.add(new TestExpression(line));
        }
      } finally {
        in.close();
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    return list;
  }
  public static List arrayToList(Object[] array) {
    List l = new ArrayList();
    for (int i = 0; i < array.length; i++) {
      if (array[i] instanceof TestExpression) {
        TestExpression re = (TestExpression) array[i];
        for (int j = 0; j < re.getNumber(); j++)
          l.add(re);
      } else {
        l.add(new TestExpression(array[i].toString()));
      }
    }
    return l;
  }
  public void expect(Object[] exp, int flags) {
    if ((flags & WAIT) != 0)
      while (testStream.numOfLines < exp.length) {
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          throw new RuntimeException(e);
        }
      }
    List output = fileToList(className + "Output.txt");
    if ((flags & IGNORE_ORDER) == IGNORE_ORDER)
      OutputVerifier.verifyIgnoreOrder(output, exp);
    else if ((flags & AT_LEAST) == AT_LEAST)
      OutputVerifier.verifyAtLeast(output, arrayToList(exp));
    else
      OutputVerifier.verify(output, arrayToList(exp));
    // Clean up the output file - see c06:Detergent.java
    testStream.openOutputFile();
  }
  public void expect(Object[] expected) {
    expect(expected, EXACT);
  }
  public void expect(Object[] expectFirst, String fname, int flags) {
    List expected = fileToList(fname);
    for (int i = 0; i < expectFirst.length; i++)
      expected.add(i, expectFirst[i]);
    expect(expected.toArray(), flags);
  }
  public void expect(Object[] expectFirst, String fname) {
    expect(expectFirst, fname, EXACT);
  }
  public void expect(String fname) {
    expect(new Object[] {}, fname, EXACT);
  }
} ///:~
class TestExpression implements Comparable {
  private Pattern p;
  private String expression;
  private boolean isRegEx;
  // Default to only one instance of this expression:
  private int duplicates = 1;
  public TestExpression(String s) {
    this.expression = s;
    if (expression.startsWith("%% ")) {
      this.isRegEx = true;
      expression = expression.substring(3);
      this.p = Pattern.compile(expression);
    }
  }
  // For duplicate instances:
  public TestExpression(String s, int duplicates) {
    this(s);
    this.duplicates = duplicates;
  }
  public String toString() {
    if (isRegEx)
      return p.pattern();
    return expression;
  }
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (isRegEx)
      return (compareTo(obj) == 0);
    return expression.equals(obj.toString());
  }
  public int compareTo(Object obj) {
    if ((isRegEx) && (p.matcher(obj.toString()).matches()))
      return 0;
    return expression.compareTo(obj.toString());
  }
  public int getNumber() {
    return duplicates;
  }
  public String getExpression() {
    return expression;
  }
  public boolean isRegEx() {
    return isRegEx;
  }
} ///:~
class TestStream extends PrintStream {
  protected int numOfLines;
  private PrintStream console = System.out, err = System.err, fout;
  // To store lines sent to System.out or err
  private InputStream stdin;
  private String className;
  public TestStream(String className) {
    super(System.out, true); // Autoflush
    System.setOut(this);
    System.setErr(this);
    stdin = System.in; // Save to restore in dispose()
    // Replace the default version with one that
    // automatically produces input on demand:
    System.setIn(new BufferedInputStream(new InputStream() {
      char[] input = ("test\n").toCharArray();
      int index = 0;
      public int read() {
        return (int) input[index = (index + 1) % input.length];
      }
    }));
    this.className = className;
    openOutputFile();
  }
  // public PrintStream getConsole() { return console; }
  public void dispose() {
    System.setOut(console);
    System.setErr(err);
    System.setIn(stdin);
  }
  // This will write over an old Output.txt file:
  public void openOutputFile() {
    try {
      fout = new PrintStream(new FileOutputStream(new File(className
          + "Output.txt")));
    } catch (FileNotFoundException e) {
      throw new RuntimeException(e);
    }
  }
  // Override all possible print/println methods to send
  // intercepted console output to both the console and
  // the Output.txt file:
  public void print(boolean x) {
    console.print(x);
    fout.print(x);
  }
  public void println(boolean x) {
    numOfLines++;
    console.println(x);
    fout.println(x);
  }
  public void print(char x) {
    console.print(x);
    fout.print(x);
  }
  public void println(char x) {
    numOfLines++;
    console.println(x);
    fout.println(x);
  }
  public void print(int x) {
    console.print(x);
    fout.print(x);
  }
  public void println(int x) {
    numOfLines++;
    console.println(x);
    fout.println(x);
  }
  public void print(long x) {
    console.print(x);
    fout.print(x);
  }
  public void println(long x) {
    numOfLines++;
    console.println(x);
    fout.println(x);
  }
  public void print(float x) {
    console.print(x);
    fout.print(x);
  }
  public void println(float x) {
    numOfLines++;
    console.println(x);
    fout.println(x);
  }
  public void print(double x) {
    console.print(x);
    fout.print(x);
  }
  public void println(double x) {
    numOfLines++;
    console.println(x);
    fout.println(x);
  }
  public void print(char[] x) {
    console.print(x);
    fout.print(x);
  }
  public void println(char[] x) {
    numOfLines++;
    console.println(x);
    fout.println(x);
  }
  public void print(String x) {
    console.print(x);
    fout.print(x);
  }
  public void println(String x) {
    numOfLines++;
    console.println(x);
    fout.println(x);
  }
  public void print(Object x) {
    console.print(x);
    fout.print(x);
  }
  public void println(Object x) {
    numOfLines++;
    console.println(x);
    fout.println(x);
  }
  public void println() {
    if (false)
      console.print("println");
    numOfLines++;
    console.println();
    fout.println();
  }
  public void write(byte[] buffer, int offset, int length) {
    console.write(buffer, offset, length);
    fout.write(buffer, offset, length);
  }
  public void write(int b) {
    console.write(b);
    fout.write(b);
  }
} ///:~
class OutputVerifier {
  private static void verifyLength(int output, int expected, int compare) {
    if ((compare == Test.EXACT && expected != output)
        || (compare == Test.AT_LEAST && output < expected))
      throw new NumOfLinesException(expected, output);
  }
  public static void verify(List output, List expected) {
    verifyLength(output.size(), expected.size(), Test.EXACT);
    if (!expected.equals(output)) {
      //find the line of mismatch
      ListIterator it1 = expected.listIterator();
      ListIterator it2 = output.listIterator();
      while (it1.hasNext() && it2.hasNext()
          && it1.next().equals(it2.next()))
        ;
      throw new LineMismatchException(it1.nextIndex(), it1.previous()
          .toString(), it2.previous().toString());
    }
  }
  public static void verifyIgnoreOrder(List output, Object[] expected) {
    verifyLength(expected.length, output.size(), Test.EXACT);
    if (!(expected instanceof String[]))
      throw new RuntimeException(
          "IGNORE_ORDER only works with String objects");
    String[] out = new String[output.size()];
    Iterator it = output.iterator();
    for (int i = 0; i < out.length; i++)
      out[i] = it.next().toString();
    Arrays.sort(out);
    Arrays.sort(expected);
    int i = 0;
    if (!Arrays.equals(expected, out)) {
      while (expected[i].equals(out[i])) {
        i++;
      }
      
      
      throw new SimpleTestException(((String) out[i]).compareTo(expected[i]) < 0 ? "output: <" + out[i] + ">"
          : "expected: <" + expected[i] + ">");
    }
  }
  public static void verifyAtLeast(List output, List expected) {
    verifyLength(output.size(), expected.size(), Test.AT_LEAST);
    if (!output.containsAll(expected)) {
      ListIterator it = expected.listIterator();
      while (output.contains(it.next())) {
      }
      throw new SimpleTestException("expected: <"
          + it.previous().toString() + ">");
    }
  }
} ///:~
class SimpleTestException extends RuntimeException {
  public SimpleTestException(String msg) {
    super(msg);
  }
} ///:~
class NumOfLinesException extends SimpleTestException {
  public NumOfLinesException(int exp, int out) {
    super("Number of lines of output and "
        + "expected output did not match.\n" + "expected: <" + exp
        + ">\n" + "output:   <" + out + "> lines)");
  }
} ///:~
class LineMismatchException extends SimpleTestException {
  public LineMismatchException(int lineNum, String expected, String output) {
    super("line " + lineNum + " of output did not match expected output\n"
        + "expected: <" + expected + ">\n" + "output:   <" + output
        + ">");
  }
} ///:~