// a testing "framework"!

export type TestFn = (t: Test) => void;

export class Test {
    label: string;
    level: number;
    errors = 0;

    constructor(label: string, level: number) {
        this.label = label;
        this.level = level;
    }

    report() {
        console.log(`"${this.label}" completed with ${this.errors} errors`);
    }

    test(label: string, fn: TestFn) {
        let subtest = new Test(label, this.level + 1);
        fn(subtest);
        this.errors += subtest.errors;
    }

    expect(b: boolean, message: string): boolean {
        if (!b) {
            this.errors += 1;
            let indent = ''
            for (let i = 0; i < this.level; i++) {
                indent += '    '
            }
            // printNiceStackTrace();
            console.log(indent + message);
            // debugger;
        }
        return b
    }

    equal(a: any, b: any, a_label: string = 'A', b_label: string = String(b)): boolean {
        return this.expect(a === b, `${a_label} is not equal to ${b_label}. ${a} !== ${b}`);
    }

    notEqual(a: any, b: any, a_label: string = 'A', b_label: string = String(b)): boolean {
        return this.expect(a !== b, `${a_label} is equal to ${b_label}, ${a}`);
    }
}

export function test(label: string, fn: (t: Test) => void) {
    let t = new Test(label, 0);
    try {
        fn(t);
    } catch(e) {
        console.log("Exception thrown!!");
    } finally {
        t.report();
    }
}

function printNiceStackTrace() {
    let err = new Error()
    let stk = err.stack;
    console.log(stk);
}
