view tests/run.d @ 192:fda35d57847e

Fixed String parsing, so that they get created with the right type in AST. Also added so that you can parse options to the test program, that will mirror them to Dang. Eg. ./tests/run --semantic-only will pass --semantic-only to Dang on each run.
author Anders Johnsen <skabet@gmail.com>
date Fri, 25 Jul 2008 15:00:54 +0200
parents e1e170c2cd44
children
line wrap: on
line source

// skip
module run.d;

import tango.core.Array,
       tango.io.FileConduit,
       tango.io.FileScan,
       tango.io.Stdout,
       tango.sys.Process,
       tango.text.Ascii,
       tango.text.Regex,
       tango.text.Util;

// -- Settings --
char[] compiler = "./Dang";
char[] test_folder = "tests";
char[] valid_filenames = r"^[^.].*";
bool print_expected = false;
char[][] options;
// the tests can be sorted by one of the following functions
bool nameSort    (FilePath a, FilePath b) { return a.name     < b.name;     }
bool pathSort    (FilePath a, FilePath b) { return a.toString < b.toString; }
bool modifiedSort(FilePath a, FilePath b) { return a.modified < b.modified; }
bool createdSort (FilePath a, FilePath b) { return a.created  < b.created;  }
const sortBy = &pathSort;

// -- end of settings

enum TestResult
{
    Skipped,
    Expected,
    Unexpected
}

void main(char[][] args)
{
    foreach (arg ; args[1..$])
        options ~= arg;

    scope scan = new FileScan;
//    scope regex = new Regex(valid_filenames); // DMD FAILS!! ?? 
    // Return true for files/folders to include
    bool filter(FilePath p, bool isDir)
    {
        if (isDir)
            return p.name[0] != '.';
        else
            return p.ext == "d" ; //&& regex.test(p.name);
    }
    scan.sweep(test_folder, &filter, true);
    FilePath[] files = scan.files;
    int total_tests = files.length;

    // Sort the result by the chosen function - default is the full path
    sort(files, sortBy);

    int[TestResult.max + 1] results = 0;
    foreach (i, ref test; files)
    {
        begin_test(i + 1, total_tests, test.name);
        TestResult res = run_test(test);
        results[res] += 1;
        end_test();
    }
    Stdout.format("\r{,80}\r", " ");
    Stdout.newline;
    int good = TestResult.Expected;
    int bad = TestResult.Unexpected;
    int tests_run = results[good] + results[bad];
    Stdout.formatln("{}/{} tests failed", results[bad], tests_run);
}

void begin_test(int number, int total_tests, char[] name)
{
    char[60] progressbar = ' ';
    int progress = number*progressbar.length/total_tests;
    progressbar[0 .. progress] = '=';
    if(progress)
        progressbar[progress-1] = '>';
    Stdout.format("\r{}% - [{}]", 1e2 * number / total_tests, progressbar);
    Stdout.flush();
    //Thread.sleep(0.05);
}

void end_test() { }

enum {
    NoFail,
    CompiletimeFail,
    RuntimeFail
}

private int min(int a, int b) { return a < b? a : b; }
TestResult run_test(ref FilePath p)
{
    auto file = new FileConduit(p.toString(), FileConduit.ReadExisting);
    char[256] content;
    int len = file.read(content);
    file.close();
    char[] line = content[0 .. min(len, content.find('\n'))];

    bool compile = true;
    int fail = NoFail;
    if (line.length >= 2 && line[0 .. 2] == "//")
    {
        foreach (command; line[2 .. $].delimiters(",;"))
        {
            switch (toLower(substitute(command, " ", "")))
            {
                case "skip", "dontcompile":
                    compile = false;
                    break;
                case "fail", "compilefail",
                     "compiletimefail", "failatcompiletime":
                    fail = CompiletimeFail;
                    break;
                case "runtime", "runtimefail", "failatruntime":
                    fail = RuntimeFail;
                    Stderr("== Compiled tests will not be run! ==").newline;
                    return TestResult.Skipped;
                default:
                    break;
            }
            break;
        }
    }

    if (compile)
    {
        auto o = compiler ~ options ~ p.toString;
        auto process = new Process(o);
        process.execute();
        auto result = process.wait();
        return resultOf(p, result.status, fail); 
    }

    return TestResult.Skipped;
}

private TestResult resultOf(FilePath p, int result, int expected)
{
    char[] good(char[] s)
    {
        version (Posix)
            return "\033[1;32m" ~ s ~ "\033[m";
        else
            return s;
    }

    char[] bad(char[] s)
    {
        s = s ~ " - Unexpected";
        version (Posix)
            return "\033[1;31m" ~ s ~ "\033[m";
        else
            return s;
    }

    bool unexpected = expected == 0 ? result != 0 : result == 0;
    auto f = unexpected? &bad : &good;
    char[] s = (result == 0)? "SUCCESS" : "FAILURE";
    // always print if unexpeted, otherwise check the settings
    if (unexpected || print_expected)
    {
        Stdout.format("\r{,80}\r", " ");
        Stdout.format("  {,-45}", p);
        Stdout(f(s)).newline;
    }
    return unexpected? TestResult.Unexpected : TestResult.Expected;
}