diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -170,6 +170,7 @@ 'CSharpToolsTestEngine' => 'unit/engine/CSharpToolsTestEngine.php', 'ComprehensiveLintEngine' => 'lint/engine/ComprehensiveLintEngine.php', 'ExampleLintEngine' => 'lint/engine/ExampleLintEngine.php', + 'GenericXUnitTestEngine' => 'unit/engine/GenericXUnitTestEngine.php', 'GoTestResultParser' => 'unit/engine/GoTestResultParser.php', 'GoTestResultParserTestCase' => 'unit/engine/__tests__/GoTestResultParserTestCase.php', 'NoseTestEngine' => 'unit/engine/NoseTestEngine.php', @@ -313,6 +314,7 @@ 'CSharpToolsTestEngine' => 'XUnitTestEngine', 'ComprehensiveLintEngine' => 'ArcanistLintEngine', 'ExampleLintEngine' => 'ArcanistLintEngine', + 'GenericXUnitTestEngine' => 'ArcanistBaseUnitTestEngine', 'GoTestResultParser' => 'ArcanistBaseTestResultParser', 'GoTestResultParserTestCase' => 'ArcanistTestCase', 'NoseTestEngine' => 'ArcanistBaseUnitTestEngine', diff --git a/src/unit/engine/GenericXUnitTestEngine.php b/src/unit/engine/GenericXUnitTestEngine.php new file mode 100644 --- /dev/null +++ b/src/unit/engine/GenericXUnitTestEngine.php @@ -0,0 +1,95 @@ +runTests(); + + return $results; + } + + private function runTests() { + $root = $this->getWorkingCopy()->getProjectRoot(); + $script = $this->getConfiguredScript(); + $path = $this->getConfiguredTestResultPath(); + + foreach (glob($path."/*.xml") as $filename) { + // Remove existing files so we cannot report old results + $this->unlink($filename); + } + + $future = new ExecFuture('%C %s', $script, $path); + $future->setCWD($root); + try { + $future->resolvex(); + } catch(CommandException $exc) { + if ($exc->getError() != 0) { + throw $exc; + } + } + + return $this->parseTestResults($path); + } + + public function parseTestResults($path) { + $results = array(); + + foreach (glob($path."/*.xml") as $filename) { + $parser = new ArcanistXUnitTestResultParser(); + $results[] = $parser->parseTestResults( + Filesystem::readFile($filename)); + } + + return array_mergev($results); + } + + private function unlink($filepath) { + if (file_exists($filepath)) { + unlink($filepath); + } + } + + /** + * Load, validate, and return the "script" configuration. + * + * @return string The shell command fragment to use to run the unit tests. + * + * @task config + */ + private function getConfiguredScript() { + $key = 'unit.genericxunit.script'; + $config = $this->getConfigurationManager() + ->getConfigFromAnySource($key); + + if (!$config) { + throw new ArcanistUsageException( + "GenericXunitTestEngine: ". + "You must configure '{$key}' to point to a script to execute."); + } + + // NOTE: No additional validation since the "script" can be some random + // shell command and/or include flags, so it does not need to point to some + // file on disk. + + return $config; + } + + private function getConfiguredTestResultPath() { + $key = 'unit.genericxunit.result_path'; + $config = $this->getConfigurationManager() + ->getConfigFromAnySource($key); + + if (!$config) { + throw new ArcanistUsageException( + "GenericXunitTestEngine: ". + "You must configure '{$key}' to point to a path."); + } + + return $config; + } +}