1<?php 2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4/** 5 * PHP Version 4 6 * 7 * Copyright (c) 2002-2005, Sebastian Bergmann <sb@sebastian-bergmann.de>. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * * Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * * Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in 19 * the documentation and/or other materials provided with the 20 * distribution. 21 * 22 * * Neither the name of Sebastian Bergmann nor the names of his 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 30 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 36 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 * 39 * @category Testing 40 * @package PHPUnit 41 * @author Wolfram Kriesing <wolfram@kriesing.de> 42 * @copyright 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> 43 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 44 * @version CVS: $Id: HTML.php,v 1.19 2005/11/10 09:47:15 sebastian Exp $ 45 * @link http://pear.php.net/package/PHPUnit 46 * @since File available since Release 1.0.0 47 */ 48 49/** 50 * HTML GUI. 51 * 52 * @category Testing 53 * @package PHPUnit 54 * @author Wolfram Kriesing <wolfram@kriesing.de> 55 * @copyright 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> 56 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 57 * @version Release: 1.3.2 58 * @link http://pear.php.net/package/PHPUnit 59 * @since Class available since Release 1.0.0 60 */ 61class PHPUnit_GUI_HTML 62{ 63 var $_suites = array(); 64 65 /** 66 * the current implementation of PHPUnit is designed 67 * this way that adding a suite to another suite only 68 * grabs all the tests and adds them to the suite, so you 69 * have no chance to find out which test goes with which suite 70 * therefore you can simply pass an array of suites to this constructor here 71 * 72 * @param array The suites to be tested. If not given, then you might 73 * be using the SetupDecorator, which detects them automatically 74 * when calling getSuitesFromDir() 75 */ 76 function PHPUnit_GUI_HTML($suites = array()) 77 { 78 if (!is_array($suites)) { 79 $this->_suites = array($suites); 80 } else { 81 $this->_suites = $suites; 82 } 83 } 84 85 /** 86 * Add suites to the GUI 87 * 88 * @param object this should be an instance of PHPUnit_TestSuite 89 */ 90 function addSuites($suites) 91 { 92 $this->_suites = array_merge($this->_suites,$suites); 93 } 94 95 /** 96 * this prints the HTML code straight out 97 * 98 */ 99 function show() 100 { 101 $request = $_REQUEST; 102 $showPassed = FALSE; 103 $submitted = @$request['submitted']; 104 105 if ($submitted) { 106 $showPassed = @$request['showOK'] ? TRUE : FALSE; 107 } 108 109 $suiteResults = array(); 110 111 foreach ($this->_suites as $aSuite) { 112 $aSuiteResult = array(); 113 114 // remove the first directory's name from the test-suite name, since it 115 // mostly is something like 'tests' or alike 116 $removablePrefix = explode('_',$aSuite->getName()); 117 $aSuiteResult['name'] = str_replace($removablePrefix[0].'_', '', $aSuite->getName()); 118 119 if ($submitted && isset($request[$aSuiteResult['name']])) { 120 $result = PHPUnit::run($aSuite); 121 122 $aSuiteResult['counts']['run'] = $result->runCount(); 123 $aSuiteResult['counts']['error'] = $result->errorCount(); 124 $aSuiteResult['counts']['failure'] = $result->failureCount(); 125 126 $aSuiteResult['results'] = $this->_prepareResult($result,$showPassed); 127 128 $per = 100/$result->runCount(); 129 $failed = ($per*$result->errorCount())+($per*$result->failureCount()); 130 $aSuiteResult['percent'] = round(100-$failed,2); 131 } else { 132 $aSuiteResult['addInfo'] = 'NOT EXECUTED'; 133 } 134 135 $suiteResults[] = $aSuiteResult; 136 } 137 138 $final['name'] = 'OVERALL RESULT'; 139 $final['counts'] = array(); 140 $final['percent'] = 0; 141 $numExecutedTests = 0; 142 143 foreach ($suiteResults as $aSuiteResult) { 144 if (sizeof(@$aSuiteResult['counts'])) { 145 foreach ($aSuiteResult['counts'] as $key=>$aCount) { 146 if (!isset($final['counts'][$key])) { 147 $final['counts'][$key] = 0; 148 } 149 150 $final['counts'][$key] += $aCount; 151 } 152 } 153 } 154 155 if (isset($final['counts']['run'])) { 156 $per = 100/$final['counts']['run']; 157 $failed = ($per*$final['counts']['error'])+($per*$final['counts']['failure']); 158 $final['percent'] = round(100-$failed,2); 159 } else { 160 $final['percent'] = 0; 161 } 162 163 array_unshift($suiteResults,$final); 164 165 include 'PHPUnit/GUI/HTML.tpl'; 166 } 167 168 function _prepareResult($result,$showPassed) 169 { 170 $ret = array(); 171 $failures = $result->failures(); 172 173 foreach($failures as $aFailure) { 174 $ret['failures'][] = $this->_prepareFailure($aFailure); 175 } 176 177 $errors = $result->errors(); 178 179 foreach($errors as $aError) { 180 $ret['errors'][] = $this->_prepareErrors($aError); 181 } 182 183 if ($showPassed) { 184 $passed = $result->passedTests(); 185 186 foreach($passed as $aPassed) { 187 $ret['passed'][] = $this->_preparePassedTests($aPassed); 188 } 189 } 190 191 return $ret; 192 } 193 194 function _prepareFailure($failure) 195 { 196 $test = $failure->failedTest(); 197 $ret['testName'] = $test->getName(); 198 $exception = $failure->thrownException(); 199 200 // a serialized string starts with a 'character:decimal:{' 201 // if so we try to unserialize it 202 // this piece of the regular expression is for detecting a serialized 203 // type like 'a:3:' for an array with three element or an object i.e. 'O:12:"class":3' 204 $serialized = '(\w:\d+:(?:"[^"]+":\d+:)?\{.*\})'; 205 206 // Spaces might make a diff, so we shall show them properly (since a 207 // user agent ignores them). 208 if (preg_match('/^(.*)expected ' . $serialized . ', actual ' . $serialized . '$/sU', $exception, $matches)) { 209 ob_start(); 210 print_r(unserialize($matches[2])); 211 $ret['expected'] = htmlspecialchars($matches[1]) . "<pre>" . htmlspecialchars(rtrim(ob_get_contents())) . "</pre>"; 212 // Improved compatibility, ob_clean() would be PHP >= 4.2.0 only. 213 ob_end_clean(); 214 215 ob_start(); 216 print_r(unserialize($matches[3])); 217 $ret['actual'] = htmlspecialchars($matches[1]) . "<pre>" . htmlspecialchars(rtrim(ob_get_contents())) . "</pre>"; 218 ob_end_clean(); 219 } 220 221 else if (preg_match('/^(.*)expected (.*), actual (.*)$/sU', $exception, $matches)) { 222 $ret['expected'] = nl2br(str_replace(" ", " ", htmlspecialchars($matches[1] . $matches[2]))); 223 $ret['actual'] = nl2br(str_replace(" ", " ", htmlspecialchars($matches[1] . $matches[3]))); 224 } else { 225 $ret['message'] = nl2br(str_replace(" ", " ", htmlspecialchars($exception))); 226 } 227 228 return $ret; 229 } 230 231 function _preparePassedTests($passed) 232 { 233 $ret['testName'] = $passed->getName(); 234 return $ret; 235 } 236 237 function _prepareError($error) 238 { 239 $ret['testName'] = $error->getName(); 240 $ret['message'] = $error->toString(); 241 return $ret; 242 } 243} 244 245/* 246 * Local variables: 247 * tab-width: 4 248 * c-basic-offset: 4 249 * c-hanging-comment-ender-p: nil 250 * End: 251 */ 252?> 253