1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-14 19:02:40 +01:00
phorge-arcanist/src/unit/engine/NoseTestEngine.php
Joshua Spence ef18ae08eb Don't explicitly name abstract base classes
Summary:
Ref T5655. It is superfluous to include "base" in the name of an abstract base class. Furthermore, it is not done consistently within the code base.

In order to retain compatibility with external code, I have kept the `ArcanistBaseWorkflow` class (which trivially extends from `ArcanistWorkflow`), but it is now deprecated and should output a warning message. Similarly for `ArcanistBaseUnitTestEngine`.

Test Plan: Created a workflow which extends from `ArcanistBaseWorkflow`. Executed the workflow and saw a deprecation warning.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: epriestley, Korvin, aurelijus

Maniphest Tasks: T5655

Differential Revision: https://secure.phabricator.com/D9983
2014-07-22 07:49:15 +10:00

162 lines
4.4 KiB
PHP

<?php
/**
* Very basic 'nose' unit test engine wrapper.
*
* Requires nose 1.1.3 for code coverage.
*/
final class NoseTestEngine extends ArcanistUnitTestEngine {
public function run() {
$paths = $this->getPaths();
$affected_tests = array();
foreach ($paths as $path) {
$absolute_path = Filesystem::resolvePath($path);
if (is_dir($absolute_path)) {
$absolute_test_path = Filesystem::resolvePath('tests/'.$path);
if (is_readable($absolute_test_path)) {
$affected_tests[] = $absolute_test_path;
}
}
if (is_readable($absolute_path)) {
$filename = basename($path);
$directory = dirname($path);
// assumes directory layout: tests/<package>/test_<module>.py
$relative_test_path = 'tests/'.$directory.'/test_'.$filename;
$absolute_test_path = Filesystem::resolvePath($relative_test_path);
if (is_readable($absolute_test_path)) {
$affected_tests[] = $absolute_test_path;
}
}
}
return $this->runTests($affected_tests, './');
}
public function runTests($test_paths, $source_path) {
if (empty($test_paths)) {
return array();
}
$futures = array();
$tmpfiles = array();
foreach ($test_paths as $test_path) {
$xunit_tmp = new TempFile();
$cover_tmp = new TempFile();
$future = $this->buildTestFuture($test_path, $xunit_tmp, $cover_tmp);
$futures[$test_path] = $future;
$tmpfiles[$test_path] = array(
'xunit' => $xunit_tmp,
'cover' => $cover_tmp,
);
}
$results = array();
foreach (Futures($futures)->limit(4) as $test_path => $future) {
try {
list($stdout, $stderr) = $future->resolvex();
} catch(CommandException $exc) {
if ($exc->getError() > 1) {
// 'nose' returns 1 when tests are failing/broken.
throw $exc;
}
}
$xunit_tmp = $tmpfiles[$test_path]['xunit'];
$cover_tmp = $tmpfiles[$test_path]['cover'];
$this->parser = new ArcanistXUnitTestResultParser();
$results[] = $this->parseTestResults($source_path,
$xunit_tmp,
$cover_tmp);
}
return array_mergev($results);
}
public function buildTestFuture($path, $xunit_tmp, $cover_tmp) {
$cmd_line = csprintf('nosetests --with-xunit --xunit-file=%s',
$xunit_tmp);
if ($this->getEnableCoverage() !== false) {
$cmd_line .= csprintf(
' --with-coverage --cover-xml --cover-xml-file=%s',
$cover_tmp);
}
return new ExecFuture('%C %s', $cmd_line, $path);
}
public function parseTestResults($source_path, $xunit_tmp, $cover_tmp) {
$results = $this->parser->parseTestResults(
Filesystem::readFile($xunit_tmp));
// coverage is for all testcases in the executed $path
if ($this->getEnableCoverage() !== false) {
$coverage = $this->readCoverage($cover_tmp, $source_path);
foreach ($results as $result) {
$result->setCoverage($coverage);
}
}
return $results;
}
public function readCoverage($cover_file, $source_path) {
$coverage_dom = new DOMDocument();
$coverage_dom->loadXML(Filesystem::readFile($cover_file));
$reports = array();
$classes = $coverage_dom->getElementsByTagName('class');
foreach ($classes as $class) {
$path = $class->getAttribute('filename');
$root = $this->getWorkingCopy()->getProjectRoot();
if (!Filesystem::isDescendant($path, $root)) {
continue;
}
// get total line count in file
$line_count = count(phutil_split_lines(Filesystem::readFile($path)));
$coverage = '';
$start_line = 1;
$lines = $class->getElementsByTagName('line');
for ($ii = 0; $ii < $lines->length; $ii++) {
$line = $lines->item($ii);
$next_line = intval($line->getAttribute('number'));
for ($start_line; $start_line < $next_line; $start_line++) {
$coverage .= 'N';
}
if (intval($line->getAttribute('hits')) == 0) {
$coverage .= 'U';
} else if (intval($line->getAttribute('hits')) > 0) {
$coverage .= 'C';
}
$start_line++;
}
if ($start_line < $line_count) {
foreach (range($start_line, $line_count) as $line_num) {
$coverage .= 'N';
}
}
$reports[$path] = $coverage;
}
return $reports;
}
}