// The following code contains unit test function that test the functionality 
// of the above classes and functions.

// Test 1 tests the case of an empty graph.
function test1() {
    let bellmanFord = new BellmanFord([]);
    bellmanFord.run();
    let actual = bellmanFord.toString();
    let expected = '[] []';

    compareStringsAndReport('Test 1', actual, expected);
}

// Test 2 tests the case of a graph with no edges.
function test2() {
    let matrix = [
        [0,   inf, inf, inf, inf],
        [inf, 0,   inf, inf, inf],
        [inf, inf, 0,   inf, inf],
        [inf, inf, inf, 0,   inf],
        [inf, inf, inf, inf, 0]
    ];

    let bellmanFord = new BellmanFord(matrix);
    bellmanFord.run(0);
    let actual = bellmanFord.toString();
    let expected = '[0,inf,inf,inf,inf] [null,null,null,null,null]';

    compareStringsAndReport('Test 2', actual, expected);
}

// Test 3 tests the case of a graph with edges but no negative cycles.
function test3() {
    let matrix = [
        [0,   10,  inf, inf, inf],
        [inf, 0,   20,  inf, inf],
        [inf, inf, 0,   30,  inf],
        [inf, inf, inf, 0,   40],
        [inf, inf, inf, inf, 0]
    ];

    let bellmanFord = new BellmanFord(matrix);
    bellmanFord.run(0);
    let actual = bellmanFord.toString();
    let expected = '[0,10,30,60,100] [null,0,1,2,3]';

    compareStringsAndReport('Test 3', actual, expected);
}

// Test 4 tests the case of a graph with edges but no negative cycles, and the
// starting point is not the first node.
function test4() {
    let matrix = [
        [0,   10,  inf, inf, inf],
        [10,  0,   20,  inf, inf],
        [inf, 20,  0,   30,  inf],
        [inf, inf, 30,  0,   40],
        [inf, inf, inf, 40,  0]
    ];

    let bellmanFord = new BellmanFord(matrix);
    bellmanFord.run(2);
    let actual = bellmanFord.toString();
    let expected = '[30,20,0,30,70] [1,2,null,2,3]';

    compareStringsAndReport('Test 4', actual, expected);
}

// Test 5 tests the case of a graph with edges but no negative cycles, and the
// starting point is the last node.
function test5() {
    let matrix = [
        [0,   1,   1,   1,   1],
        [inf, 0,   1,   1,   1],
        [inf, inf, 0,   1,   1],
        [inf, inf, inf, 0,   1],
        [inf, inf, inf, inf, 0]
    ];

    let bellmanFord = new BellmanFord(matrix);
    bellmanFord.run(0);
    let actual = bellmanFord.toString();
    let expected = '[0,1,1,1,1] [null,0,0,0,0]';

    compareStringsAndReport('Test 5', actual, expected);
}

// Test 6 tests the case of a graph with a negative cycle.
function test6() {
    let matrix = [
        [0,   10,  inf, inf, inf],
        [inf, 0,   20,  inf, inf],
        [inf, inf, 0,   30,  inf],
        [inf, -90, inf, 0,   40],
        [inf, inf, inf, inf, 0]
    ];

    let bellmanFord = new BellmanFord(matrix);
    let actual = bellmanFord.run(0);
    let expected = false;

    compareAndReport('Test 6', actual, expected);
}

// Test 7 tests the case of a graph with edges but no negative cycles, and 
// the starting point is not the first node.
function test7() {
    let matrix = [
        [0,   10,  inf, inf, inf],
        [inf, 0,   20,  inf, inf],
        [inf, inf, 0,   30,  inf],
        [inf, inf, inf, 0,   40],
        [inf, inf, inf, inf, 0]
    ];

    let bellmanFord = new BellmanFord(matrix);
    bellmanFord.run(0);
    let actual = bellmanFord.getPath(4);
    let expected = '1,2,3,4';

    compareStringsAndReport('Test 7', actual, expected);
}

// Test 8 tests the case of a graph with edges but no negative cycles, and 
// the starting point is the first node, and the target is the last node.
function test8() {
    let matrix = [
        [0, 10, inf, inf, inf],
        [inf, 0, 20, inf, inf],
        [inf, inf, 0, 30, inf],
        [inf, inf, inf, 0, 40],
        [inf, inf, inf, inf, 0]
    ];

    let bellmanFord = new BellmanFord(matrix);
    bellmanFord.run(0);
    let actual = bellmanFord.getRoute(4);
    let expected = '0,1,10,1,2,20,2,3,30,3,4,40';

    compareStringsAndReport('Test 8', actual, expected);
}

// Test 9 tests the stress test case of a graph with 100 nodes, and 
// no negative cycles. Function getPath() is tested.
function test9() {
    let SIZE = 100;

    //    0,   10,  inf, inf, inf, ..., inf
    //    inf, 0,   20,  inf, inf, ..., inf
    //    inf, inf, 0,   30,  inf, ..., inf
    //    inf, inf, inf, 0,   40,  ..., inf
    //    ...
    //    inf, inf, inf, inf, inf, ..., 990
    //    inf, inf, inf, inf, inf, ..., 0

    let matrix = [];
    matrix.length = SIZE;
    for (let i = 0; i < SIZE; ++i) {
        matrix[i] = [];
        matrix[i].length = SIZE;
    }
    for (let j = 0; j < SIZE; ++j)
        for (let i = 0; i < SIZE; ++i)
            matrix[j][i] = inf;
    for (let i = 0; i < SIZE; ++i)
        matrix[i][i] = 0;
    for (let i = 0; i < SIZE - 1; ++i)
        matrix[i][i + 1] = (i + 1) * 10;

    let bellmanFord = new BellmanFord(matrix);
    bellmanFord.run(0);
    let actual = bellmanFord.getPath(SIZE - 1);
    let expected = ''; // = "1,2,3,4,...,99";
    for (let i = 1; i < SIZE; ++i)
        expected += (i + (i < SIZE - 1 ? ',' : ''));

    compareAndReport('Test 9', actual, expected);
}

// Test 10 tests the stress test case of a graph with 100 nodes, and 
// no negative cycles. Function getRoute() is tested.
function test10() {
    let SIZE = 100;

    //    0,   10,  inf, inf, inf, ..., inf
    //    inf, 0,   20,  inf, inf, ..., inf
    //    inf, inf, 0,   30,  inf, ..., inf
    //    inf, inf, inf, 0,   40,  ..., inf
    //    ...
    //    inf, inf, inf, inf, inf, ..., 990
    //    inf, inf, inf, inf, inf, ..., 0

    let matrix = [];
    matrix.length = SIZE;
    for (let i = 0; i < SIZE; ++i) {
        matrix[i] = [];
        matrix[i].length = SIZE;
    }
    for (let j = 0; j < SIZE; ++j)
        for (let i = 0; i < SIZE; ++i)
            matrix[j][i] = inf;
    for (let i = 0; i < SIZE; ++i)
        matrix[i][i] = 0;
    for (let i = 0; i < SIZE - 1; ++i)
        matrix[i][i + 1] = (i + 1) * 10;

    let bellmanFord = new BellmanFord(matrix);
    bellmanFord.run(0);
    let actual = bellmanFord.getRoute(SIZE - 1);
    let expected = ''; // = '0,1,10,1,2,20,...,98,99,990';
    for (let i = 0; i < SIZE - 1; ++i)
        expected += (i + ',' + (i + 1) + ',' + ((i + 1) * 10) + 
                        (i < SIZE - 2 ? ',' : ''));

    compareStringsAndReport('Test 10', actual, expected);
}