JsonViewTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * JsonViewTest file
  5. *
  6. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  7. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  8. *
  9. * Licensed under The MIT License
  10. * For full copyright and license information, please see the LICENSE.txt
  11. * Redistributions of files must retain the above copyright notice
  12. *
  13. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  14. * @link https://cakephp.org CakePHP(tm) Project
  15. * @since 2.1.0
  16. * @license https://opensource.org/licenses/mit-license.php MIT License
  17. */
  18. namespace Cake\Test\TestCase\View;
  19. use Cake\Controller\Controller;
  20. use Cake\Core\Configure;
  21. use Cake\Http\Response;
  22. use Cake\Http\ServerRequest;
  23. use Cake\TestSuite\TestCase;
  24. use Cake\View\Exception\SerializationFailureException;
  25. /**
  26. * JsonViewTest
  27. */
  28. class JsonViewTest extends TestCase
  29. {
  30. public function setUp(): void
  31. {
  32. parent::setUp();
  33. Configure::write('debug', false);
  34. }
  35. /**
  36. * Generates testRenderWithoutView data.
  37. *
  38. * Note: array($data, $serialize, expected)
  39. *
  40. * @return array
  41. */
  42. public static function renderWithoutViewProvider()
  43. {
  44. return [
  45. // Test render with a valid string in _serialize.
  46. [
  47. ['data' => ['user' => 'fake', 'list' => ['item1', 'item2']]],
  48. 'data',
  49. null,
  50. json_encode(['user' => 'fake', 'list' => ['item1', 'item2']]),
  51. ],
  52. // Test render with a string with an invalid key in _serialize.
  53. [
  54. ['data' => ['user' => 'fake', 'list' => ['item1', 'item2']]],
  55. 'no_key',
  56. null,
  57. json_encode(null),
  58. ],
  59. // Test render with a valid array in _serialize.
  60. [
  61. ['no' => 'nope', 'user' => 'fake', 'list' => ['item1', 'item2']],
  62. ['no', 'user'],
  63. null,
  64. json_encode(['no' => 'nope', 'user' => 'fake']),
  65. ],
  66. // Test render with an empty array in _serialize.
  67. [
  68. ['no' => 'nope', 'user' => 'fake', 'list' => ['item1', 'item2']],
  69. [],
  70. null,
  71. json_encode(null),
  72. ],
  73. // Test render with a valid array with an invalid key in _serialize.
  74. [
  75. ['no' => 'nope', 'user' => 'fake', 'list' => ['item1', 'item2']],
  76. ['no', 'user', 'no_key'],
  77. null,
  78. json_encode(['no' => 'nope', 'user' => 'fake']),
  79. ],
  80. // Test render with a valid array with only an invalid key in _serialize.
  81. [
  82. ['no' => 'nope', 'user' => 'fake', 'list' => ['item1', 'item2']],
  83. ['no_key'],
  84. null,
  85. json_encode(null),
  86. ],
  87. // Test render with True in _serialize.
  88. [
  89. ['no' => 'nope', 'user' => 'fake', 'list' => ['item1', 'item2']],
  90. true,
  91. JSON_HEX_QUOT,
  92. json_encode(['no' => 'nope', 'user' => 'fake', 'list' => ['item1', 'item2']]),
  93. ],
  94. // Test render with True in _serialize and single var
  95. [
  96. ['no' => 'nope'],
  97. true,
  98. null,
  99. json_encode(['no' => 'nope']),
  100. ],
  101. // Test render with empty string in _serialize.
  102. [
  103. ['no' => 'nope', 'user' => 'fake', 'list' => ['item1', 'item2']],
  104. '',
  105. null,
  106. json_encode(null),
  107. ],
  108. // Test render with a valid array in _serialize and alias.
  109. [
  110. ['original_name' => 'my epic name', 'user' => 'fake', 'list' => ['item1', 'item2']],
  111. ['new_name' => 'original_name', 'user'],
  112. null,
  113. json_encode(['new_name' => 'my epic name', 'user' => 'fake']),
  114. ],
  115. // Test render with an a valid array in _serialize and alias of a null value.
  116. [
  117. ['null' => null],
  118. ['null'],
  119. null,
  120. json_encode(['null' => null]),
  121. ],
  122. // Test render with a False value to be serialized.
  123. [
  124. ['false' => false],
  125. 'false',
  126. null,
  127. json_encode(false),
  128. ],
  129. // Test render with a True value to be serialized.
  130. [
  131. ['true' => true],
  132. 'true',
  133. null,
  134. json_encode(true),
  135. ],
  136. // Test render with an empty string value to be serialized.
  137. [
  138. ['empty' => ''],
  139. 'empty',
  140. null,
  141. json_encode(''),
  142. ],
  143. // Test render with a zero value to be serialized.
  144. [
  145. ['zero' => 0],
  146. 'zero',
  147. null,
  148. json_encode(0),
  149. ],
  150. // Test render with encode <, >, ', &, and " for RFC4627-compliant to be serialized.
  151. [
  152. ['rfc4627_escape' => '<tag> \'quote\' "double-quote" &'],
  153. 'rfc4627_escape',
  154. null,
  155. json_encode('<tag> \'quote\' "double-quote" &', JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT),
  156. ],
  157. // Test render with _jsonOptions = false to be serialized.
  158. [
  159. ['noescape' => '<tag> \'quote\' "double-quote" &'],
  160. 'noescape',
  161. false,
  162. json_encode('<tag> \'quote\' "double-quote" &'),
  163. ],
  164. // Test render with setting _jsonOptions to be serialized.
  165. [
  166. ['rfc4627_escape' => '<tag> \'quote\' "double-quote" &'],
  167. 'rfc4627_escape',
  168. JSON_HEX_TAG | JSON_HEX_APOS,
  169. json_encode('<tag> \'quote\' "double-quote" &', JSON_HEX_TAG | JSON_HEX_APOS),
  170. ],
  171. // Test render of NAN
  172. [
  173. ['value' => NAN],
  174. true,
  175. null,
  176. '{"value":0}',
  177. ],
  178. // Test render of INF
  179. [
  180. ['value' => INF],
  181. true,
  182. null,
  183. '{"value":0}',
  184. ],
  185. ];
  186. }
  187. /**
  188. * Test render with a valid string in _serialize.
  189. *
  190. * @param array $data
  191. * @param string|null $serialize
  192. * @param int|false|null $jsonOptions
  193. * @param string $expected
  194. * @dataProvider renderWithoutViewProvider
  195. * @return void
  196. */
  197. public function testRenderWithoutView($data, $serialize, $jsonOptions, $expected)
  198. {
  199. $Request = new ServerRequest();
  200. $Response = new Response();
  201. $Controller = new Controller($Request, $Response);
  202. $this->deprecated(function () use ($Controller, $data, $serialize, $jsonOptions, $expected) {
  203. $Controller->set($data);
  204. $Controller->set('_serialize', $serialize);
  205. $Controller->set('_jsonOptions', $jsonOptions);
  206. $Controller->viewBuilder()->setClassName('Json');
  207. $View = $Controller->createView();
  208. $output = $View->render();
  209. $this->assertSame($expected, $output);
  210. });
  211. $Controller = new Controller($Request, $Response);
  212. $Controller->set($data);
  213. $Controller->viewBuilder()
  214. ->setOptions(compact('serialize', 'jsonOptions'))
  215. ->setClassName('Json');
  216. $View = $Controller->createView();
  217. $output = $View->render();
  218. $this->assertSame($expected, $output);
  219. }
  220. /**
  221. * Test that rendering with _serialize does not load helpers.
  222. *
  223. * @return void
  224. */
  225. public function testRenderSerializeNoHelpers()
  226. {
  227. $Request = new ServerRequest();
  228. $Response = new Response();
  229. $Controller = new Controller($Request, $Response);
  230. $Controller->set([
  231. 'tags' => ['cakephp', 'framework'],
  232. ]);
  233. $Controller->viewBuilder()
  234. ->setClassName('Json')
  235. ->setOption('serialize', 'tags');
  236. $View = $Controller->createView();
  237. $View->render();
  238. $this->assertFalse(isset($View->Html), 'No helper loaded.');
  239. }
  240. /**
  241. * testJsonpResponse method
  242. *
  243. * @return void
  244. */
  245. public function testJsonpResponse()
  246. {
  247. $Request = new ServerRequest();
  248. $Response = new Response();
  249. $Controller = new Controller($Request, $Response);
  250. $data = ['user' => 'fake', 'list' => ['item1', 'item2']];
  251. $Controller->set([
  252. 'data' => $data,
  253. ]);
  254. $Controller->viewBuilder()
  255. ->setClassName('Json')
  256. ->setOptions(['serialize' => 'data', 'jsonp' => true]);
  257. $View = $Controller->createView();
  258. $output = $View->render();
  259. $this->assertSame(json_encode($data), $output);
  260. $this->assertSame('application/json', $View->getResponse()->getType());
  261. $View->setRequest($View->getRequest()->withQueryParams(['callback' => 'jfunc']));
  262. $output = $View->render();
  263. $expected = 'jfunc(' . json_encode($data) . ')';
  264. $this->assertSame($expected, $output);
  265. $this->assertSame('application/javascript', $View->getResponse()->getType());
  266. $Controller->viewBuilder()->setOption('jsonp', 'jsonCallback');
  267. $Controller->setRequest($Controller->getRequest()->withQueryParams(['jsonCallback' => 'jfunc']));
  268. $View = $Controller->createView();
  269. $output = $View->render();
  270. $expected = 'jfunc(' . json_encode($data) . ')';
  271. $this->assertSame($expected, $output);
  272. }
  273. /**
  274. * Test render with a View file specified.
  275. *
  276. * @return void
  277. */
  278. public function testRenderWithView()
  279. {
  280. $Request = new ServerRequest();
  281. $Response = new Response();
  282. $Controller = new Controller($Request, $Response);
  283. $Controller->setName('Posts');
  284. $data = [
  285. 'User' => [
  286. 'username' => 'fake',
  287. ],
  288. 'Item' => [
  289. ['name' => 'item1'],
  290. ['name' => 'item2'],
  291. ],
  292. ];
  293. $Controller->set('user', $data);
  294. $Controller->viewBuilder()->setClassName('Json');
  295. $View = $Controller->createView();
  296. $View->setTemplatePath($Controller->getName());
  297. $output = $View->render('index');
  298. $expected = json_encode(['user' => 'fake', 'list' => ['item1', 'item2'], 'paging' => null]);
  299. $this->assertSame($expected, $output);
  300. $this->assertSame('application/json', $View->getResponse()->getType());
  301. }
  302. public function testSerializationFailureException()
  303. {
  304. $this->expectException(SerializationFailureException::class);
  305. $this->expectExceptionMessage('Serialization of View data failed.');
  306. $Request = new ServerRequest();
  307. $Response = new Response();
  308. $Controller = new Controller($Request, $Response);
  309. $data = "\xB1\x31";
  310. $Controller->set('data', $data);
  311. $Controller->viewBuilder()
  312. ->setOption('serialize', 'data')
  313. ->setOption('jsonOptions', false)
  314. ->setClassName('Json');
  315. $View = $Controller->createView();
  316. $View->render();
  317. }
  318. }