DebuggerTest.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  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. $this->assertInstanceOf(Debugger::class, $result);
  528. $result = Debugger::getInstance(TestDebugger::class);
  529. $this->assertInstanceOf(TestDebugger::class, $result);
  530. $result = Debugger::getInstance();
  531. $this->assertInstanceOf(TestDebugger::class, $result);
  532. $result = Debugger::getInstance(Debugger::class);
  533. $this->assertInstanceOf(Debugger::class, $result);
  534. }
  535. /**
  536. * Test that exportVar() will stop traversing recursive arrays like GLOBALS.
  537. *
  538. * @return void
  539. */
  540. public function testExportVarRecursion()
  541. {
  542. $output = Debugger::exportVar($GLOBALS);
  543. $this->assertRegExp("/'GLOBALS' => \[\s+'' \=\> \[maximum depth reached\]/", $output);
  544. }
  545. /**
  546. * test trace exclude
  547. *
  548. * @return void
  549. */
  550. public function testTraceExclude()
  551. {
  552. $result = Debugger::trace();
  553. $this->assertRegExp('/^Cake\\\Test\\\TestCase\\\Error\\\DebuggerTest::testTraceExclude/', $result);
  554. $result = Debugger::trace([
  555. 'exclude' => ['Cake\Test\TestCase\Error\DebuggerTest::testTraceExclude'],
  556. ]);
  557. $this->assertNotRegExp('/^Cake\\\Test\\\TestCase\\\Error\\\DebuggerTest::testTraceExclude/', $result);
  558. }
  559. /**
  560. * Tests that __debugInfo is used when available
  561. *
  562. * @return void
  563. */
  564. public function testDebugInfo()
  565. {
  566. $object = new DebuggableThing();
  567. $result = Debugger::exportVar($object, 2);
  568. $expected = <<<eos
  569. object(TestApp\Error\Thing\DebuggableThing) id:0 {
  570. 'foo' => 'bar'
  571. 'inner' => object(TestApp\Error\Thing\DebuggableThing) id:1 {}
  572. }
  573. eos;
  574. $this->assertEquals($expected, $result);
  575. }
  576. /**
  577. * Tests reading the output mask settings.
  578. *
  579. * @return void
  580. */
  581. public function testSetOutputMask()
  582. {
  583. Debugger::setOutputMask(['password' => '[**********]']);
  584. $this->assertEquals(['password' => '[**********]'], Debugger::outputMask());
  585. Debugger::setOutputMask(['serial' => 'XXXXXX']);
  586. $this->assertEquals(['password' => '[**********]', 'serial' => 'XXXXXX'], Debugger::outputMask());
  587. Debugger::setOutputMask([], false);
  588. $this->assertEquals([], Debugger::outputMask());
  589. }
  590. /**
  591. * Tests the masking of an array key.
  592. *
  593. * @return void
  594. */
  595. public function testMaskArray()
  596. {
  597. Debugger::setOutputMask(['password' => '[**********]']);
  598. $result = Debugger::exportVar(['password' => 'pass1234']);
  599. $expected = "['password'=>'[**********]']";
  600. $this->assertEquals($expected, preg_replace('/\s+/', '', $result));
  601. }
  602. /**
  603. * Tests the masking of an array key.
  604. *
  605. * @return void
  606. */
  607. public function testMaskObject()
  608. {
  609. Debugger::setOutputMask(['password' => '[**********]']);
  610. $object = new SecurityThing();
  611. $result = Debugger::exportVar($object);
  612. $expected = "object(TestApp\\Error\\Thing\\SecurityThing)id:0{password=>'[**********]'}";
  613. $this->assertEquals($expected, preg_replace('/\s+/', '', $result));
  614. }
  615. /**
  616. * test testPrintVar()
  617. *
  618. * @return void
  619. */
  620. public function testPrintVar()
  621. {
  622. ob_start();
  623. Debugger::printVar('this-is-a-test', ['file' => __FILE__, 'line' => __LINE__], false);
  624. $result = ob_get_clean();
  625. $expectedText = <<<EXPECTED
  626. %s (line %d)
  627. ########## DEBUG ##########
  628. 'this-is-a-test'
  629. ###########################
  630. EXPECTED;
  631. $expected = sprintf($expectedText, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 9);
  632. $this->assertEquals($expected, $result);
  633. ob_start();
  634. $value = '<div>this-is-a-test</div>';
  635. Debugger::printVar($value, ['file' => __FILE__, 'line' => __LINE__], true);
  636. $result = ob_get_clean();
  637. $expectedHtml = <<<EXPECTED
  638. <div class="cake-debug-output" style="direction:ltr">
  639. <span><strong>%s</strong> (line <strong>%d</strong>)</span>
  640. <pre class="cake-debug">
  641. &#039;&lt;div&gt;this-is-a-test&lt;/div&gt;&#039;
  642. </pre>
  643. </div>
  644. EXPECTED;
  645. $expected = sprintf($expectedHtml, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 10);
  646. $this->assertEquals($expected, $result);
  647. ob_start();
  648. Debugger::printVar('<div>this-is-a-test</div>', ['file' => __FILE__, 'line' => __LINE__], true);
  649. $result = ob_get_clean();
  650. $expected = <<<EXPECTED
  651. <div class="cake-debug-output" style="direction:ltr">
  652. <span><strong>%s</strong> (line <strong>%d</strong>)</span>
  653. <pre class="cake-debug">
  654. &#039;&lt;div&gt;this-is-a-test&lt;/div&gt;&#039;
  655. </pre>
  656. </div>
  657. EXPECTED;
  658. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 10);
  659. $this->assertEquals($expected, $result);
  660. ob_start();
  661. Debugger::printVar('<div>this-is-a-test</div>', [], true);
  662. $result = ob_get_clean();
  663. $expected = <<<EXPECTED
  664. <div class="cake-debug-output" style="direction:ltr">
  665. <pre class="cake-debug">
  666. &#039;&lt;div&gt;this-is-a-test&lt;/div&gt;&#039;
  667. </pre>
  668. </div>
  669. EXPECTED;
  670. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 10);
  671. $this->assertEquals($expected, $result);
  672. ob_start();
  673. Debugger::printVar('<div>this-is-a-test</div>', ['file' => __FILE__, 'line' => __LINE__]);
  674. $result = ob_get_clean();
  675. $expectedHtml = <<<EXPECTED
  676. <div class="cake-debug-output" style="direction:ltr">
  677. <span><strong>%s</strong> (line <strong>%d</strong>)</span>
  678. <pre class="cake-debug">
  679. &#039;&lt;div&gt;this-is-a-test&lt;/div&gt;&#039;
  680. </pre>
  681. </div>
  682. EXPECTED;
  683. $expectedText = <<<EXPECTED
  684. %s (line %d)
  685. ########## DEBUG ##########
  686. '<div>this-is-a-test</div>'
  687. ###########################
  688. EXPECTED;
  689. if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
  690. $expected = sprintf($expectedText, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 18);
  691. } else {
  692. $expected = sprintf($expectedHtml, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 19);
  693. }
  694. $this->assertEquals($expected, $result);
  695. ob_start();
  696. Debugger::printVar('<div>this-is-a-test</div>');
  697. $result = ob_get_clean();
  698. $expectedHtml = <<<EXPECTED
  699. <div class="cake-debug-output" style="direction:ltr">
  700. <pre class="cake-debug">
  701. &#039;&lt;div&gt;this-is-a-test&lt;/div&gt;&#039;
  702. </pre>
  703. </div>
  704. EXPECTED;
  705. $expectedText = <<<EXPECTED
  706. ########## DEBUG ##########
  707. '<div>this-is-a-test</div>'
  708. ###########################
  709. EXPECTED;
  710. if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
  711. $expected = sprintf($expectedText, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 18);
  712. } else {
  713. $expected = sprintf($expectedHtml, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 19);
  714. }
  715. $this->assertEquals($expected, $result);
  716. ob_start();
  717. Debugger::printVar('<div>this-is-a-test</div>', ['file' => __FILE__, 'line' => __LINE__], false);
  718. $result = ob_get_clean();
  719. $expected = <<<EXPECTED
  720. %s (line %d)
  721. ########## DEBUG ##########
  722. '<div>this-is-a-test</div>'
  723. ###########################
  724. EXPECTED;
  725. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 9);
  726. $this->assertEquals($expected, $result);
  727. ob_start();
  728. Debugger::printVar('<div>this-is-a-test</div>', ['file' => __FILE__, 'line' => __LINE__], false);
  729. $result = ob_get_clean();
  730. $expected = <<<EXPECTED
  731. %s (line %d)
  732. ########## DEBUG ##########
  733. '<div>this-is-a-test</div>'
  734. ###########################
  735. EXPECTED;
  736. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 9);
  737. $this->assertEquals($expected, $result);
  738. ob_start();
  739. Debugger::printVar('<div>this-is-a-test</div>', [], false);
  740. $result = ob_get_clean();
  741. $expected = <<<EXPECTED
  742. ########## DEBUG ##########
  743. '<div>this-is-a-test</div>'
  744. ###########################
  745. EXPECTED;
  746. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 9);
  747. $this->assertEquals($expected, $result);
  748. ob_start();
  749. Debugger::printVar(false, [], false);
  750. $result = ob_get_clean();
  751. $expected = <<<EXPECTED
  752. ########## DEBUG ##########
  753. false
  754. ###########################
  755. EXPECTED;
  756. $expected = sprintf($expected, str_replace(CAKE_CORE_INCLUDE_PATH, '', __FILE__), __LINE__ - 9);
  757. $this->assertEquals($expected, $result);
  758. }
  759. /**
  760. * test formatHtmlMessage
  761. *
  762. * @return void
  763. */
  764. public function testFormatHtmlMessage()
  765. {
  766. $output = Debugger::formatHtmlMessage('Some `code` to `replace`');
  767. $this->assertSame('Some <code>code</code> to <code>replace</code>', $output);
  768. $output = Debugger::formatHtmlMessage("Some `co\nde` to `replace`\nmore");
  769. $this->assertSame("Some <code>co<br />\nde</code> to <code>replace</code><br />\nmore", $output);
  770. $output = Debugger::formatHtmlMessage("Some `code` to <script>alert(\"test\")</script>\nmore");
  771. $this->assertSame(
  772. "Some <code>code</code> to &lt;script&gt;alert(&quot;test&quot;)&lt;/script&gt;<br />\nmore",
  773. $output
  774. );
  775. }
  776. }