This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Wikibase\Lib\Tests; |
||
4 | |||
5 | use PHPUnit\Framework\TestCase; |
||
6 | use User; |
||
7 | use Wikibase\DataModel\Entity\EntityRedirect; |
||
8 | use Wikibase\DataModel\Entity\Item; |
||
9 | use Wikibase\DataModel\Entity\ItemId; |
||
10 | use Wikibase\DataModel\Entity\Property; |
||
11 | use Wikibase\DataModel\Entity\PropertyId; |
||
12 | use Wikibase\DataModel\Services\Lookup\EntityRedirectLookupException; |
||
13 | use Wikibase\DataModel\SiteLink; |
||
14 | use Wikibase\Lib\Store\EntityRevision; |
||
15 | use Wikibase\Lib\Store\RevisionedUnresolvedRedirectException; |
||
16 | use Wikibase\Lib\Store\StorageException; |
||
17 | |||
18 | /** |
||
19 | * @covers \Wikibase\Lib\Tests\MockRepository |
||
20 | * |
||
21 | * @group Wikibase |
||
22 | * @group WikibaseEntityLookup |
||
23 | * |
||
24 | * @license GPL-2.0-or-later |
||
25 | * @author Daniel Kinzler |
||
26 | */ |
||
27 | class MockRepositoryTest extends TestCase { |
||
28 | |||
29 | /** |
||
30 | * @var MockRepository|null |
||
31 | */ |
||
32 | private $repo = null; |
||
33 | |||
34 | protected function setUp(): void { |
||
35 | parent::setUp(); |
||
36 | |||
37 | $this->repo = new MockRepository(); |
||
38 | } |
||
39 | |||
40 | public function testHasEntity() { |
||
41 | $q23 = new ItemId( 'q23' ); |
||
42 | $q42 = new ItemId( 'q42' ); |
||
43 | |||
44 | $p23 = new PropertyId( 'p23' ); |
||
45 | $p42 = new PropertyId( 'p42' ); |
||
46 | |||
47 | $item = new Item( $q23 ); |
||
48 | $this->repo->putEntity( $item ); |
||
49 | |||
50 | $prop = Property::newFromType( 'string' ); |
||
51 | $prop->setId( $p23 ); |
||
52 | $this->repo->putEntity( $prop ); |
||
53 | |||
54 | // test item |
||
55 | $this->assertTrue( $this->repo->hasEntity( $q23 ) ); |
||
56 | $this->assertFalse( $this->repo->hasEntity( $q42 ) ); |
||
57 | |||
58 | // test prop |
||
59 | $this->assertTrue( $this->repo->hasEntity( $p23 ) ); |
||
60 | $this->assertFalse( $this->repo->hasEntity( $p42 ) ); |
||
61 | } |
||
62 | |||
63 | public function testGetEntity() { |
||
64 | $item = new Item(); |
||
65 | $item->setLabel( 'en', 'foo' ); |
||
66 | |||
67 | // set up a data Item |
||
68 | $this->repo->putEntity( $item, 23 ); |
||
69 | $itemId = $item->getId(); |
||
70 | |||
71 | // set up another version of the data Item |
||
72 | $item->setLabel( 'de', 'bar' ); |
||
73 | $this->repo->putEntity( $item, 24 ); |
||
74 | |||
75 | // set up a property |
||
76 | $prop = Property::newFromType( 'string' ); |
||
77 | $prop->setLabel( 'en', 'foo' ); |
||
78 | $prop->setId( PropertyId::newFromNumber( $itemId->getNumericId() ) ); // same numeric id, different prefix |
||
79 | |||
80 | $propId = $prop->getId(); |
||
81 | $this->repo->putEntity( $prop ); |
||
82 | |||
83 | // test latest item |
||
84 | /** @var Item $item */ |
||
85 | $item = $this->repo->getEntity( $itemId ); |
||
86 | $this->assertNotNull( $item, 'Entity ' . $itemId ); |
||
87 | $this->assertInstanceOf( Item::class, $item, 'Entity ' . $itemId ); |
||
88 | $this->assertEquals( 'foo', $item->getLabels()->getByLanguage( 'en' )->getText() ); |
||
89 | $this->assertEquals( 'bar', $item->getLabels()->getByLanguage( 'de' )->getText() ); |
||
90 | |||
91 | // test we can't mess with entities in the repo |
||
92 | $item->setLabel( 'en', 'STRANGE' ); |
||
93 | $item = $this->repo->getEntity( $itemId ); |
||
94 | $this->assertEquals( 'foo', $item->getLabels()->getByLanguage( 'en' )->getText() ); |
||
95 | |||
96 | // test latest prop |
||
97 | $prop = $this->repo->getEntity( $propId ); |
||
98 | $this->assertNotNull( $prop, 'Entity ' . $propId ); |
||
99 | $this->assertInstanceOf( Property::class, $prop, 'Entity ' . $propId ); |
||
100 | } |
||
101 | |||
102 | public function testGetEntityRevision() { |
||
103 | $item = new Item(); |
||
104 | $item->setLabel( 'en', 'foo' ); |
||
105 | |||
106 | // set up a data Item |
||
107 | $this->repo->putEntity( $item, 23, '20130101000000' ); |
||
108 | $itemId = $item->getId(); |
||
109 | |||
110 | // set up another version of the data Item |
||
111 | $item->setLabel( 'de', 'bar' ); |
||
112 | $this->repo->putEntity( $item, 24 ); |
||
113 | |||
114 | // set up a property |
||
115 | $prop = Property::newFromType( 'string' ); |
||
116 | $prop->setLabel( 'en', 'foo' ); |
||
117 | $prop->setId( PropertyId::newFromNumber( $itemId->getNumericId() ) ); // same numeric id, different prefix |
||
118 | |||
119 | $propId = $prop->getId(); |
||
120 | $this->repo->putEntity( $prop ); |
||
121 | |||
122 | // test latest item |
||
123 | $itemRev = $this->repo->getEntityRevision( $itemId ); |
||
124 | $this->assertNotNull( $item, 'Entity ' . $itemId ); |
||
125 | $this->assertInstanceOf( EntityRevision::class, $itemRev, 'Entity ' . $itemId ); |
||
126 | $this->assertInstanceOf( Item::class, $itemRev->getEntity(), 'Entity ' . $itemId ); |
||
127 | $this->assertEquals( 24, $itemRev->getRevisionId() ); |
||
128 | |||
129 | // test item by rev id |
||
130 | $itemRev = $this->repo->getEntityRevision( $itemId, 23 ); |
||
131 | $this->assertNotNull( $item, 'Entity ' . $itemId . '@23' ); |
||
132 | $this->assertInstanceOf( EntityRevision::class, $itemRev, 'Entity ' . $itemId ); |
||
133 | $this->assertInstanceOf( Item::class, $itemRev->getEntity(), 'Entity ' . $itemId ); |
||
134 | $this->assertEquals( 23, $itemRev->getRevisionId() ); |
||
135 | $this->assertSame( '20130101000000', $itemRev->getTimestamp() ); |
||
136 | |||
137 | // test latest prop |
||
138 | $propRev = $this->repo->getEntityRevision( $propId ); |
||
139 | $this->assertNotNull( $propRev, 'Entity ' . $propId ); |
||
140 | $this->assertInstanceOf( EntityRevision::class, $propRev, 'Entity ' . $propId ); |
||
141 | $this->assertInstanceOf( Property::class, $propRev->getEntity(), 'Entity ' . $propId ); |
||
142 | } |
||
143 | |||
144 | public function testGetItemIdForLink() { |
||
145 | $item = new Item(); |
||
146 | $item->getSiteLinkList()->addNewSiteLink( 'enwiki', 'Foo' ); |
||
147 | |||
148 | // test item lookup |
||
149 | $this->repo->putEntity( $item ); |
||
150 | $itemId = $item->getId(); |
||
151 | |||
152 | $this->assertEquals( $itemId, $this->repo->getItemIdForLink( 'enwiki', 'Foo' ) ); |
||
153 | $this->assertNull( $this->repo->getItemIdForLink( 'xywiki', 'Foo' ) ); |
||
154 | |||
155 | // test lookup after item modification |
||
156 | $item->getSiteLinkList()->setNewSiteLink( 'enwiki', 'Bar' ); |
||
157 | $this->repo->putEntity( $item ); |
||
158 | |||
159 | $this->assertNull( $this->repo->getItemIdForLink( 'enwiki', 'Foo' ) ); |
||
160 | $this->assertEquals( $itemId, $this->repo->getItemIdForLink( 'enwiki', 'Bar' ) ); |
||
161 | |||
162 | // test lookup after item deletion |
||
163 | $this->repo->removeEntity( $itemId ); |
||
164 | |||
165 | $this->assertNull( $this->repo->getItemIdForLink( 'enwiki', 'Foo' ) ); |
||
166 | $this->assertNull( $this->repo->getItemIdForLink( 'enwiki', 'Bar' ) ); |
||
167 | } |
||
168 | |||
169 | public function provideGetLinks() { |
||
170 | $a = new Item( new ItemId( 'Q1' ) ); |
||
171 | $a->getSiteLinkList()->addNewSiteLink( 'enwiki', 'Foo' ); |
||
172 | $a->getSiteLinkList()->addNewSiteLink( 'dewiki', 'Bar' ); |
||
173 | |||
174 | $b = new Item( new ItemId( 'Q2' ) ); |
||
175 | $b->getSiteLinkList()->addNewSiteLink( 'enwiki', 'Bar' ); |
||
176 | $b->getSiteLinkList()->addNewSiteLink( 'dewiki', 'Xoo' ); |
||
177 | |||
178 | $items = [ $a, $b ]; |
||
179 | |||
180 | return [ |
||
181 | 'all' => [ |
||
182 | $items, |
||
183 | 'numericIds' => [], |
||
184 | 'siteIds' => [], |
||
185 | 'pageNames' => [], |
||
186 | 'expectedLinks' => [ |
||
187 | [ 'enwiki', 'Foo', 1 ], |
||
188 | [ 'dewiki', 'Bar', 1 ], |
||
189 | [ 'enwiki', 'Bar', 2 ], |
||
190 | [ 'dewiki', 'Xoo', 2 ], |
||
191 | ] |
||
192 | ], |
||
193 | 'mismatch' => [ |
||
194 | $items, |
||
195 | 'numericIds' => [], |
||
196 | 'siteIds' => [ 'enwiki' ], |
||
197 | 'pageNames' => [ 'Xoo' ], |
||
198 | 'expectedLinks' => [] |
||
199 | ], |
||
200 | 'by item' => [ |
||
201 | $items, |
||
202 | 'numericIds' => [ 1 ], |
||
203 | 'siteIds' => [], |
||
204 | 'pageNames' => [], |
||
205 | 'expectedLinks' => [ |
||
206 | [ 'enwiki', 'Foo', 1 ], |
||
207 | [ 'dewiki', 'Bar', 1 ], |
||
208 | ] |
||
209 | ], |
||
210 | 'by site' => [ |
||
211 | $items, |
||
212 | 'numericIds' => [], |
||
213 | 'siteIds' => [ 'enwiki' ], |
||
214 | 'pageNames' => [], |
||
215 | 'expectedLinks' => [ |
||
216 | [ 'enwiki', 'Foo', 1 ], |
||
217 | [ 'enwiki', 'Bar', 2 ], |
||
218 | ] |
||
219 | ], |
||
220 | 'by page' => [ |
||
221 | $items, |
||
222 | 'numericIds' => [], |
||
223 | 'siteIds' => [], |
||
224 | 'pageNames' => [ 'Bar' ], |
||
225 | 'expectedLinks' => [ |
||
226 | [ 'dewiki', 'Bar', 1 ], |
||
227 | [ 'enwiki', 'Bar', 2 ], |
||
228 | ] |
||
229 | ], |
||
230 | 'by site and page' => [ |
||
231 | $items, |
||
232 | 'numericIds' => [], |
||
233 | 'siteIds' => [ 'dewiki' ], |
||
234 | 'pageNames' => [ 'Bar' ], |
||
235 | 'expectedLinks' => [ |
||
236 | [ 'dewiki', 'Bar', 1 ], |
||
237 | ] |
||
238 | ], |
||
239 | ]; |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * @dataProvider provideGetLinks |
||
244 | */ |
||
245 | public function testGetLinks( |
||
246 | array $items, |
||
247 | array $numericIds, |
||
248 | array $siteIds, |
||
249 | array $pageNames, |
||
250 | array $expectedLinks |
||
251 | ) { |
||
252 | foreach ( $items as $item ) { |
||
253 | $this->repo->putEntity( $item ); |
||
254 | } |
||
255 | |||
256 | $links = $this->repo->getLinks( $numericIds, $siteIds, $pageNames ); |
||
257 | |||
258 | $this->assertEquals( $expectedLinks, $links ); |
||
259 | } |
||
260 | |||
261 | public function provideGetEntities() { |
||
262 | return [ |
||
263 | 'empty' => [ |
||
264 | 'itemIds' => [], |
||
265 | 'expectedLabels' => [] |
||
266 | ], |
||
267 | 'some entities' => [ |
||
268 | 'itemIds' => [ 'Q1', 'Q2' ], |
||
269 | 'expectedLabels' => [ |
||
270 | 'Q1' => [ |
||
271 | 'de' => 'eins', |
||
272 | 'en' => 'one', |
||
273 | ], |
||
274 | 'Q2' => [ |
||
275 | 'en' => 'two', |
||
276 | ], |
||
277 | ] |
||
278 | ], |
||
279 | 'bad ID' => [ |
||
280 | 'itemIds' => [ 'Q1', 'Q22' ], |
||
281 | 'expectedLabels' => [ |
||
282 | 'Q1' => [ |
||
283 | 'en' => 'one', |
||
284 | 'de' => 'eins', |
||
285 | ], |
||
286 | 'Q22' => null, |
||
287 | ] |
||
288 | ] |
||
289 | ]; |
||
290 | } |
||
291 | |||
292 | protected function setupGetEntities() { |
||
293 | $one = new Item( new ItemId( 'Q1' ) ); |
||
294 | $one->setLabel( 'en', 'one' ); |
||
295 | |||
296 | $two = new Item( new ItemId( 'Q2' ) ); |
||
297 | $two->setLabel( 'en', 'two' ); |
||
298 | |||
299 | $three = new Item( new ItemId( 'Q3' ) ); |
||
300 | $three->setLabel( 'en', 'three' ); |
||
301 | $three->setLabel( 'de', 'drei' ); |
||
302 | $three->setDescription( 'en', 'the third' ); |
||
303 | |||
304 | $prop = new Property( new PropertyId( 'P4' ), null, 'string' ); |
||
305 | $prop->setLabel( 'en', 'property!' ); |
||
306 | |||
307 | $this->repo->putEntity( $one, 1001 ); |
||
308 | $this->repo->putEntity( $two, 1002 ); |
||
309 | $this->repo->putEntity( $three, 1003 ); |
||
310 | $this->repo->putEntity( $prop, 1101 ); |
||
311 | |||
312 | $one->setLabel( 'de', 'eins' ); |
||
313 | $this->repo->putEntity( $one, 1011 ); |
||
314 | } |
||
315 | |||
316 | /** |
||
317 | * @dataProvider provideGetEntities |
||
318 | */ |
||
319 | public function testGetEntities( array $itemIds, array $expectedLabels ) { |
||
320 | $this->setupGetEntities(); |
||
321 | |||
322 | // convert string IDs to EntityId objects |
||
323 | foreach ( $itemIds as $i => $id ) { |
||
324 | if ( is_string( $id ) ) { |
||
325 | $itemIds[$i] = new ItemId( $id ); |
||
326 | } |
||
327 | } |
||
328 | |||
329 | /** @var Item[]|null[] $items */ |
||
330 | $items = $this->repo->getEntities( $itemIds ); |
||
331 | |||
332 | $this->assertIsArray( $items, 'return value' ); |
||
333 | |||
334 | // extract map of entity IDs to label arrays. |
||
335 | $actualLabels = []; |
||
336 | foreach ( $items as $key => $item ) { |
||
337 | if ( $item === null ) { |
||
338 | $actualLabels[$key] = null; |
||
339 | } else { |
||
340 | $actualLabels[$key] = $item->getLabels()->toTextArray(); |
||
341 | } |
||
342 | } |
||
343 | |||
344 | // check that we found the right number of entities |
||
345 | $this->assertEquals( count( $expectedLabels ), count( $actualLabels ), 'number of entities found' ); |
||
346 | |||
347 | foreach ( $expectedLabels as $id => $labels ) { |
||
348 | // check that thew correct entity was found |
||
349 | $this->assertArrayHasKey( $id, $actualLabels ); |
||
350 | |||
351 | if ( $labels === null ) { |
||
352 | // check that the entity/revision wasn't found |
||
353 | $this->assertNull( $actualLabels[$id] ); |
||
354 | } else { |
||
355 | // check that the entity contains the expected labels |
||
356 | $this->assertEquals( $labels, $actualLabels[ $id ] ); |
||
357 | } |
||
358 | } |
||
359 | } |
||
360 | |||
361 | public function testGetSiteLinksForItem() { |
||
362 | $one = new Item( new ItemId( 'Q1' ) ); |
||
363 | |||
364 | $one->getSiteLinkList()->addNewSiteLink( 'dewiki', 'Xoo' ); |
||
365 | $one->getSiteLinkList()->addNewSiteLink( 'enwiki', 'Foo' ); |
||
366 | |||
367 | $this->repo->putEntity( $one ); |
||
368 | |||
369 | // check link retrieval |
||
370 | $this->assertEquals( |
||
371 | [ |
||
372 | new SiteLink( 'dewiki', 'Xoo' ), |
||
373 | new SiteLink( 'enwiki', 'Foo' ), |
||
374 | ], |
||
375 | $this->repo->getSiteLinksForItem( $one->getId() ) |
||
376 | ); |
||
377 | |||
378 | // check links of unknown id |
||
379 | $this->assertSame( [], $this->repo->getSiteLinksForItem( new ItemId( 'q123' ) ) ); |
||
380 | } |
||
381 | |||
382 | public function provideSaveEntity() { |
||
383 | $item = new Item(); |
||
384 | $item->setLabel( 'en', 'one' ); |
||
385 | |||
386 | $secondItem = new Item( new ItemId( 'Q1' ) ); |
||
387 | $secondItem->setLabel( 'en', 'one' ); |
||
388 | $secondItem->setLabel( 'it', 'uno' ); |
||
389 | |||
390 | $thirdItem = new Item( new ItemId( 'Q1' ) ); |
||
391 | $thirdItem->setLabel( 'en', 'one' ); |
||
392 | |||
393 | $fourthItem = new Item( new ItemId( 'Q123' ) ); |
||
394 | $fourthItem->setLabel( 'en', 'one two three' ); |
||
395 | $fourthItem->setLabel( 'de', 'eins zwei drei' ); |
||
396 | |||
397 | $fifthItem = new Item( new ItemId( 'Q1' ) ); |
||
398 | $fifthItem->setLabel( 'en', 'one' ); |
||
399 | $fifthItem->setLabel( 'de', 'eins' ); |
||
400 | |||
401 | return [ |
||
402 | 'fresh' => [ |
||
403 | 'entity' => $item, |
||
404 | 'flags' => EDIT_NEW, |
||
405 | 'baseRevid' => false, |
||
406 | ], |
||
407 | |||
408 | 'update' => [ |
||
409 | 'entity' => $secondItem, |
||
410 | 'flags' => EDIT_UPDATE, |
||
411 | 'baseRevid' => 1011, |
||
412 | ], |
||
413 | |||
414 | 'not fresh' => [ |
||
415 | 'entity' => $thirdItem, |
||
416 | 'flags' => EDIT_NEW, |
||
417 | 'baseRevid' => false, |
||
418 | 'error' => StorageException::class |
||
419 | ], |
||
420 | |||
421 | 'not exists' => [ |
||
422 | 'entity' => $fourthItem, |
||
423 | 'flags' => EDIT_UPDATE, |
||
424 | 'baseRevid' => false, |
||
425 | 'error' => StorageException::class |
||
426 | ], |
||
427 | |||
428 | 'bad base' => [ |
||
429 | 'entity' => $fifthItem, |
||
430 | 'flags' => EDIT_UPDATE, |
||
431 | 'baseRevid' => 1234, |
||
432 | 'error' => StorageException::class |
||
433 | ], |
||
434 | ]; |
||
435 | } |
||
436 | |||
437 | /** |
||
438 | * @dataProvider provideSaveEntity |
||
439 | */ |
||
440 | public function testSaveEntity( Item $item, $flags, $baseRevId, $error = null ) { |
||
441 | $this->setupGetEntities(); |
||
442 | |||
443 | if ( $error !== null ) { |
||
444 | $this->expectException( $error ); |
||
445 | } |
||
446 | |||
447 | $rev = $this->repo->saveEntity( $item, 'f00', $this->getUserMock(), $flags, $baseRevId ); |
||
448 | $itemId = $item->getId(); |
||
449 | $revisionId = $rev->getRevisionId(); |
||
450 | |||
451 | $logEntry = $this->repo->getLogEntry( $revisionId ); |
||
452 | $this->assertNotNull( $logEntry ); |
||
453 | $this->assertEquals( $revisionId, $logEntry['revision'] ); |
||
454 | $this->assertEquals( $itemId->getSerialization(), $logEntry['entity'] ); |
||
455 | $this->assertEquals( 'f00', $logEntry['summary'] ); |
||
456 | |||
457 | /** @var Item $revisionItem */ |
||
458 | $revisionItem = $rev->getEntity(); |
||
459 | /** @var Item $savedItem */ |
||
460 | $savedItem = $this->repo->getEntity( $itemId ); |
||
461 | |||
462 | $this->assertTrue( $item->getFingerprint()->equals( $revisionItem->getFingerprint() ) ); |
||
463 | $this->assertTrue( $item->getFingerprint()->equals( $savedItem->getFingerprint() ) ); |
||
464 | |||
465 | // test we can't mess with entities in the repo |
||
466 | $item->setLabel( 'en', 'STRANGE' ); |
||
467 | $savedItem = $this->repo->getEntity( $itemId ); |
||
468 | $this->assertNotNull( $savedItem ); |
||
469 | $this->assertNotEquals( 'STRANGE', $savedItem->getLabels()->getByLanguage( 'en' )->getText() ); |
||
470 | } |
||
471 | |||
472 | public function testSaveRedirect() { |
||
473 | $this->setupGetEntities(); |
||
474 | |||
475 | $q10 = new ItemId( 'Q10' ); |
||
476 | $q1 = new ItemId( 'Q1' ); |
||
477 | |||
478 | $redirect = new EntityRedirect( $q10, $q1 ); |
||
479 | $revId = $this->repo->saveRedirect( $redirect, 'redirected Q10 to Q1', $this->getUserMock() ); |
||
480 | |||
481 | $this->assertGreaterThan( 0, $revId ); |
||
482 | |||
483 | $logEntry = $this->repo->getLogEntry( $revId ); |
||
484 | $this->assertNotNull( $logEntry ); |
||
485 | $this->assertEquals( $revId, $logEntry['revision'] ); |
||
486 | $this->assertEquals( $redirect->getEntityId()->getSerialization(), $logEntry['entity'] ); |
||
487 | $this->assertEquals( 'redirected Q10 to Q1', $logEntry['summary'] ); |
||
488 | |||
489 | $this->expectException( RevisionedUnresolvedRedirectException::class ); |
||
490 | $this->repo->getEntity( $q10 ); |
||
491 | } |
||
492 | |||
493 | public function testGetLogEntry() { |
||
494 | $this->setupGetEntities(); |
||
495 | |||
496 | $q10 = new ItemId( 'Q10' ); |
||
497 | $q11 = new ItemId( 'Q11' ); |
||
498 | |||
499 | $redirect = new EntityRedirect( $q10, $q11 ); |
||
500 | $revId = $this->repo->saveRedirect( $redirect, 'foo', $this->getUserMock(), EDIT_NEW ); |
||
501 | |||
502 | $logEntry = $this->repo->getLogEntry( $revId ); |
||
503 | |||
504 | $this->assertNotNull( $logEntry ); |
||
505 | $this->assertEquals( $revId, $logEntry['revision'] ); |
||
506 | $this->assertEquals( 'Q10', $logEntry['entity'] ); |
||
507 | $this->assertEquals( 'foo', $logEntry['summary'] ); |
||
508 | } |
||
509 | |||
510 | public function testGetLatestLogEntryFor() { |
||
511 | $this->setupGetEntities(); |
||
512 | |||
513 | $q10 = new ItemId( 'Q10' ); |
||
514 | $q11 = new ItemId( 'Q11' ); |
||
515 | $q12 = new ItemId( 'Q12' ); |
||
516 | |||
517 | // first entry |
||
518 | $redirect = new EntityRedirect( $q10, $q11 ); |
||
519 | $revId = $this->repo->saveRedirect( $redirect, 'foo', $this->getUserMock(), EDIT_NEW ); |
||
520 | |||
521 | $logEntry = $this->repo->getLatestLogEntryFor( $q10 ); |
||
522 | |||
523 | $this->assertNotNull( $logEntry ); |
||
524 | $this->assertEquals( $revId, $logEntry['revision'] ); |
||
525 | $this->assertEquals( 'Q10', $logEntry['entity'] ); |
||
526 | $this->assertEquals( 'foo', $logEntry['summary'] ); |
||
527 | |||
528 | // second entry |
||
529 | $redirect = new EntityRedirect( $q10, $q12 ); |
||
530 | $revId = $this->repo->saveRedirect( $redirect, 'bar', $this->getUserMock(), EDIT_NEW ); |
||
531 | |||
532 | $logEntry = $this->repo->getLatestLogEntryFor( $q10 ); |
||
533 | |||
534 | $this->assertNotNull( $logEntry ); |
||
535 | $this->assertEquals( $revId, $logEntry['revision'] ); |
||
536 | $this->assertEquals( 'Q10', $logEntry['entity'] ); |
||
537 | $this->assertEquals( 'bar', $logEntry['summary'] ); |
||
538 | } |
||
539 | |||
540 | public function testDeleteEntity() { |
||
541 | $item = new Item( new ItemId( 'Q23' ) ); |
||
542 | $this->repo->putEntity( $item ); |
||
543 | |||
544 | $this->repo->deleteEntity( $item->getId(), 'testing', $this->getUserMock() ); |
||
545 | $this->assertFalse( $this->repo->hasEntity( $item->getId() ) ); |
||
546 | } |
||
547 | |||
548 | public function testPutRedirect() { |
||
549 | $redirect = new EntityRedirect( new ItemId( 'Q11' ), new ItemId( 'Q1' ) ); |
||
550 | $this->repo->putRedirect( $redirect ); |
||
551 | |||
552 | try { |
||
553 | $this->repo->getEntityRevision( new ItemId( 'Q11' ) ); |
||
554 | $this->fail( 'getEntityRevision() should fail for redirects' ); |
||
555 | } catch ( RevisionedUnresolvedRedirectException $ex ) { |
||
556 | $this->assertEquals( 'Q1', $ex->getRedirectTargetId()->getSerialization() ); |
||
557 | $this->assertGreaterThan( 0, $ex->getRevisionId() ); |
||
558 | $this->assertNotEmpty( $ex->getRevisionTimestamp() ); |
||
559 | } |
||
560 | |||
561 | $this->repo->putRedirect( $redirect, 117, '20150505000000' ); |
||
562 | |||
563 | try { |
||
564 | $this->repo->getEntityRevision( new ItemId( 'Q11' ) ); |
||
565 | $this->fail( 'getEntityRevision() should fail for redirects' ); |
||
566 | } catch ( RevisionedUnresolvedRedirectException $ex ) { |
||
567 | $this->assertEquals( 'Q1', $ex->getRedirectTargetId()->getSerialization() ); |
||
568 | $this->assertEquals( 117, $ex->getRevisionId() ); |
||
569 | $this->assertSame( '20150505000000', $ex->getRevisionTimestamp() ); |
||
570 | } |
||
571 | } |
||
572 | |||
573 | public function testDeleteRedirect() { |
||
574 | $redirect = new EntityRedirect( new ItemId( 'Q11' ), new ItemId( 'Q1' ) ); |
||
575 | $this->repo->putRedirect( $redirect ); |
||
576 | |||
577 | $this->expectException( RevisionedUnresolvedRedirectException::class ); |
||
578 | $this->repo->deleteEntity( $redirect->getEntityId(), 'testing', $this->getUserMock() ); |
||
579 | } |
||
580 | |||
581 | public function testUpdateWatchlist() { |
||
582 | $user = User::newFromName( 'WikiPageEntityStoreTestUser2' ); |
||
583 | |||
584 | $item = new Item(); |
||
585 | $this->repo->saveEntity( $item, 'testing', $user, EDIT_NEW ); |
||
586 | $itemId = $item->getId(); |
||
587 | |||
588 | $this->repo->updateWatchlist( $user, $itemId, true ); |
||
589 | $this->assertTrue( $this->repo->isWatching( $user, $itemId ) ); |
||
0 ignored issues
–
show
|
|||
590 | |||
591 | $this->repo->updateWatchlist( $user, $itemId, false ); |
||
592 | $this->assertFalse( $this->repo->isWatching( $user, $itemId ) ); |
||
0 ignored issues
–
show
It seems like
$itemId defined by $item->getId() on line 586 can be null ; however, Wikibase\Lib\Tests\MockRepository::isWatching() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
Loading history...
|
|||
593 | } |
||
594 | |||
595 | public function testUserWasLastToEdit() { |
||
596 | $user1 = User::newFromName( 'WikiPageEntityStoreTestUserWasLastToEdit1' ); |
||
597 | $user2 = User::newFromName( 'WikiPageEntityStoreTestUserWasLastToEdit2' ); |
||
598 | |||
599 | // initial revision |
||
600 | $item = new Item( new ItemId( 'Q42' ) ); |
||
601 | $item->setLabel( 'en', 'one' ); |
||
602 | $rev1 = $this->repo->saveEntity( $item, 'testing 1', $user1, EDIT_NEW ); |
||
603 | $itemId = $item->getId(); |
||
604 | |||
605 | $this->assertTrue( |
||
606 | $this->repo->userWasLastToEdit( $user1, $itemId, $rev1->getRevisionId() ), |
||
607 | 'user was first and last to edit' |
||
608 | ); |
||
609 | $this->assertFalse( |
||
610 | $this->repo->userWasLastToEdit( $user2, $itemId, $rev1->getRevisionId() ), |
||
611 | 'user has not edited yet' |
||
612 | ); |
||
613 | |||
614 | // second edit by another user |
||
615 | $item = new Item( new ItemId( 'Q42' ) ); |
||
616 | $item->setLabel( 'en', 'two' ); |
||
617 | $rev2 = $this->repo->saveEntity( $item, 'testing 2', $user2, EDIT_UPDATE ); |
||
618 | |||
619 | $this->assertFalse( |
||
620 | $this->repo->userWasLastToEdit( $user1, $itemId, $rev1->getRevisionId() ), |
||
621 | 'original user was no longer last to edit' |
||
622 | ); |
||
623 | $this->assertTrue( |
||
624 | $this->repo->userWasLastToEdit( $user2, $itemId, $rev2->getRevisionId() ), |
||
625 | 'second user has just edited' |
||
626 | ); |
||
627 | |||
628 | // subsequent edit by the original user |
||
629 | $item = new Item( new ItemId( 'Q42' ) ); |
||
630 | $item->setLabel( 'en', 'three' ); |
||
631 | $rev3 = $this->repo->saveEntity( $item, 'testing 3', $user1, EDIT_UPDATE ); |
||
632 | |||
633 | $this->assertFalse( |
||
634 | $this->repo->userWasLastToEdit( $user1, $itemId, $rev1->getRevisionId() ), |
||
635 | 'another user had edited at some point' |
||
636 | ); |
||
637 | $this->assertTrue( |
||
638 | $this->repo->userWasLastToEdit( $user1, $itemId, $rev3->getRevisionId() ), |
||
639 | 'original user was last to edit' |
||
640 | ); |
||
641 | $this->assertFalse( |
||
642 | $this->repo->userWasLastToEdit( $user2, $itemId, $rev2->getRevisionId() ), |
||
643 | 'other user was no longer last to edit' |
||
644 | ); |
||
645 | } |
||
646 | |||
647 | public function testGetRedirectIds() { |
||
648 | $mock = new MockRepository(); |
||
649 | |||
650 | $q5 = new ItemId( 'Q5' ); |
||
651 | $q55 = new ItemId( 'Q55' ); |
||
652 | $q555 = new ItemId( 'Q555' ); |
||
653 | |||
654 | $mock->putRedirect( new EntityRedirect( $q55, $q5 ) ); |
||
655 | $mock->putRedirect( new EntityRedirect( $q555, $q5 ) ); |
||
656 | |||
657 | $this->assertSame( [], $mock->getRedirectIds( $q55 ), 'no redirects to redirect' ); |
||
658 | $this->assertEquals( [ $q55, $q555 ], $mock->getRedirectIds( $q5 ), 'two redirects' ); |
||
659 | } |
||
660 | |||
661 | public function testGetRedirectForEntityId() { |
||
662 | $mock = new MockRepository(); |
||
663 | |||
664 | $q5 = new ItemId( 'Q5' ); |
||
665 | $q55 = new ItemId( 'Q55' ); |
||
666 | $q77 = new ItemId( 'Q77' ); |
||
667 | |||
668 | $mock->putEntity( new Item( $q5 ) ); |
||
669 | $mock->putRedirect( new EntityRedirect( $q55, $q5 ) ); |
||
670 | |||
671 | $this->assertNull( $mock->getRedirectForEntityId( $q5 ), 'not a redirect' ); |
||
672 | $this->assertEquals( $q5, $mock->getRedirectForEntityId( $q55 ) ); |
||
673 | |||
674 | $this->expectException( EntityRedirectLookupException::class ); |
||
675 | $mock->getRedirectForEntityId( $q77 ); |
||
676 | } |
||
677 | |||
678 | public function testGetLatestRevisionId_Redirect_ReturnsRedirectResponseWithCorrectData() { |
||
679 | $mock = new MockRepository(); |
||
680 | $entityId = new ItemId( 'Q55' ); |
||
681 | $redirectsTo = new ItemId( 'Q5' ); |
||
682 | $revisionId = 5; |
||
683 | $mock->putRedirect( new EntityRedirect( $entityId, $redirectsTo ), $revisionId ); |
||
684 | |||
685 | $latestRevisionIdResult = $mock->getLatestRevisionId( $entityId ); |
||
686 | |||
687 | $failTest = function () { |
||
688 | $this->fail( 'Redirect was expected' ); |
||
689 | }; |
||
690 | list( $gotRevisionId, $gotTargetId ) = $latestRevisionIdResult |
||
691 | ->onNonexistentEntity( $failTest ) |
||
692 | ->onConcreteRevision( $failTest ) |
||
693 | ->onRedirect( |
||
694 | function ( $revisionId, $targetId ) { |
||
695 | return [ $revisionId, $targetId ]; |
||
696 | } |
||
697 | ) |
||
698 | ->map(); |
||
699 | |||
700 | $this->assertEquals( $revisionId, $gotRevisionId ); |
||
701 | $this->assertEquals( $redirectsTo, $gotTargetId ); |
||
702 | } |
||
703 | |||
704 | private function getUserMock() : User { |
||
705 | $u = $this->getMockBuilder( User::class ) |
||
706 | ->setMethods( [ 'getName' ] ) |
||
707 | ->getMock(); |
||
708 | $u->method( 'getName' )->willReturn( __CLASS__ ); |
||
709 | return $u; |
||
710 | } |
||
711 | } |
||
712 |
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: