Alias2.java Source code

Java tutorial

Introduction

Here is the source code for Alias2.java

Source

// : 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 + ">");
    }
} ///:~