DebuggerTest.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The MIT License
  8. * For full copyright and license information, please see the LICENSE.txt
  9. * Redistributions of files must retain the above copyright notice.
  10. *
  11. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  12. * @link https://cakephp.org CakePHP Project
  13. * @since 1.2.0
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\Test\TestCase\Error;
  17. use Cake\Controller\Controller;
  18. use Cake\Core\Configure;
  19. use Cake\Error\Debugger;
  20. use Cake\Log\Log;
  21. use Cake\TestSuite\TestCase;
  22. use stdClass;
  23. use TestApp\Error\TestDebugger;
  24. use TestApp\Error\Thing\DebuggableThing;
  25. use TestApp\Error\Thing\SecurityThing;
  26. /**
  27. * DebuggerTest class
  28. *
  29. * !!! Be careful with changing code below as it may
  30. * !!! change line numbers which are used in the tests
  31. */
  32. class DebuggerTest extends TestCase
  33. {
  34. /**
  35. * @var bool
  36. */
  37. protected $restoreError = false;
  38. /**
  39. * setUp method
  40. *
  41. * @return void
  42. */
  43. public function setUp(): void
  44. {
  45. parent::setUp();
  46. Configure::write('debug', true);
  47. Log::drop('stderr');
  48. Log::drop('stdout');
  49. }
  50. /**
  51. * tearDown method
  52. *
  53. * @return void
  54. */
  55. public function tearDown(): void
  56. {
  57. parent::tearDown();
  58. if ($this->restoreError) {
  59. restore_error_handler();
  60. }
  61. }
  62. /**
  63. * testDocRef method
  64. *
  65. * @return void
  66. */
  67. public function testDocRef()
  68. {
  69. $this->skipIf(
  70. defined('HHVM_VERSION'),
  71. 'HHVM does not output doc references'
  72. );
  73. ini_set('docref_root', '');
  74. $this->assertEquals(ini_get('docref_root'), '');
  75. new Debugger();
  76. $this->assertEquals(ini_get('docref_root'), 'https://secure.php.net/');
  77. }
  78. /**
  79. * test Excerpt writing
  80. *
  81. * @return void
  82. */
  83. public function testExcerpt()
  84. {
  85. $result = Debugger::excerpt(__FILE__, __LINE__ - 1, 2);
  86. $this->assertIsArray($result);
  87. $this->assertCount(5, $result);
  88. $this->assertRegExp('/function(.+)testExcerpt/', $result[1]);
  89. $result = Debugger::excerpt(__FILE__, 2, 2);
  90. $this->assertIsArray($result);
  91. $this->assertCount(4, $result);
  92. $this->skipIf(defined('HHVM_VERSION'), 'HHVM does not highlight php code');
  93. $pattern = '/<code>.*?<span style\="color\: \#\d+">.*?&lt;\?php/';
  94. $this->assertRegExp($pattern, $result[0]);
  95. $result = Debugger::excerpt(__FILE__, 11, 2);
  96. $this->assertCount(5, $result);
  97. $pattern = '/<span style\="color\: \#\d{6}">.*?<\/span>/';
  98. $this->assertRegExp($pattern, $result[0]);
  99. $return = Debugger::excerpt('[internal]', 2, 2);
  100. $this->assertEmpty($return);
  101. $result = Debugger::excerpt(__FILE__, __LINE__, 5);
  102. $this->assertCount(11, $result);
  103. $this->assertStringContainsString('Debugger', $result[5]);
  104. $this->assertStringContainsString('excerpt', $result[5]);
  105. $this->assertStringContainsString('__FILE__', $result[5]);
  106. $result = Debugger::excerpt(__FILE__, 1, 2);
  107. $this->assertCount(3, $result);
  108. $lastLine = count(explode("\n", file_get_contents(__FILE__)));
  109. $result = Debugger::excerpt(__FILE__, $lastLine, 2);
  110. $this->assertCount(3, $result);
  111. }
  112. /**
  113. * Test that setOutputFormat works.
  114. *
  115. * @return void
  116. */
  117. public function testSetOutputFormat()
  118. {
  119. Debugger::setOutputFormat('html');
  120. $this->assertSame('html', Debugger::getOutputFormat());
  121. }
  122. /**
  123. * Test that getOutputFormat/setOutputFormat works.
  124. *
  125. * @return void
  126. */
  127. public function testGetSetOutputFormat()
  128. {
  129. Debugger::setOutputFormat('html');
  130. $this->assertSame('html', Debugger::getOutputFormat());
  131. }
  132. /**
  133. * Test that choosing a non-existent format causes an exception
  134. *
  135. * @return void
  136. */
  137. public function testSetOutputAsException()
  138. {
  139. $this->expectException(\InvalidArgumentException::class);
  140. Debugger::setOutputFormat('Invalid junk');
  141. }
  142. /**
  143. * Test outputError with description encoding
  144. *
  145. * @return void
  146. */
  147. public function testOutputErrorDescriptionEncoding()
  148. {
  149. Debugger::setOutputFormat('html');
  150. ob_start();
  151. $debugger = Debugger::getInstance();
  152. $debugger->outputError([
  153. 'error' => 'Notice',
  154. 'code' => E_NOTICE,
  155. 'level' => E_NOTICE,
  156. 'description' => 'Undefined index <script>alert(1)</script>',
  157. 'file' => __FILE__,
  158. 'line' => __LINE__,
  159. ]);
  160. $result = ob_get_clean();
  161. $this->assertStringContainsString('&lt;script&gt;', $result);
  162. $this->assertStringNotContainsString('<script>', $result);
  163. }
  164. /**
  165. * Tests that the correct line is being highlighted.
  166. *
  167. * @return void
  168. */
  169. public function testOutputErrorLineHighlight()
  170. {
  171. Debugger::setOutputFormat('js');
  172. ob_start();
  173. $debugger = Debugger::getInstance();
  174. $data = [
  175. 'level' => E_NOTICE,
  176. 'code' => E_NOTICE,
  177. 'file' => __FILE__,
  178. 'line' => __LINE__,
  179. 'description' => 'Error description',
  180. 'start' => 1,
  181. ];
  182. $debugger->outputError($data);
  183. $result = ob_get_clean();
  184. $this->assertRegExp('#^\<span class\="code\-highlight"\>.*outputError.*\</span\>$#m', $result);
  185. }
  186. /**
  187. * Tests that changes in output formats using Debugger::output() change the templates used.
  188. *
  189. * @return void
  190. */
  191. public function testAddFormat()
  192. {
  193. Debugger::addFormat('js', [
  194. 'traceLine' => '{:reference} - <a href="txmt://open?url=file://{:file}' .
  195. '&line={:line}">{:path}</a>, line {:line}',
  196. ]);
  197. Debugger::setOutputFormat('js');
  198. $result = Debugger::trace();
  199. $this->assertRegExp('/' . preg_quote('txmt://open?url=file://', '/') . '(\/|[A-Z]:\\\\)' . '/', $result);
  200. Debugger::addFormat('xml', [
  201. 'error' => '<error><code>{:code}</code><file>{:file}</file><line>{:line}</line>' .
  202. '{:description}</error>',
  203. ]);
  204. Debugger::setOutputFormat('xml');
  205. ob_start();
  206. $debugger = Debugger::getInstance();
  207. $debugger->outputError([
  208. 'level' => E_NOTICE,
  209. 'code' => E_NOTICE,
  210. 'file' => __FILE__,
  211. 'line' => __LINE__,
  212. 'description' => 'Undefined variable: foo',
  213. ]);
  214. $result = ob_get_clean();
  215. $expected = [
  216. '<error',
  217. '<code', '8', '/code',
  218. '<file', 'preg:/[^<]+/', '/file',
  219. '<line', '' . ((int)__LINE__ - 9), '/line',
  220. 'preg:/Undefined variable:\s+foo/',
  221. '/error',
  222. ];
  223. $this->assertHtml($expected, $result, true);
  224. }
  225. /**
  226. * Test adding a format that is handled by a callback.
  227. *
  228. * @return void
  229. */
  230. public function testAddFormatCallback()
  231. {
  232. Debugger::addFormat('callback', ['callback' => [$this, 'customFormat']]);
  233. Debugger::setOutputFormat('callback');
  234. ob_start();
  235. $debugger = Debugger::getInstance();
  236. $debugger->outputError([
  237. 'error' => 'Notice',
  238. 'code' => E_NOTICE,
  239. 'level' => E_NOTICE,
  240. 'description' => 'Undefined variable $foo',
  241. 'file' => __FILE__,
  242. 'line' => __LINE__,
  243. ]);
  244. $result = ob_get_clean();
  245. $this->assertStringContainsString('Notice: I eated an error', $result);
  246. $this->assertStringContainsString('DebuggerTest.php', $result);
  247. Debugger::setOutputFormat('js');
  248. }
  249. /**
  250. * Test method for testing addFormat with callbacks.
  251. *
  252. * @return void
  253. */
  254. public function customFormat($error, $strings)
  255. {
  256. echo $error['error'] . ': I eated an error ' . $error['file'];
  257. }
  258. /**
  259. * testTrimPath method
  260. *
  261. * @return void
  262. */
  263. public function testTrimPath()
  264. {
  265. $this->assertSame('APP/', Debugger::trimPath(APP));
  266. $this->assertSame('CORE' . DS . 'src' . DS, Debugger::trimPath(CAKE));
  267. $this->assertSame('Some/Other/Path', Debugger::trimPath('Some/Other/Path'));
  268. }
  269. /**
  270. * testExportVar method
  271. *
  272. * @return void
  273. */
  274. public function testExportVar()
  275. {
  276. $Controller = new Controller();
  277. $Controller->viewBuilder()->setHelpers(['Html', 'Form']);
  278. $View = $Controller->createView();
  279. $View->int = 2;
  280. $View->float = 1.333;
  281. $View->string = ' ';
  282. $result = Debugger::exportVar($View);
  283. $expected = <<<TEXT
  284. object(Cake\View\View) id:0 {
  285. Html => object(Cake\View\Helper\HtmlHelper) id:1 {}
  286. Form => object(Cake\View\Helper\FormHelper) id:2 {}
  287. int => (int) 2
  288. float => (float) 1.333
  289. string => ' '
  290. [protected] _helpers => object(Cake\View\HelperRegistry) id:3 {}
  291. [protected] Blocks => object(Cake\View\ViewBlock) id:4 {}
  292. [protected] plugin => null
  293. [protected] name => ''
  294. [protected] helpers => [
  295. (int) 0 => 'Html',
  296. (int) 1 => 'Form'
  297. ]
  298. [protected] templatePath => null
  299. [protected] template => null
  300. [protected] layout => 'default'
  301. [protected] layoutPath => ''
  302. [protected] autoLayout => true
  303. [protected] viewVars => []
  304. [protected] _ext => '.php'
  305. [protected] subDir => ''
  306. [protected] theme => null
  307. [protected] request => object(Cake\Http\ServerRequest) id:5 {}
  308. [protected] response => object(Cake\Http\Response) id:6 {}
  309. [protected] elementCache => 'default'
  310. [protected] _passedVars => [
  311. (int) 0 => 'viewVars',
  312. (int) 1 => 'autoLayout',
  313. (int) 2 => 'helpers',
  314. (int) 3 => 'template',
  315. (int) 4 => 'layout',
  316. (int) 5 => 'name',
  317. (int) 6 => 'theme',
  318. (int) 7 => 'layoutPath',
  319. (int) 8 => 'templatePath',
  320. (int) 9 => 'plugin'
  321. ]
  322. [protected] _defaultConfig => []
  323. [protected] _paths => []
  324. [protected] _pathsForPlugin => []
  325. [protected] _parents => []
  326. [protected] _current => null
  327. [protected] _currentType => ''
  328. [protected] _stack => []
  329. [protected] _viewBlockClass => 'Cake\View\ViewBlock'
  330. [protected] _eventManager => object(Cake\Event\EventManager) id:7 {}
  331. [protected] _eventClass => 'Cake\Event\Event'
  332. [protected] _config => []
  333. [protected] _configInitialized => true
  334. }
  335. TEXT;
  336. $this->assertTextEquals($expected, $result);
  337. $data = [
  338. 1 => 'Index one',
  339. 5 => 'Index five',
  340. ];
  341. $result = Debugger::exportVar($data);
  342. $expected = <<<TEXT
  343. [
  344. (int) 1 => 'Index one',
  345. (int) 5 => 'Index five'
  346. ]
  347. TEXT;
  348. $this->assertTextEquals($expected, $result);
  349. $data = [
  350. 'key' => [
  351. 'value',
  352. ],
  353. ];
  354. $result = Debugger::exportVar($data, 1);
  355. $expected = <<<TEXT
  356. [
  357. 'key' => [
  358. '' => [maximum depth reached]
  359. ]
  360. ]
  361. TEXT;
  362. $this->assertTextEquals($expected, $result);
  363. $data = false;
  364. $result = Debugger::exportVar($data);
  365. $expected = <<<TEXT
  366. false
  367. TEXT;
  368. $this->assertTextEquals($expected, $result);
  369. $file = fopen('php://output', 'w');
  370. fclose($file);
  371. $result = Debugger::exportVar($file);
  372. $this->assertTextEquals('(unknown)', $result);
  373. }
  374. /**
  375. * Test exporting various kinds of false.
  376. *
  377. * @return void
  378. */
  379. public function testExportVarZero()
  380. {
  381. $data = [
  382. 'nothing' => '',
  383. 'null' => null,
  384. 'false' => false,
  385. 'szero' => '0',
  386. 'zero' => 0,
  387. ];
  388. $result = Debugger::exportVar($data);
  389. $expected = <<<TEXT
  390. [
  391. 'nothing' => '',
  392. 'null' => null,
  393. 'false' => false,
  394. 'szero' => '0',
  395. 'zero' => (int) 0
  396. ]
  397. TEXT;
  398. $this->assertTextEquals($expected, $result);
  399. }
  400. /**
  401. * test exportVar with cyclic objects.
  402. *
  403. * @return void
  404. */
  405. public function testExportVarCyclicRef()
  406. {
  407. $parent = new stdClass();
  408. $parent->name = 'cake';
  409. $middle = new stdClass();
  410. $parent->child = $middle;
  411. $middle->name = 'php';
  412. $middle->child = $parent;
  413. $result = Debugger::exportVar($parent, 6);
  414. $expected = <<<TEXT
  415. object(stdClass) id:0 {
  416. name => 'cake'
  417. child => object(stdClass) id:1 {
  418. name => 'php'
  419. child => object(stdClass) id:0 {}
  420. }
  421. }
  422. TEXT;
  423. $this->assertTextEquals($expected, $result);
  424. }
  425. /**
  426. * testLog method
  427. *
  428. * @return void
  429. */
  430. public function testLog()
  431. {
  432. Log::setConfig('test', [
  433. 'className' => 'Array',
  434. ]);
  435. Debugger::log('cool');
  436. Debugger::log(['whatever', 'here']);
  437. $messages = Log::engine('test')->read();
  438. $this->assertCount(2, $messages);
  439. $this->assertStringContainsString('DebuggerTest::testLog', $messages[0]);
  440. $this->assertStringContainsString('cool', $messages[0]);
  441. $this->assertStringContainsString('DebuggerTest::testLog', $messages[1]);
  442. $this->assertStringContainsString('[main]', $messages[1]);
  443. $this->assertStringContainsString("'whatever'", $messages[1]);
  444. $this->assertStringContainsString("'here'", $messages[1]);
  445. Log::drop('test');
  446. }
  447. /**
  448. * test log() depth
  449. *
  450. * @return void
  451. */
  452. public function testLogDepth()
  453. {
  454. Log::setConfig('test', [
  455. 'className' => 'Array',
  456. ]);
  457. $val = [
  458. 'test' => ['key' => 'val'],
  459. ];
  460. Debugger::log($val, 'debug', 0);
  461. $messages = Log::engine('test')->read();
  462. $this->assertStringContainsString('DebuggerTest::testLogDepth', $messages[0]);
  463. $this->assertStringContainsString('test', $messages[0]);
  464. $this->assertStringNotContainsString('val', $messages[0]);
  465. }
  466. /**
  467. * testDump method
  468. *
  469. * @return void
  470. */
  471. public function testDump()
  472. {
  473. $var = ['People' => [
  474. [
  475. 'name' => 'joeseph',
  476. 'coat' => 'technicolor',
  477. 'hair_color' => 'brown',
  478. ],
  479. [
  480. 'name' => 'Shaft',
  481. 'coat' => 'black',
  482. 'hair' => 'black',
  483. ],
  484. ]];
  485. ob_start();
  486. Debugger::dump($var);
  487. $result = ob_get_clean();
  488. $open = "\n";
  489. $close = "\n\n";
  490. $expected = <<<TEXT
  491. {$open}[
  492. 'People' => [
  493. (int) 0 => [
  494. 'name' => 'joeseph',
  495. 'coat' => 'technicolor',
  496. 'hair_color' => 'brown'
  497. ],
  498. (int) 1 => [
  499. 'name' => 'Shaft',
  500. 'coat' => 'black',
  501. 'hair' => 'black'
  502. ]
  503. ]
  504. ]{$close}
  505. TEXT;
  506. $this->assertTextEquals($expected, $result);
  507. ob_start();
  508. Debugger::dump($var, 1);
  509. $result = ob_get_clean();
  510. $expected = <<<TEXT
  511. {$open}[
  512. 'People' => [
  513. '' => [maximum depth reached]
  514. ]
  515. ]{$close}
  516. TEXT;
  517. $this->assertTextEquals($expected, $result);
  518. }
  519. /**
  520. * test getInstance.
  521. *
  522. * @return void
  523. */
  524. public function testGetInstance()
  525. {
  526. $result = Debugger::getInstance();
  527. $exporter = $result->getConfig('exportFormatter');
  528. $this->assertInstanceOf(Debugger::class, $result);
  529. $result = Debugger::getInstance(TestDebugger::class);
  530. $this->assertInstanceOf(TestDebugger::class, $result);
  531. $result = Debugger::getInstance();
  532. $this->assertInstanceOf(TestDebugger::class, $result);
  533. $result = Debugger::getInstance(Debugger::class);
  534. $this->assertInstanceOf(Debugger::class, $result);
  535. $result->setConfig('exportFormatter', $exporter);
  536. }
  537. /**
  538. * Test that exportVar() will stop traversing recursive arrays like GLOBALS.
  539. *
  540. * @return void
  541. */
  542. public function testExportVarRecursion()
  543. {
  544. $output = Debugger::exportVar($GLOBALS);
  545. $this->assertRegExp("/'GLOBALS' => \[\s+'' \=\> \[maximum depth reached\]/", $output);
  546. }
  547. /**
  548. * test trace exclude
  549. *
  550. * @return void
  551. */
  552. public function testTraceExclude()
  553. {
  554. $result = Debugger::trace();
  555. $this->assertRegExp('/^Cake\\\Test\\\TestCase\\\Error\\\DebuggerTest::testTraceExclude/', $result);
  556. $result = Debugger::trace([
  557. 'exclude' => ['Cake\Test\TestCase\Error\DebuggerTest::testTraceExclude'],
  558. ]);
  559. $this->assertNotRegExp('/^Cake\\\Test\\\TestCase\\\Error\\\DebuggerTest::testTraceExclude/', $result);
  560. }
  561. /**
  562. * Tests that __debugInfo is used when available
  563. *
  564. * @return void
  565. */
  566. public function testDebugInfo()
  567. {
  568. $object = new DebuggableThing();
  569. $result = Debugger::exportVar($object, 2);
  570. $expected = <<<eos
  571. object(TestApp\Error\Thing\DebuggableThing) id:0 {
  572. 'foo' => 'bar'
  573. 'inner' => object(TestApp\Error\Thing\DebuggableThing) id:1 {}
  574. }
  575. eos;
  576. $this->assertEquals($expected, $result);
  577. }
  578. /**
  579. * Tests reading the output mask settings.
  580. *
  581. * @return void
  582. */
  583. public function testSetOutputMask()
  584. {
  585. Debugger::setOutputMask(['password' => '[**********]']);
  586. $this->assertEquals(['password' => '[**********]'], Debugger::outputMask());
  587. Debugger::setOutputMask(['serial' => 'XXXXXX']);
  588. $this->assertEquals(['password' => '[**********]', 'serial' => 'XXXXXX'], Debugger::outputMask());
  589. Debugger::setOutputMask([], false);
  590. $this->assertEquals([], Debugger::outputMask());
  591. }
  592. /**
  593. * Tests the masking of an array key.
  594. *
  595. * @return void
  596. */
  597. public function testMaskArray()
  598. {
  599. Debugger::setOutputMask(['password' => '[**********]']);
  600. $result = Debugger::exportVar(['password' => 'pass1234']);
  601. $expected = "['password'=>'[**********]']";
  602. $this->assertEquals($expected, preg_replace('/\s+/', '', $result));
  603. }
  604. /**
  605. * Tests the masking of an array key.
  606. *
  607. * @return void
  608. */
  609. public function testMaskObject()
  610. {
  611. Debugger::setOutputMask(['password' => '[**********]']);
  612. $object = new SecurityThing();
  613. $result = Debugger::exportVar($object);
  614. $expected = "object(TestApp\\Error\\Thing\\SecurityThing)id:0{password=>'[**********]'}";
  615. $this->assertEquals($expected, preg_replace('/\s+/', '', $result));
  616. }
  617. /**
  618. * test testPrintVar()
  619. *
  620. * @return void
  621. */
  622. public function testPrintVar()
  623. {
  624. ob_start();
  625. Debugger::printVar('this-is-a-test', ['file' => __FILE__, 'line' => __LINE__], false);
  626. $result = ob_get_clean();
  627. $expectedText = <<<EXPECTED
  628. %s (line %d)
  629. ########## DEBUG ##########
  630. 'this-is-a-test'
  631. ###########################
  632. EXPECTED;
  633. $expected = sprintf($expectedText, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 9);
  634. $this->assertEquals($expected, $result);
  635. ob_start();
  636. $value = '<div>this-is-a-test</div>';
  637. Debugger::printVar($value, ['file' => __FILE__, 'line' => __LINE__], true);
  638. $result = ob_get_clean();
  639. $expectedHtml = <<<EXPECTED
  640. <div class="cake-debug-output" style="direction:ltr">
  641. <span><strong>%s</strong> (line <strong>%d</strong>)</span>
  642. <pre class="cake-debug">
  643. &#039;&lt;div&gt;this-is-a-test&lt;/div&gt;&#039;
  644. </pre>
  645. </div>
  646. EXPECTED;
  647. $expected = sprintf($expectedHtml, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 10);
  648. $this->assertEquals($expected, $result);
  649. ob_start();
  650. Debugger::printVar('<div>this-is-a-test</div>', ['file' => __FILE__, 'line' => __LINE__], true);
  651. $result = ob_get_clean();
  652. $expected = <<<EXPECTED
  653. <div class="cake-debug-output" style="direction:ltr">
  654. <span><strong>%s</strong> (line <strong>%d</strong>)</span>
  655. <pre class="cake-debug">
  656. &#039;&lt;div&gt;this-is-a-test&lt;/div&gt;&#039;
  657. </pre>
  658. </div>
  659. EXPECTED;
  660. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 10);
  661. $this->assertEquals($expected, $result);
  662. ob_start();
  663. Debugger::printVar('<div>this-is-a-test</div>', [], true);
  664. $result = ob_get_clean();
  665. $expected = <<<EXPECTED
  666. <div class="cake-debug-output" style="direction:ltr">
  667. <pre class="cake-debug">
  668. &#039;&lt;div&gt;this-is-a-test&lt;/div&gt;&#039;
  669. </pre>
  670. </div>
  671. EXPECTED;
  672. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 10);
  673. $this->assertEquals($expected, $result);
  674. ob_start();
  675. Debugger::printVar('<div>this-is-a-test</div>', ['file' => __FILE__, 'line' => __LINE__]);
  676. $result = ob_get_clean();
  677. $expectedHtml = <<<EXPECTED
  678. <div class="cake-debug-output" style="direction:ltr">
  679. <span><strong>%s</strong> (line <strong>%d</strong>)</span>
  680. <pre class="cake-debug">
  681. &#039;&lt;div&gt;this-is-a-test&lt;/div&gt;&#039;
  682. </pre>
  683. </div>
  684. EXPECTED;
  685. $expectedText = <<<EXPECTED
  686. %s (line %d)
  687. ########## DEBUG ##########
  688. '<div>this-is-a-test</div>'
  689. ###########################
  690. EXPECTED;
  691. if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
  692. $expected = sprintf($expectedText, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 18);
  693. } else {
  694. $expected = sprintf($expectedHtml, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 19);
  695. }
  696. $this->assertEquals($expected, $result);
  697. ob_start();
  698. Debugger::printVar('<div>this-is-a-test</div>');
  699. $result = ob_get_clean();
  700. $expectedHtml = <<<EXPECTED
  701. <div class="cake-debug-output" style="direction:ltr">
  702. <pre class="cake-debug">
  703. &#039;&lt;div&gt;this-is-a-test&lt;/div&gt;&#039;
  704. </pre>
  705. </div>
  706. EXPECTED;
  707. $expectedText = <<<EXPECTED
  708. ########## DEBUG ##########
  709. '<div>this-is-a-test</div>'
  710. ###########################
  711. EXPECTED;
  712. if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
  713. $expected = sprintf($expectedText, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 18);
  714. } else {
  715. $expected = sprintf($expectedHtml, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 19);
  716. }
  717. $this->assertEquals($expected, $result);
  718. ob_start();
  719. Debugger::printVar('<div>this-is-a-test</div>', ['file' => __FILE__, 'line' => __LINE__], false);
  720. $result = ob_get_clean();
  721. $expected = <<<EXPECTED
  722. %s (line %d)
  723. ########## DEBUG ##########
  724. '<div>this-is-a-test</div>'
  725. ###########################
  726. EXPECTED;
  727. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 9);
  728. $this->assertEquals($expected, $result);
  729. ob_start();
  730. Debugger::printVar('<div>this-is-a-test</div>', ['file' => __FILE__, 'line' => __LINE__], false);
  731. $result = ob_get_clean();
  732. $expected = <<<EXPECTED
  733. %s (line %d)
  734. ########## DEBUG ##########
  735. '<div>this-is-a-test</div>'
  736. ###########################
  737. EXPECTED;
  738. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 9);
  739. $this->assertEquals($expected, $result);
  740. ob_start();
  741. Debugger::printVar('<div>this-is-a-test</div>', [], false);
  742. $result = ob_get_clean();
  743. $expected = <<<EXPECTED
  744. ########## DEBUG ##########
  745. '<div>this-is-a-test</div>'
  746. ###########################
  747. EXPECTED;
  748. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 9);
  749. $this->assertEquals($expected, $result);
  750. ob_start();
  751. Debugger::printVar(false, [], false);
  752. $result = ob_get_clean();
  753. $expected = <<<EXPECTED
  754. ########## DEBUG ##########
  755. false
  756. ###########################
  757. EXPECTED;
  758. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 9);
  759. $this->assertEquals($expected, $result);
  760. }
  761. /**
  762. * test formatHtmlMessage
  763. *
  764. * @return void
  765. */
  766. public function testFormatHtmlMessage()
  767. {
  768. $output = Debugger::formatHtmlMessage('Some `code` to `replace`');
  769. $this->assertSame('Some <code>code</code> to <code>replace</code>', $output);
  770. $output = Debugger::formatHtmlMessage("Some `co\nde` to `replace`\nmore");
  771. $this->assertSame("Some <code>co<br />\nde</code> to <code>replace</code><br />\nmore", $output);
  772. $output = Debugger::formatHtmlMessage("Some `code` to <script>alert(\"test\")</script>\nmore");
  773. $this->assertSame(
  774. "Some <code>code</code> to &lt;script&gt;alert(&quot;test&quot;)&lt;/script&gt;<br />\nmore",
  775. $output
  776. );
  777. }
  778. }