These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare( strict_types = 1 ); |
||
4 | |||
5 | namespace Wikibase\Client\Tests\Integration\Hooks; |
||
6 | |||
7 | use HashSiteStore; |
||
8 | use Language; |
||
9 | use MediaWiki\HookContainer\HookContainer; |
||
10 | use MediaWikiIntegrationTestCase; |
||
11 | use MediaWikiSite; |
||
12 | use ParserOutput; |
||
13 | use Psr\Log\NullLogger; |
||
14 | use Site; |
||
15 | use SiteLookup; |
||
16 | use Title; |
||
17 | use Wikibase\Client\Hooks\LangLinkHandlerFactory; |
||
18 | use Wikibase\Client\Hooks\LanguageLinkBadgeDisplay; |
||
19 | use Wikibase\Client\Hooks\OtherProjectsSidebarGeneratorFactory; |
||
20 | use Wikibase\Client\Hooks\ParserOutputUpdateHookHandler; |
||
21 | use Wikibase\Client\Hooks\SidebarLinkBadgeDisplay; |
||
22 | use Wikibase\Client\NamespaceChecker; |
||
23 | use Wikibase\Client\ParserOutput\ClientParserOutputDataUpdater; |
||
24 | use Wikibase\Client\Usage\EntityUsage; |
||
25 | use Wikibase\Client\Usage\EntityUsageFactory; |
||
26 | use Wikibase\DataModel\Entity\BasicEntityIdParser; |
||
27 | use Wikibase\DataModel\Entity\Item; |
||
28 | use Wikibase\DataModel\Entity\ItemId; |
||
29 | use Wikibase\DataModel\Entity\PropertyId; |
||
30 | use Wikibase\DataModel\Services\Lookup\InMemoryEntityLookup; |
||
31 | use Wikibase\DataModel\Services\Lookup\LabelDescriptionLookup; |
||
32 | use Wikibase\DataModel\SiteLink; |
||
33 | use Wikibase\DataModel\SiteLinkList; |
||
34 | use Wikibase\DataModel\Snak\PropertyValueSnak; |
||
35 | use Wikibase\DataModel\Statement\Statement; |
||
36 | use Wikibase\DataModel\Statement\StatementList; |
||
37 | use Wikibase\DataModel\Term\Term; |
||
38 | use Wikibase\Lib\DataValue\UnmappedEntityIdValue; |
||
39 | use Wikibase\Lib\SettingsArray; |
||
40 | use Wikibase\Lib\Store\SiteLinkLookup; |
||
41 | use Wikibase\Lib\Tests\MockRepository; |
||
42 | |||
43 | /** |
||
44 | * @covers \Wikibase\Client\Hooks\ParserOutputUpdateHookHandler |
||
45 | * |
||
46 | * @group WikibaseClient |
||
47 | * @group Wikibase |
||
48 | * @group WikibaseHooks |
||
49 | * |
||
50 | * @license GPL-2.0-or-later |
||
51 | * @author Daniel Kinzler |
||
52 | */ |
||
53 | class ParserOutputUpdateHookHandlerTest extends MediaWikiIntegrationTestCase { |
||
54 | |||
55 | /** |
||
56 | * @param string $globalId |
||
57 | * @param string $group |
||
58 | * @param string $languageCode |
||
59 | * |
||
60 | * @return Site |
||
61 | */ |
||
62 | private function newSite( $globalId, $group, $languageCode ) { |
||
63 | $site = new MediaWikiSite(); |
||
64 | $site->setGlobalId( $globalId ); |
||
65 | $site->setGroup( $group ); |
||
66 | $site->setLanguageCode( $languageCode ); |
||
67 | $site->addNavigationId( $languageCode ); |
||
68 | $site->setPagePath( 'wiki/' ); |
||
69 | $site->setFilePath( 'w/' ); |
||
70 | $site->setLinkPath( 'http://' . $globalId . '.test.com/wiki/$1' ); |
||
71 | |||
72 | return $site; |
||
73 | } |
||
74 | |||
75 | /** |
||
76 | * @return SiteLookup |
||
77 | */ |
||
78 | private function getSiteLookup() { |
||
79 | $siteLookup = new HashSiteStore( [ |
||
80 | $this->newSite( 'wikidatawiki', 'wikidata', 'en' ), |
||
81 | $this->newSite( 'commonswiki', 'commons', 'en' ), |
||
82 | $this->newSite( 'enwiki', 'wikipedia', 'en' ), |
||
83 | $this->newSite( 'dewiki', 'wikipedia', 'de' ), |
||
84 | ] ); |
||
85 | |||
86 | return $siteLookup; |
||
87 | } |
||
88 | |||
89 | private function getBadgeItem() { |
||
90 | $item = new Item( new ItemId( 'Q17' ) ); |
||
91 | $item->setLabel( 'de', 'exzellent' ); |
||
92 | $item->setLabel( 'en', 'featured' ); |
||
93 | |||
94 | return $item; |
||
95 | } |
||
96 | |||
97 | private function getTestSiteLinkData() { |
||
98 | $badgeId = $this->getBadgeItem()->getId(); |
||
99 | |||
100 | return [ |
||
101 | 'Q1' => [ |
||
102 | new SiteLink( 'dewiki', 'Sauerstoff', [ $badgeId ] ), |
||
0 ignored issues
–
show
|
|||
103 | new SiteLink( 'enwiki', 'Oxygen' ), |
||
104 | new SiteLink( 'commonswiki', 'Oxygen' ), |
||
105 | ], |
||
106 | ]; |
||
107 | } |
||
108 | |||
109 | private function getTestSiteLinkDataInNotEnabledNamespace() { |
||
110 | return [ |
||
111 | 'Q7' => [ |
||
112 | new SiteLink( 'dewiki', 'User:Foo' ), |
||
113 | new SiteLink( 'enwiki', 'User:Foo' ), |
||
114 | new SiteLink( 'commonswiki', 'User:Foo' ), |
||
115 | ], |
||
116 | ]; |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * @param ItemId $id |
||
121 | * @param SiteLink[] $links |
||
122 | * |
||
123 | * @return Item |
||
124 | */ |
||
125 | private function newItem( ItemId $id, array $links ) { |
||
126 | $item = new Item( $id ); |
||
127 | $item->setSiteLinkList( new SiteLinkList( $links ) ); |
||
128 | return $item; |
||
129 | } |
||
130 | |||
131 | /** |
||
132 | * @param array[] $links |
||
133 | * |
||
134 | * @return MockRepository |
||
135 | */ |
||
136 | private function getMockRepo( array $links ) { |
||
137 | $repo = new MockRepository(); |
||
138 | |||
139 | foreach ( $links as $itemKey => $itemLinks ) { |
||
140 | $itemId = new ItemId( $itemKey ); |
||
141 | $item = $this->newItem( $itemId, $itemLinks ); |
||
142 | $repo->putEntity( $item ); |
||
143 | } |
||
144 | |||
145 | return $repo; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * @return SettingsArray |
||
150 | */ |
||
151 | private function newSettings() { |
||
152 | $defaults = [ |
||
153 | 'siteGlobalID' => 'enwiki', |
||
154 | 'languageLinkSiteGroup' => 'wikipedia', |
||
155 | 'namespaces' => [ NS_MAIN, NS_CATEGORY ], |
||
156 | 'otherProjectsLinks' => [ 'commonswiki' ], |
||
157 | ]; |
||
158 | |||
159 | return new SettingsArray( $defaults ); |
||
160 | } |
||
161 | |||
162 | private function newParserOutputUpdateHookHandler( array $siteLinkData ) { |
||
163 | $settings = $this->newSettings(); |
||
164 | |||
165 | $namespaceChecker = $this->newNamespaceChecker(); |
||
166 | |||
167 | $mockRepo = $this->getMockRepo( $siteLinkData ); |
||
168 | $mockRepo->putEntity( $this->getBadgeItem() ); |
||
169 | |||
170 | $parserOutputDataUpdater = $this->newParserOutputDataUpdater( $mockRepo, $siteLinkData, $settings ); |
||
171 | |||
172 | $langLinkHandlerFactory = $this->newLangLinkHandlerFactory( $namespaceChecker, $mockRepo, $settings ); |
||
173 | |||
174 | return new ParserOutputUpdateHookHandler( |
||
175 | $namespaceChecker, |
||
176 | $langLinkHandlerFactory, |
||
177 | $parserOutputDataUpdater, |
||
178 | new EntityUsageFactory( new BasicEntityIdParser() ) |
||
179 | ); |
||
180 | } |
||
181 | |||
182 | private function getBadgeDisplay() { |
||
183 | $labelDescriptionLookup = $this->createMock( LabelDescriptionLookup::class ); |
||
184 | |||
185 | $labelDescriptionLookup->expects( $this->any() ) |
||
186 | ->method( 'getLabel' ) |
||
187 | ->will( $this->returnValue( new Term( 'en', 'featured' ) ) ); |
||
188 | |||
189 | return new LanguageLinkBadgeDisplay( |
||
190 | new SidebarLinkBadgeDisplay( |
||
191 | $labelDescriptionLookup, |
||
192 | [ 'Q17' => 'featured' ], |
||
193 | Language::factory( 'en' ) |
||
194 | ) |
||
195 | ); |
||
196 | } |
||
197 | |||
198 | private function getEntityLookup( array $siteLinkData ) { |
||
199 | $lookup = new InMemoryEntityLookup(); |
||
200 | |||
201 | foreach ( $siteLinkData as $itemId => $siteLinks ) { |
||
202 | $item = new Item( new ItemId( $itemId ) ); |
||
203 | $item->setSiteLinkList( new SiteLinkList( $siteLinks ) ); |
||
204 | $lookup->addEntity( $item ); |
||
205 | } |
||
206 | |||
207 | return $lookup; |
||
208 | } |
||
209 | |||
210 | private function getOtherProjectsSidebarGeneratorFactory( |
||
211 | SettingsArray $settings, |
||
212 | SiteLinkLookup $siteLinkLookup, |
||
213 | array $siteLinkData |
||
214 | ) { |
||
215 | $sidebarLinkBadgeDisplay = new SidebarLinkBadgeDisplay( |
||
216 | $this->createMock( LabelDescriptionLookup::class ), |
||
217 | [], |
||
218 | Language::factory( 'en' ) |
||
219 | ); |
||
220 | |||
221 | return new OtherProjectsSidebarGeneratorFactory( |
||
222 | $settings, |
||
223 | $siteLinkLookup, |
||
224 | $this->getSiteLookup(), |
||
225 | $this->getEntityLookup( $siteLinkData ), |
||
226 | $sidebarLinkBadgeDisplay, |
||
227 | $this->createMock( HookContainer::class ), |
||
228 | new NullLogger() |
||
229 | ); |
||
230 | } |
||
231 | |||
232 | private function newParserOutput( array $pageProps, array $extensionData ) { |
||
233 | $parserOutput = new ParserOutput(); |
||
234 | |||
235 | foreach ( $pageProps as $name => $value ) { |
||
236 | $parserOutput->setProperty( $name, $value ); |
||
237 | } |
||
238 | |||
239 | foreach ( $extensionData as $key => $value ) { |
||
240 | $parserOutput->setExtensionData( $key, $value ); |
||
241 | } |
||
242 | |||
243 | return $parserOutput; |
||
244 | } |
||
245 | |||
246 | public function parserAfterParseProvider() { |
||
247 | $commonsOxygen = [ |
||
248 | 'msg' => 'wikibase-otherprojects-commons', |
||
249 | 'class' => 'wb-otherproject-link wb-otherproject-commons', |
||
250 | 'href' => 'http://commonswiki.test.com/wiki/Oxygen', |
||
251 | 'hreflang' => 'en', |
||
252 | ]; |
||
253 | |||
254 | $badgesQ1 = [ |
||
255 | 'class' => 'badge-Q17 featured', |
||
256 | 'label' => 'featured', |
||
257 | ]; |
||
258 | |||
259 | return [ |
||
260 | 'repo-links' => [ |
||
261 | Title::makeTitle( NS_MAIN, 'Oxygen' ), |
||
262 | 'Q1', |
||
263 | [], |
||
264 | [ 'de:Sauerstoff' ], |
||
265 | [ $commonsOxygen ], |
||
266 | [ 'de' => $badgesQ1 ], |
||
267 | ], |
||
268 | |||
269 | 'noexternallanglinks=*' => [ |
||
270 | Title::makeTitle( NS_MAIN, 'Oxygen' ), |
||
271 | 'Q1', |
||
272 | [ 'noexternallanglinks' => serialize( [ '*' ] ) ], |
||
273 | [], |
||
274 | [ $commonsOxygen ], |
||
275 | null, |
||
276 | ], |
||
277 | |||
278 | 'noexternallanglinks=de' => [ |
||
279 | Title::makeTitle( NS_MAIN, 'Oxygen' ), |
||
280 | 'Q1', |
||
281 | [ 'noexternallanglinks' => serialize( [ 'de' ] ) ], |
||
282 | [], |
||
283 | [ $commonsOxygen ], |
||
284 | [], |
||
285 | ], |
||
286 | |||
287 | 'noexternallanglinks=ja' => [ |
||
288 | Title::makeTitle( NS_MAIN, 'Oxygen' ), |
||
289 | 'Q1', |
||
290 | [ 'noexternallanglinks' => serialize( [ 'ja' ] ) ], |
||
291 | [ 'de:Sauerstoff' ], |
||
292 | [ $commonsOxygen ], |
||
293 | [ 'de' => $badgesQ1 ], |
||
294 | ], |
||
295 | ]; |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * @dataProvider parserAfterParseProvider |
||
300 | */ |
||
301 | public function testDoContentAlterParserOutput( |
||
302 | Title $title, |
||
303 | $expectedItem, |
||
304 | array $pagePropsBefore, |
||
305 | array $expectedLanguageLinks, |
||
306 | array $expectedSisterLinks, |
||
307 | array $expectedBadges = null |
||
308 | ) { |
||
309 | $parserOutput = $this->newParserOutput( $pagePropsBefore, [] ); |
||
310 | $handler = $this->newParserOutputUpdateHookHandler( $this->getTestSiteLinkData() ); |
||
311 | |||
312 | $handler->doContentAlterParserOutput( $title, $parserOutput ); |
||
313 | |||
314 | $expectedUsage = new EntityUsage( |
||
315 | new ItemId( $expectedItem ), |
||
316 | EntityUsage::SITELINK_USAGE |
||
317 | ); |
||
318 | |||
319 | $this->assertEquals( $expectedItem, $parserOutput->getProperty( 'wikibase_item' ) ); |
||
320 | $this->assertLanguageLinks( $expectedLanguageLinks, $parserOutput ); |
||
321 | $this->assertSisterLinks( $expectedSisterLinks, $parserOutput->getExtensionData( 'wikibase-otherprojects-sidebar' ) ); |
||
322 | |||
323 | $actualUsage = $parserOutput->getExtensionData( 'wikibase-entity-usage' ); |
||
324 | |||
325 | $this->assertEquals( [ $expectedUsage->getIdentityString() ], array_keys( $actualUsage ) ); |
||
326 | |||
327 | $actualBadges = $parserOutput->getExtensionData( 'wikibase_badges' ); |
||
328 | |||
329 | // $actualBadges contains info arrays, these are checked by LanguageLinkBadgeDisplayTest and LangLinkHandlerTest |
||
330 | $this->assertSame( $expectedBadges, $actualBadges ); |
||
331 | } |
||
332 | |||
333 | public function testDoContentAlterParserOutput_sitelinkOfNoItem() { |
||
334 | $title = Title::makeTitle( NS_MAIN, 'Plutonium' ); |
||
335 | |||
336 | $parserOutput = $this->newParserOutput( [], [] ); |
||
337 | $handler = $this->newParserOutputUpdateHookHandler( $this->getTestSiteLinkData() ); |
||
338 | |||
339 | $handler->doContentAlterParserOutput( $title, $parserOutput ); |
||
340 | |||
341 | $this->assertFalse( $parserOutput->getProperty( 'wikibase_item' ) ); |
||
342 | |||
343 | $this->assertSame( [], $parserOutput->getLanguageLinks() ); |
||
344 | $this->assertSame( [], $parserOutput->getExtensionData( 'wikibase-otherprojects-sidebar' ) ); |
||
345 | |||
346 | $this->assertNull( $parserOutput->getExtensionData( 'wikibase-entity-usage' ) ); |
||
347 | $this->assertSame( [], $parserOutput->getExtensionData( 'wikibase_badges' ) ); |
||
348 | } |
||
349 | |||
350 | public function testDoContentAlterParserOutput_sitelinkInNotWikibaseEnabledNamespace() { |
||
351 | $title = Title::makeTitle( NS_USER, 'Foo' ); |
||
352 | |||
353 | $parserOutput = $this->newParserOutput( [], [] ); |
||
354 | $handler = $this->newParserOutputUpdateHookHandler( $this->getTestSiteLinkDataInNotEnabledNamespace() ); |
||
355 | |||
356 | $handler->doContentAlterParserOutput( $title, $parserOutput ); |
||
357 | |||
358 | $this->assertFalse( $parserOutput->getProperty( 'wikibase_item' ) ); |
||
359 | |||
360 | $this->assertSame( [], $parserOutput->getLanguageLinks() ); |
||
361 | $this->assertNull( $parserOutput->getExtensionData( 'wikibase-otherprojects-sidebar' ) ); |
||
362 | |||
363 | $this->assertNull( $parserOutput->getExtensionData( 'wikibase-entity-usage' ) ); |
||
364 | $this->assertNull( $parserOutput->getExtensionData( 'wikibase_badges' ) ); |
||
365 | } |
||
366 | |||
367 | public function testGivenSitelinkHasStatementWithUnknownEntityType_linkDataIsAddedNormally() { |
||
368 | $itemId = 'Q555'; |
||
369 | $siteLink = new SiteLink( 'enwiki', 'Foobarium' ); |
||
370 | |||
371 | $namespaceChecker = $this->newNamespaceChecker(); |
||
372 | |||
373 | $mockRepo = new MockRepository(); |
||
374 | $item = new Item( |
||
375 | new ItemId( $itemId ), |
||
376 | null, |
||
377 | new SiteLinkList( [ $siteLink ] ), |
||
378 | new StatementList( [ |
||
379 | new Statement( new PropertyValueSnak( |
||
380 | new PropertyId( 'P100' ), |
||
381 | new UnmappedEntityIdValue( 'X808' ) |
||
382 | ) ) |
||
383 | ] ) |
||
384 | ); |
||
385 | $mockRepo->putEntity( $item ); |
||
386 | |||
387 | $langLinkHandlerFactory = $this->newLangLinkHandlerFactory( $namespaceChecker, $mockRepo ); |
||
388 | |||
389 | $handler = new ParserOutputUpdateHookHandler( |
||
390 | $namespaceChecker, |
||
391 | $langLinkHandlerFactory, |
||
392 | $this->newParserOutputDataUpdater( $mockRepo, [ $itemId => [ $siteLink ] ] ), |
||
393 | $this->createMock( EntityUsageFactory::class ) |
||
394 | ); |
||
395 | |||
396 | $title = Title::makeTitle( NS_MAIN, 'Foobarium' ); |
||
397 | |||
398 | $parserOutput = $this->newParserOutput( [], [] ); |
||
399 | |||
400 | $handler->doContentAlterParserOutput( $title, $parserOutput ); |
||
401 | |||
402 | $this->assertEquals( $itemId, $parserOutput->getProperty( 'wikibase_item' ) ); |
||
403 | } |
||
404 | |||
405 | private function assertLanguageLinks( $links, ParserOutput $parserOutput ) { |
||
406 | $this->assertIsArray( $links ); |
||
407 | |||
408 | $actualLinks = $parserOutput->getLanguageLinks(); |
||
409 | |||
410 | foreach ( $links as $link ) { |
||
411 | $this->assertContains( $link, $actualLinks, 'LanguageLink: ' ); |
||
412 | } |
||
413 | |||
414 | $this->assertSameSize( $links, $actualLinks, 'Unmatched languageLinks!' ); |
||
415 | } |
||
416 | |||
417 | private function assertSisterLinks( $expectedLinks, $actualLinks ) { |
||
418 | if ( !is_array( $expectedLinks ) ) { |
||
419 | $this->assertEquals( $expectedLinks, $actualLinks ); |
||
420 | return; |
||
421 | } |
||
422 | |||
423 | $this->assertSameSize( $expectedLinks, $actualLinks, 'SisterLinks' ); |
||
424 | |||
425 | $actual = reset( $actualLinks ); |
||
426 | foreach ( $expectedLinks as $expected ) { |
||
427 | $this->assertEquals( $expected, $actual, 'SisterLink: ' ); |
||
428 | $actual = next( $actualLinks ); |
||
429 | } |
||
430 | } |
||
431 | |||
432 | private function newNamespaceChecker() { |
||
433 | $settings = $this->newSettings(); |
||
434 | |||
435 | $namespaces = $settings->getSetting( 'namespaces' ); |
||
436 | $namespaceChecker = new NamespaceChecker( [], $namespaces ); |
||
437 | |||
438 | return $namespaceChecker; |
||
439 | } |
||
440 | |||
441 | private function newParserOutputDataUpdater( MockRepository $mockRepo, array $siteLinkData ) { |
||
442 | $settings = $this->newSettings(); |
||
443 | |||
444 | return new ClientParserOutputDataUpdater( |
||
445 | $this->getOtherProjectsSidebarGeneratorFactory( $settings, $mockRepo, $siteLinkData ), |
||
446 | $mockRepo, |
||
447 | $mockRepo, |
||
448 | new EntityUsageFactory( new BasicEntityIdParser() ), |
||
449 | $settings->getSetting( 'siteGlobalID' ) |
||
450 | ); |
||
451 | } |
||
452 | |||
453 | private function newLangLinkHandlerFactory( $namespaceChecker, $mockRepo ) { |
||
454 | $settings = $this->newSettings(); |
||
455 | |||
456 | return new LangLinkHandlerFactory( |
||
457 | $this->getBadgeDisplay(), |
||
458 | $namespaceChecker, |
||
459 | $mockRepo, |
||
460 | $mockRepo, |
||
461 | $this->getSiteLookup(), |
||
462 | $this->createMock( HookContainer::class ), |
||
463 | new NullLogger(), |
||
464 | $settings->getSetting( 'siteGlobalID' ), |
||
465 | $settings->getSetting( 'languageLinkSiteGroup' ) |
||
466 | ); |
||
467 | } |
||
468 | |||
469 | } |
||
470 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: