<?php
-/**
- * This file test the CSSMin library shipped with Mediawiki.
- *
- * @author Timo Tijhof
- */
+
+use Wikimedia\TestingAccessWrapper;
/**
* @group ResourceLoader
protected function setUp() {
parent::setUp();
- $server = 'http://doc.example.org';
-
+ // For wfExpandUrl
+ $server = 'https://expand.example';
$this->setMwGlobals( [
'wgServer' => $server,
'wgCanonicalServer' => $server,
}
/**
- * @dataProvider mimeTypeProvider
+ * @dataProvider provideSerializeStringValue
+ * @covers CSSMin::serializeStringValue
+ */
+ public function testSerializeStringValue( $input, $expected ) {
+ $output = CSSMin::serializeStringValue( $input );
+ $this->assertEquals(
+ $expected,
+ $output,
+ 'Serialized output must be in the expected form.'
+ );
+ }
+
+ public static function provideSerializeStringValue() {
+ return [
+ [ 'Hello World!', '"Hello World!"' ],
+ [ "Null\0Null", "\"Null\\fffd Null\"" ],
+ [ '"', '"\\""' ],
+ [ "'", '"\'"' ],
+ [ "\\", '"\\\\"' ],
+ [ "Tab\tTab", '"Tab\\9 Tab"' ],
+ [ "Space tab \t space", '"Space tab \\9 space"' ],
+ [ "Line\nfeed", '"Line\\a feed"' ],
+ [ "Return\rreturn", '"Return\\d return"' ],
+ [ "Next\xc2\x85line", "\"Next\xc2\x85line\"" ],
+ [ "Del\x7fDel", '"Del\\7f Del"' ],
+ [ "nb\xc2\xa0sp", "\"nb\xc2\xa0sp\"" ],
+ [ "AMP&AMP", "\"AMP&AMP\"" ],
+ [ '!"#$%&\'()*+,-./0123456789:;<=>?', '"!\\"#$%&\'()*+,-./0123456789:;<=>?"' ],
+ [ '@[\\]^_`{|}~', '"@[\\\\]^_`{|}~"' ],
+ [ 'ä', '"ä"' ],
+ [ 'Ä', '"Ä"' ],
+ [ '€', '"€"' ],
+ [ '𝒞', '"𝒞"' ], // U+1D49E 'MATHEMATICAL SCRIPT CAPITAL C'
+ ];
+ }
+
+ /**
+ * @dataProvider provideMimeType
* @covers CSSMin::getMimeType
*/
public function testGetMimeType( $fileContents, $fileExtension, $expected ) {
$this->assertSame( $expected, CSSMin::getMimeType( $fileName ) );
}
- public function mimeTypeProvider() {
+ public static function provideMimeType() {
return [
'JPEG with short extension' => [
"\xFF\xD8\xFF",
[ "foo { content: '\"'; }", "foo{content:'\"'}" ],
// - Whitespace in string values
[ 'foo { content: " "; }', 'foo{content:" "}' ],
+
+ // Whitespaces after opening and before closing parentheses and brackets
+ [ 'a:not( [ href ] ) { prop: url( foobar.png ); }', 'a:not([href]){prop:url(foobar.png)}' ],
+
+ // Ensure that the invalid "url (" will not become the valid "url(" by minification
+ [ 'foo { prop: url ( foobar.png ); }', 'foo{prop:url (foobar.png)}' ],
];
}
* @covers CSSMin::isRemoteUrl
*/
public function testIsRemoteUrl( $expect, $url ) {
- $this->assertEquals( CSSMinTestable::isRemoteUrl( $url ), $expect );
+ $class = TestingAccessWrapper::newFromClass( CSSMin::class );
+ $this->assertEquals( $class->isRemoteUrl( $url ), $expect );
}
public static function provideIsLocalUrls() {
* @covers CSSMin::isLocalUrl
*/
public function testIsLocalUrl( $expect, $url ) {
- $this->assertEquals( CSSMinTestable::isLocalUrl( $url ), $expect );
+ $class = TestingAccessWrapper::newFromClass( CSSMin::class );
+ $this->assertEquals( $class->isLocalUrl( $url ), $expect );
}
/**
[
'Expand absolute paths',
[ '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); }',
+ 'foo { prop: url(https://expand.example/w/skin/images/bar.png); }',
],
[
"Don't barf at behavior: url(#default#behaviorName) - T162973",
];
}
+ /**
+ * Cases with empty url() for CSSMin::remap.
+ *
+ * Regression test for T191237.
+ *
+ * @dataProvider provideRemapEmptyUrl
+ * @covers CSSMin
+ */
+ public function testRemapEmptyUrl( $params, $expected ) {
+ $remapped = call_user_func_array( 'CSSMin::remap', $params );
+ $this->assertEquals( $expected, $remapped, 'Ignore empty url' );
+ }
+
+ public static function provideRemapEmptyUrl() {
+ return [
+ 'Empty' => [
+ [ "background-image: url();", false, '/example', false ],
+ "background-image: url();",
+ ],
+ 'Single quote' => [
+ [ "background-image: url('');", false, '/example', false ],
+ "background-image: url('');",
+ ],
+ 'Double quote' => [
+ [ 'background-image: url("");', false, '/example', false ],
+ 'background-image: url("");',
+ ],
+ ];
+ }
+
/**
* This tests the basic functionality of CSSMin::remap.
*
[
'Domain-relative URL',
'foo { background: url(/static/foo.png); }',
- 'foo { background: url(http://doc.example.org/static/foo.png); }',
+ 'foo { background: url(https://expand.example/static/foo.png); }',
],
[
'Domain-relative URL with query',
'foo { background: url(/static/foo.png?query=yes); }',
- 'foo { background: url(http://doc.example.org/static/foo.png?query=yes); }',
+ 'foo { background: url(https://expand.example/static/foo.png?query=yes); }',
],
[
'Remote URL (unnecessary quotes not preserved)',
[
'@import rule to local file (should we remap this?)',
'@import url(/styles.css)',
- '@import url(http://doc.example.org/styles.css)',
+ '@import url(https://expand.example/styles.css)',
],
[
'@import rule to local file (should we remap this?)',
'@import url(/styles.css)',
- '@import url(http://doc.example.org/styles.css)',
+ '@import url(https://expand.example/styles.css)',
],
[
'@import rule to URL',
'foo { background: url(//localhost/styles.css?quoted=single) }',
],
[
- 'Background URL (containing parentheses; T60473)',
+ 'Background URL (double quoted, containing parentheses; T60473)',
'foo { background: url("//localhost/styles.css?query=(parens)") }',
'foo { background: url("//localhost/styles.css?query=(parens)") }',
],
'foo { background: url(\'//localhost/styles.css?quote="\') }',
'foo { background: url("//localhost/styles.css?quote=\"") }',
],
+ [
+ 'Background URL (double quoted with outer spacing)',
+ 'foo { background: url( "http://localhost/styles.css?quoted=double" ) }',
+ 'foo { background: url(http://localhost/styles.css?quoted=double) }',
+ ],
[
'Simple case with comments before url',
'foo { prop: /* some {funny;} comment */ url(bar.png); }',
];
}
}
-
-class CSSMinTestable extends CSSMin {
- // Make some protected methods public
- public static function isRemoteUrl( $maybeUrl ) {
- return parent::isRemoteUrl( $maybeUrl );
- }
- public static function isLocalUrl( $maybeUrl ) {
- return parent::isLocalUrl( $maybeUrl );
- }
-}