Merge "Exclude redirects from Special:Fewestrevisions"
[lhc/web/wiklou.git] / tests / phpunit / includes / resourceloader / ResourceLoaderImageModuleTest.php
1 <?php
2
3 use Wikimedia\TestingAccessWrapper;
4
5 /**
6 * @group ResourceLoader
7 */
8 class ResourceLoaderImageModuleTest extends ResourceLoaderTestCase {
9
10 public static $commonImageData = [
11 'abc' => 'abc.gif',
12 'def' => [
13 'file' => 'def.svg',
14 'variants' => [ 'destructive' ],
15 ],
16 'ghi' => [
17 'file' => [
18 'ltr' => 'ghi.svg',
19 'rtl' => 'jkl.svg'
20 ],
21 ],
22 'mno' => [
23 'file' => [
24 'ltr' => 'mno-ltr.svg',
25 'rtl' => 'mno-rtl.svg',
26 'lang' => [
27 'he' => 'mno-ltr.svg',
28 ]
29 ],
30 ],
31 'pqr' => [
32 'file' => [
33 'default' => 'pqr-a.svg',
34 'lang' => [
35 'en' => 'pqr-b.svg',
36 'ar,de' => 'pqr-f.svg',
37 ]
38 ],
39 ]
40 ];
41
42 public static $commonImageVariants = [
43 'invert' => [
44 'color' => '#FFFFFF',
45 'global' => true,
46 ],
47 'primary' => [
48 'color' => '#598AD1',
49 ],
50 'constructive' => [
51 'color' => '#00C697',
52 ],
53 'destructive' => [
54 'color' => '#E81915',
55 ],
56 ];
57
58 public static function providerGetModules() {
59 return [
60 [
61 [
62 'class' => ResourceLoaderImageModule::class,
63 'prefix' => 'oo-ui-icon',
64 'variants' => self::$commonImageVariants,
65 'images' => self::$commonImageData,
66 ],
67 '.oo-ui-icon-abc {
68 ...
69 }
70 .oo-ui-icon-abc-invert {
71 ...
72 }
73 .oo-ui-icon-def {
74 ...
75 }
76 .oo-ui-icon-def-invert {
77 ...
78 }
79 .oo-ui-icon-def-destructive {
80 ...
81 }
82 .oo-ui-icon-ghi {
83 ...
84 }
85 .oo-ui-icon-ghi-invert {
86 ...
87 }
88 .oo-ui-icon-mno {
89 ...
90 }
91 .oo-ui-icon-mno-invert {
92 ...
93 }
94 .oo-ui-icon-pqr {
95 ...
96 }
97 .oo-ui-icon-pqr-invert {
98 ...
99 }',
100 ],
101 [
102 [
103 'class' => ResourceLoaderImageModule::class,
104 'selectorWithoutVariant' => '.mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
105 'selectorWithVariant' =>
106 '.mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before',
107 'variants' => self::$commonImageVariants,
108 'images' => self::$commonImageData,
109 ],
110 '.mw-ui-icon-abc:after, .mw-ui-icon-abc:before {
111 ...
112 }
113 .mw-ui-icon-abc-invert:after, .mw-ui-icon-abc-invert:before {
114 ...
115 }
116 .mw-ui-icon-def:after, .mw-ui-icon-def:before {
117 ...
118 }
119 .mw-ui-icon-def-invert:after, .mw-ui-icon-def-invert:before {
120 ...
121 }
122 .mw-ui-icon-def-destructive:after, .mw-ui-icon-def-destructive:before {
123 ...
124 }
125 .mw-ui-icon-ghi:after, .mw-ui-icon-ghi:before {
126 ...
127 }
128 .mw-ui-icon-ghi-invert:after, .mw-ui-icon-ghi-invert:before {
129 ...
130 }
131 .mw-ui-icon-mno:after, .mw-ui-icon-mno:before {
132 ...
133 }
134 .mw-ui-icon-mno-invert:after, .mw-ui-icon-mno-invert:before {
135 ...
136 }
137 .mw-ui-icon-pqr:after, .mw-ui-icon-pqr:before {
138 ...
139 }
140 .mw-ui-icon-pqr-invert:after, .mw-ui-icon-pqr-invert:before {
141 ...
142 }',
143 ],
144 ];
145 }
146
147 /**
148 * Test reading files from elsewhere than localBasePath using ResourceLoaderFilePath.
149 *
150 * This mimics modules modified by skins using 'ResourceModuleSkinStyles' and 'OOUIThemePaths'
151 * skin attributes.
152 *
153 * @covers ResourceLoaderFilePath::getLocalBasePath
154 * @covers ResourceLoaderFilePath::getRemoteBasePath
155 */
156 public function testResourceLoaderFilePath() {
157 $basePath = __DIR__ . '/../../data/blahblah';
158 $filePath = __DIR__ . '/../../data/rlfilepath';
159 $testModule = new ResourceLoaderImageModule( [
160 'localBasePath' => $basePath,
161 'remoteBasePath' => 'blahblah',
162 'prefix' => 'foo',
163 'images' => [
164 'eye' => new ResourceLoaderFilePath( 'eye.svg', $filePath, 'rlfilepath' ),
165 'flag' => [
166 'file' => [
167 'ltr' => new ResourceLoaderFilePath( 'flag-ltr.svg', $filePath, 'rlfilepath' ),
168 'rtl' => new ResourceLoaderFilePath( 'flag-rtl.svg', $filePath, 'rlfilepath' ),
169 ],
170 ],
171 ],
172 ] );
173 $expectedModule = new ResourceLoaderImageModule( [
174 'localBasePath' => $filePath,
175 'remoteBasePath' => 'rlfilepath',
176 'prefix' => 'foo',
177 'images' => [
178 'eye' => 'eye.svg',
179 'flag' => [
180 'file' => [
181 'ltr' => 'flag-ltr.svg',
182 'rtl' => 'flag-rtl.svg',
183 ],
184 ],
185 ],
186 ] );
187
188 $context = $this->getResourceLoaderContext();
189 $this->assertEquals(
190 $expectedModule->getModuleContent( $context ),
191 $testModule->getModuleContent( $context ),
192 "Using ResourceLoaderFilePath works correctly"
193 );
194 }
195
196 /**
197 * @dataProvider providerGetModules
198 * @covers ResourceLoaderImageModule::getStyles
199 */
200 public function testGetStyles( $module, $expected ) {
201 $module = new ResourceLoaderImageModuleTestable(
202 $module,
203 __DIR__ . '/../../data/resourceloader'
204 );
205 $styles = $module->getStyles( $this->getResourceLoaderContext() );
206 $this->assertEquals( $expected, $styles['all'] );
207 }
208
209 /**
210 * @covers ResourceLoaderContext::getImageObj
211 */
212 public function testContext() {
213 $context = new ResourceLoaderContext( new EmptyResourceLoader(), new FauxRequest() );
214 $this->assertFalse( $context->getImageObj(), 'Missing image parameter' );
215
216 $context = new ResourceLoaderContext( new EmptyResourceLoader(), new FauxRequest( [
217 'image' => 'example',
218 ] ) );
219 $this->assertFalse( $context->getImageObj(), 'Missing module parameter' );
220
221 $context = new ResourceLoaderContext( new EmptyResourceLoader(), new FauxRequest( [
222 'modules' => 'unknown',
223 'image' => 'example',
224 ] ) );
225 $this->assertFalse( $context->getImageObj(), 'Not an image module' );
226
227 $rl = new EmptyResourceLoader();
228 $rl->register( 'test', [
229 'class' => ResourceLoaderImageModule::class,
230 'prefix' => 'test',
231 'images' => [ 'example' => 'example.png' ],
232 ] );
233 $context = new ResourceLoaderContext( $rl, new FauxRequest( [
234 'modules' => 'test',
235 'image' => 'unknown',
236 ] ) );
237 $this->assertFalse( $context->getImageObj(), 'Unknown image' );
238
239 $rl = new EmptyResourceLoader();
240 $rl->register( 'test', [
241 'class' => ResourceLoaderImageModule::class,
242 'prefix' => 'test',
243 'images' => [ 'example' => 'example.png' ],
244 ] );
245 $context = new ResourceLoaderContext( $rl, new FauxRequest( [
246 'modules' => 'test',
247 'image' => 'example',
248 ] ) );
249 $this->assertInstanceOf( ResourceLoaderImage::class, $context->getImageObj() );
250 }
251
252 public static function providerGetStyleDeclarations() {
253 return [
254 [
255 false,
256 <<<TEXT
257 background-image: url(rasterized.png);
258 background-image: linear-gradient(transparent, transparent), url(original.svg);
259 TEXT
260 ],
261 [
262 'data:image/svg+xml',
263 <<<TEXT
264 background-image: url(rasterized.png);
265 background-image: linear-gradient(transparent, transparent), url(data:image/svg+xml);
266 TEXT
267 ],
268
269 ];
270 }
271
272 /**
273 * @dataProvider providerGetStyleDeclarations
274 * @covers ResourceLoaderImageModule::getStyleDeclarations
275 */
276 public function testGetStyleDeclarations( $dataUriReturnValue, $expected ) {
277 $module = TestingAccessWrapper::newFromObject( new ResourceLoaderImageModule() );
278 $context = $this->getResourceLoaderContext();
279 $image = $this->getImageMock( $context, $dataUriReturnValue );
280
281 $styles = $module->getStyleDeclarations(
282 $context,
283 $image,
284 'load.php'
285 );
286
287 $this->assertEquals( $expected, $styles );
288 }
289
290 private function getImageMock( ResourceLoaderContext $context, $dataUriReturnValue ) {
291 $image = $this->getMockBuilder( ResourceLoaderImage::class )
292 ->disableOriginalConstructor()
293 ->getMock();
294 $image->method( 'getDataUri' )
295 ->will( $this->returnValue( $dataUriReturnValue ) );
296 $image->expects( $this->any() )
297 ->method( 'getUrl' )
298 ->will( $this->returnValueMap( [
299 [ $context, 'load.php', null, 'original', 'original.svg' ],
300 [ $context, 'load.php', null, 'rasterized', 'rasterized.png' ],
301 ] ) );
302
303 return $image;
304 }
305 }
306
307 class ResourceLoaderImageModuleTestable extends ResourceLoaderImageModule {
308 /**
309 * Replace with a stub to make test cases easier to write.
310 */
311 protected function getCssDeclarations( $primary, $fallback ) {
312 return [ '...' ];
313 }
314 }