
import junit.framework.*;
import org.erights.e.develop.trace.TraceCaller;

/**
 * Some simple tests.
 *
 */




public class TestTraceCaller extends TestCase {


	public TestTraceCaller(String name) {
		super(name);
	}

	protected void setUp() {
	}

	public static Test suite() {
		return new TestSuite(TestTraceCaller.class);
	}



    // STACK WALKING TESTS - can we find the right frame to parse?
    // In the following, "Sun stack" means the stack produced by 
    // "1.2.2" Classic VM (build JDK-1.2.2-001, native threads,
    // symcjit) on Windows 


    // Standard trace message, Sun stack.
    public void testStackWalkNormalSun() {
        String msg = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.errorm(Trace.java:213)\n"+
            "\tat Dump.main(Dump.java:18)\n";
        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("Dump.main"));
        assert(tc.fileName.equals("Dump.java"));
        assert(tc.lineNumber.equals("18"));
    }


    // Standard trace message, Sun stack.
    // Small variation on above: CRLFs instead of terminating LFs, and
    // no terminating LF at the top of the stack. Also changing package
    // names to flush out package dependencies.
    public void testStackWalkCRLFSun() {
        String msg = 
            "java.lang.Exception\r\n"+
            "\tat X.TraceMessage.<init>(TraceMessage.java:88)\r\n"+
            "\tat X.recordTraceMessageXyzzY(Trace.java:348)\r\n"+
            "\tat X.errorm(Trace.java:213)\r\n"+
            "\tat Dump.main(Dump.java:18)";
        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("Dump.main"));
        assert(tc.fileName.equals("Dump.java"));
        assert(tc.lineNumber.equals("18"));
    }


    // Unposted trace message, Sun stack.
    public void testStackWalkUnpostedSun() {
        String msg = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.TraceBuffer.recordTraceMessageXyzzY(TraceBuffer.java:348)\n"+
            "\tat org.erights.e.develop.trace.TraceBuffer.unpostedTraceMessage(TraceBuffer.java:229)\n"+
            "\tat org.erights.e.develop.trace.TraceBuffer.dump(TraceBuffer.java, Compiled Code)\n"+
            "\tat org.erights.e.develop.trace.TraceController.dumpBufferToLog(TraceController.java:217)\n"+
            "\tat Dump.main(Dump.java, Compiled Code)\n";
        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("TraceBuffer.dump"));
        assert(tc.fileName.equals("TraceBuffer.java"));
        assert(tc.lineNumber.equals("line?"));
    }


    // Standard trace message, Sun stack.
    // There are two calls to trace on the stack.
    public void testStackWalkTwoCallsSun() {
        String msg = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.worldm(Trace.java:479)\n"+
            "\tat org.erights.e.develop.trace.TraceLog.handleFullLog(TraceLog.java:415)\n"+
            "\tat org.erights.e.develop.trace.TraceLog.acceptBypassingQueue(TraceLog.java:147)\n"+
            "\tat org.erights.e.develop.trace.TraceLog.accept(TraceLog.java:126)\n"+
            "\tat org.erights.e.develop.trace.TraceSubsystemMediator.accept(TraceSubsystemMediator.java, Compiled Code)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:353)\n"+
            "\tat org.erights.e.develop.trace.Trace.worldm(Trace.java:482)\n"+
            "\tat Dump.main(Dump.java, Compiled Code)\n";

        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("TraceLog.handleFullLog"));
        assert(tc.fileName.equals("TraceLog.java"));
        assert(tc.lineNumber.equals("415"));
    }

    // Standard trace message, Sun stack.
    // The bottommost frame has been lost by the VM.
    public void testStackLostBottomFrameSun() {
        String msg = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.worldm(Trace.java:479)\n"+
            "\tat Dump.main(Dump.java, Compiled Code)\n";
        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("Dump.main"));
        assert(tc.fileName.equals("Dump.java"));
        assert(tc.lineNumber.equals("line?"));
    }

    // Standard trace message, Sun stack.
    // The bottommost frame is mislabelled as recordTraceMessage by
    // the VM. 
    public void testStackMisnamedBottomFrameSun() {
        String msg = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java, Compiled Code)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java, Compiled Code)\n"+
            "\tat org.erights.e.develop.trace.Trace.worldm(Trace.java:479)\n"+
            "\tat mumble.Dump.main(Dump.java:333)\n";
        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("Dump.main"));
        assert(tc.fileName.equals("Dump.java"));
        assert(tc.lineNumber.equals("333"));
    }

    // Unposted trace message, Sun stack.
    // Bottommost frame has been lost
    public void testStackWalkUnpostedLostFrameSun() {
        String msg = 
            "java.lang.Exception\n"+
            "\tat TraceBuffer.recordTraceMessageXyzzY(TraceBuffer.java:348)\n"+
            "\tat TraceBuffer.unpostedTraceMessage(TraceBuffer.java:229)\n"+
            "\tat TraceBuffer.<init>(TraceBuffer.java:70)\n"+
            "\tat TraceController.<clinit>(TraceController.java:113)\n"+
            "\tat Trace.<init>(Trace.java:167)\n"+
            "\tat Trace.<clinit>(Trace.java:117)\n"+
            "\tat Dump.<clinit>(Dump.java:5)\n";
        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("TraceBuffer.<init>"));
        assert(tc.fileName.equals("TraceBuffer.java"));
        assert(tc.lineNumber.equals("70"));
    }

    // Unposted trace message, Sun stack.
    // Bottommost frame has been duplicated
    public void testStackWalkUnpostedMisnamedFrameSun() {
        String msg = 
            "java.lang.Exception\n"+
            "\tat TraceBuffer.recordTraceMessageXyzzY(TraceBuffer.java:348)\n"+
            "\tat TraceBuffer.recordTraceMessageXyzzY(TraceBuffer.java:348)\n"+
            "\tat TraceBuffer.unpostedTraceMessage(TraceBuffer.java:229)\n"+
            "\tat org.erights.e.develop.trace.TraceBuffer.dump(TraceBuffer.java, Compiled Code)\n"+
            "\tat org.erights.e.develop.trace.TraceController.dumpBufferToLog(TraceController.java:217)\n"+
            "\tat Dump.main(Dump.java, Compiled Code)\n";
        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("TraceBuffer.dump"));
        assert(tc.fileName.equals("TraceBuffer.java"));
        assert(tc.lineNumber.equals("line?"));
    }


    // Standard trace message, Sun stack.
    // Everything above the recordTraceMessage is gone.
    public void testStackWalkRecordAtTopSun() {
        String msg = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n";
        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("method?"));
        assert(tc.fileName.equals("file?"));
        assert(tc.lineNumber.equals("line?"));
    }

    // Standard trace message, Sun stack.
    // Everything above the recordTraceMessage is gone, except for the
    // errorm call.
    public void testStackWalkRecordAlmostAtTopSun() {
        String msg = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.errorm(Trace.java:213)\n";
        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("method?"));
        assert(tc.fileName.equals("file?"));
        assert(tc.lineNumber.equals("line?"));
    }

    // Sun stack, but there's no recordTraceMessage in the stack.
    public void testStackWalkNoRecordSun() {
        String msg = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.worldm(Trace.java:479)\n"+
            "\tat org.erights.e.develop.trace.TraceLog.handleFullLog(TraceLog.java:415)\n"+
            "\tat org.erights.e.develop.trace.TraceLog.acceptBypassingQueue(TraceLog.java:147)\n"+
            "\tat org.erights.e.develop.trace.TraceLog.accept(TraceLog.java:126)\n"+
            "\tat org.erights.e.develop.trace.TraceSubsystemMediator.accept(TraceSubsystemMediator.java, Compiled Code)\n"+
            "\tat org.erights.e.develop.trace.Trace.worldm(Trace.java:482)\n"+
            "\tat Dump.main(Dump.java, Compiled Code)\n";

        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("method?"));
        assert(tc.fileName.equals("file?"));
        assert(tc.lineNumber.equals("line?"));
    }


    // Sun stack, but there's no recordTraceMessage in the stack. And
    // there's only one frame.
    public void testStackWalkOneFrameSun() {
        String msg = 
            "java.lang.Exception\n"+
            "\tat Gorp.handleFullLog(Log.java:415)\n";

        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("method?"));
        assert(tc.fileName.equals("file?"));
        assert(tc.lineNumber.equals("line?"));
    }

    // Sun stack, but there's no recordTraceMessage in the stack. And
    // there's no frame.
    public void testStackWalkNoFrameSun() {
        String msg = 
            "java.lang.Exception\n";

        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("method?"));
        assert(tc.fileName.equals("file?"));
        assert(tc.lineNumber.equals("line?"));
    }


    // Sun stack, but there's no recordTraceMessage in the stack. And
    // the stack is an empty string.
    public void testStackWalkNoNothing() {
        String msg = "";

        TraceCaller tc = new TraceCaller(msg);
        assert(tc.methodName.equals("method?"));
        assert(tc.fileName.equals("file?"));
        assert(tc.lineNumber.equals("line?"));
    }




    // PARSING OF PARTICULAR FRAMES
    // These are older tests, retrofitted for the new (August 02000)
    // stack walking code. They use "Jdk" to mean:
    // "1.2.2" Classic VM (build JDK-1.2.2-001, native threads,
    // symcjit) on Windows.

    // Printing of constructor frame. Sun jdk 1.2
    public void testJdkConstructor() {
        String jdkConstructor = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.errorm(Trace.java:213)\n"+
            "\tat java.util.StackPrinter.<init>(StackPrinter.java:1)\n";
        TraceCaller msg = new TraceCaller(jdkConstructor);
        assert(msg.methodName.equals("StackPrinter.<init>"));
        assert(msg.fileName.equals("StackPrinter.java"));
        assert(msg.lineNumber.equals("1"));
    }

    // Printing of compiled frame. Sun jdk 1.2
    public void testJdkCompiled() {
        String jdkCompiled = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.warningm(Trace.java:213)\n"+
            "\tat StackPrinter.inlineMe(StackPrinter.class, Compiled Code)\n";
        TraceCaller msg = new TraceCaller(jdkCompiled);
        assert(msg.methodName.equals("StackPrinter.inlineMe"));
        assert(msg.fileName.equals("StackPrinter.class"));
        assert(msg.lineNumber.equals("line?"));
    }


    // Use of <> instead of parens, comma instead of
    // colon before line number. What VM does this?
    public void testAlternateTabPair1() {
        String s = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.worldm(Trace.java:213)\n"+
            "\tat StackPrinter.underInline<StackPrinter.java,63>\n";

        TraceCaller msg = new TraceCaller(s);
        assert(msg.methodName.equals("StackPrinter.underInline"));
        assert(msg.fileName.equals("StackPrinter.java"));
        assert(msg.lineNumber.equals("63"));

    }

    // Use of tabs instead of parens, comma instead of
    // colon before line numbers. What VM does this?
    public void testAlternateTabPair2() {
        String s = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.usagem(Trace.java:213)\n"+
            "\tat StackPrinter.underInline\tStackPrinter.java,63\t\n";

        TraceCaller msg = new TraceCaller(s);
        msg = new TraceCaller(s);
        assert(msg.methodName.equals("StackPrinter.underInline"));
        assert(msg.fileName.equals("StackPrinter.java"));
        assert(msg.lineNumber.equals("63"));
    }

    // No closing delimiter still yields a good parse
    public void testNoClose() {
        String s = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.eventm(Trace.java:213)\n"+
            "\tat StackPrinter.underInline(StackPrinter.java:630\n" + 
            "\tat S.u<P.java,63>\n";

        TraceCaller msg = new TraceCaller(s);
        assert(msg.methodName.equals("StackPrinter.underInline"));
        assert(msg.fileName.equals("StackPrinter.java"));
        assert(msg.lineNumber.equals("630"));
    }


    // Very wrong format frame. If TraceCaller gets smarter, the 
    // given string may need to change.
    public void testWrongFormat() {
        String s = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.debugm(Trace.java:213)\n"+
            "StackPrinter.foo ; underInline at StackPrinter.java (630)\n"+
            "\tat S.u<P.java,63>\n";

        TraceCaller msg = new TraceCaller(s);
        assert(msg.methodName.equals("method?"));
        assert(msg.fileName.equals("file?"));
        assert(msg.lineNumber.equals("line?"));
    }

    // The leading prefix of a frame is wrong. 
    public void testBadStart() {
        String s = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.verbosem(Trace.java:213)\n"+
            "  at mumble.StackPrinter.main(S.java:71)\n"+
            "\tat S.main(StackPrinter.foo.java:9)\n";


        TraceCaller msg = new TraceCaller(s);
        assert(msg.methodName.equals("StackPrinter.main"));
        assert(msg.fileName.equals("S.java"));
        assert(msg.lineNumber.equals("71"));
    }

    // Unexpected delimiters around the line numbers. Note that the
    // bad delimiter causes all accessors to have their default
    // values. This is expected behavior.
    public void testBadDelim() {
        String s = 
            "java.lang.Exception\n"+
            "\tat org.erights.e.develop.trace.TraceMessage.<init>(TraceMessage.java:88)\n"+
            "\tat org.erights.e.develop.trace.Trace.recordTraceMessageXyzzY(Trace.java:348)\n"+
            "\tat org.erights.e.develop.trace.Trace.verbosem(Trace.java:213)\n"+
            "\tat StackPrinter.printStackTrace[StackPrinter.java:21]\n" +
            "\tat S.z.p(S.java:1)\n";

        TraceCaller msg = new TraceCaller(s);
        assert(msg.methodName.equals("method?"));
        assert(msg.fileName.equals("file?"));
        assert(msg.lineNumber.equals("line?"));
    }

}
