JsonViewTest.php 11 KB

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