public function runTest($name)
{
// don't run a test more than once!
if ($this->tests[$name]['run']) {
\FUnit::debug_out("test '{$name}' was already run; skipping");
return $this->tests[$name];
}
\FUnit::info_out("Running test '{$name}' in suite {$this->getName()}");
$ts_start = microtime(true);
// to associate the assertions in a test with the test,
// we use this static var to avoid the need to for globals
$this->current_test_name = $name;
$test = $this->tests[$name]['test'];
// setup
if (isset($this->setup_func)) {
\FUnit::debug_out("running setup for '{$name}'");
$setup_func = $this->setup_func;
$setup_func();
unset($setup_func);
}
$ts_setup = microtime(true);
try {
\FUnit::debug_out("executing test function for '{$name}'");
$test();
} catch (\Exception $e) {
\FUnit::exception_handler($e);
}
$ts_run = microtime(true);
// teardown
if (isset($this->teardown_func)) {
\FUnit::debug_out("running teardown for '{$name}'");
$teardown_func = $this->teardown_func;
$teardown_func();
unset($teardown_func);
}
$ts_teardown = microtime(true);
$this->current_test_name = null;
$this->tests[$name]['run'] = true;
$this->tests[$name]['timing'] = array('setup' => $ts_setup - $ts_start, 'run' => $ts_run - $ts_setup, 'teardown' => $ts_teardown - $ts_run, 'total' => $ts_teardown - $ts_start);
if (count($this->tests[$name]['errors']) > 0) {
$this->tests[$name]['pass'] = false;
} else {
$assert_counts = $this->assertCounts($name);
if ($assert_counts['pass'] === $assert_counts['total']) {
$this->tests[$name]['pass'] = true;
} else {
$this->tests[$name]['pass'] = false;
}
}
if (false === $this->tests[$name]['pass']) {
$this->exit_code = 1;
}
\FUnit::debug_out("Timing: " . json_encode($this->tests[$name]['timing']));
// json is easy to read
return $this->tests[$name];
}