CodeView

PHPUnit test harness for Komodo

drive_testrunner.php

<?php
/*
 * Usage:
 * php drive_testrunner.php dirname [options1]
 * php drive_testrunner.php [options2]
 *   where
 * options1 = ( --file FileNameSubstring |
 *              --class TestClassNameSubstring)*
 * options2 = ( --dirname Directory |
 *              --file FileNameSubstring |
 *              --class TestClassNameSubstring)*
 * --file and --class options intersect -- use all found files unless --file is
 * specified.  Use all found test classes unless --class is specified.
 * No option for filtering particular tests in a suite.
 */
require_once("PHPUnit/Framework.php" );
require_once("MyTestRunner.php");
require_once("MyTestFormatter.php");
 
function check_arg($candidate, $args, $category) {
    if (!$args[$category]) {
        return true;
    }
    $hasMatch = false;
    foreach ($args[$category] as $currCandidate) {
        if (stristr($candidate, $currCandidate)) {
            $hasMatch = true;
            break;
        }
    }
    //if (!$hasMatch) {
    //    print("************ Didn't match $category $candidate\n");
    //}
    return $hasMatch;
}
 
function get_suite_from_file($suite, $file, $checkBasename=true, $args) {
    if (!check_arg($file, $args, 'files')) {
        return;
    }
    $basename = basename($file);
    if ($checkBasename) {
        if (!preg_match('/.*test.*\./i', $basename)) {
            #print("File $basename doesn't look like a test file\n");
            return;
        }
    }
    # Always load only .inc or .php files
    if (!preg_match('/.*\.(?:php|inc)$/i', $basename)) {
        #print("File $basename doesn't look like a PHP file\n");
        return;
    }
    $before_classes = get_declared_classes();
    #print("**************** About to load file $file from dir " . getcwd() . "\n");
    $file_fs = preg_replace('/\\\\/', '/', $file);
    #print("**************** Actually $file_fs... \n");
    require_once $file_fs;
    $after_classes = get_declared_classes();
    $new_classes = array_diff($after_classes, $before_classes);
    foreach ($new_classes as $class) {
        if (preg_match('/(?:T|\\bt)est(?:$|[^a-z])/i', $class)) {
            # print "Adding class $class from file $file ($basename)\n";
            if (check_arg($class, $args, 'classes')) {
                $suite->addTestSuite($class);
            }
        }
    }
}
 
function has_test_dir($dir_contents) {
    foreach ($dir_contents as $subdir) {
        if (preg_match('/^tests?$/i', $subdir)) {
            return $subdir;
        }
    }
    return null;
}
function is_test_dir($parent, $subdir) {
    return (preg_match('/^tests?$/i', $subdir)
            && is_dir("$parent/$subdir") );
}
 
function is_possible_subdir_name($dir) {
    return $dir != '.' && $dir != '..' && $dir != '.svn';
}
 
function get_suite_from_all_modules($suite, $directory, $subdir, $checkFilename, $args) {
    $fullname = "$directory/$subdir";
    if (is_dir($fullname)) {
        $dh = opendir($fullname);
        if (!$dh) {
            return;
        }
        while (($file = readdir($dh)) != false) {
            if (is_possible_subdir_name($file)) {
                get_suite_from_all_modules($suite, $fullname, $file, $checkFilename, $args);
            }
        }
        closedir($dh);
    } else {
        get_suite_from_file($suite, $fullname, $checkFilename, $args);
    }
}
 
function get_suite_from_dir($directory, $args) {
    // Find all tests under dir $directory...
    // Introspect to pull out the test classes
    if (!is_dir($directory)) {
        // Maybe it's a file
        if (!file_exists($directory)) {
            print("Can't work with \$directory=$directory\n");
            return $suite;
        }
        $suite = new PHPUnit_Framework_TestSuite();
        get_suite_from_file($suite, $directory, true, $args);
        return $suite;
    } else {
        $suite = new PHPUnit_Framework_TestSuite();
        // Look for a 'test' or 'tests' dir
        $members = scandir($directory);
        if (has_test_dir($members)) {
            # Just pick out the testdirs and walk their contents
            foreach ($members as $subdir) {
                if (is_test_dir($directory, $subdir)) {
                    $curr_dir = getcwd();
                    chdir("$directory");
                    get_suite_from_all_modules($suite, ".", $subdir, false, $args);
                    chdir($curr_dir);
                }
            }
        }
        $dh = opendir($directory);
        if (!$dh) {
            return $suite;
        }
        while (($file = readdir($dh)) != false) {
            if (is_possible_subdir_name($file)) {
                get_suite_from_all_modules($suite, $directory, $file, true, $args);
            }
        }
        closedir($dh);
    }
    return $suite;
}
 
# first arg is the directory to get tests from
# --file fname  -- if given, choose only matching files
# --class test   -- if given, choose only matching tests
$dirname = null;
$args = Array('dirname' => null,
              'files' => Array(),
              'classes' => Array()
              );
if ($argc <= 1) {
    $args['dirname'] = getcwd();
} else {
    if ($argc <= 3 && $argv[1] == "--dir") {
        $args['dirname'] = $argv[2];
        $idx = 3;
    } else {
        $args['dirname'] = $argv[1];
        $idx = 2;
    }
    while ($idx < $argc - 1) {
        switch ($argv[$idx]) {
        case '--file':
            $args['files'][] = $argv[$idx + 1];
            $idx += 2;
            break;
        case '--class':
            $args['classes'][] = $argv[$idx + 1];
            $idx += 2;
            break;
        default:
            print_error("drive_testrunner.php: Unrecognized comment-line argument $idx: $argv[$idx]");
            return;
        }
    }
    if ($idx == $argc - 1) {
        print_error("drive_testrunner.php: Unhandled comment-line argument $idx: $argv[$idx]");
        return;
    }
}
 
function print_error($msg) {
    print "@suite_started@: drive_testrunner.php\n";
    print "@fault@: $msg\n";
    print "@suite_finished@:\n";
}
#print_r($args);
$suite = get_suite_from_dir($args['dirname'], $args);
if ($suite) {
    if ($suite->count() == 0) {
        print "@suite_started@: drive_testrunner.php: No PHP Unit tests selected\n";
        if ($args['files']) {
            printf("@info@: No matching files in ['%s']\n", implode("', '", $args['files']));
        }
        if ($args['classes']) {
            printf("@info@: No matching classes in ['%s']\n", implode("', '", $args['classes']));
        }
        print "@suite_finished@:\n";
        return;
    }
    $runner = new tests_TestRunner($suite);
    $formatter = new KoUnit_Formatter();
    $runner->addFormatter($formatter);
    $runner->run();
}
 
?>