getServiceContainer()->getWikiPageFactory()->newFromTitle( $title );
$user = static::getTestSysop()->getUser();
$status = $page->doUserEditContent( $content, $user, 'Test for TemplateStyles' );
if ( !$status->isOk() ) {
$this->fail( "Failed to create $title: " . $status->getWikiText( false, false, 'en' ) );
}
}
public function addDBDataOnce() {
$this->addPage( 'wikitext', '.foo { color: red; }', CONTENT_MODEL_WIKITEXT );
$this->addPage( 'nonsanitized.css', '.foo { color: red; }', CONTENT_MODEL_CSS );
$this->addPage( 'styles1.css', '.foo { color: blue; }', 'sanitized-css' );
$this->addPage( 'styles2.css', '.bar { color: green; }', 'sanitized-css' );
$this->addPage(
'styles3.css', 'html.no-js body.skin-minerva .bar { color: yellow; }', 'sanitized-css'
);
}
public function testGetSanitizerInvalidWrapper() {
$this->expectException( InvalidArgumentException::class );
$this->expectExceptionMessage( 'Invalid value for $extraWrapper: .foo>.bar' );
TemplateStylesHooks::getSanitizer( 'foo', '.foo>.bar' );
}
public function testGetSanitizerNonLinearWrapper() {
$sanitizer = TemplateStylesHooks::getSanitizer( 'foo', 'div[data]' );
$sanitizer->sanitize( CSSParser::newFromString( '.not-empty { }' )->parseStylesheet() );
$this->assertSame( [], $sanitizer->getSanitizationErrors() );
}
/**
* @dataProvider provideOnRegistration
* @param array $textModelsToParse
* @param bool $autoParseContent
* @param array $expect
*/
public function testOnRegistration( $textModelsToParse, $autoParseContent, $expect ) {
$this->setMwGlobals( [
'wgTextModelsToParse' => $textModelsToParse,
'wgTemplateStylesAutoParseContent' => $autoParseContent,
] );
global $wgTextModelsToParse;
TemplateStylesHooks::onRegistration();
$this->assertSame( $expect, $wgTextModelsToParse );
}
public static function provideOnRegistration() {
return [
[
[ CONTENT_MODEL_WIKITEXT ],
true,
[ CONTENT_MODEL_WIKITEXT ]
],
[
[ CONTENT_MODEL_WIKITEXT, CONTENT_MODEL_CSS ],
true,
[ CONTENT_MODEL_WIKITEXT, CONTENT_MODEL_CSS, 'sanitized-css' ],
],
[
[ CONTENT_MODEL_WIKITEXT, CONTENT_MODEL_CSS ],
false,
[ CONTENT_MODEL_WIKITEXT, CONTENT_MODEL_CSS ],
],
];
}
/**
* @dataProvider provideOnContentHandlerDefaultModelFor
*/
public function testOnContentHandlerDefaultModelFor( $ns, $title, $expect ) {
$this->setMwGlobals( [
'wgTemplateStylesNamespaces' => [
10 => true,
2 => false,
3000 => true,
3002 => true,
3006 => false,
],
'wgNamespacesWithSubpages' => [
10 => true,
2 => true,
3000 => true,
3002 => false,
3004 => true,
3006 => true
],
] );
$reset = ExtensionRegistry::getInstance()->setAttributeForTest(
'TemplateStylesNamespaces', [ 3004, 3006 ]
);
$model = 'unchanged';
$ret = ( new TemplateStylesHooks )->onContentHandlerDefaultModelFor(
Title::makeTitle( $ns, $title ), $model
);
$this->assertSame( !$expect, $ret );
$this->assertSame( $expect ? 'sanitized-css' : 'unchanged', $model );
}
public static function provideOnContentHandlerDefaultModelFor() {
return [
[ 10, 'Test/test.css', true ],
[ 10, 'Test.css', false ],
[ 10, 'Test/test.xss', false ],
[ 10, 'Test/test.CSS', false ],
[ 3000, 'Test/test.css', true ],
[ 3002, 'Test/test.css', false ],
[ 2, 'Test/test.css', false ],
[ 3004, 'Test/test.css', true ],
[ 3006, 'Test/test.css', false ],
];
}
/**
* Unfortunately we can't just use a parserTests.txt file because our
* tag's output depends on the revision IDs of the input pages.
* @dataProvider provideTag
*/
public function testTag(
ParserOptions $popt, $getTextOptions, $wikitext, $expect, $globals = []
) {
$this->setMwGlobals( $globals + [
'wgScriptPath' => '',
'wgScript' => '/index.php',
'wgArticlePath' => '/wiki/$1',
] );
$oldCurrentRevisionRecordCallback = $popt->setCurrentRevisionRecordCallback(
static function ( Title $title, $parser = null ) use ( &$oldCurrentRevisionRecordCallback ) {
if ( $title->getPrefixedText() === 'Template:Test replacement' ) {
$user = RequestContext::getMain()->getUser();
$revRecord = new MutableRevisionRecord( $title );
$revRecord->setUser( $user );
$revRecord->setContent(
SlotRecord::MAIN,
new TemplateStylesContent( '.baz { color:orange; bogus:bogus; }' )
);
$revRecord->setParentId( $title->getLatestRevID() );
return $revRecord;
}
return call_user_func( $oldCurrentRevisionRecordCallback, $title, $parser );
}
);
$services = MediaWikiServices::getInstance();
$parser = $services->getParserFactory()->create();
$parser->firstCallInit();
if ( !in_array( 'templatestyles', $parser->getTags(), true ) ) {
throw new Exception( 'templatestyles tag hook is not in the parser' );
}
$out = $parser->parse( $wikitext, Title::newFromText( 'Test' ), $popt );
$expect = preg_replace_callback( '/\{\{REV:(.*?)\}\}/', static function ( $m ) {
return Title::newFromText( 'Template:TemplateStyles test/' . $m[1] )->getLatestRevID();
}, $expect );
$this->assertEquals( $expect, $out->getText( $getTextOptions ) );
}
public static function provideTag() {
$popt = ParserOptions::newFromContext( RequestContext::getMain() );
$popt->setWrapOutputClass( 'templatestyles-test' );
$popt2 = ParserOptions::newFromContext( RequestContext::getMain() );
$popt3 = ParserOptions::newFromContext( RequestContext::getMain() );
AtEase::quietCall( [ $popt3, 'setWrapOutputClass' ], false );
return [
'Tag without src' => [
$popt, [],
'
TemplateStyles' src
attribute must not be empty.\n
Invalid title for TemplateStyles' src
attribute.\n
Page Template:ThisDoes'''Not'''Exist has no content.\n
Page ThisDoes'''Not'''Exist has no content.\n
Page Template:TemplateStyles test/wikitext must have content model \"Sanitized CSS\" for TemplateStyles (current model is \"wikitext\").\n
Page Template:TemplateStyles test/nonsanitized.css must have content model \"Sanitized CSS\" for TemplateStyles (current model is \"CSS\").\n
Invalid value for TemplateStyles' wrapper
attribute.\n
Invalid value for TemplateStyles' wrapper
attribute.\n