/package/app/app/symfony/vendor/lime/lime.php

https://bitbucket.org/pandaos/kaltura · PHP · 933 lines · 822 code · 93 blank · 18 comment · 84 complexity · 200478c519f97c165441d031daba8cd6 MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the symfony package.
  4. * (c) 2004-2006 Fabien Potencier <fabien.potencier@gmail.com>
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * Unit test library.
  11. *
  12. * @package lime
  13. * @author Fabien Potencier <fabien.potencier@gmail.com>
  14. * @version SVN: $Id: lime.php 3298 2007-01-17 06:08:15Z fabien $
  15. */
  16. class lime_test
  17. {
  18. public $plan = null;
  19. public $test_nb = 0;
  20. public $failed = 0;
  21. public $passed = 0;
  22. public $skipped = 0;
  23. public $output = null;
  24. function __construct($plan = null, $output_instance = null)
  25. {
  26. $this->plan = $plan;
  27. $this->output = $output_instance ? $output_instance : new lime_output();
  28. null !== $this->plan and $this->output->echoln(sprintf("1..%d", $this->plan));
  29. }
  30. function __destruct()
  31. {
  32. $total = $this->passed + $this->failed + $this->skipped;
  33. null === $this->plan and $this->plan = $total and $this->output->echoln(sprintf("1..%d", $this->plan));
  34. if ($total > $this->plan)
  35. {
  36. $this->output->diag(sprintf("Looks like you planned %d tests but ran %d extra.", $this->plan, $total - $this->plan));
  37. }
  38. elseif ($total < $this->plan)
  39. {
  40. $this->output->diag(sprintf("Looks like you planned %d tests but only ran %d.", $this->plan, $total));
  41. }
  42. if ($this->failed)
  43. {
  44. $this->output->diag(sprintf("Looks like you failed %d tests of %d.", $this->failed, $this->plan));
  45. }
  46. flush();
  47. }
  48. function ok($exp, $message = '')
  49. {
  50. if ($result = (boolean) $exp)
  51. {
  52. ++$this->passed;
  53. }
  54. else
  55. {
  56. ++$this->failed;
  57. }
  58. $this->output->echoln(sprintf("%s %d%s", $result ? 'ok' : 'not ok', ++$this->test_nb, $message = $message ? sprintf('%s %s', 0 === strpos($message, '#') ? '' : ' -', $message) : ''));
  59. if (!$result)
  60. {
  61. $traces = debug_backtrace();
  62. if ($_SERVER['PHP_SELF'])
  63. {
  64. $i = strstr($traces[0]['file'], $_SERVER['PHP_SELF']) ? 0 : 1;
  65. }
  66. else
  67. {
  68. $i = 0;
  69. }
  70. $this->output->diag(sprintf(' Failed test (%s at line %d)', str_replace(getcwd(), '.', $traces[$i]['file']), $traces[$i]['line']));
  71. }
  72. return $result;
  73. }
  74. function is($exp1, $exp2, $message = '')
  75. {
  76. if (is_object($exp1) || is_object($exp2))
  77. {
  78. $value = $exp1 === $exp2;
  79. }
  80. else
  81. {
  82. $value = $exp1 == $exp2;
  83. }
  84. if (!$result = $this->ok($value, $message))
  85. {
  86. $this->output->diag(sprintf(" got: %s", str_replace("\n", '', var_export($exp1, true))), sprintf(" expected: %s", str_replace("\n", '', var_export($exp2, true))));
  87. }
  88. return $result;
  89. }
  90. function isnt($exp1, $exp2, $message = '')
  91. {
  92. if (!$result = $this->ok($exp1 != $exp2, $message))
  93. {
  94. $this->output->diag(sprintf(" %s", str_replace("\n", '', var_export($exp1, true))), ' ne', sprintf(" %s", str_replace("\n", '', var_export($exp2, true))));
  95. }
  96. return $result;
  97. }
  98. function like($exp, $regex, $message = '')
  99. {
  100. if (!$result = $this->ok(preg_match($regex, $exp), $message))
  101. {
  102. $this->output->diag(sprintf(" '%s'", $exp), sprintf(" doesn't match '%s'", $regex));
  103. }
  104. return $result;
  105. }
  106. function unlike($exp, $regex, $message = '')
  107. {
  108. if (!$result = $this->ok(!preg_match($regex, $exp), $message))
  109. {
  110. $this->output->diag(sprintf(" '%s'", $exp), sprintf(" matches '%s'", $regex));
  111. }
  112. return $result;
  113. }
  114. function cmp_ok($exp1, $op, $exp2, $message = '')
  115. {
  116. eval(sprintf("\$result = \$exp1 $op \$exp2;"));
  117. if (!$this->ok($result, $message))
  118. {
  119. $this->output->diag(sprintf(" %s", str_replace("\n", '', var_export($exp1, true))), sprintf(" %s", $op), sprintf(" %s", str_replace("\n", '', var_export($exp2, true))));
  120. }
  121. return $result;
  122. }
  123. function can_ok($object, $methods, $message = '')
  124. {
  125. $result = true;
  126. $failed_messages = array();
  127. foreach ((array) $methods as $method)
  128. {
  129. if (!method_exists($object, $method))
  130. {
  131. $failed_messages[] = sprintf(" method '%s' does not exist", $method);
  132. $result = false;
  133. }
  134. }
  135. !$this->ok($result, $message);
  136. !$result and $this->output->diag($failed_messages);
  137. return $result;
  138. }
  139. function isa_ok($var, $class, $message = '')
  140. {
  141. $type = is_object($var) ? get_class($var) : gettype($var);
  142. if (!$result = $this->ok($type == $class, $message))
  143. {
  144. $this->output->diag(sprintf(" isa_ok isn't a '%s' it's a '%s'", $class, $type));
  145. }
  146. return $result;
  147. }
  148. function is_deeply($exp1, $exp2, $message = '')
  149. {
  150. if (!$result = $this->ok($this->test_is_deeply($exp1, $exp2), $message))
  151. {
  152. $this->output->diag(sprintf(" got: %s", str_replace("\n", '', var_export($exp1, true))), sprintf(" expected: %s", str_replace("\n", '', var_export($exp2, true))));
  153. }
  154. return $result;
  155. }
  156. function pass($message = '')
  157. {
  158. return $this->ok(true, $message);
  159. }
  160. function fail($message = '')
  161. {
  162. return $this->ok(false, $message);
  163. }
  164. function diag($message)
  165. {
  166. $this->output->diag($message);
  167. }
  168. function skip($message = '', $nb_tests = 1)
  169. {
  170. for ($i = 0; $i < $nb_tests; $i++)
  171. {
  172. ++$this->skipped and --$this->passed;
  173. $this->pass(sprintf("# SKIP%s", $message ? ' '.$message : ''));
  174. }
  175. }
  176. function todo($message = '')
  177. {
  178. ++$this->skipped and --$this->passed;
  179. $this->pass(sprintf("# TODO%s", $message ? ' '.$message : ''));
  180. }
  181. function include_ok($file, $message = '')
  182. {
  183. if (!$result = $this->ok((@include($file)) == 1, $message))
  184. {
  185. $this->output->diag(sprintf(" Tried to include '%s'", $file));
  186. }
  187. return $result;
  188. }
  189. private function test_is_deeply($var1, $var2)
  190. {
  191. if (gettype($var1) != gettype($var2))
  192. {
  193. return false;
  194. }
  195. if (is_array($var1))
  196. {
  197. ksort($var1);
  198. ksort($var2);
  199. if (array_diff(array_keys($var1), array_keys($var2)))
  200. {
  201. return false;
  202. }
  203. $is_equal = true;
  204. foreach ($var1 as $key => $value)
  205. {
  206. $is_equal = $this->test_is_deeply($var1[$key], $var2[$key]);
  207. if ($is_equal === false)
  208. {
  209. break;
  210. }
  211. }
  212. return $is_equal;
  213. }
  214. else
  215. {
  216. return $var1 === $var2;
  217. }
  218. }
  219. function comment($message)
  220. {
  221. $this->output->comment($message);
  222. }
  223. static function get_temp_directory()
  224. {
  225. if ('\\' == DIRECTORY_SEPARATOR)
  226. {
  227. foreach (array('TEMP', 'TMP', 'windir') as $dir)
  228. {
  229. if ($var = isset($_ENV[$dir]) ? $_ENV[$dir] : getenv($dir))
  230. {
  231. return $var;
  232. }
  233. }
  234. return getenv('SystemRoot').'\temp';
  235. }
  236. if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR'))
  237. {
  238. return $var;
  239. }
  240. return '/tmp';
  241. }
  242. }
  243. class lime_output
  244. {
  245. function diag()
  246. {
  247. $messages = func_get_args();
  248. foreach ($messages as $message)
  249. {
  250. array_map(array($this, 'comment'), (array) $message);
  251. }
  252. }
  253. function comment($message)
  254. {
  255. echo "# $message\n";
  256. }
  257. function echoln($message)
  258. {
  259. echo "$message\n";
  260. }
  261. }
  262. class lime_output_color extends lime_output
  263. {
  264. public $colorizer = null;
  265. function __construct()
  266. {
  267. $this->colorizer = new lime_colorizer();
  268. }
  269. function diag()
  270. {
  271. $messages = func_get_args();
  272. foreach ($messages as $message)
  273. {
  274. echo $this->colorizer->colorize('# '.join("\n# ", (array) $message), 'COMMENT')."\n";
  275. }
  276. }
  277. function comment($message)
  278. {
  279. echo $this->colorizer->colorize(sprintf('# %s', $message), 'COMMENT')."\n";
  280. }
  281. function echoln($message, $colorizer_parameter = null)
  282. {
  283. $message = preg_replace('/(?:^|\.)((?:not ok|dubious) *\d*)\b/e', '$this->colorizer->colorize(\'$1\', \'ERROR\')', $message);
  284. $message = preg_replace('/(?:^|\.)(ok *\d*)\b/e', '$this->colorizer->colorize(\'$1\', \'INFO\')', $message);
  285. $message = preg_replace('/"(.+?)"/e', '$this->colorizer->colorize(\'$1\', \'PARAMETER\')', $message);
  286. $message = preg_replace('/(\->|\:\:)?([a-zA-Z0-9_]+?)\(\)/e', '$this->colorizer->colorize(\'$1$2()\', \'PARAMETER\')', $message);
  287. echo ($colorizer_parameter ? $this->colorizer->colorize($message, $colorizer_parameter) : $message)."\n";
  288. }
  289. }
  290. class lime_colorizer
  291. {
  292. static public $styles = array();
  293. static function style($name, $options = array())
  294. {
  295. self::$styles[$name] = $options;
  296. }
  297. static function colorize($text = '', $parameters = array())
  298. {
  299. // disable colors if not supported (windows or non tty console)
  300. if (DIRECTORY_SEPARATOR == '\\' || !function_exists('posix_isatty') || !@posix_isatty(STDOUT))
  301. {
  302. return $text;
  303. }
  304. static $options = array('bold' => 1, 'underscore' => 4, 'blink' => 5, 'reverse' => 7, 'conceal' => 8);
  305. static $foreground = array('black' => 30, 'red' => 31, 'green' => 32, 'yellow' => 33, 'blue' => 34, 'magenta' => 35, 'cyan' => 36, 'white' => 37);
  306. static $background = array('black' => 40, 'red' => 41, 'green' => 42, 'yellow' => 43, 'blue' => 44, 'magenta' => 45, 'cyan' => 46, 'white' => 47);
  307. !is_array($parameters) && isset(self::$styles[$parameters]) and $parameters = self::$styles[$parameters];
  308. $codes = array();
  309. isset($parameters['fg']) and $codes[] = $foreground[$parameters['fg']];
  310. isset($parameters['bg']) and $codes[] = $background[$parameters['bg']];
  311. foreach ($options as $option => $value)
  312. {
  313. isset($parameters[$option]) && $parameters[$option] and $codes[] = $value;
  314. }
  315. return "\033[".implode(';', $codes).'m'.$text."\033[0m";
  316. }
  317. }
  318. lime_colorizer::style('ERROR', array('bg' => 'red', 'fg' => 'white', 'bold' => true));
  319. lime_colorizer::style('INFO', array('fg' => 'green', 'bold' => true));
  320. lime_colorizer::style('PARAMETER', array('fg' => 'cyan'));
  321. lime_colorizer::style('COMMENT', array('fg' => 'yellow'));
  322. class lime_harness extends lime_registration
  323. {
  324. public $php_cli = '';
  325. public $stats = array();
  326. public $output = null;
  327. function __construct($output_instance, $php_cli = null)
  328. {
  329. $this->php_cli = null === $php_cli ? PHP_BINDIR.DIRECTORY_SEPARATOR.'php' : $php_cli;
  330. if (!is_executable($this->php_cli))
  331. {
  332. $this->php_cli = $this->find_php_cli();
  333. }
  334. $this->output = $output_instance ? $output_instance : new lime_output();
  335. }
  336. protected function find_php_cli()
  337. {
  338. $path = getenv('PATH') ? getenv('PATH') : getenv('Path');
  339. $exe_suffixes = DIRECTORY_SEPARATOR == '\\' ? (getenv('PATHEXT') ? explode(PATH_SEPARATOR, getenv('PATHEXT')) : array('.exe', '.bat', '.cmd', '.com')) : array('');
  340. foreach (array('php5', 'php') as $php_cli)
  341. {
  342. foreach ($exe_suffixes as $suffix)
  343. {
  344. foreach (explode(PATH_SEPARATOR, $path) as $dir)
  345. {
  346. $file = $dir.DIRECTORY_SEPARATOR.$php_cli.$suffix;
  347. if (is_executable($file))
  348. {
  349. return $file;
  350. }
  351. }
  352. }
  353. }
  354. throw new Exception("Unable to find PHP executable.");
  355. }
  356. function run()
  357. {
  358. if (!count($this->files))
  359. {
  360. throw new Exception('You must register some test files before running them!');
  361. }
  362. // sort the files to be able to predict the order
  363. sort($this->files);
  364. $this->stats =array(
  365. '_failed_files' => array(),
  366. '_failed_tests' => 0,
  367. '_nb_tests' => 0,
  368. );
  369. foreach ($this->files as $file)
  370. {
  371. $this->stats[$file] = array(
  372. 'plan' => null,
  373. 'nb_tests' => 0,
  374. 'failed' => array(),
  375. 'passed' => array(),
  376. );
  377. $this->current_file = $file;
  378. $this->current_test = 0;
  379. $relative_file = $this->get_relative_file($file);
  380. ob_start(array($this, 'process_test_output'));
  381. passthru(sprintf('%s -d html_errors=off -d open_basedir= -q "%s" 2>&1', $this->php_cli, $file), $return);
  382. ob_end_clean();
  383. if ($return > 0)
  384. {
  385. $this->stats[$file]['status'] = 'dubious';
  386. $this->stats[$file]['status_code'] = $return;
  387. }
  388. else
  389. {
  390. $delta = $this->stats[$file]['plan'] - $this->stats[$file]['nb_tests'];
  391. if ($delta > 0)
  392. {
  393. $this->output->echoln(sprintf('%s%s%s', substr($relative_file, -67), str_repeat('.', 70 - min(67, strlen($relative_file))), $this->output->colorizer->colorize(sprintf('# Looks like you planned %d tests but only ran %d.', $this->stats[$file]['plan'], $this->stats[$file]['nb_tests']), 'COMMENT')));
  394. $this->stats[$file]['status'] = 'dubious';
  395. $this->stats[$file]['status_code'] = 255;
  396. $this->stats['_nb_tests'] += $delta;
  397. for ($i = 1; $i <= $delta; $i++)
  398. {
  399. $this->stats[$file]['failed'][] = $this->stats[$file]['nb_tests'] + $i;
  400. }
  401. }
  402. else if ($delta < 0)
  403. {
  404. $this->output->echoln(sprintf('%s%s%s', substr($relative_file, -67), str_repeat('.', 70 - min(67, strlen($relative_file))), $this->output->colorizer->colorize(sprintf('# Looks like you planned %s test but ran %s extra.', $this->stats[$file]['plan'], $this->stats[$file]['nb_tests'] - $this->stats[$file]['plan']), 'COMMENT')));
  405. $this->stats[$file]['status'] = 'dubious';
  406. $this->stats[$file]['status_code'] = 255;
  407. for ($i = 1; $i <= -$delta; $i++)
  408. {
  409. $this->stats[$file]['failed'][] = $this->stats[$file]['plan'] + $i;
  410. }
  411. }
  412. else
  413. {
  414. $this->stats[$file]['status_code'] = 0;
  415. $this->stats[$file]['status'] = $this->stats[$file]['failed'] ? 'not ok' : 'ok';
  416. }
  417. }
  418. $this->output->echoln(sprintf('%s%s%s', substr($relative_file, -67), str_repeat('.', 70 - min(67, strlen($relative_file))), $this->stats[$file]['status']));
  419. if (($nb = count($this->stats[$file]['failed'])) || $return > 0)
  420. {
  421. if ($nb)
  422. {
  423. $this->output->echoln(sprintf(" Failed tests: %s", implode(', ', $this->stats[$file]['failed'])));
  424. }
  425. $this->stats['_failed_files'][] = $file;
  426. $this->stats['_failed_tests'] += $nb;
  427. }
  428. if ('dubious' == $this->stats[$file]['status'])
  429. {
  430. $this->output->echoln(sprintf(' Test returned status %s', $this->stats[$file]['status_code']));
  431. }
  432. }
  433. if (count($this->stats['_failed_files']))
  434. {
  435. $format = "%-30s %4s %5s %5s %s";
  436. $this->output->echoln(sprintf($format, 'Failed Test', 'Stat', 'Total', 'Fail', 'List of Failed'));
  437. $this->output->echoln("------------------------------------------------------------------");
  438. foreach ($this->stats as $file => $file_stat)
  439. {
  440. if (!in_array($file, $this->stats['_failed_files'])) continue;
  441. $this->output->echoln(sprintf($format, substr($this->get_relative_file($file), -30), $file_stat['status_code'], count($file_stat['failed']) + count($file_stat['passed']), count($file_stat['failed']), implode(' ', $file_stat['failed'])));
  442. }
  443. $this->output->echoln(sprintf('Failed %d/%d test scripts, %.2f%% okay. %d/%d subtests failed, %.2f%% okay.',
  444. $nb_failed_files = count($this->stats['_failed_files']),
  445. $nb_files = count($this->files),
  446. ($nb_files - $nb_failed_files) * 100 / $nb_files,
  447. $nb_failed_tests = $this->stats['_failed_tests'],
  448. $nb_tests = $this->stats['_nb_tests'],
  449. $nb_tests > 0 ? ($nb_tests - $nb_failed_tests) * 100 / $nb_tests : 0
  450. ), 'ERROR');
  451. }
  452. else
  453. {
  454. $this->output->echoln('All tests successful.', 'INFO');
  455. $this->output->echoln(sprintf('Files=%d, Tests=%d', count($this->files), $this->stats['_nb_tests']), 'INFO');
  456. }
  457. return $this->stats['_failed_tests'] ? false : true;
  458. }
  459. private function process_test_output($lines)
  460. {
  461. foreach (explode("\n", $lines) as $text)
  462. {
  463. if (false !== strpos($text, 'not ok '))
  464. {
  465. ++$this->current_test;
  466. $test_number = (int) substr($text, 7);
  467. $this->stats[$this->current_file]['failed'][] = $test_number;
  468. ++$this->stats[$this->current_file]['nb_tests'];
  469. ++$this->stats['_nb_tests'];
  470. }
  471. else if (false !== strpos($text, 'ok '))
  472. {
  473. ++$this->stats[$this->current_file]['nb_tests'];
  474. ++$this->stats['_nb_tests'];
  475. }
  476. else if (preg_match('/^1\.\.(\d+)/', $text, $match))
  477. {
  478. $this->stats[$this->current_file]['plan'] = $match[1];
  479. }
  480. }
  481. return;
  482. }
  483. }
  484. class lime_coverage extends lime_registration
  485. {
  486. public $files = array();
  487. public $extension = '.php';
  488. public $base_dir = '';
  489. public $harness = null;
  490. public $verbose = false;
  491. function __construct($harness)
  492. {
  493. $this->harness = $harness;
  494. }
  495. function run()
  496. {
  497. if (!function_exists('xdebug_start_code_coverage'))
  498. {
  499. throw new Exception('You must install and enable xdebug before using lime coverage.');
  500. }
  501. if (!count($this->harness->files))
  502. {
  503. throw new Exception('You must register some test files before running coverage!');
  504. }
  505. if (!count($this->files))
  506. {
  507. throw new Exception('You must register some files to cover!');
  508. }
  509. $coverage = array();
  510. $tmp_file = lime_test::get_temp_directory().DIRECTORY_SEPARATOR.'test.php';
  511. foreach ($this->harness->files as $file)
  512. {
  513. $tmp = <<<EOF
  514. <?php
  515. xdebug_start_code_coverage();
  516. ob_start();
  517. include('$file');
  518. ob_end_clean();
  519. echo '<PHP_SER>'.serialize(xdebug_get_code_coverage()).'</PHP_SER>';
  520. EOF;
  521. file_put_contents($tmp_file, $tmp);
  522. ob_start();
  523. passthru(sprintf('%s -d html_errors=off -d open_basedir= -q "%s" 2>&1', $this->harness->php_cli, $tmp_file), $return);
  524. $retval = ob_get_clean();
  525. if (0 == $return)
  526. {
  527. if (false === $cov = unserialize(substr($retval, strpos($retval, '<PHP_SER>') + 9, strpos($retval, '</PHP_SER>') - 9)))
  528. {
  529. throw new Exception(sprintf('Unable to unserialize coverage for file "%s"', $file));
  530. }
  531. foreach ($cov as $file => $lines)
  532. {
  533. if (!isset($coverage[$file]))
  534. {
  535. $coverage[$file] = array();
  536. }
  537. foreach ($lines as $line => $count)
  538. {
  539. if (!isset($coverage[$file][$line]))
  540. {
  541. $coverage[$file][$line] = 0;
  542. }
  543. $coverage[$file][$line] = $coverage[$file][$line] + $count;
  544. }
  545. }
  546. }
  547. }
  548. unlink($tmp_file);
  549. ksort($coverage);
  550. $total_php_lines = 0;
  551. $total_covered_lines = 0;
  552. foreach ($this->files as $file)
  553. {
  554. $cov = isset($coverage[$file]) ? $coverage[$file] : array();
  555. list($cov, $php_lines) = $this->compute(file_get_contents($file), $cov);
  556. $output = $this->harness->output;
  557. $percent = count($php_lines) ? count($cov) * 100 / count($php_lines) : 100;
  558. $total_php_lines += count($php_lines);
  559. $total_covered_lines += count($cov);
  560. $output->echoln(sprintf("%-70s %3.0f%%", substr($this->get_relative_file($file), -70), $percent), $percent == 100 ? 'INFO' : ($percent > 90 ? 'PARAMETER' : ($percent < 20 ? 'ERROR' : '')));
  561. if ($this->verbose && $percent != 100)
  562. {
  563. $output->comment(sprintf("missing: %s", $this->format_range(array_keys(array_diff_key($php_lines, $cov)))));
  564. }
  565. }
  566. $output->echoln(sprintf("TOTAL COVERAGE: %3.0f%%", $total_covered_lines * 100 / $total_php_lines));
  567. }
  568. static function get_php_lines($content)
  569. {
  570. if (is_file($content))
  571. {
  572. $content = file_get_contents($content);
  573. }
  574. $tokens = token_get_all($content);
  575. $php_lines = array();
  576. $current_line = 1;
  577. $in_class = false;
  578. $in_function = false;
  579. $in_function_declaration = false;
  580. $end_of_current_expr = true;
  581. $open_braces = 0;
  582. foreach ($tokens as $token)
  583. {
  584. if (is_string($token))
  585. {
  586. switch ($token)
  587. {
  588. case '=':
  589. if (false === $in_class || (false !== $in_function && !$in_function_declaration))
  590. {
  591. $php_lines[$current_line] = true;
  592. }
  593. break;
  594. case '{':
  595. ++$open_braces;
  596. $in_function_declaration = false;
  597. break;
  598. case ';':
  599. $in_function_declaration = false;
  600. $end_of_current_expr = true;
  601. break;
  602. case '}':
  603. $end_of_current_expr = true;
  604. --$open_braces;
  605. if ($open_braces == $in_class)
  606. {
  607. $in_class = false;
  608. }
  609. if ($open_braces == $in_function)
  610. {
  611. $in_function = false;
  612. }
  613. break;
  614. }
  615. continue;
  616. }
  617. list($id, $text) = $token;
  618. switch ($id)
  619. {
  620. case T_CURLY_OPEN:
  621. case T_DOLLAR_OPEN_CURLY_BRACES:
  622. ++$open_braces;
  623. break;
  624. case T_WHITESPACE:
  625. case T_OPEN_TAG:
  626. case T_CLOSE_TAG:
  627. $end_of_current_expr = true;
  628. $current_line += count(explode("\n", $text)) - 1;
  629. break;
  630. case T_COMMENT:
  631. case T_DOC_COMMENT:
  632. $current_line += count(explode("\n", $text)) - 1;
  633. break;
  634. case T_CLASS:
  635. $in_class = $open_braces;
  636. break;
  637. case T_FUNCTION:
  638. $in_function = $open_braces;
  639. $in_function_declaration = true;
  640. break;
  641. case T_AND_EQUAL:
  642. case T_CASE:
  643. case T_CATCH:
  644. case T_CLONE:
  645. case T_CONCAT_EQUAL:
  646. case T_CONTINUE:
  647. case T_DEC:
  648. case T_DECLARE:
  649. case T_DEFAULT:
  650. case T_DIV_EQUAL:
  651. case T_DO:
  652. case T_ECHO:
  653. case T_ELSEIF:
  654. case T_EMPTY:
  655. case T_ENDDECLARE:
  656. case T_ENDFOR:
  657. case T_ENDFOREACH:
  658. case T_ENDIF:
  659. case T_ENDSWITCH:
  660. case T_ENDWHILE:
  661. case T_EVAL:
  662. case T_EXIT:
  663. case T_FOR:
  664. case T_FOREACH:
  665. case T_GLOBAL:
  666. case T_IF:
  667. case T_INC:
  668. case T_INCLUDE:
  669. case T_INCLUDE_ONCE:
  670. case T_INSTANCEOF:
  671. case T_ISSET:
  672. case T_IS_EQUAL:
  673. case T_IS_GREATER_OR_EQUAL:
  674. case T_IS_IDENTICAL:
  675. case T_IS_NOT_EQUAL:
  676. case T_IS_NOT_IDENTICAL:
  677. case T_IS_SMALLER_OR_EQUAL:
  678. case T_LIST:
  679. case T_LOGICAL_AND:
  680. case T_LOGICAL_OR:
  681. case T_LOGICAL_XOR:
  682. case T_MINUS_EQUAL:
  683. case T_MOD_EQUAL:
  684. case T_MUL_EQUAL:
  685. case T_NEW:
  686. case T_OBJECT_OPERATOR:
  687. case T_OR_EQUAL:
  688. case T_PLUS_EQUAL:
  689. case T_PRINT:
  690. case T_REQUIRE:
  691. case T_REQUIRE_ONCE:
  692. case T_RETURN:
  693. case T_SL:
  694. case T_SL_EQUAL:
  695. case T_SR:
  696. case T_SR_EQUAL:
  697. case T_THROW:
  698. case T_TRY:
  699. case T_UNSET:
  700. case T_UNSET_CAST:
  701. case T_USE:
  702. case T_WHILE:
  703. case T_XOR_EQUAL:
  704. $php_lines[$current_line] = true;
  705. $end_of_current_expr = false;
  706. break;
  707. default:
  708. if (false === $end_of_current_expr)
  709. {
  710. $php_lines[$current_line] = true;
  711. }
  712. //print "$current_line: ".token_name($id)."\n";
  713. }
  714. }
  715. return $php_lines;
  716. }
  717. function compute($content, $cov)
  718. {
  719. $php_lines = self::get_php_lines($content);
  720. // we remove from $cov non php lines
  721. foreach (array_diff_key($cov, $php_lines) as $line => $tmp)
  722. {
  723. unset($cov[$line]);
  724. }
  725. return array($cov, $php_lines);
  726. }
  727. function format_range($lines)
  728. {
  729. sort($lines);
  730. $formatted = '';
  731. $first = -1;
  732. $last = -1;
  733. foreach ($lines as $line)
  734. {
  735. if ($last + 1 != $line)
  736. {
  737. if ($first != -1)
  738. {
  739. $formatted .= $first == $last ? "$first " : "[$first - $last] ";
  740. }
  741. $first = $line;
  742. $last = $line;
  743. }
  744. else
  745. {
  746. $last = $line;
  747. }
  748. }
  749. if ($first != -1)
  750. {
  751. $formatted .= $first == $last ? "$first " : "[$first - $last] ";
  752. }
  753. return $formatted;
  754. }
  755. }
  756. class lime_registration
  757. {
  758. public $files = array();
  759. public $extension = '.php';
  760. public $base_dir = '';
  761. function register($files_or_directories)
  762. {
  763. foreach ((array) $files_or_directories as $f_or_d)
  764. {
  765. if (is_file($f_or_d))
  766. {
  767. $this->files[] = realpath($f_or_d);
  768. }
  769. elseif (is_dir($f_or_d))
  770. {
  771. $this->register_dir($f_or_d);
  772. }
  773. else
  774. {
  775. throw new Exception(sprintf('The file or directory "%s" does not exist.', $f_or_d));
  776. }
  777. }
  778. }
  779. function register_glob($glob)
  780. {
  781. if ($dirs = glob($glob))
  782. {
  783. foreach ($dirs as $file)
  784. {
  785. $this->files[] = realpath($file);
  786. }
  787. }
  788. }
  789. function register_dir($directory)
  790. {
  791. if (!is_dir($directory))
  792. {
  793. throw new Exception(sprintf('The directory "%s" does not exist.', $directory));
  794. }
  795. $files = array();
  796. $current_dir = opendir($directory);
  797. while ($entry = readdir($current_dir))
  798. {
  799. if ($entry == '.' || $entry == '..') continue;
  800. if (is_dir($entry))
  801. {
  802. $this->register_dir($entry);
  803. }
  804. elseif (preg_match('#'.$this->extension.'$#', $entry))
  805. {
  806. $files[] = realpath($directory.DIRECTORY_SEPARATOR.$entry);
  807. }
  808. }
  809. $this->files = array_merge($this->files, $files);
  810. }
  811. protected function get_relative_file($file)
  812. {
  813. return str_replace(DIRECTORY_SEPARATOR, '/', str_replace(array(realpath($this->base_dir).DIRECTORY_SEPARATOR, $this->extension), '', $file));
  814. }
  815. }