ModelTaskTest.php 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242
  1. <?php
  2. /**
  3. * CakePHP : Rapid Development Framework (http://cakephp.org)
  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://cakephp.org CakePHP Project
  12. * @since CakePHP v 1.2.6
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Console\Command\Task;
  16. use Cake\Console\Command\Task\ModelTask;
  17. use Cake\Console\Command\Task\TemplateTask;
  18. use Cake\Core\Plugin;
  19. use Cake\Model\Model;
  20. use Cake\ORM\TableRegistry;
  21. use Cake\TestSuite\TestCase;
  22. use Cake\Utility\ClassRegistry;
  23. use Cake\Utility\Inflector;
  24. /**
  25. * ModelTaskTest class
  26. *
  27. */
  28. class ModelTaskTest extends TestCase {
  29. /**
  30. * fixtures
  31. *
  32. * @var array
  33. */
  34. public $fixtures = array(
  35. 'core.bake_article', 'core.bake_comment', 'core.bake_articles_bake_tag',
  36. 'core.bake_tag', 'core.category_thread', 'core.number_tree'
  37. );
  38. /**
  39. * setUp method
  40. *
  41. * @return void
  42. */
  43. public function setUp() {
  44. parent::setUp();
  45. $out = $this->getMock('Cake\Console\ConsoleOutput', [], [], '', false);
  46. $in = $this->getMock('Cake\Console\ConsoleInput', [], [], '', false);
  47. $this->Task = $this->getMock('Cake\Console\Command\Task\ModelTask',
  48. array('in', 'err', 'createFile', '_stop', '_checkUnitTest'),
  49. array($out, $out, $in)
  50. );
  51. $this->Task->connection = 'test';
  52. $this->_setupOtherMocks();
  53. }
  54. /**
  55. * Setup a mock that has out mocked. Normally this is not used as it makes $this->at() really tricky.
  56. *
  57. * @return void
  58. */
  59. protected function _useMockedOut() {
  60. $out = $this->getMock('Cake\Console\ConsoleOutput', [], [], '', false);
  61. $in = $this->getMock('Cake\Console\ConsoleInput', [], [], '', false);
  62. $this->Task = $this->getMock('Cake\Console\Command\Task\ModelTask',
  63. array('in', 'out', 'err', 'hr', 'createFile', '_stop', '_checkUnitTest'),
  64. array($out, $out, $in)
  65. );
  66. $this->_setupOtherMocks();
  67. }
  68. /**
  69. * sets up the rest of the dependencies for Model Task
  70. *
  71. * @return void
  72. */
  73. protected function _setupOtherMocks() {
  74. $out = $this->getMock('Cake\Console\ConsoleOutput', [], [], '', false);
  75. $in = $this->getMock('Cake\Console\ConsoleInput', [], [], '', false);
  76. $this->Task->Fixture = $this->getMock('Cake\Console\Command\Task\FixtureTask', [], [$out, $out, $in]);
  77. $this->Task->Test = $this->getMock('Cake\Console\Command\Task\FixtureTask', [], [$out, $out, $in]);
  78. $this->Task->Template = new TemplateTask($out, $out, $in);
  79. $this->Task->name = 'Model';
  80. }
  81. /**
  82. * tearDown method
  83. *
  84. * @return void
  85. */
  86. public function tearDown() {
  87. parent::tearDown();
  88. unset($this->Task);
  89. }
  90. /**
  91. * Test that listAll uses the connection property
  92. *
  93. * @return void
  94. */
  95. public function testListAllConnection() {
  96. $this->_useMockedOut();
  97. $this->Task->connection = 'test';
  98. $result = $this->Task->listAll();
  99. $this->assertContains('bake_articles', $result);
  100. $this->assertContains('bake_articles_bake_tags', $result);
  101. $this->assertContains('bake_tags', $result);
  102. $this->assertContains('bake_comments', $result);
  103. $this->assertContains('category_threads', $result);
  104. }
  105. /**
  106. * Test getName() method.
  107. *
  108. * @return void
  109. */
  110. public function testGetTable() {
  111. $this->Task->args[0] = 'BakeArticle';
  112. $result = $this->Task->getTable();
  113. $this->assertEquals('bake_articles', $result);
  114. $this->Task->args[0] = 'BakeArticles';
  115. $result = $this->Task->getTable();
  116. $this->assertEquals('bake_articles', $result);
  117. $this->Task->args[0] = 'Article';
  118. $this->Task->params['table'] = 'bake_articles';
  119. $result = $this->Task->getTable();
  120. $this->assertEquals('bake_articles', $result);
  121. }
  122. /**
  123. * Test getting the a table class.
  124. *
  125. * @return void
  126. */
  127. public function testGetTableObject() {
  128. $result = $this->Task->getTableObject('Article', 'bake_articles');
  129. $this->assertInstanceOf('Cake\ORM\Table', $result);
  130. $this->assertEquals('bake_articles', $result->table());
  131. $this->assertEquals('Article', $result->alias());
  132. }
  133. /**
  134. * Test getAssociations with off flag.
  135. *
  136. * @return void
  137. */
  138. public function testGetAssociationsNoFlag() {
  139. $this->Task->params['no-associations'] = true;
  140. $articles = TableRegistry::get('BakeArticle');
  141. $this->assertEquals([], $this->Task->getAssociations($articles));
  142. }
  143. /**
  144. * Test getAssociations
  145. *
  146. * @return void
  147. */
  148. public function testGetAssociations() {
  149. $articles = TableRegistry::get('BakeArticles');
  150. $result = $this->Task->getAssociations($articles);
  151. $expected = [
  152. 'belongsTo' => [
  153. [
  154. 'alias' => 'BakeUsers',
  155. 'className' => 'BakeUsers',
  156. 'foreignKey' => 'bake_user_id',
  157. ],
  158. ],
  159. 'hasMany' => [
  160. [
  161. 'alias' => 'BakeComments',
  162. 'className' => 'BakeComments',
  163. 'foreignKey' => 'bake_article_id',
  164. ],
  165. ],
  166. 'belongsToMany' => [
  167. [
  168. 'alias' => 'BakeTags',
  169. 'className' => 'BakeTags',
  170. 'foreignKey' => 'bake_article_id',
  171. 'joinTable' => 'bake_articles_bake_tags',
  172. 'targetForeignKey' => 'bake_tag_id',
  173. ],
  174. ],
  175. ];
  176. $this->assertEquals($expected, $result);
  177. }
  178. /**
  179. * test that belongsTo generation works.
  180. *
  181. * @return void
  182. */
  183. public function testBelongsToGeneration() {
  184. $model = TableRegistry::get('BakeComments');
  185. $result = $this->Task->findBelongsTo($model, []);
  186. $expected = [
  187. 'belongsTo' => [
  188. [
  189. 'alias' => 'BakeArticles',
  190. 'className' => 'BakeArticles',
  191. 'foreignKey' => 'bake_article_id',
  192. ],
  193. [
  194. 'alias' => 'BakeUsers',
  195. 'className' => 'BakeUsers',
  196. 'foreignKey' => 'bake_user_id',
  197. ],
  198. ]
  199. ];
  200. $this->assertEquals($expected, $result);
  201. $model = TableRegistry::get('CategoryThreads');
  202. $result = $this->Task->findBelongsTo($model, array());
  203. $expected = [
  204. 'belongsTo' => [
  205. [
  206. 'alias' => 'ParentCategoryThreads',
  207. 'className' => 'CategoryThreads',
  208. 'foreignKey' => 'parent_id',
  209. ],
  210. ]
  211. ];
  212. $this->assertEquals($expected, $result);
  213. }
  214. /**
  215. * test that hasOne and/or hasMany relations are generated properly.
  216. *
  217. * @return void
  218. */
  219. public function testHasManyGeneration() {
  220. $this->Task->connection = 'test';
  221. $model = TableRegistry::get('BakeArticles');
  222. $result = $this->Task->findHasMany($model, []);
  223. $expected = [
  224. 'hasMany' => [
  225. [
  226. 'alias' => 'BakeComments',
  227. 'className' => 'BakeComments',
  228. 'foreignKey' => 'bake_article_id',
  229. ],
  230. ],
  231. ];
  232. $this->assertEquals($expected, $result);
  233. $model = TableRegistry::get('CategoryThreads');
  234. $result = $this->Task->findHasMany($model, []);
  235. $expected = [
  236. 'hasMany' => [
  237. [
  238. 'alias' => 'ChildCategoryThreads',
  239. 'className' => 'CategoryThreads',
  240. 'foreignKey' => 'parent_id',
  241. ],
  242. ]
  243. ];
  244. $this->assertEquals($expected, $result);
  245. }
  246. /**
  247. * Test that HABTM generation works
  248. *
  249. * @return void
  250. */
  251. public function testHasAndBelongsToManyGeneration() {
  252. $this->Task->connection = 'test';
  253. $model = TableRegistry::get('BakeArticles');
  254. $result = $this->Task->findBelongsToMany($model, []);
  255. $expected = [
  256. 'belongsToMany' => [
  257. [
  258. 'alias' => 'BakeTags',
  259. 'className' => 'BakeTags',
  260. 'foreignKey' => 'bake_article_id',
  261. 'joinTable' => 'bake_articles_bake_tags',
  262. 'targetForeignKey' => 'bake_tag_id',
  263. ],
  264. ],
  265. ];
  266. $this->assertEquals($expected, $result);
  267. }
  268. /**
  269. * test that initializing the validations works.
  270. *
  271. * @return void
  272. */
  273. public function testInitValidations() {
  274. $result = $this->Task->initValidations();
  275. $this->assertTrue(in_array('notEmpty', $result));
  276. }
  277. /**
  278. * test that individual field validation works, with interactive = false
  279. * tests the guessing features of validation
  280. *
  281. * @return void
  282. */
  283. public function testFieldValidationGuessing() {
  284. $this->markTestIncomplete('Not done here yet');
  285. $this->Task->interactive = false;
  286. $this->Task->initValidations();
  287. $result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
  288. $expected = array('notEmpty' => 'notEmpty');
  289. $this->assertEquals($expected, $result);
  290. $result = $this->Task->fieldValidation('text', array('type' => 'date', 'length' => 10, 'null' => false));
  291. $expected = array('date' => 'date');
  292. $this->assertEquals($expected, $result);
  293. $result = $this->Task->fieldValidation('text', array('type' => 'time', 'length' => 10, 'null' => false));
  294. $expected = array('time' => 'time');
  295. $this->assertEquals($expected, $result);
  296. $result = $this->Task->fieldValidation('email', array('type' => 'string', 'length' => 10, 'null' => false));
  297. $expected = array('email' => 'email');
  298. $this->assertEquals($expected, $result);
  299. $result = $this->Task->fieldValidation('test', array('type' => 'integer', 'length' => 10, 'null' => false));
  300. $expected = array('numeric' => 'numeric');
  301. $this->assertEquals($expected, $result);
  302. $result = $this->Task->fieldValidation('test', array('type' => 'boolean', 'length' => 10, 'null' => false));
  303. $expected = array('boolean' => 'boolean');
  304. $this->assertEquals($expected, $result);
  305. }
  306. /**
  307. * test that interactive field validation works and returns multiple validators.
  308. *
  309. * @return void
  310. */
  311. public function testInteractiveFieldValidation() {
  312. $this->markTestIncomplete('Not done here yet');
  313. $this->Task->initValidations();
  314. $this->Task->interactive = true;
  315. $this->Task->expects($this->any())->method('in')
  316. ->will($this->onConsecutiveCalls('24', 'y', '18', 'n'));
  317. $result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
  318. $expected = array('notEmpty' => 'notEmpty', 'maxLength' => 'maxLength');
  319. $this->assertEquals($expected, $result);
  320. }
  321. /**
  322. * test that a bogus response doesn't cause errors to bubble up.
  323. *
  324. * @return void
  325. */
  326. public function testInteractiveFieldValidationWithBogusResponse() {
  327. $this->markTestIncomplete('Not done here yet');
  328. $this->_useMockedOut();
  329. $this->Task->initValidations();
  330. $this->Task->interactive = true;
  331. $this->Task->expects($this->any())->method('in')
  332. ->will($this->onConsecutiveCalls('999999', '24', 'n'));
  333. $this->Task->expects($this->at(10))->method('out')
  334. ->with($this->stringContains('make a valid'));
  335. $result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
  336. $expected = array('notEmpty' => 'notEmpty');
  337. $this->assertEquals($expected, $result);
  338. }
  339. /**
  340. * test that a regular expression can be used for validation.
  341. *
  342. * @return void
  343. */
  344. public function testInteractiveFieldValidationWithRegexp() {
  345. $this->markTestIncomplete('Not done here yet');
  346. $this->Task->initValidations();
  347. $this->Task->interactive = true;
  348. $this->Task->expects($this->any())->method('in')
  349. ->will($this->onConsecutiveCalls('/^[a-z]{0,9}$/', 'n'));
  350. $result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
  351. $expected = array('a_z_0_9' => '/^[a-z]{0,9}$/');
  352. $this->assertEquals($expected, $result);
  353. }
  354. /**
  355. * Test that skipping fields during rule choice works when doing interactive field validation.
  356. *
  357. * @return void
  358. */
  359. public function testSkippingChoiceInteractiveFieldValidation() {
  360. $this->markTestIncomplete('Not done here yet');
  361. $this->Task->initValidations();
  362. $this->Task->interactive = true;
  363. $this->Task->expects($this->any())->method('in')
  364. ->will($this->onConsecutiveCalls('24', 'y', 's'));
  365. $result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
  366. $expected = array('notEmpty' => 'notEmpty', '_skipFields' => true);
  367. $this->assertEquals($expected, $result);
  368. }
  369. /**
  370. * Test that skipping fields after rule choice works when doing interactive field validation.
  371. *
  372. * @return void
  373. */
  374. public function testSkippingAnotherInteractiveFieldValidation() {
  375. $this->markTestIncomplete('Not done here yet');
  376. $this->Task->initValidations();
  377. $this->Task->interactive = true;
  378. $this->Task->expects($this->any())->method('in')
  379. ->will($this->onConsecutiveCalls('24', 's'));
  380. $result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false));
  381. $expected = array('notEmpty' => 'notEmpty', '_skipFields' => true);
  382. $this->assertEquals($expected, $result);
  383. }
  384. /**
  385. * Test the validation generation routine with skipping the rest of the fields
  386. * when doing interactive field validation.
  387. *
  388. * @return void
  389. */
  390. public function testInteractiveDoValidationWithSkipping() {
  391. $this->markTestIncomplete('Not done here yet');
  392. $this->Task->expects($this->any())
  393. ->method('in')
  394. ->will($this->onConsecutiveCalls('35', '24', 'n', '11', 's'));
  395. $this->Task->interactive = true;
  396. $Model = $this->getMock('Model');
  397. $Model->primaryKey = 'id';
  398. $Model->expects($this->any())
  399. ->method('schema')
  400. ->will($this->returnValue(array(
  401. 'id' => array(
  402. 'type' => 'integer',
  403. 'length' => 11,
  404. 'null' => false,
  405. 'key' => 'primary',
  406. ),
  407. 'name' => array(
  408. 'type' => 'string',
  409. 'length' => 20,
  410. 'null' => false,
  411. ),
  412. 'email' => array(
  413. 'type' => 'string',
  414. 'length' => 255,
  415. 'null' => false,
  416. ),
  417. 'some_date' => array(
  418. 'type' => 'date',
  419. 'length' => '',
  420. 'null' => false,
  421. ),
  422. 'some_time' => array(
  423. 'type' => 'time',
  424. 'length' => '',
  425. 'null' => false,
  426. ),
  427. 'created' => array(
  428. 'type' => 'datetime',
  429. 'length' => '',
  430. 'null' => false,
  431. )
  432. )
  433. ));
  434. $result = $this->Task->doValidation($Model);
  435. $expected = array(
  436. 'name' => array(
  437. 'notEmpty' => 'notEmpty'
  438. ),
  439. 'email' => array(
  440. 'email' => 'email',
  441. ),
  442. );
  443. $this->assertEquals($expected, $result);
  444. }
  445. /**
  446. * test the validation Generation routine
  447. *
  448. * @return void
  449. */
  450. public function testNonInteractiveDoValidation() {
  451. $this->markTestIncomplete('Not done here yet');
  452. $Model = $this->getMock('Model');
  453. $Model->primaryKey = 'id';
  454. $Model->expects($this->any())
  455. ->method('schema')
  456. ->will($this->returnValue(array(
  457. 'id' => array(
  458. 'type' => 'integer',
  459. 'length' => 11,
  460. 'null' => false,
  461. 'key' => 'primary',
  462. ),
  463. 'name' => array(
  464. 'type' => 'string',
  465. 'length' => 20,
  466. 'null' => false,
  467. ),
  468. 'email' => array(
  469. 'type' => 'string',
  470. 'length' => 255,
  471. 'null' => false,
  472. ),
  473. 'some_date' => array(
  474. 'type' => 'date',
  475. 'length' => '',
  476. 'null' => false,
  477. ),
  478. 'some_time' => array(
  479. 'type' => 'time',
  480. 'length' => '',
  481. 'null' => false,
  482. ),
  483. 'created' => array(
  484. 'type' => 'datetime',
  485. 'length' => '',
  486. 'null' => false,
  487. )
  488. )
  489. ));
  490. $this->Task->interactive = false;
  491. $result = $this->Task->doValidation($Model);
  492. $expected = array(
  493. 'name' => array(
  494. 'notEmpty' => 'notEmpty'
  495. ),
  496. 'email' => array(
  497. 'email' => 'email',
  498. ),
  499. 'some_date' => array(
  500. 'date' => 'date'
  501. ),
  502. 'some_time' => array(
  503. 'time' => 'time'
  504. ),
  505. );
  506. $this->assertEquals($expected, $result);
  507. }
  508. /**
  509. * test non interactive doAssociations
  510. *
  511. * @return void
  512. */
  513. public function testDoAssociationsNonInteractive() {
  514. $this->markTestIncomplete('Not done here yet');
  515. $this->Task->connection = 'test';
  516. $this->Task->interactive = false;
  517. $model = new Model(array('ds' => 'test', 'name' => 'BakeArticle'));
  518. $result = $this->Task->doAssociations($model);
  519. $expected = array(
  520. 'belongsTo' => array(
  521. array(
  522. 'alias' => 'BakeUser',
  523. 'className' => 'BakeUser',
  524. 'foreignKey' => 'bake_user_id',
  525. ),
  526. ),
  527. 'hasMany' => array(
  528. array(
  529. 'alias' => 'BakeComment',
  530. 'className' => 'BakeComment',
  531. 'foreignKey' => 'bake_article_id',
  532. ),
  533. ),
  534. 'hasAndBelongsToMany' => array(
  535. array(
  536. 'alias' => 'BakeTag',
  537. 'className' => 'BakeTag',
  538. 'foreignKey' => 'bake_article_id',
  539. 'joinTable' => 'bake_articles_bake_tags',
  540. 'associationForeignKey' => 'bake_tag_id',
  541. ),
  542. ),
  543. );
  544. $this->assertEquals($expected, $result);
  545. }
  546. /**
  547. * test non interactive doActsAs
  548. *
  549. * @return void
  550. */
  551. public function testDoActsAs() {
  552. $this->markTestIncomplete('Not done here yet');
  553. $this->Task->connection = 'test';
  554. $this->Task->interactive = false;
  555. $model = new Model(array('ds' => 'test', 'name' => 'NumberTree'));
  556. $result = $this->Task->doActsAs($model);
  557. $this->assertEquals(array('Tree'), $result);
  558. }
  559. /**
  560. * Ensure that the fixture object is correctly called.
  561. *
  562. * @return void
  563. */
  564. public function testBakeFixture() {
  565. $this->Task->plugin = 'TestPlugin';
  566. $this->Task->Fixture->expects($this->at(0))
  567. ->method('bake')
  568. ->with('BakeArticle', 'bake_articles');
  569. $this->Task->bakeFixture('BakeArticle', 'bake_articles');
  570. $this->assertEquals($this->Task->plugin, $this->Task->Fixture->plugin);
  571. $this->assertEquals($this->Task->connection, $this->Task->Fixture->connection);
  572. $this->assertEquals($this->Task->interactive, $this->Task->Fixture->interactive);
  573. }
  574. /**
  575. * Ensure that the fixture baking can be disabled
  576. *
  577. * @return void
  578. */
  579. public function testBakeFixtureDisabled() {
  580. $this->Task->params['no-fixture'] = true;
  581. $this->Task->plugin = 'TestPlugin';
  582. $this->Task->Fixture->expects($this->never())
  583. ->method('bake');
  584. $this->Task->bakeFixture('BakeArticle', 'bake_articles');
  585. }
  586. /**
  587. * Ensure that the test object is correctly called.
  588. *
  589. * @return void
  590. */
  591. public function testBakeTest() {
  592. $this->Task->plugin = 'TestPlugin';
  593. $this->Task->Test->expects($this->at(0))
  594. ->method('bake')
  595. ->with('Model', 'BakeArticle');
  596. $this->Task->bakeTest('BakeArticle');
  597. $this->assertEquals($this->Task->plugin, $this->Task->Test->plugin);
  598. $this->assertEquals($this->Task->connection, $this->Task->Test->connection);
  599. $this->assertEquals($this->Task->interactive, $this->Task->Test->interactive);
  600. }
  601. /**
  602. * Ensure that test baking can be disabled.
  603. *
  604. * @return void
  605. */
  606. public function testBakeTestDisabled() {
  607. $this->Task->params['no-test'] = true;
  608. $this->Task->plugin = 'TestPlugin';
  609. $this->Task->Test->expects($this->never())
  610. ->method('bake');
  611. $this->Task->bakeTest('BakeArticle');
  612. }
  613. /**
  614. * test confirming of associations, and that when an association is hasMany
  615. * a question for the hasOne is also not asked.
  616. *
  617. * @return void
  618. */
  619. public function testConfirmAssociations() {
  620. $this->markTestIncomplete('Not done here yet');
  621. $associations = array(
  622. 'hasOne' => array(
  623. array(
  624. 'alias' => 'ChildCategoryThread',
  625. 'className' => 'CategoryThread',
  626. 'foreignKey' => 'parent_id',
  627. ),
  628. ),
  629. 'hasMany' => array(
  630. array(
  631. 'alias' => 'ChildCategoryThread',
  632. 'className' => 'CategoryThread',
  633. 'foreignKey' => 'parent_id',
  634. ),
  635. ),
  636. 'belongsTo' => array(
  637. array(
  638. 'alias' => 'User',
  639. 'className' => 'User',
  640. 'foreignKey' => 'user_id',
  641. ),
  642. )
  643. );
  644. $model = new Model(array('ds' => 'test', 'name' => 'CategoryThread'));
  645. $this->Task->expects($this->any())->method('in')
  646. ->will($this->onConsecutiveCalls('n', 'y', 'n', 'n', 'n'));
  647. $result = $this->Task->confirmAssociations($model, $associations);
  648. $this->assertTrue(empty($result['hasOne']));
  649. $result = $this->Task->confirmAssociations($model, $associations);
  650. $this->assertTrue(empty($result['hasMany']));
  651. $this->assertTrue(empty($result['hasOne']));
  652. }
  653. /**
  654. * test that inOptions generates questions and only accepts a valid answer
  655. *
  656. * @return void
  657. */
  658. public function testInOptions() {
  659. $this->markTestIncomplete('Not done here yet');
  660. $this->_useMockedOut();
  661. $options = array('one', 'two', 'three');
  662. $this->Task->expects($this->at(0))->method('out')->with('1. one');
  663. $this->Task->expects($this->at(1))->method('out')->with('2. two');
  664. $this->Task->expects($this->at(2))->method('out')->with('3. three');
  665. $this->Task->expects($this->at(3))->method('in')->will($this->returnValue(10));
  666. $this->Task->expects($this->at(4))->method('out')->with('1. one');
  667. $this->Task->expects($this->at(5))->method('out')->with('2. two');
  668. $this->Task->expects($this->at(6))->method('out')->with('3. three');
  669. $this->Task->expects($this->at(7))->method('in')->will($this->returnValue(2));
  670. $result = $this->Task->inOptions($options, 'Pick a number');
  671. $this->assertEquals(1, $result);
  672. }
  673. /**
  674. * test baking validation
  675. *
  676. * @return void
  677. */
  678. public function testBakeValidation() {
  679. $this->markTestIncomplete('Not done here yet');
  680. $validate = array(
  681. 'name' => array(
  682. 'notempty' => 'notEmpty'
  683. ),
  684. 'email' => array(
  685. 'email' => 'email',
  686. ),
  687. 'some_date' => array(
  688. 'date' => 'date'
  689. ),
  690. 'some_time' => array(
  691. 'time' => 'time'
  692. )
  693. );
  694. $result = $this->Task->bake('BakeArticle', compact('validate'));
  695. $this->assertRegExp('/class BakeArticle extends AppModel \{/', $result);
  696. $this->assertRegExp('/\$validate \= array\(/', $result);
  697. $expected = <<< STRINGEND
  698. array(
  699. 'notempty' => array(
  700. 'rule' => array('notEmpty'),
  701. //'message' => 'Your custom message here',
  702. //'allowEmpty' => false,
  703. //'required' => false,
  704. //'last' => false, // Stop validation after this rule
  705. //'on' => 'create', // Limit validation to 'create' or 'update' operations
  706. ),
  707. STRINGEND;
  708. $this->assertRegExp('/' . preg_quote(str_replace("\r\n", "\n", $expected), '/') . '/', $result);
  709. }
  710. /**
  711. * test baking relations
  712. *
  713. * @return void
  714. */
  715. public function testBakeRelations() {
  716. $this->markTestIncomplete('Not done here yet');
  717. $associations = array(
  718. 'belongsTo' => array(
  719. array(
  720. 'alias' => 'SomethingElse',
  721. 'className' => 'SomethingElse',
  722. 'foreignKey' => 'something_else_id',
  723. ),
  724. array(
  725. 'alias' => 'BakeUser',
  726. 'className' => 'BakeUser',
  727. 'foreignKey' => 'bake_user_id',
  728. ),
  729. ),
  730. 'hasOne' => array(
  731. array(
  732. 'alias' => 'OtherModel',
  733. 'className' => 'OtherModel',
  734. 'foreignKey' => 'other_model_id',
  735. ),
  736. ),
  737. 'hasMany' => array(
  738. array(
  739. 'alias' => 'BakeComment',
  740. 'className' => 'BakeComment',
  741. 'foreignKey' => 'parent_id',
  742. ),
  743. ),
  744. 'hasAndBelongsToMany' => array(
  745. array(
  746. 'alias' => 'BakeTag',
  747. 'className' => 'BakeTag',
  748. 'foreignKey' => 'bake_article_id',
  749. 'joinTable' => 'bake_articles_bake_tags',
  750. 'associationForeignKey' => 'bake_tag_id',
  751. ),
  752. )
  753. );
  754. $result = $this->Task->bake('BakeArticle', compact('associations'));
  755. $this->assertContains(' * @property BakeUser $BakeUser', $result);
  756. $this->assertContains(' * @property OtherModel $OtherModel', $result);
  757. $this->assertContains(' * @property BakeComment $BakeComment', $result);
  758. $this->assertContains(' * @property BakeTag $BakeTag', $result);
  759. $this->assertRegExp('/\$hasAndBelongsToMany \= array\(/', $result);
  760. $this->assertRegExp('/\$hasMany \= array\(/', $result);
  761. $this->assertRegExp('/\$belongsTo \= array\(/', $result);
  762. $this->assertRegExp('/\$hasOne \= array\(/', $result);
  763. $this->assertRegExp('/BakeTag/', $result);
  764. $this->assertRegExp('/OtherModel/', $result);
  765. $this->assertRegExp('/SomethingElse/', $result);
  766. $this->assertRegExp('/BakeComment/', $result);
  767. }
  768. /**
  769. * test bake() with a -plugin param
  770. *
  771. * @return void
  772. */
  773. public function testBakeWithPlugin() {
  774. $this->markTestIncomplete('Not done here yet');
  775. $this->Task->plugin = 'ControllerTest';
  776. //fake plugin path
  777. Plugin::load('ControllerTest', array('path' => APP . 'Plugin/ControllerTest/'));
  778. $path = APP . 'Plugin/ControllerTest/Model/BakeArticle.php';
  779. $this->Task->expects($this->once())->method('createFile')
  780. ->with($path, $this->stringContains('BakeArticle extends ControllerTestAppModel'));
  781. $result = $this->Task->bake('BakeArticle', array(), array());
  782. $this->assertContains("App::uses('ControllerTestAppModel', 'ControllerTest.Model');", $result);
  783. $this->assertEquals(count(ClassRegistry::keys()), 0);
  784. $this->assertEquals(count(ClassRegistry::mapKeys()), 0);
  785. }
  786. /**
  787. * test bake() for models with behaviors
  788. *
  789. * @return void
  790. */
  791. public function testBakeWithBehaviors() {
  792. $this->markTestIncomplete('Not done here yet');
  793. $result = $this->Task->bake('NumberTree', array('actsAs' => array('Tree', 'PluginName.Sluggable')));
  794. $expected = <<<TEXT
  795. /**
  796. * Behaviors
  797. *
  798. * @var array
  799. */
  800. public \$actsAs = array(
  801. 'Tree',
  802. 'PluginName.Sluggable',
  803. );
  804. TEXT;
  805. $this->assertTextContains($expected, $result);
  806. }
  807. /**
  808. * test that execute passes runs bake depending with named model.
  809. *
  810. * @return void
  811. */
  812. public function testExecuteWithNamedModel() {
  813. $this->markTestIncomplete('Not done here yet');
  814. $this->Task->connection = 'test';
  815. $this->Task->path = '/my/path/';
  816. $this->Task->args = array('BakeArticle');
  817. $filename = '/my/path/BakeArticle.php';
  818. $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(1));
  819. $this->Task->expects($this->once())->method('createFile')
  820. ->with($filename, $this->stringContains('class BakeArticle extends AppModel'));
  821. $this->Task->execute();
  822. $this->assertEquals(count(ClassRegistry::keys()), 0);
  823. $this->assertEquals(count(ClassRegistry::mapKeys()), 0);
  824. }
  825. /**
  826. * data provider for testExecuteWithNamedModelVariations
  827. *
  828. * @return void
  829. */
  830. public static function nameVariations() {
  831. return array(
  832. array('BakeArticles'), array('BakeArticle'), array('bake_article'), array('bake_articles')
  833. );
  834. }
  835. /**
  836. * test that execute passes with different inflections of the same name.
  837. *
  838. * @dataProvider nameVariations
  839. * @return void
  840. */
  841. public function testExecuteWithNamedModelVariations($name) {
  842. $this->markTestIncomplete('Not done here yet');
  843. $this->Task->connection = 'test';
  844. $this->Task->path = '/my/path/';
  845. $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(1));
  846. $this->Task->args = array($name);
  847. $filename = '/my/path/BakeArticle.php';
  848. $this->Task->expects($this->at(0))->method('createFile')
  849. ->with($filename, $this->stringContains('class BakeArticle extends AppModel'));
  850. $this->Task->execute();
  851. }
  852. /**
  853. * test that execute with a model name picks up hasMany associations.
  854. *
  855. * @return void
  856. */
  857. public function testExecuteWithNamedModelHasManyCreated() {
  858. $this->markTestIncomplete('Not done here yet');
  859. $this->Task->connection = 'test';
  860. $this->Task->path = '/my/path/';
  861. $this->Task->args = array('BakeArticle');
  862. $filename = '/my/path/BakeArticle.php';
  863. $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(1));
  864. $this->Task->expects($this->at(0))->method('createFile')
  865. ->with($filename, $this->stringContains("'BakeComment' => array("));
  866. $this->Task->execute();
  867. }
  868. /**
  869. * test that execute runs all() when args[0] = all
  870. *
  871. * @return void
  872. */
  873. public function testExecuteIntoAll() {
  874. $this->markTestIncomplete('Not done here yet');
  875. $count = count($this->Task->listAll('test'));
  876. if ($count != count($this->fixtures)) {
  877. $this->markTestSkipped('Additional tables detected.');
  878. }
  879. $this->Task->connection = 'test';
  880. $this->Task->path = '/my/path/';
  881. $this->Task->args = array('all');
  882. $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
  883. $this->Task->Fixture->expects($this->exactly(5))->method('bake');
  884. $this->Task->Test->expects($this->exactly(5))->method('bake');
  885. $filename = '/my/path/BakeArticle.php';
  886. $this->Task->expects($this->at(1))->method('createFile')
  887. ->with($filename, $this->stringContains('class BakeArticle'));
  888. $filename = '/my/path/BakeArticlesBakeTag.php';
  889. $this->Task->expects($this->at(2))->method('createFile')
  890. ->with($filename, $this->stringContains('class BakeArticlesBakeTag'));
  891. $filename = '/my/path/BakeComment.php';
  892. $this->Task->expects($this->at(3))->method('createFile')
  893. ->with($filename, $this->stringContains('class BakeComment'));
  894. $filename = '/my/path/BakeComment.php';
  895. $this->Task->expects($this->at(3))->method('createFile')
  896. ->with($filename, $this->stringContains('public $primaryKey = \'otherid\';'));
  897. $filename = '/my/path/BakeTag.php';
  898. $this->Task->expects($this->at(4))->method('createFile')
  899. ->with($filename, $this->stringContains('class BakeTag'));
  900. $filename = '/my/path/BakeTag.php';
  901. $this->Task->expects($this->at(4))->method('createFile')
  902. ->with($filename, $this->logicalNot($this->stringContains('public $primaryKey')));
  903. $filename = '/my/path/CategoryThread.php';
  904. $this->Task->expects($this->at(5))->method('createFile')
  905. ->with($filename, $this->stringContains('class CategoryThread'));
  906. $this->Task->execute();
  907. $this->assertEquals(count(ClassRegistry::keys()), 0);
  908. $this->assertEquals(count(ClassRegistry::mapKeys()), 0);
  909. }
  910. /**
  911. * test that odd tablenames aren't inflected back from modelname
  912. *
  913. * @return void
  914. */
  915. public function testExecuteIntoAllOddTables() {
  916. $this->markTestIncomplete('Not done here yet');
  917. $out = $this->getMock('Cake\Console\ConsoleOutput', array(), array(), '', false);
  918. $in = $this->getMock('Cake\Console\ConsoleInput', array(), array(), '', false);
  919. $this->Task = $this->getMock('Cake\Console\Command\Task\ModelTask',
  920. array('in', 'err', '_stop', '_checkUnitTest', 'getAllTables', '_getModelObject', 'bake', 'bakeFixture'),
  921. array($out, $out, $in)
  922. );
  923. $this->_setupOtherMocks();
  924. $this->Task->connection = 'test';
  925. $this->Task->path = '/my/path/';
  926. $this->Task->args = array('all');
  927. $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
  928. $this->Task->expects($this->once())->method('getAllTables')->will($this->returnValue(array('bake_odd')));
  929. $object = new Model(array('name' => 'BakeOdd', 'table' => 'bake_odd', 'ds' => 'test'));
  930. $this->Task->expects($this->once())->method('_getModelObject')->with('BakeOdd', 'bake_odd')->will($this->returnValue($object));
  931. $this->Task->expects($this->at(3))->method('bake')->with($object, false)->will($this->returnValue(true));
  932. $this->Task->expects($this->once())->method('bakeFixture')->with('BakeOdd', 'bake_odd');
  933. $this->Task->execute();
  934. $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
  935. $in = $this->getMock('ConsoleInput', array(), array(), '', false);
  936. $this->Task = $this->getMock('ModelTask',
  937. array('in', 'err', '_stop', '_checkUnitTest', 'getAllTables', '_getModelObject', 'doAssociations', 'doValidation', 'doActsAs', 'createFile'),
  938. array($out, $out, $in)
  939. );
  940. $this->_setupOtherMocks();
  941. $this->Task->connection = 'test';
  942. $this->Task->path = '/my/path/';
  943. $this->Task->args = array('all');
  944. $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
  945. $this->Task->expects($this->once())->method('getAllTables')->will($this->returnValue(array('bake_odd')));
  946. $object = new Model(array('name' => 'BakeOdd', 'table' => 'bake_odd', 'ds' => 'test'));
  947. $this->Task->expects($this->once())->method('_getModelObject')->will($this->returnValue($object));
  948. $this->Task->expects($this->once())->method('doAssociations')->will($this->returnValue(array()));
  949. $this->Task->expects($this->once())->method('doValidation')->will($this->returnValue(array()));
  950. $this->Task->expects($this->once())->method('doActsAs')->will($this->returnValue(array()));
  951. $filename = '/my/path/BakeOdd.php';
  952. $this->Task->expects($this->once())->method('createFile')
  953. ->with($filename, $this->stringContains('class BakeOdd'));
  954. $filename = '/my/path/BakeOdd.php';
  955. $this->Task->expects($this->once())->method('createFile')
  956. ->with($filename, $this->stringContains('public $useTable = \'bake_odd\''));
  957. $this->Task->execute();
  958. }
  959. /**
  960. * test that odd tablenames aren't inflected back from modelname
  961. *
  962. * @return void
  963. */
  964. public function testExecuteIntoBakeOddTables() {
  965. $this->markTestIncomplete('Not done here yet');
  966. $out = $this->getMock('Cake\Console\ConsoleOutput', array(), array(), '', false);
  967. $in = $this->getMock('Cake\Console\ConsoleInput', array(), array(), '', false);
  968. $this->Task = $this->getMock('Cake\Console\Command\Task\ModelTask',
  969. array('in', 'err', '_stop', '_checkUnitTest', 'getAllTables', '_getModelObject', 'bake', 'bakeFixture'),
  970. array($out, $out, $in)
  971. );
  972. $this->_setupOtherMocks();
  973. $this->Task->connection = 'test';
  974. $this->Task->path = '/my/path/';
  975. $this->Task->args = array('BakeOdd');
  976. $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
  977. $this->Task->expects($this->once())->method('getAllTables')->will($this->returnValue(array('articles', 'bake_odd')));
  978. $object = new Model(array('name' => 'BakeOdd', 'table' => 'bake_odd', 'ds' => 'test'));
  979. $this->Task->expects($this->once())->method('_getModelObject')->with('BakeOdd', 'bake_odd')->will($this->returnValue($object));
  980. $this->Task->expects($this->once())->method('bake')->with($object, false)->will($this->returnValue(true));
  981. $this->Task->expects($this->once())->method('bakeFixture')->with('BakeOdd', 'bake_odd');
  982. $this->Task->execute();
  983. $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
  984. $in = $this->getMock('ConsoleInput', array(), array(), '', false);
  985. $this->Task = $this->getMock('ModelTask',
  986. array('in', 'err', '_stop', '_checkUnitTest', 'getAllTables', '_getModelObject', 'doAssociations', 'doValidation', 'doActsAs', 'createFile'),
  987. array($out, $out, $in)
  988. );
  989. $this->_setupOtherMocks();
  990. $this->Task->connection = 'test';
  991. $this->Task->path = '/my/path/';
  992. $this->Task->args = array('BakeOdd');
  993. $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
  994. $this->Task->expects($this->once())->method('getAllTables')->will($this->returnValue(array('articles', 'bake_odd')));
  995. $object = new Model(array('name' => 'BakeOdd', 'table' => 'bake_odd', 'ds' => 'test'));
  996. $this->Task->expects($this->once())->method('_getModelObject')->will($this->returnValue($object));
  997. $this->Task->expects($this->once())->method('doAssociations')->will($this->returnValue(array()));
  998. $this->Task->expects($this->once())->method('doValidation')->will($this->returnValue(array()));
  999. $this->Task->expects($this->once())->method('doActsAs')->will($this->returnValue(array()));
  1000. $filename = '/my/path/BakeOdd.php';
  1001. $this->Task->expects($this->once())->method('createFile')
  1002. ->with($filename, $this->stringContains('class BakeOdd'));
  1003. $filename = '/my/path/BakeOdd.php';
  1004. $this->Task->expects($this->once())->method('createFile')
  1005. ->with($filename, $this->stringContains('public $useTable = \'bake_odd\''));
  1006. $this->Task->execute();
  1007. }
  1008. /**
  1009. * test that skipTables changes how all() works.
  1010. *
  1011. * @return void
  1012. */
  1013. public function testSkipTablesAndAll() {
  1014. $this->markTestIncomplete('Not done here yet');
  1015. $count = count($this->Task->listAll('test'));
  1016. if ($count != count($this->fixtures)) {
  1017. $this->markTestSkipped('Additional tables detected.');
  1018. }
  1019. $this->Task->connection = 'test';
  1020. $this->Task->path = '/my/path/';
  1021. $this->Task->args = array('all');
  1022. $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
  1023. $this->Task->skipTables = array('bake_tags');
  1024. $this->Task->Fixture->expects($this->exactly(4))->method('bake');
  1025. $this->Task->Test->expects($this->exactly(4))->method('bake');
  1026. $filename = '/my/path/BakeArticle.php';
  1027. $this->Task->expects($this->at(1))->method('createFile')
  1028. ->with($filename, $this->stringContains('class BakeArticle'));
  1029. $filename = '/my/path/BakeArticlesBakeTag.php';
  1030. $this->Task->expects($this->at(2))->method('createFile')
  1031. ->with($filename, $this->stringContains('class BakeArticlesBakeTag'));
  1032. $filename = '/my/path/BakeComment.php';
  1033. $this->Task->expects($this->at(3))->method('createFile')
  1034. ->with($filename, $this->stringContains('class BakeComment'));
  1035. $filename = '/my/path/CategoryThread.php';
  1036. $this->Task->expects($this->at(4))->method('createFile')
  1037. ->with($filename, $this->stringContains('class CategoryThread'));
  1038. $this->Task->execute();
  1039. }
  1040. /**
  1041. * test the interactive side of bake.
  1042. *
  1043. * @return void
  1044. */
  1045. public function testExecuteIntoInteractive() {
  1046. $this->markTestIncomplete('Not done here yet');
  1047. $tables = $this->Task->listAll('test');
  1048. $article = array_search('bake_articles', $tables) + 1;
  1049. $this->Task->connection = 'test';
  1050. $this->Task->path = '/my/path/';
  1051. $this->Task->interactive = true;
  1052. $this->Task->expects($this->any())->method('in')
  1053. ->will($this->onConsecutiveCalls(
  1054. $article, // article
  1055. 'n', // no validation
  1056. 'y', // associations
  1057. 'y', // comment relation
  1058. 'y', // user relation
  1059. 'y', // tag relation
  1060. 'n', // additional assocs
  1061. 'y' // looks good?
  1062. ));
  1063. $this->Task->expects($this->once())->method('_checkUnitTest')->will($this->returnValue(true));
  1064. $this->Task->Test->expects($this->once())->method('bake');
  1065. $this->Task->Fixture->expects($this->once())->method('bake');
  1066. $filename = '/my/path/BakeArticle.php';
  1067. $this->Task->expects($this->once())->method('createFile')
  1068. ->with($filename, $this->stringContains('class BakeArticle'));
  1069. $this->Task->execute();
  1070. $this->assertEquals(count(ClassRegistry::keys()), 0);
  1071. $this->assertEquals(count(ClassRegistry::mapKeys()), 0);
  1072. }
  1073. /**
  1074. * test using bake interactively with a table that does not exist.
  1075. *
  1076. * @return void
  1077. */
  1078. public function testExecuteWithNonExistantTableName() {
  1079. $this->markTestIncomplete('Not done here yet');
  1080. $this->Task->connection = 'test';
  1081. $this->Task->path = '/my/path/';
  1082. $this->Task->expects($this->any())->method('in')
  1083. ->will($this->onConsecutiveCalls(
  1084. 'Foobar', // Or type in the name of the model
  1085. 'y', // Do you want to use this table
  1086. 'n' // Doesn't exist, continue anyway?
  1087. ));
  1088. $this->Task->execute();
  1089. }
  1090. /**
  1091. * test using bake interactively with a table that does not exist.
  1092. *
  1093. * @return void
  1094. */
  1095. public function testForcedExecuteWithNonExistantTableName() {
  1096. $this->markTestIncomplete('Not done here yet');
  1097. $this->Task->connection = 'test';
  1098. $this->Task->path = '/my/path/';
  1099. $this->Task->expects($this->any())->method('in')
  1100. ->will($this->onConsecutiveCalls(
  1101. 'Foobar', // Or type in the name of the model
  1102. 'y', // Do you want to use this table
  1103. 'y', // Doesn't exist, continue anyway?
  1104. 'id', // Primary key
  1105. 'y' // Looks good?
  1106. ));
  1107. $this->Task->execute();
  1108. }
  1109. }