array( 'param' => 'classname', 'help' => "Override configured unit engine for this project." ), '*' => 'paths', ); } public function requiresWorkingCopy() { return true; } public function requiresRepositoryAPI() { return true; } public function run() { $working_copy = $this->getWorkingCopy(); $engine_class = $this->getArgument( 'engine', $working_copy->getConfig('unit_engine')); if (!$engine_class) { throw new ArcanistNoEngineException( "No unit test engine is configured for this project. Edit .arcconfig ". "to specify a unit test engine."); } $repository_api = $this->getRepositoryAPI(); if ($this->getArgument('paths')) { // TODO: deal with git stuff $paths = $this->getArgument('paths'); } else { $paths = $repository_api->getWorkingCopyStatus(); // TODO: clean this up foreach ($paths as $path => $mask) { if ($mask & ArcanistRepositoryAPI::FLAG_UNTRACKED) { unset($paths[$path]); } } $paths = array_keys($paths); } PhutilSymbolLoader::loadClass($engine_class); $this->engine = newv($engine_class, array()); $this->engine->setWorkingCopy($working_copy); $this->engine->setPaths($paths); $this->engine->setArguments($this->getPassthruArgumentsAsMap('unit')); // Enable possible async tests only for 'arc diff' not 'arc unit' if ($this->getParentWorkflow()) { $this->engine->setEnableAsyncTests(true); } else { $this->engine->setEnableAsyncTests(false); } $results = $this->engine->run(); $status_codes = array( ArcanistUnitTestResult::RESULT_PASS => phutil_console_format( '** PASS **'), ArcanistUnitTestResult::RESULT_FAIL => phutil_console_format( '** FAIL **'), ArcanistUnitTestResult::RESULT_SKIP => phutil_console_format( '** SKIP **'), ArcanistUnitTestResult::RESULT_BROKEN => phutil_console_format( '** BROKEN **'), ArcanistUnitTestResult::RESULT_UNSOUND => phutil_console_format( '** UNSOUND **'), ArcanistUnitTestResult::RESULT_POSTPONED => phutil_console_format( '** POSTPONED **'), ); $unresolved = array(); $postponed_count = 0; foreach ($results as $result) { $result_code = $result->getResult(); if ($result_code == ArcanistUnitTestResult::RESULT_POSTPONED) { $postponed_count++; $unresolved[] = $result; } else { if ($this->engine->shouldEchoTestResults()) { echo ' '.$status_codes[$result_code].' '.$result->getName()."\n"; } if ($result_code != ArcanistUnitTestResult::RESULT_PASS) { if ($this->engine->shouldEchoTestResults()) { echo $result->getUserData()."\n"; } $unresolved[] = $result; } } } if ($postponed_count) { echo sprintf("%s %d %s\n", $status_codes[ArcanistUnitTestResult::RESULT_POSTPONED], $postponed_count, ($postponed_count > 1)?'tests':'test'); } $this->unresolvedTests = $unresolved; $overall_result = self::RESULT_OKAY; foreach ($results as $result) { $result_code = $result->getResult(); if ($result_code == ArcanistUnitTestResult::RESULT_FAIL || $result_code == ArcanistUnitTestResult::RESULT_BROKEN) { $overall_result = self::RESULT_FAIL; break; } else if ($result_code == ArcanistUnitTestResult::RESULT_UNSOUND) { $overall_result = self::RESULT_UNSOUND; } else if ($result_code == ArcanistUnitTestResult::RESULT_POSTPONED && $overall_result != self::RESULT_UNSOUND) { $overall_result = self::RESULT_POSTPONED; } } return $overall_result; } public function getUnresolvedTests() { return $this->unresolvedTests; } public function setDifferentialDiffID($id) { if ($this->engine) { $this->engine->setDifferentialDiffID($id); } } }