https://github.com/probmods/webchurch
Raw File
Tip revision: 52a17db0a9c916509ce89664fe819062bfde0027 authored by Long Ouyang on 26 June 2018, 19:50:49 UTC
Add deprecation note
Tip revision: 52a17db
tester.js
/* global global, console, require, process */


// Takes as input an arbitrary number of filenames / directories

var log = function() {
    var array = Array.prototype.slice.call(arguments, 0);
    array.forEach(function(x) {
        console.log(x);
    });
};

var pc = process.argv.some(function(x){return x.match(/-pc/)});

//console.log("pc",pc)

// make a string appear red in terminal
// HT http://stackoverflow.com/a/17524301/351392
var red = function(str) {
    return "\033[31m" + str + ":\033[91m";
};

var evaluate = require("./evaluate.js").evaluate;
var church_builtins = require("./church_builtins.js");
var format_result = require("./evaluate.js").format_result;
var fs = require('fs');

var tests = [];

// parse tests from a .church file
function parseChurch(src) {
    var cases = src.split("\n\n");
    cases = cases.map(function(c) {
        c = c.trim();
        var lines = c.split("\n");
        var wantedOutput = lines.pop();
        var input = lines.join("\n");

        return {
            input: input,
            wantedOutput: wantedOutput
        };
    });
    return cases;
}

// parse tests from a .md file exported from probmods
// for now, just want things to run without errors
function parseMd(src) {
    var lines = src.split("\n");
    var inInput = false;
    var cases = [];

    var currentCase;

    for(var i = 0, ii = lines.length, inputLines = []; i < ii; i++) {
        var line = lines[i];

        // match end of test
        if (line.match(/~~~~/) && !line.match(/test/)) {
            if (inInput) {
                inInput = false;
                cases.push(currentCase);
            }
        }

        if (inInput) {
            currentCase.input += '\n' + line;
            // skip incomplete code (includes ...)
            // and physics code
            if (line.match(/\.\.\.|runPhysics/)) {
                currentCase.skip = true;
            }
        }

        // match beginning of test
        if (line.match(/~~~~ {/) ) {
            // create a new case
            currentCase = {input: []};

            if (line.match(/shouldfail/)) {
                currentCase.shouldFail = true;
            }
            if (line.match(/norun|mit-church|idealized|skip/)) {
                currentCase.skip = true;
            }
            inInput = true;
        }

    }

    return cases;

}

var parsers = {
    'md': parseMd,
    'church': parseChurch
};

// shims for probmods
global.hist = function(x) { return x };
global.multiviz = function(x) { return x };
global.density = function(x) { return x };
global.runPhysics = function(x) { return x };
global.animatePhysics = function(x) { return x };
global.scatter = function(x) { return x };
global['draw-rect'] = function(x) { return x };
global['raphael-js'] = function(x) { return x };
global['make-raphael'] = function(x) { return x };
global['lineplot'] = function(x) { return x };
global['lineplot-value'] = function(x) { return x };
global['lineplot_45value'] = function(x) { return x };
global['_46_46_46'] = true; // for ...
global.worldWidth = 350;
global.worldHeight = 500;

function runTestFile(filename) {
    var src = fs.readFileSync(filename, 'utf8');
    var filenameSplit = filename.split(".");
    var fileExtension = filenameSplit[filenameSplit.length-1];
    var parser = parsers[fileExtension];

    var cases = parser(src);

    var numCases = cases.length;
    var numPassed = 0;

    // for each case, parse the last line as
    // the desired output
    var testResults = cases.map(function(c, index) {
        var input = c.input;
        var wantedOutput = c.wantedOutput;

        if (c.skip) {
            numPassed++;
            return c;
        }

        try {
            var actualOutput = format_result( evaluate(input) );
            if (typeof wantedOutput != 'undefined' && actualOutput != wantedOutput) {
                log(red("Test " + index + " failed"),
                    input,
                    red("Wanted"),
                    wantedOutput,
                    red("Actual"),
                    actualOutput,""
                   );
            } else {
                numPassed++;
                //process.stdout.write(".");
            }
        } catch(e) {
            // if this test should fail, count it as a success
            // otherwise, complain
            if (c.shouldFail) {
                numPassed++;
            } else {
                log(red("Test " + index + " failed"),
                    input,
                    red('Exception'),
                    e,'');
            }
        }

        c.actualOutput = actualOutput;
        return c;
    });

    log("");
    var allPassed = (numPassed == numCases);
    log("",
        "Passed " + numPassed + " / " + numCases + " tests",
        allPassed ? "Good" : "Bad" );

    return allPassed;
}

var paths = process.argv.slice(2);

var allTestFiles = [];

// TODO: doesn't handle nested directories
paths.forEach(function(path) {
    var lstat = fs.lstatSync(path);
    if (lstat.isFile()) {
        allTestFiles.push(path);
    } else if (lstat.isDirectory()) {
        var dirFiles = fs.readdirSync(path);

        dirFiles = dirFiles
            .filter(function(fileName) {
                // filter out any files that aren't church or markdown
                return /\.(md|church)$/.test( fileName );
            })
            .map(function(fileName) {
                return path + '/' + fileName;
            });

        allTestFiles = allTestFiles.concat(dirFiles);
    }
})

allPassed = true;
allTestFiles.forEach(function(filename) {
    console.log('----- Starting', filename);
    if (!runTestFile(filename)) {
        allPassed = false;
    }
})

process.exit(allPassed ? 0 : 1)
back to top