Merge "CSSMin: Skip #default#behaviorName when detecting local files"
[lhc/web/wiklou.git] / tests / phpunit / includes / libs / CSSMinTest.php
index 366714b..1a15c26 100644 (file)
@@ -5,6 +5,10 @@
  * @author Timo Tijhof
  */
 
+/**
+ * @group ResourceLoader
+ * @group CSSMin
+ */
 class CSSMinTest extends MediaWikiTestCase {
 
        protected function setUp() {
@@ -18,6 +22,81 @@ class CSSMinTest extends MediaWikiTestCase {
                ] );
        }
 
+       /**
+        * @dataProvider mimeTypeProvider
+        */
+       public function testGetMimeType( $fileContents, $fileExtension, $expected ) {
+               $fileName = wfTempDir() . DIRECTORY_SEPARATOR . uniqid( 'MW_PHPUnit_CSSMinTest_' ) . '.'
+                       . $fileExtension;
+               $this->addTmpFiles( $fileName );
+               file_put_contents( $fileName, $fileContents );
+               $this->assertSame( $expected, CSSMin::getMimeType( $fileName ) );
+       }
+
+       public function mimeTypeProvider() {
+               return [
+                       'JPEG with short extension' => [
+                               "\xFF\xD8\xFF",
+                               'jpg',
+                               'image/jpeg'
+                       ],
+                       'JPEG with long extension' => [
+                               "\xFF\xD8\xFF",
+                               'jpeg',
+                               'image/jpeg'
+                       ],
+                       'PNG' => [
+                               "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A",
+                               'png',
+                               'image/png'
+                       ],
+
+                       'PNG extension but JPEG content' => [
+                               "\xFF\xD8\xFF",
+                               'png',
+                               'image/png'
+                       ],
+                       'JPEG extension but PNG content' => [
+                               "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A",
+                               'jpg',
+                               'image/jpeg'
+                       ],
+                       'PNG extension but SVG content' => [
+                               '<?xml version="1.0"?><svg></svg>',
+                               'png',
+                               'image/png'
+                       ],
+                       'SVG extension but PNG content' => [
+                               "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A",
+                               'svg',
+                               'image/svg+xml'
+                       ],
+
+                       'SVG with all headers' => [
+                               '<?xml version="1.0"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" '
+                               . '"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg></svg>',
+                               'svg',
+                               'image/svg+xml'
+                       ],
+                       'SVG with XML header only' => [
+                               '<?xml version="1.0"?><svg></svg>',
+                               'svg',
+                               'image/svg+xml'
+                       ],
+                       'SVG with DOCTYPE only' => [
+                               '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" '
+                               . '"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg></svg>',
+                               'svg',
+                               'image/svg+xml'
+                       ],
+                       'SVG without any header' => [
+                               '<svg></svg>',
+                               'svg',
+                               'image/svg+xml'
+                       ],
+               ];
+       }
+
        /**
         * @dataProvider provideMinifyCases
         * @covers CSSMin::minify
@@ -54,7 +133,7 @@ class CSSMinTest extends MediaWikiTestCase {
                        [ "foo, bar {\n\tprop: value; /* comment */\n}", "foo,bar{prop:value; }" ],
 
                        // Keep track of things that aren't as minified as much as they
-                       // could be (bug 35493)
+                       // could be (T37493)
                        [ 'foo { prop: value ;}', 'foo{prop:value }' ],
                        [ 'foo { prop : value; }', 'foo{prop :value}' ],
                        [ 'foo { prop: value ; }', 'foo{prop:value }' ],
@@ -72,6 +151,45 @@ class CSSMinTest extends MediaWikiTestCase {
                ];
        }
 
+       public static function provideIsRemoteUrl() {
+               return [
+                       [ true, 'http://localhost/w/red.gif?123' ],
+                       [ true, 'https://example.org/x.png' ],
+                       [ true, '//example.org/x.y.z/image.png' ],
+                       [ true, '//localhost/styles.css?query=yes' ],
+                       [ true, 'data:image/gif;base64,R0lGODlhAQABAIAAAP8AADAAACwAAAAAAQABAAACAkQBADs=' ],
+                       [ false, 'x.gif' ],
+                       [ false, '/x.gif' ],
+                       [ false, './x.gif' ],
+                       [ false, '../x.gif' ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideIsRemoteUrl
+        * @cover CSSMin::isRemoteUrl
+        */
+       public function testIsRemoteUrl( $expect, $url ) {
+               $this->assertEquals( CSSMinTestable::isRemoteUrl( $url ), $expect );
+       }
+
+       public static function provideIsLocalUrls() {
+               return [
+                       [ false, 'x.gif' ],
+                       [ true, '/x.gif' ],
+                       [ false, './x.gif' ],
+                       [ false, '../x.gif' ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideIsLocalUrls
+        * @cover CSSMin::isLocalUrl
+        */
+       public function testIsLocalUrl( $expect, $url ) {
+               $this->assertEquals( CSSMinTestable::isLocalUrl( $url ), $expect );
+       }
+
        /**
         * This tests funky parameters to CSSMin::remap. testRemapRemapping tests
         * the basic functionality.
@@ -105,7 +223,7 @@ class CSSMinTest extends MediaWikiTestCase {
                                'foo { prop: url(http://example.org/bar.png); }',
                        ],
                        [
-                               'With trailing slash on remote (bug 27052)',
+                               'With trailing slash on remote (T29052)',
                                [ 'foo { prop: url(../bar.png); }', false, 'http://example.org/quux/', false ],
                                'foo { prop: url(http://example.org/bar.png); }',
                        ],
@@ -119,6 +237,11 @@ class CSSMinTest extends MediaWikiTestCase {
                                [ 'foo { prop: url(/w/skin/images/bar.png); }', false, 'http://example.org/quux', false ],
                                'foo { prop: url(http://doc.example.org/w/skin/images/bar.png); }',
                        ],
+                       [
+                               "Don't barf at behavior: url(#default#behaviorName) - T162973",
+                               [ 'foo { behavior: url(#default#bar); }', false, '/w/', false ],
+                               'foo { behavior: url("#default#bar"); }',
+                       ],
                ];
        }
 
@@ -136,45 +259,6 @@ class CSSMinTest extends MediaWikiTestCase {
                $this->assertEquals( $expectedOutput, $realOutput, "CSSMin::remap: $message" );
        }
 
-       public static function provideIsRemoteUrl() {
-               return [
-                       [ true, 'http://localhost/w/red.gif?123' ],
-                       [ true, 'https://example.org/x.png' ],
-                       [ true, '//example.org/x.y.z/image.png' ],
-                       [ true, '//localhost/styles.css?query=yes' ],
-                       [ true, 'data:image/gif;base64,R0lGODlhAQABAIAAAP8AADAAACwAAAAAAQABAAACAkQBADs=' ],
-                       [ false, 'x.gif' ],
-                       [ false, '/x.gif' ],
-                       [ false, './x.gif' ],
-                       [ false, '../x.gif' ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideIsRemoteUrl
-        * @cover CSSMin::isRemoteUrl
-        */
-       public function testIsRemoteUrl( $expect, $url ) {
-               $this->assertEquals( CSSMinTestable::isRemoteUrl( $url ), $expect );
-       }
-
-       public static function provideIsLocalUrls() {
-               return [
-                       [ false, 'x.gif' ],
-                       [ true, '/x.gif' ],
-                       [ false, './x.gif' ],
-                       [ false, '../x.gif' ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideIsLocalUrls
-        * @cover CSSMin::isLocalUrl
-        */
-       public function testIsLocalUrl( $expect, $url ) {
-               $this->assertEquals( CSSMinTestable::isLocalUrl( $url ), $expect );
-       }
-
        public static function provideRemapRemappingCases() {
                // red.gif and green.gif are one-pixel 35-byte GIFs.
                // large.png is a 35K PNG that should be non-embeddable.
@@ -232,8 +316,8 @@ class CSSMinTest extends MediaWikiTestCase {
                        ],
                        [
                                'Remote URL (unnecessary quotes not preserved)',
-                               'foo { background: url("http://example.org/w/foo.png"); }',
-                               'foo { background: url(http://example.org/w/foo.png); }',
+                               'foo { background: url("http://example.org/w/unnecessary-quotes.png"); }',
+                               'foo { background: url(http://example.org/w/unnecessary-quotes.png); }',
                        ],
                        [
                                'Embedded file',
@@ -335,9 +419,39 @@ class CSSMinTest extends MediaWikiTestCase {
                                '@import url(http://doc.example.org/styles.css)',
                        ],
                        [
-                               '@import rule to URL (should we remap this?)',
-                               '@import url(//localhost/styles.css?query=yes)',
-                               '@import url(//localhost/styles.css?query=yes)',
+                               '@import rule to local file (should we remap this?)',
+                               '@import url(/styles.css)',
+                               '@import url(http://doc.example.org/styles.css)',
+                       ],
+                       [
+                               '@import rule to URL',
+                               '@import url(//localhost/styles.css?query=val)',
+                               '@import url(//localhost/styles.css?query=val)',
+                       ],
+                       [
+                               'Background URL (double quotes)',
+                               'foo { background: url("//localhost/styles.css?quoted=double") }',
+                               'foo { background: url(//localhost/styles.css?quoted=double) }',
+                       ],
+                       [
+                               'Background URL (single quotes)',
+                               'foo { background: url(\'//localhost/styles.css?quoted=single\') }',
+                               'foo { background: url(//localhost/styles.css?quoted=single) }',
+                       ],
+                       [
+                               'Background URL (containing parentheses; T60473)',
+                               'foo { background: url("//localhost/styles.css?query=(parens)") }',
+                               'foo { background: url("//localhost/styles.css?query=(parens)") }',
+                       ],
+                       [
+                               'Background URL (double quoted, containing single quotes; T60473)',
+                               'foo { background: url("//localhost/styles.css?quote=\'") }',
+                               'foo { background: url("//localhost/styles.css?quote=\'") }',
+                       ],
+                       [
+                               'Background URL (single quoted, containing double quotes; T60473)',
+                               'foo { background: url(\'//localhost/styles.css?quote="\') }',
+                               'foo { background: url("//localhost/styles.css?quote=\"") }',
                        ],
                        [
                                'Simple case with comments before url',
@@ -370,7 +484,7 @@ class CSSMinTest extends MediaWikiTestCase {
                                '{ background: /*asd*/ url(http://localhost/w/something.png); background: /*jkl*/ url(http://localhost/w/something.png); }',
                        ],
                        [
-                               'Sanity check for offending line from jquery.ui.theme.css (bug 60077)',
+                               'Sanity check for offending line from jquery.ui.theme.css (T62077)',
                                '.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }',
                                '.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(http://localhost/w/images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }',
                        ],
@@ -418,7 +532,7 @@ class CSSMinTest extends MediaWikiTestCase {
        }
 
        /**
-        * Seperated because they are currently broken (bug 35492)
+        * Seperated because they are currently broken (T37492)
         *
         * @group Broken
         * @dataProvider provideStringCases