PHPMailer updated to latest version 2.3
[core.git] / inc / classes / third_party / php_mailer / test / phpunit.php
1 <?php\r
2 //\r
3 // PHP framework for testing, based on the design of "JUnit".\r
4 //\r
5 // Written by Fred Yankowski <fred@ontosys.com>\r
6 //            OntoSys, Inc  <http://www.OntoSys.com>\r
7 //\r
8 // $Id$\r
9 \r
10 // Copyright (c) 2000 Fred Yankowski\r
11 \r
12 // Permission is hereby granted, free of charge, to any person\r
13 // obtaining a copy of this software and associated documentation\r
14 // files (the "Software"), to deal in the Software without\r
15 // restriction, including without limitation the rights to use, copy,\r
16 // modify, merge, publish, distribute, sublicense, and/or sell copies\r
17 // of the Software, and to permit persons to whom the Software is\r
18 // furnished to do so, subject to the following conditions:\r
19 //\r
20 // The above copyright notice and this permission notice shall be\r
21 // included in all copies or substantial portions of the Software.\r
22 //\r
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
27 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
28 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
29 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
30 // SOFTWARE.\r
31 //\r
32 error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE |\r
33     E_CORE_ERROR | E_CORE_WARNING);\r
34 \r
35 /*\r
36 interface Test {\r
37   function run(&$aTestResult);\r
38   function countTestCases();\r
39 }\r
40 */\r
41 \r
42 function trace($msg) {\r
43   return;\r
44   print($msg);\r
45   flush();\r
46 }\r
47 \r
48 \r
49 class phpUnitException {\r
50     /* Emulate a Java exception, sort of... */\r
51   var $message;\r
52   var $type;\r
53   function phpUnitException($message, $type = 'FAILURE') {\r
54     $this->message = $message;\r
55     $this->type = $type;\r
56   }\r
57   function getMessage() {\r
58     return $this->message;\r
59   }\r
60 }\r
61 \r
62 class Assert {\r
63   function assert($boolean, $message=0) {\r
64     if (! $boolean)\r
65       $this->fail($message);\r
66   }\r
67 \r
68   function assertEquals($expected, $actual, $message=0) {\r
69     if ($expected != $actual) {\r
70       $this->failNotEquals($expected, $actual, "expected", $message);\r
71     }\r
72   }\r
73 \r
74   function assertRegexp($regexp, $actual, $message=false) {\r
75     if (! preg_match($regexp, $actual)) {\r
76       $this->failNotEquals($regexp, $actual, "pattern", $message);\r
77     }\r
78   }\r
79 \r
80   function failNotEquals($expected, $actual, $expected_label, $message=0) {\r
81     // Private function for reporting failure to match.\r
82     $str = $message ? ($message . ' ') : '';\r
83     $str .= "($expected_label/actual)<br>";\r
84     $htmlExpected = htmlspecialchars($expected);\r
85     $htmlActual = htmlspecialchars($actual);\r
86     $str .= sprintf("<pre>%s\n--------\n%s</pre>",\r
87         $htmlExpected, $htmlActual);\r
88     $this->fail($str);\r
89   }\r
90 }\r
91 \r
92 class TestCase extends Assert /* implements Test */ {\r
93   /* Defines context for running tests.  Specific context -- such as\r
94      instance variables, global variables, global state -- is defined\r
95      by creating a subclass that specializes the setUp() and\r
96      tearDown() methods.  A specific test is defined by a subclass\r
97      that specializes the runTest() method. */\r
98   var $fName;\r
99   var $fResult;\r
100   var $fExceptions = array();\r
101 \r
102   function TestCase($name) {\r
103     $this->fName = $name;\r
104   }\r
105 \r
106   function run($testResult=0) {\r
107     /* Run this single test, by calling the run() method of the\r
108        TestResult object which will in turn call the runBare() method\r
109        of this object.  That complication allows the TestResult object\r
110        to do various kinds of progress reporting as it invokes each\r
111        test.  Create/obtain a TestResult object if none was passed in.\r
112        Note that if a TestResult object was passed in, it must be by\r
113        reference. */\r
114     if (! $testResult)\r
115       $testResult = $this->_createResult();\r
116     $this->fResult = $testResult;\r
117     $testResult->run(&$this);\r
118     $this->fResult = 0;\r
119     return $testResult;\r
120   }\r
121 \r
122   function countTestCases() {\r
123     return 1;\r
124   }\r
125 \r
126   function runTest() {\r
127     $name = $this->name();\r
128     // Since isset($this->$name) is false, no way to run defensive checks\r
129     $this->$name();\r
130   }\r
131 \r
132   function setUp() /* expect override */ {\r
133     //print("TestCase::setUp()<br>\n");\r
134   }\r
135 \r
136   function tearDown() /* possible override */ {\r
137     //print("TestCase::tearDown()<br>\n");\r
138   }\r
139 \r
140   ////////////////////////////////////////////////////////////////\r
141 \r
142 \r
143   function _createResult() /* protected */ {\r
144     /* override this to use specialized subclass of TestResult */\r
145     return new TestResult;\r
146   }\r
147 \r
148   function fail($message=0) {\r
149     //printf("TestCase::fail(%s)<br>\n", ($message) ? $message : '');\r
150     /* JUnit throws AssertionFailedError here.  We just record the\r
151        failure and carry on */\r
152     $this->fExceptions[] = new Exception(&$message);\r
153   }\r
154 \r
155   function error($message) {\r
156     /* report error that requires correction in the test script\r
157        itself, or (heaven forbid) in this testing infrastructure */\r
158     printf('<b>ERROR: ' . $message . '</b><br>');\r
159     $this->fResult->stop();\r
160   }\r
161 \r
162   function failed() {\r
163     return count($this->fExceptions);\r
164   }\r
165 \r
166   function getExceptions() {\r
167     return $this->fExceptions;\r
168   }\r
169 \r
170   function name() {\r
171     return $this->fName;\r
172   }\r
173 \r
174   function runBare() {\r
175     $this->setup();\r
176     $this->runTest();\r
177     $this->tearDown();\r
178   }\r
179 }\r
180 \r
181 \r
182 class TestSuite /* implements Test */ {\r
183   /* Compose a set of Tests (instances of TestCase or TestSuite), and\r
184      run them all. */\r
185   var $fTests = array();\r
186 \r
187   function TestSuite($classname=false) {\r
188     if ($classname) {\r
189       // Find all methods of the given class whose name starts with\r
190       // "test" and add them to the test suite.  We are just _barely_\r
191       // able to do this with PHP's limited introspection...  Note\r
192       // that PHP seems to store method names in lower case, and we\r
193       // have to avoid the constructor function for the TestCase class\r
194       // superclass.  This will fail when $classname starts with\r
195       // "Test" since that will have a constructor method that will\r
196       // get matched below and then treated (incorrectly) as a test\r
197       // method.  So don't name any TestCase subclasses as "Test..."!\r
198       if (floor(phpversion()) >= 4) {\r
199   // PHP4 introspection, submitted by Dylan Kuhn\r
200   $names = get_class_methods($classname);\r
201   while (list($key, $method) = each($names)) {\r
202     if (preg_match('/^test/', $method) && $method != "testcase") {\r
203       $this->addTest(new $classname($method));\r
204     }\r
205   }\r
206       }\r
207       else {\r
208   $dummy = new $classname("dummy");\r
209   $names = (array) $dummy;\r
210   while (list($key, $value) = each($names)) {\r
211     $type = gettype($value);\r
212     if ($type == "user function" && preg_match('/^test/', $key)\r
213     && $key != "testcase") {\r
214       $this->addTest(new $classname($key));\r
215     }\r
216   }\r
217       }\r
218     }\r
219   }\r
220 \r
221   function addTest($test) {\r
222     /* Add TestCase or TestSuite to this TestSuite */\r
223     $this->fTests[] = $test;\r
224   }\r
225 \r
226   function run(&$testResult) {\r
227     /* Run all TestCases and TestSuites comprising this TestSuite,\r
228        accumulating results in the given TestResult object. */\r
229     reset($this->fTests);\r
230     while (list($na, $test) = each($this->fTests)) {\r
231       if ($testResult->shouldStop())\r
232   break;\r
233       $test->run(&$testResult);\r
234     }\r
235   }\r
236 \r
237   function countTestCases() {\r
238     /* Number of TestCases comprising this TestSuite (including those\r
239        in any constituent TestSuites) */\r
240     $count = 0;\r
241     reset($fTests);\r
242     while (list($na, $test_case) = each($this->fTests)) {\r
243       $count += $test_case->countTestCases();\r
244     }\r
245     return $count;\r
246   }\r
247 }\r
248 \r
249 \r
250 class TestFailure {\r
251   /* Record failure of a single TestCase, associating it with the\r
252      exception(s) that occurred */\r
253   var $fFailedTestName;\r
254   var $fExceptions;\r
255 \r
256   function TestFailure(&$test, &$exceptions) {\r
257     $this->fFailedTestName = $test->name();\r
258     $this->fExceptions = $exceptions;\r
259   }\r
260 \r
261   function getExceptions() {\r
262       return $this->fExceptions;\r
263   }\r
264   function getTestName() {\r
265     return $this->fFailedTestName;\r
266   }\r
267 }\r
268 \r
269 \r
270 class TestResult {\r
271   /* Collect the results of running a set of TestCases. */\r
272   var $fFailures = array();\r
273   var $fRunTests = 0;\r
274   var $fStop = false;\r
275 \r
276   function TestResult() { }\r
277 \r
278   function _endTest($test) /* protected */ {\r
279       /* specialize this for end-of-test action, such as progress\r
280    reports  */\r
281   }\r
282 \r
283   function getFailures() {\r
284     return $this->fFailures;\r
285   }\r
286 \r
287   function run($test) {\r
288     /* Run a single TestCase in the context of this TestResult */\r
289     $this->_startTest($test);\r
290     $this->fRunTests++;\r
291 \r
292     $test->runBare();\r
293 \r
294     /* this is where JUnit would catch AssertionFailedError */\r
295     $exceptions = $test->getExceptions();\r
296     if ($exceptions)\r
297       $this->fFailures[] = new TestFailure(&$test, &$exceptions);\r
298     $this->_endTest($test);\r
299   }\r
300 \r
301   function countTests() {\r
302     return $this->fRunTests;\r
303   }\r
304 \r
305   function shouldStop() {\r
306     return $this->fStop;\r
307   }\r
308 \r
309   function _startTest($test) /* protected */ {\r
310       /* specialize this for start-of-test actions */\r
311   }\r
312 \r
313   function stop() {\r
314     /* set indication that the test sequence should halt */\r
315     $fStop = true;\r
316   }\r
317 \r
318   function countFailures() {\r
319     return count($this->fFailures);\r
320   }\r
321 }\r
322 \r
323 \r
324 class TextTestResult extends TestResult {\r
325   /* Specialize TestResult to produce text/html report */\r
326   function TextTestResult() {\r
327     $this->TestResult();  // call superclass constructor\r
328   }\r
329 \r
330   function report() {\r
331     /* report result of test run */\r
332     $nRun = $this->countTests();\r
333     $nFailures = $this->countFailures();\r
334     printf("<p>%s test%s run<br>", $nRun, ($nRun == 1) ? '' : 's');\r
335     printf("%s failure%s.<br>\n", $nFailures, ($nFailures == 1) ? '' : 's');\r
336     if ($nFailures == 0)\r
337       return;\r
338 \r
339     print("<ol>\n");\r
340     $failures = $this->getFailures();\r
341     while (list($i, $failure) = each($failures)) {\r
342       $failedTestName = $failure->getTestName();\r
343       printf("<li>%s\n", $failedTestName);\r
344 \r
345       $exceptions = $failure->getExceptions();\r
346       print("<ul>");\r
347       while (list($na, $exception) = each($exceptions))\r
348   printf("<li>%s\n", $exception->getMessage());\r
349       print("</ul>");\r
350     }\r
351     print("</ol>\n");\r
352   }\r
353 \r
354   function _startTest($test) {\r
355     printf("%s ", $test->name());\r
356     flush();\r
357   }\r
358 \r
359   function _endTest($test) {\r
360     $outcome = $test->failed()\r
361        ? "<font color=\"red\">FAIL</font>"\r
362        : "<font color=\"green\">ok</font>";\r
363     printf("$outcome<br>\n");\r
364     flush();\r
365   }\r
366 }\r
367 \r
368 \r
369 class TestRunner {\r
370   /* Run a suite of tests and report results. */\r
371   function run($suite) {\r
372     $result = new TextTestResult;\r
373     $suite->run($result);\r
374     $result->report();\r
375   }\r
376 }\r
377 \r
378 ?>\r