Merge "Revert "Log the reason why revision->getContent() returns null""
[lhc/web/wiklou.git] / tests / phpunit / includes / filerepo / file / FileTest.php
1 <?php
2
3 class FileTest extends MediaWikiMediaTestCase {
4
5 /**
6 * @param string $filename
7 * @param bool $expected
8 * @dataProvider providerCanAnimate
9 * @covers File::canAnimateThumbIfAppropriate
10 */
11 function testCanAnimateThumbIfAppropriate( $filename, $expected ) {
12 $this->setMwGlobals( 'wgMaxAnimatedGifArea', 9000 );
13 $file = $this->dataFile( $filename );
14 $this->assertEquals( $file->canAnimateThumbIfAppropriate(), $expected );
15 }
16
17 function providerCanAnimate() {
18 return [
19 [ 'nonanimated.gif', true ],
20 [ 'jpeg-comment-utf.jpg', true ],
21 [ 'test.tiff', true ],
22 [ 'Animated_PNG_example_bouncing_beach_ball.png', false ],
23 [ 'greyscale-png.png', true ],
24 [ 'Toll_Texas_1.svg', true ],
25 [ 'LoremIpsum.djvu', true ],
26 [ '80x60-2layers.xcf', true ],
27 [ 'Soccer_ball_animated.svg', false ],
28 [ 'Bishzilla_blink.gif', false ],
29 [ 'animated.gif', true ],
30 ];
31 }
32
33 /**
34 * @dataProvider getThumbnailBucketProvider
35 * @covers File::getThumbnailBucket
36 */
37 public function testGetThumbnailBucket( $data ) {
38 $this->setMwGlobals( 'wgThumbnailBuckets', $data['buckets'] );
39 $this->setMwGlobals( 'wgThumbnailMinimumBucketDistance', $data['minimumBucketDistance'] );
40
41 $fileMock = $this->getMockBuilder( File::class )
42 ->setConstructorArgs( [ 'fileMock', false ] )
43 ->setMethods( [ 'getWidth' ] )
44 ->getMockForAbstractClass();
45
46 $fileMock->expects( $this->any() )
47 ->method( 'getWidth' )
48 ->will( $this->returnValue( $data['width'] ) );
49
50 $this->assertEquals(
51 $data['expectedBucket'],
52 $fileMock->getThumbnailBucket( $data['requestedWidth'] ),
53 $data['message'] );
54 }
55
56 public function getThumbnailBucketProvider() {
57 $defaultBuckets = [ 256, 512, 1024, 2048, 4096 ];
58
59 return [
60 [ [
61 'buckets' => $defaultBuckets,
62 'minimumBucketDistance' => 0,
63 'width' => 3000,
64 'requestedWidth' => 120,
65 'expectedBucket' => 256,
66 'message' => 'Picking bucket bigger than requested size'
67 ] ],
68 [ [
69 'buckets' => $defaultBuckets,
70 'minimumBucketDistance' => 0,
71 'width' => 3000,
72 'requestedWidth' => 300,
73 'expectedBucket' => 512,
74 'message' => 'Picking bucket bigger than requested size'
75 ] ],
76 [ [
77 'buckets' => $defaultBuckets,
78 'minimumBucketDistance' => 0,
79 'width' => 3000,
80 'requestedWidth' => 1024,
81 'expectedBucket' => 2048,
82 'message' => 'Picking bucket bigger than requested size'
83 ] ],
84 [ [
85 'buckets' => $defaultBuckets,
86 'minimumBucketDistance' => 0,
87 'width' => 3000,
88 'requestedWidth' => 2048,
89 'expectedBucket' => false,
90 'message' => 'Picking no bucket because none is bigger than the requested size'
91 ] ],
92 [ [
93 'buckets' => $defaultBuckets,
94 'minimumBucketDistance' => 0,
95 'width' => 3000,
96 'requestedWidth' => 3500,
97 'expectedBucket' => false,
98 'message' => 'Picking no bucket because requested size is bigger than original'
99 ] ],
100 [ [
101 'buckets' => [ 1024 ],
102 'minimumBucketDistance' => 0,
103 'width' => 3000,
104 'requestedWidth' => 1024,
105 'expectedBucket' => false,
106 'message' => 'Picking no bucket because requested size equals biggest bucket'
107 ] ],
108 [ [
109 'buckets' => null,
110 'minimumBucketDistance' => 0,
111 'width' => 3000,
112 'requestedWidth' => 1024,
113 'expectedBucket' => false,
114 'message' => 'Picking no bucket because no buckets have been specified'
115 ] ],
116 [ [
117 'buckets' => [ 256, 512 ],
118 'minimumBucketDistance' => 10,
119 'width' => 3000,
120 'requestedWidth' => 245,
121 'expectedBucket' => 256,
122 'message' => 'Requested width is distant enough from next bucket for it to be picked'
123 ] ],
124 [ [
125 'buckets' => [ 256, 512 ],
126 'minimumBucketDistance' => 10,
127 'width' => 3000,
128 'requestedWidth' => 246,
129 'expectedBucket' => 512,
130 'message' => 'Requested width is too close to next bucket, picking next one'
131 ] ],
132 ];
133 }
134
135 /**
136 * @dataProvider getThumbnailSourceProvider
137 * @covers File::getThumbnailSource
138 */
139 public function testGetThumbnailSource( $data ) {
140 $backendMock = $this->getMockBuilder( FSFileBackend::class )
141 ->setConstructorArgs( [ [ 'name' => 'backendMock', 'wikiId' => wfWikiID() ] ] )
142 ->getMock();
143
144 $repoMock = $this->getMockBuilder( FileRepo::class )
145 ->setConstructorArgs( [ [ 'name' => 'repoMock', 'backend' => $backendMock ] ] )
146 ->setMethods( [ 'fileExists', 'getLocalReference' ] )
147 ->getMock();
148
149 $fsFile = new FSFile( 'fsFilePath' );
150
151 $repoMock->expects( $this->any() )
152 ->method( 'fileExists' )
153 ->will( $this->returnValue( true ) );
154
155 $repoMock->expects( $this->any() )
156 ->method( 'getLocalReference' )
157 ->will( $this->returnValue( $fsFile ) );
158
159 $handlerMock = $this->getMockBuilder( BitmapHandler::class )
160 ->setMethods( [ 'supportsBucketing' ] )->getMock();
161 $handlerMock->expects( $this->any() )
162 ->method( 'supportsBucketing' )
163 ->will( $this->returnValue( $data['supportsBucketing'] ) );
164
165 $fileMock = $this->getMockBuilder( File::class )
166 ->setConstructorArgs( [ 'fileMock', $repoMock ] )
167 ->setMethods( [ 'getThumbnailBucket', 'getLocalRefPath', 'getHandler' ] )
168 ->getMockForAbstractClass();
169
170 $fileMock->expects( $this->any() )
171 ->method( 'getThumbnailBucket' )
172 ->will( $this->returnValue( $data['thumbnailBucket'] ) );
173
174 $fileMock->expects( $this->any() )
175 ->method( 'getLocalRefPath' )
176 ->will( $this->returnValue( 'localRefPath' ) );
177
178 $fileMock->expects( $this->any() )
179 ->method( 'getHandler' )
180 ->will( $this->returnValue( $handlerMock ) );
181
182 $reflection = new ReflectionClass( $fileMock );
183 $reflection_property = $reflection->getProperty( 'handler' );
184 $reflection_property->setAccessible( true );
185 $reflection_property->setValue( $fileMock, $handlerMock );
186
187 if ( !is_null( $data['tmpBucketedThumbCache'] ) ) {
188 $reflection_property = $reflection->getProperty( 'tmpBucketedThumbCache' );
189 $reflection_property->setAccessible( true );
190 $reflection_property->setValue( $fileMock, $data['tmpBucketedThumbCache'] );
191 }
192
193 $result = $fileMock->getThumbnailSource(
194 [ 'physicalWidth' => $data['physicalWidth'] ] );
195
196 $this->assertEquals( $data['expectedPath'], $result['path'], $data['message'] );
197 }
198
199 public function getThumbnailSourceProvider() {
200 return [
201 [ [
202 'supportsBucketing' => true,
203 'tmpBucketedThumbCache' => null,
204 'thumbnailBucket' => 1024,
205 'physicalWidth' => 2048,
206 'expectedPath' => 'fsFilePath',
207 'message' => 'Path downloaded from storage'
208 ] ],
209 [ [
210 'supportsBucketing' => true,
211 'tmpBucketedThumbCache' => [ 1024 => '/tmp/shouldnotexist' . rand() ],
212 'thumbnailBucket' => 1024,
213 'physicalWidth' => 2048,
214 'expectedPath' => 'fsFilePath',
215 'message' => 'Path downloaded from storage because temp file is missing'
216 ] ],
217 [ [
218 'supportsBucketing' => true,
219 'tmpBucketedThumbCache' => [ 1024 => '/tmp' ],
220 'thumbnailBucket' => 1024,
221 'physicalWidth' => 2048,
222 'expectedPath' => '/tmp',
223 'message' => 'Temporary path because temp file was found'
224 ] ],
225 [ [
226 'supportsBucketing' => false,
227 'tmpBucketedThumbCache' => null,
228 'thumbnailBucket' => 1024,
229 'physicalWidth' => 2048,
230 'expectedPath' => 'localRefPath',
231 'message' => 'Original file path because bucketing is unsupported by handler'
232 ] ],
233 [ [
234 'supportsBucketing' => true,
235 'tmpBucketedThumbCache' => null,
236 'thumbnailBucket' => false,
237 'physicalWidth' => 2048,
238 'expectedPath' => 'localRefPath',
239 'message' => 'Original file path because no width provided'
240 ] ],
241 ];
242 }
243
244 /**
245 * @dataProvider generateBucketsIfNeededProvider
246 * @covers File::generateBucketsIfNeeded
247 */
248 public function testGenerateBucketsIfNeeded( $data ) {
249 $this->setMwGlobals( 'wgThumbnailBuckets', $data['buckets'] );
250
251 $backendMock = $this->getMockBuilder( FSFileBackend::class )
252 ->setConstructorArgs( [ [ 'name' => 'backendMock', 'wikiId' => wfWikiID() ] ] )
253 ->getMock();
254
255 $repoMock = $this->getMockBuilder( FileRepo::class )
256 ->setConstructorArgs( [ [ 'name' => 'repoMock', 'backend' => $backendMock ] ] )
257 ->setMethods( [ 'fileExists', 'getLocalReference' ] )
258 ->getMock();
259
260 $fileMock = $this->getMockBuilder( File::class )
261 ->setConstructorArgs( [ 'fileMock', $repoMock ] )
262 ->setMethods( [ 'getWidth', 'getBucketThumbPath', 'makeTransformTmpFile',
263 'generateAndSaveThumb', 'getHandler' ] )
264 ->getMockForAbstractClass();
265
266 $handlerMock = $this->getMockBuilder( JpegHandler::class )
267 ->setMethods( [ 'supportsBucketing' ] )->getMock();
268 $handlerMock->expects( $this->any() )
269 ->method( 'supportsBucketing' )
270 ->will( $this->returnValue( true ) );
271
272 $fileMock->expects( $this->any() )
273 ->method( 'getHandler' )
274 ->will( $this->returnValue( $handlerMock ) );
275
276 $reflectionMethod = new ReflectionMethod( File::class, 'generateBucketsIfNeeded' );
277 $reflectionMethod->setAccessible( true );
278
279 $fileMock->expects( $this->any() )
280 ->method( 'getWidth' )
281 ->will( $this->returnValue( $data['width'] ) );
282
283 $fileMock->expects( $data['expectedGetBucketThumbPathCalls'] )
284 ->method( 'getBucketThumbPath' );
285
286 $repoMock->expects( $data['expectedFileExistsCalls'] )
287 ->method( 'fileExists' )
288 ->will( $this->returnValue( $data['fileExistsReturn'] ) );
289
290 $fileMock->expects( $data['expectedMakeTransformTmpFile'] )
291 ->method( 'makeTransformTmpFile' )
292 ->will( $this->returnValue( $data['makeTransformTmpFileReturn'] ) );
293
294 $fileMock->expects( $data['expectedGenerateAndSaveThumb'] )
295 ->method( 'generateAndSaveThumb' )
296 ->will( $this->returnValue( $data['generateAndSaveThumbReturn'] ) );
297
298 $this->assertEquals( $data['expectedResult'],
299 $reflectionMethod->invoke(
300 $fileMock,
301 [
302 'physicalWidth' => $data['physicalWidth'],
303 'physicalHeight' => $data['physicalHeight'] ]
304 ),
305 $data['message'] );
306 }
307
308 public function generateBucketsIfNeededProvider() {
309 $defaultBuckets = [ 256, 512, 1024, 2048, 4096 ];
310
311 return [
312 [ [
313 'buckets' => $defaultBuckets,
314 'width' => 256,
315 'physicalWidth' => 256,
316 'physicalHeight' => 100,
317 'expectedGetBucketThumbPathCalls' => $this->never(),
318 'expectedFileExistsCalls' => $this->never(),
319 'fileExistsReturn' => null,
320 'expectedMakeTransformTmpFile' => $this->never(),
321 'makeTransformTmpFileReturn' => false,
322 'expectedGenerateAndSaveThumb' => $this->never(),
323 'generateAndSaveThumbReturn' => false,
324 'expectedResult' => false,
325 'message' => 'No bucket found, nothing to generate'
326 ] ],
327 [ [
328 'buckets' => $defaultBuckets,
329 'width' => 5000,
330 'physicalWidth' => 300,
331 'physicalHeight' => 200,
332 'expectedGetBucketThumbPathCalls' => $this->once(),
333 'expectedFileExistsCalls' => $this->once(),
334 'fileExistsReturn' => true,
335 'expectedMakeTransformTmpFile' => $this->never(),
336 'makeTransformTmpFileReturn' => false,
337 'expectedGenerateAndSaveThumb' => $this->never(),
338 'generateAndSaveThumbReturn' => false,
339 'expectedResult' => false,
340 'message' => 'File already exists, no reason to generate buckets'
341 ] ],
342 [ [
343 'buckets' => $defaultBuckets,
344 'width' => 5000,
345 'physicalWidth' => 300,
346 'physicalHeight' => 200,
347 'expectedGetBucketThumbPathCalls' => $this->once(),
348 'expectedFileExistsCalls' => $this->once(),
349 'fileExistsReturn' => false,
350 'expectedMakeTransformTmpFile' => $this->once(),
351 'makeTransformTmpFileReturn' => false,
352 'expectedGenerateAndSaveThumb' => $this->never(),
353 'generateAndSaveThumbReturn' => false,
354 'expectedResult' => false,
355 'message' => 'Cannot generate temp file for bucket'
356 ] ],
357 [ [
358 'buckets' => $defaultBuckets,
359 'width' => 5000,
360 'physicalWidth' => 300,
361 'physicalHeight' => 200,
362 'expectedGetBucketThumbPathCalls' => $this->once(),
363 'expectedFileExistsCalls' => $this->once(),
364 'fileExistsReturn' => false,
365 'expectedMakeTransformTmpFile' => $this->once(),
366 'makeTransformTmpFileReturn' => new TempFSFile( '/tmp/foo' ),
367 'expectedGenerateAndSaveThumb' => $this->once(),
368 'generateAndSaveThumbReturn' => false,
369 'expectedResult' => false,
370 'message' => 'Bucket image could not be generated'
371 ] ],
372 [ [
373 'buckets' => $defaultBuckets,
374 'width' => 5000,
375 'physicalWidth' => 300,
376 'physicalHeight' => 200,
377 'expectedGetBucketThumbPathCalls' => $this->once(),
378 'expectedFileExistsCalls' => $this->once(),
379 'fileExistsReturn' => false,
380 'expectedMakeTransformTmpFile' => $this->once(),
381 'makeTransformTmpFileReturn' => new TempFSFile( '/tmp/foo' ),
382 'expectedGenerateAndSaveThumb' => $this->once(),
383 'generateAndSaveThumbReturn' => new ThumbnailImage( false, 'bar', false, false ),
384 'expectedResult' => true,
385 'message' => 'Bucket image could not be generated'
386 ] ],
387 ];
388 }
389 }