phpunit5-loggers.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. <?php
  2. // @codingStandardsIgnoreStart
  3. /*
  4. * This file is part of PHPUnit.
  5. *
  6. * (c) Sebastian Bergmann <sebastian@phpunit.de>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace {
  12. if (!class_exists('PHPUnit_Util_String')) {
  13. /**
  14. * String helpers.
  15. */
  16. class PHPUnit_Util_String
  17. {
  18. /**
  19. * Converts a string to UTF-8 encoding.
  20. *
  21. * @param string $string
  22. *
  23. * @return string
  24. */
  25. public static function convertToUtf8($string)
  26. {
  27. return mb_convert_encoding($string, 'UTF-8');
  28. }
  29. /**
  30. * Checks a string for UTF-8 encoding.
  31. *
  32. * @param string $string
  33. *
  34. * @return bool
  35. */
  36. protected static function isUtf8($string)
  37. {
  38. $length = strlen($string);
  39. for ($i = 0; $i < $length; $i++) {
  40. if (ord($string[$i]) < 0x80) {
  41. $n = 0;
  42. } elseif ((ord($string[$i]) & 0xE0) == 0xC0) {
  43. $n = 1;
  44. } elseif ((ord($string[$i]) & 0xF0) == 0xE0) {
  45. $n = 2;
  46. } elseif ((ord($string[$i]) & 0xF0) == 0xF0) {
  47. $n = 3;
  48. } else {
  49. return false;
  50. }
  51. for ($j = 0; $j < $n; $j++) {
  52. if ((++$i == $length) || ((ord($string[$i]) & 0xC0) != 0x80)) {
  53. return false;
  54. }
  55. }
  56. }
  57. return true;
  58. }
  59. }
  60. }
  61. }
  62. namespace PHPUnit\Util\Log {
  63. /*
  64. * This file is part of PHPUnit.
  65. *
  66. * (c) Sebastian Bergmann <sebastian@phpunit.de>
  67. *
  68. * For the full copyright and license information, please view the LICENSE
  69. * file that was distributed with this source code.
  70. */
  71. /**
  72. * A TestListener that generates JSON messages.
  73. */
  74. if (!class_exists('\PHPUnit\Util\Log\JSON')) {
  75. class JSON extends \PHPUnit\Util\Printer implements \PHPUnit\Framework\TestListener
  76. {
  77. /**
  78. * @var string
  79. */
  80. protected $currentTestSuiteName = '';
  81. /**
  82. * @var string
  83. */
  84. protected $currentTestName = '';
  85. /**
  86. * @var bool
  87. */
  88. protected $currentTestPass = true;
  89. /**
  90. * @var array
  91. */
  92. protected $logEvents = [];
  93. /**
  94. * An error occurred.
  95. *
  96. * @param \PHPUnit\Framework\Test $test
  97. * @param Exception $e
  98. * @param float $time
  99. */
  100. public function addError(\PHPUnit\Framework\Test $test, \Exception $e, $time)
  101. {
  102. $this->writeCase(
  103. 'error',
  104. $time,
  105. \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
  106. \PHPUnit\Framework\TestFailure::exceptionToString($e),
  107. $test
  108. );
  109. $this->currentTestPass = false;
  110. }
  111. /**
  112. * A warning occurred.
  113. *
  114. * @param \PHPUnit\Framework\Test $test
  115. * @param \PHPUnit\Framework\Warning $e
  116. * @param float $time
  117. */
  118. public function addWarning(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, $time)
  119. {
  120. $this->writeCase(
  121. 'warning',
  122. $time,
  123. \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
  124. \PHPUnit\Framework\TestFailure::exceptionToString($e),
  125. $test
  126. );
  127. $this->currentTestPass = false;
  128. }
  129. /**
  130. * A failure occurred.
  131. *
  132. * @param \PHPUnit\Framework\Test $test
  133. * @param \PHPUnit\Framework\AssertionFailedError $e
  134. * @param float $time
  135. */
  136. public function addFailure(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\AssertionFailedError $e, $time)
  137. {
  138. $this->writeCase(
  139. 'fail',
  140. $time,
  141. \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
  142. \PHPUnit\Framework\TestFailure::exceptionToString($e),
  143. $test
  144. );
  145. $this->currentTestPass = false;
  146. }
  147. /**
  148. * Incomplete test.
  149. *
  150. * @param \PHPUnit\Framework\Test $test
  151. * @param Exception $e
  152. * @param float $time
  153. */
  154. public function addIncompleteTest(\PHPUnit\Framework\Test $test, \Exception $e, $time)
  155. {
  156. $this->writeCase(
  157. 'error',
  158. $time,
  159. \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
  160. 'Incomplete Test: ' . $e->getMessage(),
  161. $test
  162. );
  163. $this->currentTestPass = false;
  164. }
  165. /**
  166. * Risky test.
  167. *
  168. * @param \PHPUnit\Framework\Test $test
  169. * @param Exception $e
  170. * @param float $time
  171. */
  172. public function addRiskyTest(\PHPUnit\Framework\Test $test, \Exception $e, $time)
  173. {
  174. $this->writeCase(
  175. 'error',
  176. $time,
  177. \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
  178. 'Risky Test: ' . $e->getMessage(),
  179. $test
  180. );
  181. $this->currentTestPass = false;
  182. }
  183. /**
  184. * Skipped test.
  185. *
  186. * @param \PHPUnit\Framework\Test $test
  187. * @param Exception $e
  188. * @param float $time
  189. */
  190. public function addSkippedTest(\PHPUnit\Framework\Test $test, \Exception $e, $time)
  191. {
  192. $this->writeCase(
  193. 'error',
  194. $time,
  195. \PHPUnit\Util\Filter::getFilteredStacktrace($e, false),
  196. 'Skipped Test: ' . $e->getMessage(),
  197. $test
  198. );
  199. $this->currentTestPass = false;
  200. }
  201. /**
  202. * A testsuite started.
  203. *
  204. * @param \PHPUnit\Framework\TestSuite $suite
  205. */
  206. public function startTestSuite(\PHPUnit\Framework\TestSuite $suite)
  207. {
  208. $this->currentTestSuiteName = $suite->getName();
  209. $this->currentTestName = '';
  210. $this->addLogEvent(
  211. [
  212. 'event' => 'suiteStart',
  213. 'suite' => $this->currentTestSuiteName,
  214. 'tests' => count($suite)
  215. ]
  216. );
  217. }
  218. /**
  219. * A testsuite ended.
  220. *
  221. * @param \PHPUnit\Framework\TestSuite $suite
  222. */
  223. public function endTestSuite(\PHPUnit\Framework\TestSuite $suite)
  224. {
  225. $this->currentTestSuiteName = '';
  226. $this->currentTestName = '';
  227. $this->writeAll($this->logEvents);
  228. }
  229. /**
  230. * A test started.
  231. *
  232. * @param \PHPUnit\Framework\Test $test
  233. */
  234. public function startTest(\PHPUnit\Framework\Test $test)
  235. {
  236. $this->currentTestName = \PHPUnit\Util\Test::describe($test);
  237. $this->currentTestPass = true;
  238. $this->addLogEvent(
  239. [
  240. 'event' => 'testStart',
  241. 'suite' => $this->currentTestSuiteName,
  242. 'test' => $this->currentTestName
  243. ]
  244. );
  245. }
  246. /**
  247. * A test ended.
  248. *
  249. * @param \PHPUnit\Framework\Test $test
  250. * @param float $time
  251. */
  252. public function endTest(\PHPUnit\Framework\Test $test, $time)
  253. {
  254. if ($this->currentTestPass) {
  255. $this->writeCase('pass', $time, [], '', $test);
  256. }
  257. }
  258. /**
  259. * @param string $status
  260. * @param float $time
  261. * @param array $trace
  262. * @param string $message
  263. * @param \PHPUnit\Framework\TestCase|null $test
  264. */
  265. protected function writeCase($status, $time, array $trace = [], $message = '', $test = null)
  266. {
  267. $output = '';
  268. // take care of TestSuite producing error (e.g. by running into exception) as TestSuite doesn't have hasOutput
  269. if ($test !== null && method_exists($test, 'hasOutput') && $test->hasOutput()) {
  270. $output = $test->getActualOutput();
  271. }
  272. $this->addLogEvent(
  273. [
  274. 'event' => 'test',
  275. 'suite' => $this->currentTestSuiteName,
  276. 'test' => $this->currentTestName,
  277. 'status' => $status,
  278. 'time' => $time,
  279. 'trace' => $trace,
  280. 'message' => \PHPUnit_Util_String::convertToUtf8($message),
  281. 'output' => $output,
  282. ]
  283. );
  284. }
  285. /**
  286. * @param array $event_data
  287. */
  288. protected function addLogEvent($event_data = [])
  289. {
  290. if (count($event_data)) {
  291. array_push($this->logEvents, $event_data);
  292. }
  293. }
  294. /**
  295. * @param array $buffer
  296. */
  297. public function writeAll($buffer)
  298. {
  299. array_walk_recursive(
  300. $buffer, function (&$input) {
  301. if (is_string($input)) {
  302. $input = \PHPUnit_Util_String::convertToUtf8($input);
  303. }
  304. }
  305. );
  306. parent::write(json_encode($buffer, JSON_PRETTY_PRINT));
  307. }
  308. }
  309. }
  310. /*
  311. * This file is part of PHPUnit.
  312. *
  313. * (c) Sebastian Bergmann <sebastian@phpunit.de>
  314. *
  315. * For the full copyright and license information, please view the LICENSE
  316. * file that was distributed with this source code.
  317. */
  318. if (!class_exists('\PHPUnit\Util\Log\TAP')) {
  319. /**
  320. * A TestListener that generates a logfile of the
  321. * test execution using the Test Anything Protocol (TAP).
  322. */
  323. class TAP extends \PHPUnit\Util\Printer implements \PHPUnit\Framework\TestListener
  324. {
  325. /**
  326. * @var int
  327. */
  328. protected $testNumber = 0;
  329. /**
  330. * @var int
  331. */
  332. protected $testSuiteLevel = 0;
  333. /**
  334. * @var bool
  335. */
  336. protected $testSuccessful = true;
  337. /**
  338. * Constructor.
  339. *
  340. * @param mixed $out
  341. *
  342. * @throws \PHPUnit\Framework\Exception
  343. */
  344. public function __construct($out = null)
  345. {
  346. parent::__construct($out);
  347. $this->write("TAP version 13\n");
  348. }
  349. /**
  350. * An error occurred.
  351. *
  352. * @param \PHPUnit\Framework\Test $test
  353. * @param Exception $e
  354. * @param float $time
  355. */
  356. public function addError(\PHPUnit\Framework\Test $test, \Exception $e, $time)
  357. {
  358. $this->writeNotOk($test, 'Error');
  359. }
  360. /**
  361. * A warning occurred.
  362. *
  363. * @param \PHPUnit\Framework\Test $test
  364. * @param \PHPUnit\Framework\Warning $e
  365. * @param float $time
  366. */
  367. public function addWarning(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, $time)
  368. {
  369. $this->writeNotOk($test, 'Warning');
  370. }
  371. /**
  372. * A failure occurred.
  373. *
  374. * @param \PHPUnit\Framework\Test $test
  375. * @param \PHPUnit\Framework\AssertionFailedError $e
  376. * @param float $time
  377. */
  378. public function addFailure(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\AssertionFailedError $e, $time)
  379. {
  380. $this->writeNotOk($test, 'Failure');
  381. $message = explode(
  382. "\n",
  383. \PHPUnit\Framework\TestFailure::exceptionToString($e)
  384. );
  385. $diagnostic = [
  386. 'message' => $message[0],
  387. 'severity' => 'fail'
  388. ];
  389. if ($e instanceof \PHPUnit\Framework\ExpectationFailedException) {
  390. $cf = $e->getComparisonFailure();
  391. if ($cf !== null) {
  392. $diagnostic['data'] = [
  393. 'got' => $cf->getActual(),
  394. 'expected' => $cf->getExpected()
  395. ];
  396. }
  397. }
  398. $yaml = new \Symfony\Component\Yaml\Dumper;
  399. $this->write(
  400. sprintf(
  401. " ---\n%s ...\n",
  402. $yaml->dump($diagnostic, 2, 2)
  403. )
  404. );
  405. }
  406. /**
  407. * Incomplete test.
  408. *
  409. * @param \PHPUnit\Framework\Test $test
  410. * @param \Exception $e
  411. * @param float $time
  412. */
  413. public function addIncompleteTest(\PHPUnit\Framework\Test $test, \Exception $e, $time)
  414. {
  415. $this->writeNotOk($test, '', 'TODO Incomplete Test');
  416. }
  417. /**
  418. * Risky test.
  419. *
  420. * @param \PHPUnit\Framework\Test $test
  421. * @param Exception $e
  422. * @param float $time
  423. */
  424. public function addRiskyTest(\PHPUnit\Framework\Test $test, \Exception $e, $time)
  425. {
  426. $this->write(
  427. sprintf(
  428. "ok %d - # RISKY%s\n",
  429. $this->testNumber,
  430. $e->getMessage() != '' ? ' ' . $e->getMessage() : ''
  431. )
  432. );
  433. $this->testSuccessful = false;
  434. }
  435. /**
  436. * Skipped test.
  437. *
  438. * @param \PHPUnit\Framework\Test $test
  439. * @param Exception $e
  440. * @param float $time
  441. */
  442. public function addSkippedTest(\PHPUnit\Framework\Test $test, \Exception $e, $time)
  443. {
  444. $this->write(
  445. sprintf(
  446. "ok %d - # SKIP%s\n",
  447. $this->testNumber,
  448. $e->getMessage() != '' ? ' ' . $e->getMessage() : ''
  449. )
  450. );
  451. $this->testSuccessful = false;
  452. }
  453. /**
  454. * A testsuite started.
  455. *
  456. * @param \PHPUnit\Framework\TestSuite $suite
  457. */
  458. public function startTestSuite(\PHPUnit\Framework\TestSuite $suite)
  459. {
  460. $this->testSuiteLevel++;
  461. }
  462. /**
  463. * A testsuite ended.
  464. *
  465. * @param \PHPUnit\Framework\TestSuite $suite
  466. */
  467. public function endTestSuite(\PHPUnit\Framework\TestSuite $suite)
  468. {
  469. $this->testSuiteLevel--;
  470. if ($this->testSuiteLevel == 0) {
  471. $this->write(sprintf("1..%d\n", $this->testNumber));
  472. }
  473. }
  474. /**
  475. * A test started.
  476. *
  477. * @param \PHPUnit\Framework\Test $test
  478. */
  479. public function startTest(\PHPUnit\Framework\Test $test)
  480. {
  481. $this->testNumber++;
  482. $this->testSuccessful = true;
  483. }
  484. /**
  485. * A test ended.
  486. *
  487. * @param \PHPUnit\Framework\Test $test
  488. * @param float $time
  489. */
  490. public function endTest(\PHPUnit\Framework\Test $test, $time)
  491. {
  492. if ($this->testSuccessful === true) {
  493. $this->write(
  494. sprintf(
  495. "ok %d - %s\n",
  496. $this->testNumber,
  497. \PHPUnit\Util\Test::describe($test)
  498. )
  499. );
  500. }
  501. $this->writeDiagnostics($test);
  502. }
  503. /**
  504. * @param \PHPUnit\Framework\Test $test
  505. * @param string $prefix
  506. * @param string $directive
  507. */
  508. protected function writeNotOk(\PHPUnit\Framework\Test $test, $prefix = '', $directive = '')
  509. {
  510. $this->write(
  511. sprintf(
  512. "not ok %d - %s%s%s\n",
  513. $this->testNumber,
  514. $prefix != '' ? $prefix . ': ' : '',
  515. \PHPUnit\Util\Test::describe($test),
  516. $directive != '' ? ' # ' . $directive : ''
  517. )
  518. );
  519. $this->testSuccessful = false;
  520. }
  521. /**
  522. * @param \PHPUnit\Framework\Test $test
  523. */
  524. private function writeDiagnostics(\PHPUnit\Framework\Test $test)
  525. {
  526. if (!$test instanceof \PHPUnit\Framework\TestCase) {
  527. return;
  528. }
  529. if (!$test->hasOutput()) {
  530. return;
  531. }
  532. foreach (explode("\n", trim($test->getActualOutput())) as $line) {
  533. $this->write(
  534. sprintf(
  535. "# %s\n",
  536. $line
  537. )
  538. );
  539. }
  540. }
  541. }
  542. }
  543. }
  544. // @codingStandardsIgnoreEnd