diff --git a/public/assets/js/build-plugins/phpunit.js b/public/assets/js/build-plugins/phpunit.js index 71495603..f5080077 100644 --- a/public/assets/js/build-plugins/phpunit.js +++ b/public/assets/js/build-plugins/phpunit.js @@ -33,6 +33,11 @@ var phpunitPlugin = ActiveBuild.UiPlugin.extend({ var input = $(ev.target); $('#phpunit-data tbody ' + input.data('target')).toggle(input.prop('checked')); }); + + $(document).on('click', '#phpunit-data button.trace', function() { + var $btn = $(this); + $($btn).replaceWith(self.buildTrace($btn.data('trace'))); + }); }, render: function() { @@ -69,7 +74,7 @@ var phpunitPlugin = ActiveBuild.UiPlugin.extend({ for (var i in tests) { var content = $(''), - message = $('
').appendTo(content), + message = $('
').appendTo(content), severity = tests[i].severity || (tests[i].pass ? 'success' : 'failed'); if (tests[i].message) { @@ -84,6 +89,13 @@ var phpunitPlugin = ActiveBuild.UiPlugin.extend({ content.append('
' + this.repr(tests[i].data) + '
'); } + if (tests[i].trace && tests[i].trace.length) { + var $traceBtn = $(''); + $traceBtn.data('trace', tests[i].trace); + content.append('Trace: '); + content.append($traceBtn); + } + $('').append(content).appendTo(tbody); counts[severity]++; @@ -141,6 +153,17 @@ var phpunitPlugin = ActiveBuild.UiPlugin.extend({ ''; } return '???'; + }, + + buildTrace: function(trace){ + var list = '
    '; + + trace.forEach(function(line){ + list += '
  1. ' + line + '
  2. '; + }); + list += '
'; + + return list; } }); diff --git a/src/PHPCensor/Builder.php b/src/PHPCensor/Builder.php index c46838d5..40280acf 100644 --- a/src/PHPCensor/Builder.php +++ b/src/PHPCensor/Builder.php @@ -106,7 +106,7 @@ class Builder implements LoggerAwareInterface public function __construct(Build $build, LoggerInterface $logger = null) { $this->build = $build; - $this->store = Factory::getStore('Build'); + $this->store = Factory::getStore('Build', 'PHPCensor'); $this->buildLogger = new BuildLogger($logger, $build); diff --git a/src/PHPCensor/Languages/lang.en.php b/src/PHPCensor/Languages/lang.en.php index b63abeb5..5b866c68 100644 --- a/src/PHPCensor/Languages/lang.en.php +++ b/src/PHPCensor/Languages/lang.en.php @@ -193,6 +193,7 @@ PHP Censor', 'phpcs_errors' => 'PHPCS Errors', 'phplint_errors' => 'Lint Errors', 'phpunit_errors' => 'PHPUnit Errors', + 'phpunit_fail_init' => 'Neither a configuration file nor a test directory found.', 'phpcpd_warnings' => 'PHP Copy/Paste Detector Warnings', 'phpdoccheck_warnings' => 'Missing Docblocks', 'issues' => 'Issues', diff --git a/src/PHPCensor/Languages/lang.es.php b/src/PHPCensor/Languages/lang.es.php index df0032aa..b8716f78 100644 --- a/src/PHPCensor/Languages/lang.es.php +++ b/src/PHPCensor/Languages/lang.es.php @@ -176,6 +176,7 @@ PHP Censor', 'phpcs_errors' => 'PHPCS Errors', 'phplint_errors' => 'Lint Errors', 'phpunit_errors' => 'PHPUnit Errors', + 'phpunit_fail_init' => 'No se encontro archivo o folder de pruevas.', 'phpdoccheck_warnings' => 'Docblocks faltantes', 'issues' => 'Incidencias', diff --git a/src/PHPCensor/Model/Base/ProjectBase.php b/src/PHPCensor/Model/Base/ProjectBase.php index 09096d01..e0eff10c 100644 --- a/src/PHPCensor/Model/Base/ProjectBase.php +++ b/src/PHPCensor/Model/Base/ProjectBase.php @@ -292,7 +292,7 @@ class ProjectBase extends Model */ public function getBuildConfig() { - $rtn = $this->data['build_config']; + $rtn = $this->data['build_config']; return $rtn; } diff --git a/src/PHPCensor/Model/Build.php b/src/PHPCensor/Model/Build.php index 2823ef23..58a7eaba 100644 --- a/src/PHPCensor/Model/Build.php +++ b/src/PHPCensor/Model/Build.php @@ -96,36 +96,25 @@ class Build extends BuildBase */ protected function handleConfig(Builder $builder, $buildPath) { - $build_config = null; + $build_config = $this->getProject()->getBuildConfig(); - // Try getting the project build config from the database: if (empty($build_config)) { - $build_config = $this->getProject()->getBuildConfig(); + if (file_exists($buildPath . '/.php-censor.yml')) { + $build_config = file_get_contents($buildPath . '/.php-censor.yml'); + } elseif (file_exists($buildPath . '/.phpci.yml')) { + $build_config = file_get_contents($buildPath . '/.phpci.yml'); + } elseif (file_exists($buildPath . '/phpci.yml')) { + $build_config = file_get_contents($buildPath . '/phpci.yml'); + } else { + $build_config = $this->getZeroConfigPlugins($builder); + } } - if (is_file($buildPath . '/.php-censor.yml')) { - $build_config = file_get_contents($buildPath . '/.php-censor.yml'); - } - - if (is_file($buildPath . '/.phpci.yml')) { - $build_config = file_get_contents($buildPath . '/.phpci.yml'); - } - - if (empty($build_config) && is_file($buildPath . '/phpci.yml')) { - $build_config = file_get_contents($buildPath . '/phpci.yml'); - } - - // Fall back to zero config plugins: - if (empty($build_config)) { - $build_config = $this->getZeroConfigPlugins($builder); - } - - if (is_string($build_config)) { - $yamlParser = new YamlParser(); - $build_config = $yamlParser->parse($build_config); - } + $yamlParser = new YamlParser(); + $build_config = $yamlParser->parse($build_config); $builder->setConfigArray($build_config); + return true; } diff --git a/src/PHPCensor/Plugin/Option/PhpUnitOptions.php b/src/PHPCensor/Plugin/Option/PhpUnitOptions.php new file mode 100644 index 00000000..50a684cd --- /dev/null +++ b/src/PHPCensor/Plugin/Option/PhpUnitOptions.php @@ -0,0 +1,273 @@ + + * @package PHPCI + * @subpackage Plugin + */ +class PhpUnitOptions +{ + protected $options; + protected $arguments = array(); + + public function __construct($options) + { + $this->options = $options; + } + + /** + * Remove a command argument + * + * @param $argumentName + * + * @return $this + */ + public function removeArgument($argumentName) + { + unset($this->arguments[$argumentName]); + return $this; + } + + /** + * Combine all the argument into a string for the phpunit command + * + * @return string + */ + public function buildArgumentString() + { + $argumentString = ''; + foreach ($this->getCommandArguments() as $argumentName => $argumentValues) { + $prefix = $argumentName[0] == '-' ? '' : '--'; + + if (!is_array($argumentValues)) { + $argumentValues = array($argumentValues); + } + + foreach ($argumentValues as $argValue) { + $postfix = ' '; + if (!empty($argValue)) { + $postfix = ' "' . $argValue . '" '; + } + $argumentString .= $prefix . $argumentName . $postfix; + } + } + + return $argumentString; + } + + /** + * Get all the command arguments + * + * @return string[] + */ + public function getCommandArguments() + { + /* + * Return the full list of arguments + */ + return $this->parseArguments()->arguments; + } + + /** + * Parse the arguments from the config options + * + * @return $this + */ + private function parseArguments() + { + if (empty($this->arguments)) { + /* + * Parse the arguments from the YML options file + */ + if (isset($this->options['args'])) { + $rawArgs = $this->options['args']; + if (is_array($rawArgs)) { + $this->arguments = $rawArgs; + } else { + /* + * Try to parse old arguments in a single string + */ + preg_match_all('@--([a-z\-]+)([\s=]+)?[\'"]?((?!--)[-\w/.,\\\]+)?[\'"]?@', (string)$rawArgs, $argsMatch); + + if (!empty($argsMatch) && sizeof($argsMatch) > 2) { + foreach ($argsMatch[1] as $index => $argName) { + $this->addArgument($argName, $argsMatch[3][$index]); + } + } + } + } + + /* + * Handles command aliases outside of the args option + */ + if (isset($this->options['coverage'])) { + $this->addArgument('coverage-html', $this->options['coverage']); + } + + /* + * Handles command aliases outside of the args option + */ + if (isset($this->options['config'])) { + $this->addArgument('configuration', $this->options['config']); + } + } + + return $this; + } + + /** + * Add an argument to the collection + * Note: adding argument before parsing the options will prevent the other options from been parsed. + * + * @param string $argumentName + * @param string $argumentValue + */ + public function addArgument($argumentName, $argumentValue) + { + if (isset($this->arguments[$argumentName])) { + if (!is_array($this->arguments[$argumentName])) { + // Convert existing argument values into an array + $this->arguments[$argumentName] = array($this->arguments[$argumentName]); + } + + // Appends the new argument to the list + $this->arguments[$argumentName][] = $argumentValue; + } else { + // Adds new argument + $this->arguments[$argumentName] = $argumentValue; + } + } + + /** + * Get the list of directory to run phpunit in + * + * @return string[] List of directories + */ + public function getDirectories() + { + $directories = $this->getOption('directory'); + + if (is_string($directories)) { + $directories = array($directories); + } else { + if (is_null($directories)) { + $directories = array(); + } + } + + return is_array($directories) ? $directories : array($directories); + } + + /** + * Get an option if defined + * + * @param $optionName + * + * @return string[]|string|null + */ + public function getOption($optionName) + { + if (isset($this->options[$optionName])) { + return $this->options[$optionName]; + } + + return null; + } + + /** + * Get the directory to execute the command from + * + * @return mixed|null + */ + public function getRunFrom() + { + return $this->getOption('run_from'); + } + + /** + * Ge the directory name where tests file reside + * + * @return string|null + */ + public function getTestsPath() + { + return $this->getOption('path'); + } + + /** + * Get the PHPUnit configuration from the options, or the optional path + * + * @param string $altPath + * + * @return string[] path of files + */ + public function getConfigFiles($altPath = null) + { + $configFiles = $this->getArgument('configuration'); + if (empty($configFiles) && $altPath) { + $configFile = self::findConfigFile($altPath); + if ($configFile) { + $configFiles[] = $configFile; + } + } + + return $configFiles; + } + + /** + * Get options for a given argument + * + * @param $argumentName + * + * @return string[] All the options for given argument + */ + public function getArgument($argumentName) + { + $this->parseArguments(); + + if (isset($this->arguments[$argumentName])) { + return is_array( + $this->arguments[$argumentName] + ) ? $this->arguments[$argumentName] : array($this->arguments[$argumentName]); + } + + return array(); + } + + /** + * Find a PHPUnit configuration file in a directory + * + * @param string $buildPath The path to configuration file + * + * @return null|string + */ + public static function findConfigFile($buildPath) + { + $files = array( + 'phpunit.xml', + 'phpunit.xml.dist', + 'tests/phpunit.xml', + 'tests/phpunit.xml.dist', + ); + + foreach ($files as $file) { + if (file_exists($buildPath . $file)) { + return $file; + } + } + + return null; + } +} diff --git a/src/PHPCensor/Plugin/PhpUnit.php b/src/PHPCensor/Plugin/PhpUnit.php index 444ffb9b..666ae0ff 100644 --- a/src/PHPCensor/Plugin/PhpUnit.php +++ b/src/PHPCensor/Plugin/PhpUnit.php @@ -1,4 +1,5 @@ -* @package PHPCI -* @subpackage Plugins -*/ + * PHP Unit Plugin - A rewrite of the original PHP Unit plugin + * + * @author Dan Cryer + * @author Pablo Tejada + * @package PHPCI + * @subpackage Plugins + */ class PhpUnit implements PHPCensor\Plugin, PHPCensor\ZeroConfigPlugin { - protected $args; protected $phpci; protected $build; + /** @var string[] Raw options from the PHPCI config file */ + protected $options = array(); + /** - * @var string|string[] $directory The directory (or array of dirs) to run PHPUnit on + * Standard Constructor + * $options['config'] Path to a PHPUnit XML configuration file. + * $options['run_from'] The directory where the phpunit command will run from when using 'config'. + * $options['coverage'] Value for the --coverage-html command line flag. + * $options['directory'] Optional directory or list of directories to run PHPUnit on. + * $options['args'] Command line args (in string format) to pass to PHP Unit + * + * @param Builder $phpci + * @param Build $build + * @param string[] $options */ - protected $directory; + public function __construct(Builder $phpci, Build $build, array $options = array()) + { + $this->phpci = $phpci; + $this->build = $build; + $this->options = new PhpUnitOptions($options); + } /** - * @var string $runFrom When running PHPUnit with an XML config, the command is run from this directory - */ - protected $runFrom; - - /** - * @var string, in cases where tests files are in a sub path of the /tests path, - * allows this path to be set in the config. - */ - protected $path; - - protected $coverage = ""; - - /** - * @var string|string[] $xmlConfigFile The path (or array of paths) of an xml config for PHPUnit - */ - protected $xmlConfigFile; - - /** - * Check if this plugin can be executed. - * @param $stage + * Check if the plugin can be executed without any configurations + * + * @param $stage * @param Builder $builder - * @param Build $build + * @param Build $build + * * @return bool */ public static function canExecute($stage, Builder $builder, Build $build) { - if ($stage == 'test' && !is_null(self::findConfigFile($builder->buildPath))) { + if ($stage == 'test' && !is_null(PhpUnitOptions::findConfigFile($build->getBuildPath()))) { return true; } @@ -66,185 +72,118 @@ class PhpUnit implements PHPCensor\Plugin, PHPCensor\ZeroConfigPlugin } /** - * Try and find the phpunit XML config file. - * @param $buildPath - * @return null|string + * Runs PHP Unit tests in a specified directory, optionally using specified config file(s). */ - public static function findConfigFile($buildPath) - { - if (file_exists($buildPath . 'phpunit.xml')) { - return 'phpunit.xml'; - } - - if (file_exists($buildPath . 'tests' . DIRECTORY_SEPARATOR . 'phpunit.xml')) { - return 'tests' . DIRECTORY_SEPARATOR . 'phpunit.xml'; - } - - if (file_exists($buildPath . 'phpunit.xml.dist')) { - return 'phpunit.xml.dist'; - } - - if (file_exists($buildPath . 'tests/phpunit.xml.dist')) { - return 'tests' . DIRECTORY_SEPARATOR . 'phpunit.xml.dist'; - } - - return null; - } - - /** - * Standard Constructor - * - * $options['directory'] Output Directory. Default: %BUILDPATH% - * $options['filename'] Phar Filename. Default: build.phar - * $options['regexp'] Regular Expression Filename Capture. Default: /\.php$/ - * $options['stub'] Stub Content. No Default Value - * - * @param Builder $phpci - * @param Build $build - * @param array $options - */ - public function __construct(Builder $phpci, Build $build, array $options = []) - { - $this->phpci = $phpci; - $this->build = $build; - - if (empty($options['config']) && empty($options['directory'])) { - $this->xmlConfigFile = self::findConfigFile($phpci->buildPath); - } - - if (isset($options['directory'])) { - $this->directory = $options['directory']; - } - - if (isset($options['config'])) { - $this->xmlConfigFile = $options['config']; - } - - if (isset($options['run_from'])) { - $this->runFrom = $options['run_from']; - } - - if (isset($options['args'])) { - $this->args = $this->phpci->interpolate($options['args']); - } - - if (isset($options['path'])) { - $this->path = $options['path']; - } - - if (isset($options['coverage'])) { - $this->coverage = ' --coverage-html ' . $this->phpci->interpolate($options['coverage']) . ' '; - } - - $this->phpci->logDebug('Plugin options: ' . json_encode($options)); - } - - /** - * Runs PHP Unit tests in a specified directory, optionally using specified config file(s). - */ public function execute() { - if (empty($this->xmlConfigFile) && empty($this->directory)) { - $this->phpci->logFailure('Neither configuration file nor test directory found.'); + $xmlConfigFiles = $this->options->getConfigFiles($this->build->getBuildPath()); + $directories = $this->options->getDirectories(); + if (empty($xmlConfigFiles) && empty($directories)) { + $this->phpci->logFailure(Lang::get('phpunit_fail_init')); return false; } - $success = true; + $success = array(); - $this->phpci->logExecOutput(false); - - // Run any config files first. This can be either a single value or an array. - if ($this->xmlConfigFile !== null) { - $success &= $this->runConfigFile($this->xmlConfigFile); + // Run any directories + if (!empty($directories)) { + foreach ($directories as $directory) { + $success[] = $this->runDir($directory); + } + } else { + // Run any config files + if (!empty($xmlConfigFiles)) { + foreach ($xmlConfigFiles as $configFile) { + $success[] = $this->runConfigFile($configFile); + } + } } - // Run any dirs next. Again this can be either a single value or an array. - if ($this->directory !== null) { - $success &= $this->runDir($this->directory); - } + return !in_array(false, $success); + } - $tapString = $this->phpci->getLastOutput(); - $tapString = mb_convert_encoding($tapString, "UTF-8", "ISO-8859-1"); + /** + * Run the PHPUnit tests in a specific directory or array of directories. + * + * @param $directory + * + * @return bool|mixed + */ + protected function runDir($directory) + { + $options = clone $this->options; - try { - $tapParser = new TapParser($tapString); - $output = $tapParser->parse(); - } catch (\Exception $ex) { - $this->phpci->logFailure($tapString); - throw $ex; - } + // Save the results into a json file + $jsonFile = tempnam(RUNTIME_DIR, 'jLog_'); + $options->addArgument('log-json', $jsonFile); - $failures = $tapParser->getTotalFailures(); + // Removes any current configurations files + $options->removeArgument('configuration'); - $this->build->storeMeta('phpunit-errors', $failures); - $this->build->storeMeta('phpunit-data', $output); + $arguments = $this->phpci->interpolate($options->buildArgumentString()); + $cmd = $this->phpci->findBinary('phpunit') . ' %s "%s"'; + $success = $this->phpci->executeCommand($cmd, $arguments, $directory); - $this->phpci->logExecOutput(true); + $this->processResults($jsonFile); return $success; } /** * Run the tests defined in a PHPUnit config file. - * @param $configPath + * + * @param $configFile + * * @return bool|mixed */ - protected function runConfigFile($configPath) + protected function runConfigFile($configFile) { - if (is_array($configPath)) { - return $this->recurseArg($configPath, [$this, "runConfigFile"]); - } else { - if ($this->runFrom) { - $curdir = getcwd(); - chdir($this->phpci->buildPath . DIRECTORY_SEPARATOR . $this->runFrom); - } + $options = clone $this->options; + $buildPath = $this->build->getBuildPath() . DIRECTORY_SEPARATOR; - $phpunit = $this->phpci->findBinary('phpunit'); + // Save the results into a json file + $jsonFile = tempnam(RUNTIME_DIR, 'jLog_'); + $options->addArgument('log-json', $jsonFile); - $cmd = $phpunit . ' --tap %s -c "%s" ' . $this->coverage . $this->path; - $success = $this->phpci->executeCommand($cmd, $this->args, $this->phpci->buildPath . $configPath); + // Removes any current configurations files + $options->removeArgument('configuration'); + // Only the add the configuration file been passed + $options->addArgument('configuration', $buildPath . $configFile); - if ($this->runFrom) { - chdir($curdir); - } + $arguments = $this->phpci->interpolate($options->buildArgumentString()); + $cmd = $this->phpci->findBinary('phpunit') . ' %s %s'; + $success = $this->phpci->executeCommand($cmd, $arguments, $options->getTestsPath()); - return $success; - } - } + $this->processResults($jsonFile); - /** - * Run the PHPUnit tests in a specific directory or array of directories. - * @param $directory - * @return bool|mixed - */ - protected function runDir($directory) - { - if (is_array($directory)) { - return $this->recurseArg($directory, [$this, "runDir"]); - } else { - $curdir = getcwd(); - chdir($this->phpci->buildPath); - - $phpunit = $this->phpci->findBinary('phpunit'); - - $cmd = $phpunit . ' --tap %s "%s"'; - $success = $this->phpci->executeCommand($cmd, $this->args, $this->phpci->buildPath . $directory); - chdir($curdir); - return $success; - } - } - - /** - * @param $array - * @param $callable - * @return bool|mixed - */ - protected function recurseArg($array, $callable) - { - $success = true; - foreach ($array as $subItem) { - $success &= call_user_func($callable, $subItem); - } return $success; } + + /** + * Saves the test results + * + * @param string $jsonFile + * + * @throws \Exception If the failed to parse the JSON file + */ + protected function processResults($jsonFile) + { + var_dump('fuck!'); + if (file_exists($jsonFile)) { + $parser = new PhpUnitResult($jsonFile, $this->build->getBuildPath()); + + $this->build->storeMeta('phpunit-data', $parser->parse()->getResults()); + $this->build->storeMeta('phpunit-errors', $parser->getFailures()); + + foreach ($parser->getErrors() as $error) { + $severity = $error['severity'] == $parser::SEVERITY_ERROR ? BuildError::SEVERITY_CRITICAL : BuildError::SEVERITY_HIGH; + $this->build->reportError( + $this->phpci, 'php_unit', $error['message'], $severity, $error['file'], $error['line'] + ); + } + @unlink($jsonFile); + } else { + throw new \Exception('JSON output file does not exist: ' . $jsonFile); + } + } } diff --git a/src/PHPCensor/Plugin/Util/PhpUnitResult.php b/src/PHPCensor/Plugin/Util/PhpUnitResult.php new file mode 100644 index 00000000..a8264e21 --- /dev/null +++ b/src/PHPCensor/Plugin/Util/PhpUnitResult.php @@ -0,0 +1,235 @@ + + * @package PHPCI + * @subpackage Plugin + */ +class PhpUnitResult +{ + const EVENT_TEST = 'test'; + const EVENT_TEST_START = 'testStart'; + const EVENT_SUITE_START = 'suiteStart'; + + const SEVERITY_PASS = 'success'; + const SEVERITY_FAIL = 'fail'; + const SEVERITY_ERROR = 'error'; + const SEVERITY_SKIPPED = 'skipped'; + + protected $options; + protected $arguments = array(); + protected $results; + protected $failures = 0; + protected $errors = array(); + + public function __construct($outputFile, $buildPath = '') + { + $this->outputFile = $outputFile; + $this->buildPath = $buildPath; + } + + /** + * Parse the results + * + * @return $this + * @throws \Exception If fails to parse the output + */ + public function parse() + { + $rawResults = file_get_contents($this->outputFile); + if (empty($rawResults)) { + throw new \Exception('No test executed.'); + } + if ($rawResults[0] == '{') { + $fixedJson = '[' . str_replace('}{', '},{', $rawResults) . ']'; + $events = json_decode($fixedJson, true); + } else { + $events = json_decode($rawResults, true); + } + + // Reset the parsing variables + $this->results = array(); + $this->errors = array(); + $this->failures = 0; + + if (is_array($events)) { + foreach ($events as $event) { + if ($event['event'] == self::EVENT_TEST) { + $this->results[] = $this->parseEvent($event); + } + } + } else { + throw new \Exception('Failed to parse the JSON output.'); + } + + return $this; + } + + /** + * Parse a test event + * + * @param array $event + * + * @return string[] + */ + protected function parseEvent($event) + { + list($pass, $severity) = $this->getStatus($event); + + $data = array( + 'pass' => $pass, + 'severity' => $severity, + 'message' => $this->buildMessage($event), + 'trace' => $pass ? array() : $this->buildTrace($event), + 'output' => $event['output'], + ); + + if (!$pass) { + $this->failures++; + $this->addError($data, $event); + } + + return $data; + } + + /** + * Build the status of the event + * + * @param $event + * + * @return mixed[bool,string] - The pass and severity flags + * @throws \Exception + */ + protected function getStatus($event) + { + $status = $event['status']; + switch ($status) { + case 'fail': + $pass = false; + $severity = self::SEVERITY_FAIL; + break; + case 'error': + if (strpos($event['message'], 'Skipped') === 0 || strpos($event['message'], 'Incomplete') === 0) { + $pass = true; + $severity = self::SEVERITY_SKIPPED; + } else { + $pass = false; + $severity = self::SEVERITY_ERROR; + } + break; + case 'pass': + $pass = true; + $severity = self::SEVERITY_PASS; + break; + case 'warning': + $pass = true; + $severity = self::SEVERITY_PASS; + break; + default: + throw new \Exception("Unexpected PHPUnit test status: {$status}"); + break; + } + + return array($pass, $severity); + } + + /** + * Build the message string for an event + * + * @param array $event + * + * @return string + */ + protected function buildMessage($event) + { + $message = $event['test']; + + if ($event['message']) { + $message .= PHP_EOL . $event ['message']; + } + + return $message; + } + + /** + * Build a string base trace of the failure + * + * @param array $event + * + * @return string[] + */ + protected function buildTrace($event) + { + $formattedTrace = array(); + + if (!empty($event['trace'])) { + foreach ($event['trace'] as $step){ + $line = str_replace($this->buildPath, '', $step['file']) . ':' . $step['line']; + $formattedTrace[] = $line; + } + } + + return $formattedTrace; + } + + /** + * Saves additional info for a failing test + * + * @param array $data + * @param array $event + */ + protected function addError($data, $event) + { + $firstTrace = end($event['trace']); + reset($event['trace']); + + $this->errors[] = array( + 'message' => $data['message'], + 'severity' => $data['severity'], + 'file' => str_replace($this->buildPath, '', $firstTrace['file']), + 'line' => $firstTrace['line'], + ); + } + + /** + * Get the parse results + * + * @return string[] + */ + public function getResults() + { + return $this->results; + } + + /** + * Get the total number of failing tests + * + * @return int + */ + public function getFailures() + { + return $this->failures; + } + + /** + * Get the tests with failing status + * + * @return string[] + */ + public function getErrors() + { + return $this->errors; + } +} diff --git a/src/PHPCensor/View/Build/errors.phtml b/src/PHPCensor/View/Build/errors.phtml index 55d1ae7b..8a383c92 100644 --- a/src/PHPCensor/View/Build/errors.phtml +++ b/src/PHPCensor/View/Build/errors.phtml @@ -3,7 +3,7 @@ use PHPCensor\Helper\Lang; $linkTemplate = $build->getFileLinkTemplate(); -/** @var \PHPCensor\Model\BuildError $error */ +/** @var \PHPCI\Model\BuildError[] $errors */ foreach ($errors as $error): $link = str_replace('{FILE}', $error->getFile(), $linkTemplate); @@ -30,8 +30,8 @@ foreach ($errors as $error): ?> - getMessage(); ?> + getMessage(); ?> - \ No newline at end of file + diff --git a/src/PHPCensor/View/layout.phtml b/src/PHPCensor/View/layout.phtml index 043af1f4..40b6cba6 100644 --- a/src/PHPCensor/View/layout.phtml +++ b/src/PHPCensor/View/layout.phtml @@ -17,6 +17,11 @@ +