[+BUGFIX] (Persistence) clone setDefaultQuerySettings for new queries
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Persistence / RepositoryTest.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2010 Bastian Waidelich <bastian@typo3.org>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25 class Tx_Extbase_Tests_Unit_Persistence_RepositoryTest extends Tx_Extbase_Tests_Unit_BaseTestCase {
26
27 /**
28 * @var Tx_Extbase_Persistence_Repository
29 */
30 protected $repository;
31
32 /**
33 * @var Tx_Extbase_Object_ObjectManagerInterface
34 */
35 protected $mockObjectManager;
36
37 /**
38 * @var Tx_Extbase_Persistence_IdentityMap
39 */
40 protected $mockIdentityMap;
41
42 /**
43 * @var Tx_Extbase_Persistence_QueryFactory
44 */
45 protected $mockQueryFactory;
46
47 /**
48 * @var Tx_Extbase_Persistence_ManagerInterface
49 */
50 protected $mockPersistenceManager;
51
52 /**
53 * @var Tx_Extbase_Persistence_QueryInterface
54 */
55 protected $mockQuery;
56
57 /**
58 * @var Tx_Extbase_Persistence_QuerySettingsInterface
59 */
60 protected $querySettings;
61
62 public function setUp() {
63 $this->mockIdentityMap = $this->getMock('Tx_Extbase_Persistence_IdentityMap');
64 $this->mockQueryFactory = $this->getMock('Tx_Extbase_Persistence_QueryFactory');
65 $this->mockQuery = $this->getMock('Tx_Extbase_Persistence_QueryInterface');
66 $this->mockQuerySettings = $this->getMock('Tx_Extbase_Persistence_QuerySettingsInterface');
67 $this->mockQuery->expects($this->any())->method('getQuerySettings')->will($this->returnValue($this->mockQuerySettings));
68 $this->mockQueryFactory->expects($this->any())->method('create')->will($this->returnValue($this->mockQuery));
69 $this->mockPersistenceManager = $this->getMock('Tx_Extbase_Persistence_ManagerInterface');
70 $this->mockObjectManager = $this->getMock('Tx_Extbase_Object_ObjectManagerInterface');
71 $this->repository = $this->getAccessibleMock('Tx_Extbase_Persistence_Repository', array('dummy'), array($this->mockObjectManager));
72 $this->repository->injectIdentityMap($this->mockIdentityMap);
73 $this->repository->injectQueryFactory($this->mockQueryFactory);
74 $this->repository->injectPersistenceManager($this->mockPersistenceManager);
75 }
76
77 /**
78 * @test
79 */
80 public function abstractRepositoryImplementsRepositoryInterface() {
81 $this->assertTrue($this->repository instanceof Tx_Extbase_Persistence_RepositoryInterface);
82 }
83
84 /**
85 * @test
86 */
87 public function addActuallyAddsAnObjectToTheInternalObjectsArray() {
88 $someObject = new stdClass();
89
90 $this->repository->_set('objectType', get_class($someObject));
91 $this->repository->add($someObject);
92
93 $this->assertTrue($this->repository->getAddedObjects()->contains($someObject));
94 }
95
96 /**
97 * @test
98 */
99 public function removeActuallyRemovesAnObjectFromTheInternalObjectsArray() {
100 $object1 = $this->getMock('Tx_Extbase_DomainObject_AbstractDomainObject');
101 $object2 = $this->getMock('Tx_Extbase_DomainObject_AbstractDomainObject');
102 $object3 = $this->getMock('Tx_Extbase_DomainObject_AbstractDomainObject');
103
104 $this->repository->_set('objectType', get_class($object1));
105 $this->repository->add($object1);
106 $this->repository->add($object2);
107 $this->repository->add($object3);
108
109 $this->repository->remove($object2);
110
111 $this->assertTrue($this->repository->getAddedObjects()->contains($object1));
112 $this->assertFalse($this->repository->getAddedObjects()->contains($object2));
113 $this->assertTrue($this->repository->getAddedObjects()->contains($object3));
114 }
115
116 /**
117 * @test
118 */
119 public function removeRemovesTheRightObjectEvenIfItHasBeenModifiedSinceItsAddition() {
120 $object1 = $this->getMock('Tx_Extbase_DomainObject_AbstractDomainObject');
121 $object2 = $this->getMock('Tx_Extbase_DomainObject_AbstractDomainObject');
122 $object3 = $this->getMock('Tx_Extbase_DomainObject_AbstractDomainObject');
123
124 $this->repository->_set('objectType', get_class($object1));
125 $this->repository->add($object1);
126 $this->repository->add($object2);
127 $this->repository->add($object3);
128
129 $object2->setPid(1);
130 $object3->setPid(2);
131
132 $this->repository->remove($object2);
133
134 $this->assertTrue($this->repository->getAddedObjects()->contains($object1));
135 $this->assertFalse($this->repository->getAddedObjects()->contains($object2));
136 $this->assertTrue($this->repository->getAddedObjects()->contains($object3));
137 }
138
139 /**
140 * Make sure we remember the objects that are not currently add()ed
141 * but might be in persistent storage.
142 *
143 * @test
144 */
145 public function removeRetainsObjectForObjectsNotInCurrentSession() {
146 $object = $this->getMock('Tx_Extbase_DomainObject_AbstractDomainObject');
147 // if the object is not currently add()ed, it is not new
148 $object->expects($this->once())->method('_isNew')->will($this->returnValue(FALSE));
149
150 $this->repository->_set('objectType', get_class($object));
151 $this->repository->remove($object);
152
153 $this->assertTrue($this->repository->getRemovedObjects()->contains($object));
154 }
155
156 /**
157 * dataProvider for createQueryCallsQueryFactoryWithExpectedType
158 */
159 public function modelAndRepositoryClassNames() {
160 return array(
161 array('Tx_BlogExample_Domain_Repository_BlogRepository', 'Tx_BlogExample_Domain_Model_Blog'),
162 array('_Domain_Repository_Content_PageRepository', '_Domain_Model_Content_Page')
163 );
164 }
165
166 /**
167 * @test
168 * @dataProvider modelAndRepositoryClassNames
169 */
170 public function constructSetsObjectTypeFromClassName($repositoryClassName, $modelClassName) {
171 $mockClassName = 'MockRepository' . uniqid();
172 eval('class ' . $mockClassName . ' extends Tx_Extbase_Persistence_Repository {
173 protected function getRepositoryClassName() {
174 return \'' . $repositoryClassName . '\';
175 }
176 public function _getObjectType() {
177 return $this->objectType;
178 }
179 }');
180
181 $this->repository = new $mockClassName($this->mockObjectManager);
182 $this->assertEquals($modelClassName, $this->repository->_getObjectType());
183 }
184
185 /**
186 * @test
187 */
188 public function createQueryCallsQueryFactoryWithExpectedClassName() {
189 $this->mockQueryFactory->expects($this->once())->method('create')->with('ExpectedType');
190 $this->repository->_set('objectType', 'ExpectedType');
191 $this->repository->createQuery();
192 }
193
194 /**
195 * @test
196 */
197 public function createQueryReturnsQueryWithUnmodifiedDefaultQuerySettings() {
198 $mockQueryFactory = $this->getMock('Tx_Extbase_Persistence_QueryFactory');
199 $mockQuery = new Tx_Extbase_Persistence_Query('foo');
200
201 $mockDefaultQuerySettings = $this->getMock('Tx_Extbase_Persistence_QuerySettingsInterface');
202 $this->repository->injectQueryFactory($mockQueryFactory);
203 $this->repository->setDefaultQuerySettings($mockDefaultQuerySettings);
204
205 $mockQueryFactory->expects($this->once())->method('create')->will($this->returnValue($mockQuery));
206 $this->repository->createQuery();
207
208 $instanceQuerySettings = $mockQuery->getQuerySettings();
209 $this->assertEquals($mockDefaultQuerySettings, $instanceQuerySettings);
210 $this->assertNotSame($mockDefaultQuerySettings, $instanceQuerySettings);
211 }
212
213 /**
214 * @test
215 */
216 public function findAllCreatesQueryAndReturnsResultOfExecuteCall() {
217 $expectedResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
218 $this->mockQuery->expects($this->once())->method('execute')->with()->will($this->returnValue($expectedResult));
219 $this->assertSame($expectedResult, $this->repository->findAll());
220 }
221
222 /**
223 * @test
224 */
225 public function findByUidReturnsResultOfGetObjectByIdentifierCall() {
226 $fakeUid = '123';
227 $object = new stdClass();
228 $this->repository->_set('objectType', 'someObjectType');
229
230 $this->mockIdentityMap->expects($this->once())->method('hasIdentifier')->with($fakeUid, 'someObjectType')->will($this->returnValue(TRUE));
231 $this->mockIdentityMap->expects($this->once())->method('getObjectByIdentifier')->with($fakeUid)->will($this->returnValue($object));
232
233 $expectedResult = $object;
234 $actualResult = $this->repository->findByUid($fakeUid);
235 $this->assertSame($expectedResult, $actualResult);
236 }
237
238 /**
239 * @test
240 */
241 public function findByUidQueriesObjectAndRegistersItIfItWasNotFoundInIdentityMap() {
242 $fakeUid = '123';
243 $object = new stdClass();
244 $this->repository->_set('objectType', 'someObjectType');
245
246 $mockQuerySettings = $this->getMock('Tx_Extbase_Persistence_QuerySettingsInterface');
247 $this->mockQuery->expects($this->atLeastOnce())->method('getQuerySettings')->will($this->returnValue($mockQuerySettings));
248
249 $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
250
251 $this->mockQuery->expects($this->once())->method('equals')->with('uid', $fakeUid)->will($this->returnValue('matchingConstraint'));
252 $this->mockQuery->expects($this->once())->method('matching')->with('matchingConstraint')->will($this->returnValue($this->mockQuery));
253 $this->mockQuery->expects($this->once())->method('execute')->will($this->returnValue($mockQueryResult));
254 $mockQueryResult->expects($this->once())->method('getFirst')->will($this->returnValue($object));
255
256 $this->mockIdentityMap->expects($this->once())->method('hasIdentifier')->with($fakeUid, 'someObjectType')->will($this->returnValue(FALSE));
257 $this->mockIdentityMap->expects($this->once())->method('registerObject')->with($object, $fakeUid);
258 $this->mockQueryFactory->expects($this->once())->method('create')->with('someObjectType')->will($this->returnValue($this->mockQuery));
259
260 $expectedResult = $object;
261 $actualResult = $this->repository->findByUid($fakeUid);
262 $this->assertSame($expectedResult, $actualResult);
263 }
264
265 /**
266 * Replacing a reconstituted object (which has a uuid) by a new object
267 * will ask the persistence backend to replace them accordingly in the
268 * identity map.
269 *
270 * @test
271 * @return void
272 */
273 public function replaceReplacesReconstitutedEntityByNewObject() {
274 $existingObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
275 $newObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
276
277 $mockBackend = $this->getMock('Tx_Extbase_Persistence_BackendInterface');
278 $this->mockPersistenceManager->expects($this->once())->method('getBackend')->will($this->returnValue($mockBackend));
279 $mockBackend->expects($this->once())->method('getIdentifierByObject')->with($existingObject)->will($this->returnValue('123'));
280 $mockBackend->expects($this->once())->method('replaceObject')->with($existingObject, $newObject);
281
282 $mockSession = $this->getMock('Tx_Extbase_Persistence_Session');
283 $this->mockPersistenceManager->expects($this->once())->method('getSession')->will($this->returnValue($mockSession));
284
285 $this->repository->_set('objectType', get_class($newObject));
286 $this->repository->replace($existingObject, $newObject);
287 }
288
289 /**
290 * Replacing a reconstituted object which during this session has been
291 * marked for removal (by calling the repository's remove method)
292 * additionally registers the "newObject" for removal and removes the
293 * "existingObject" from the list of removed objects.
294 *
295 * @test
296 * @return void
297 */
298 public function replaceRemovesReconstitutedObjectWhichIsMarkedToBeRemoved() {
299 $existingObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
300 $newObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
301
302 $removedObjects = new SplObjectStorage;
303 $removedObjects->attach($existingObject);
304
305 $mockBackend = $this->getMock('Tx_Extbase_Persistence_BackendInterface');
306 $this->mockPersistenceManager->expects($this->once())->method('getBackend')->will($this->returnValue($mockBackend));
307 $mockBackend->expects($this->once())->method('getIdentifierByObject')->with($existingObject)->will($this->returnValue('123'));
308 $mockBackend->expects($this->once())->method('replaceObject')->with($existingObject, $newObject);
309
310 $mockSession = $this->getMock('Tx_Extbase_Persistence_Session');
311 $this->mockPersistenceManager->expects($this->once())->method('getSession')->will($this->returnValue($mockSession));
312
313 $this->repository->_set('objectType', get_class($newObject));
314 $this->repository->_set('removedObjects', $removedObjects);
315 $this->repository->replace($existingObject, $newObject);
316
317 $this->assertFalse($removedObjects->contains($existingObject));
318 $this->assertTrue($removedObjects->contains($newObject));
319 }
320
321 /**
322 * Replacing a new object which has not yet been persisted by another
323 * new object will just replace them in the repository's list of added
324 * objects.
325 *
326 * @test
327 * @return void
328 */
329 public function replaceAddsNewObjectToAddedObjects() {
330 $existingObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
331 $newObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
332
333 $addedObjects = new SplObjectStorage;
334 $addedObjects->attach($existingObject);
335
336 $mockBackend = $this->getMock('Tx_Extbase_Persistence_BackendInterface');
337 $this->mockPersistenceManager->expects($this->once())->method('getBackend')->will($this->returnValue($mockBackend));
338 $mockBackend->expects($this->once())->method('getIdentifierByObject')->with($existingObject)->will($this->returnValue(NULL));
339 $mockBackend->expects($this->never())->method('replaceObject');
340
341 $mockSession = $this->getMock('Tx_Extbase_Persistence_Session');
342 $this->mockPersistenceManager->expects($this->once())->method('getSession')->will($this->returnValue($mockSession));
343
344 $this->repository->_set('objectType', get_class($newObject));
345 $this->repository->_set('addedObjects', $addedObjects);
346 $this->repository->replace($existingObject, $newObject);
347
348 $this->assertFalse($addedObjects->contains($existingObject));
349 $this->assertTrue($addedObjects->contains($newObject));
350 }
351
352 /**
353 * @test
354 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
355 */
356 public function replaceChecksObjectType() {
357 $this->repository->_set('objectType', 'ExpectedObjectType');
358
359 $this->repository->replace(new stdClass(), new stdClass());
360 }
361
362 /**
363 * @test
364 */
365 public function updateReplacesAnObjectWithTheSameUuidByTheGivenObject() {
366 $existingObject = new stdClass;
367 $modifiedObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
368 $modifiedObject->expects($this->once())->method('getUid')->will($this->returnValue('123'));
369
370 $repository = $this->getAccessibleMock('Tx_Extbase_Persistence_Repository', array('findByUid', 'replace'), array($this->mockObjectManager));
371 $repository->expects($this->once())->method('findByUid')->with('123')->will($this->returnValue($existingObject));
372 $repository->expects($this->once())->method('replace')->with($existingObject, $modifiedObject);
373 $repository->_set('objectType', get_class($modifiedObject));
374 $repository->update($modifiedObject);
375 }
376
377 /**
378 * @test
379 * @expectedException Tx_Extbase_Persistence_Exception_UnknownObject
380 */
381 public function updateRejectsUnknownObjects() {
382 $someObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
383 $someObject->expects($this->once())->method('getUid')->will($this->returnValue(NULL));
384
385 $this->repository->_set('objectType', get_class($someObject));
386
387 $this->repository->update($someObject);
388 }
389
390 /**
391 * @test
392 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
393 */
394 public function updateRejectsObjectsOfWrongType() {
395 $this->repository->_set('objectType', 'Foo');
396 $this->repository->update(new stdClass());
397 }
398
399 /**
400 * @test
401 */
402 public function magicCallMethodAcceptsFindBySomethingCallsAndExecutesAQueryWithThatCriteria() {
403 $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
404 $this->mockQuery->expects($this->once())->method('equals')->with('foo', 'bar')->will($this->returnValue('matchCriteria'));
405 $this->mockQuery->expects($this->once())->method('matching')->with('matchCriteria')->will($this->returnValue($this->mockQuery));
406 $this->mockQuery->expects($this->once())->method('execute')->will($this->returnValue($mockQueryResult));
407
408 $this->assertSame($mockQueryResult, $this->repository->findByFoo('bar'));
409 }
410
411 /**
412 * @test
413 */
414 public function magicCallMethodAcceptsFindOneBySomethingCallsAndExecutesAQueryWithThatCriteria() {
415 $object = new stdClass();
416 $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
417 $mockQueryResult->expects($this->once())->method('getFirst')->will($this->returnValue($object));
418 $this->mockQuery->expects($this->once())->method('equals')->with('foo', 'bar')->will($this->returnValue('matchCriteria'));
419 $this->mockQuery->expects($this->once())->method('matching')->with('matchCriteria')->will($this->returnValue($this->mockQuery));
420 $this->mockQuery->expects($this->once())->method('setLimit')->with(1)->will($this->returnValue($this->mockQuery));
421 $this->mockQuery->expects($this->once())->method('execute')->will($this->returnValue($mockQueryResult));
422
423 $this->assertSame($object, $this->repository->findOneByFoo('bar'));
424 }
425
426 /**
427 * @test
428 */
429 public function magicCallMethodAcceptsCountBySomethingCallsAndExecutesAQueryWithThatCriteria() {
430 $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
431 $mockQueryResult->expects($this->once())->method('count')->will($this->returnValue(2));
432 $this->mockQuery->expects($this->once())->method('equals')->with('foo', 'bar')->will($this->returnValue('matchCriteria'));
433 $this->mockQuery->expects($this->once())->method('matching')->with('matchCriteria')->will($this->returnValue($this->mockQuery));
434 $this->mockQuery->expects($this->once())->method('execute')->will($this->returnValue($mockQueryResult));
435
436 $this->assertSame(2, $this->repository->countByFoo('bar'));
437 }
438
439 /**
440 * @test
441 * @expectedException Exception
442 */
443 public function magicCallMethodTriggersAnErrorIfUnknownMethodsAreCalled() {
444 $this->repository->__call('foo', array());
445 }
446
447 /**
448 * @test
449 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
450 */
451 public function addChecksObjectType() {
452 $this->repository->_set('objectType', 'ExpectedObjectType');
453
454 $this->repository->add(new stdClass());
455 }
456
457 /**
458 * @test
459 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
460 */
461 public function removeChecksObjectType() {
462 $this->repository->_set('objectType', 'ExpectedObjectType');
463
464 $this->repository->remove(new stdClass());
465 }
466
467 }
468 ?>