mOptions = ParserOptions::newFromUserAndLang( new User, $wgContLang );
$name = isset( $wgParserConf['preprocessorClass'] ) ? $wgParserConf['preprocessorClass'] : 'Preprocessor_DOM';
$this->mPreprocessor = new $name( $this );
}
function getStripList() {
return array( 'gallery', 'display map' /* Used by Maps, see r80025 CR */, '/foo' );
}
public static function provideCases() {
return array(
array( "Foo", "Foo" ),
array( "", "<!-- Foo -->" ),
array( "", "<!-- Foo --><!-- Bar -->" ),
array( " ", "<!-- Foo --> <!-- Bar -->" ),
array( " \n ", "<!-- Foo --> \n <!-- Bar -->" ),
array( " \n \n", "<!-- Foo --> \n <!-- Bar -->\n" ),
array( " \n", "<!-- Foo --> <!-- Bar -->\n" ),
array( "Bar", "<!-->Bar" ),
array( "\n== Baz ==\n", "== Foo ==\n <!-- Bar -->\n== Baz ==\n" ),
array( "", "gallery" ),
array( "Foo Bar", "Foo gallery Bar" ),
array( "", "gallery</gallery>" ),
array( " ", "<foo> gallery</gallery>" ),
array( " ", "<foo> gallery<gallery></gallery>" ),
array( " Foo bar ", "<noinclude> Foo bar </noinclude>" ),
array( "\n{{Foo}}\n", "<noinclude>\nFoo\n</noinclude>" ),
array( "\n{{Foo}}\n\n", "<noinclude>\nFoo\n</noinclude>\n" ),
array( "foo bar", "galleryfoo bar" ),
array( "<{{foo}}>", "<foo>" ),
array( "<{{{foo}}}>", "<foo>" ),
array( "", "gallery</gallery</gallery>" ),
array( "=== Foo === ", "=== Foo === " ),
array( "=== Foo === ", "==<!-- -->= Foo === " ),
array( "=== Foo === ", "=== Foo ==<!-- -->= " ),
array( "=== Foo ===\n", "=== Foo ===<!-- -->\n" ),
array( "=== Foo === \n", "=== Foo ===<!-- --> <!-- -->\n" ),
array( "== Foo ==\n== Bar == \n", "== Foo ==\n== Bar == \n" ),
array( "===========", "===========" ),
array( "Foo\n=\n==\n=\n", "Foo\n=\n==\n=\n" ),
array( "{{Foo}}", "Foo" ),
array( "\n{{Foo}}", "\nFoo" ),
array( "{{Foo|bar}}", "Foobar" ),
array( "{{Foo|bar}}a", "Foobara" ),
array( "{{Foo|bar|baz}}", "Foobarbaz" ),
array( "{{Foo|1=bar}}", "Foo1=bar" ),
array( "{{Foo|=bar}}", "Foo=bar" ),
array( "{{Foo|bar=baz}}", "Foobar=baz" ),
array( "{{Foo|{{bar}}=baz}}", "Foobar=baz" ),
array( "{{Foo|1=bar|baz}}", "Foo1=barbaz" ),
array( "{{Foo|1=bar|2=baz}}", "Foo1=bar2=baz" ),
array( "{{Foo|bar|foo=baz}}", "Foobarfoo=baz" ),
array( "{{{1}}}", "1" ),
array( "{{{1|}}}", "1" ),
array( "{{{Foo}}}", "Foo" ),
array( "{{{Foo|}}}", "Foo" ),
array( "{{{Foo|bar|baz}}}", "Foobarbaz" ),
array( "{{Foo}}", "{<!-- -->{Foo}}" ),
array( "{{{{Foobar}}}}", "{Foobar}" ),
array( "{{{ {{Foo}} }}}", " Foo " ),
array( "{{ {{{Foo}}} }}", " Foo " ),
array( "{{{{{Foo}}}}}", "Foo" ),
array( "{{{{{Foo}} }}}", "Foo " ),
array( "{{{{{{Foo}}}}}}", "Foo" ),
array( "{{{{{{Foo}}}}}", "{Foo" ),
array( "[[[Foo]]", "[[[Foo]]" ),
array( "{{Foo|[[[[bar]]|baz]]}}", "Foo[[[[bar]]|baz]]" ), // This test is important, since it means the difference between having the [[ rule stacked or not
array( "{{Foo|[[[[bar]|baz]]}}", "{{Foo|[[[[bar]|baz]]}}" ),
array( "{{Foo|Foo [[[[bar]|baz]]}}", "{{Foo|Foo [[[[bar]|baz]]}}" ),
array( "Foo BarBaz", "Foo display mapBar</display map >Baz" ),
array( "Foo BarBaz", "Foo display map fooBar</display map >Baz" ),
array( "Foo ", "Foo gallery bar="baz" " ),
array( "Foo ", "Foo gallery bar="1" baz=2 " ),
array( "Foo/foo>", "/fooFoo<//foo>" ), # Worth blacklisting IMHO
array( "{{#ifexpr: ({{{1|1}}} = 2) | Foo | Bar }}", "#ifexpr: (11 = 2) Foo Bar " ),
array( "{{#if: {{{1|}}} | Foo | {{Bar}} }}", "#if: 1 Foo Bar " ),
array( "{{#if: {{{1|}}} | Foo | [[Bar]] }}", "#if: 1 Foo [[Bar]] " ),
array( "{{#if: {{{1|}}} | [[Foo]] | Bar }}", "#if: 1 [[Foo]] Bar " ),
array( "{{#if: {{{1|}}} | 1 | {{#if: {{{1|}}} | 2 | 3 }} }}", "#if: 1 1 #if: 1 2 3 " ),
array( "{{ {{Foo}}", "{{ Foo" ),
array( "{{Foobar {{Foo}} {{Bar}} {{Baz}} ", "{{Foobar Foo Bar Baz " ),
array( "[[Foo]] |", "[[Foo]] |" ),
array( "{{Foo|Bar|", "{{Foo|Bar|" ),
array( "[[Foo]", "[[Foo]" ),
array( "[[Foo|Bar]", "[[Foo|Bar]" ),
array( "{{Foo| [[Bar] }}", "{{Foo| [[Bar] }}" ),
array( "{{Foo| [[Bar|Baz] }}", "{{Foo| [[Bar|Baz] }}" ),
array( "{{Foo|bar=[[baz]}}", "{{Foo|bar=[[baz]}}" ),
array( "{{foo|", "{{foo|" ),
array( "{{foo|}", "{{foo|}" ),
array( "{{foo|} }}", "foo} " ),
array( "{{foo|bar=|}", "{{foo|bar=|}" ),
array( "{{Foo|} Bar=", "{{Foo|} Bar=" ),
array( "{{Foo|} Bar=}}", "Foo} Bar=" ),
/* array( file_get_contents( __DIR__ . '/QuoteQuran.txt' ), file_get_contents( __DIR__ . '/QuoteQuranExpanded.txt' ) ), */
);
}
/**
* Get XML preprocessor tree from the preprocessor (which may not be the
* native XML-based one).
*
* @param string $wikiText
* @return string
*/
protected function preprocessToXml( $wikiText ) {
if ( method_exists( $this->mPreprocessor, 'preprocessToXml' ) ) {
return $this->normalizeXml( $this->mPreprocessor->preprocessToXml( $wikiText ) );
}
$dom = $this->mPreprocessor->preprocessToObj( $wikiText );
if ( is_callable( array( $dom, 'saveXML' ) ) ) {
return $dom->saveXML();
} else {
return $this->normalizeXml( $dom->__toString() );
}
}
/**
* Normalize XML string to the form that a DOMDocument saves out.
*
* @param string $xml
* @return string
*/
protected function normalizeXml( $xml ) {
return preg_replace( '!<([a-z]+)/>!', '<$1>$1>', str_replace( ' />', '/>', $xml ) );
}
/**
* @dataProvider provideCases
* @covers Preprocessor_DOM::preprocessToXml
*/
public function testPreprocessorOutput( $wikiText, $expectedXml ) {
$this->assertEquals( $this->normalizeXml( $expectedXml ), $this->preprocessToXml( $wikiText ) );
}
/**
* These are more complex test cases taken out of wiki articles.
*/
public static function provideFiles() {
return array(
array( "QuoteQuran" ), # http://en.wikipedia.org/w/index.php?title=Template:QuoteQuran/sandbox&oldid=237348988 GFDL + CC-BY-SA by Striver
array( "Factorial" ), # http://en.wikipedia.org/w/index.php?title=Template:Factorial&oldid=98548758 GFDL + CC-BY-SA by Polonium
array( "All_system_messages" ), # http://tl.wiktionary.org/w/index.php?title=Suleras:All_system_messages&oldid=2765 GPL text generated by MediaWiki
array( "Fundraising" ), # http://tl.wiktionary.org/w/index.php?title=MediaWiki:Sitenotice&oldid=5716 GFDL + CC-BY-SA, copied there by Sky Harbor.
array( "NestedTemplates" ), # bug 27936
);
}
/**
* @dataProvider provideFiles
* @covers Preprocessor_DOM::preprocessToXml
*/
public function testPreprocessorOutputFiles( $filename ) {
$folder = __DIR__ . "/../../../parser/preprocess";
$wikiText = file_get_contents( "$folder/$filename.txt" );
$output = $this->preprocessToXml( $wikiText );
$expectedFilename = "$folder/$filename.expected";
if ( file_exists( $expectedFilename ) ) {
$expectedXml = $this->normalizeXml( file_get_contents( $expectedFilename ) );
$this->assertEquals( $expectedXml, $output );
} else {
$tempFilename = tempnam( $folder, "$filename." );
file_put_contents( $tempFilename, $output );
$this->markTestIncomplete( "File $expectedFilename missing. Output stored as $tempFilename" );
}
}
/**
* Tests from Bug 28642 ยท https://bugzilla.wikimedia.org/28642
*/
public static function provideHeadings() {
return array( /* These should become headings: */
array( "== h ==", "== h ==<!--c1-->" ),
array( "== h == ", "== h == <!--c1-->" ),
array( "== h == ", "== h ==<!--c1--> " ),
array( "== h == ", "== h == <!--c1--> " ),
array( "== h ==", "== h ==<!--c1--><!--c2-->" ),
array( "== h == ", "== h == <!--c1--><!--c2-->" ),
array( "== h == ", "== h ==<!--c1--><!--c2--> " ),
array( "== h == ", "== h == <!--c1--><!--c2--> " ),
array( "== h == ", "== h == <!--c1--> <!--c2-->" ),
array( "== h == ", "== h ==<!--c1--> <!--c2--> " ),
array( "== h == ", "== h == <!--c1--> <!--c2--> " ),
array( "== h ==", "== h ==<!--c1--><!--c2--><!--c3-->" ),
array( "== h == ", "== h ==<!--c1--> <!--c2--><!--c3-->" ),
array( "== h == ", "== h ==<!--c1--><!--c2--> <!--c3-->" ),
array( "== h == ", "== h ==<!--c1--> <!--c2--> <!--c3-->" ),
array( "== h == ", "== h == <!--c1--><!--c2--><!--c3-->" ),
array( "== h == ", "== h == <!--c1--> <!--c2--><!--c3-->" ),
array( "== h == ", "== h == <!--c1--><!--c2--> <!--c3-->" ),
array( "== h == ", "== h == <!--c1--> <!--c2--> <!--c3-->" ),
array( "== h == ", "== h ==<!--c1--><!--c2--><!--c3--> " ),
array( "== h == ", "== h ==<!--c1--> <!--c2--><!--c3--> " ),
array( "== h == ", "== h ==<!--c1--><!--c2--> <!--c3--> " ),
array( "== h == ", "== h ==<!--c1--> <!--c2--> <!--c3--> " ),
array( "== h == ", "== h == <!--c1--><!--c2--><!--c3--> " ),
array( "== h == ", "== h == <!--c1--> <!--c2--><!--c3--> " ),
array( "== h == ", "== h == <!--c1--><!--c2--> <!--c3--> " ),
array( "== h == ", "== h == <!--c1--> <!--c2--> <!--c3--> " ),
array( "== h == ", "== h ==<!--c1--> <!--c2-->" ),
array( "== h == ", "== h == <!--c1--> <!--c2-->" ),
array( "== h == ", "== h ==<!--c1--> <!--c2--> " ),
/* These are not working: */
array( "== h == x ", "== h == x <!--c1--><!--c2--><!--c3--> " ),
array( "== h == x ", "== h ==<!--c1--> x <!--c2--><!--c3--> " ),
array( "== h == x ", "== h ==<!--c1--><!--c2--><!--c3--> x " ),
);
}
/**
* @dataProvider provideHeadings
* @covers Preprocessor_DOM::preprocessToXml
*/
public function testHeadings( $wikiText, $expectedXml ) {
$this->assertEquals( $this->normalizeXml( $expectedXml ), $this->preprocessToXml( $wikiText ) );
}
}