PaginatorComponentTest.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. <?php
  2. /**
  3. * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
  12. * @since CakePHP(tm) v 2.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Controller\Component;
  16. use Cake\Controller\ComponentRegistry;
  17. use Cake\Controller\Component\PaginatorComponent;
  18. use Cake\Controller\Controller;
  19. use Cake\Core\Configure;
  20. use Cake\Database\ConnectionManager;
  21. use Cake\Error;
  22. use Cake\Network\Request;
  23. use Cake\ORM\TableRegistry;
  24. use Cake\TestSuite\TestCase;
  25. use Cake\Utility\Hash;
  26. /**
  27. * PaginatorTestController class
  28. *
  29. */
  30. class PaginatorTestController extends Controller {
  31. /**
  32. * components property
  33. *
  34. * @var array
  35. */
  36. public $components = array('Paginator');
  37. }
  38. class PaginatorComponentTest extends TestCase {
  39. /**
  40. * fixtures property
  41. *
  42. * @var array
  43. */
  44. public $fixtures = array('core.post', 'core.author');
  45. /**
  46. * setup
  47. *
  48. * @return void
  49. */
  50. public function setUp() {
  51. parent::setUp();
  52. Configure::write('App.namespace', 'TestApp');
  53. $this->request = new Request('controller_posts/index');
  54. $this->request->params['pass'] = array();
  55. $controller = new Controller($this->request);
  56. $registry = new ComponentRegistry($controller);
  57. $this->Paginator = new PaginatorComponent($registry, []);
  58. $this->Post = $this->getMock('Cake\ORM\Table', [], [], '', false);
  59. }
  60. /**
  61. * tearDown
  62. *
  63. * @return void
  64. */
  65. public function tearDown() {
  66. parent::tearDown();
  67. TableRegistry::clear();
  68. }
  69. /**
  70. * Test that non-numeric values are rejected for page, and limit
  71. *
  72. * @return void
  73. */
  74. public function testPageParamCasting() {
  75. $this->Post->expects($this->any())
  76. ->method('alias')
  77. ->will($this->returnValue('Posts'));
  78. $query = $this->_getMockFindQuery();
  79. $this->Post->expects($this->any())
  80. ->method('find')
  81. ->will($this->returnValue($query));
  82. $this->request->query = array('page' => '1 " onclick="alert(\'xss\');">');
  83. $settings = array('limit' => 1, 'maxLimit' => 10);
  84. $this->Paginator->paginate($this->Post, $settings);
  85. $this->assertSame(1, $this->request->params['paging']['Posts']['page'], 'XSS exploit opened');
  86. }
  87. /**
  88. * test that unknown keys in the default settings are
  89. * passed to the find operations.
  90. *
  91. * @return void
  92. */
  93. public function testPaginateExtraParams() {
  94. $this->request->query = array('page' => '-1');
  95. $settings = array(
  96. 'PaginatorPosts' => array(
  97. 'contain' => array('PaginatorAuthor'),
  98. 'maxLimit' => 10,
  99. 'group' => 'PaginatorPosts.published',
  100. 'order' => array('PaginatorPosts.id' => 'ASC')
  101. ),
  102. );
  103. $table = $this->_getMockPosts(['find']);
  104. $query = $this->_getMockFindQuery();
  105. $table->expects($this->once())
  106. ->method('find')
  107. ->with('all', [
  108. 'conditions' => [],
  109. 'contain' => ['PaginatorAuthor'],
  110. 'fields' => null,
  111. 'group' => 'PaginatorPosts.published',
  112. 'limit' => 10,
  113. 'order' => ['PaginatorPosts.id' => 'ASC'],
  114. 'page' => 1,
  115. ])
  116. ->will($this->returnValue($query));
  117. $this->Paginator->paginate($table, $settings);
  118. }
  119. /**
  120. * Test that special paginate types are called and that the type param doesn't leak out into defaults or options.
  121. *
  122. * @return void
  123. */
  124. public function testPaginateCustomFinder() {
  125. $settings = array(
  126. 'PaginatorPosts' => array(
  127. 'findType' => 'popular',
  128. 'fields' => array('id', 'title'),
  129. 'maxLimit' => 10,
  130. )
  131. );
  132. $table = $this->_getMockPosts(['findPopular']);
  133. $query = $this->_getMockFindQuery();
  134. $table->expects($this->any())
  135. ->method('findPopular')
  136. ->will($this->returnValue($query));
  137. $this->Paginator->paginate($table, $settings);
  138. $this->assertEquals('popular', $this->request->params['paging']['PaginatorPosts']['findType']);
  139. }
  140. /**
  141. * test that flat default pagination parameters work.
  142. *
  143. * @return void
  144. */
  145. public function testDefaultPaginateParams() {
  146. $settings = array(
  147. 'order' => ['PaginatorPosts.id' => 'DESC'],
  148. 'maxLimit' => 10,
  149. );
  150. $table = $this->_getMockPosts(['find']);
  151. $query = $this->_getMockFindQuery();
  152. $table->expects($this->once())
  153. ->method('find')
  154. ->with('all', [
  155. 'conditions' => [],
  156. 'fields' => null,
  157. 'limit' => 10,
  158. 'page' => 1,
  159. 'order' => ['PaginatorPosts.id' => 'DESC']
  160. ])
  161. ->will($this->returnValue($query));
  162. $this->Paginator->paginate($table, $settings);
  163. }
  164. /**
  165. * test that default sort and default direction are injected into request
  166. *
  167. * @return void
  168. */
  169. public function testDefaultPaginateParamsIntoRequest() {
  170. $settings = array(
  171. 'order' => ['PaginatorPosts.id' => 'DESC'],
  172. 'maxLimit' => 10,
  173. );
  174. $table = $this->_getMockPosts(['find']);
  175. $query = $this->_getMockFindQuery();
  176. $table->expects($this->once())
  177. ->method('find')
  178. ->with('all', [
  179. 'conditions' => [],
  180. 'fields' => null,
  181. 'limit' => 10,
  182. 'page' => 1,
  183. 'order' => ['PaginatorPosts.id' => 'DESC']
  184. ])
  185. ->will($this->returnValue($query));
  186. $this->Paginator->paginate($table, $settings);
  187. $this->assertEquals('PaginatorPosts.id', $this->request->params['paging']['PaginatorPosts']['sortDefault']);
  188. $this->assertEquals('DESC', $this->request->params['paging']['PaginatorPosts']['directionDefault']);
  189. }
  190. /**
  191. * test that option merging prefers specific models
  192. *
  193. * @return void
  194. */
  195. public function testMergeOptionsModelSpecific() {
  196. $settings = array(
  197. 'page' => 1,
  198. 'limit' => 20,
  199. 'maxLimit' => 100,
  200. 'Posts' => array(
  201. 'page' => 1,
  202. 'limit' => 10,
  203. 'maxLimit' => 50,
  204. )
  205. );
  206. $result = $this->Paginator->mergeOptions('Silly', $settings);
  207. $this->assertEquals($settings, $result);
  208. $result = $this->Paginator->mergeOptions('Posts', $settings);
  209. $expected = array('page' => 1, 'limit' => 10, 'maxLimit' => 50);
  210. $this->assertEquals($expected, $result);
  211. }
  212. /**
  213. * test mergeOptions with customFind key
  214. *
  215. * @return void
  216. */
  217. public function testMergeOptionsCustomFindKey() {
  218. $this->request->query = [
  219. 'page' => 10,
  220. 'limit' => 10
  221. ];
  222. $settings = [
  223. 'page' => 1,
  224. 'limit' => 20,
  225. 'maxLimit' => 100,
  226. 'findType' => 'myCustomFind'
  227. ];
  228. $result = $this->Paginator->mergeOptions('Post', $settings);
  229. $expected = array(
  230. 'page' => 10,
  231. 'limit' => 10,
  232. 'maxLimit' => 100,
  233. 'findType' => 'myCustomFind'
  234. );
  235. $this->assertEquals($expected, $result);
  236. }
  237. /**
  238. * test merging options from the querystring.
  239. *
  240. * @return void
  241. */
  242. public function testMergeOptionsQueryString() {
  243. $this->request->query = array(
  244. 'page' => 99,
  245. 'limit' => 75
  246. );
  247. $settings = array(
  248. 'page' => 1,
  249. 'limit' => 20,
  250. 'maxLimit' => 100,
  251. );
  252. $result = $this->Paginator->mergeOptions('Post', $settings);
  253. $expected = array('page' => 99, 'limit' => 75, 'maxLimit' => 100);
  254. $this->assertEquals($expected, $result);
  255. }
  256. /**
  257. * test that the default whitelist doesn't let people screw with things they should not be allowed to.
  258. *
  259. * @return void
  260. */
  261. public function testMergeOptionsDefaultWhiteList() {
  262. $this->request->query = array(
  263. 'page' => 10,
  264. 'limit' => 10,
  265. 'fields' => array('bad.stuff'),
  266. 'recursive' => 1000,
  267. 'conditions' => array('bad.stuff'),
  268. 'contain' => array('bad')
  269. );
  270. $settings = array(
  271. 'page' => 1,
  272. 'limit' => 20,
  273. 'maxLimit' => 100,
  274. );
  275. $result = $this->Paginator->mergeOptions('Post', $settings);
  276. $expected = array('page' => 10, 'limit' => 10, 'maxLimit' => 100);
  277. $this->assertEquals($expected, $result);
  278. }
  279. /**
  280. * test that modifying the whitelist works.
  281. *
  282. * @return void
  283. */
  284. public function testMergeOptionsExtraWhitelist() {
  285. $this->request->query = array(
  286. 'page' => 10,
  287. 'limit' => 10,
  288. 'fields' => array('bad.stuff'),
  289. 'recursive' => 1000,
  290. 'conditions' => array('bad.stuff'),
  291. 'contain' => array('bad')
  292. );
  293. $settings = array(
  294. 'page' => 1,
  295. 'limit' => 20,
  296. 'maxLimit' => 100,
  297. );
  298. $this->Paginator->whitelist[] = 'fields';
  299. $result = $this->Paginator->mergeOptions('Post', $settings);
  300. $expected = array(
  301. 'page' => 10, 'limit' => 10, 'maxLimit' => 100, 'fields' => array('bad.stuff')
  302. );
  303. $this->assertEquals($expected, $result);
  304. }
  305. /**
  306. * test mergeOptions with limit > maxLimit in code.
  307. *
  308. * @return void
  309. */
  310. public function testMergeOptionsMaxLimit() {
  311. $settings = array(
  312. 'limit' => 200,
  313. 'paramType' => 'named',
  314. );
  315. $result = $this->Paginator->mergeOptions('Post', $settings);
  316. $expected = array('page' => 1, 'limit' => 200, 'maxLimit' => 200, 'paramType' => 'named');
  317. $this->assertEquals($expected, $result);
  318. $settings = array(
  319. 'maxLimit' => 10,
  320. 'paramType' => 'named',
  321. );
  322. $result = $this->Paginator->mergeOptions('Post', $settings);
  323. $expected = array('page' => 1, 'limit' => 20, 'maxLimit' => 10, 'paramType' => 'named');
  324. $this->assertEquals($expected, $result);
  325. }
  326. /**
  327. * Integration test to ensure that validateSort is being used by paginate()
  328. *
  329. * @return void
  330. */
  331. public function testValidateSortInvalid() {
  332. $table = $this->_getMockPosts(['find']);
  333. $query = $this->_getMockFindQuery();
  334. $table->expects($this->once())
  335. ->method('find')
  336. ->with('all', [
  337. 'fields' => null,
  338. 'limit' => 20,
  339. 'conditions' => [],
  340. 'page' => 1,
  341. 'order' => ['PaginatorPosts.id' => 'asc'],
  342. ])
  343. ->will($this->returnValue($query));
  344. $this->request->query = [
  345. 'page' => 1,
  346. 'sort' => 'id',
  347. 'direction' => 'herp'
  348. ];
  349. $this->Paginator->paginate($table);
  350. $this->assertEquals('PaginatorPosts.id', $this->request->params['paging']['PaginatorPosts']['sort']);
  351. $this->assertEquals('asc', $this->request->params['paging']['PaginatorPosts']['direction']);
  352. }
  353. /**
  354. * test that invalid directions are ignored.
  355. *
  356. * @return void
  357. */
  358. public function testValidateSortInvalidDirection() {
  359. $model = $this->getMock('Cake\ORM\Table');
  360. $model->expects($this->any())
  361. ->method('alias')
  362. ->will($this->returnValue('model'));
  363. $model->expects($this->any())
  364. ->method('hasField')
  365. ->will($this->returnValue(true));
  366. $options = array('sort' => 'something', 'direction' => 'boogers');
  367. $result = $this->Paginator->validateSort($model, $options);
  368. $this->assertEquals('asc', $result['order']['model.something']);
  369. }
  370. /**
  371. * Test that a really large page number gets clamped to the max page size.
  372. *
  373. * @return void
  374. */
  375. public function testOutOfRangePageNumberGetsClamped() {
  376. $this->request->query['page'] = 3000;
  377. $table = TableRegistry::get('PaginatorPosts');
  378. try {
  379. $this->Paginator->paginate($table);
  380. $this->fail('No exception raised');
  381. } catch (\Cake\Error\NotFoundException $e) {
  382. $this->assertEquals(
  383. 1,
  384. $this->request->params['paging']['PaginatorPosts']['page'],
  385. 'Page number should not be 0'
  386. );
  387. }
  388. }
  389. /**
  390. * Test that a really REALLY large page number gets clamped to the max page size.
  391. *
  392. * @expectedException Cake\Error\NotFoundException
  393. * @return void
  394. */
  395. public function testOutOfVeryBigPageNumberGetsClamped() {
  396. $this->request->query = [
  397. 'page' => '3000000000000000000000000',
  398. ];
  399. $table = TableRegistry::get('PaginatorPosts');
  400. $this->Paginator->paginate($table);
  401. }
  402. /**
  403. * test that fields not in whitelist won't be part of order conditions.
  404. *
  405. * @return void
  406. */
  407. public function testValidateSortWhitelistFailure() {
  408. $model = $this->getMock('Cake\ORM\Table');
  409. $model->expects($this->any())
  410. ->method('alias')
  411. ->will($this->returnValue('model'));
  412. $model->expects($this->any())->method('hasField')->will($this->returnValue(true));
  413. $options = array(
  414. 'sort' => 'body',
  415. 'direction' => 'asc',
  416. 'sortWhitelist' => ['title', 'id']
  417. );
  418. $result = $this->Paginator->validateSort($model, $options);
  419. $this->assertEquals([], $result['order']);
  420. }
  421. /**
  422. * test that fields in the whitelist are not validated
  423. *
  424. * @return void
  425. */
  426. public function testValidateSortWhitelistTrusted() {
  427. $model = $this->getMock('Cake\ORM\Table');
  428. $model->expects($this->any())
  429. ->method('alias')
  430. ->will($this->returnValue('model'));
  431. $model->expects($this->never())->method('hasField');
  432. $options = array(
  433. 'sort' => 'body',
  434. 'direction' => 'asc',
  435. 'sortWhitelist' => ['body']
  436. );
  437. $result = $this->Paginator->validateSort($model, $options);
  438. $expected = array('body' => 'asc');
  439. $this->assertEquals($expected, $result['order']);
  440. }
  441. /**
  442. * test that multiple sort works.
  443. *
  444. * @return void
  445. */
  446. public function testValidateSortMultiple() {
  447. $model = $this->getMock('Cake\ORM\Table');
  448. $model->expects($this->any())
  449. ->method('alias')
  450. ->will($this->returnValue('model'));
  451. $model->expects($this->any())->method('hasField')->will($this->returnValue(true));
  452. $options = array(
  453. 'order' => array(
  454. 'author_id' => 'asc',
  455. 'title' => 'asc'
  456. )
  457. );
  458. $result = $this->Paginator->validateSort($model, $options);
  459. $expected = array(
  460. 'model.author_id' => 'asc',
  461. 'model.title' => 'asc'
  462. );
  463. $this->assertEquals($expected, $result['order']);
  464. }
  465. /**
  466. * Tests that order strings can used by Paginator
  467. *
  468. * @return void
  469. */
  470. public function testValidateSortWithString() {
  471. $model = $this->getMock('Cake\ORM\Table');
  472. $model->expects($this->any())
  473. ->method('alias')
  474. ->will($this->returnValue('model'));
  475. $model->expects($this->any())->method('hasField')->will($this->returnValue(true));
  476. $options = array(
  477. 'order' => 'model.author_id DESC'
  478. );
  479. $result = $this->Paginator->validateSort($model, $options);
  480. $expected = 'model.author_id DESC';
  481. $this->assertEquals($expected, $result['order']);
  482. }
  483. /**
  484. * Test that no sort doesn't trigger an error.
  485. *
  486. * @return void
  487. */
  488. public function testValidateSortNoSort() {
  489. $model = $this->getMock('Cake\ORM\Table');
  490. $model->expects($this->any())
  491. ->method('alias')
  492. ->will($this->returnValue('model'));
  493. $model->expects($this->any())->method('hasField')
  494. ->will($this->returnValue(true));
  495. $options = array(
  496. 'direction' => 'asc',
  497. 'sortWhitelist' => ['title', 'id'],
  498. );
  499. $result = $this->Paginator->validateSort($model, $options);
  500. $this->assertEquals([], $result['order']);
  501. }
  502. /**
  503. * Test sorting with incorrect aliases on valid fields.
  504. *
  505. * @return void
  506. */
  507. public function testValidateSortInvalidAlias() {
  508. $model = $this->getMock('Cake\ORM\Table');
  509. $model->expects($this->any())
  510. ->method('alias')
  511. ->will($this->returnValue('model'));
  512. $model->expects($this->any())->method('hasField')->will($this->returnValue(true));
  513. $options = array('sort' => 'Derp.id');
  514. $result = $this->Paginator->validateSort($model, $options);
  515. $this->assertEquals(array(), $result['order']);
  516. }
  517. /**
  518. * test that maxLimit is respected
  519. *
  520. * @return void
  521. */
  522. public function testCheckLimit() {
  523. $result = $this->Paginator->checkLimit(array('limit' => 1000000, 'maxLimit' => 100));
  524. $this->assertEquals(100, $result['limit']);
  525. $result = $this->Paginator->checkLimit(array('limit' => 'sheep!', 'maxLimit' => 100));
  526. $this->assertEquals(1, $result['limit']);
  527. $result = $this->Paginator->checkLimit(array('limit' => '-1', 'maxLimit' => 100));
  528. $this->assertEquals(1, $result['limit']);
  529. $result = $this->Paginator->checkLimit(array('limit' => null, 'maxLimit' => 100));
  530. $this->assertEquals(1, $result['limit']);
  531. $result = $this->Paginator->checkLimit(array('limit' => 0, 'maxLimit' => 100));
  532. $this->assertEquals(1, $result['limit']);
  533. }
  534. /**
  535. * Integration test for checkLimit() being applied inside paginate()
  536. *
  537. * @return void
  538. */
  539. public function testPaginateMaxLimit() {
  540. $table = TableRegistry::get('PaginatorPosts');
  541. $settings = [
  542. 'maxLimit' => 100,
  543. ];
  544. $this->request->query = [
  545. 'limit' => '1000'
  546. ];
  547. $this->Paginator->paginate($table, $settings);
  548. $this->assertEquals(100, $this->request->params['paging']['PaginatorPosts']['limit']);
  549. $this->request->query = [
  550. 'limit' => '10'
  551. ];
  552. $this->Paginator->paginate($table, $settings);
  553. $this->assertEquals(10, $this->request->params['paging']['PaginatorPosts']['limit']);
  554. }
  555. /**
  556. * test paginate() and custom find, to make sure the correct count is returned.
  557. *
  558. * @return void
  559. */
  560. public function testPaginateCustomFind() {
  561. $idExtractor = function ($result) {
  562. $ids = [];
  563. foreach ($result as $record) {
  564. $ids[] = $record->id;
  565. }
  566. return $ids;
  567. };
  568. $table = TableRegistry::get('PaginatorPosts');
  569. $data = array('author_id' => 3, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N');
  570. $result = $table->save(new \Cake\ORM\Entity($data));
  571. $this->assertNotEmpty($result);
  572. $result = $this->Paginator->paginate($table);
  573. $this->assertCount(4, $result, '4 rows should come back');
  574. $this->assertEquals(array(1, 2, 3, 4), $idExtractor($result));
  575. $result = $this->request->params['paging']['PaginatorPosts'];
  576. $this->assertEquals(4, $result['current']);
  577. $this->assertEquals(4, $result['count']);
  578. $settings = array('findType' => 'published');
  579. $result = $this->Paginator->paginate($table, $settings);
  580. $this->assertCount(3, $result, '3 rows should come back');
  581. $this->assertEquals(array(1, 2, 3), $idExtractor($result));
  582. $result = $this->request->params['paging']['PaginatorPosts'];
  583. $this->assertEquals(3, $result['current']);
  584. $this->assertEquals(3, $result['count']);
  585. $settings = array('findType' => 'published', 'limit' => 2);
  586. $result = $this->Paginator->paginate($table, $settings);
  587. $this->assertCount(2, $result, '2 rows should come back');
  588. $this->assertEquals(array(1, 2), $idExtractor($result));
  589. $result = $this->request->params['paging']['PaginatorPosts'];
  590. $this->assertEquals(2, $result['current']);
  591. $this->assertEquals(3, $result['count']);
  592. $this->assertEquals(2, $result['pageCount']);
  593. $this->assertTrue($result['nextPage']);
  594. $this->assertFalse($result['prevPage']);
  595. }
  596. /**
  597. * test paginate() and custom find with fields array, to make sure the correct count is returned.
  598. *
  599. * @return void
  600. */
  601. public function testPaginateCustomFindFieldsArray() {
  602. $table = TableRegistry::get('PaginatorPosts');
  603. $data = array('author_id' => 3, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N');
  604. $table->save(new \Cake\ORM\Entity($data));
  605. $settings = [
  606. 'findType' => 'list',
  607. 'conditions' => array('PaginatorPosts.published' => 'Y'),
  608. 'limit' => 2
  609. ];
  610. $results = $this->Paginator->paginate($table, $settings);
  611. $result = $results->toArray();
  612. $expected = array(
  613. 1 => 'First Post',
  614. 2 => 'Second Post',
  615. );
  616. $this->assertEquals($expected, $result);
  617. $result = $this->request->params['paging']['PaginatorPosts'];
  618. $this->assertEquals(2, $result['current']);
  619. $this->assertEquals(3, $result['count']);
  620. $this->assertEquals(2, $result['pageCount']);
  621. $this->assertTrue($result['nextPage']);
  622. $this->assertFalse($result['prevPage']);
  623. }
  624. /**
  625. * test paginate() and custom finders to ensure the count + find
  626. * use the custom type.
  627. *
  628. * @return void
  629. */
  630. public function testPaginateCustomFindCount() {
  631. $settings = array(
  632. 'findType' => 'published',
  633. 'limit' => 2
  634. );
  635. $table = $this->_getMockPosts(['find']);
  636. $query = $this->_getMockFindQuery();
  637. $table->expects($this->once())
  638. ->method('find')
  639. ->with('published', [
  640. 'conditions' => [],
  641. 'order' => [],
  642. 'limit' => 2,
  643. 'fields' => null,
  644. 'page' => 1,
  645. ])
  646. ->will($this->returnValue($query));
  647. $this->Paginator->paginate($table, $settings);
  648. }
  649. /**
  650. * Helper method for making mocks.
  651. *
  652. * @return Table
  653. */
  654. protected function _getMockPosts($methods = []) {
  655. return $this->getMock(
  656. 'TestApp\Model\Table\PaginatorPostsTable',
  657. $methods,
  658. [['connection' => ConnectionManager::get('test'), 'alias' => 'PaginatorPosts']]
  659. );
  660. }
  661. /**
  662. * Helper method for mocking queries.
  663. *
  664. * @return Query
  665. */
  666. protected function _getMockFindQuery() {
  667. $query = $this->getMockBuilder('Cake\ORM\Query')
  668. ->setMethods(['total', 'all', 'count'])
  669. ->disableOriginalConstructor()
  670. ->getMock();
  671. $results = $this->getMock('Cake\ORM\ResultSet', [], [], '', false);
  672. $query->expects($this->any())
  673. ->method('count')
  674. ->will($this->returnValue(2));
  675. $query->expects($this->any())
  676. ->method('all')
  677. ->will($this->returnValue($results));
  678. $query->expects($this->any())
  679. ->method('count')
  680. ->will($this->returnValue(2));
  681. return $query;
  682. }
  683. }