diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index a4963e2b..4149409d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -168,6 +168,7 @@ phutil_register_library_map(array( 'PhutilLintEngine' => 'lint/engine/PhutilLintEngine.php', 'PhutilUnitTestEngine' => 'unit/engine/PhutilUnitTestEngine.php', 'PhutilUnitTestEngineTestCase' => 'unit/engine/__tests__/PhutilUnitTestEngineTestCase.php', + 'PytestTestEngine' => 'unit/engine/PytestTestEngine.php', 'UnitTestableArcanistLintEngine' => 'lint/engine/UnitTestableArcanistLintEngine.php', ), 'function' => @@ -299,6 +300,7 @@ phutil_register_library_map(array( 'PhutilLintEngine' => 'ArcanistLintEngine', 'PhutilUnitTestEngine' => 'ArcanistBaseUnitTestEngine', 'PhutilUnitTestEngineTestCase' => 'ArcanistTestCase', + 'PytestTestEngine' => 'ArcanistBaseUnitTestEngine', 'UnitTestableArcanistLintEngine' => 'ArcanistLintEngine', ), )); diff --git a/src/unit/engine/PytestTestEngine.php b/src/unit/engine/PytestTestEngine.php new file mode 100644 index 00000000..37a43b72 --- /dev/null +++ b/src/unit/engine/PytestTestEngine.php @@ -0,0 +1,89 @@ +resolvex(); + + return $this->parseTestResults($junit_tmp); + } + + public function parseTestResults($junit_tmp) { + // xunit xsd: https://gist.github.com/959290 + $xunit_dom = new DOMDocument(); + $xunit_dom->loadXML(Filesystem::readFile($junit_tmp)); + + $results = array(); + $testcases = $xunit_dom->getElementsByTagName("testcase"); + foreach ($testcases as $testcase) { + $classname = $testcase->getAttribute("classname"); + $name = $testcase->getAttribute("name"); + $time = $testcase->getAttribute("time"); + + $status = ArcanistUnitTestResult::RESULT_PASS; + $user_data = ""; + + // A skipped test is a test which was ignored using framework + // mechanizms (e.g. @skip decorator) + $skipped = $testcase->getElementsByTagName("skipped"); + if ($skipped->length > 0) { + $status = ArcanistUnitTestResult::RESULT_SKIP; + $messages = array(); + for ($ii = 0; $ii < $skipped->length; $ii++) { + $messages[] = trim($skipped->item($ii)->nodeValue, " \n"); + } + + $user_data .= implode("\n", $messages); + } + + // Failure is a test which the code has explicitly failed by using + // the mechanizms for that purpose. e.g., via an assertEquals + $failures = $testcase->getElementsByTagName("failure"); + if ($failures->length > 0) { + $status = ArcanistUnitTestResult::RESULT_FAIL; + $messages = array(); + for ($ii = 0; $ii < $failures->length; $ii++) { + $messages[] = trim($failures->item($ii)->nodeValue, " \n"); + } + + $user_data .= implode("\n", $messages)."\n"; + } + + // An errored test is one that had an unanticipated problem. e.g., an + // unchecked throwable, or a problem with an implementation of the + // test. + $errors = $testcase->getElementsByTagName("error"); + if ($errors->length > 0) { + $status = ArcanistUnitTestResult::RESULT_BROKEN; + $messages = array(); + for ($ii = 0; $ii < $errors->length; $ii++) { + $messages[] = trim($errors->item($ii)->nodeValue, " \n"); + } + + $user_data .= implode("\n", $messages)."\n"; + } + + $result = new ArcanistUnitTestResult(); + $result->setName($classname.".".$name); + $result->setResult($status); + $result->setDuration($time); + $result->setUserData($user_data); + + $results[] = $result; + } + + return $results; + } + +}