phpunit5-loggers.php 19 KB

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