9e612753dd71157eb2faa5ba711dd00b6ec8200c
[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_Persistence_IdentityMap
34 */
35 protected $identityMap;
36
37 /**
38 * @var Tx_Extbase_Persistence_QueryFactory
39 */
40 protected $queryFactory;
41
42 /**
43 * @var Tx_Extbase_Persistence_ManagerInterface
44 */
45 protected $persistenceManager;
46
47 /**
48 * @var Tx_Extbase_Persistence_QueryInterface
49 */
50 protected $query;
51
52 /**
53 * @var Tx_Extbase_Persistence_QuerySettingsInterface
54 */
55 protected $querySettings;
56
57 public function setUp() {
58 $this->identityMap = $this->getMock('Tx_Extbase_Persistence_IdentityMap');
59 $this->queryFactory = $this->getMock('Tx_Extbase_Persistence_QueryFactory');
60 $this->query = $this->getMock('Tx_Extbase_Persistence_QueryInterface');
61 $this->querySettings = $this->getMock('Tx_Extbase_Persistence_QuerySettingsInterface');
62 $this->query->expects($this->any())->method('getQuerySettings')->will($this->returnValue($this->querySettings));
63 $this->queryFactory->expects($this->any())->method('create')->will($this->returnValue($this->query));
64 $this->persistenceManager = $this->getMock('Tx_Extbase_Persistence_ManagerInterface');
65 $this->repository = $this->getAccessibleMock('Tx_Extbase_Persistence_Repository', array('dummy'), array($this->identityMap, $this->queryFactory, $this->persistenceManager));
66 }
67
68 /**
69 * @test
70 */
71 public function abstractRepositoryImplementsRepositoryInterface() {
72 $this->assertTrue($this->repository instanceof Tx_Extbase_Persistence_RepositoryInterface);
73 }
74
75 /**
76 * @test
77 */
78 public function addActuallyAddsAnObjectToTheInternalObjectsArray() {
79 $someObject = new stdClass();
80 $this->repository->_set('objectType', get_class($someObject));
81 $this->repository->add($someObject);
82
83 $this->assertTrue($this->repository->getAddedObjects()->contains($someObject));
84 }
85
86 /**
87 * @test
88 */
89 public function removeActuallyRemovesAnObjectFromTheInternalObjectsArray() {
90 $object1 = new stdClass();
91 $object2 = new stdClass();
92 $object3 = new stdClass();
93
94 $this->repository->_set('objectType', get_class($object1));
95 $this->repository->add($object1);
96 $this->repository->add($object2);
97 $this->repository->add($object3);
98
99 $this->repository->remove($object2);
100
101 $this->assertTrue($this->repository->getAddedObjects()->contains($object1));
102 $this->assertFalse($this->repository->getAddedObjects()->contains($object2));
103 $this->assertTrue($this->repository->getAddedObjects()->contains($object3));
104 }
105
106 /**
107 * @test
108 */
109 public function removeRemovesTheRightObjectEvenIfItHasBeenModifiedSinceItsAddition() {
110 $object1 = new ArrayObject(array('val' => '1'));
111 $object2 = new ArrayObject(array('val' => '2'));
112 $object3 = new ArrayObject(array('val' => '3'));
113
114 $this->repository->_set('objectType', get_class($object1));
115 $this->repository->add($object1);
116 $this->repository->add($object2);
117 $this->repository->add($object3);
118
119 $object2['foo'] = 'bar';
120 $object3['val'] = '2';
121
122 $this->repository->remove($object2);
123
124 $this->assertTrue($this->repository->getAddedObjects()->contains($object1));
125 $this->assertFalse($this->repository->getAddedObjects()->contains($object2));
126 $this->assertTrue($this->repository->getAddedObjects()->contains($object3));
127 }
128
129 /**
130 * Make sure we remember the objects that are not currently add()ed
131 * but might be in persistent storage.
132 *
133 * @test
134 */
135 public function removeRetainsObjectForObjectsNotInCurrentSession() {
136 $object = new ArrayObject(array('val' => '1'));
137 $this->repository->_set('objectType', get_class($object));
138 $this->repository->remove($object);
139
140 $this->assertTrue($this->repository->getRemovedObjects()->contains($object));
141 }
142
143 /**
144 * dataProvider for createQueryCallsQueryFactoryWithExpectedType
145 */
146 public function modelAndRepositoryClassNames() {
147 return array(
148 array('Tx_BlogExample_Domain_Repository_BlogRepository', 'Tx_BlogExample_Domain_Model_Blog'),
149 array('_Domain_Repository_Content_PageRepository', '_Domain_Model_Content_Page')
150 );
151 }
152
153 /**
154 * @test
155 * @dataProvider modelAndRepositoryClassNames
156 */
157 public function constructSetsObjectTypeFromClassName($repositoryClassName, $modelClassName) {
158 $mockClassName = 'MockRepository' . uniqid();
159 eval('class ' . $mockClassName . ' extends Tx_Extbase_Persistence_Repository {
160 protected function getRepositoryClassName() {
161 return \'' . $repositoryClassName . '\';
162 }
163 public function _getObjectType() {
164 return $this->objectType;
165 }
166 }');
167
168 $this->repository = new $mockClassName($this->identityMap, $this->queryFactory, $this->persistenceManager);
169 $this->assertEquals($modelClassName, $this->repository->_getObjectType());
170 }
171
172 /**
173 * @test
174 */
175 public function createQueryCallsQueryFactoryWithExpectedClassName() {
176 $this->queryFactory->expects($this->once())->method('create')->with('ExpectedType');
177 $this->repository->_set('objectType', 'ExpectedType');
178 $this->repository->createQuery();
179 }
180
181 /**
182 * @test
183 */
184 public function findAllCreatesQueryAndReturnsResultOfExecuteCall() {
185 $expectedResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
186 $this->query->expects($this->once())->method('execute')->with()->will($this->returnValue($expectedResult));
187 $this->assertSame($expectedResult, $this->repository->findAll());
188 }
189
190 /**
191 * @test
192 */
193 public function findByUidReturnsResultOfGetObjectByIdentifierCall() {
194 $fakeUid = '123';
195 $object = new stdClass();
196
197 $this->persistenceManager->expects($this->once())->method('getObjectByIdentifier')->with($fakeUid)->will($this->returnValue($object));
198 $this->repository->_set('objectType', 'stdClass');
199
200 $this->assertSame($object, $this->repository->findByUid($fakeUid));
201 }
202
203 /**
204 * @test
205 */
206 public function findByUidReturnsNullIfObjectOfMismatchingTypeWasFoundByGetObjectByIdentifierCall() {
207 $fakeUUID = '123';
208 $object = new stdClass();
209
210 $this->persistenceManager->expects($this->once())->method('getObjectByIdentifier')->with($fakeUUID)->will($this->returnValue($object));
211 $this->repository->_set('objectType', 'otherExpectedClass');
212
213 $this->assertNULL($this->repository->findByUuid($fakeUUID));
214 }
215
216 /**
217 * Replacing a reconstituted object (which has a uuid) by a new object
218 * will ask the persistence backend to replace them accordingly in the
219 * identity map.
220 *
221 * @test
222 * @return void
223 */
224 public function replaceReconstitutedEntityByNewObject() {
225 $existingObject = new stdClass;
226 $newObject = new stdClass;
227
228 $this->persistenceManager->expects($this->once())->method('getIdentifierByObject')->with($existingObject)->will($this->returnValue('86ea8820-19f6-11de-8c30-0800200c9a66'));
229 $this->persistenceManager->expects($this->once())->method('replaceObject')->with($existingObject, $newObject);
230
231 $this->repository->_set('objectType', get_class($newObject));
232 $this->repository->replace($existingObject, $newObject);
233 }
234
235 /**
236 * Replacing a reconstituted object which during this session has been
237 * marked for removal (by calling the repository's remove method)
238 * additionally registers the "newObject" for removal and removes the
239 * "existingObject" from the list of removed objects.
240 *
241 * @test
242 * @return void
243 */
244 public function replaceReconstitutedObjectWhichIsMarkedToBeRemoved() {
245 $existingObject = new stdClass;
246 $newObject = new stdClass;
247
248 $removedObjects = new SplObjectStorage;
249 $removedObjects->attach($existingObject);
250
251 $this->persistenceManager->expects($this->once())->method('getIdentifierByObject')->with($existingObject)->will($this->returnValue('86ea8820-19f6-11de-8c30-0800200c9a66'));
252 $this->persistenceManager->expects($this->once())->method('replaceObject')->with($existingObject, $newObject);
253
254 $this->repository->_set('objectType', get_class($newObject));
255 $this->repository->_set('removedObjects', $removedObjects);
256 $this->repository->replace($existingObject, $newObject);
257
258 $this->assertFalse($removedObjects->contains($existingObject));
259 $this->assertTrue($removedObjects->contains($newObject));
260 }
261
262 /**
263 * Replacing a new object which has not yet been persisted by another
264 * new object will just replace them in the repository's list of added
265 * objects.
266 *
267 * @test
268 * @return void
269 */
270 public function replaceNewObjectByNewObject() {
271 $existingObject = new stdClass;
272 $newObject = new stdClass;
273
274 $addedObjects = new SplObjectStorage;
275 $addedObjects->attach($existingObject);
276
277 $this->persistenceManager->expects($this->once())->method('getIdentifierByObject')->with($existingObject)->will($this->returnValue(NULL));
278 $this->persistenceManager->expects($this->never())->method('replaceObject');
279
280 $this->repository->_set('objectType', get_class($newObject));
281 $this->repository->_set('addedObjects', $addedObjects);
282 $this->repository->replace($existingObject, $newObject);
283
284 $this->assertFalse($addedObjects->contains($existingObject));
285 $this->assertTrue($addedObjects->contains($newObject));
286 }
287
288 /**
289 * @test
290 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
291 */
292 public function replaceChecksObjectType() {
293 $this->repository->_set('objectType', 'ExpectedObjectType');
294
295 $this->repository->replace(new stdClass(), new stdClass());
296 }
297
298 /**
299 * @test
300 */
301 public function updateReplacesAnObjectWithTheSameUuidByTheGivenObject() {
302 $existingObject = new stdClass;
303 $modifiedObject = $this->getMock('FooBar' . uniqid(), array('FLOW3_Persistence_isClone'));
304 $modifiedObject->expects($this->once())->method('FLOW3_Persistence_isClone')->will($this->returnValue(TRUE));
305
306 $this->persistenceManager->expects($this->once())->method('getIdentifierByObject')->with($modifiedObject)->will($this->returnValue('86ea8820-19f6-11de-8c30-0800200c9a66'));
307 $this->persistenceManager->expects($this->once())->method('getObjectByIdentifier')->with('86ea8820-19f6-11de-8c30-0800200c9a66')->will($this->returnValue($existingObject));
308
309 $this->repository->expects($this->once())->method('replaceObject')->with($existingObject, $modifiedObject);
310
311 $this->repository->_set('objectType', get_class($modifiedObject));
312 $this->repository->update($modifiedObject);
313 }
314
315 /**
316 * @test
317 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
318 */
319 public function updateRejectsNonClonedObjects() {
320 $someObject = $this->getMock('FooBar' . uniqid(), array('FLOW3_Persistence_isClone'));
321 $someObject->expects($this->once())->method('FLOW3_Persistence_isClone')->will($this->returnValue(FALSE));
322
323 $this->repository->_set('objectType', get_class($someObject));
324
325 $this->repository->update($someObject);
326 }
327
328 /**
329 * @test
330 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
331 */
332 public function updateRejectsObjectsOfWrongType() {
333 $this->repository->_set('objectType', 'Foo');
334 $this->repository->update(new stdClass());
335 }
336
337 /**
338 * @test
339 */
340 public function magicCallMethodAcceptsFindBySomethingCallsAndExecutesAQueryWithThatCriteria() {
341 $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
342 $mockQuery = $this->getMock('Tx_Extbase_Persistence_QueryInterface');
343 $mockQuery->expects($this->once())->method('equals')->with('foo', 'bar')->will($this->returnValue('matchCriteria'));
344 $mockQuery->expects($this->once())->method('matching')->with('matchCriteria')->will($this->returnValue($mockQuery));
345 $mockQuery->expects($this->once())->method('execute')->with()->will($this->returnValue($mockQueryResult));
346
347 $this->repository->expects($this->once())->method('createQuery')->will($this->returnValue($mockQuery));
348
349 $this->assertSame($mockQueryResult, $this->repository->findByFoo('bar'));
350 }
351
352 /**
353 * @test
354 */
355 public function magicCallMethodAcceptsFindOneBySomethingCallsAndExecutesAQueryWithThatCriteria() {
356 $object = new stdClass();
357 $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
358 $mockQueryResult->expects($this->once())->method('getFirst')->will($this->returnValue($object));
359 $mockQuery = $this->getMock('Tx_Extbase_Persistence_QueryInterface');
360 $mockQuery->expects($this->once())->method('equals')->with('foo', 'bar')->will($this->returnValue('matchCriteria'));
361 $mockQuery->expects($this->once())->method('matching')->with('matchCriteria')->will($this->returnValue($mockQuery));
362 $mockQuery->expects($this->once())->method('execute')->will($this->returnValue($mockQueryResult));
363
364 $this->repository->expects($this->once())->method('createQuery')->will($this->returnValue($mockQuery));
365
366 $this->assertSame($object, $this->repository->findOneByFoo('bar'));
367 }
368
369 /**
370 * @test
371 */
372 public function magicCallMethodAcceptsCountBySomethingCallsAndExecutesAQueryWithThatCriteria() {
373 $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
374 $mockQueryResult->expects($this->once())->method('count')->will($this->returnValue(2));
375 $mockQuery = $this->getMock('Tx_Extbase_Persistence_QueryInterface');
376 $mockQuery->expects($this->once())->method('equals')->with('foo', 'bar')->will($this->returnValue('matchCriteria'));
377 $mockQuery->expects($this->once())->method('matching')->with('matchCriteria')->will($this->returnValue($mockQuery));
378 $mockQuery->expects($this->once())->method('execute')->will($this->returnValue($mockQueryResult));
379
380 $this->repository->expects($this->once())->method('createQuery')->will($this->returnValue($mockQuery));
381
382 $this->assertSame(2, $this->repository->countByFoo('bar'));
383 }
384
385 /**
386 * @test
387 * @expectedException Exception
388 */
389 public function magicCallMethodTriggersAnErrorIfUnknownMethodsAreCalled() {
390 $this->repository->__call('foo', array());
391 }
392
393 /**
394 * @test
395 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
396 */
397 public function addChecksObjectType() {
398 $this->repository->_set('objectType', 'ExpectedObjectType');
399
400 $this->repository->add(new stdClass());
401 }
402
403 /**
404 * @test
405 * @expectedException Tx_Extbase_Persistence_Exception_IllegalObjectType
406 */
407 public function removeChecksObjectType() {
408 $this->repository->_set('objectType', 'ExpectedObjectType');
409
410 $this->repository->remove(new stdClass());
411 }
412
413 }
414 ?>