[+TASK] Extbase (Tests): Fixed Extbase unit tests
[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 $this->repository->_set('objectType', get_class($someObject));
90 $this->repository->add($someObject);
91
92 $this->assertTrue($this->repository->getAddedObjects()->contains($someObject));
93 }
94
95 /**
96 * @test
97 */
98 public function removeActuallyRemovesAnObjectFromTheInternalObjectsArray() {
99 $object1 = new stdClass();
100 $object2 = new stdClass();
101 $object3 = new stdClass();
102
103 $this->repository->_set('objectType', get_class($object1));
104 $this->repository->add($object1);
105 $this->repository->add($object2);
106 $this->repository->add($object3);
107
108 $this->repository->remove($object2);
109
110 $this->assertTrue($this->repository->getAddedObjects()->contains($object1));
111 $this->assertFalse($this->repository->getAddedObjects()->contains($object2));
112 $this->assertTrue($this->repository->getAddedObjects()->contains($object3));
113 }
114
115 /**
116 * @test
117 */
118 public function removeRemovesTheRightObjectEvenIfItHasBeenModifiedSinceItsAddition() {
119 $object1 = new ArrayObject(array('val' => '1'));
120 $object2 = new ArrayObject(array('val' => '2'));
121 $object3 = new ArrayObject(array('val' => '3'));
122
123 $this->repository->_set('objectType', get_class($object1));
124 $this->repository->add($object1);
125 $this->repository->add($object2);
126 $this->repository->add($object3);
127
128 $object2['foo'] = 'bar';
129 $object3['val'] = '2';
130
131 $this->repository->remove($object2);
132
133 $this->assertTrue($this->repository->getAddedObjects()->contains($object1));
134 $this->assertFalse($this->repository->getAddedObjects()->contains($object2));
135 $this->assertTrue($this->repository->getAddedObjects()->contains($object3));
136 }
137
138 /**
139 * Make sure we remember the objects that are not currently add()ed
140 * but might be in persistent storage.
141 *
142 * @test
143 */
144 public function removeRetainsObjectForObjectsNotInCurrentSession() {
145 $object = new ArrayObject(array('val' => '1'));
146 $this->repository->_set('objectType', get_class($object));
147 $this->repository->remove($object);
148
149 $this->assertTrue($this->repository->getRemovedObjects()->contains($object));
150 }
151
152 /**
153 * dataProvider for createQueryCallsQueryFactoryWithExpectedType
154 */
155 public function modelAndRepositoryClassNames() {
156 return array(
157 array('Tx_BlogExample_Domain_Repository_BlogRepository', 'Tx_BlogExample_Domain_Model_Blog'),
158 array('_Domain_Repository_Content_PageRepository', '_Domain_Model_Content_Page')
159 );
160 }
161
162 /**
163 * @test
164 * @dataProvider modelAndRepositoryClassNames
165 */
166 public function constructSetsObjectTypeFromClassName($repositoryClassName, $modelClassName) {
167 $mockClassName = 'MockRepository' . uniqid();
168 eval('class ' . $mockClassName . ' extends Tx_Extbase_Persistence_Repository {
169 protected function getRepositoryClassName() {
170 return \'' . $repositoryClassName . '\';
171 }
172 public function _getObjectType() {
173 return $this->objectType;
174 }
175 }');
176
177 $this->repository = new $mockClassName($this->mockObjectManager);
178 $this->assertEquals($modelClassName, $this->repository->_getObjectType());
179 }
180
181 /**
182 * @test
183 */
184 public function createQueryCallsQueryFactoryWithExpectedClassName() {
185 $this->mockQueryFactory->expects($this->once())->method('create')->with('ExpectedType');
186 $this->repository->_set('objectType', 'ExpectedType');
187 $this->repository->createQuery();
188 }
189
190 /**
191 * @test
192 */
193 public function findAllCreatesQueryAndReturnsResultOfExecuteCall() {
194 $expectedResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
195 $this->mockQuery->expects($this->once())->method('execute')->with()->will($this->returnValue($expectedResult));
196 $this->assertSame($expectedResult, $this->repository->findAll());
197 }
198
199 /**
200 * @test
201 */
202 public function findByUidReturnsResultOfGetObjectByIdentifierCall() {
203 $fakeUid = '123';
204 $object = new stdClass();
205 $this->repository->_set('objectType', 'someObjectType');
206
207 $this->mockIdentityMap->expects($this->once())->method('hasIdentifier')->with($fakeUid, 'someObjectType')->will($this->returnValue(TRUE));
208 $this->mockIdentityMap->expects($this->once())->method('getObjectByIdentifier')->with($fakeUid)->will($this->returnValue($object));
209
210 $expectedResult = $object;
211 $actualResult = $this->repository->findByUid($fakeUid);
212 $this->assertSame($expectedResult, $actualResult);
213 }
214
215 /**
216 * @test
217 */
218 public function findByUidQueriesObjectAndRegistersItIfItWasNotFoundInIdentityMap() {
219 $fakeUid = '123';
220 $object = new stdClass();
221 $this->repository->_set('objectType', 'someObjectType');
222
223 $mockQuerySettings = $this->getMock('Tx_Extbase_Persistence_QuerySettingsInterface');
224 $this->mockQuery->expects($this->atLeastOnce())->method('getQuerySettings')->will($this->returnValue($mockQuerySettings));
225
226 $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
227
228 $this->mockQuery->expects($this->once())->method('equals')->with('uid', $fakeUid)->will($this->returnValue('matchingConstraint'));
229 $this->mockQuery->expects($this->once())->method('matching')->with('matchingConstraint')->will($this->returnValue($this->mockQuery));
230 $this->mockQuery->expects($this->once())->method('execute')->will($this->returnValue($mockQueryResult));
231 $mockQueryResult->expects($this->once())->method('getFirst')->will($this->returnValue($object));
232
233 $this->mockIdentityMap->expects($this->once())->method('hasIdentifier')->with($fakeUid, 'someObjectType')->will($this->returnValue(FALSE));
234 $this->mockIdentityMap->expects($this->once())->method('registerObject')->with($object, $fakeUid);
235 $this->mockQueryFactory->expects($this->once())->method('create')->with('someObjectType')->will($this->returnValue($this->mockQuery));
236
237 $expectedResult = $object;
238 $actualResult = $this->repository->findByUid($fakeUid);
239 $this->assertSame($expectedResult, $actualResult);
240 }
241
242 /**
243 * Replacing a reconstituted object (which has a uuid) by a new object
244 * will ask the persistence backend to replace them accordingly in the
245 * identity map.
246 *
247 * @test
248 * @return void
249 */
250 public function replaceReplacesReconstitutedEntityByNewObject() {
251 $existingObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
252 $newObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
253
254 $mockBackend = $this->getMock('Tx_Extbase_Persistence_BackendInterface');
255 $this->mockPersistenceManager->expects($this->once())->method('getBackend')->will($this->returnValue($mockBackend));
256 $mockBackend->expects($this->once())->method('getIdentifierByObject')->with($existingObject)->will($this->returnValue('123'));
257 $mockBackend->expects($this->once())->method('replaceObject')->with($existingObject, $newObject);
258
259 $mockSession = $this->getMock('Tx_Extbase_Persistence_Session');
260 $this->mockPersistenceManager->expects($this->once())->method('getSession')->will($this->returnValue($mockSession));
261
262 $this->repository->_set('objectType', get_class($newObject));
263 $this->repository->replace($existingObject, $newObject);
264 }
265
266 /**
267 * Replacing a reconstituted object which during this session has been
268 * marked for removal (by calling the repository's remove method)
269 * additionally registers the "newObject" for removal and removes the
270 * "existingObject" from the list of removed objects.
271 *
272 * @test
273 * @return void
274 */
275 public function replaceRemovesReconstitutedObjectWhichIsMarkedToBeRemoved() {
276 $existingObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
277 $newObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
278
279 $removedObjects = new SplObjectStorage;
280 $removedObjects->attach($existingObject);
281
282 $mockBackend = $this->getMock('Tx_Extbase_Persistence_BackendInterface');
283 $this->mockPersistenceManager->expects($this->once())->method('getBackend')->will($this->returnValue($mockBackend));
284 $mockBackend->expects($this->once())->method('getIdentifierByObject')->with($existingObject)->will($this->returnValue('123'));
285 $mockBackend->expects($this->once())->method('replaceObject')->with($existingObject, $newObject);
286
287 $mockSession = $this->getMock('Tx_Extbase_Persistence_Session');
288 $this->mockPersistenceManager->expects($this->once())->method('getSession')->will($this->returnValue($mockSession));
289
290 $this->repository->_set('objectType', get_class($newObject));
291 $this->repository->_set('removedObjects', $removedObjects);
292 $this->repository->replace($existingObject, $newObject);
293
294 $this->assertFalse($removedObjects->contains($existingObject));
295 $this->assertTrue($removedObjects->contains($newObject));
296 }
297
298 /**
299 * Replacing a new object which has not yet been persisted by another
300 * new object will just replace them in the repository's list of added
301 * objects.
302 *
303 * @test
304 * @return void
305 */
306 public function replaceAddsNewObjectToAddedObjects() {
307 $existingObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
308 $newObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
309
310 $addedObjects = new SplObjectStorage;
311 $addedObjects->attach($existingObject);
312
313 $mockBackend = $this->getMock('Tx_Extbase_Persistence_BackendInterface');
314 $this->mockPersistenceManager->expects($this->once())->method('getBackend')->will($this->returnValue($mockBackend));
315 $mockBackend->expects($this->once())->method('getIdentifierByObject')->with($existingObject)->will($this->returnValue(NULL));
316 $mockBackend->expects($this->never())->method('replaceObject');
317
318 $mockSession = $this->getMock('Tx_Extbase_Persistence_Session');
319 $this->mockPersistenceManager->expects($this->once())->method('getSession')->will($this->returnValue($mockSession));
320
321 $this->repository->_set('objectType', get_class($newObject));
322 $this->repository->_set('addedObjects', $addedObjects);
323 $this->repository->replace($existingObject, $newObject);
324
325 $this->assertFalse($addedObjects->contains($existingObject));
326 $this->assertTrue($addedObjects->contains($newObject));
327 }
328
329 /**
330 * @test
331 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
332 */
333 public function replaceChecksObjectType() {
334 $this->repository->_set('objectType', 'ExpectedObjectType');
335
336 $this->repository->replace(new stdClass(), new stdClass());
337 }
338
339 /**
340 * @test
341 */
342 public function updateReplacesAnObjectWithTheSameUuidByTheGivenObject() {
343 $existingObject = new stdClass;
344 $modifiedObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
345 $modifiedObject->expects($this->once())->method('getUid')->will($this->returnValue('123'));
346
347 $repository = $this->getAccessibleMock('Tx_Extbase_Persistence_Repository', array('findByUid', 'replace'));
348 $repository->expects($this->once())->method('findByUid')->with('123')->will($this->returnValue($existingObject));
349 $repository->expects($this->once())->method('replace')->with($existingObject, $modifiedObject);
350 $repository->_set('objectType', get_class($modifiedObject));
351 $repository->update($modifiedObject);
352 }
353
354 /**
355 * @test
356 * @expectedException Tx_Extbase_Persistence_Exception_UnknownObject
357 */
358 public function updateRejectsUnknownObjects() {
359 $someObject = $this->getMock('Tx_Extbase_DomainObject_DomainObjectInterface');
360 $someObject->expects($this->once())->method('getUid')->will($this->returnValue(NULL));
361
362 $this->repository->_set('objectType', get_class($someObject));
363
364 $this->repository->update($someObject);
365 }
366
367 /**
368 * @test
369 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
370 */
371 public function updateRejectsObjectsOfWrongType() {
372 $this->repository->_set('objectType', 'Foo');
373 $this->repository->update(new stdClass());
374 }
375
376 /**
377 * @test
378 */
379 public function magicCallMethodAcceptsFindBySomethingCallsAndExecutesAQueryWithThatCriteria() {
380 $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
381 $this->mockQuery->expects($this->once())->method('equals')->with('foo', 'bar')->will($this->returnValue('matchCriteria'));
382 $this->mockQuery->expects($this->once())->method('matching')->with('matchCriteria')->will($this->returnValue($this->mockQuery));
383 $this->mockQuery->expects($this->once())->method('execute')->will($this->returnValue($mockQueryResult));
384
385 $this->assertSame($mockQueryResult, $this->repository->findByFoo('bar'));
386 }
387
388 /**
389 * @test
390 */
391 public function magicCallMethodAcceptsFindOneBySomethingCallsAndExecutesAQueryWithThatCriteria() {
392 $object = new stdClass();
393 $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
394 $mockQueryResult->expects($this->once())->method('getFirst')->will($this->returnValue($object));
395 $this->mockQuery->expects($this->once())->method('equals')->with('foo', 'bar')->will($this->returnValue('matchCriteria'));
396 $this->mockQuery->expects($this->once())->method('matching')->with('matchCriteria')->will($this->returnValue($this->mockQuery));
397 $this->mockQuery->expects($this->once())->method('setLimit')->with(1)->will($this->returnValue($this->mockQuery));
398 $this->mockQuery->expects($this->once())->method('execute')->will($this->returnValue($mockQueryResult));
399
400 $this->assertSame($object, $this->repository->findOneByFoo('bar'));
401 }
402
403 /**
404 * @test
405 */
406 public function magicCallMethodAcceptsCountBySomethingCallsAndExecutesAQueryWithThatCriteria() {
407 $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
408 $mockQueryResult->expects($this->once())->method('count')->will($this->returnValue(2));
409 $this->mockQuery->expects($this->once())->method('equals')->with('foo', 'bar')->will($this->returnValue('matchCriteria'));
410 $this->mockQuery->expects($this->once())->method('matching')->with('matchCriteria')->will($this->returnValue($this->mockQuery));
411 $this->mockQuery->expects($this->once())->method('execute')->will($this->returnValue($mockQueryResult));
412
413 $this->assertSame(2, $this->repository->countByFoo('bar'));
414 }
415
416 /**
417 * @test
418 * @expectedException Exception
419 */
420 public function magicCallMethodTriggersAnErrorIfUnknownMethodsAreCalled() {
421 $this->repository->__call('foo', array());
422 }
423
424 /**
425 * @test
426 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
427 */
428 public function addChecksObjectType() {
429 $this->repository->_set('objectType', 'ExpectedObjectType');
430
431 $this->repository->add(new stdClass());
432 }
433
434 /**
435 * @test
436 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
437 */
438 public function removeChecksObjectType() {
439 $this->repository->_set('objectType', 'ExpectedObjectType');
440
441 $this->repository->remove(new stdClass());
442 }
443
444 }
445 ?>