/** * Runs the test case and collects the results in a TestResult object. * If no TestResult object is passed a new one will be created. * * @param PHPUnit_Framework_TestResult $result * @return PHPUnit_Framework_TestResult * @throws InvalidArgumentException */ public function run(PHPUnit_Framework_TestResult $result = NULL) { if ($result === NULL) { $result = $this->createResult(); } $this->setExpectedExceptionFromAnnotation(); $this->setUseErrorHandlerFromAnnotation(); $this->setUseOutputBufferingFromAnnotation(); if ($this->useErrorHandler !== NULL) { $oldErrorHandlerSetting = $result->getConvertErrorsToExceptions(); $result->convertErrorsToExceptions($this->useErrorHandler); } $this->result = $result; if (!empty($this->dependencies) && !$this->inIsolation) { $className = get_class($this); $passed = $this->result->passed(); $passedKeys = array_keys($passed); $numKeys = count($passedKeys); for ($i = 0; $i < $numKeys; $i++) { $pos = strpos($passedKeys[$i], ' with data set'); if ($pos !== FALSE) { $passedKeys[$i] = substr($passedKeys[$i], 0, $pos); } } $passedKeys = array_flip(array_unique($passedKeys)); foreach ($this->dependencies as $dependency) { if (strpos($dependency, '::') === FALSE) { $dependency = $className . '::' . $dependency; } if (!isset($passedKeys[$dependency])) { $result->addError($this, new PHPUnit_Framework_SkippedTestError(sprintf('This test depends on "%s" to pass.', $dependency)), 0); return; } else { if (isset($passed[$dependency])) { $this->dependencyInput[] = $passed[$dependency]; } else { $this->dependencyInput[] = NULL; } } } } if ($this->runTestInSeparateProcess === TRUE && $this->inIsolation !== TRUE && !$this instanceof PHPUnit_Extensions_SeleniumTestCase && !$this instanceof PHPUnit_Extensions_PhptTestCase) { $class = new ReflectionClass($this); $collectCodeCoverageInformation = $result->getCollectCodeCoverageInformation(); $template = new PHPUnit_Util_Template(sprintf('%s%sProcess%sTestCaseMethod.tpl', dirname(__FILE__), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)); $template->setVar(array('filename' => $class->getFileName(), 'className' => $class->getName(), 'methodName' => $this->name, 'data' => addcslashes(serialize($this->data), "'"), 'dependencyInput' => addcslashes(serialize($this->dependencyInput), "'"), 'dataName' => $this->dataName, 'collectCodeCoverageInformation' => $collectCodeCoverageInformation ? 'TRUE' : 'FALSE', 'included_files' => $this->preserveGlobalState ? PHPUnit_Util_GlobalState::getIncludedFilesAsString() : '', 'constants' => $this->preserveGlobalState ? PHPUnit_Util_GlobalState::getConstantsAsString() : '', 'globals' => $this->preserveGlobalState ? PHPUnit_Util_GlobalState::getGlobalsAsString() : '', 'include_path' => addslashes(get_include_path()))); $this->prepareTemplate($template); $job = $template->render(); $result->startTest($this); $jobResult = PHPUnit_Util_PHP::runJob($job); if (!empty($jobResult['stderr'])) { $time = 0; $result->addError($this, new RuntimeException(trim($jobResult['stderr'])), $time); } else { $childResult = @unserialize($jobResult['stdout']); if ($childResult !== FALSE) { if (!empty($childResult['output'])) { print $childResult['output']; } $this->testResult = $childResult['testResult']; $this->numAssertions = $childResult['numAssertions']; $childResult = $childResult['result']; if ($collectCodeCoverageInformation) { $codeCoverageInformation = $childResult->getRawCodeCoverageInformation(); $result->appendCodeCoverageInformation($this, $codeCoverageInformation[0]['data']); } $time = $childResult->time(); $notImplemented = $childResult->notImplemented(); $skipped = $childResult->skipped(); $errors = $childResult->errors(); $failures = $childResult->failures(); if (!empty($notImplemented)) { $result->addError($this, $notImplemented[0]->thrownException(), $time); } else { if (!empty($skipped)) { $result->addError($this, $skipped[0]->thrownException(), $time); } else { if (!empty($errors)) { $result->addError($this, $errors[0]->thrownException(), $time); } else { if (!empty($failures)) { $result->addFailure($this, $failures[0]->thrownException(), $time); } } } } } else { $time = 0; $result->addError($this, new RuntimeException(trim($jobResult['stdout'])), $time); } } $result->endTest($this, $time); } else { $result->run($this); } if ($this->useErrorHandler !== NULL) { $result->convertErrorsToExceptions($oldErrorHandlerSetting); } $this->result = NULL; return $result; }
/** * Returns the cached result of date('D M j G:i:s T Y'). * * @return string * @since Method available since Release 3.0.1 */ public static function getDate() { if (self::$date == '') { self::$date = date('D M j G:i:s T Y'); } return self::$date; }
/** * @param PHPUnit_Util_Template $template * @param string $title * @param string $charset */ protected function setTemplateVars(PHPUnit_Util_Template $template, $title, $charset) { $template->setVar(array('title' => $title, 'charset' => $charset, 'link' => $this->getLink(TRUE), 'num_executable_lines' => $this->getNumExecutableLines(), 'num_executed_lines' => $this->getNumExecutedLines(), 'lines_executed_percent' => $this->getLineExecutedPercent(), 'date' => $template->getDate(), 'phpunit_version' => PHPUnit_Runner_Version::id(), 'xdebug_version' => phpversion('xdebug'), 'php_version' => PHP_VERSION)); }
/** * @param PHPUnit_Util_Template $template * @param string $title * @access public */ protected function setTemplateVars(PHPUnit_Util_Template $template, $title) { $template->setVar(array('title', 'link', 'date', 'phpunit_version', 'xdebug_version'), array($title, $this->getLink(TRUE), $template->getDate(), PHPUnit_Runner_Version::id(), phpversion('xdebug'))); }
/** * Renders this node. * * @param string $target * @param string $title * @param string $charset * @param boolean $highlight * @param integer $lowUpperBound * @param integer $highLowerBound * @access public */ public function render($target, $title, $charset = 'ISO-8859-1', $highlight = FALSE, $lowUpperBound = 35, $highLowerBound = 70) { if ($this->yui) { $template = new PHPUnit_Util_Template(PHPUnit_Util_Report::$templatePath . 'file.html'); $yuiTemplate = new PHPUnit_Util_Template(PHPUnit_Util_Report::$templatePath . 'yui_item.js'); } else { $template = new PHPUnit_Util_Template(PHPUnit_Util_Report::$templatePath . 'file_no_yui.html'); } $i = 1; $lines = ''; $ignore = FALSE; foreach ($this->codeLines as $line) { if (strpos($line, '@codeCoverageIgnore') !== FALSE) { if (strpos($line, '@codeCoverageIgnoreStart') !== FALSE) { $ignore = TRUE; } else { if (strpos($line, '@codeCoverageIgnoreEnd') !== FALSE) { $ignore = FALSE; } } } $css = ''; if (!$ignore && isset($this->executedLines[$i])) { $count = ''; // Array: Line is executable and was executed. // count(Array) = Number of tests that hit this line. if (is_array($this->executedLines[$i])) { $color = 'lineCov'; $numTests = count($this->executedLines[$i]); $count = sprintf('%8d', $numTests); if ($this->yui) { $buffer = ''; foreach ($this->executedLines[$i] as $test) { if (!isset($test->__liHtml)) { $test->__liHtml = ''; if ($test instanceof PHPUnit_Framework_SelfDescribing) { $testName = $test->toString(); if ($test instanceof PHPUnit_Framework_TestCase) { switch ($test->getStatus()) { case PHPUnit_Runner_BaseTestRunner::STATUS_PASSED: $testCSS = ' class=\\"testPassed\\"'; break; case PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE: $testCSS = ' class=\\"testFailure\\"'; break; case PHPUnit_Runner_BaseTestRunner::STATUS_ERROR: $testCSS = ' class=\\"testError\\"'; break; case PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE: case PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED: $testCSS = ' class=\\"testIncomplete\\"'; break; default: $testCSS = ''; } } } $test->__liHtml .= sprintf('<li%s>%s</li>', $testCSS, $testName); } $buffer .= $test->__liHtml; } if ($numTests > 1) { $header = $numTests . ' tests cover'; } else { $header = '1 test covers'; } $header .= ' line ' . $i; $yuiTemplate->setVar(array('line' => $i, 'header' => $header, 'tests' => $buffer), FALSE); $this->yuiPanelJS .= $yuiTemplate->render(); } } else { if ($this->executedLines[$i] == -1) { $color = 'lineNoCov'; $count = sprintf('%8d', 0); } else { $color = 'lineDeadCode'; $count = ' '; } } $css = sprintf('<span class="%s"> %s : ', $color, $count); } $fillup = array_shift($this->codeLinesFillup); if ($fillup > 0) { $line .= str_repeat(' ', $fillup); } $lines .= sprintf('<span class="lineNum" id="container%d"><a name="%d"></a><a href="#%d" id="line%d">%8d</a> </span>%s%s%s' . "\n", $i, $i, $i, $i, $i, !empty($css) ? $css : ' : ', !$this->highlight ? htmlspecialchars($line) : $line, !empty($css) ? '</span>' : ''); $i++; } $items = ''; foreach ($this->classes as $className => $classData) { $numCalledClasses = $classData['executedLines'] > 0 ? 1 : 0; $calledClassesPercent = $numCalledClasses == 1 ? 100 : 0; $numCalledMethods = 0; $numMethods = count($classData['methods']); foreach ($classData['methods'] as $method) { if ($method['executedLines'] > 0) { $numCalledMethods++; } } $items .= $this->doRenderItem(array('name' => sprintf('<b><a href="#%d">%s</a></b>', $classData['startLine'], $className), 'numClasses' => 1, 'numCalledClasses' => $numCalledClasses, 'calledClassesPercent' => sprintf('%01.2f', $calledClassesPercent), 'numMethods' => $numMethods, 'numCalledMethods' => $numCalledMethods, 'calledMethodsPercent' => $this->calculatePercent($numCalledMethods, $numMethods), 'numExecutableLines' => $classData['executableLines'], 'numExecutedLines' => $classData['executedLines'], 'executedLinesPercent' => $this->calculatePercent($classData['executedLines'], $classData['executableLines'])), $lowUpperBound, $highLowerBound); foreach ($classData['methods'] as $methodName => $methodData) { $numCalledMethods = $methodData['executedLines'] > 0 ? 1 : 0; $calledMethodsPercent = $numCalledMethods == 1 ? 100 : 0; $items .= $this->doRenderItem(array('name' => sprintf(' <a href="#%d">%s</a>', $methodData['startLine'], PHPUnit_Util_Class::getMethodSignature(new ReflectionMethod($className, $methodName))), 'numClasses' => '', 'numCalledClasses' => '', 'calledClassesPercent' => '', 'numMethods' => 1, 'numCalledMethods' => $numCalledMethods, 'calledMethodsPercent' => sprintf('%01.2f', $calledMethodsPercent), 'numExecutableLines' => $methodData['executableLines'], 'numExecutedLines' => $methodData['executedLines'], 'executedLinesPercent' => $this->calculatePercent($methodData['executedLines'], $methodData['executableLines'])), $lowUpperBound, $highLowerBound, 'method_item.html'); } } $this->setTemplateVars($template, $title, $charset); $template->setVar(array('lines' => $lines, 'total_item' => $this->renderTotalItem($lowUpperBound, $highLowerBound, FALSE), 'items' => $items, 'yuiPanelJS' => $this->yuiPanelJS)); $cleanId = PHPUnit_Util_Filesystem::getSafeFilename($this->getId()); $template->renderTo($target . $cleanId . '.html'); }
/** * Generates the class' source. * * @return mixed */ public function generate() { $methods = ''; foreach ($this->findTestedMethods() as $method) { $methodTemplate = new PHPUnit_Util_Template(sprintf('%s%sTemplate%sMethod.tpl', dirname(__FILE__), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)); $methodTemplate->setVar(array('methodName' => $method)); $methods .= $methodTemplate->render(); } $classTemplate = new PHPUnit_Util_Template(sprintf('%s%sTemplate%sClass.tpl', dirname(__FILE__), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)); $classTemplate->setVar(array('className' => $this->outClassName['fullyQualifiedClassName'], 'methods' => $methods, 'date' => date('Y-m-d'), 'time' => date('H:i:s'))); return $classTemplate->render(); }
/** * @param string $templateDir * @param string $className * @param string $methodName * @param string $modifier * @param string $arguments * @param string $reference * @return string */ protected static function generateMockedMethodDefinition($templateDir, $className, $methodName, $modifier = 'public', $arguments = '', $reference = '') { $template = new PHPUnit_Util_Template($templateDir . 'mocked_method.tpl'); $template->setVar(array('arguments' => $arguments, 'class_name' => $className, 'method_name' => $methodName, 'modifier' => $modifier, 'reference' => $reference)); return $template->render(); }
/** * Generates the test class' source. * * @param boolean $verbose * @return mixed */ public function generate($verbose = FALSE) { $class = new ReflectionClass($this->className); $methods = ''; $incompleteMethods = ''; foreach ($class->getMethods() as $method) { if (!$method->isConstructor() && !$method->isAbstract() && $method->isPublic() && $method->getDeclaringClass()->getName() == $this->className) { $assertAnnotationFound = FALSE; if (preg_match_all('/@assert(.*)$/Um', $method->getDocComment(), $annotations)) { foreach ($annotations[1] as $annotation) { if (preg_match('/\\((.*)\\)\\s+([^\\s]*)\\s+(.*)/', $annotation, $matches)) { switch ($matches[2]) { case '==': $assertion = 'Equals'; break; case '!=': $assertion = 'NotEquals'; break; case '===': $assertion = 'Same'; break; case '!==': $assertion = 'NotSame'; break; case '>': $assertion = 'GreaterThan'; break; case '>=': $assertion = 'GreaterThanOrEqual'; break; case '<': $assertion = 'LessThan'; break; case '<=': $assertion = 'LessThanOrEqual'; break; case 'throws': $assertion = 'exception'; break; default: throw new RuntimeException(); } if ($assertion == 'exception') { $template = 'TestMethodException'; } else { if ($assertion == 'Equals' && strtolower($matches[3]) == 'true') { $assertion = 'True'; $template = 'TestMethodBool'; } else { if ($assertion == 'NotEquals' && strtolower($matches[3]) == 'true') { $assertion = 'False'; $template = 'TestMethodBool'; } else { if ($assertion == 'Equals' && strtolower($matches[3]) == 'false') { $assertion = 'False'; $template = 'TestMethodBool'; } else { if ($assertion == 'NotEquals' && strtolower($matches[3]) == 'false') { $assertion = 'True'; $template = 'TestMethodBool'; } else { $template = 'TestMethod'; } } } } } if ($method->isStatic()) { $template .= 'Static'; } $methodTemplate = new PHPUnit_Util_Template(sprintf('%s%sSkeleton%s%s.tpl', dirname(__FILE__), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, $template)); $origMethodName = $method->getName(); $methodName = ucfirst($origMethodName); if (isset($this->methodNameCounter[$methodName])) { $this->methodNameCounter[$methodName]++; } else { $this->methodNameCounter[$methodName] = 1; } if ($this->methodNameCounter[$methodName] > 1) { $methodName .= $this->methodNameCounter[$methodName]; } $methodTemplate->setVar(array('annotation' => trim($annotation), 'arguments' => $matches[1], 'assertion' => isset($assertion) ? $assertion : '', 'expected' => $matches[3], 'origMethodName' => $origMethodName, 'className' => $this->className, 'methodName' => $methodName)); $methods .= $methodTemplate->render(); $assertAnnotationFound = TRUE; } } } if (!$assertAnnotationFound) { $methodTemplate = new PHPUnit_Util_Template(sprintf('%s%sSkeleton%sIncompleteTestMethod.tpl', dirname(__FILE__), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)); $methodTemplate->setVar(array('methodName' => ucfirst($method->getName()))); $incompleteMethods .= $methodTemplate->render(); } } } $classTemplate = new PHPUnit_Util_Template(sprintf('%s%sSkeleton%sTestClass.tpl', dirname(__FILE__), DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)); if ($this->classSourceFile != '<internal>') { $requireClassFile = sprintf("\n\nrequire_once '%s';", $this->classSourceFile); } else { $requireClassFile = ''; } $classTemplate->setVar(array('className' => $this->className, 'requireClassFile' => $requireClassFile, 'methods' => $methods . $incompleteMethods, 'date' => date('Y-m-d'), 'time' => date('H:i:s'))); if (!$verbose) { return $classTemplate->render(); } else { return array('code' => $classTemplate->render(), 'incomplete' => empty($methods)); } }
/** * Handler for 'end run' event. * */ protected function endRun() { $scenariosTemplate = new PHPUnit_Util_Template($this->templatePath . 'scenarios.html'); $scenariosTemplate->setVar(array('scenarios' => $this->scenarios, 'successfulScenarios' => $this->successful, 'failedScenarios' => $this->failed, 'skippedScenarios' => $this->skipped, 'incompleteScenarios' => $this->incomplete)); $this->write($scenariosTemplate->render()); }
/** * @param PHPUnit_Util_Template $template * @param string $title * @access public */ protected function setTemplateVars(PHPUnit_Util_Template $template, $title) { $template->setVar(array('title', 'link', 'executable_lines', 'executed_lines', 'executed_percent', 'date', 'phpunit_version', 'xdebug_version'), array($title, $this->getLink(FALSE, TRUE), $this->getNumExecutableLines(), $this->getNumExecutedLines(), $this->getExecutedPercent(), $template->getDate(), PHPUnit_Runner_Version::id(), phpversion('xdebug'))); }
/** * @param array $items * @param boolean $includeDetails * @return string * @access protected */ protected function doRenderItems(array $items, $includeDetails) { $result = ''; foreach ($items as $item) { $itemTemplate = new PHPUnit_Util_Template(PHPUnit_Util_Report::getTemplatePath() . 'coverage_item.html'); $details = ''; if ($includeDetails) { foreach ($item->getCoveringTests() as $suite => $tests) { $detailsHeaderTemplate = new PHPUnit_Util_Template(PHPUnit_Util_Report::getTemplatePath() . 'coverage_item_details_header.html'); $detailsHeaderTemplate->setVar('link', sprintf('<a href="%s-test.html">%s</a>', PHPUnit_Util_Filesystem::getSafeFilename($suite), $suite)); $details .= $detailsHeaderTemplate->render(); foreach ($tests as $test => $_test) { $detailsTemplate = new PHPUnit_Util_Template(PHPUnit_Util_Report::getTemplatePath() . 'coverage_item_details.html'); if ($_test['object']->getResult() !== PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { $failure = sprintf('<br /><pre>%s</pre>', htmlspecialchars($_test['object']->getResult()->exceptionMessage())); } else { $failure = ''; } $detailsTemplate->setVar(array('item', 'executed_percent', 'executed_lines', 'executable_lines'), array($test . $failure, sprintf('%01.2f', $_test['numLinesExecuted'] / $item->getNumExecutableLines() * 100), $_test['numLinesExecuted'], $item->getNumExecutableLines())); $details .= $detailsTemplate->render(); } } } $floorPercent = floor($item->getExecutedPercent()); if ($floorPercent < self::LOW_UPPER_BOUND) { $color = 'scarlet_red'; $level = 'Lo'; } else { if ($floorPercent >= self::LOW_UPPER_BOUND && $floorPercent < self::HIGH_LOWER_BOUND) { $color = 'butter'; $level = 'Med'; } else { $color = 'chameleon'; $level = 'Hi'; } } $itemTemplate->setVar(array('link', 'color', 'level', 'executed_width', 'executed_percent', 'not_executed_width', 'executable_lines', 'executed_lines', 'details'), array($item->getLink(FALSE, FALSE), $color, $level, floor($item->getExecutedPercent()), $item->getExecutedPercent(), 100 - floor($item->getExecutedPercent()), $item->getNumExecutableLines(), $item->getNumExecutedLines(), $details)); $result .= $itemTemplate->render(); } return $result; }
/** * @param PHPUnit_Util_Template $template * @param string $target * @access public */ protected function setGraphVizTemplateVars(PHPUnit_Util_Template $template, $target) { $testmap = ''; $testmap_image = 'snow.png'; $safeName = PHPUnit_Util_Filesystem::getSafeFilename($this->getName()); $dotFile = $target . $safeName . '.dot'; if (file_exists($dotFile) && class_exists('Image_GraphViz', FALSE)) { $pngFile = $target . $safeName . '.png'; $mapFile = $target . $safeName . '.map'; shell_exec(sprintf('neato -T png -o %s -T cmapx -o %s %s', $pngFile, $mapFile, $dotFile)); if (file_exists($pngFile)) { $testmap_image = basename($pngFile); } if (file_exists($mapFile)) { $testmap = file_get_contents($mapFile); unlink($mapFile); } unlink($dotFile); } $template->setVar(array('testmap', 'testmap_image'), array($testmap, $testmap_image)); }