MediaWiki REL1_34
LinksUpdateHookHandlerTest.php
Go to the documentation of this file.
1<?php
2
4
6use PageImages;
9use MediaWikiTestCase;
10use RepoGroup;
11use Title;
12use Wikimedia\TestingAccessWrapper;
13
22class LinksUpdateHookHandlerTest extends MediaWikiTestCase {
23
24 public function tearDown() {
25 // remove mock added in testGetMetadata()
27 parent::tearDown();
28 }
29
30 public function setUp() {
31 parent::setUp();
32
33 // Force LinksUpdateHookHandler::getPageImageCanditates to look at all
34 // sections.
35 $this->setMwGlobals( 'wgPageImagesLeadSectionOnly', false );
36 }
37
44 private function getLinksUpdate( array $images, $leadImages = false ) {
45 $parserOutput = new ParserOutput();
46 $parserOutput->setExtensionData( 'pageImages', $images );
47 $parserOutputLead = new ParserOutput();
48 $parserOutputLead->setExtensionData( 'pageImages', $leadImages ?: $images );
49
50 $rev = $this->getMockBuilder( 'Revision' )
51 ->disableOriginalConstructor()
52 ->getMock();
53
54 $content = $this->getMockBuilder( 'AbstractContent' )
55 ->disableOriginalConstructor()
56 ->getMock();
57
58 $sectionContent = $this->getMockBuilder( 'AbstractContent' )
59 ->disableOriginalConstructor()
60 ->getMock();
61
62 $linksUpdate = $this->getMockBuilder( 'LinksUpdate' )
63 ->disableOriginalConstructor()
64 ->getMock();
65
66 $linksUpdate->expects( $this->any() )
67 ->method( 'getTitle' )
68 ->will( $this->returnValue( new Title( 'LinksUpdateHandlerTest' ) ) );
69
70 $linksUpdate->expects( $this->any() )
71 ->method( 'getParserOutput' )
72 ->will( $this->returnValue( $parserOutput ) );
73
74 $linksUpdate->expects( $this->any() )
75 ->method( 'getRevision' )
76 ->will( $this->returnValue( $rev ) );
77
78 $rev->expects( $this->any() )
79 ->method( 'getContent' )
80 ->will( $this->returnValue( $content ) );
81
82 $content->expects( $this->any() )
83 ->method( 'getSection' )
84 ->will( $this->returnValue( $sectionContent ) );
85
86 $sectionContent->expects( $this->any() )
87 ->method( 'getParserOutput' )
88 ->will( $this->returnValue( $parserOutputLead ) );
89
90 return $linksUpdate;
91 }
92
97 private function getRepoGroup() {
98 $file = $this->getMockBuilder( 'File' )
99 ->disableOriginalConstructor()
100 ->getMock();
101 // ugly hack to avoid all the unmockable crap in FormatMetadata
102 $file->expects( $this->any() )
103 ->method( 'isDeleted' )
104 ->will( $this->returnValue( true ) );
105
106 $repoGroup = $this->getMockBuilder( 'RepoGroup' )
107 ->disableOriginalConstructor()
108 ->getMock();
109 $repoGroup->expects( $this->any() )
110 ->method( 'findFile' )
111 ->will( $this->returnValue( $file ) );
112
113 return $repoGroup;
114 }
115
120 public function testDoLinksUpdate(
121 array $images,
122 $expectedFreeFileName,
123 $expectedNonFreeFileName
124 ) {
125 $linksUpdate = $this->getLinksUpdate( $images );
126 $mock = TestingAccessWrapper::newFromObject(
127 $this->getMockBuilder( LinksUpdateHookHandler::class )
128 ->setMethods( [ 'getScore', 'isImageFree' ] )
129 ->getMock()
130 );
131
132 $scoreMap = [];
133 $isFreeMap = [];
134 $counter = 0;
135 foreach ( $images as $image ) {
136 array_push( $scoreMap, [ $image, $counter++, $image['score'] ] );
137 array_push( $isFreeMap, [ $image['filename'], $image['isFree'] ] );
138 }
139
140 $mock->expects( $this->any() )
141 ->method( 'getScore' )
142 ->will( $this->returnValueMap( $scoreMap ) );
143
144 $mock->expects( $this->any() )
145 ->method( 'isImageFree' )
146 ->will( $this->returnValueMap( $isFreeMap ) );
147
148 $mock->doLinksUpdate( $linksUpdate );
149
150 $this->assertTrue( property_exists( $linksUpdate, 'mProperties' ), 'precondition' );
151 if ( is_null( $expectedFreeFileName ) ) {
152 $this->assertArrayNotHasKey( PageImages::PROP_NAME_FREE, $linksUpdate->mProperties );
153 } else {
154 $this->assertSame( $expectedFreeFileName,
155 $linksUpdate->mProperties[PageImages::PROP_NAME_FREE] );
156 }
157 if ( is_null( $expectedNonFreeFileName ) ) {
158 $this->assertArrayNotHasKey( PageImages::PROP_NAME, $linksUpdate->mProperties );
159 } else {
160 $this->assertSame( $expectedNonFreeFileName, $linksUpdate->mProperties[PageImages::PROP_NAME] );
161 }
162 }
163
164 public function provideDoLinksUpdate() {
165 return [
166 // both images are non-free
167 [
168 [
169 [ 'filename' => 'A.jpg', 'score' => 100, 'isFree' => false ],
170 [ 'filename' => 'B.jpg', 'score' => 90, 'isFree' => false ],
171 ],
172 null,
173 'A.jpg'
174 ],
175 // both images are free
176 [
177 [
178 [ 'filename' => 'A.jpg', 'score' => 100, 'isFree' => true ],
179 [ 'filename' => 'B.jpg', 'score' => 90, 'isFree' => true ],
180 ],
181 'A.jpg',
182 null
183 ],
184 // one free (with a higher score), one non-free image
185 [
186 [
187 [ 'filename' => 'A.jpg', 'score' => 100, 'isFree' => true ],
188 [ 'filename' => 'B.jpg', 'score' => 90, 'isFree' => false ],
189 ],
190 'A.jpg',
191 null
192 ],
193 // one non-free (with a higher score), one free image
194 [
195 [
196 [ 'filename' => 'A.jpg', 'score' => 100, 'isFree' => false ],
197 [ 'filename' => 'B.jpg', 'score' => 90, 'isFree' => true ],
198 ],
199 'B.jpg',
200 'A.jpg'
201 ]
202 ];
203 }
204
208 public function testGetPageImageCandidates() {
209 $candidates = [
210 [ 'filename' => 'A.jpg', 'score' => 100, 'isFree' => false ],
211 [ 'filename' => 'B.jpg', 'score' => 90, 'isFree' => false ],
212 ];
213 $linksUpdate = $this->getLinksUpdate( $candidates, array_slice( $candidates, 0, 1 ) );
214
215 // should get without lead.
216 $handler = new LinksUpdateHookHandler();
217 $this->setMwGlobals( 'wgPageImagesLeadSectionOnly', false );
218 $images = $handler->getPageImageCandidates( $linksUpdate );
219 $this->assertCount( 2, $images, 'All images are returned.' );
220
221 $this->setMwGlobals( 'wgPageImagesLeadSectionOnly', true );
222 $images = $handler->getPageImageCandidates( $linksUpdate );
223 $this->assertCount( 1, $images, 'Only lead images are returned.' );
224 }
225
229 public function testGetScore( $image, $scoreFromTable, $position, $expected ) {
230 $mock = TestingAccessWrapper::newFromObject(
231 $this->getMockBuilder( LinksUpdateHookHandler::class )
232 ->setMethods( [ 'scoreFromTable', 'getMetadata', 'getRatio', 'getBlacklist' ] )
233 ->getMock()
234 );
235 $mock->expects( $this->any() )
236 ->method( 'scoreFromTable' )
237 ->will( $this->returnValue( $scoreFromTable ) );
238 $mock->expects( $this->any() )
239 ->method( 'getRatio' )
240 ->will( $this->returnValue( 0 ) );
241 $mock->expects( $this->any() )
242 ->method( 'getBlacklist' )
243 ->will( $this->returnValue( [ 'blacklisted.jpg' => 1 ] ) );
244
245 $score = $mock->getScore( $image, $position );
246 $this->assertEquals( $expected, $score );
247 }
248
249 public function provideGetScore() {
250 return [
251 [
252 [ 'filename' => 'A.jpg', 'handler' => [ 'width' => 100 ] ],
253 100,
254 0,
255 // width score + ratio score + position score
256 100 + 100 + 8
257 ],
258 [
259 [ 'filename' => 'A.jpg', 'fullwidth' => 100 ],
260 50,
261 1,
262 // width score + ratio score + position score
263 106
264 ],
265 [
266 [ 'filename' => 'A.jpg', 'fullwidth' => 100 ],
267 50,
268 2,
269 // width score + ratio score + position score
270 104
271 ],
272 [
273 [ 'filename' => 'A.jpg', 'fullwidth' => 100 ],
274 50,
275 3,
276 // width score + ratio score + position score
277 103
278 ],
279 [
280 [ 'filename' => 'blacklisted.jpg', 'fullwidth' => 100 ],
281 50,
282 3,
283 // blacklist score
284 - 1000
285 ],
286 ];
287 }
288
293 public function testScoreFromTable( array $scores, $value, $expected ) {
294 $handlerWrapper = TestingAccessWrapper::newFromObject( new LinksUpdateHookHandler );
295
296 $score = $handlerWrapper->scoreFromTable( $value, $scores );
297 $this->assertEquals( $expected, $score );
298 }
299
300 public function provideScoreFromTable() {
301 global $wgPageImagesScores;
302
303 return [
304 'no match' => [ [], 100, 0 ],
305 'float' => [ [ 0.5 ], 0, 0.5 ],
306
307 'always min when below range' => [ [ 200 => 2, 800 => 1 ], 0, 2 ],
308 'always max when above range' => [ [ 200 => 2, 800 => 1 ], 1000, 1 ],
309
310 'always min when below range (reversed)' => [ [ 800 => 1, 200 => 2 ], 0, 2 ],
311 'always max when above range (reversed)' => [ [ 800 => 1, 200 => 2 ], 1000, 1 ],
312
313 'min match' => [ [ 200 => 2, 400 => 3, 800 => 1 ], 200, 2 ],
314 'above min' => [ [ 200 => 2, 400 => 3, 800 => 1 ], 201, 3 ],
315 'second last match' => [ [ 200 => 2, 400 => 3, 800 => 1 ], 400, 3 ],
316 'above second last' => [ [ 200 => 2, 400 => 3, 800 => 1 ], 401, 1 ],
317
318 // These test cases use the default values from extension.json
319 [ $wgPageImagesScores['width'], 100, -100 ],
320 [ $wgPageImagesScores['width'], 119, -100 ],
321 [ $wgPageImagesScores['width'], 300, 10 ],
322 [ $wgPageImagesScores['width'], 400, 10 ],
323 [ $wgPageImagesScores['width'], 500, 5 ],
324 [ $wgPageImagesScores['width'], 600, 5 ],
325 [ $wgPageImagesScores['width'], 601, 0 ],
326 [ $wgPageImagesScores['width'], 999, 0 ],
327 [ $wgPageImagesScores['galleryImageWidth'], 99, -100 ],
328 [ $wgPageImagesScores['galleryImageWidth'], 100, 0 ],
329 [ $wgPageImagesScores['galleryImageWidth'], 500, 0 ],
330 [ $wgPageImagesScores['ratio'], 1, -100 ],
331 [ $wgPageImagesScores['ratio'], 3, -100 ],
332 [ $wgPageImagesScores['ratio'], 4, 0 ],
333 [ $wgPageImagesScores['ratio'], 5, 0 ],
334 [ $wgPageImagesScores['ratio'], 10, 5 ],
335 [ $wgPageImagesScores['ratio'], 20, 5 ],
336 [ $wgPageImagesScores['ratio'], 25, 0 ],
337 [ $wgPageImagesScores['ratio'], 30, 0 ],
338 [ $wgPageImagesScores['ratio'], 31, -100 ],
339 [ $wgPageImagesScores['ratio'], 40, -100 ],
340
341 'T212013' => [ $wgPageImagesScores['width'], 0, -100 ],
342 ];
343 }
344
349 public function testIsFreeImage( $fileName, $metadata, $expected ) {
351 $mock = TestingAccessWrapper::newFromObject(
352 $this->getMockBuilder( LinksUpdateHookHandler::class )
353 ->setMethods( [ 'fetchFileMetadata' ] )
354 ->getMock()
355 );
356 $mock->expects( $this->any() )
357 ->method( 'fetchFileMetadata' )
358 ->will( $this->returnValue( $metadata ) );
359 $this->assertEquals( $expected, $mock->isImageFree( $fileName ) );
360 }
361
362 public function provideIsFreeImage() {
363 return [
364 [ 'A.jpg', [], true ],
365 [ 'A.jpg', [ 'NonFree' => [ 'value' => '0' ] ], true ],
366 [ 'A.jpg', [ 'NonFree' => [ 'value' => 0 ] ], true ],
367 [ 'A.jpg', [ 'NonFree' => [ 'value' => false ] ], true ],
368 [ 'A.jpg', [ 'NonFree' => [ 'value' => 'something' ] ], false ],
369 [ 'A.jpg', [ 'something' => [ 'value' => 'something' ] ], true ],
370 ];
371 }
372}
Class the manages updates of *_link tables as well as similar extension-managed tables.
Handler for the "LinksUpdate" hook.
@covers \PageImages\Hooks\LinksUpdateHookHandler
testGetPageImageCandidates()
@covers \PageImages\Hooks\LinksUpdateHookHandler::getPageImageCandidates
testScoreFromTable(array $scores, $value, $expected)
@dataProvider provideScoreFromTable @covers \PageImages\Hooks\LinksUpdateHookHandler::scoreFromTable
testDoLinksUpdate(array $images, $expectedFreeFileName, $expectedNonFreeFileName)
@dataProvider provideDoLinksUpdate @covers \PageImages\Hooks\LinksUpdateHookHandler::doLinksUpdate
testGetScore( $image, $scoreFromTable, $position, $expected)
@dataProvider provideGetScore
getRepoGroup()
Required to make wfFindFile in LinksUpdateHookHandler::getScore return something.
testIsFreeImage( $fileName, $metadata, $expected)
@dataProvider provideIsFreeImage @covers \PageImages\Hooks\LinksUpdateHookHandler::isImageFree
Prioritized list of file repositories.
Definition RepoGroup.php:31
static setSingleton( $instance)
Definition RepoGroup.php:77
static destroySingleton()
Definition RepoGroup.php:68
Represents a title within MediaWiki.
Definition Title.php:42
$content
Definition router.php:78
return true
Definition router.php:94
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition router.php:42