PageRenderTime 38ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/host-tools/offline-renderer/mediawiki-offline/t/Test.php

https://github.com/sunnysujan/wikireader
PHP | 496 lines | 279 code | 59 blank | 158 comment | 52 complexity | 7327665364eb337d07fab5df08704235 MD5 | raw file
  1. <?php
  2. # See the end of this file for documentation
  3. # The latest release of this test framework can always be found on CPAN:
  4. # http://search.cpan.org/search?query=Test.php
  5. register_shutdown_function('_test_ends');
  6. $__Test = array(
  7. # How many tests are planned
  8. 'planned' => null,
  9. # How many tests we've run, if 'planned' is still null by the time we're
  10. # done we report the total count at the end
  11. 'run' => 0,
  12. # Are are we currently within todo_start()/todo_end() ?
  13. 'todo' => array(),
  14. );
  15. function plan($plan, $why = '')
  16. {
  17. global $__Test;
  18. $__Test['planned'] = true;
  19. switch ($plan)
  20. {
  21. case 'no_plan':
  22. $__Test['planned'] = false;
  23. break;
  24. case 'skip_all';
  25. printf("1..0%s\n", $why ? " # Skip $why" : '');
  26. exit;
  27. default:
  28. printf("1..%d\n", $plan);
  29. break;
  30. }
  31. }
  32. function pass($desc = '')
  33. {
  34. return _proclaim(true, $desc);
  35. }
  36. function fail($desc = '')
  37. {
  38. return _proclaim(false, $desc);
  39. }
  40. function ok($cond, $desc = '') {
  41. return _proclaim($cond, $desc);
  42. }
  43. function is($got, $expected, $desc = '') {
  44. $pass = $got == $expected;
  45. return _proclaim($pass, $desc, /* todo */ false, $got, $expected);
  46. }
  47. function isnt($got, $expected, $desc = '') {
  48. $pass = $got != $expected;
  49. return _proclaim($pass, $desc, /* todo */ false, $got, $expected, /* negated */ true);
  50. }
  51. function like($got, $expected, $desc = '') {
  52. $pass = preg_match($expected, $got);
  53. return _proclaim($pass, $desc, /* todo */ false, $got, $expected);
  54. }
  55. function unlike($got, $expected, $desc = '') {
  56. $pass = !preg_match($expected, $got);
  57. return _proclaim($pass, $desc, /* todo */ false, $got, $expected, /* negated */ true);
  58. }
  59. function cmp_ok($got, $op, $expected, $desc = '')
  60. {
  61. $pass = null;
  62. # See http://www.php.net/manual/en/language.operators.comparison.php
  63. switch ($op)
  64. {
  65. case '==':
  66. $pass = $got == $expected;
  67. break;
  68. case '===':
  69. $pass = $got === $expected;
  70. break;
  71. case '!=':
  72. case '<>':
  73. $pass = $got != $expected;
  74. break;
  75. case '!==':
  76. $pass = $got !== $expected;
  77. break;
  78. case '<':
  79. $pass = $got < $expected;
  80. break;
  81. case '>':
  82. $pass = $got > $expected;
  83. break;
  84. case '<=':
  85. $pass = $got <= $expected;
  86. break;
  87. case '>=':
  88. $pass = $got >= $expected;
  89. break;
  90. default:
  91. if (function_exists($op)) {
  92. $pass = $op($got, $expected);
  93. } else {
  94. die("No such operator or function $op\n");
  95. }
  96. }
  97. return _proclaim($pass, $desc, /* todo */ false, $got, "$got $op $expected");
  98. }
  99. function diag($message)
  100. {
  101. if (is_array($message))
  102. {
  103. $message = implode("\n", $message);
  104. }
  105. foreach (explode("\n", $message) as $line)
  106. {
  107. echo "# $line\n";
  108. }
  109. }
  110. function include_ok($file, $desc = '')
  111. {
  112. $pass = include $file;
  113. return _proclaim($pass, $desc == '' ? "include $file" : $desc);
  114. }
  115. function require_ok($file, $desc = '')
  116. {
  117. $pass = require $file;
  118. return _proclaim($pass, $desc == '' ? "require $file" : $desc);
  119. }
  120. function is_deeply($got, $expected, $desc = '')
  121. {
  122. $diff = _cmp_deeply($got, $expected);
  123. $pass = is_null($diff);
  124. if (!$pass) {
  125. $got = strlen($diff['gpath']) ? ($diff['gpath'] . ' = ' . $diff['got'])
  126. : _repl($got);
  127. $expected = strlen($diff['epath']) ? ($diff['epath'] . ' = ' . $diff['expected'])
  128. : _repl($expected);
  129. }
  130. _proclaim($pass, $desc, /* todo */ false, $got, $expected);
  131. }
  132. function isa_ok($obj, $expected, $desc = '')
  133. {
  134. $pass = is_a($obj, $expected);
  135. _proclaim($pass, $desc, /* todo */ false, $name, $expected);
  136. }
  137. function todo_start($why = '')
  138. {
  139. global $__Test;
  140. $__Test['todo'][] = $why;
  141. }
  142. function todo_end()
  143. {
  144. global $__Test;
  145. if (count($__Test['todo']) == 0) {
  146. die("todo_end() called without a matching todo_start() call");
  147. } else {
  148. array_pop($__Test['todo']);
  149. }
  150. }
  151. #
  152. # The code below consists of private utility functions for the above functions
  153. #
  154. function _proclaim(
  155. $cond, # bool
  156. $desc = '',
  157. $todo = false,
  158. $got = null,
  159. $expected = null,
  160. $negate = false) {
  161. global $__Test;
  162. $__Test['run'] += 1;
  163. # We're in a TODO block via todo_start()/todo_end(). TODO via specific
  164. # functions is currently unimplemented and will probably stay that way
  165. if (count($__Test['todo'])) {
  166. $todo = true;
  167. }
  168. # Everything after the first # is special, so escape user-supplied messages
  169. $desc = str_replace('#', '\\#', $desc);
  170. $desc = str_replace("\n", '\\n', $desc);
  171. $ok = $cond ? "ok" : "not ok";
  172. $directive = '';
  173. if ($todo) {
  174. $todo_idx = count($__Test['todo']) - 1;
  175. $directive .= ' # TODO ' . $__Test['todo'][$todo_idx];
  176. }
  177. printf("%s %d %s%s\n", $ok, $__Test['run'], $desc, $directive);
  178. # report a failure
  179. if (!$cond) {
  180. # Every public function in this file calls _proclaim so our culprit is
  181. # the second item in the stack
  182. $caller = debug_backtrace();
  183. $call = $caller['1'];
  184. diag(
  185. sprintf(" Failed%stest '%s'\n in %s at line %d\n got: %s\n expected: %s",
  186. $todo ? ' TODO ' : ' ',
  187. $desc,
  188. $call['file'],
  189. $call['line'],
  190. $got,
  191. $expected
  192. )
  193. );
  194. }
  195. return $cond;
  196. }
  197. function _test_ends()
  198. {
  199. global $__Test;
  200. if (count($__Test['todo']) != 0) {
  201. $todos = join("', '", $__Test['todo']);
  202. die("Missing todo_end() for '$todos'");
  203. }
  204. if (!$__Test['planned']) {
  205. printf("1..%d\n", $__Test['run']);
  206. }
  207. }
  208. #
  209. # All of the below is for is_deeply()
  210. #
  211. function _repl($obj, $deep = true) {
  212. if (is_string($obj)) {
  213. return "'" . $obj . "'";
  214. } else if (is_numeric($obj)) {
  215. return $obj;
  216. } else if (is_null($obj)) {
  217. return 'null';
  218. } else if (is_bool($obj)) {
  219. return $obj ? 'true' : 'false';
  220. } else if (is_array($obj)) {
  221. return _repl_array($obj, $deep);
  222. }else {
  223. return gettype($obj);
  224. }
  225. }
  226. function _diff($gpath, $got, $epath, $expected) {
  227. return array(
  228. 'gpath' => $gpath,
  229. 'got' => $got,
  230. 'epath' => $epath,
  231. 'expected' => $expected
  232. );
  233. }
  234. function _idx($obj, $path = '') {
  235. return $path . '[' . _repl($obj) . ']';
  236. }
  237. function _cmp_deeply($got, $exp, $path = '') {
  238. if (is_array($exp)) {
  239. if (!is_array($got)) {
  240. return _diff($path, _repl($got), $path, _repl($exp));
  241. }
  242. $gk = array_keys($got);
  243. $ek = array_keys($exp);
  244. $mc = max(count($gk), count($ek));
  245. for ($el = 0; $el < $mc; $el++) {
  246. # One array shorter than the other?
  247. if ($el >= count($ek)) {
  248. return _diff(_idx($gk[$el], $path), _repl($got[$gk[$el]]),
  249. 'missing', 'nothing');
  250. } else if ($el >= count($gk)) {
  251. return _diff('missing', 'nothing',
  252. _idx($ek[$el], $path), _repl($exp[$ek[$el]]));
  253. }
  254. # Keys differ?
  255. if ($gk[$el] != $ek[$el]) {
  256. return _diff(_idx($gk[$el], $path), _repl($got[$gk[$el]]),
  257. _idx($ek[$el], $path), _repl($exp[$ek[$el]]));
  258. }
  259. # Recurse
  260. $rc = _cmp_deeply($got[$gk[$el]], $exp[$ek[$el]], _idx($gk[$el], $path));
  261. if (!is_null($rc)) {
  262. return $rc;
  263. }
  264. }
  265. }
  266. else {
  267. # Default to serialize hack
  268. if (serialize($got) != serialize($exp)) {
  269. return _diff($path, _repl($got), $path, _repl($exp));
  270. }
  271. }
  272. return null;
  273. }
  274. function _plural($n, $singular, $plural = null) {
  275. if (is_null($plural)) {
  276. $plural = $singular . 's';
  277. }
  278. return $n == 1 ? "$n $singular" : "$n $plural";
  279. }
  280. function _repl_array($obj, $deep) {
  281. if ($deep) {
  282. $slice = array_slice($obj, 0, 3); # Increase from 3 to show more
  283. $repl = array();
  284. $next = 0;
  285. foreach ($slice as $idx => $el) {
  286. $elrep = _repl($el, false);
  287. if (is_numeric($idx) && $next == $idx) {
  288. // Numeric index
  289. $next++;
  290. } else {
  291. // Out of sequence or non-numeric
  292. $elrep = _repl($idx, false) . ' => ' . $elrep;
  293. }
  294. $repl[] = $elrep;
  295. }
  296. $more = count($obj) - count($slice);
  297. if ($more > 0) {
  298. $repl[] = '... ' . _plural($more, 'more element') . ' ...';
  299. }
  300. return 'array(' . join(', ', $repl) . ')';
  301. }
  302. else {
  303. return 'array(' . count($obj) . ')';
  304. }
  305. }
  306. /*
  307. =head1 NAME
  308. Test.php - TAP test framework for PHP with a L<Test::More>-like interface
  309. =head1 SYNOPSIS
  310. #!/usr/bin/env php
  311. <?php
  312. require 'Test.php';
  313. plan($num); # plan $num tests
  314. # or
  315. plan('no_plan'); # We don't know how many
  316. # or
  317. plan('skip_all'); # Skip all tests
  318. # or
  319. plan('skip_all', $reason); # Skip all tests with a reason
  320. diag('message in test output') # Trailing \n not required
  321. # $test_name is always optional and should be a short description of
  322. # the test, e.g. "some_function() returns an integer"
  323. # Various ways to say "ok"
  324. ok($got == $expected, $test_name);
  325. # Compare with == and !=
  326. is($got, $expected, $test_name);
  327. isnt($got, $expected, $test_name);
  328. # Run a preg regex match on some data
  329. like($got, $regex, $test_name);
  330. unlike($got, $regex, $test_name);
  331. # Compare something with a given comparison operator
  332. cmp_ok($got, '==', $expected, $test_name);
  333. # Compare something with a comparison function (should return bool)
  334. cmp_ok($got, $func, $expected, $test_name);
  335. # Recursively check datastructures for equalness
  336. is_deeply($got, $expected, $test_name);
  337. # Always pass or fail a test under an optional name
  338. pass($test_name);
  339. fail($test_name);
  340. # TODO tests, these are expected to fail but won't fail the test run,
  341. # unexpected success will be reported
  342. todo_start("integer arithmetic still working");
  343. ok(1 + 2 == 3);
  344. {
  345. # TODOs can be nested
  346. todo_start("string comparison still working")
  347. is("foo", "bar");
  348. todo_end();
  349. }
  350. todo_end();
  351. ?>
  352. =head1 DESCRIPTION
  353. F<Test.php> is an implementation of Perl's L<Test::More> for PHP. Like
  354. Test::More it produces language agnostic TAP output (see L<TAP>) which
  355. can then be gathered, formatted and summarized by a program that
  356. understands TAP such as prove(1).
  357. =head1 HOWTO
  358. First place the F<Test.php> in the project root or somewhere else in
  359. the include path where C<require> and C<include> will find it.
  360. Then make a place to put your tests in, it's customary to place TAP
  361. tests in a directory named F<t> under the root but they can be
  362. anywhere you like. Make a test in this directory or one of its subdirs
  363. and try running it with php(1):
  364. $ php t/pass.t
  365. 1..1
  366. ok 1 This dummy test passed
  367. The TAP output consists of very simple output, of course reading
  368. larger output is going to be harder which is where prove(1) comes
  369. in. prove is a harness program that reads test output and produces
  370. reports based on it:
  371. $ prove t/pass.t
  372. t/pass....ok
  373. All tests successful.
  374. Files=1, Tests=1, 0 wallclock secs ( 0.03 cusr + 0.02 csys = 0.05 CPU)
  375. To run all the tests in the F<t> directory recursively use C<prove -r
  376. t>. This can be put in a F<Makefile> under a I<test> target, for
  377. example:
  378. test: Test.php
  379. prove -r t
  380. For reference the example test file above looks like this, the shebang
  381. on the first line is needed so that prove(1) and other test harness
  382. programs know they're dealing with a PHP file.
  383. #!/usr/bin/env php
  384. <?php
  385. require 'Test.php';
  386. plan(1);
  387. pass('This dummy test passed');
  388. ?>
  389. =head1 SEE ALSO
  390. L<TAP> - The TAP protocol
  391. =head1 AUTHOR
  392. E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@cpan.org> and Andy Armstrong <andy@hexten.net>
  393. =head1 LICENSING
  394. The author or authors of this code dedicate any and all copyright
  395. interest in this code to the public domain. We make this dedication
  396. for the benefit of the public at large and to the detriment of our
  397. heirs and successors. We intend this dedication to be an overt act of
  398. relinquishment in perpetuity of all present and future rights this
  399. code under copyright law.
  400. =cut
  401. */