JsonViewTest.php 11 KB

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