fix for escaping in the code search popup
[openemr.git] / gacl / test_suite / phpunit / phpunit.php
blobd21bb74a2a45771d9835370fa1fc3382eaf1558c
1 <?php
2 //
3 // PHP framework for testing, based on the design of "JUnit".
4 //
5 // Written by Fred Yankowski <fred@ontosys.com>
6 // OntoSys, Inc <http://www.OntoSys.com>
7 //
8 // $Id$
10 // Copyright (c) 2000 Fred Yankowski
12 // Permission is hereby granted, free of charge, to any person
13 // obtaining a copy of this software and associated documentation
14 // files (the "Software"), to deal in the Software without
15 // restriction, including without limitation the rights to use, copy,
16 // modify, merge, publish, distribute, sublicense, and/or sell copies
17 // of the Software, and to permit persons to whom the Software is
18 // furnished to do so, subject to the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 // SOFTWARE.
32 error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE |
33 E_CORE_ERROR | E_CORE_WARNING);
36 interface Test {
37 function run(&$aTestResult);
38 function countTestCases();
42 function trace($msg) {
43 return;
44 print($msg);
45 flush();
48 if (phpversion() >= '4') {
49 function PHPUnit_error_handler($errno, $errstr, $errfile, $errline) {
50 global $PHPUnit_testRunning;
51 $PHPUnit_testRunning[0]->fail("<B>PHP ERROR:</B> ".$errstr." <B>in</B> ".$errfile." <B>at line</B> ".$errline);
55 class Exception {
56 /* Emulate a Java exception, sort of... */
57 var $message;
58 var $type;
59 function Exception($message, $type = 'FAILURE') {
60 $this->message = $message;
61 $this->type = $type;
63 function getMessage() {
64 return $this->message;
66 function getType() {
67 return $this->type;
71 class Assert {
72 function assert($boolean, $message=0) {
73 if (! $boolean)
74 $this->fail($message);
77 function assertEquals($expected, $actual, $message=0) {
78 if (gettype($expected) != gettype($actual)) {
79 $this->failNotEquals($expected, $actual, "expected", $message);
80 return;
82 if (phpversion() < '4') {
83 if (is_object($expected) or is_object($actual)
84 or is_array($expected) or is_array($actual)) {
85 $this->error("INVALID TEST: cannot compare arrays or objects in PHP3");
86 return;
89 if (phpversion() >= '4' && is_object($expected)) {
90 if (get_class($expected) != get_class($actual)) {
91 $this->failNotEquals($expected, $actual, "expected", $message);
92 return;
94 if (method_exists($expected, "equals")) {
95 if (! $expected->equals($actual)) {
96 $this->failNotEquals($expected, $actual, "expected", $message);
98 return; // no further tests after equals()
102 if (phpversion() >= '4.0.4') {
103 if (is_null($expected) != is_null($actual)) {
104 $this->failNotEquals($expected, $actual, "expected", $message);
105 return;
108 if ($expected != $actual) {
109 $this->failNotEquals($expected, $actual, "expected", $message);
113 function assertRegexp($regexp, $actual, $message=false) {
114 if (! preg_match($regexp, $actual)) {
115 $this->failNotEquals($regexp, $actual, "pattern", $message);
119 function assertEqualsMultilineStrings($string0, $string1,
120 $message="") {
121 $lines0 = split("\n",$string0);
122 $lines1 = split("\n",$string1);
123 if (sizeof($lines0) != sizeof($lines1)) {
124 $this->failNotEquals(sizeof($lines0)." line(s)",
125 sizeof($lines1)." line(s)", "expected", $message);
127 for($i=0; $i< sizeof($lines0); $i++) {
128 $this->assertEquals(trim($lines0[$i]),
129 trim($lines1[$i]),
130 "line ".($i+1)." of multiline strings differ. ".$message);
134 function _formatValue($value, $class="") {
135 $translateValue = $value;
136 if (phpversion() >= '4.0.0') {
137 if (is_object($value)) {
138 if (method_exists($value, "toString") ) {
139 $translateValue = $value->toString();
141 else {
142 $translateValue = serialize($value);
145 else if (is_array($value)) {
146 $translateValue = serialize($value);
149 $htmlValue = "<code class=\"$class\">"
150 . htmlspecialchars($translateValue) . "</code>";
151 if (phpversion() >= '4.0.0') {
152 if (is_bool($value)) {
153 $htmlValue = $value ? "<i>true</i>" : "<i>false</i>";
155 elseif (phpversion() >= '4.0.4' && is_null($value)) {
156 $htmlValue = "<i>null</i>";
158 $htmlValue .= "&nbsp;&nbsp;&nbsp;<span class=\"typeinfo\">";
159 $htmlValue .= "type:" . gettype($value);
160 $htmlValue .= is_object($value) ? ", class:" . get_class($value) : "";
161 $htmlValue .= "</span>";
163 return $htmlValue;
166 function failNotEquals($expected, $actual, $expected_label, $message=0) {
167 // Private function for reporting failure to match.
168 $str = $message ? ($message . ' ') : '';
169 //$str .= "($expected_label/actual)<br>";
170 $str .= "<br>";
171 $str .= sprintf("%s<br>%s",
172 $this->_formatValue($expected, "expected"),
173 $this->_formatValue($actual, "actual"));
174 $this->fail($str);
178 class TestCase extends Assert /* implements Test */ {
179 /* Defines context for running tests. Specific context -- such as
180 instance variables, global variables, global state -- is defined
181 by creating a subclass that specializes the setUp() and
182 tearDown() methods. A specific test is defined by a subclass
183 that specializes the runTest() method. */
184 var $fName;
185 var $fClassName;
186 var $fResult;
187 var $fExceptions = array();
189 function TestCase($name) {
190 $this->fName = $name;
193 function run($testResult=0) {
194 /* Run this single test, by calling the run() method of the
195 TestResult object which will in turn call the runBare() method
196 of this object. That complication allows the TestResult object
197 to do various kinds of progress reporting as it invokes each
198 test. Create/obtain a TestResult object if none was passed in.
199 Note that if a TestResult object was passed in, it must be by
200 reference. */
201 if (! $testResult)
202 $testResult = $this->_createResult();
203 $this->fResult = $testResult;
204 $testResult->run(&$this);
205 $this->fResult = 0;
206 return $testResult;
209 function classname() {
210 if (isset($this->fClassName)) {
211 return $this->fClassName;
212 } else {
213 return get_class($this);
217 function countTestCases() {
218 return 1;
221 function runTest() {
222 if (phpversion() >= '4') {
223 global $PHPUnit_testRunning;
224 eval('$PHPUnit_testRunning[0] = & $this;');
225 // Saved ref to current TestCase, so that the error handler
226 // can access it. This code won't even parse in PHP3, so we
227 // hide it in an eval.
228 $old_handler = set_error_handler("PHPUnit_error_handler");
229 // errors will now be handled by our error handler
232 $name = $this->name();
233 if (phpversion() >= '4' && ! method_exists($this, $name)) {
234 $this->error("Method '$name' does not exist");
236 else
237 $this->$name();
240 if (phpversion() >= '4') {
241 set_error_handler($old_handler); // revert to prior error handler
242 $PHPUnit_testRunning = null;
247 function setUp() /* expect override */ {
248 //print("TestCase::setUp()<br>\n");
251 function tearDown() /* possible override */ {
252 //print("TestCase::tearDown()<br>\n");
255 ////////////////////////////////////////////////////////////////
258 function _createResult() /* protected */ {
259 /* override this to use specialized subclass of TestResult */
260 return new TestResult;
263 function fail($message=0) {
264 //printf("TestCase::fail(%s)<br>\n", ($message) ? $message : '');
265 /* JUnit throws AssertionFailedError here. We just record the
266 failure and carry on */
267 $this->fExceptions[] = new Exception(&$message, 'FAILURE');
270 function error($message) {
271 /* report error that requires correction in the test script
272 itself, or (heaven forbid) in this testing infrastructure */
273 $this->fExceptions[] = new Exception(&$message, 'ERROR');
274 $this->fResult->stop(); // [does not work]
277 function failed() {
278 reset($this->fExceptions);
279 while (list($key, $exception) = each($this->fExceptions)) {
280 if ($exception->type == 'FAILURE')
281 return true;
283 return false;
285 function errored() {
286 reset($this->fExceptions);
287 while (list($key, $exception) = each($this->fExceptions)) {
288 if ($exception->type == 'ERROR')
289 return true;
291 return false;
294 function getExceptions() {
295 return $this->fExceptions;
298 function name() {
299 return $this->fName;
302 function runBare() {
303 $this->setup();
304 $this->runTest();
305 $this->tearDown();
310 class TestSuite /* implements Test */ {
311 /* Compose a set of Tests (instances of TestCase or TestSuite), and
312 run them all. */
313 var $fTests = array();
314 var $fClassname;
316 function TestSuite($classname=false) {
317 // Find all methods of the given class whose name starts with
318 // "test" and add them to the test suite.
320 // PHP3: We are just _barely_ able to do this with PHP's limited
321 // introspection... Note that PHP seems to store method names in
322 // lower case, and we have to avoid the constructor function for
323 // the TestCase class superclass. Names of subclasses of TestCase
324 // must not start with "Test" since such a class will have a
325 // constructor method name also starting with "test" and we can't
326 // distinquish such a construtor from the real test method names.
327 // So don't name any TestCase subclasses as "Test..."!
329 // PHP4: Never mind all that. We can now ignore constructor
330 // methods, so a test class may be named "Test...".
332 if (empty($classname))
333 return;
334 $this->fClassname = $classname;
336 if (floor(phpversion()) >= 4) {
337 // PHP4 introspection, submitted by Dylan Kuhn
339 $names = get_class_methods($classname);
340 while (list($key, $method) = @each($names)) {
341 if (preg_match('/^test/', $method)) {
342 $test = new $classname($method);
343 if (strcasecmp($method, $classname) == 0 || is_subclass_of($test, $method)) {
344 // Ignore the given method name since it is a constructor:
345 // it's the name of our test class or it is the name of a
346 // superclass of our test class. (This code smells funny.
347 // Anyone got a better way?)
349 //print "skipping $method<br>";
351 else {
352 $this->addTest($test);
357 else { // PHP3
358 $dummy = new $classname("dummy");
359 $names = (array) $dummy;
360 while (list($key, $value) = each($names)) {
361 $type = gettype($value);
362 if ($type == "user function" && preg_match('/^test/', $key)
363 && $key != "testcase") {
364 $this->addTest(new $classname($key));
370 function addTest($test) {
371 /* Add TestCase or TestSuite to this TestSuite */
372 $this->fTests[] = $test;
375 function run(&$testResult) {
376 /* Run all TestCases and TestSuites comprising this TestSuite,
377 accumulating results in the given TestResult object. */
378 reset($this->fTests);
379 while (list($na, $test) = each($this->fTests)) {
380 if ($testResult->shouldStop())
381 break;
382 $test->run(&$testResult);
386 function countTestCases() {
387 /* Number of TestCases comprising this TestSuite (including those
388 in any constituent TestSuites) */
389 $count = 0;
390 reset($fTests);
391 while (list($na, $test_case) = each($this->fTests)) {
392 $count += $test_case->countTestCases();
394 return $count;
399 class TestFailure {
400 /* Record failure of a single TestCase, associating it with the
401 exception that occurred */
402 var $fFailedTestName;
403 var $fException;
405 function TestFailure(&$test, &$exception) {
406 $this->fFailedTestName = $test->name();
407 $this->fException = $exception;
410 function getExceptions() {
411 // deprecated
412 return array($this->fException);
414 function getException() {
415 return $this->fException;
418 function getTestName() {
419 return $this->fFailedTestName;
424 class TestResult {
425 /* Collect the results of running a set of TestCases. */
426 var $fFailures = array();
427 var $fErrors = array();
428 var $fRunTests = 0;
429 var $fStop = false;
431 function TestResult() { }
433 function _endTest($test) /* protected */ {
434 /* specialize this for end-of-test action, such as progress
435 reports */
438 function addError($test, $exception) {
439 $this->fErrors[] = new TestFailure(&$test, &$exception);
442 function addFailure($test, $exception) {
443 $this->fFailures[] = new TestFailure(&$test, &$exception);
446 function getFailures() {
447 return $this->fFailures;
450 function run($test) {
451 /* Run a single TestCase in the context of this TestResult */
452 $this->_startTest($test);
453 $this->fRunTests++;
455 $test->runBare();
457 /* this is where JUnit would catch AssertionFailedError */
458 $exceptions = $test->getExceptions();
459 reset($exceptions);
460 while (list($key, $exception) = each($exceptions)) {
461 if ($exception->type == 'ERROR')
462 $this->addError($test, $exception);
463 else if ($exception->type == 'FAILURE')
464 $this->addFailure($test, $exception);
466 // if ($exceptions)
467 // $this->fFailures[] = new TestFailure(&$test, &$exceptions);
468 $this->_endTest($test);
471 function countTests() {
472 return $this->fRunTests;
475 function shouldStop() {
476 return $this->fStop;
479 function _startTest($test) /* protected */ {
480 /* specialize this for start-of-test actions */
483 function stop() {
484 /* set indication that the test sequence should halt */
485 $fStop = true;
488 function errorCount() {
489 return count($this->fErrors);
491 function failureCount() {
492 return count($this->fFailures);
494 function countFailures() {
495 // deprecated
496 return $this->failureCount();
501 class TextTestResult extends TestResult {
502 /* Specialize TestResult to produce text/html report */
503 function TextTestResult() {
504 $this->TestResult(); // call superclass constructor
507 function report() {
508 /* report result of test run */
509 $nRun = $this->countTests();
510 $nFailures = $this->failureCount();
511 $nErrors = $this->errorCount();
512 printf("<p>%s test%s run<br>", $nRun, ($nRun == 1) ? '' : 's');
513 printf("%s failure%s<br>\n", $nFailures, ($nFailures == 1) ? '' : 's');
514 printf("%s error%s.<br>\n", $nErrors, ($nErrors == 1) ? '' : 's');
516 if ($nFailures > 0) {
517 print("<h2>Failures</h2>");
518 print("<ol>\n");
519 $failures = $this->getFailures();
520 while (list($i, $failure) = each($failures)) {
521 $failedTestName = $failure->getTestName();
522 printf("<li>%s\n", $failedTestName);
524 $exceptions = $failure->getExceptions();
525 print("<ul>");
526 while (list($na, $exception) = each($exceptions))
527 printf("<li>%s\n", $exception->getMessage());
528 print("</ul>");
530 print("</ol>\n");
533 if ($nErrors > 0) {
534 print("<h2>Errors</h2>");
535 print("<ol>\n");
536 reset($this->fErrors);
537 while (list($i, $error) = each($this->fErrors)) {
538 $erroredTestName = $error->getTestName();
539 printf("<li>%s\n", $failedTestName);
541 $exception = $error->getException();
542 print("<ul>");
543 printf("<li>%s\n", $exception->getMessage());
544 print("</ul>");
546 print("</ol>\n");
551 function _startTest($test) {
552 if (phpversion() > '4') {
553 printf("%s - %s ", get_class($test), $test->name());
554 } else {
555 printf("%s ", $test->name());
557 flush();
560 function _endTest($test) {
561 $outcome = $test->failed()
562 ? "<font color=\"red\">FAIL</font>"
563 : "<font color=\"green\">ok</font>";
564 printf("$outcome<br>\n");
565 flush();
569 // PrettyTestResult created by BJG 17/11/01
570 // beacuse the standard test result provided looks
571 // rubbish.
572 class PrettyTestResult extends TestResult {
573 /* Specialize TestResult to produce text/html report */
574 function PrettyTestResult() {
575 $this->TestResult(); // call superclass constructor
576 echo "<h2>Tests</h2>";
578 echo "<TABLE CELLSPACING=\"1\" CELLPADDING=\"1\" BORDER=\"0\" WIDTH=\"90%\" ALIGN=\"CENTER\" class=\"details\">";
579 echo "<TR><TH>Class</TH><TH>Function</TH><TH>Success?</TH></TR>";
582 function report() {
583 echo "</TABLE>";
584 /* report result of test run */
585 $nRun = $this->countTests();
586 $nFailures = $this->countFailures();
587 echo "<h2>Summary</h2>";
589 printf("<p>%s test%s run<br>", $nRun, ($nRun == 1) ? '' : 's');
590 printf("%s failure%s.<br>\n", $nFailures, ($nFailures == 1) ? '' : 's');
591 if ($nFailures == 0)
592 return;
594 echo "<h2>Failure Details</h2>";
595 print("<ol>\n");
596 $failures = $this->getFailures();
597 while (list($i, $failure) = each($failures)) {
598 $failedTestName = $failure->getTestName();
599 printf("<li>%s\n", $failedTestName);
601 $exceptions = $failure->getExceptions();
602 print("<ul>");
603 while (list($na, $exception) = each($exceptions))
604 printf("<li>%s\n", $exception->getMessage());
605 print("</ul>");
607 print("</ol>\n");
610 function _startTest($test) {
611 printf("<TR><TD>%s </TD><TD>%s </TD>", $test->classname(),$test->name());
612 flush();
615 function _endTest($test) {
616 $outcome = $test->failed()
617 ? " class=\"Failure\">FAIL"
618 : " class=\"Pass\">OK";
619 printf("<TD$outcome</TD></TR>");
620 flush();
624 class TestRunner {
625 /* Run a suite of tests and report results. */
626 function run($suite) {
627 $result = new TextTestResult;
628 $suite->run($result);
629 $result->report();