Changeset View
Changeset View
Standalone View
Standalone View
src/unit/engine/PhpunitTestEngine.php
<?php | <?php | ||||
/** | /** | ||||
* PHPUnit wrapper. | * PHPUnit wrapper. | ||||
*/ | */ | ||||
final class PhpunitTestEngine extends ArcanistUnitTestEngine { | final class PhpunitTestEngine extends ArcanistUnitTestEngine { | ||||
private $configFile; | private $configFile; | ||||
private $phpunitBinary = 'phpunit'; | private $phpunitBinary = 'phpunit'; | ||||
private $affectedTests; | private $affectedTests; | ||||
private $projectRoot; | private $projectRoot; | ||||
private $flags = []; | |||||
public function getEngineConfigurationName() { | |||||
return 'phpunit'; | |||||
} | |||||
public function run() { | public function run() { | ||||
$this->projectRoot = $this->getWorkingCopy()->getProjectRoot(); | $this->projectRoot = $this->getWorkingCopy()->getProjectRoot(); | ||||
$this->affectedTests = array(); | $this->affectedTests = array(); | ||||
foreach ($this->getPaths() as $path) { | foreach ($this->getPaths() as $path) { | ||||
$path = Filesystem::resolvePath($path, $this->projectRoot); | $path = Filesystem::resolvePath($path, $this->projectRoot); | ||||
Show All 20 Lines | foreach ($this->getPaths() as $path) { | ||||
} | } | ||||
} | } | ||||
if (empty($this->affectedTests)) { | if (empty($this->affectedTests)) { | ||||
throw new ArcanistNoEffectException(pht('No tests to run.')); | throw new ArcanistNoEffectException(pht('No tests to run.')); | ||||
} | } | ||||
$this->prepareConfigFile(); | $this->prepareConfig(); | ||||
if (!Filesystem::binaryExists($this->phpunitBinary)) { | |||||
throw new Exception(pht( | |||||
"PHPUnit binary not found at '%s'", | |||||
$this->phpunitBinary)); | |||||
} | |||||
$futures = array(); | $futures = array(); | ||||
$tmpfiles = array(); | $tmpfiles = array(); | ||||
$all_flags = implode(' ', $this->flags); | |||||
foreach ($this->affectedTests as $class_path => $test_path) { | foreach ($this->affectedTests as $class_path => $test_path) { | ||||
if (!Filesystem::pathExists($test_path)) { | if (!Filesystem::pathExists($test_path)) { | ||||
continue; | continue; | ||||
} | } | ||||
$json_tmp = new TempFile(); | $json_tmp = new TempFile(); | ||||
$json = csprintf('--log-json %s', $json_tmp); | |||||
$clover_tmp = null; | $clover_tmp = null; | ||||
$clover = null; | $clover = null; | ||||
if ($this->getEnableCoverage() !== false) { | if ($this->getEnableCoverage() !== false) { | ||||
$clover_tmp = new TempFile(); | $clover_tmp = new TempFile(); | ||||
$clover = csprintf('--coverage-clover %s', $clover_tmp); | $clover = csprintf('--coverage-clover %s', $clover_tmp); | ||||
} | } | ||||
$config = $this->configFile ? csprintf('-c %s', $this->configFile) : null; | $futures[$test_path] = new ExecFuture('%C %C %C %C %s', | ||||
$this->phpunitBinary, $all_flags, $json, $clover, $test_path); | |||||
$stderr = '-d display_errors=stderr'; | |||||
$futures[$test_path] = new ExecFuture('%C %C %C --log-json %s %C %s', | |||||
$this->phpunitBinary, $config, $stderr, $json_tmp, $clover, $test_path); | |||||
$tmpfiles[$test_path] = array( | $tmpfiles[$test_path] = array( | ||||
'json' => $json_tmp, | 'json' => $json_tmp, | ||||
'clover' => $clover_tmp, | 'clover' => $clover_tmp, | ||||
); | ); | ||||
} | } | ||||
$results = array(); | $results = array(); | ||||
$futures = id(new FutureIterator($futures)) | $futures = id(new FutureIterator($futures)) | ||||
▲ Show 20 Lines • Show All 166 Lines • ▼ Show 20 Lines | public static function getSearchLocationsForTests($path) { | ||||
foreach ($try_directories as $parts) { | foreach ($try_directories as $parts) { | ||||
$results[implode(DIRECTORY_SEPARATOR, $parts).DIRECTORY_SEPARATOR] = true; | $results[implode(DIRECTORY_SEPARATOR, $parts).DIRECTORY_SEPARATOR] = true; | ||||
} | } | ||||
return array_keys($results); | return array_keys($results); | ||||
} | } | ||||
/** | /** | ||||
* Tries to find and update phpunit configuration file based on | * Apply configuration values from all possible sources | ||||
* `phpunit_config` option in `.arcconfig`. | */ | ||||
private function prepareConfig() { | |||||
// .arcconfig, .arcrc, etc. | |||||
$manager = $this->getConfigurationManager(); | |||||
if ($manager) { | |||||
$this->prepareConfigFromManager($manager); | |||||
} | |||||
// .arcunit | |||||
foreach ($this->getOption('flags', array()) as $k => $v) { | |||||
$v = str_replace('$ROOT', $this->projectRoot, $v); | |||||
$this->flags[] = (string)csprintf('%C %s', $k, $v); | |||||
} | |||||
if ($bin = $this->getOption('binary')) { | |||||
$this->setBinaryPath($bin); | |||||
} | |||||
// Try to avoid errors in tests from being suppressed (TODO: leave this as | |||||
Lint: TODO Comment: This comment has a TODO. | |||||
// an exercise to the person configuring the engine?) | |||||
$this->flags[] = '-d display_errors=stderr'; | |||||
} | |||||
/** | |||||
* Apply configuration from working copy configs. Eventually this may be | |||||
* deprecated in favor of `.arcunit`. | |||||
*/ | */ | ||||
private function prepareConfigFile() { | private function prepareConfigFromManager( | ||||
ArcanistConfigurationManager $manager) { | |||||
$project_root = $this->projectRoot.DIRECTORY_SEPARATOR; | $project_root = $this->projectRoot.DIRECTORY_SEPARATOR; | ||||
$config = $this->getConfigurationManager()->getConfigFromAnySource( | $config = $manager->getConfigFromAnySource( | ||||
'phpunit_config'); | 'phpunit_config'); | ||||
if ($config) { | if ($config) { | ||||
if (Filesystem::pathExists($project_root.$config)) { | if (Filesystem::pathExists($project_root.$config)) { | ||||
$this->configFile = $project_root.$config; | $this->flags[] = (string)csprintf('%C %s', | ||||
'--configuration', $project_root.$config); | |||||
} else { | } else { | ||||
throw new Exception( | throw new Exception( | ||||
pht( | pht( | ||||
'PHPUnit configuration file was not found in %s', | 'PHPUnit configuration file was not found in %s', | ||||
$project_root.$config)); | $project_root.$config)); | ||||
} | } | ||||
} | } | ||||
$bin = $this->getConfigurationManager()->getConfigFromAnySource( | $bin = $manager->getConfigFromAnySource( | ||||
'unit.phpunit.binary'); | 'unit.phpunit.binary'); | ||||
if ($bin) { | if ($bin) { | ||||
$this->setBinaryPath($bin); | |||||
} | |||||
} | |||||
public function getEngineOptions() { | |||||
return array( | |||||
'flags' => 'optional map<string, string>', | |||||
'binary' => 'optional string', | |||||
); | |||||
} | |||||
private function setBinaryPath($bin) { | |||||
// Try exactly as-is | |||||
if (Filesystem::binaryExists($bin)) { | if (Filesystem::binaryExists($bin)) { | ||||
$this->phpunitBinary = $bin; | $this->phpunitBinary = $bin; | ||||
} else { | } else { | ||||
$this->phpunitBinary = Filesystem::resolvePath($bin, $project_root); | // This may resolve wrong, but we check before run that the binary exists. | ||||
} | // It's done there instead of here so the default value is also checked. | ||||
$this->phpunitBinary = Filesystem::resolvePath($bin, $this->projectRoot); | |||||
} | } | ||||
return $this; | |||||
} | } | ||||
} | } |
This comment has a TODO.