diff options
514 files changed, 88029 insertions, 2855 deletions
diff --git a/.gitreview b/.gitreview new file mode 100644 index 00000000..65dbc270 --- /dev/null +++ b/.gitreview @@ -0,0 +1,6 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/core.git +defaultbranch=REL1_21 +defaultrebase=0 diff --git a/.jshintignore b/.jshintignore new file mode 100644 index 00000000..3869deb9 --- /dev/null +++ b/.jshintignore @@ -0,0 +1,27 @@ +# third-party libs +extensions/ +node_modules/ +resources/jquery/jquery.appear.js +resources/jquery/jquery.async.js +resources/jquery/jquery.cycle.all.js +resources/jquery/jquery.cookie.js +resources/jquery/jquery.farbtastic.js +resources/jquery/jquery.form.js +resources/jquery/jquery.hoverIntent.js +resources/jquery/jquery.js +resources/jquery/jquery.json.js +resources/jquery/jquery.jStorage.js +resources/jquery/jquery.mockjax.js +resources/jquery/jquery.qunit.js +resources/jquery/jquery.validate.js +resources/jquery/jquery.xmldom.js +resources/jquery.effects/ +resources/jquery.tipsy/ +resources/jquery.ui/ +resources/mediawiki.libs/ + +# legacy scripts +skins/common/ + +# github.com/jshint/jshint/issues/729 +tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 00000000..7fa138d4 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,34 @@ +{ + "predef": [ + "mediaWiki", + "jQuery", + "QUnit" + ], + + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "forin": false, + "immed": true, + "latedef": true, + "newcap": true, + "noarg": true, + "noempty": true, + "nonew": true, + "quotmark": "single", + "regexp": false, + "undef": true, + "unused": true, + "strict": false, + "trailing": true, + + "laxbreak": true, + "smarttabs": true, + "multistr": true, + + "browser": true, + + "nomen": true, + "onevar": true +} diff --git a/RELEASE-NOTES-1.21 b/RELEASE-NOTES-1.21 index ef4f08c6..4e08480f 100644 --- a/RELEASE-NOTES-1.21 +++ b/RELEASE-NOTES-1.21 @@ -3,11 +3,25 @@ Security reminder: MediaWiki does not require PHP's register_globals. If you have it on, turn it '''off''' if you can. +== MediaWiki 1.21.2 == + +This is a security adn maintenance release of the MediaWiki 1.21 branch. + +=== Changes since 1.21.1 === + +* SECURITY: Fix extension detection with 2 .'s +* SECURITY: Support for the 'gettoken' parameter to action=block and action=unblock, + deprecated since 1.20, has been removed. +* SECURITY: Sanitize ResourceLoader exception messages +* Purge upstream caches when deleting file assets. +* Unit test suite now runs the AutoLoader tests. Also fixed the autoloading + entry for the PageORMTableForTesting class though it had no impact. + == MediaWiki 1.21.1 == This is a maintenance release of the 1.21 branch. -MediaWiki 1.21 is an stable branch and is recommended for use in production. +MediaWiki 1.21 is a stable branch, and is recommended for use in production. === Changes since 1.21.0 === diff --git a/extensions/Cite/.gitreview b/extensions/Cite/.gitreview new file mode 100644 index 00000000..6ae9db41 --- /dev/null +++ b/extensions/Cite/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/Cite.git +defaultbranch=master diff --git a/extensions/ConfirmEdit/.gitreview b/extensions/ConfirmEdit/.gitreview new file mode 100644 index 00000000..780d35df --- /dev/null +++ b/extensions/ConfirmEdit/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/ConfirmEdit.git +defaultbranch=master diff --git a/extensions/ConfirmEdit/ReCaptcha.i18n.php b/extensions/ConfirmEdit/ReCaptcha.i18n.php index a7fffb59..e8722f93 100644 --- a/extensions/ConfirmEdit/ReCaptcha.i18n.php +++ b/extensions/ConfirmEdit/ReCaptcha.i18n.php @@ -400,13 +400,12 @@ $messages['nl-informal'] = array( ); /** Polish (polski) - * @author WTM */ $messages['pl'] = array( 'recaptcha-edit' => 'Aby uchronić nas przed robotami, proszę wpisać dwa widoczne słowa w poniższym polu:', 'recaptcha-addurl' => 'Twoja edycja zawiera linki zewnętrzne. Aby uchronić nas przed robotami, proszę wpisać dwa widoczne słowa w poniższym polu:', 'recaptcha-badpass' => 'Aby uchronić nas przed złamaniem automatycznym haseł, proszę wpisać dwa widoczne słowa w poniższym polu:', - 'recaptcha-createaccount' => 'Aby uchronić nas przed automatycznym tworzeniem użytkowników, proszę wpisać dwa widoczne słowa w poniższym polu:', + 'recaptcha-createaccount' => 'Aby uchronić nas przed automatycznym stworzeniem użytkowników, proszę wpisać dwa widoczne słowa w poniższym polu:', 'recaptcha-createaccount-fail' => 'Odpowiedź na reCAPTCHA jest fałszywa lub brakująca.', 'recaptcha-create' => 'Aby uchronić nas przed tworzeniem stron przez robotów, proszę wpisać dwa widoczne słowa w poniższym polu:', ); diff --git a/extensions/Gadgets/.gitreview b/extensions/Gadgets/.gitreview new file mode 100644 index 00000000..a1a8ead4 --- /dev/null +++ b/extensions/Gadgets/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/Gadgets.git +defaultbranch=master diff --git a/extensions/Gadgets/tests/GadgetTest.php b/extensions/Gadgets/tests/GadgetTest.php new file mode 100644 index 00000000..c9332a6c --- /dev/null +++ b/extensions/Gadgets/tests/GadgetTest.php @@ -0,0 +1,81 @@ +<?php +/** + * @group Gadgets + */ + +class GadgetsTest extends MediaWikiTestCase { + private function create( $line ) { + $g = Gadget::newFromDefinition( $line ); + // assertInstanceOf() is available since PHPUnit 3.5 + $this->assertEquals( 'Gadget', get_class( $g ) ); + + return $g; + } + + function testInvalidLines() { + $this->assertFalse( Gadget::newFromDefinition( '' ) ); + $this->assertFalse( Gadget::newFromDefinition( '<foo|bar>' ) ); + } + + function testSimpleCases() { + $g = $this->create( '* foo bar| foo.css|foo.js|foo.bar' ); + $this->assertEquals( 'foo_bar', $g->getName() ); + $this->assertEquals( 'ext.gadget.foo_bar', $g->getModuleName() ); + $this->assertEquals( array( 'Gadget-foo.js' ), $g->getScripts() ); + $this->assertEquals( array( 'Gadget-foo.css' ), $g->getStyles() ); + $this->assertEquals( array( 'Gadget-foo.js', 'Gadget-foo.css' ), + $g->getScriptsAndStyles() ); + $this->assertEquals( array( 'Gadget-foo.js' ), $g->getLegacyScripts() ); + $this->assertFalse( $g->supportsResourceLoader() ); + $this->assertTrue( $g->hasModule() ); + } + + function testRLtag() { + $g = $this->create( '*foo [ResourceLoader]|foo.js|foo.css' ); + $this->assertEquals( 'foo', $g->getName() ); + $this->assertTrue( $g->supportsResourceLoader() ); + $this->assertEquals( 0, count( $g->getLegacyScripts() ) ); + } + + function testDependencies() { + $g = $this->create( '* foo[ResourceLoader|dependencies=jquery.ui]|bar.js' ); + $this->assertEquals( array( 'Gadget-bar.js' ), $g->getScripts() ); + $this->assertTrue( $g->supportsResourceLoader() ); + $this->assertEquals( array( 'jquery.ui' ), $g->getDependencies() ); + } + + function testPreferences() { + global $wgUser, $wgOut, $wgTitle; + + // This test makes call to the parser which requires valids Outputpage + // and Title objects. Set them up there, they will be released at the + // end of the test. + $old_wgOut = $wgOut; + $old_wgTitle = $wgTitle; + $wgTitle = Title::newFromText( 'Parser test for Gadgets extension' ); + + // Proceed with test setup: + $prefs = array(); + $context = new RequestContext(); + $wgOut = $context->getOutput(); + $wgOut->setTitle( Title::newFromText( 'test' ) ); + + Gadget::loadStructuredList( '* foo | foo.js +==keep-section1== +* bar| bar.js +==remove-section== +* baz [rights=embezzle] |baz.js +==keep-section2== +* quux [rights=read] | quux.js' ); + $this->assertTrue( GadgetHooks::getPreferences( $wgUser, $prefs ), 'GetPrefences hook should return true' ); + + $options = $prefs['gadgets']['options']; + $this->assertFalse( isset( $options['<gadget-section-remove-section>'] ), 'Must not show empty sections' ); + $this->assertTrue( isset( $options['<gadget-section-keep-section1>'] ) ); + $this->assertTrue( isset( $options['<gadget-section-keep-section2>'] ) ); + + // Restore globals + $wgOut = $old_wgOut; + $wgTitle = $old_wgTitle; + } +} diff --git a/extensions/ImageMap/.gitreview b/extensions/ImageMap/.gitreview new file mode 100644 index 00000000..2629c9d9 --- /dev/null +++ b/extensions/ImageMap/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/ImageMap.git +defaultbranch=master diff --git a/extensions/InputBox/.gitreview b/extensions/InputBox/.gitreview new file mode 100644 index 00000000..9d0c704d --- /dev/null +++ b/extensions/InputBox/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/InputBox.git +defaultbranch=master diff --git a/extensions/Interwiki/.gitreview b/extensions/Interwiki/.gitreview new file mode 100644 index 00000000..fcc03f61 --- /dev/null +++ b/extensions/Interwiki/.gitreview @@ -0,0 +1,6 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/Interwiki.git +defaultbranch=master +defaultrebase=0
\ No newline at end of file diff --git a/extensions/LocalisationUpdate/.gitreview b/extensions/LocalisationUpdate/.gitreview new file mode 100644 index 00000000..da37d04d --- /dev/null +++ b/extensions/LocalisationUpdate/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/LocalisationUpdate.git +defaultbranch=master diff --git a/extensions/LocalisationUpdate/tests/tokenTest.php b/extensions/LocalisationUpdate/tests/tokenTest.php new file mode 100644 index 00000000..1112313c --- /dev/null +++ b/extensions/LocalisationUpdate/tests/tokenTest.php @@ -0,0 +1,91 @@ +<?php + +$IP = strval( getenv( 'MW_INSTALL_PATH' ) ) !== '' + ? getenv( 'MW_INSTALL_PATH' ) + : realpath( dirname( __FILE__ ) . "/../../../" ); + +require_once( "$IP/maintenance/commandLine.inc" ); + +function evalExtractArray( $php, $varname ) { + eval( $php ); + return @$$varname; +} + +function confExtractArray( $php, $varname ) { + try { + $ce = new ConfEditor("<?php $php"); + $vars = $ce->getVars(); + $retval = @$vars[$varname]; + } catch( Exception $e ) { + print $e . "\n"; + $retval = null; + } + return $retval; +} + +function quickTokenExtractArray( $php, $varname ) { + $reader = new QuickArrayReader("<?php $php"); + return $reader->getVar( $varname ); +} + + +if( count( $args ) ) { + $sources = $args; +} else { + $sources = + array_merge( + glob("$IP/extensions/*/*.i18n.php"), + glob("$IP/languages/messages/Messages*.php") ); +} + +foreach( $sources as $sourceFile ) { + $rel = basename( $sourceFile ); + $out = str_replace( '/', '-', $rel ); + + $sourceData = file_get_contents( $sourceFile ); + + if( preg_match( '!extensions/!', $sourceFile ) ) { + $sourceData = LocalisationUpdate::cleanupExtensionFile( $sourceData ); + $items = 'langs'; + } else { + $sourceData = LocalisationUpdate::cleanupFile( $sourceData ); + $items = 'messages'; + } + + file_put_contents( "$out.txt", $sourceData ); + + $start = microtime(true); + $eval = evalExtractArray( $sourceData, 'messages' ); + $deltaEval = microtime(true) - $start; + + $start = microtime(true); + $quick = quickTokenExtractArray( $sourceData, 'messages' ); + $deltaQuick = microtime(true) - $start; + + $start = microtime(true); + $token = confExtractArray( $sourceData, 'messages' ); + $deltaToken = microtime(true) - $start; + + $hashEval = md5(serialize($eval)); + $hashToken = md5(serialize($token)); + $hashQuick = md5(serialize($quick)); + $countEval = count( (array)$eval); + $countToken = count( (array)$token ); + $countQuick = count( (array)$quick ); + + printf( "%s %s %d $items - %0.1fms - eval\n", $rel, $hashEval, $countEval, $deltaEval * 1000 ); + printf( "%s %s %d $items - %0.1fms - QuickArrayReader\n", $rel, $hashQuick, $countQuick, $deltaQuick * 1000 ); + printf( "%s %s %d $items - %0.1fms - ConfEditor\n", $rel, $hashToken, $countToken, $deltaToken * 1000 ); + + if( $hashEval !== $hashToken || $hashEval !== $hashQuick ) { + echo "FAILED on $rel\n"; + file_put_contents( "$out-eval.txt", var_export( $eval, true ) ); + file_put_contents( "$out-token.txt", var_export( $token, true ) ); + file_put_contents( "$out-quick.txt", var_export( $quick, true ) ); + #die("check eval.txt and token.txt\n"); + } + echo "\n"; +} + +echo "ok\n"; + diff --git a/extensions/Nuke/.gitreview b/extensions/Nuke/.gitreview new file mode 100644 index 00000000..c623aede --- /dev/null +++ b/extensions/Nuke/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/Nuke.git +defaultbranch=master diff --git a/extensions/ParserFunctions/.gitreview b/extensions/ParserFunctions/.gitreview new file mode 100644 index 00000000..decb9867 --- /dev/null +++ b/extensions/ParserFunctions/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/ParserFunctions.git +defaultbranch=master diff --git a/extensions/ParserFunctions/ParserFunctions.i18n.magic.php b/extensions/ParserFunctions/ParserFunctions.i18n.magic.php index 1a37cf9e..4fdb83eb 100644 --- a/extensions/ParserFunctions/ParserFunctions.i18n.magic.php +++ b/extensions/ParserFunctions/ParserFunctions.i18n.magic.php @@ -96,8 +96,8 @@ $magicWords['br'] = array( /** Chechen (нохчийн) */ $magicWords['ce'] = array( - 'time' => array( 0, 'хан' ), - 'replace' => array( 0, 'хийцарна', 'замена' ), + 'time' => array( 0, 'хан', 'time' ), + 'replace' => array( 0, 'хийцарна', 'замена', 'replace' ), ); /** Czech (česky) */ diff --git a/extensions/ParserFunctions/tests/ExpressionTest.php b/extensions/ParserFunctions/tests/ExpressionTest.php new file mode 100644 index 00000000..169a9cb4 --- /dev/null +++ b/extensions/ParserFunctions/tests/ExpressionTest.php @@ -0,0 +1,76 @@ +<?php +class ExpressionTest extends MediaWikiTestCase { + + /** + * @var ExprParser + */ + protected $parser; + + protected function setUp() { + parent::setUp(); + $this->parser = new ExprParser(); + } + + /** + * @dataProvider provideExpressions + */ + function testExpression( $input, $expected ) { + $this->assertEquals( + $expected, + $this->parser->doExpression( $input ) + ); + } + + function provideExpressions() { + return array( + array( '1 or 0', '1' ), + array( 'not (1 and 0)', '1' ), + array( 'not 0', '1' ), + array( '4 < 5', '1' ), + array( '-5 < 2', '1' ), + array( '-2 <= -2', '1' ), + array( '4 > 3', '1' ), + array( '4 > -3', '1' ), + array( '5 >= 2', '1' ), + array( '2 >= 2', '1' ), + array( '1 != 2', '1' ), + array( '-4 * -4 = 4 * 4', '1' ), + array( 'not (1 != 1)', '1' ), + array( '1 + 1', '2' ), + array( '-1 + 1', '0' ), + array( '+1 + 1', '2' ), + array( '4 * 4', '16' ), + array( '(1/3) * 3', '1' ), + array( '3 / 1.5', '2' ), + array( '3 / 0.2', '15' ), + array( '3 / ( 2.0 * 0.1 )', '15' ), + array( '3 / ( 2.0 / 10 )', '15' ), + array( '3 / (- 0.2 )', '-15' ), + array( '3 / abs( 0.2 )', '15' ), + array( '3 mod 2', '1' ), + array( '1e4', '10000' ), + array( '1e-2', '0.01' ), + array( '4.0 round 0', '4' ), + array( 'ceil 4', '4' ), + array( 'floor 4', '4' ), + array( '4.5 round 0', '5' ), + array( '4.2 round 0', '4' ), + array( '-4.2 round 0', '-4' ), + array( '-4.5 round 0', '-5' ), + array( '-2.0 round 0', '-2' ), + array( 'ceil -3', '-3' ), + array( 'floor -6.0', '-6' ), + array( 'ceil 4.2', '5' ), + array( 'ceil -4.5', '-4' ), + array( 'floor -4.5', '-5' ), + array( 'abs(-2)', '2' ), + array( 'ln(exp(1))', '1' ), + array( 'trunc(4.5)', '4' ), + array( 'trunc(-4.5)', '-4' ), + array( '123 fmod (2^64-1)', '123' ), + array( '5.7 mod 1.3', '0' ), + array( '5.7 fmod 1.3', '0.5' ), + ); + } +} + diff --git a/extensions/PdfHandler/.gitreview b/extensions/PdfHandler/.gitreview new file mode 100644 index 00000000..f5eca40e --- /dev/null +++ b/extensions/PdfHandler/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/PdfHandler.git +defaultbranch=master diff --git a/extensions/PdfHandler/PdfHandler_body.php b/extensions/PdfHandler/PdfHandler_body.php index 8fa6719b..73ce1b58 100644 --- a/extensions/PdfHandler/PdfHandler_body.php +++ b/extensions/PdfHandler/PdfHandler_body.php @@ -315,7 +315,7 @@ class PdfHandler extends ImageHandler { */ function pageCount( $image ) { $data = $this->getMetaArray( $image ); - if ( !$data || !isset( $data['Pages'] ) ) { + if ( !$data ) { return false; } return intval( $data['Pages'] ); diff --git a/extensions/Poem/.gitreview b/extensions/Poem/.gitreview new file mode 100644 index 00000000..aac78b2b --- /dev/null +++ b/extensions/Poem/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/Poem.git +defaultbranch=master diff --git a/extensions/Renameuser/.gitreview b/extensions/Renameuser/.gitreview new file mode 100644 index 00000000..0d757141 --- /dev/null +++ b/extensions/Renameuser/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/Renameuser.git +defaultbranch=master diff --git a/extensions/SpamBlacklist/.gitreview b/extensions/SpamBlacklist/.gitreview new file mode 100644 index 00000000..d74ae8f9 --- /dev/null +++ b/extensions/SpamBlacklist/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/SpamBlacklist.git +defaultbranch=master diff --git a/extensions/SyntaxHighlight_GeSHi/.gitreview b/extensions/SyntaxHighlight_GeSHi/.gitreview new file mode 100644 index 00000000..cb9e4b44 --- /dev/null +++ b/extensions/SyntaxHighlight_GeSHi/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/SyntaxHighlight_GeSHi.git +defaultbranch=master diff --git a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/aliased.php b/extensions/SyntaxHighlight_GeSHi/geshi/contrib/aliased.php deleted file mode 100644 index cee31289..00000000 --- a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/aliased.php +++ /dev/null @@ -1,123 +0,0 @@ -<?php - -/** - * Another GeSHi example script - * - * Configure your Apache server with 'AcceptPathInfo true' and something like - * 'Alias /viewmysource /var/www/geshi/contrib/aliased.php'. Don't forget - * to protect this alias as necessary. - * - * Usage - visit /viewmysource/file.name.ext to see that file with syntax - * highlighting, where "viewmysource" is the name of the alias you set up. - * You can use this without an alias too, just by visiting - * aliased.php/file.name.ext. - * - * @author Ross Golder <ross@golder.org> - * @version $Id: aliased.php 2533 2012-08-15 18:49:04Z benbe $ - */ - -// Your config here -define("SOURCE_ROOT", "/var/www/your/source/root/"); - -// Assume you've put geshi in the include_path already -require_once("geshi.php"); - -// Get path info -$path = SOURCE_ROOT.$_SERVER['PATH_INFO']; - -// Check for dickheads trying to use '../' to get to sensitive areas -$base_path_len = strlen(SOURCE_ROOT); -$real_path = realpath($path); -if(strncmp($real_path, SOURCE_ROOT, $base_path_len)) { - exit("Access outside acceptable path."); -} - -// Check file exists -if(!file_exists($path)) { - exit("File not found ($path)."); -} - -// Prepare GeSHi instance -$geshi = new GeSHi(); -$geshi->set_language('text'); -$geshi->load_from_file($path); -$geshi->set_header_type(GESHI_HEADER_PRE); -$geshi->enable_classes(); -$geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS, 10); -$geshi->set_overall_style('color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;', true); -$geshi->set_line_style('font: normal normal 95% \'Courier New\', Courier, monospace; color: #003030;', 'font-weight: bold; color: #006060;', true); -$geshi->set_code_style('color: #000020;', 'color: #000020;'); -$geshi->set_link_styles(GESHI_LINK, 'color: #000060;'); -$geshi->set_link_styles(GESHI_HOVER, 'background-color: #f0f000;'); -$geshi->set_header_content('Source code viewer - ' . $path . ' - ' . $geshi->get_language_name()); -$geshi->set_header_content_style('font-family: Verdana, Arial, sans-serif; color: #808080; font-size: 70%; font-weight: bold; background-color: #f0f0ff; border-bottom: 1px solid #d0d0d0; padding: 2px;'); -$geshi->set_footer_content('Parsed in <TIME> seconds, using GeSHi <VERSION>'); -$geshi->set_footer_content_style('font-family: Verdana, Arial, sans-serif; color: #808080; font-size: 70%; font-weight: bold; background-color: #f0f0ff; border-top: 1px solid #d0d0d0; padding: 2px;'); - -?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head> - <title>Source code viewer - <?php echo $path; ?> - <?php $geshi->get_language_name(); ?></title> - <style type="text/css"> - <!-- - <?php - // Output the stylesheet. Note it doesn't output the <style> tag - echo $geshi->get_stylesheet(); - ?> - html { - background-color: #f0f0f0; - } - body { - font-family: Verdana, Arial, sans-serif; - margin: 10px; - border: 2px solid #e0e0e0; - background-color: #fcfcfc; - padding: 5px; - } - h2 { - margin: .1em 0 .2em .5em; - border-bottom: 1px solid #b0b0b0; - color: #b0b0b0; - font-weight: normal; - font-size: 150%; - } - h3 { - margin: .1em 0 .2em .5em; - color: #b0b0b0; - font-weight: normal; - font-size: 120%; - } - #footer { - text-align: center; - font-size: 80%; - color: #a9a9a9; - } - #footer a { - color: #9999ff; - } - textarea { - border: 1px solid #b0b0b0; - font-size: 90%; - color: #333; - margin-left: 20px; - } - select, input { - margin-left: 20px; - } - p { - font-size: 90%; - margin-left: .5em; - } - --> - </style> -</head> -<body> -<?php -// The fun part :) -echo $geshi->parse_code(); -?> -<hr/> -</body> -</html> diff --git a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/cssgen.php b/extensions/SyntaxHighlight_GeSHi/geshi/contrib/cssgen.php deleted file mode 100644 index cc71b58f..00000000 --- a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/cssgen.php +++ /dev/null @@ -1,466 +0,0 @@ -<?php -/************************************************************************************* - * cssgen.php - * ---------- - * Author: Nigel McNie (nigel@geshi.org) - * Copyright: (c) 2004 Nigel McNie - * Release Version: 1.0.8.6 - * Date Started: 2004/05/20 - * - * Application to generate custom CSS files for GeSHi (based on an idea by Andreas - * Gohr) - * - ************************************************************************************* - * - * This file is part of GeSHi. - * - * GeSHi is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GeSHi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GeSHi; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ************************************************************************************/ - -set_magic_quotes_runtime(0); -// -// Functions -// - -function make_header ( $title ) -{ - echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head> - <title>GeSHi CSS Generator :: ' . $title . ' </title> - <style type="text/css" media="screen"> - <!-- - html { - font-family: Verdana, Arial, sans-serif; - font-size: 80%; - background-color: #d0d0d0; - } - body { - margin: 10px; - padding: 5px; - border: 1px solid #f0f0f0; - background-color: #f6f6f6; - } - h1 { - border-bottom: 2px solid #e0e0e0; - font-weight: normal; - font-size: 150%; - color: #c0c0c0; - } - input, textarea { - border: 1px solid #d0d0d0; - } - th { - text-align: right; - font-weight: normal; - } - pre { - font-size: 110%; - color: #202020; - } - #footer { - color: #b0b0b0; - text-align: center; - font-size: 90%; - margin: 0 auto; - border-top: 1px solid #e0e0e0; - } - #footer a { - color: #c0c0c0; - } - --> - </style> - <script type="text/javascript"> - function select (state) - { - var cboxes = document.getElementsByTagName(\'input\'); - for (var i = 0; i < cboxes.length; i++) { - if (cboxes[i].type == "checkbox") { - if (state == "true") { - cboxes[i].checked = true; - } elseif (state == "false") { - cboxes[i].checked = false; - } elseif (state == "invert") { - cboxes[i].checked = !cboxes[i].checked; - } - } - } - } - </script> -</head> -<body> -<h1>' . $title . '</h1> -'; -} - -function make_footer () -{ - echo '<div id="footer"><a href="http://qbnz.com/highlighter/">GeSHi</a> © Nigel McNie, 2004, released under the GPL</div></body> -</html>'; -} - - -function get_var ( $var_name ) -{ - if ( isset($_GET[$var_name]) ) - { - return str_replace("\'", "'", $_GET[$var_name]); - } - elseif ( isset($_POST[$var_name]) ) - { - return str_replace("\'", "'", $_POST[$var_name]); - } - return null; -} - - - -// -// Unset everything -// -foreach ( $_REQUEST as $var ) -{ - unset($$var); -} -foreach ( array( - '_POST' => 'HTTP_POST_VARS', - '_GET' => 'HTTP_GET_VARS', - '_COOKIE' => 'HTTP_COOKIE_VARS', - '_SERVER' => 'HTTP_SERVER_VARS', - '_ENV' => 'HTTP_ENV_VARS', - '_FILES' => 'HTTP_POST_FILES') as $array => $other ) -{ - if ( !isset($$array) ) - { - $$array = $$other; - } - unset($$other); -} - - -// Get what step we're up to -$step = get_var('step'); - -if ( !$step || $step == 1 ) -{ - $errors = 0; - make_header('Step 1'); - echo "Welcome to the GeSHi CSS generator.<br /><pre>Searching for GeSHi... "; - - // Find GeSHi - $geshi_path = get_var('geshi-path'); - $geshi_lang_path = get_var('geshi-lang-path'); - - if(strstr($geshi_path, '..')) { - unset($geshi_path); - } - if(strstr($geshi_lang_path, '..')) { - unset($geshi_lang_path); - } - - if ( !$geshi_path ) - { - $geshi_path = '../geshi.php'; - } - if ( !$geshi_lang_path ) - { - $geshi_lang_path = '../geshi/'; - } - - if ( is_file($geshi_path) && is_readable($geshi_path) ) - { - // Get file contents and see if GeSHi is in here - $file = @file($geshi_path); - $contents = ''; - foreach ( $file as $line ) - { - $contents .= $line; - } - if ( strpos($contents, '<?php -/** - * GeSHi - Generic Syntax Highlighter') !== false ) - { - echo '<span style="color: green;">Found at ' . realpath($geshi_path) . '</span>'; - } - else - { - ++$errors; - $no_geshi_dot_php_error = true; - echo '<span style="color: red;">Not found</span>'; - } - } - else - { - ++$errors; - $no_geshi_dot_php_error = true; - echo '<span style="color: red;">Not found</span>'; - } - - // Find language files - echo "\nSearching for language files... "; - if ( is_readable($geshi_lang_path . 'css-gen.cfg') ) - { - - echo '<span style="color: green;">Found at ' . realpath($geshi_lang_path) . '</span>'; - } - else - { - ++$errors; - $no_lang_dir_error = true; - echo '<span style="color: red;">Not found</span>'; - } - echo "</pre>\n"; - - if ( $errors > 0 ) - { - // We're gonna have to ask for the paths... - echo 'Unfortunately CSSGen could not detect the following paths. Please input them and press "submit" to try again.'; - echo " -<form action=\"cssgen.php\" method=\"post\">"; - if ( $no_geshi_dot_php_error ) - { - echo " -<br />geshi.php: <input type=\"text\" name=\"geshi-path\" value=\"" . realpath('../geshi.php') . "\" size=\"50\" />"; - } - else - { - echo '<input type="hidden" name="geshi-path" value="' . htmlspecialchars($geshi_path) . '" />'; - } - if ( $no_lang_dir_error ) - { - echo " -<br />language files directory: <input type=\"text\" name=\"geshi-lang-path\" value=\"" . realpath('../geshi/') . "/\" size=\"50\" /> (should have a trailing slash)"; - } - else - { - echo '<input type="hidden" name="geshi-lang-path" value="' . $geshi_lang_path . '" />'; - } - - echo " -<br /><input type=\"submit\" value=\"Search\" /></form>"; - } - else - { - // no errors - echo continue form - echo 'Everything seems to be detected successfully. Use the button to continue. -<br /><br /><form action="cssgen.php?step=2" method="post"> -<input type="hidden" name="geshi-path" value="' . realpath($geshi_path) . '" /><input type="hidden" name="geshi-lang-path" value="' . realpath($geshi_lang_path) . '" /> -<input type="submit" value="Step 2" />'; - } - - make_footer(); -} -// Step 2 -elseif ( $step == 2 ) -{ - make_header('Step 2'); - - $geshi_path = get_var('geshi-path'); - $geshi_lang_path = get_var('geshi-lang-path'); - - $dh = opendir($geshi_lang_path); - $lang_files = array(); - $file = readdir($dh); - while ( $file !== false ) - { - if ( $file == '.' || $file == '..' || $file == 'CVS' || $file == 'css-gen.cfg' ) - { - $file = readdir($dh); - continue; - } - if(!strstr(file_get_contents($dh . DIRECTORY_SEPARATOR . $file), '$language_data')) { - $file = readdir($dh); - continue; - } - $lang_files[] = $file; - $file = readdir($dh); - } - closedir($dh); - sort($lang_files); - - // Now installed languages are in $lang_files - - echo '<form action="cssgen.php?step=3" method="post" id="step2"> -What languages are you wanting to make this stylesheet for?<br /><br /> -Detected languages:<br />'; - - foreach ( $lang_files as $lang ) - { - $lang = substr($lang, 0, strpos($lang, '.')); - if ($lang) { - echo "<input type=\"checkbox\" name=\"langs[$lang]\" checked=\"checked\" /> $lang<br />\n"; - } - } - - echo "Select: <a href=\"javascript:select('true')\">All</a>, <a href=\"javascript:select('false')\">None</a>, <a href=\"javascript:select('invert')\">Invert</a><br />\n"; - - echo 'If you\'d like any other languages not detected here to be supported, please enter -them here, one per line:<br /><textarea rows="4" cols="20" name="extra-langs"></textarea><br /> -'; - - echo '<br />Styles: -<table> - <tr><th>Style for the overall code block:</th><td><input type="text" name="overall" value="border: 1px dotted #a0a0a0; font-family: \'Courier New\', Courier, monospace; background-color: #f0f0f0; color: #0000bb;" /></td></tr> - <tr><th>Default Styles</th><td><input type="text" name="default-styles" value="font-weight:normal;background:transparent;color:#000; padding-left: 5px;" /></td></tr> - <tr><th>Keywords I (if, do, while etc)</th><td><input type="text" name="keywords-1" value="color: #a1a100;" /></td></tr> - <tr><th>Keywords II (null, true, false etc)</th><td><input type="text" name="keywords-2" value="color: #000; font-weight: bold;" /></td></tr> - <tr><th>Inbuilt Functions (echo, print etc)</th><td><input type="text" name="keywords-3" value="color: #000066;" /></td></tr> - <tr><th>Data Types (int, boolean etc)</th><td><input type="text" name="keywords-4" value="color: #f63333;" /></td></tr> - - <tr><th>Comments (//, <!-- --> etc)</th><td><input type="text" name="comments" value="color: #808080;" /></td></tr> - <tr><th>Escaped Characters (\n, \t etc)</th><td><input type="text" name="escaped-chars" value="color: #000033; font-weight: bold;" /></td></tr> - <tr><th>Brackets ( ([{}]) etc)</th><td><input type="text" name="brackets" value="color: #66cc66;" /></td></tr> - <tr><th>Strings ("foo" etc)</th><td><input type="text" name="strings" value="color: #ff0000;" /></td></tr> - <tr><th>Numbers (1, -54, 2.5 etc)</th><td><input type="text" name="numbers" value="color: #ff33ff;" /></td></tr> - <tr><th>Methods (Foo.bar() etc)</th><td><input type="text" name="methods" value="color: #006600;" /></td></tr> -</table>'; - - echo '<input type="hidden" name="geshi-path" value="' . realpath($geshi_path) . '" /><input type="hidden" name="geshi-lang-path" value="' . realpath($geshi_lang_path) . '" /> -<input type="submit" value="Step 3" /></form>'; - - make_footer(); -} -// Step 3 -elseif ( $step == 3 ) -{ - make_header('Step 3'); - echo '<p>Here is your completed stylesheet. Note that it may not be perfect - no regular expression styles are included for one thing, -you\'ll have to add those yourself (php and xml are just two languages that use them), and line numbers are not included, however -it includes most of the basic information.</p>'; - - // Make the stylesheet - $part_selector_1 = ''; - $part_selector_2 = ''; - $part_selector_3 = ''; - - $langs = get_var('langs'); - $extra_langs = trim(get_var('extra-langs')); - if ( $extra_langs != '' ) - { - $l = explode("\r\n", $extra_langs); - foreach ( $l as $lng ) - { - $langs[$lng] = true; - } - } - - - foreach ( $langs as $lang => $dummy ) - { - $part_selector_1 .= ".$lang {PART}, "; - $part_selector_2 .= ".$lang {PART1}, .$lang {PART2}, "; - $part_selector_3 .= ".$lang {PART1}, .$lang {PART2}, .$lang {PART3}, "; - } - $part_selector_1 = substr($part_selector_1, 0, -2); - $part_selector_2 = substr($part_selector_2, 0, -2); - $part_selector_3 = substr($part_selector_3, 0, -2); - - - $default_styles = get_var('default-styles'); - $ol_selector = str_replace('{PART}', 'ol', $part_selector_1); - $overall_styles = get_var('overall'); - $overall_selector = str_replace('{PART}', '', $part_selector_1); - - $stylesheet = "/* GeSHi (c) Nigel McNie 2004 (http://qbnz.com/highlighter) */"; - - if ( $overall != '' ) - { - $stylesheet .= "\n$overall_selector {{$overall_styles}}"; - } - if ( $default_styles != '' ) - { - $default_selector = str_replace(array('{PART1}', '{PART2}'), array('.de1', '.de2'), $part_selector_2); - $stylesheet .= "\n$default_selector {{$default_styles}}"; - } - - // Do keywords - $keywords_1 = get_var('keywords-1'); - $keyword_selector_1 = str_replace('{PART}', '.kw1', $part_selector_1); - if ( $keywords_1 != '' ) - { - $stylesheet .= "\n$keyword_selector_1 {{$keywords_1}}"; - } - - $keywords_2 = get_var('keywords-2'); - $keyword_selector_2 = str_replace('{PART}', '.kw2', $part_selector_1); - if ( $keywords_2 != '' ) - { - $stylesheet .= "\n$keyword_selector_2 {{$keywords_2}}"; - } - - $keywords_3 = get_var('keywords-3'); - $keyword_selector_3 = str_replace('{PART}', '.kw3', $part_selector_1); - if ( $keywords_3 != '' ) - { - $stylesheet .= "\n$keyword_selector_3 {{$keywords_3}}"; - } - - $keywords_4 = get_var('keywords-4'); - $keyword_selector_4 = str_replace('{PART}', '.kw4', $part_selector_1); - if ( $keywords_4 != '' ) - { - $stylesheet .= "\n$keyword_selector_4 {{$keywords_4}}"; - } - - // Do other lexics - $comments = get_var('comments'); - $comment_selector = str_replace(array('{PART1}', '{PART2}', '{PART3}'), array('.co1', '.co2', '.coMULTI'), $part_selector_3); - if ( $comments != '' ) - { - $stylesheet .= "\n$comment_selector {{$comments}}"; - } - - $esc = get_var('escaped-chars'); - $esc_selector = str_replace('{PART}', '.es0', $part_selector_1); - if ( $esc != '' ) - { - $stylesheet .= "\n$esc_selector {{$esc}}"; - } - - $brackets = get_var('brackets'); - $brk_selector = str_replace('{PART}', '.br0', $part_selector_1); - if ( $brackets != '' ) - { - $stylesheet .= "\n$brk_selector {{$brackets}}"; - } - - $strings = get_var('strings'); - $string_selector = str_replace('{PART}', '.st0', $part_selector_1); - if ( $strings != '' ) - { - $stylesheet .= "\n$string_selector {{$strings}}"; - } - - $numbers = get_var('numbers'); - $num_selector = str_replace('{PART}', '.nu0', $part_selector_1); - if ( $numbers != '' ) - { - $stylesheet .= "\n$num_selector {{$numbers}}"; - } - - $methods = get_var('methods'); - $method_selector = str_replace('{PART}', '.me0', $part_selector_1); - if ( $methods != '' ) - { - $stylesheet .= "\n$method_selector {{$methods}}"; - } - - echo "<pre>$stylesheet</pre>"; - - make_footer(); -} - -?> diff --git a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/cssgen2.php b/extensions/SyntaxHighlight_GeSHi/geshi/contrib/cssgen2.php deleted file mode 100644 index cc3c39cb..00000000 --- a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/cssgen2.php +++ /dev/null @@ -1,59 +0,0 @@ -<?php -/** - * A simple script which outputs the CSS classes for all languages - * supported by GeSHi. You can access it directly to download - * the CSS file. On *NIX you can also do a simple `php cssgen.php > geshi.css`. - * - * This file is part of GeSHi. - * - * GeSHi is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GeSHi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GeSHi; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * @package geshi - * @subpackage contrib - * @author revulo <revulon@gmail.com> - * @copyright 2008 revulo - * @license http://gnu.org/copyleft/gpl.html GNU GPL - * - */ - -require dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'geshi.php'; -$geshi = new GeSHi; - -$languages = array(); -if ($handle = opendir($geshi->language_path)) { - while (($file = readdir($handle)) !== false) { - $pos = strpos($file, '.'); - if ($pos > 0 && substr($file, $pos) == '.php') { - $languages[] = substr($file, 0, $pos); - } - } - closedir($handle); -} -sort($languages); - -header('Content-Type: application/octet-stream'); -header('Content-Disposition: attachment; filename="geshi.css"'); - -echo "/**\n". - " * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann\n" . - " * (http://qbnz.com/highlighter/ and http://geshi.org/)\n". - " */\n"; - -foreach ($languages as $language) { - $geshi->set_language($language); - // note: the false argument is required for stylesheet generators, see API documentation - $css = $geshi->get_stylesheet(false); - echo preg_replace('/^\/\*\*.*?\*\//s', '', $css); -} diff --git a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/example.php b/extensions/SyntaxHighlight_GeSHi/geshi/contrib/example.php deleted file mode 100644 index e07399e3..00000000 --- a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/example.php +++ /dev/null @@ -1,217 +0,0 @@ -<?php -/** - * GeSHi example script - * - * Just point your browser at this script (with geshi.php in the parent directory, - * and the language files in subdirectory "../geshi/") - * - * @author Nigel McNie - * @version $Id: example.php 2510 2012-06-27 15:57:55Z reedy_boy $ - */ -header('Content-Type: text/html; charset=utf-8'); - -error_reporting(E_ALL); - -// Rudimentary checking of where GeSHi is. In a default install it will be in ../, but -// it could be in the current directory if the include_path is set. There's nowhere else -// we can reasonably guess. -if (is_readable('../geshi.php')) { - $path = '../'; -} elseif (is_readable('geshi.php')) { - $path = './'; -} else { - die('Could not find geshi.php - make sure it is in your include path!'); -} -require $path . 'geshi.php'; - -$fill_source = false; -if (isset($_POST['submit'])) { - if (get_magic_quotes_gpc()) { - $_POST['source'] = stripslashes($_POST['source']); - } - if (!strlen(trim($_POST['source']))) { - $_POST['language'] = preg_replace('#[^a-zA-Z0-9\-_]#', '', $_POST['language']); - $_POST['source'] = implode('', @file($path . 'geshi/' . $_POST['language'] . '.php')); - $_POST['language'] = 'php'; - } else { - $fill_source = true; - } - - // Here's a free demo of how GeSHi works. - - // First the initialisation: source code to highlight and the language to use. Make sure - // you sanitise correctly if you use $_POST of course - this very script has had a security - // advisory against it in the past because of this. Please try not to use this script on a - // live site. - $geshi = new GeSHi($_POST['source'], $_POST['language']); - - // Use the PRE_VALID header. This means less output source since we don't have to output - // everywhere. Of course it also means you can't set the tab width. - // HEADER_PRE_VALID puts the <pre> tag inside the list items (<li>) thus producing valid HTML markup. - // HEADER_PRE puts the <pre> tag around the list (<ol>) which is invalid in HTML 4 and XHTML 1 - // HEADER_DIV puts a <div> tag arount the list (valid!) but needs to replace whitespaces with   - // thus producing much larger overhead. You can set the tab width though. - $geshi->set_header_type(GESHI_HEADER_PRE_VALID); - - // Enable CSS classes. You can use get_stylesheet() to output a stylesheet for your code. Using - // CSS classes results in much less output source. - $geshi->enable_classes(); - - // Enable line numbers. We want fancy line numbers, and we want every 5th line number to be fancy - $geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS, 5); - - // Set the style for the PRE around the code. The line numbers are contained within this box (not - // XHTML compliant btw, but if you are liberally minded about these things then you'll appreciate - // the reduced source output). - $geshi->set_overall_style('font: normal normal 90% monospace; color: #000066; border: 1px solid #d0d0d0; background-color: #f0f0f0;', false); - - // Set the style for line numbers. In order to get style for line numbers working, the <li> element - // is being styled. This means that the code on the line will also be styled, and most of the time - // you don't want this. So the set_code_style reverts styles for the line (by using a <div> on the line). - // So the source output looks like this: - // - // <pre style="[set_overall_style styles]"><ol> - // <li style="[set_line_style styles]"><div style="[set_code_style styles]>...</div></li> - // ... - // </ol></pre> - $geshi->set_line_style('color: #003030;', 'font-weight: bold; color: #006060;', true); - $geshi->set_code_style('color: #000020;', true); - - // Styles for hyperlinks in the code. GESHI_LINK for default styles, GESHI_HOVER for hover style etc... - // note that classes must be enabled for this to work. - $geshi->set_link_styles(GESHI_LINK, 'color: #000060;'); - $geshi->set_link_styles(GESHI_HOVER, 'background-color: #f0f000;'); - - // Use the header/footer functionality. This puts a div with content within the PRE element, so it is - // affected by the styles set by set_overall_style. So if the PRE has a border then the header/footer will - // appear inside it. - $geshi->set_header_content('<SPEED> <TIME> GeSHi © 2004-2007, Nigel McNie, 2007-2008 Benny Baumann. View source of example.php for example of using GeSHi'); - $geshi->set_header_content_style('font-family: sans-serif; color: #808080; font-size: 70%; font-weight: bold; background-color: #f0f0ff; border-bottom: 1px solid #d0d0d0; padding: 2px;'); - - // You can use <TIME> and <VERSION> as placeholders - $geshi->set_footer_content('Parsed in <TIME> seconds at <SPEED>, using GeSHi <VERSION>'); - $geshi->set_footer_content_style('font-family: sans-serif; color: #808080; font-size: 70%; font-weight: bold; background-color: #f0f0ff; border-top: 1px solid #d0d0d0; padding: 2px;'); -} else { - // make sure we don't preselect any language - $_POST['language'] = null; -} -?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head> - <title>GeSHi examples</title> - <style type="text/css"> - <!-- - <?php - if (isset($_POST['submit'])) { - // Output the stylesheet. Note it doesn't output the <style> tag - echo $geshi->get_stylesheet(true); - } - ?> - html { - background-color: #f0f0f0; - } - body { - font-family: Verdana, Arial, sans-serif; - margin: 10px; - border: 2px solid #e0e0e0; - background-color: #fcfcfc; - padding: 5px; - } - h2 { - margin: .1em 0 .2em .5em; - border-bottom: 1px solid #b0b0b0; - color: #b0b0b0; - font-weight: normal; - font-size: 150%; - } - h3 { - margin: .1em 0 .2em .5em; - color: #b0b0b0; - font-weight: normal; - font-size: 120%; - } - #footer { - text-align: center; - font-size: 80%; - color: #a9a9a9; - } - #footer a { - color: #9999ff; - } - textarea { - border: 1px solid #b0b0b0; - font-size: 90%; - color: #333; - margin-left: 20px; - } - select, input { - margin-left: 20px; - } - p { - font-size: 90%; - margin-left: .5em; - } - --> - </style> -</head> -<body> -<h2>GeSHi Example Script</h2> -<p>To use this script, make sure that <strong>geshi.php</strong> is in the parent directory or in your -include_path, and that the language files are in a subdirectory of GeSHi's directory called <strong>geshi/</strong>.</p> -<p>Enter your source and a language to highlight the source in and submit, or just choose a language to -have that language file highlighted in PHP.</p> -<?php -if (isset($_POST['submit'])) { - // The fun part :) - echo $geshi->parse_code(); - echo '<hr />'; -} -?> -<form action="<?php echo basename($_SERVER['PHP_SELF']); ?>" method="post"> -<h3>Source to highlight</h3> -<p> -<textarea rows="10" cols="60" name="source" id="source"><?php echo $fill_source ? htmlspecialchars($_POST['source']) : '' ?></textarea> -</p> -<h3>Choose a language</h3> -<p> -<select name="language" id="language"> -<?php -if (!($dir = @opendir(dirname(__FILE__) . '/geshi'))) { - if (!($dir = @opendir(dirname(__FILE__) . '/../geshi'))) { - echo '<option>No languages available!</option>'; - } -} -$languages = array(); -while ($file = readdir($dir)) { - if ( $file[0] == '.' || strpos($file, '.', 1) === false) { - continue; - } - $lang = substr($file, 0, strpos($file, '.')); - $languages[] = $lang; -} -closedir($dir); -sort($languages); -foreach ($languages as $lang) { - if (isset($_POST['language']) && $_POST['language'] == $lang) { - $selected = 'selected="selected"'; - } else { - $selected = ''; - } - echo '<option value="' . $lang . '" '. $selected .'>' . $lang . "</option>\n"; -} - -?> -</select> -</p> -<p> -<input type="submit" name="submit" value="Highlight Source" /> -<input type="submit" name="clear" onclick="document.getElementById('source').value='';document.getElementById('language').value='';return false" value="clear" /> -</p> -</form> -<div id="footer">GeSHi © Nigel McNie, 2004, released under the GNU GPL<br /> -For a better demonstration, check out the <a href="http://qbnz.com/highlighter/demo.php">online demo</a> -</div> -</body> -</html> diff --git a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/langcheck.php b/extensions/SyntaxHighlight_GeSHi/geshi/contrib/langcheck.php deleted file mode 100644 index fa8288be..00000000 --- a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/langcheck.php +++ /dev/null @@ -1,769 +0,0 @@ -<?php -/** - * GeSHi language file validation script - * - * Just point your browser at this script (with geshi.php in the parent directory) - * and the language files in subdirectory "../geshi/" are being validated - * - * CLI mode is supported - * - * @author Benny Baumann - * @version $Id: langcheck.php 2510 2012-06-27 15:57:55Z reedy_boy $ - */ -header('Content-Type: text/html; charset=utf-8'); - -set_time_limit(0); -error_reporting(E_ALL); -$time_start = explode(' ', microtime()); - -function colorize($level, $string) { - static $colors, $end; - if ( !isset($colors) ) { - if ( PHP_SAPI != 'cli' ) { - $end = '</span>'; - $colors = array( - TYPE_NOTICE => '<span style="color:#080;font-weight:bold;">', - TYPE_WARNING => '<span style="color:#CC0; font-weight: bold;">', - TYPE_ERROR => '<span style="color:#F00; font-weight: bold;">', - TYPE_OK => '<span style="color: #080; font-weight: bold;">' - ); - } else { - $end = chr(27).'[0m'; - $colors = array( - TYPE_NOTICE => chr(27).'[1m', - TYPE_WARNING => chr(27).'[1;33m', - TYPE_ERROR => chr(27).'[1;31m', - TYPE_OK => chr(27).'[1;32m' - ); - } - } - - if ( !isset($colors[$level]) ) { - trigger_error("no colors for level $level", E_USER_ERROR); - } - - return $colors[$level].$string.$end; -} - -define ('TYPE_NOTICE', 0); -define ('TYPE_WARNING', 1); -define ('TYPE_ERROR', 2); -define ('TYPE_OK', 3); - -$error_abort = false; -$error_cache = array(); -function output_error_cache(){ - global $error_cache, $error_abort; - - if(count($error_cache)) { - echo colorize(TYPE_ERROR, "Failed"); - if ( PHP_SAPI == 'cli' ) { - echo "\n\n"; - } else { - echo "<br /><ol>\n"; - } - foreach($error_cache as $error_msg) { - if ( PHP_SAPI == 'cli' ) { - echo "\n"; - } else { - echo "<li>"; - } - switch($error_msg['t']) { - case TYPE_NOTICE: - $msg = 'NOTICE'; - break; - case TYPE_WARNING: - $msg = 'WARNING'; - break; - case TYPE_ERROR: - $msg = 'ERROR'; - break; - } - echo colorize($error_msg['t'], $msg); - if ( PHP_SAPI == 'cli' ) { - echo "\t" . $error_msg['m']; - } else { - echo " " . $error_msg['m'] . "</li>"; - } - } - if ( PHP_SAPI == 'cli' ) { - echo "\n"; - } else { - echo "</ol>\n"; - } - } else { - echo colorize(TYPE_OK, "OK"); - if ( PHP_SAPI == 'cli' ) { - echo "\n"; - } else { - echo "\n<br />"; - } - } - echo "\n"; - - $error_cache = array(); -} - -function report_error($type, $message) { - global $error_cache, $error_abort; - - $error_cache[] = array('t' => $type, 'm' => $message); - if(TYPE_ERROR == $type) { - $error_abort = true; - } -} - -function dupfind_strtolower(&$value){ - $value = strtolower($value); -} - -if ( PHP_SAPI != 'cli' ) { ?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head> - <title>GeSHi Language File Validation Script</title> - <style type="text/css"> - <!-- - html { - background-color: #f0f0f0; - } - body { - font-family: Verdana, Arial, sans-serif; - margin: 10px; - border: 2px solid #e0e0e0; - background-color: #fcfcfc; - padding: 5px; - font-size: 10pt; - } - h2 { - margin: .1em 0 .2em .5em; - border-bottom: 1px solid #b0b0b0; - color: #b0b0b0; - font-weight: normal; - font-size: 150%; - } - h3 { - margin: .1em 0 .2em .5em; - color: #b0b0b0; - font-weight: normal; - font-size: 120%; - } - #footer { - text-align: center; - font-size: 80%; - color: #a9a9a9; - } - #footer a { - color: #9999ff; - } - textarea { - border: 1px solid #b0b0b0; - font-size: 90%; - color: #333; - margin-left: 20px; - } - select, input { - margin-left: 20px; - } - p { - font-size: 90%; - margin-left: .5em; - } - --> - </style> -</head> -<body> -<h2>GeSHi Language File Validation Script</h2> -<p>To use this script, make sure that <strong>geshi.php</strong> is in the -parent directory or in your include_path, and that the language files are in a -subdirectory of GeSHi's directory called <strong>geshi/</strong>.</p> -<p>Everything else will be done by this script automatically. After the script -finished you should see messages of what could cause trouble with GeSHi or where -your language files can be improved. Please be patient, as this might take some time.</p> - -<ol> -<li>Checking where to find GeSHi installation ...<?php -} else { ?> -<?php echo colorize(TYPE_NOTICE, "#### GeSHi Language File Validation Script ####") ?> - - -To use this script, make sure that <?php echo colorize(TYPE_NOTICE, "geshi.php"); ?> is in the -parent directory or in your include_path, and that the language files are in a -subdirectory of GeSHi's directory called <?php echo colorize(TYPE_NOTICE, "geshi/"); ?>. - -Everything else will be done by this script automatically. After the script -finished you should see messages of what could cause trouble with GeSHi or where -your language files can be improved. Please be patient, as this might take some time. - - -Checking where to find GeSHi installation ...<?php echo "\t"; -} - -// Rudimentary checking of where GeSHi is. In a default install it will be in ../, but -// it could be in the current directory if the include_path is set. There's nowhere else -// we can reasonably guess. -if (is_readable('../geshi.php')) { - $path = '../'; -} elseif (is_readable('geshi.php')) { - $path = './'; -} else { - report_error(TYPE_ERROR, 'Could not find geshi.php - make sure it is in your include path!'); -} - -if(!$error_abort) { - require $path . 'geshi.php'; - - if(!class_exists('GeSHi')) { - report_error(TYPE_ERROR, 'The GeSHi class was not found, although it seemed we loaded the correct file!'); - } -} - -if(!$error_abort) { - if(!defined('GESHI_LANG_ROOT')) { - report_error(TYPE_ERROR, 'There\'s no information present on where to find the language files!'); - } elseif(!is_dir(GESHI_LANG_ROOT)) { - report_error(TYPE_ERROR, 'The path "'.GESHI_LANG_ROOT.'" given, does not ressemble a directory!'); - } elseif(!is_readable(GESHI_LANG_ROOT)) { - report_error(TYPE_ERROR, 'The path "'.GESHI_LANG_ROOT.'" is not readable to this script!'); - } -} - -output_error_cache(); - -if(!$error_abort) { - if ( PHP_SAPI == 'cli' ) { - echo "Listing available language files ...\t\t"; - } else { - echo "</li>\n<li>Listing available language files ... "; - } - - if (!($dir = @opendir(GESHI_LANG_ROOT))) { - report_error(TYPE_ERROR, 'Error requesting listing for available language files!'); - } - - $languages = array(); - - if(!$error_abort) { - while ($file = readdir($dir)) { - if (!$file || $file[0] == '.' || strpos($file, '.php') === false) { - continue; - } - $lang = substr($file, 0, strpos($file, '.')); - if(4 != strlen($file) - strlen($lang)) { - continue; - } - $languages[] = $lang; - } - closedir($dir); - } - - $languages = array_unique($languages); - sort($languages); - - if(!count($languages)) { - report_error(TYPE_WARNING, 'Unable to locate any usable language files in "'.GESHI_LANG_ROOT.'"!'); - } - - output_error_cache(); -} - -if ( PHP_SAPI == 'cli' ) { - if (isset($_SERVER['argv'][1]) && in_array($_SERVER['argv'][1], $languages)) { - $languages = array($_SERVER['argv'][1]); - } -} else { - if (isset($_REQUEST['show']) && in_array($_REQUEST['show'], $languages)) { - $languages = array($_REQUEST['show']); - } -} - -if(!$error_abort) { - foreach ($languages as $lang) { - - if ( PHP_SAPI == 'cli' ) { - echo "Validating language file for '$lang' ...\t\t"; - } else { - echo "</li>\n<li>Validating language file for '$lang' ... "; - } - - $langfile = GESHI_LANG_ROOT . $lang . '.php'; - - $language_data = array(); - - if(!is_file($langfile)) { - report_error(TYPE_ERROR, 'The path "' .$langfile. '" does not ressemble a regular file!'); - } elseif(!is_readable($langfile)) { - report_error(TYPE_ERROR, 'Cannot read file "' .$langfile. '"!'); - } else { - $langfile_content = file_get_contents($langfile); - if(preg_match("/\?>(?:\r?\n|\r(?!\n)){2,}\Z/", $langfile_content)) { - report_error(TYPE_ERROR, 'Language file contains trailing empty lines at EOF!'); - } - if(!preg_match("/\?>(?:\r?\n|\r(?!\n))?\Z/", $langfile_content)) { - report_error(TYPE_ERROR, 'Language file contains no PHP end marker at EOF!'); - } - if(preg_match("/\t/", $langfile_content)) { - report_error(TYPE_NOTICE, 'Language file contains unescaped tabulator chars (probably for indentation)!'); - } - if(preg_match('/^(?: )*(?! )(?! \*) /m', $langfile_content)) { - report_error(TYPE_NOTICE, 'Language file contains irregular indentation (other than 4 spaces per indentation level)!'); - } - - if(!preg_match("/\/\*\*((?!\*\/).)*?Author:((?!\*\/).)*?\*\//s", $langfile_content)) { - report_error(TYPE_WARNING, 'Language file does not contain a specification of an author!'); - } - if(!preg_match("/\/\*\*((?!\*\/).)*?Copyright:((?!\*\/).)*?\*\//s", $langfile_content)) { - report_error(TYPE_WARNING, 'Language file does not contain a specification of the copyright!'); - } - if(!preg_match("/\/\*\*((?!\*\/).)*?Release Version:((?!\*\/).)*?\*\//s", $langfile_content)) { - report_error(TYPE_WARNING, 'Language file does not contain a specification of the release version!'); - } - if(!preg_match("/\/\*\*((?!\*\/).)*?Date Started:((?!\*\/).)*?\*\//s", $langfile_content)) { - report_error(TYPE_WARNING, 'Language file does not contain a specification of the date it was started!'); - } - if(!preg_match("/\/\*\*((?!\*\/).)*?This file is part of GeSHi\.((?!\*\/).)*?\*\//s", $langfile_content)) { - report_error(TYPE_WARNING, 'Language file does not state that it belongs to GeSHi!'); - } - if(!preg_match("/\/\*\*((?!\*\/).)*?language file for GeSHi\.((?!\*\/).)*?\*\//s", $langfile_content)) { - report_error(TYPE_WARNING, 'Language file does not state that it is a language file for GeSHi!'); - } - if(!preg_match("/\/\*\*((?!\*\/).)*?GNU General Public License((?!\*\/).)*?\*\//s", $langfile_content)) { - report_error(TYPE_WARNING, 'Language file does not state that it is provided under the terms of the GNU GPL!'); - } - - unset($langfile_content); - - include $langfile; - - if(!isset($language_data)) { - report_error(TYPE_ERROR, 'Language file does not contain a $language_data structure to check!'); - } elseif (!is_array($language_data)) { - report_error(TYPE_ERROR, 'Language file contains a $language_data structure which is not an array!'); - } - } - - if(!$error_abort) { - if(!isset($language_data['LANG_NAME'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'LANG_NAME\'] specification!'); - } elseif (!is_string($language_data['LANG_NAME'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'LANG_NAME\'] specification which is not a string!'); - } - - if(!isset($language_data['COMMENT_SINGLE'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'COMMENT_SIGNLE\'] structure to check!'); - } elseif (!is_array($language_data['COMMENT_SINGLE'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'COMMENT_SINGLE\'] structure which is not an array!'); - } - - if(!isset($language_data['COMMENT_MULTI'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'COMMENT_MULTI\'] structure to check!'); - } elseif (!is_array($language_data['COMMENT_MULTI'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'COMMENT_MULTI\'] structure which is not an array!'); - } - - if(isset($language_data['COMMENT_REGEXP'])) { - if (!is_array($language_data['COMMENT_REGEXP'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'COMMENT_REGEXP\'] structure which is not an array!'); - } - } - - if(!isset($language_data['QUOTEMARKS'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'QUOTEMARKS\'] structure to check!'); - } elseif (!is_array($language_data['QUOTEMARKS'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'QUOTEMARKS\'] structure which is not an array!'); - } - - if(isset($language_data['HARDQUOTE'])) { - if (!is_array($language_data['HARDQUOTE'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'HARDQUOTE\'] structure which is not an array!'); - } - } - - if(!isset($language_data['ESCAPE_CHAR'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'ESCAPE_CHAR\'] specification to check!'); - } elseif (!is_string($language_data['ESCAPE_CHAR'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'ESCAPE_CHAR\'] specification which is not a string!'); - } elseif (1 < strlen($language_data['ESCAPE_CHAR'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'ESCAPE_CHAR\'] specification is not empty or exactly one char!'); - } - - if(!isset($language_data['CASE_KEYWORDS'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'CASE_KEYWORDS\'] specification!'); - } elseif (!is_int($language_data['CASE_KEYWORDS'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'CASE_KEYWORDS\'] specification which is not an integer!'); - } elseif (GESHI_CAPS_NO_CHANGE != $language_data['CASE_KEYWORDS'] && - GESHI_CAPS_LOWER != $language_data['CASE_KEYWORDS'] && - GESHI_CAPS_UPPER != $language_data['CASE_KEYWORDS']) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'CASE_KEYWORDS\'] specification which is neither of GESHI_CAPS_NO_CHANGE, GESHI_CAPS_LOWER nor GESHI_CAPS_UPPER!'); - } - - if(!isset($language_data['KEYWORDS'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'KEYWORDS\'] structure to check!'); - } elseif (!is_array($language_data['KEYWORDS'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'KEYWORDS\'] structure which is not an array!'); - } else { - foreach($language_data['KEYWORDS'] as $kw_key => $kw_value) { - if(!is_integer($kw_key)) { - report_error(TYPE_WARNING, "Language file contains an key '$kw_key' in \$language_data['KEYWORDS'] that is not integer!"); - } elseif (!is_array($kw_value)) { - report_error(TYPE_ERROR, "Language file contains a \$language_data['KEYWORDS']['$kw_value'] structure which is not an array!"); - } - } - } - - if(!isset($language_data['SYMBOLS'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'SYMBOLS\'] structure to check!'); - } elseif (!is_array($language_data['SYMBOLS'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'SYMBOLS\'] structure which is not an array!'); - } - - if(!isset($language_data['CASE_SENSITIVE'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'CASE_SENSITIVE\'] structure to check!'); - } elseif (!is_array($language_data['CASE_SENSITIVE'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'CASE_SENSITIVE\'] structure which is not an array!'); - } else { - foreach($language_data['CASE_SENSITIVE'] as $cs_key => $cs_value) { - if(!is_integer($cs_key)) { - report_error(TYPE_WARNING, "Language file contains an key '$cs_key' in \$language_data['CASE_SENSITIVE'] that is not integer!"); - } elseif (!is_bool($cs_value)) { - report_error(TYPE_ERROR, "Language file contains a Case Sensitivity specification for \$language_data['CASE_SENSITIVE']['$cs_value'] which is not a boolean!"); - } - } - } - - if(!isset($language_data['URLS'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'URLS\'] structure to check!'); - } elseif (!is_array($language_data['URLS'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'URLS\'] structure which is not an array!'); - } else { - foreach($language_data['URLS'] as $url_key => $url_value) { - if(!is_integer($url_key)) { - report_error(TYPE_WARNING, "Language file contains an key '$url_key' in \$language_data['URLS'] that is not integer!"); - } elseif (!is_string($url_value)) { - report_error(TYPE_ERROR, "Language file contains a Documentation URL specification for \$language_data['URLS']['$url_value'] which is not a string!"); - } elseif (preg_match('#&([^;]*(=|$))#U', $url_value)) { - report_error(TYPE_ERROR, "Language file contains unescaped ampersands (&) in \$language_data['URLS']!"); - } - } - } - - if(!isset($language_data['OOLANG'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'OOLANG\'] specification!'); - } elseif (!is_int($language_data['OOLANG']) && !is_bool($language_data['OOLANG'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'OOLANG\'] specification which is neither boolean nor integer!'); - } elseif (false !== $language_data['OOLANG'] && - true !== $language_data['OOLANG'] && - 2 !== $language_data['OOLANG']) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'OOLANG\'] specification which is neither of false, true or 2!'); - } - - if(!isset($language_data['OBJECT_SPLITTERS'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'OBJECT_SPLITTERS\'] structure to check!'); - } elseif (!is_array($language_data['OBJECT_SPLITTERS'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'OBJECT_SPLITTERS\'] structure which is not an array!'); - } - - if(!isset($language_data['REGEXPS'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'REGEXPS\'] structure to check!'); - } elseif (!is_array($language_data['REGEXPS'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'REGEXPS\'] structure which is not an array!'); - } - - if(!isset($language_data['STRICT_MODE_APPLIES'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'STRICT_MODE_APPLIES\'] specification!'); - } elseif (!is_int($language_data['STRICT_MODE_APPLIES'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'STRICT_MODE_APPLIES\'] specification which is not an integer!'); - } elseif (GESHI_MAYBE != $language_data['STRICT_MODE_APPLIES'] && - GESHI_ALWAYS != $language_data['STRICT_MODE_APPLIES'] && - GESHI_NEVER != $language_data['STRICT_MODE_APPLIES']) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'STRICT_MODE_APPLIES\'] specification which is neither of GESHI_MAYBE, GESHI_ALWAYS nor GESHI_NEVER!'); - } - - if(!isset($language_data['SCRIPT_DELIMITERS'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'SCRIPT_DELIMITERS\'] structure to check!'); - } elseif (!is_array($language_data['SCRIPT_DELIMITERS'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'SCRIPT_DELIMITERS\'] structure which is not an array!'); - } - - if(!isset($language_data['HIGHLIGHT_STRICT_BLOCK'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'HIGHLIGHT_STRICT_BLOCK\'] structure to check!'); - } elseif (!is_array($language_data['HIGHLIGHT_STRICT_BLOCK'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'HIGHLIGHT_STRICT_BLOCK\'] structure which is not an array!'); - } - - if(isset($language_data['TAB_WIDTH'])) { - if (!is_int($language_data['TAB_WIDTH'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'TAB_WIDTH\'] specification which is not an integer!'); - } elseif (1 > $language_data['TAB_WIDTH']) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'TAB_WIDTH\'] specification which is less than 1!'); - } - } - - if(isset($language_data['PARSER_CONTROL'])) { - if (!is_array($language_data['PARSER_CONTROL'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'PARSER_CONTROL\'] structure which is not an array!'); - } - } - - if(!isset($language_data['STYLES'])) { - report_error(TYPE_ERROR, 'Language file contains no $language_data[\'STYLES\'] structure to check!'); - } elseif (!is_array($language_data['STYLES'])) { - report_error(TYPE_ERROR, 'Language file contains a $language_data[\'STYLES\'] structure which is not an array!'); - } else { - $style_arrays = array('KEYWORDS', 'COMMENTS', 'ESCAPE_CHAR', - 'BRACKETS', 'STRINGS', 'NUMBERS', 'METHODS', 'SYMBOLS', - 'REGEXPS', 'SCRIPT'); - foreach($style_arrays as $style_kind) { - if(!isset($language_data['STYLES'][$style_kind])) { - report_error(TYPE_ERROR, "Language file contains no \$language_data['STYLES']['$style_kind'] structure to check!"); - } elseif (!is_array($language_data['STYLES'][$style_kind])) { - report_error(TYPE_ERROR, "Language file contains a \$language_data['STYLES\']['$style_kind'] structure which is not an array!"); - } else { - foreach($language_data['STYLES'][$style_kind] as $sk_key => $sk_value) { - if(!is_int($sk_key) && ('COMMENTS' != $style_kind && 'MULTI' != $sk_key) - && !(('STRINGS' == $style_kind || 'ESCAPE_CHAR' == $style_kind) && 'HARD' == $sk_key)) { - report_error(TYPE_WARNING, "Language file contains an key '$sk_key' in \$language_data['STYLES']['$style_kind'] that is not integer!"); - } elseif (!is_string($sk_value)) { - report_error(TYPE_WARNING, "Language file contains a CSS specification for \$language_data['STYLES']['$style_kind'][$key] which is not a string!"); - } - } - } - } - - unset($style_arrays); - } - } - - if(!$error_abort) { - //Initial sanity checks survived? --> Let's dig deeper! - foreach($language_data['KEYWORDS'] as $key => $keywords) { - if(!isset($language_data['CASE_SENSITIVE'][$key])) { - report_error(TYPE_ERROR, "Language file contains no \$language_data['CASE_SENSITIVE'] specification for keyword group $key!"); - } - if(!isset($language_data['URLS'][$key])) { - report_error(TYPE_ERROR, "Language file contains no \$language_data['URLS'] specification for keyword group $key!"); - } - if(empty($keywords)) { - report_error(TYPE_WARNING, "Language file contains an empty keyword list in \$language_data['KEYWORDS'] for group $key!"); - } - foreach($keywords as $id => $kw) { - if(!is_string($kw)) { - report_error(TYPE_WARNING, "Language file contains an non-string entry at \$language_data['KEYWORDS'][$key][$id]!"); - } elseif (!strlen($kw)) { - report_error(TYPE_ERROR, "Language file contains an empty string entry at \$language_data['KEYWORDS'][$key][$id]!"); - } elseif (preg_match('/^([\(\)\{\}\[\]\^=.,:;\-+\*\/%\$\"\'\?]|&[\w#]\w*;)+$/i', $kw)) { - report_error(TYPE_NOTICE, "Language file contains an keyword ('$kw') at \$language_data['KEYWORDS'][$key][$id] which seems to be better suited for the symbols section!"); - } - } - if(isset($language_data['CASE_SENSITIVE'][$key]) && !$language_data['CASE_SENSITIVE'][$key]) { - array_walk($keywords, 'dupfind_strtolower'); - } - if(count($keywords) != count(array_unique($keywords))) { - $kw_diffs = array_count_values($keywords); - foreach($kw_diffs as $kw => $kw_count) { - if($kw_count > 1) { - report_error(TYPE_WARNING, "Language file contains per-group duplicate keyword '$kw' in \$language_data['KEYWORDS'][$key]!"); - } - } - } - } - - $disallowed_before = "(?<![a-zA-Z0-9\$_\|\#;>|^&"; - $disallowed_after = "(?![a-zA-Z0-9_\|%\\-&;"; - - foreach($language_data['KEYWORDS'] as $key => $keywords) { - foreach($language_data['KEYWORDS'] as $key2 => $keywords2) { - if($key2 <= $key) { - continue; - } - $kw_diffs = array_intersect($keywords, $keywords2); - foreach($kw_diffs as $kw) { - if(isset($language_data['PARSER_CONTROL']['KEYWORDS'])) { - //Check the precondition\post-cindition for the involved keyword groups - $g1_pre = $disallowed_before; - $g2_pre = $disallowed_before; - $g1_post = $disallowed_after; - $g2_post = $disallowed_after; - if(isset($language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_BEFORE'])) { - $g1_pre = $language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_BEFORE']; - $g2_pre = $language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_BEFORE']; - } - if(isset($language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_AFTER'])) { - $g1_post = $language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_AFTER']; - $g2_post = $language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_AFTER']; - } - - if(isset($language_data['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_BEFORE'])) { - $g1_pre = $language_data['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_BEFORE']; - } - if(isset($language_data['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_AFTER'])) { - $g1_post = $language_data['PARSER_CONTROL']['KEYWORDS'][$key]['DISALLOWED_AFTER']; - } - - if(isset($language_data['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_BEFORE'])) { - $g2_pre = $language_data['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_BEFORE']; - } - if(isset($language_data['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_AFTER'])) { - $g2_post = $language_data['PARSER_CONTROL']['KEYWORDS'][$key2]['DISALLOWED_AFTER']; - } - - if($g1_pre != $g2_pre || $g1_post != $g2_post) { - continue; - } - } - report_error(TYPE_WARNING, "Language file contains cross-group duplicate keyword '$kw' in \$language_data['KEYWORDS'][$key] and \$language_data['KEYWORDS'][$key2]!"); - } - } - } - foreach($language_data['CASE_SENSITIVE'] as $key => $keywords) { - if(!isset($language_data['KEYWORDS'][$key]) && $key != GESHI_COMMENTS) { - report_error(TYPE_WARNING, "Language file contains an superfluous \$language_data['CASE_SENSITIVE'] specification for non-existing keyword group $key!"); - } - } - foreach($language_data['URLS'] as $key => $keywords) { - if(!isset($language_data['KEYWORDS'][$key])) { - report_error(TYPE_WARNING, "Language file contains an superfluous \$language_data['URLS'] specification for non-existing keyword group $key!"); - } - } - foreach($language_data['STYLES']['KEYWORDS'] as $key => $keywords) { - if(!isset($language_data['KEYWORDS'][$key])) { - report_error(TYPE_WARNING, "Language file contains an superfluous \$language_data['STYLES']['KEYWORDS'] specification for non-existing keyword group $key!"); - } - } - - foreach($language_data['COMMENT_SINGLE'] as $ck => $cv) { - if(!is_int($ck)) { - report_error(TYPE_WARNING, "Language file contains an key '$ck' in \$language_data['COMMENT_SINGLE'] that is not integer!"); - } - if(!is_string($cv)) { - report_error(TYPE_WARNING, "Language file contains an non-string entry at \$language_data['COMMENT_SINGLE'][$ck]!"); - } - if(!isset($language_data['STYLES']['COMMENTS'][$ck])) { - report_error(TYPE_WARNING, "Language file contains no \$language_data['STYLES']['COMMENTS'] specification for comment group $ck!"); - } - } - if(isset($language_data['COMMENT_REGEXP'])) { - foreach($language_data['COMMENT_REGEXP'] as $ck => $cv) { - if(!is_int($ck)) { - report_error(TYPE_WARNING, "Language file contains an key '$ck' in \$language_data['COMMENT_REGEXP'] that is not integer!"); - } - if(!is_string($cv)) { - report_error(TYPE_WARNING, "Language file contains an non-string entry at \$language_data['COMMENT_REGEXP'][$ck]!"); - } - if(!isset($language_data['STYLES']['COMMENTS'][$ck])) { - report_error(TYPE_WARNING, "Language file contains no \$language_data['STYLES']['COMMENTS'] specification for comment group $ck!"); - } - } - } - foreach($language_data['STYLES']['COMMENTS'] as $ck => $cv) { - if($ck != 'MULTI' && !isset($language_data['COMMENT_SINGLE'][$ck]) && - !isset($language_data['COMMENT_REGEXP'][$ck])) { - report_error(TYPE_NOTICE, "Language file contains an superfluous \$language_data['STYLES']['COMMENTS'] specification for Single Line or Regular-Expression Comment key $ck!"); - } - } - if (isset($language_data['STYLES']['STRINGS']['HARD'])) { - if (empty($language_data['HARDQUOTE'])) { - report_error(TYPE_NOTICE, "Language file contains superfluous \$language_data['STYLES']['STRINGS'] specification for key 'HARD', but no 'HARDQUOTE's are defined!"); - } - unset($language_data['STYLES']['STRINGS']['HARD']); - } - foreach($language_data['STYLES']['STRINGS'] as $sk => $sv) { - if($sk && !isset($language_data['QUOTEMARKS'][$sk])) { - report_error(TYPE_NOTICE, "Language file contains an superfluous \$language_data['STYLES']['STRINGS'] specification for non-existing quotemark key $sk!"); - } - } - - foreach($language_data['REGEXPS'] as $rk => $rv) { - if(!is_int($rk)) { - report_error(TYPE_WARNING, "Language file contains an key '$rk' in \$language_data['REGEXPS'] that is not integer!"); - } - if(is_string($rv)) { - //Check for unmasked / in regular expressions ... - if(empty($rv)) { - report_error(TYPE_WARNING, "Language file contains an empty regular expression at \$language_data['REGEXPS'][$rk]!"); - } else { - if(preg_match("/(?<!\\\\)\//s", $rv)) { - report_error(TYPE_WARNING, "Language file contains a regular expression with an unmasked / character at \$language_data['REGEXPS'][$rk]!"); - } elseif (preg_match("/(?<!<)(\\\\\\\\)*\\\\\|(?!>)/s", $rv)) { - report_error(TYPE_WARNING, "Language file contains a regular expression with an unescaped match for a pipe character '|' which needs escaping as '<PIPE>' instead at \$language_data['REGEXPS'][$rk]!"); - } - } - } elseif(is_array($rv)) { - if(!isset($rv[GESHI_SEARCH])) { - report_error(TYPE_ERROR, "Language file contains no GESHI_SEARCH entry in extended regular expression at \$language_data['REGEXPS'][$rk]!"); - } elseif(!is_string($rv[GESHI_SEARCH])) { - report_error(TYPE_ERROR, "Language file contains a GESHI_SEARCH entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!"); - } else { - if(preg_match("/(?<!\\\\)\//s", $rv[GESHI_SEARCH])) { - report_error(TYPE_WARNING, "Language file contains a regular expression with an unmasked / character at \$language_data['REGEXPS'][$rk]!"); - } elseif (preg_match("/(?<!<)(\\\\\\\\)*\\\\\|(?!>)/s", $rv[GESHI_SEARCH])) { - report_error(TYPE_WARNING, "Language file contains a regular expression with an unescaped match for a pipe character '|' which needs escaping as '<PIPE>' instead at \$language_data['REGEXPS'][$rk]!"); - } - } - if(!isset($rv[GESHI_REPLACE])) { - report_error(TYPE_WARNING, "Language file contains no GESHI_REPLACE entry in extended regular expression at \$language_data['REGEXPS'][$rk]!"); - } elseif(!is_string($rv[GESHI_REPLACE])) { - report_error(TYPE_ERROR, "Language file contains a GESHI_REPLACE entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!"); - } - if(!isset($rv[GESHI_MODIFIERS])) { - report_error(TYPE_WARNING, "Language file contains no GESHI_MODIFIERS entry in extended regular expression at \$language_data['REGEXPS'][$rk]!"); - } elseif(!is_string($rv[GESHI_MODIFIERS])) { - report_error(TYPE_ERROR, "Language file contains a GESHI_MODIFIERS entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!"); - } - if(!isset($rv[GESHI_BEFORE])) { - report_error(TYPE_WARNING, "Language file contains no GESHI_BEFORE entry in extended regular expression at \$language_data['REGEXPS'][$rk]!"); - } elseif(!is_string($rv[GESHI_BEFORE])) { - report_error(TYPE_ERROR, "Language file contains a GESHI_BEFORE entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!"); - } - if(!isset($rv[GESHI_AFTER])) { - report_error(TYPE_WARNING, "Language file contains no GESHI_AFTER entry in extended regular expression at \$language_data['REGEXPS'][$rk]!"); - } elseif(!is_string($rv[GESHI_AFTER])) { - report_error(TYPE_ERROR, "Language file contains a GESHI_AFTER entry in extended regular expression at \$language_data['REGEXPS'][$rk] which is not a string!"); - } - } else { - report_error(TYPE_WARNING, "Language file contains an non-string and non-array entry at \$language_data['REGEXPS'][$rk]!"); - } - if(!isset($language_data['STYLES']['REGEXPS'][$rk])) { - report_error(TYPE_WARNING, "Language file contains no \$language_data['STYLES']['REGEXPS'] specification for regexp group $rk!"); - } - } - foreach($language_data['STYLES']['REGEXPS'] as $rk => $rv) { - if(!isset($language_data['REGEXPS'][$rk])) { - report_error(TYPE_NOTICE, "Language file contains an superfluous \$language_data['STYLES']['REGEXPS'] specification for regexp key $rk!"); - } - } - - - } - - output_error_cache(); - - flush(); - - if($error_abort) { - break; - } - } -} - -$time_end = explode(' ', microtime()); -$time_diff = $time_end[0] + $time_end[1] - $time_start[0] - $time_start[1]; - -if ( PHP_SAPI != 'cli' ) { -?></li> -</ol> - -<p>Validation process completed in <? printf("%.2f", $time_diff); ?> seconds.</p> - -<div id="footer">GeSHi © 2004-2007 Nigel McNie, 2007-2008 Benny Baumann, released under the GNU GPL</div> -</body> -</html> - -<?php } else { ?> - -Validation process completed in <? printf("%.2f", $time_diff); ?> seconds. - -GeSHi © 2004-2007 Nigel McNie, 2007-2012 Benny Baumann, released under the GNU GPL - -<?php } ?>
\ No newline at end of file diff --git a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/langwiz.php b/extensions/SyntaxHighlight_GeSHi/geshi/contrib/langwiz.php deleted file mode 100644 index 32d025a9..00000000 --- a/extensions/SyntaxHighlight_GeSHi/geshi/contrib/langwiz.php +++ /dev/null @@ -1,1158 +0,0 @@ -<?php -/** - * GeSHi example script - * - * Just point your browser at this script (with geshi.php in the parent directory, - * and the language files in subdirectory "../geshi/") - * - *This script - * - * @author Nigel McNie, Benny Baumann (BenBE@geshi.org), Andreas 'Segaja' Schleifer (webmaster at segaja dot de) - * @version $Id: langwiz.php 2510 2012-06-27 15:57:55Z reedy_boy $ - */ -header('Content-Type: text/html; charset=utf-8'); - -set_time_limit(0); -error_reporting(E_ALL); -$time_start = explode(' ', microtime()); - -//Handle crappy PHP magic: -if (get_magic_quotes_gpc()) { - function stripslashes_deep($value) { - $value = is_array($value) ? - array_map('stripslashes_deep', $value) : - stripslashes($value); - - return $value; - } - - $_POST = array_map('stripslashes_deep', $_POST); - $_GET = array_map('stripslashes_deep', $_GET); - $_COOKIE = array_map('stripslashes_deep', $_COOKIE); - $_REQUEST = array_map('stripslashes_deep', $_REQUEST); -} - -function htmlspecialchars_deep($value) { - return is_array($value) ? array_map('htmlspecialchars_deep', $value) : htmlspecialchars($value); -} - -define ('TYPE_NOTICE', 0); -define ('TYPE_WARNING', 1); -define ('TYPE_ERROR', 2); - -$error_abort = false; -$error_cache = array(); -function output_error_cache(){ - global $error_cache, $error_abort; - - if(count($error_cache)) { - echo "<span style=\"color: #F00; font-weight: bold;\">Failed</span><br />"; - echo "<ol>\n"; - foreach($error_cache as $error_msg) { - echo "<li>"; - switch($error_msg['t']) { - case TYPE_NOTICE: - echo "<span style=\"color: #080; font-weight: bold;\">NOTICE:</span>"; - break; - case TYPE_WARNING: - echo "<span style=\"color: #CC0; font-weight: bold;\">WARNING:</span>"; - break; - case TYPE_ERROR: - echo "<span style=\"color: #F00; font-weight: bold;\">ERROR:</span>"; - break; - } - echo " " . $error_msg['m'] . "</li>"; - } - echo "</ol>\n"; - } else { - echo "<span style=\"color: #080; font-weight: bold;\">OK</span><br />"; - } - echo "\n"; - - $error_cache = array(); -} - -function report_error($type, $message) { - global $error_cache, $error_abort; - - $error_cache[] = array('t' => $type, 'm' => $message); - if(TYPE_ERROR == $type) { - $error_abort = true; - } -} - -?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head> - <title>GeSHi Language File Generator Script</title> - <style type="text/css"> - <!-- - html { - background-color: #f0f0f0; - } - body { - font-family: Verdana, Arial, sans-serif; - margin: 10px; - border: 2px solid #e0e0e0; - background-color: #fcfcfc; - padding: 5px; - font-size: 10pt; - } - h2 { - margin: .1em 0 .2em .5em; - border-bottom: 1px solid #b0b0b0; - color: #b0b0b0; - font-weight: normal; - font-size: 150%; - } - h3 { - margin: .1em 0 .2em .5em; - color: #b0b0b0; - font-weight: normal; - font-size: 120%; - } - #footer { - text-align: center; - font-size: 80%; - color: #a9a9a9; - } - #footer a { - color: #9999ff; - } - textarea { - border: 1px solid #b0b0b0; - font-size: 90%; - color: #333; - margin-left: 20px; - } - select, input { - margin-left: 2px; - border: 1px solid #808080; - } - p { - font-size: 90%; - margin-left: .5em; - } - fieldset { - border: 1px dotted gray; - background-color: #f0f0f0; - margin-bottom: .5em; - } - legend { - font-weight: bold; - background-color: #f9f9f9; - border: 1px solid #a0a0a0; - border-width: 1px 2px 2px 1px; - } - fieldset table > tbody > tr > td { - width: 20%; - } - fieldset table > tbody > tr > td+td { - width: 80%; - } - - fieldset table > tbody > tr > td+td > input { - width: 98%; - } - --> - </style> -</head> -<body> -<h2>GeSHi Language File Generator Script</h2> -<p>To use this script, make sure that <strong>geshi.php</strong> is in the -parent directory or in your include_path, and that the language files are in a -subdirectory of GeSHi's directory called <strong>geshi/</strong>.</p> -<p>If not already done, select a language file below that will be used as -base for the language file to generate or create a blank one. Following this -you can do whatever you like to edit your language file. But note that not all -features are made available through this script.</p> - -<p>Checking GeSHi installation ... <?php -// Rudimentary checking of where GeSHi is. In a default install it will be in ../, but -// it could be in the current directory if the include_path is set. There's nowhere else -// we can reasonably guess. -if (is_readable('../geshi.php')) { - $path = '../'; -} elseif (is_readable('geshi.php')) { - $path = './'; -} else { - report_error(TYPE_ERROR, 'Could not find geshi.php - make sure it is in your include path!'); -} - -if(!$error_abort) { - require $path . 'geshi.php'; - - if(!class_exists('GeSHi')) { - report_error(TYPE_ERROR, 'The GeSHi class was not found, although it seemed we loaded the correct file!'); - } -} - -if(!$error_abort) { - if(!defined('GESHI_LANG_ROOT')) { - report_error(TYPE_ERROR, 'There\'s no information present on where to find the language files!'); - } elseif(!is_dir(GESHI_LANG_ROOT)) { - report_error(TYPE_ERROR, 'The path "'.GESHI_LANG_ROOT.'" given, does not ressemble a directory!'); - } elseif(!is_readable(GESHI_LANG_ROOT)) { - report_error(TYPE_ERROR, 'The path "'.GESHI_LANG_ROOT.'" is not readable to this script!'); - } -} - -if(!$error_abort) { - if (!($dir = @opendir(GESHI_LANG_ROOT))) { - report_error(TYPE_ERROR, 'Error requesting listing for available language files!'); - } - - $languages = array(); - - if(!$error_abort) { - while ($file = readdir($dir)) { - if (!$file || $file[0] == '.' || strpos($file, '.') === false) { - continue; - } - $lang = substr($file, 0, strpos($file, '.')); - $languages[] = $lang; - } - closedir($dir); - } - - $languages = array_unique($languages); - sort($languages); - - if(!count($languages)) { - report_error(TYPE_WARNING, 'Unable to locate any usable language files in "'.GESHI_LANG_ROOT.'"!'); - } -} - -output_error_cache(); - -// --- empty variables for values of $_POST - begin --- -$post_var_names = array('li', 'ai', 'ld'); - -$li = array( - 'file' => 'example', - 'name' => 'Example' - ); - -$ai = array( - 'name' => 'Benny Baumann', - 'email' => 'BenBE@geshi.org', - 'web' => 'http://qbnz.com/highlighter/' - ); - -$ld = array( - 'cmt' => array( - 'sl' => array( - 1 => array( - 'start' => '//', - 'style' => 'font-style: italic; color: #666666;' - ), - 2 => array( - 'start' => '#', - 'style' => 'font-style: italic; color: #666666;' - ) - ), - 'ml' => array( - 1 => array( - 'start' => '/*', - 'end' => '*/', - 'style' => 'font-style: italic; color: #666666;' - ), - 2 => array( - 'start' => '/**', - 'end' => '*/', - 'style' => 'font-style: italic; color: #006600;' - ) - ), - 'rxc' => array( - 1 => array( - 'rx' => '/Hello RegExp/', - 'style' => 'font-style: italic; color: #666666;' - ) - ) - ), - 'str' => array( - 'qm' => array( - 1 => array( - 'delim' => "'", - 'style' => 'color: #0000FF;' - ), - 2 => array( - 'delim' => """, - 'style' => 'color: #0000FF;' - ) - ), - 'ec' => array( - 'char' => '\\', - 'style' => 'font-weight: bold; color: #000080;' - ), - 'erx' => array( - 1 => array( - 'rx' => '/\{\\\\$\w+\}/', - 'style' => 'font-weight: bold; color: #008080;' - ), - 2 => array( - 'rx'=> '/\{\\\\$\w+\}/', - 'style' => 'font-weight: bold; color: #008080;' - ) - ) - ), - 'kw_case' => 'GESHI_CAPS_NO_CHANGE', - 'kw' => array( - 1 => array( - 'list' => '', - 'case' => '0', - 'style' => 'color: #0000FF; font-weight: bold;', - 'docs' => '' - ) - ), - 'sy' => array( - 0 => array( - 'list' => '', - 'style' => 'color: #0000FF; font-weight: bold;' - ) - ) - ); - -$kw_case_sel = array( - 'GESHI_CAPS_NO_CHANGE' => '', - 'GESHI_CAPS_UPPER' => '', - 'GESHI_CAPS_LOWER' => '' - ); - -$kw_cases_sel = array( - 1 => array( - 0 => '', - 1 => '' - ) - ); -// --- empty variables for values of $_POST - end --- - -echo "<pre>"; -//var_dump($languages); - -foreach($post_var_names as $varName) { // export wanted variables of $_POST array... - if(array_key_exists($varName, $_POST)) { - $$varName = htmlspecialchars_deep($_POST[$varName]); - } -} - -// determine the selected kw_case... -$kw_case_sel[$ld['kw_case']] = ' selected="selected"'; - -// determine the selected kw_cases... -for($i = 1; $i <= count($kw_cases_sel); $i += 1) { - $kw_cases_sel[$i][(int) $ld['kw'][$i]['case']] = ' selected="selected"'; -} - -$lang = validate_lang(); -var_dump($lang); -echo "</pre>"; - -?> - -<form action="?action=test" method="post"> - <fieldset> - <legend>Generic Information</legend> - - <table width="100%"> - <tr> - <td> - <label for="li[file]">Language File ID:</label> - </td> - <td> - <input type="text" name="li[file]" id="li[file]" value="<?=$li['file']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="li[name]">Language Name:</label> - </td> - <td> - <input type="text" name="li[name]" id="li[name]" value="<?=$li['name']; ?>" /> - </td> - </tr> - - </table> - </fieldset> - - <fieldset> - <legend>Author</legend> - - <table width="100%"> - <tr> - <td> - <label for="ai[name]">Full Name:</label> - </td> - <td> - <input type="text" name="ai[name]" id="ai[name]" value="<?=$ai['name']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ai[email]">eMail address:</label> - </td> - <td> - <input type="text" name="ai[email]" id="ai[email]" value="<?=$ai['email']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ai[web]">Homepage:</label> - </td> - <td> - <input type="text" name="ai[web]" id="ai[web]" value="<?=$ai['web']; ?>" /> - </td> - </tr> - </table> - </fieldset> - - <fieldset> - <legend>Comments</legend> - - <fieldset> - <legend>Single Line</legend> - - <fieldset> - <legend>Comment Group 1</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[cmt][sl][1][start]">Comment Start:</label> - </td> - <td> - <input type="text" name="ld[cmt][sl][1][start]" id="ld[cmt][sl][1][start]" value="<?=$ld['cmt']['sl'][1]['start']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[cmt][sl][1][style]">Comment Style:</label> - </td> - <td> - <input type="text" name="ld[cmt][sl][1][style]" id="ld[cmt][sl][1][style]" value="<?=$ld['cmt']['sl'][1]['style']; ?>" /> - </td> - </tr> - </table> - </fieldset> - - <fieldset> - <legend>Comment Group 2</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[cmt][sl][2][start]">Comment Start:</label> - </td> - <td> - <input type="text" name="ld[cmt][sl][2][start]" id="ld[cmt][sl][2][start]" value="<?=$ld['cmt']['sl'][2]['start']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[cmt][sl][2][style]">Comment Style:</label> - </td> - <td> - <input type="text" name="ld[cmt][sl][2][style]" id="ld[cmt][sl][2][style]" value="<?=$ld['cmt']['sl'][2]['style']; ?>" /> - </td> - </tr> - </table> - </fieldset> - </fieldset> - - <fieldset> - <legend>Multiple Lines</legend> - - <fieldset> - <legend>Comment Group 1</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[cmt][ml][1][start]">Comment Start:</label> - </td> - <td> - <input type="text" name="ld[cmt][ml][1][start]" id="ld[cmt][ml][1][start]" value="<?=$ld['cmt']['ml'][1]['start']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[cmt][ml][1][end]">Comment End:</label> - </td> - <td> - <input type="text" name="ld[cmt][ml][1][end]" id="ld[cmt][ml][1][end]" value="<?=$ld['cmt']['ml'][1]['end']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[cmt][ml][1][style]">Comment Style:</label> - </td> - <td> - <input type="text" name="ld[cmt][ml][1][style]" id="ld[cmt][ml][1][style]" value="<?=$ld['cmt']['ml'][1]['style']; ?>" /> - </td> - </tr> - </table> - </fieldset> - - <fieldset> - <legend>Comment Group 2</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[cmt][ml][2][start]">Comment Start:</label> - </td> - <td> - <input type="text" name="ld[cmt][ml][2][start]" id="ld[cmt][ml][2][start]" value="<?=$ld['cmt']['ml'][2]['start']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[cmt][ml][2][end]">Comment End:</label> - </td> - <td> - <input type="text" name="ld[cmt][ml][2][end]" id="ld[cmt][ml][2][end]" value="<?=$ld['cmt']['ml'][2]['end']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[cmt][ml][2][style]">Comment Style:</label> - </td> - <td> - <input type="text" name="ld[cmt][ml][2][style]" id="ld[cmt][ml][2][style]" value="<?=$ld['cmt']['ml'][2]['style']; ?>" /> - </td> - </tr> - </table> - </fieldset> - </fieldset> - - <fieldset> - <legend>Regular Expressions</legend> - - <fieldset> - <legend>Comment Group 1</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[cmt][rxc][1][rx]">Comment RX:</label> - </td> - <td> - <input type="text" name="ld[cmt][rxc][1][rx]" id="ld[cmt][rxc][1][rx]" value="<?=$ld['cmt']['rxc'][1]['rx']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[cmt][rxc][1][style]">Comment Style:</label> - </td> - <td> - <input type="text" name="ld[cmt][rxc][1][style]" id="ld[cmt][rxc][1][style]" value="<?=$ld['cmt']['rxc'][1]['style']; ?>" /> - </td> - </tr> - </table> - </fieldset> - </fieldset> - </fieldset> - - <fieldset> - <legend>Strings</legend> - - <fieldset> - <legend>String \ Quotes (delimiters, parsed)</legend> - - <fieldset> - <legend>Quotemark Group 1</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[str][qm][1][delim]">String Delimiter:</label> - </td> - <td> - <input type="text" name="ld[str][qm][1][delim]" id="ld[str][qm][1][delim]" value="<?=$ld['str']['qm'][1]['delim']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[str][qm][1][style]">String Style:</label> - </td> - <td> - <input type="text" name="ld[str][qm][1][style]" id="ld[str][qm][1][style]" value="<?=$ld['str']['qm'][1]['style']; ?>" /> - </td> - </tr> - </table> - </fieldset> - <fieldset> - <legend>Quotemark Group 2</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[str][qm][1][delim]">String Delimiter:</label> - </td> - <td> - <input type="text" name="ld[str][qm][2][delim]" id="ld[str][qm][2][delim]" value="<?=$ld['str']['qm'][2]['delim']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[str][qm][1][style]">String Style:</label> - </td> - <td> - <input type="text" name="ld[str][qm][2][style]" id="ld[str][qm][2][style]" value="<?=$ld['str']['qm'][2]['style']; ?>" /> - </td> - </tr> - </table> - </fieldset> - - - </fieldset> - - <fieldset> - <legend>Escape Sequences</legend> - - <fieldset> - <legend>Generic Escape Char</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[str][ec][char]">Escape Char:</label> - </td> - <td> - <input type="text" name="ld[str][ec][char]" id="ld[str][ec][char]" value="<?=$ld['str']['ec']['char']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[str][ec][style]">Escape Char Style:</label> - </td> - <td> - <input type="text" name="ld[str][ec][style]" id="ld[str][ec][style]" value="<?=$ld['str']['ec']['style']; ?>" /> - </td> - </tr> - </table> - </fieldset> - - <fieldset> - <legend>Escape Regexp Group 1</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[str][erx][1][rx]">Escape Regexp:</label> - </td> - <td> - <input type="text" name="ld[str][erx][1][rx]" id="ld[str][erx][1][rx]" value="<?=$ld['str']['erx'][1]['rx']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[str][erx][1][style]">Escape Style:</label> - </td> - <td> - <input type="text" name="ld[str][erx][1][style]" id="ld[str][erx][1][style]" value="<?=$ld['str']['erx'][1]['style']; ?>" /> - </td> - </tr> - </table> - </fieldset> - - <fieldset> - <legend>Escape Regexp Group 2</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[str][erx][2][rx]">Escape Regexp:</label> - </td> - <td> - <input type="text" name="ld[str][erx][2][rx]" id="ld[str][erx][2][rx]" value="<?=$ld['str']['erx'][2]['rx']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[str][erx][2][style]">Escape Style:</label> - </td> - <td> - <input type="text" name="ld[str][erx][2][style]" id="ld[str][erx][2][style]" value="<?=$ld['str']['erx'][2]['style']; ?>" /> - </td> - </tr> - </table> - </fieldset> - </fieldset> - </fieldset> - - <fieldset> - <legend>Keywords</legend> - - <fieldset> - <legend>Case of Keywords</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[kw_case]">Handling of keywords case:</label> - </td> - <td> - <select name=ld[kw_case]" id="ld[kw_case]"> - <option value="GESHI_CAPS_NO_CHANGE"<?=$kw_case_sel['GESHI_CAPS_NO_CHANGE']; ?>>Don’t change the case of any keyword</option> - <option value="GESHI_CAPS_UPPER"<?=$kw_case_sel['GESHI_CAPS_UPPER']; ?>>Convert the case of all keywords to upper case</option> - <option value="GESHI_CAPS_LOWER"<?=$kw_case_sel['GESHI_CAPS_LOWER']; ?>>Convert the case of all keywords to lower case</option> - </select> - </td> - </tr> - </table> - </fieldset> - - <fieldset> - <legend>Keyword Group 1</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[kw][1][list]">Keyword List:</label> - </td> - <td> - <textarea name="ld[kw][1][list]" id="ld[kw][1][list]" rows="10" cols="80"><?=$ld['kw'][1]['list']; ?></textarea> - </td> - </tr> - - <tr> - <td> - <label for="ld[kw][1][case]">Case Sensitive:</label> - </td> - <td> - <select name="ld[kw][1][case]" id="ld[kw][1][case]"> - <option value="0"<?=$kw_cases_sel[1][0]; ?>>No</option> - <option value="1"<?=$kw_cases_sel[1][1]; ?>>Yes</option> - </select> - </td> - </tr> - - <tr> - <td> - <label for="ld[kw][1][style]">Keyword Style:</label> - </td> - <td> - <input type="text" name="ld[kw][1][style]" id="ld[kw][1][style]" value="<?=$ld['kw'][1]['style']; ?>" /> - </td> - </tr> - - <tr> - <td> - <label for="ld[kw][1][docs]">Documentation URL:</label> - </td> - <td> - <input type="text" name="ld[kw][1][docs]" id="ld[kw][1][docs]" value="<?=$ld['kw'][1]['docs']; ?>" /> - </td> - </tr> - </table> - </fieldset> - - </fieldset> - - - <fieldset> - <legend>Symbols</legend> - - <fieldset> - <legend>Symbols Group 1</legend> - - <table width="100%"> - <tr> - <td> - <label for="ld[sy][0][list]">Symbols List:</label> - </td> - <td> - <textarea name="ld[sy][0][list]" id="ld[sy][0][list]" rows="10" cols="80"><?=$ld['sy'][0]['list']; ?></textarea> - </td> - </tr> - - <tr> - <td> - <label for="ld[sy][0][style]">Symbols Style:</label> - </td> - <td> - <input type="text" name="ld[sy][0][style]" id="ld[sy][0][style]" value="<?=$ld['sy'][0]['style']; ?>" /> - </td> - </tr> - </table> - </fieldset> - - </fieldset> - - - <div id="langfile"> - <fieldset> - <legend>Language File Source</legend> -<? -$G = new GeSHi('', 'php'); -$langfile_source = gen_langfile($lang); -$G->set_source($langfile_source); -echo $G->parse_code(); -unset($G); -?> - </fieldset> - </div> - - <input type="submit" name="btn" value="Send!" /> -</form> - -<p>Operation completed in <? -$time_end = explode(' ', microtime()); -$time_diff = $time_end[0] + $time_end[1] - $time_start[0] - $time_start[1]; - -echo sprintf("%.2f", $time_diff); -?> seconds.</p> - -<div id="footer">GeSHi © 2004-2007 Nigel McNie, 2007-2009 Benny Baumann, released under the GNU GPL</div> -</body> -</html> -<? - -function str_to_phpstring($str, $doublequote = false){ - if($doublequote) { - return '"' . strtr($str, - array( - "\"" => "\\\"", - "\\" => "\\\\", - "\0" => "\\0", - "\n" => "\\n", - "\r" => "\\r", - "\t" => "\\t", - "\$" => "\\\$" - ) - ) . '"'; - } else { - return "'" . strtr($str, - array( - "'" => "\\'", - "\\" => "\\\\" - ) - ) . "'"; - } -} - -function validate_lang(){ - $ai = array( - 'name' => 'Benny Baumann', - 'email' => 'BenBE@geshi.org', - 'web' => 'http://qbnz.com/highlighter/' - ); - - $li = array( - 'file' => 'example', - 'desc' => 'Example' - ); - - if(isset($_POST['ld'])) { - $ld = $_POST['ld']; - } else { - $ld = array( - 'cmt' => array( - 'sl' => array( - 1 => array( - 'start' => '//', - 'style' => 'test' - ) - ), - 'ml' => array( - 1 => array( - 'start' => '/*', - 'end' => '*/', - 'style' => 'font-style: italic; color: #666666;' - ) - ), - 'rxc' => array( - 1 => array( - 'rx' => '/Hello/', - 'style' => 'color: #00000' - ) - ) - ), - 'str' => array( - 'qm' => array(), - 'ec' => array( - 'char' => '' - ), - 'erx' => array() - ), - 'kw' => array(), - 'kw_case' => 'GESHI_CAPS_NO_CHANGE', - 'sy' => array() - ); - } - - return array('ai' => $ai, 'li' => $li, 'ld' => $ld); -} - -function gen_langfile($lang){ - $langfile = $lang['li']['file']; - $langdesc = $lang['li']['desc']; - - $langauthor_name = $lang['ai']['name']; - $langauthor_email = $lang['ai']['email']; - $langauthor_web = $lang['ai']['web']; - - $langversion = GESHI_VERSION; - - $langdate = date('Y/m/d'); - $langyear = date('Y'); - - $i = ' '; - $i = array('', $i, $i.$i, $i.$i.$i); - - $src = <<<GESHI_LANGFILE_HEAD -<?php -/************************************************************************************* - * {$langfile}.php - * -------- - * Author: {$langauthor_name} ({$langauthor_email}) - * Copyright: (c) {$langyear} {$langauthor_name} ({$langauthor_web}) - * Release Version: {$langversion} - * Date Started: {$langdate} - * - * {$langdesc} language file for GeSHi. - * - * CHANGES - * ------- - * {$langdate} ({$langversion}) - * - First Release - * - * TODO (updated {$langdate}) - * ------------------------- - * * Complete language file - * - ************************************************************************************* - * - * This file is part of GeSHi. - * - * GeSHi is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GeSHi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GeSHi; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ************************************************************************************/ - -\$language_data = array( - -GESHI_LANGFILE_HEAD; - - //Language Name - $src .= $i[1] . "'LANG_NAME' => ".str_to_phpstring($langdesc).",\n"; - - //Comments - $src .= $i[1] . "'COMMENT_SINGLE' => array(\n"; - foreach($lang['ld']['cmt']['sl'] as $idx_cmt_sl => $tmp_cmt_sl) { - $src .= $i[2] . ((int)$idx_cmt_sl). " => ". str_to_phpstring($tmp_cmt_sl['start']) . ",\n"; - } - $src .= $i[2] . "),\n"; - $src .= $i[1] . "'COMMENT_MULTI' => array(\n"; - foreach($lang['ld']['cmt']['ml'] as $tmp_cmt_ml) { - $src .= $i[2] . str_to_phpstring($tmp_cmt_ml['start']). " => ". str_to_phpstring($tmp_cmt_ml['end']) . ",\n"; - } - $src .= $i[2] . "),\n"; - $src .= $i[1] . "'COMMENT_REGEXP' => array(\n"; - foreach($lang['ld']['cmt']['rxc'] as $idx_cmt_rxc => $tmp_cmt_rxc) { - $src .= $i[2] . ((int)$idx_cmt_rxc). " => ". str_to_phpstring($tmp_cmt_rxc['rx']) . ",\n"; - } - $src .= $i[2] . "),\n"; - - //Case Keywords - $src .= $i[1] . "'CASE_KEYWORDS' => " . $lang['ld']['kw_case'] . ",\n"; - - //Quotes \ Strings - $src .= $i[1] . "'QUOTEMARKS' => array(\n"; - foreach($lang['ld']['str']['qm'] as $idx_str_qm => $tmp_str_qm) { - $src .= $i[2] . ((int)$idx_str_qm). " => ". str_to_phpstring($tmp_str_qm['delim']) . ",\n"; - } - $src .= $i[2] . "),\n"; - $src .= $i[1] . "'ESCAPE_CHAR' => " . str_to_phpstring($lang['ld']['str']['ec']['char']) . ",\n"; - $src .= $i[1] . "'ESCAPE_REGEXP' => array(\n"; - foreach($lang['ld']['str']['erx'] as $idx_str_erx => $tmp_str_erx) { - $src .= $i[2] . ((int)$idx_str_erx). " => ". str_to_phpstring($tmp_str_erx['rx']) . ",\n"; - } - $src .= $i[2] . "),\n"; - - //HardQuotes - $src .= $i[1] . "'HARDQUOTE' => array(\n"; - $src .= $i[2] . "),\n"; - $src .= $i[1] . "'HARDESCAPE' => array(\n"; - $src .= $i[2] . "),\n"; - $src .= $i[1] . "'HARDCHAR' => '',\n"; - - //Numbers - $src .= $i[1] . "'NUMBERS' =>\n"; - $src .= $i[2] . "GESHI_NUMBER_INT_BASIC | GESHI_NUMBER_OCT_PREFIX | GESHI_NUMBER_HEX_PREFIX |\n"; - $src .= $i[2] . "GESHI_NUMBER_FLT_SCI_ZERO,\n"; - - //Keywords - $src .= $i[1] . "'KEYWRODS' => array(\n"; - foreach($lang['ld']['kw'] as $idx_kw => $tmp_kw) { - $src .= $i[2] . ((int)$idx_kw) . " => array(\n"; - if(!is_array($tmp_kw['list'])) { - $tmp_kw['list'] = explode("\n", $tmp_kw['list']); - } - $tmp_kw['list'] = array_map('trim', $tmp_kw['list']); - sort($tmp_kw['list']); - $kw_esc = array_map('str_to_phpstring', $tmp_kw['list']); - $kw_nl = true; - $kw_pos = 0; - foreach($kw_esc as $kw_data) { - if((strlen($kw_data) + $kw_pos > 79) && $kw_pos > strlen($i[3])) { - $src .= "\n"; - $kw_nl = true; - $kw_pos = 0; - } - if($kw_nl) { - $src .= $i[3]; - $kw_pos += strlen($i[3]); - $kw_nl = false; - } - $src .= $kw_data . ', '; - $kw_pos += strlen($kw_data) + 2; - } - $src .= "\n"; - $src .= $i[3] . "),\n"; - } - $src .= $i[2] . "),\n"; - - //Case Sensitivity - $src .= $i[1] . "'CASE_SENSITIVE' => array(\n"; - foreach($lang['ld']['kw'] as $idx_kw => $tmp_kw) { - $src .= $i[2] . ((int)$idx_kw) . " => " . ($tmp_kw['case'] ? 'true' : 'false') . ",\n"; - } - $src .= $i[2] . "),\n"; - - //Symbols - $src .= $i[1] . "'SYMBOLS' => array(\n"; - foreach($lang['ld']['sy'] as $idx_kw => $tmp_kw) { - $src .= $i[2] . ((int)$idx_kw) . " => array(\n"; - $tmp_kw['list'] = (array)$tmp_kw['list']; - sort($tmp_kw['list']); - $kw_esc = array_map('str_to_phpstring', $tmp_kw['list']); - $kw_nl = true; - $kw_pos = strlen($i[3]); - foreach($kw_esc as $kw_data) { - if((strlen($kw_data) + $kw_pos > 79) && $kw_pos > strlen($i[3])) { - $src .= "\n"; - $kw_nl = true; - $kw_pos = 0; - } - if($kw_nl) { - $src .= $i[3]; - $kw_pos += strlen($i[3]); - $kw_nl = false; - } - $src .= $kw_data . ', '; - $kw_pos += strlen($kw_data) + 2; - } - $src .= "\n"; - $src .= $i[3] . "),\n"; - } - $src .= $i[2] . "),\n"; - - //Styles \ CSS - $src .= $i[1] . "'STYLES' => array(\n"; - $src .= $i[2] . "'KEYWRODS' => array(\n"; - foreach($lang['ld']['kw'] as $idx_kw => $tmp_kw) { - $src .= $i[3] . ((int)$idx_kw) . " => " . str_to_phpstring($tmp_kw['style']) . ",\n"; - } - $src .= $i[3] . "),\n"; - $src .= $i[2] . "'COMMENTS' => array(\n"; - foreach($lang['ld']['cmt']['sl'] as $idx_cmt_sl => $tmp_cmt_sl) { - $src .= $i[3] . ((int)$idx_cmt_sl) . " => " . str_to_phpstring($tmp_cmt_sl['style']) . ",\n"; - } - foreach($lang['ld']['cmt']['rxc'] as $idx_cmt_rxc => $tmp_cmt_rxc) { - $src .= $i[3] . ((int)$idx_cmt_rxc) . " => " . str_to_phpstring($tmp_cmt_rxc['style']) . ",\n"; - } - $src .= $i[3] . "'MULTI' => " . str_to_phpstring($lang['ld']['cmt']['ml'][1]['style']) . "\n"; - $src .= $i[3] . "),\n"; - $src .= $i[2] . "'ESCAPE_CHAR' => array(\n"; - foreach($lang['ld']['str']['erx'] as $idx_str_erx => $tmp_str_erx) { - $src .= $i[3] . ((int)$idx_str_erx). " => ". str_to_phpstring($tmp_str_erx['style']) . ",\n"; - } - // 'HARD' => 'color: #000099; font-weight: bold;' - $src .= $i[3] . "),\n"; - $src .= $i[2] . "'BRACKETS' => array(\n"; - $src .= $i[3] . "),\n"; - $src .= $i[2] . "'STRINGS' => array(\n"; - foreach($lang['ld']['str']['qm'] as $idx_str_qm => $tmp_str_qm) { - $src .= $i[3] . ((int)$idx_str_qm). " => ". str_to_phpstring($tmp_str_qm['style']) . ",\n"; - } - // 'HARD' => 'color: #0000ff;' - $src .= $i[3] . "),\n"; - $src .= $i[2] . "'NUMBERS' => array(\n"; - $src .= $i[3] . "),\n"; - $src .= $i[2] . "'METHODS' => array(\n"; - $src .= $i[3] . "),\n"; - $src .= $i[2] . "'SYMBOLS' => array(\n"; - foreach($lang['ld']['sy'] as $idx_kw => $tmp_kw) { - $src .= $i[3] . ((int)$idx_kw) . " => " . str_to_phpstring($tmp_kw['style']) . ",\n"; - } - $src .= $i[3] . "),\n"; - $src .= $i[2] . "'REGEXPS' => array(\n"; - $src .= $i[3] . "),\n"; - $src .= $i[2] . "'SCRIPT' => array(\n"; - $src .= $i[3] . "),\n"; - $src .= $i[2] . "),\n"; - - //Keyword Documentation - $src .= $i[1] . "'URLS' => array(\n"; - foreach($lang['ld']['kw'] as $idx_kw => $tmp_kw) { - $src .= $i[2] . ((int)$idx_kw) . " => " . str_to_phpstring($tmp_kw['docs']) . ",\n"; - } - $src .= $i[2] . "),\n"; - $src .= $i[1] . "'OOLANG' => false,\n"; - $src .= $i[1] . "'OBJECT_SPLITTERS' => array(\n"; - $src .= $i[2] . "),\n"; - $src .= $i[1] . "'REGEXPS' => array(\n"; - $src .= $i[2] . "),\n"; - $src .= $i[1] . "'STRICT_MODE_APPLIES' => GESHI_MAYBE,\n"; - $src .= $i[1] . "'SCRIPT_DELIMITERS' => array(\n"; - $src .= $i[2] . "),\n"; - $src .= $i[1] . "'HIGHLIGHT_STRICT_BLOCK' => array(\n"; - $src .= $i[2] . "),\n"; - $src .= $i[1] . "'TAB_WIDTH' => 4,\n"; - - $src .= <<<GESHI_LANGFILE_FOOTER -); - -?> -GESHI_LANGFILE_FOOTER; - - //Reduce source ... - $src = preg_replace('/array\(\s*\)/s', 'array()', $src); - $src = preg_replace('/\,(\s*\))/s', '\1', $src); - $src = preg_replace('/\s+$/m', '', $src); - - return $src; -} - -// vim: shiftwidth=4 softtabstop=4 -?> diff --git a/extensions/TitleBlacklist/.gitreview b/extensions/TitleBlacklist/.gitreview new file mode 100644 index 00000000..964229c3 --- /dev/null +++ b/extensions/TitleBlacklist/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/TitleBlacklist.git +defaultbranch=master diff --git a/extensions/TitleBlacklist/tests/ApiQueryTitleBlacklistTest.php b/extensions/TitleBlacklist/tests/ApiQueryTitleBlacklistTest.php new file mode 100644 index 00000000..1f8164e7 --- /dev/null +++ b/extensions/TitleBlacklist/tests/ApiQueryTitleBlacklistTest.php @@ -0,0 +1,110 @@ +<?php +/** + * Test the TitleBlacklist API. + * + * This wants to run with phpunit.php, like so: + * cd $IP/tests/phpunit + * php phpunit.php ../../extensions/TitleBlacklist/tests/ApiQueryTitleBlacklistTest.php + * + * The blacklist file is `testSource` and shared by all tests. + * + * Ian Baker <ian@wikimedia.org> + */ + +ini_set( 'include_path', ini_get( 'include_path' ) . ':' . __DIR__ . '/../../../tests/phpunit/includes/api' ); + +/** + * @group medium + **/ +class ApiQueryTitleBlacklistTest extends ApiTestCase { + + function setUp() { + global $wgTitleBlacklistSources; + parent::setUp(); + $this->doLogin(); + + $wgTitleBlacklistSources = array( + array( + 'type' => TBLSRC_FILE, + 'src' => __DIR__ . '/testSource', + ), + ); + } + + /** + * Verify we allow a title which is not blacklisted + */ + function testCheckingUnlistedTitle() { + $unlisted = $this->doApiRequest( array( + 'action' => 'titleblacklist', + // evil_acc is blacklisted as <newaccountonly> + 'tbtitle' => 'evil_acc', + 'tbaction' => 'create', + 'tbnooverride' => true, + ) ); + + $this->assertEquals( + 'ok', + $unlisted[0]['titleblacklist']['result'], + 'Not blacklisted title returns ok' + ); + } + + /** + * Verify tboverride works + */ + function testTboverride() { + global $wgGroupPermissions; + + // Allow all users to override the titleblacklist + $wgGroupPermissions['*']['tboverride'] = true; + + $unlisted = $this->doApiRequest( array( + 'action' => 'titleblacklist', + 'tbtitle' => 'bar', + 'tbaction' => 'create', + ) ); + + $this->assertEquals( + 'ok', + $unlisted[0]['titleblacklist']['result'], + 'Blacklisted title returns ok if the user is allowd to tboverride' + ); + } + + /** + * Verify a blacklisted title gives out an error. + */ + function testCheckingBlackListedTitle() { + $listed = $this->doApiRequest( array( + 'action' => 'titleblacklist', + 'tbtitle' => 'bar', + 'tbaction' => 'create', + 'tbnooverride' => true, + ) ); + + $this->assertEquals( + 'blacklisted', + $listed[0]['titleblacklist']['result'], + 'Listed title returns error' + ); + $this->assertEquals( + "The title \"bar\" has been banned from creation.\nIt matches the following blacklist entry: <code>[Bb]ar #example blacklist entry</code>", + $listed[0]['titleblacklist']['reason'], + 'Listed title error text is as expected' + ); + + $this->assertEquals( + "titleblacklist-forbidden-edit", + $listed[0]['titleblacklist']['message'], + 'Correct blacklist message name is returned' + ); + + $this->assertEquals( + "[Bb]ar #example blacklist entry", + $listed[0]['titleblacklist']['line'], + 'Correct blacklist line is returned' + ); + + } +} diff --git a/extensions/TitleBlacklist/tests/testSource b/extensions/TitleBlacklist/tests/testSource new file mode 100644 index 00000000..f73d9dd7 --- /dev/null +++ b/extensions/TitleBlacklist/tests/testSource @@ -0,0 +1,4 @@ +[Bb]ar #example blacklist entry +.*[Ff]ail.* +.*[Nn]yancat.* <errmsg=blacklisted-nyancat> +.*evil_acc.* <newaccountonly> diff --git a/extensions/Vector/.gitreview b/extensions/Vector/.gitreview new file mode 100644 index 00000000..8d06d24a --- /dev/null +++ b/extensions/Vector/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/Vector.git +defaultbranch=master diff --git a/extensions/WikiEditor/.gitreview b/extensions/WikiEditor/.gitreview new file mode 100644 index 00000000..622413f0 --- /dev/null +++ b/extensions/WikiEditor/.gitreview @@ -0,0 +1,6 @@ +[gerrit] +host=gerrit.wikimedia.org +port=29418 +project=mediawiki/extensions/WikiEditor.git +defaultbranch=master +defaultrebase=0 diff --git a/extensions/WikiEditor/.jshintignore b/extensions/WikiEditor/.jshintignore new file mode 100644 index 00000000..66a218b5 --- /dev/null +++ b/extensions/WikiEditor/.jshintignore @@ -0,0 +1,2 @@ +# upstream lib from Google +modules/contentCollector.js diff --git a/extensions/WikiEditor/.jshintrc b/extensions/WikiEditor/.jshintrc new file mode 100644 index 00000000..64cd5087 --- /dev/null +++ b/extensions/WikiEditor/.jshintrc @@ -0,0 +1,9 @@ +{ + "predef": [ + "mediaWiki", + "jQuery" + ], + "browser": true, + "smarttabs": true, + "multistr": true +} diff --git a/extensions/WikiEditor/tests/selenium/WikiDialogs_Links.php b/extensions/WikiEditor/tests/selenium/WikiDialogs_Links.php new file mode 100644 index 00000000..7153f49f --- /dev/null +++ b/extensions/WikiEditor/tests/selenium/WikiDialogs_Links.php @@ -0,0 +1,67 @@ +<?php +require_once 'WikiDialogs_Links_Setup.php'; +/** + * Description of WikiNewPageDialogs + * + * @author bhagyag, pdhanda + * + * This test case is part of the WikiEditorTestSuite. + * Configuration for these tests are dosumented as part of extensions/WikiEditor/tests/selenium/WikiEditorTestSuite.php + * + */ +class WikiDialogs_Links extends WikiDialogs_Links_Setup { + // Set up the testing environment + function setup() { + parent::setUp(); + parent::doCreateInternalTestPageIfMissing(); + } + + function tearDown() { + parent::doLogout(); + parent::tearDown(); + } + + // Create a new page temporary + function createNewPage() { + parent::doOpenLink(); + parent::login(); + parent::doCreateNewPageTemporary(); + } + + // Add a internal link and verify + function testInternalLink() { + $this->createNewPage(); + parent::verifyInternalLink(); + } + + // Add a internal link with different display text and verify + function testInternalLinkWithDisplayText() { + $this->createNewPage(); + parent::verifyInternalLinkWithDisplayText(); + } + + // Add a internal link with blank display text and verify + function testInternalLinkWithBlankDisplayText() { + $this->createNewPage(); + parent::verifyInternalLinkWithBlankDisplayText(); + } + + // Add external link and verify + function testExternalLink() { + $this->createNewPage(); + parent::verifyExternalLink(); + } + + // Add external link with different display text and verify + function testExternalLinkWithDisplayText( ) { + $this->createNewPage(); + parent::verifyExternalLinkWithDisplayText(); + } + + // Add external link with Blank display text and verify + function testExternalLinkWithBlankDisplayText() { + $this->createNewPage(); + parent::verifyExternalLinkWithBlankDisplayText(); + } + +} diff --git a/extensions/WikiEditor/tests/selenium/WikiDialogs_Links_Setup.php b/extensions/WikiEditor/tests/selenium/WikiDialogs_Links_Setup.php new file mode 100644 index 00000000..352ebec0 --- /dev/null +++ b/extensions/WikiEditor/tests/selenium/WikiDialogs_Links_Setup.php @@ -0,0 +1,295 @@ +<?php +include( "WikiEditorConstants.php" ); +/** + * This test case will be handling the Wiki Tool bar Dialog functions + * Date : Apr - 2010 + * @author : BhagyaG - Calcey + */ +class WikiDialogs_Links_Setup extends SeleniumTestCase { + + // Open the page. + function doOpenLink() { + $this->open( $this->getUrl() . '/index.php' ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + } + + // Expand advance tool bar section if its not + function doExpandAdvanceSection() { + if ( !$this->isTextPresent( TEXT_HEADING ) ) { + $this->click( LINK_ADVANCED ); + } + } + + // Log out from the application + function doLogout() { + $this->open( $this->getUrl() . '/index.php' ); + if ( $this->isTextPresent( TEXT_LOGOUT ) ) { + $this->click( LINK_LOGOUT ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertEquals( TEXT_LOGOUT_CONFIRM, $this->getText( LINK_LOGIN ) ); + $this->open( $this->getUrl() . '/index.php' ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + } + } + + // Create a temporary fixture page + function doCreateInternalTestPageIfMissing() { + $this->type( INPUT_SEARCH_BOX, WIKI_INTERNAL_LINK ); + $this->click( BUTTON_SEARCH ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->click( LINK_START . WIKI_INTERNAL_LINK ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $location = $this->getLocation() . "\n"; + if ( strpos( $location, '&redlink=1' ) !== false ) { + $this->type( TEXT_EDITOR, "Test fixture page. No real content here" ); + $this->click( BUTTON_SAVE_WATCH ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertTrue( $this->isTextPresent( WIKI_INTERNAL_LINK ), + $this->getText( TEXT_PAGE_HEADING ) ); + } + } + + // Create a temporary new page + function doCreateNewPageTemporary() { + $this->type( INPUT_SEARCH_BOX, WIKI_TEMP_NEWPAGE ); + $this->click( BUTTON_SEARCH ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->click( LINK_START . WIKI_TEMP_NEWPAGE ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + } + + // Add a internal link and verify + function verifyInternalLink() { + $this->type( TEXT_EDITOR, "" ); + $this->click( LINK_ADDLINK ); + $this->waitForPopup( 'addLink', WIKI_TEST_WAIT_TIME ); + $this->type( TEXT_LINKNAME, ( WIKI_INTERNAL_LINK ) ); + $this->assertTrue( $this->isElementPresent( ICON_PAGEEXISTS ), 'Element ' . ICON_PAGEEXISTS . 'Not found' ); + $this->assertEquals( "on", $this->getValue( OPT_INTERNAL ) ); + $this->click( BUTTON_INSERTLINK ); + $this->click( LINK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertEquals( ( WIKI_INTERNAL_LINK ), $this->getText( LINK_START . WIKI_INTERNAL_LINK ) ); + $this->click( LINK_START . WIKI_INTERNAL_LINK ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertTrue( $this->isTextPresent( WIKI_INTERNAL_LINK ), $this->getText( TEXT_PAGE_HEADING ) ); + } + + // Add a internal link with different display text and verify + function verifyInternalLinkWithDisplayText() { + $this->type( TEXT_EDITOR, "" ); + $this->click( LINK_ADDLINK ); + $this->waitForPopup( 'addLink', WIKI_TEST_WAIT_TIME ); + $this->type( TEXT_LINKNAME, WIKI_INTERNAL_LINK ); + $this->type ( TEXT_LINKDISPLAYNAME, WIKI_INTERNAL_LINK . TEXT_LINKDISPLAYNAME_APPENDTEXT ); + $this->assertTrue( $this->isElementPresent( ICON_PAGEEXISTS ) ); + $this->assertEquals( "on", $this->getValue( OPT_INTERNAL ) ); + $this->click( BUTTON_INSERTLINK ); + $this->click( LINK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertEquals( WIKI_INTERNAL_LINK . TEXT_LINKDISPLAYNAME_APPENDTEXT, + $this->getText( LINK_START . WIKI_INTERNAL_LINK . TEXT_LINKDISPLAYNAME_APPENDTEXT ) ); + $this->click( LINK_START . WIKI_INTERNAL_LINK . TEXT_LINKDISPLAYNAME_APPENDTEXT ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertTrue( $this->isTextPresent( WIKI_INTERNAL_LINK ), $this->getText( TEXT_PAGE_HEADING ) ); + + } + + // Add a internal link with blank display text and verify + function verifyInternalLinkWithBlankDisplayText() { + $this->type( TEXT_EDITOR, "" ); + $this->click( LINK_ADDLINK ); + $this->waitForPopup( 'addLink', WIKI_TEST_WAIT_TIME ); + $this->type( TEXT_LINKNAME, WIKI_INTERNAL_LINK ); + $this->type( TEXT_LINKDISPLAYNAME, "" ); + $this->assertTrue( $this->isElementPresent( ICON_PAGEEXISTS ) ); + $this->assertEquals( "on", $this->getValue( OPT_INTERNAL ) ); + $this->click( BUTTON_INSERTLINK ); + $this->click( LINK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertEquals( WIKI_INTERNAL_LINK, $this->getText( LINK_START . WIKI_INTERNAL_LINK ) ); + $this->click( LINK_START . WIKI_INTERNAL_LINK ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertEquals( WIKI_INTERNAL_LINK, $this->getText( TEXT_PAGE_HEADING ) ); + + } + + // Add external link and verify + function verifyExternalLink() { + $this->type( LINK_PREVIEW, "" ); + $this->click( LINK_ADDLINK ); + $this->type( TEXT_LINKNAME, WIKI_EXTERNAL_LINK ); + $this->assertTrue( $this->isElementPresent( ICON_PAGEEXTERNAL ) ); + $this->assertEquals( "on", $this->getValue( OPT_EXTERNAL ) ); + $this->click( BUTTON_INSERTLINK ); + $this->click( LINK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertEquals( WIKI_EXTERNAL_LINK, $this->getText( LINK_START . WIKI_EXTERNAL_LINK ) ); + + $this->click( LINK_START . WIKI_EXTERNAL_LINK ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertEquals( WIKI_EXTERNAL_LINK_TITLE, $this->getTitle() ); + } + + // Add external link with different display text and verify + function verifyExternalLinkWithDisplayText() { + $this->type( TEXT_EDITOR, "" ); + $this->click( LINK_ADDLINK ); + $this->type( TEXT_LINKNAME, WIKI_EXTERNAL_LINK ); + $this->type( TEXT_LINKDISPLAYNAME, WIKI_EXTERNAL_LINK_TITLE ); + $this->assertTrue( $this->isElementPresent( ICON_PAGEEXTERNAL ) ); + $this->assertEquals( "on", $this->getValue( OPT_EXTERNAL ) ); + $this->click( BUTTON_INSERTLINK ); + $this->click( LINK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertEquals( WIKI_EXTERNAL_LINK_TITLE, $this->getText( LINK_START . WIKI_EXTERNAL_LINK_TITLE ) ); + $this->click( LINK_START . ( WIKI_EXTERNAL_LINK_TITLE ) ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertEquals( WIKI_EXTERNAL_LINK_TITLE , $this->getTitle() ); + } + + // Add external link with Blank display text and verify + function verifyExternalLinkWithBlankDisplayText() { + $this->type( TEXT_EDITOR, "" ); + $this->click( LINK_ADDLINK ); + $this->type( TEXT_LINKNAME, WIKI_EXTERNAL_LINK ); + $this->type( TEXT_LINKDISPLAYNAME, "" ); + $this->assertTrue( $this->isElementPresent( ICON_PAGEEXTERNAL ) ); + $this->assertEquals( "on", $this->getValue( OPT_EXTERNAL ) ); + $this->click( BUTTON_INSERTLINK ); + $this->click( LINK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertEquals( "[1]", $this->getText( LINK_START . "[1]" ) ); + $this->click( LINK_START . "[1]" ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertEquals( WIKI_EXTERNAL_LINK_TITLE, $this->getTitle() ); + } + + // Add a table and verify + function verifyCreateTable() { + $WIKI_TABLE_ROW = 2; + $WIKI_TABLE_COL = "5"; + $this->doExpandAdvanceSection(); + $this->type( TEXT_EDITOR, "" ); + $this->click( LINK_ADDTABLE ); + $this->click( CHK_SORT ); + $this->type( TEXT_ROW, $WIKI_TABLE_ROW ); + $this->type( TEXT_COL, $WIKI_TABLE_COL ); + $this->click( BUTTON_INSERTABLE ); + $this->click( CHK_SORT ); + $this->click( LINK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $WIKI_TABLE_ROW = $WIKI_TABLE_ROW + 1; + $this->assertTrue( $this->isElementPresent( TEXT_TABLEID_OTHER . + TEXT_VALIDATE_TABLE_PART1 . $WIKI_TABLE_ROW . + TEXT_VALIDATE_TABLE_PART2 . $WIKI_TABLE_COL . + TEXT_VALIDATE_TABLE_PART3 ) ); + } + + // Add a table and verify only with head row + function verifyCreateTableWithHeadRow() { + $WIKI_TABLE_ROW = 3; + $WIKI_TABLE_COL = "4"; + $this->doExpandAdvanceSection(); + $this->type( TEXT_EDITOR, "" ); + $this->click( LINK_ADDTABLE ); + $this->click( CHK_BOARDER ); + $this->type( TEXT_ROW, $WIKI_TABLE_ROW ); + $this->type( TEXT_COL, $WIKI_TABLE_COL ); + $this->click( BUTTON_INSERTABLE ); + $this->click( LINK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $WIKI_TABLE_ROW = $WIKI_TABLE_ROW + 1; + $this->assertTrue( $this->isElementPresent( TEXT_TABLEID_OTHER . + TEXT_VALIDATE_TABLE_PART1 . $WIKI_TABLE_ROW . + TEXT_VALIDATE_TABLE_PART2 . $WIKI_TABLE_COL . + TEXT_VALIDATE_TABLE_PART3 ) ); + } + + // Add a table and verify only with borders + function verifyCreateTableWithBorders() { + $WIKI_TABLE_ROW = "4"; + $WIKI_TABLE_COL = "6"; + $this->type( TEXT_EDITOR, "" ); + $this->click( LINK_ADDTABLE ); + $this->click( CHK_HEADER ); + $this->type( TEXT_ROW, $WIKI_TABLE_ROW ); + $this->type( TEXT_COL, $WIKI_TABLE_COL ); + $this->click( BUTTON_INSERTABLE ); + $this->click( CHK_HEADER ); + $this->click( LINK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertTrue( $this->isElementPresent( TEXT_TABLEID_OTHER . + TEXT_VALIDATE_TABLE_PART1 . $WIKI_TABLE_ROW . + TEXT_VALIDATE_TABLE_PART2 . $WIKI_TABLE_COL . + TEXT_VALIDATE_TABLE_PART3 ) ); + } + + // Add a table and verify only with sort row + function verifyCreateTableWithSortRow() { + $WIKI_TABLE_ROW = "2"; + $WIKI_TABLE_COL = "5"; + $this->type( TEXT_EDITOR, "" ); + $this->click( LINK_ADDTABLE ); + $this->click( CHK_HEADER ); + $this->click( CHK_BOARDER ); + $this->click( CHK_SORT ); + $this->type( TEXT_ROW, $WIKI_TABLE_ROW ); + $this->type( TEXT_COL, $WIKI_TABLE_COL ); + $this->click( BUTTON_INSERTABLE ); + $this->click( CHK_HEADER ); + $this->click( CHK_BOARDER ); + $this->click( CHK_SORT ); + $this->click( LINK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertTrue( $this->isElementPresent( TEXT_TABLEID_WITHALLFEATURES . + TEXT_VALIDATE_TABLE_PART1 . $WIKI_TABLE_ROW . + TEXT_VALIDATE_TABLE_PART2 . $WIKI_TABLE_COL . + TEXT_VALIDATE_TABLE_PART3 ) ); + } + + // Add a table without headers,borders and sort rows + function verifyCreateTableWithNoSpecialEffects() { + $WIKI_TABLE_ROW = "6"; + $WIKI_TABLE_COL = "2"; + $this-> + $this->doExpandAdvanceSection(); + $this->type( TEXT_EDITOR, "" ); + $this->click( LINK_ADDTABLE ); + $this->click( CHK_BOARDER ); + $this->click( CHK_HEADER ); + $this->type( TEXT_ROW, $WIKI_TABLE_ROW ); + $this->type( TEXT_COL, $WIKI_TABLE_COL ); + $this->click( BUTTON_INSERTABLE ); + $this->click( CHK_BOARDER ); + $this->click( CHK_HEADER ); + $this->click( INK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $this->assertTrue( $this->isElementPresent( TEXT_TABLEID_OTHER . + TEXT_VALIDATE_TABLE_PART1 . $WIKI_TABLE_ROW . + TEXT_VALIDATE_TABLE_PART2 . $WIKI_TABLE_COL . + TEXT_VALIDATE_TABLE_PART3 ) ); + } + + // Add a table with headers,borders and sort rows + function verifyCreateTableWithAllSpecialEffects() { + $WIKI_TABLE_ROW = 6; + $WIKI_TABLE_COL = "2"; + $this->doExpandAdvanceSection(); + $this->type( TEXT_EDITOR, "" ); + $this->click( LINK_ADDTABLE ); + $this->click( CHK_SORT ); + $this->type( TEXT_ROW, $WIKI_TABLE_ROW ); + $this->type( TEXT_COL, $WIKI_TABLE_COL ); + $this->click( BUTTON_INSERTABLE ); + $this->click( CHK_SORT ); + $this->click( LINK_PREVIEW ); + $this->waitForPageToLoad( WIKI_TEST_WAIT_TIME ); + $WIKI_TABLE_ROW = $WIKI_TABLE_ROW + 1; + $this->assertTrue( $this->isElementPresent( TEXT_TABLEID_WITHALLFEATURES . + TEXT_VALIDATE_TABLE_PART1 . $WIKI_TABLE_ROW . + TEXT_VALIDATE_TABLE_PART2 . $WIKI_TABLE_COL . + TEXT_VALIDATE_TABLE_PART3 ) ); + } + +} diff --git a/extensions/WikiEditor/tests/selenium/WikiEditorConstants.php b/extensions/WikiEditor/tests/selenium/WikiEditorConstants.php new file mode 100644 index 00000000..090f96bf --- /dev/null +++ b/extensions/WikiEditor/tests/selenium/WikiEditorConstants.php @@ -0,0 +1,84 @@ +<?php +define ( 'WIKI_TEST_WAIT_TIME', "3000" ); // Waiting time + +// tool bar, buttons , links +// commonly using links +define ( 'LINK_MAIN_PAGE', "link=Main page" ); +define ( 'LINK_RANDOM_PAGE', "link=Random article" ); +define ( 'TEXT_PAGE_HEADING', "firstHeading" ); +define ( 'LINK_START', "link=" ); +define ( 'LINK_EDITPAGE', "//li[@id='ca-edit']/a/span" ); +define ( 'TEXT_EDITOR', "wpTextbox1" ); +define ( 'LINK_PREVIEW', "wpPreview" ); + +define ( 'WIKI_SEARCH_PAGE', "Hair (musical)" ); // Page name to search +define ( 'WIKI_TEXT_SEARCH', "TV" ); // Text to search +define ( 'WIKI_INTERNAL_LINK', "Wikieditor-Fixture-Page" ); // Exisiting page name to add as an internal tag +define ( 'WIKI_EXTERNAL_LINK', "www.google.com" ); // External web site name +define ( 'WIKI_EXTERNAL_LINK_TITLE', "Google" ); // Page title of the external web site name +define ( 'WIKI_CODE_PATH', getcwd() ); // get the current path of the program +define ( 'WIKI_SCREENSHOTS_PATH', "screenshots" ); // the folder the error screen shots will be saved +define ( 'WIKI_SCREENSHOTS_TYPE', "png" ); // screen print type +define ( 'WIKI_TEMP_NEWPAGE', "TestWikiPage" ); // temporary creating new page name +// for WikiCommonFunction_TC + +// for WikiSearch_TC +define ( 'INPUT_SEARCH_BOX', "searchInput" ); +define ( 'BUTTON_SEARCH', "mw-searchButton" ); +define ( 'TEXT_SEARCH_RESULT_HEADING', " - Search results - Wikipedia, the free encyclopedia" ); + +// for WikiWatchUnWatch_TC +define ( 'LINK_WATCH_PAGE', "link=Watch" ); +define ( 'LINK_WATCH_LIST', "link=My watchlist" ); +define ( 'LINK_WATCH_EDIT', "link=View and edit watchlist" ); +define ( 'LINK_UNWATCH', "link=Unwatch" ); +define ( 'BUTTON_WATCH', "wpWatchthis" ); +define ( 'BUTTON_SAVE_WATCH', "wpSave" ); +define ( 'TEXT_WATCH', "Watch" ); +define ( 'TEXT_UNWATCH', "Unwatch" ); + +// for WikiCommonFunction_TC +define ( 'TEXT_LOGOUT', "Log out" ); +define ( 'LINK_LOGOUT', "link=Log out" ); +define ( 'LINK_LOGIN', "link=Log in / create account" ); +define ( 'TEXT_LOGOUT_CONFIRM', "Log in / create account" ); +define ( 'INPUT_USER_NAME', "wpName1" ); +define ( 'INPUT_PASSWD', "wpPassword1" ); +define ( 'BUTTON_LOGIN', "wpLoginAttempt" ); +define ( 'TEXT_HEADING', "Heading" ); +define ( 'LINK_ADVANCED', "link=Advanced" ); + +// for WikiDialogs_TC +define ( 'LINK_ADDLINK', "//div[@id='wikiEditor-ui-toolbar']/div[1]/div[2]/span[2 ]" ); +define ( 'TEXT_LINKNAME', "wikieditor-toolbar-link-int-target" ); +define ( 'TEXT_LINKDISPLAYNAME', "wikieditor-toolbar-link-int-text" ); +define ( 'TEXT_LINKDISPLAYNAME_APPENDTEXT', " Test" ); +define ( 'ICON_PAGEEXISTS', "wikieditor-toolbar-link-int-target-status-exists" ); +define ( 'ICON_PAGEEXTERNAL', "wikieditor-toolbar-link-int-target-status-external" ); +define ( 'OPT_INTERNAL', "wikieditor-toolbar-link-type-int" ); +define ( 'OPT_EXTERNAL', "wikieditor-toolbar-link-type-ext" ); +define ( 'BUTTON_INSERTLINK', "//div[10]/div[11]/button[1]" ); +define ( 'LINK_ADDTABLE', "//div[@id='wikiEditor-ui-toolbar']/div[3]/div[1]/div[4]/span[2]" ); +define ( 'CHK_HEADER', "wikieditor-toolbar-table-dimensions-header" ); +define ( 'CHK_BOARDER', "wikieditor-toolbar-table-wikitable" ); +define ( 'CHK_SORT', "wikieditor-toolbar-table-sortable" ); +define ( 'TEXT_ROW', "wikieditor-toolbar-table-dimensions-rows" ); +define ( 'TEXT_COL', "wikieditor-toolbar-table-dimensions-columns" ); +define ( 'BUTTON_INSERTABLE', "//div[3]/button[1]" ); +define ( 'TEXT_HEADTABLE_TEXT', "Header text" ); +define ( 'TEXT_TABLEID_WITHALLFEATURES', "//table[@id='sortable_table_id_0']/tbody/" ); +define ( 'TEXT_TABLEID_OTHER', "//div[@id='wikiPreview']/table/tbody/" ); +define ( 'TEXT_VALIDATE_TABLE_PART1', "tr[" ); +define ( 'TEXT_VALIDATE_TABLE_PART2', "]/td[" ); +define ( 'TEXT_VALIDATE_TABLE_PART3', "]" ); +define ( 'LINK_SEARCH', "//div[@id='wikiEditor-ui-toolbar']/div[3]/div[1]/div[5]/span" ); +define ( 'INPUT_SEARCH', "wikieditor-toolbar-replace-search" ); +define ( 'INPUT_REPLACE', "wikieditor-toolbar-replace-replace" ); +define ( 'BUTTON_REPLACEALL', "//button[3]" ); +define ( 'BUTTON_REPLACENEXT', "//button[2]" ); +define ( 'BUTTON_CANCEL', "//button[4]" ); +define ( 'TEXT_PREVIEW_TEXT1', "//div[@id='wikiPreview']/p[1]" ); +define ( 'TEXT_PREVIEW_TEXT2', "//div[@id='wikiPreview']/p[2]" ); +define ( 'TEXT_PREVIEW_TEXT3', "//div[@id='wikiPreview']/p[3]" ); + + diff --git a/extensions/WikiEditor/tests/selenium/WikiEditorSeleniumConfig.php b/extensions/WikiEditor/tests/selenium/WikiEditorSeleniumConfig.php new file mode 100644 index 00000000..ad4be489 --- /dev/null +++ b/extensions/WikiEditor/tests/selenium/WikiEditorSeleniumConfig.php @@ -0,0 +1,27 @@ +<?php + +class WikiEditorSeleniumConfig { + + public static function getSettings( &$includeFiles, &$globalConfigs ) { + $includes = array( + 'extensions/Vector/Vector.php', + 'extensions/WikiEditor/WikiEditor.php' + ); + $configs = array( + 'wgDefaultSkin' => 'vector', + 'wgWikiEditorFeatures' => array( + 'toolbar' => array( 'global' => true, 'user' => true ), + 'toc' => array( 'global' => false, 'user' => false ), + 'highlight' => array( 'global' => false, 'user' => false ), + 'templateEditor' => array( 'global' => false, 'user' => false ), + 'dialogs' => array( 'global' => true, 'user' => true ) + ), + 'wgVectorFeatures' => array( + 'editwarning' => array( 'global' => false, 'user' => false ) + ) + ); + $includeFiles = array_merge( $includeFiles, $includes ); + $globalConfigs = array_merge( $globalConfigs, $configs ); + return true; + } +}
\ No newline at end of file diff --git a/extensions/WikiEditor/tests/selenium/WikiEditorTestSuite.php b/extensions/WikiEditor/tests/selenium/WikiEditorTestSuite.php new file mode 100644 index 00000000..b4029d3a --- /dev/null +++ b/extensions/WikiEditor/tests/selenium/WikiEditorTestSuite.php @@ -0,0 +1,35 @@ +<?php + +/** + * To configure MW for these tests + * 1) If you are running multiple test suites, add the following in LocalSettings.php + * require_once("extensions/WikiEditor/tests/selenium/WikiEditorSeleniumConfig.php"); + * $wgSeleniumTestConfigs['WikiEditorTestSuite'] = 'WikiEditorSeleniumConfig::getSettings'; + * OR + * 2) Add the following to your Localsettings.php + * require_once( "$IP/extensions/Vector/Vector.php" ); + * require_once( "$IP/extensions/WikiEditor/WikiEditor.php" ); + * $wgDefaultSkin = 'vector'; + * $wgVectorFeatures['editwarning'] = array( 'global' => false, 'user' => false ); + * $wgWikiEditorFeatures['templateEditor'] = array( 'global' => false, 'user' => false ); + * $wgWikiEditorFeatures['toolbar'] = array( 'global' => true, 'user' => true ); + * $wgWikiEditorFeatures['toc'] = array( 'global' => false, 'user' => false ); + * $wgWikiEditorFeatures['highlight'] = array( 'global' => false, 'user' => false ); + * $wgWikiEditorFeatures['dialogs'] = array( 'global' => true, 'user' => true ); + * + */ +class WikiEditorTestSuite extends SeleniumTestSuite +{ + public function setUp() { + $this->setLoginBeforeTests( false ); + parent::setUp(); + } + public function addTests() { + $testFiles = array( + 'extensions/WikiEditor/tests/selenium/WikiDialogs_Links.php' + ); + parent::addTestFiles( $testFiles ); + } + + +} diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 9d024c86..0e493eb0 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -63,7 +63,7 @@ $wgConf = new SiteConfiguration; * MediaWiki version number * @since 1.2 */ -$wgVersion = '1.21.1'; +$wgVersion = '1.21.2'; /** * Name of the site. It must be changed in LocalSettings.php diff --git a/includes/api/ApiBlock.php b/includes/api/ApiBlock.php index 90432b95..6f3d1e4f 100644 --- a/includes/api/ApiBlock.php +++ b/includes/api/ApiBlock.php @@ -42,12 +42,6 @@ class ApiBlock extends ApiBase { $user = $this->getUser(); $params = $this->extractRequestParams(); - if ( $params['gettoken'] ) { - $res['blocktoken'] = $user->getEditToken(); - $this->getResult()->addValue( null, $this->getModuleName(), $res ); - return; - } - if ( !$user->isAllowed( 'block' ) ) { $this->dieUsageMsg( 'cantblock' ); } @@ -156,10 +150,6 @@ class ApiBlock extends ApiBase { ApiBase::PARAM_REQUIRED => true ), 'token' => null, - 'gettoken' => array( - ApiBase::PARAM_DFLT => false, - ApiBase::PARAM_DEPRECATED => true, - ), 'expiry' => 'never', 'reason' => '', 'anononly' => false, @@ -177,7 +167,6 @@ class ApiBlock extends ApiBase { return array( 'user' => 'Username, IP address or IP range you want to block', 'token' => 'A block token previously obtained through prop=info', - 'gettoken' => 'If set, a block token will be returned, and no other action will be taken', 'expiry' => 'Relative expiry time, e.g. \'5 months\' or \'2 weeks\'. If set to \'infinite\', \'indefinite\' or \'never\', the block will never expire.', 'reason' => 'Reason for block', 'anononly' => 'Block anonymous users only (i.e. disable anonymous edits for this IP)', @@ -194,10 +183,6 @@ class ApiBlock extends ApiBase { public function getResultProperties() { return array( '' => array( - 'blocktoken' => array( - ApiBase::PROP_TYPE => 'string', - ApiBase::PROP_NULLABLE => true - ), 'user' => array( ApiBase::PROP_TYPE => 'string', ApiBase::PROP_NULLABLE => true diff --git a/includes/api/ApiCreateAccount.php b/includes/api/ApiCreateAccount.php index 55c60cce..69748c93 100644 --- a/includes/api/ApiCreateAccount.php +++ b/includes/api/ApiCreateAccount.php @@ -29,6 +29,10 @@ */ class ApiCreateAccount extends ApiBase { public function execute() { + // If we're in JSON callback mode, no tokens can be obtained + if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { + $this->dieUsage( 'Cannot create account when using a callback', 'aborted' ); + } // $loginForm->addNewaccountInternal will throw exceptions // if wiki is read only (already handled by api), user is blocked or does not have rights. diff --git a/includes/api/ApiLogin.php b/includes/api/ApiLogin.php index b936d3be..b51d441d 100644 --- a/includes/api/ApiLogin.php +++ b/includes/api/ApiLogin.php @@ -46,6 +46,15 @@ class ApiLogin extends ApiBase { * is reached. The expiry is $this->mLoginThrottle. */ public function execute() { + // If we're in JSON callback mode, no tokens can be obtained + if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { + $this->getResult()->addValue( null, 'login', array( + 'result' => 'Aborted', + 'reason' => 'Cannot log in when using a callback', + ) ); + return; + } + $params = $this->extractRequestParams(); $result = array(); diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php index 80bca2f6..7b2fd914 100644 --- a/includes/api/ApiMain.php +++ b/includes/api/ApiMain.php @@ -714,15 +714,9 @@ class ApiMain extends ApiBase { } $moduleParams = $module->extractRequestParams(); - // Die if token required, but not provided (unless there is a gettoken parameter) - if ( isset( $moduleParams['gettoken'] ) ) { - $gettoken = $moduleParams['gettoken']; - } else { - $gettoken = false; - } - + // Die if token required, but not provided $salt = $module->getTokenSalt(); - if ( $salt !== false && !$gettoken ) { + if ( $salt !== false ) { if ( !isset( $moduleParams['token'] ) ) { $this->dieUsageMsg( array( 'missingparam', 'token' ) ); } else { diff --git a/includes/api/ApiQueryDeletedrevs.php b/includes/api/ApiQueryDeletedrevs.php index 31ca1ef5..890e4ecf 100644 --- a/includes/api/ApiQueryDeletedrevs.php +++ b/includes/api/ApiQueryDeletedrevs.php @@ -57,6 +57,11 @@ class ApiQueryDeletedrevs extends ApiQueryBase { $fld_content = isset( $prop['content'] ); $fld_token = isset( $prop['token'] ); + // If we're in JSON callback mode, no tokens can be obtained + if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { + $fld_token = false; + } + $result = $this->getResult(); $pageSet = $this->getPageSet(); $titles = $pageSet->getTitles(); diff --git a/includes/api/ApiTokens.php b/includes/api/ApiTokens.php index 7080f547..d220a5e6 100644 --- a/includes/api/ApiTokens.php +++ b/includes/api/ApiTokens.php @@ -48,6 +48,11 @@ class ApiTokens extends ApiBase { } private function getTokenTypes() { + // If we're in JSON callback mode, no tokens can be obtained + if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { + return array(); + } + static $types = null; if ( $types ) { return $types; diff --git a/includes/api/ApiUnblock.php b/includes/api/ApiUnblock.php index 55e7331d..6a739a2f 100644 --- a/includes/api/ApiUnblock.php +++ b/includes/api/ApiUnblock.php @@ -39,12 +39,6 @@ class ApiUnblock extends ApiBase { $user = $this->getUser(); $params = $this->extractRequestParams(); - if ( $params['gettoken'] ) { - $res['unblocktoken'] = $user->getEditToken(); - $this->getResult()->addValue( null, $this->getModuleName(), $res ); - return; - } - if ( is_null( $params['id'] ) && is_null( $params['user'] ) ) { $this->dieUsageMsg( 'unblock-notarget' ); } @@ -96,10 +90,6 @@ class ApiUnblock extends ApiBase { ), 'user' => null, 'token' => null, - 'gettoken' => array( - ApiBase::PARAM_DFLT => false, - ApiBase::PARAM_DEPRECATED => true, - ), 'reason' => '', ); } @@ -110,7 +100,6 @@ class ApiUnblock extends ApiBase { 'id' => "ID of the block you want to unblock (obtained through list=blocks). Cannot be used together with {$p}user", 'user' => "Username, IP address or IP range you want to unblock. Cannot be used together with {$p}id", 'token' => "An unblock token previously obtained through prop=info", - 'gettoken' => 'If set, an unblock token will be returned, and no other action will be taken', 'reason' => 'Reason for unblock', ); } @@ -118,10 +107,6 @@ class ApiUnblock extends ApiBase { public function getResultProperties() { return array( '' => array( - 'unblocktoken' => array( - ApiBase::PROP_TYPE => 'string', - ApiBase::PROP_NULLABLE => true - ), 'id' => array( ApiBase::PROP_TYPE => 'integer', ApiBase::PROP_NULLABLE => true diff --git a/includes/filerepo/file/LocalFile.php b/includes/filerepo/file/LocalFile.php index 639228b9..4f50bfaa 100644 --- a/includes/filerepo/file/LocalFile.php +++ b/includes/filerepo/file/LocalFile.php @@ -1484,6 +1484,7 @@ class LocalFile extends File { * @return FileRepoStatus object. */ function delete( $reason, $suppress = false ) { + global $wgUseSquid; if ( $this->getRepo()->getReadOnlyReason() !== false ) { return $this->readOnlyFatalStatus(); } @@ -1506,6 +1507,15 @@ class LocalFile extends File { $this->purgeOldThumbnails( $archiveName ); } + if ( $wgUseSquid ) { + // Purge the squid + $purgeUrls = array(); + foreach ($archiveNames as $archiveName ) { + $purgeUrls[] = $this->getArchiveUrl( $archiveName ); + } + SquidUpdate::purge( $purgeUrls ); + } + return $status; } @@ -1524,6 +1534,7 @@ class LocalFile extends File { * @return FileRepoStatus object. */ function deleteOld( $archiveName, $reason, $suppress = false ) { + global $wgUseSquid; if ( $this->getRepo()->getReadOnlyReason() !== false ) { return $this->readOnlyFatalStatus(); } @@ -1541,6 +1552,11 @@ class LocalFile extends File { $this->purgeHistory(); } + if ( $wgUseSquid ) { + // Purge the squid + SquidUpdate::purge( array( $this->getArchiveUrl( $archiveName ) ) ); + } + return $status; } diff --git a/includes/installer/Installer.php b/includes/installer/Installer.php index 4d8e5f0d..9fd67c93 100644 --- a/includes/installer/Installer.php +++ b/includes/installer/Installer.php @@ -46,6 +46,14 @@ abstract class Installer { */ protected $settings; + + /** + * List of detected DBs, access using getCompiledDBs(). + * + * @var array + */ + protected $compiledDBs; + /** * Cached DB installer instances, access using getDBInstaller(). * @@ -173,7 +181,6 @@ abstract class Installer { protected $internalDefaults = array( '_UserLang' => 'en', '_Environment' => false, - '_CompiledDBs' => array(), '_SafeMode' => false, '_RaiseMemory' => false, '_UpgradeDone' => false, @@ -368,7 +375,7 @@ abstract class Installer { } } } - $this->setVar( '_CompiledDBs', $compiledDBs ); + $this->compiledDBs = $compiledDBs; $this->parserTitle = Title::newFromText( 'Installer' ); $this->parserOptions = new ParserOptions; // language will be wrong :( @@ -450,6 +457,15 @@ abstract class Installer { } /** + * Get a list of DBs supported by current PHP setup + * + * @return array + */ + public function getCompiledDBs() { + return $this->compiledDBs; + } + + /** * Get an instance of DatabaseInstaller for the specified DB type. * * @param $type Mixed: DB installer for which is needed, false to use default. @@ -647,13 +663,7 @@ abstract class Installer { $allNames[] = wfMessage( "config-type-$name" )->text(); } - // cache initially available databases to make sure that everything will be displayed correctly - // after a refresh on env checks page - $databases = $this->getVar( '_CompiledDBs-preFilter' ); - if ( !$databases ) { - $databases = $this->getVar( '_CompiledDBs' ); - $this->setVar( '_CompiledDBs-preFilter', $databases ); - } + $databases = $this->getCompiledDBs(); $databases = array_flip ( $databases ); foreach ( array_keys( $databases ) as $db ) { @@ -672,7 +682,6 @@ abstract class Installer { // @todo FIXME: This only works for the web installer! return false; } - $this->setVar( '_CompiledDBs', $databases ); return true; } diff --git a/includes/installer/MysqlUpdater.php b/includes/installer/MysqlUpdater.php index 9d73e629..030c57fc 100644 --- a/includes/installer/MysqlUpdater.php +++ b/includes/installer/MysqlUpdater.php @@ -200,9 +200,9 @@ class MysqlUpdater extends DatabaseUpdater { // 1.19 array( 'addIndex', 'logging', 'type_action', 'patch-logging-type-action-index.sql'), + array( 'addField', 'revision', 'rev_sha1', 'patch-rev_sha1.sql' ), array( 'doMigrateUserOptions' ), array( 'dropField', 'user', 'user_options', 'patch-drop-user_options.sql' ), - array( 'addField', 'revision', 'rev_sha1', 'patch-rev_sha1.sql' ), array( 'addField', 'archive', 'ar_sha1', 'patch-ar_sha1.sql' ), array( 'addIndex', 'page', 'page_redirect_namespace_len', 'patch-page_redirect_namespace_len.sql' ), array( 'addField', 'uploadstash', 'us_chunk_inx', 'patch-uploadstash_chunk.sql' ), diff --git a/includes/installer/WebInstallerPage.php b/includes/installer/WebInstallerPage.php index 78830293..06d16a5a 100644 --- a/includes/installer/WebInstallerPage.php +++ b/includes/installer/WebInstallerPage.php @@ -462,7 +462,7 @@ class WebInstaller_DBConnect extends WebInstallerPage { // It's possible that the library for the default DB type is not compiled in. // In that case, instead select the first supported DB type in the list. - $compiledDBs = $this->parent->getVar( '_CompiledDBs' ); + $compiledDBs = $this->parent->getCompiledDBs(); if ( !in_array( $defaultType, $compiledDBs ) ) { $defaultType = $compiledDBs[0]; } diff --git a/includes/libs/IEUrlExtension.php b/includes/libs/IEUrlExtension.php index 79387e63..49d05d4b 100644 --- a/includes/libs/IEUrlExtension.php +++ b/includes/libs/IEUrlExtension.php @@ -232,7 +232,7 @@ class IEUrlExtension { } // We found an illegal character or another dot // Skip to that character and continue the loop - $pos = $nextPos + 1; + $pos = $nextPos; $remainingLength = $urlLength - $pos; } return false; diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index 27f682c2..4e047be4 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -175,7 +175,7 @@ class ResourceLoader { $cache->set( $key, $result ); } catch ( Exception $exception ) { // Return exception as a comment - $result = $this->makeComment( $exception->__toString() ); + $result = $this->formatException( $exception ); $this->hasErrors = true; } @@ -461,7 +461,7 @@ class ResourceLoader { $this->preloadModuleInfo( array_keys( $modules ), $context ); } catch( Exception $e ) { // Add exception to the output as a comment - $errors .= $this->makeComment( $e->__toString() ); + $errors .= $this->formatException( $e ); $this->hasErrors = true; } @@ -479,7 +479,7 @@ class ResourceLoader { $mtime = max( $mtime, $module->getModifiedTime( $context ) ); } catch ( Exception $e ) { // Add exception to the output as a comment - $errors .= $this->makeComment( $e->__toString() ); + $errors .= $this->formatException( $e ); $this->hasErrors = true; } } @@ -663,6 +663,22 @@ class ResourceLoader { } /** + * Handle exception display + * + * @param Exception $e to be shown to the user + * @return string sanitized text that can be returned to the user + */ + protected function formatException( $e ) { + global $wgShowExceptionDetails; + + if ( $wgShowExceptionDetails ) { + return $this->makeComment( $e->__toString() ); + } else { + return $this->makeComment( wfMessage( 'internalerror' )->text() ); + } + } + + /** * Generates code for a response * * @param $context ResourceLoaderContext: Context in which to generate a response @@ -686,7 +702,7 @@ class ResourceLoader { $blobs = MessageBlobStore::get( $this, $modules, $context->getLanguage() ); } catch ( Exception $e ) { // Add exception to the output as a comment - $exceptions .= $this->makeComment( $e->__toString() ); + $exceptions .= $this->formatException( $e ); $this->hasErrors = true; } } else { @@ -792,7 +808,7 @@ class ResourceLoader { } } catch ( Exception $e ) { // Add exception to the output as a comment - $exceptions .= $this->makeComment( $e->__toString() ); + $exceptions .= $this->formatException( $e ); $this->hasErrors = true; // Register module as missing diff --git a/includes/revisiondelete/RevisionDelete.php b/includes/revisiondelete/RevisionDelete.php index 1ace3836..f4c07968 100644 --- a/includes/revisiondelete/RevisionDelete.php +++ b/includes/revisiondelete/RevisionDelete.php @@ -499,9 +499,20 @@ class RevDel_FileList extends RevDel_List { } public function doPostCommitUpdates() { + global $wgUseSquid; $file = wfLocalFile( $this->title ); $file->purgeCache(); $file->purgeDescription(); + $purgeUrls = array(); + foreach ( $this->ids as $timestamp ) { + $archiveName = $timestamp . '!' . $this->title->getDBkey(); + $file->purgeOldThumbnails( $archiveName ); + $purgeUrls[] = $file->getArchiveUrl( $archiveName ); + } + if ( $wgUseSquid ) { + // purge full images from cache + SquidUpdate::purge( $purgeUrls ); + } return Status::newGood(); } diff --git a/includes/zhtable/trad2simp_supp_unset.manual b/maintenance/language/zhtable/trad2simp_supp_unset.manual index e69de29b..e69de29b 100644 --- a/includes/zhtable/trad2simp_supp_unset.manual +++ b/maintenance/language/zhtable/trad2simp_supp_unset.manual diff --git a/maintenance/postgres/archives/patch-ipb_address_unique.sql b/maintenance/postgres/archives/patch-ipb_address_unique.sql deleted file mode 100644 index e69de29b..00000000 --- a/maintenance/postgres/archives/patch-ipb_address_unique.sql +++ /dev/null diff --git a/skins/common/images/icons/fileicon-djvu.xcf b/skins/common/images/icons/fileicon-djvu.xcf Binary files differnew file mode 100644 index 00000000..8043dcdb --- /dev/null +++ b/skins/common/images/icons/fileicon-djvu.xcf diff --git a/skins/common/images/icons/fileicon-ogg.xcf b/skins/common/images/icons/fileicon-ogg.xcf Binary files differnew file mode 100644 index 00000000..a91024bf --- /dev/null +++ b/skins/common/images/icons/fileicon-ogg.xcf diff --git a/tests/.htaccess b/tests/.htaccess new file mode 100644 index 00000000..3a428827 --- /dev/null +++ b/tests/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/tests/RunSeleniumTests.php b/tests/RunSeleniumTests.php new file mode 100644 index 00000000..b7320cb1 --- /dev/null +++ b/tests/RunSeleniumTests.php @@ -0,0 +1,258 @@ +#!/usr/bin/env php +<?php +/** + * @file + * @ingroup Maintenance + * @copyright Copyright © Wikimedia Deuschland, 2009 + * @author Hallo Welt! Medienwerkstatt GmbH + * @author Markus Glaser, Dan Nessett, Priyanka Dhanda + * initial idea by Daniel Kinzler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + */ + +if ( PHP_SAPI != 'cli' ) { + die( "Run me from the command line please.\n" ); +} + +define( 'SELENIUMTEST', true ); + +require( __DIR__ . '/../maintenance/Maintenance.php' ); + +require_once( 'PHPUnit/Runner/Version.php' ); +if ( version_compare( PHPUnit_Runner_Version::id(), '3.5.0', '>=' ) ) { + # PHPUnit 3.5.0 introduced a nice autoloader based on class name + require_once( 'PHPUnit/Autoload.php' ); +} else { + # Keep the old pre PHPUnit 3.5.0 behavior for compatibility + require_once( 'PHPUnit/TextUI/Command.php' ); +} + +require_once( 'PHPUnit/Extensions/SeleniumTestCase.php' ); +include_once( 'PHPUnit/Util/Log/JUnit.php' ); + +require_once( __DIR__ . "/selenium/SeleniumServerManager.php" ); + +class SeleniumTester extends Maintenance { + protected $selenium; + protected $serverManager; + protected $seleniumServerExecPath; + + public function __construct() { + parent::__construct(); + $this->mDescription = "Selenium Test Runner. For documentation, visit http://www.mediawiki.org/wiki/SeleniumFramework"; + $this->addOption( 'port', 'Port used by selenium server. Default: 4444', false, true ); + $this->addOption( 'host', 'Host selenium server. Default: $wgServer . $wgScriptPath', false, true ); + $this->addOption( 'testBrowser', 'The browser used during testing. Default: firefox', false, true ); + $this->addOption( 'wikiUrl', 'The Mediawiki installation to point to. Default: http://localhost', false, true ); + $this->addOption( 'username', 'The login username for sunning tests. Default: empty', false, true ); + $this->addOption( 'userPassword', 'The login password for running tests. Default: empty', false, true ); + $this->addOption( 'seleniumConfig', 'Location of the selenium config file. Default: empty', false, true ); + $this->addOption( 'list-browsers', 'List the available browsers.' ); + $this->addOption( 'verbose', 'Be noisier.' ); + $this->addOption( 'startserver', 'Start Selenium Server (on localhost) before the run.' ); + $this->addOption( 'stopserver', 'Stop Selenium Server (on localhost) after the run.' ); + $this->addOption( 'jUnitLogFile', 'Log results in a specified JUnit log file. Default: empty', false, true ); + $this->addOption( 'runAgainstGrid', 'The test will be run against a Selenium Grid. Default: false.', false, true ); + $this->deleteOption( 'dbpass' ); + $this->deleteOption( 'dbuser' ); + $this->deleteOption( 'globals' ); + $this->deleteOption( 'wiki' ); + } + + public function listBrowsers() { + $desc = "Available browsers:\n"; + + foreach ( $this->selenium->getAvailableBrowsers() as $k => $v ) { + $desc .= " $k => $v\n"; + } + + echo $desc; + } + + protected function startServer() { + if ( $this->seleniumServerExecPath == '' ) { + die ( "The selenium server exec path is not set in " . + "selenium_settings.ini. Cannot start server \n" . + "as requested - terminating RunSeleniumTests\n" ); + } + $this->serverManager = new SeleniumServerManager( 'true', + $this->selenium->getPort(), + $this->seleniumServerExecPath ); + switch ( $this->serverManager->start() ) { + case 'started': + break; + case 'failed': + die ( "Unable to start the Selenium Server - " . + "terminating RunSeleniumTests\n" ); + case 'running': + echo ( "Warning: The Selenium Server is " . + "already running\n" ); + break; + } + + return; + } + + protected function stopServer() { + if ( !isset ( $this->serverManager ) ) { + echo ( "Warning: Request to stop Selenium Server, but it was " . + "not stared by RunSeleniumTests\n" . + "RunSeleniumTests cannot stop a Selenium Server it " . + "did not start\n" ); + } else { + switch ( $this->serverManager->stop() ) { + case 'stopped': + break; + case 'failed': + echo ( "unable to stop the Selenium Server\n" ); + } + } + return; + } + + protected function runTests( $seleniumTestSuites = array() ) { + $result = new PHPUnit_Framework_TestResult; + $result->addListener( new SeleniumTestListener( $this->selenium->getLogger() ) ); + if ( $this->selenium->getJUnitLogFile() ) { + $jUnitListener = new PHPUnit_Util_Log_JUnit( $this->selenium->getJUnitLogFile(), true ); + $result->addListener( $jUnitListener ); + } + + foreach ( $seleniumTestSuites as $testSuiteName => $testSuiteFile ) { + require( $testSuiteFile ); + $suite = new $testSuiteName(); + $suite->setName( $testSuiteName ); + $suite->addTests(); + + try { + $suite->run( $result ); + } catch ( Testing_Selenium_Exception $e ) { + $suite->tearDown(); + throw new MWException( $e->getMessage() ); + } + } + + if ( $this->selenium->getJUnitLogFile() ) { + $jUnitListener->flush(); + } + } + + public function execute() { + global $wgServer, $wgScriptPath, $wgHooks; + + $seleniumSettings = array(); + $seleniumBrowsers = array(); + $seleniumTestSuites = array(); + + $configFile = $this->getOption( 'seleniumConfig', '' ); + if ( strlen( $configFile ) > 0 ) { + $this->output( "Using Selenium Configuration file: " . $configFile . "\n" ); + SeleniumConfig::getSeleniumSettings( $seleniumSettings, + $seleniumBrowsers, + $seleniumTestSuites, + $configFile ); + } elseif ( !isset( $wgHooks['SeleniumSettings'] ) ) { + $this->output( "No command line, configuration file or configuration hook found.\n" ); + SeleniumConfig::getSeleniumSettings( $seleniumSettings, + $seleniumBrowsers, + $seleniumTestSuites + ); + } else { + $this->output( "Using 'SeleniumSettings' hook for configuration.\n" ); + wfRunHooks( 'SeleniumSettings', array( $seleniumSettings, + $seleniumBrowsers, + $seleniumTestSuites ) ); + } + + // State for starting/stopping the Selenium server has nothing to do with the Selenium + // class. Keep this state local to SeleniumTester class. Using getOption() is clumsy, but + // the Maintenance class does not have a setOption() + if ( !isset( $seleniumSettings['startserver'] ) ) { + $this->getOption( 'startserver', true ); + } + if ( !isset( $seleniumSettings['stopserver'] ) ) { + $this->getOption( 'stopserver', true ); + } + if ( !isset( $seleniumSettings['seleniumserverexecpath'] ) ) { + $seleniumSettings['seleniumserverexecpath'] = ''; + } + $this->seleniumServerExecPath = $seleniumSettings['seleniumserverexecpath']; + + //set reasonable defaults if we did not find the settings + if ( !isset( $seleniumBrowsers ) ) { + $seleniumBrowsers = array( 'firefox' => '*firefox' ); + } + if ( !isset( $seleniumSettings['host'] ) ) { + $seleniumSettings['host'] = $wgServer . $wgScriptPath; + } + if ( !isset( $seleniumSettings['port'] ) ) { + $seleniumSettings['port'] = '4444'; + } + if ( !isset( $seleniumSettings['wikiUrl'] ) ) { + $seleniumSettings['wikiUrl'] = 'http://localhost'; + } + if ( !isset( $seleniumSettings['username'] ) ) { + $seleniumSettings['username'] = ''; + } + if ( !isset( $seleniumSettings['userPassword'] ) ) { + $seleniumSettings['userPassword'] = ''; + } + if ( !isset( $seleniumSettings['testBrowser'] ) ) { + $seleniumSettings['testBrowser'] = 'firefox'; + } + if ( !isset( $seleniumSettings['jUnitLogFile'] ) ) { + $seleniumSettings['jUnitLogFile'] = false; + } + if ( !isset( $seleniumSettings['runAgainstGrid'] ) ) { + $seleniumSettings['runAgainstGrid'] = false; + } + + // Setup Selenium class + $this->selenium = new Selenium(); + $this->selenium->setAvailableBrowsers( $seleniumBrowsers ); + $this->selenium->setRunAgainstGrid( $this->getOption( 'runAgainstGrid', $seleniumSettings['runAgainstGrid'] ) ); + $this->selenium->setUrl( $this->getOption( 'wikiUrl', $seleniumSettings['wikiUrl'] ) ); + $this->selenium->setBrowser( $this->getOption( 'testBrowser', $seleniumSettings['testBrowser'] ) ); + $this->selenium->setPort( $this->getOption( 'port', $seleniumSettings['port'] ) ); + $this->selenium->setHost( $this->getOption( 'host', $seleniumSettings['host'] ) ); + $this->selenium->setUser( $this->getOption( 'username', $seleniumSettings['username'] ) ); + $this->selenium->setPass( $this->getOption( 'userPassword', $seleniumSettings['userPassword'] ) ); + $this->selenium->setVerbose( $this->hasOption( 'verbose' ) ); + $this->selenium->setJUnitLogFile( $this->getOption( 'jUnitLogFile', $seleniumSettings['jUnitLogFile'] ) ); + + if ( $this->hasOption( 'list-browsers' ) ) { + $this->listBrowsers(); + exit( 0 ); + } + if ( $this->hasOption( 'startserver' ) ) { + $this->startServer(); + } + + $logger = new SeleniumTestConsoleLogger; + $this->selenium->setLogger( $logger ); + + $this->runTests( $seleniumTestSuites ); + + if ( $this->hasOption( 'stopserver' ) ) { + $this->stopServer(); + } + } +} + +$maintClass = "SeleniumTester"; + +require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/tests/TestsAutoLoader.php b/tests/TestsAutoLoader.php new file mode 100644 index 00000000..c1c301f6 --- /dev/null +++ b/tests/TestsAutoLoader.php @@ -0,0 +1,104 @@ +<?php +/** + * AutoLoader for the testing suite. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Testing + */ + +global $wgAutoloadClasses; +$testDir = __DIR__; + +$wgAutoloadClasses += array( + + # tests + 'DbTestPreviewer' => "$testDir/testHelpers.inc", + 'DbTestRecorder' => "$testDir/testHelpers.inc", + 'DelayedParserTest' => "$testDir/testHelpers.inc", + 'TestFileIterator' => "$testDir/testHelpers.inc", + 'TestRecorder' => "$testDir/testHelpers.inc", + + # tests/phpunit + 'MediaWikiTestCase' => "$testDir/phpunit/MediaWikiTestCase.php", + 'MediaWikiPHPUnitCommand' => "$testDir/phpunit/MediaWikiPHPUnitCommand.php", + 'MediaWikiLangTestCase' => "$testDir/phpunit/MediaWikiLangTestCase.php", + 'MediaWikiProvide' => "$testDir/phpunit/includes/Providers.php", + 'TestUser' => "$testDir/phpunit/includes/TestUser.php", + + # tests/phpunit/includes + 'BlockTest' => "$testDir/phpunit/includes/BlockTest.php", + 'RevisionStorageTest' => "$testDir/phpunit/includes/RevisionStorageTest.php", + 'WikiPageTest' => "$testDir/phpunit/includes/WikiPageTest.php", + + //db + 'ORMTableTest' => "$testDir/phpunit/includes/db/ORMTableTest.php", + 'PageORMTableForTesting' => "$testDir/phpunit/includes/db/ORMTableTest.php", + + //Selenium + 'SeleniumTestConstants' => "$testDir/selenium/SeleniumTestConstants.php", + + # tests/phpunit/includes/api + 'ApiFormatTestBase' => "$testDir/phpunit/includes/api/format/ApiFormatTestBase.php", + 'ApiTestCase' => "$testDir/phpunit/includes/api/ApiTestCase.php", + 'ApiTestContext' => "$testDir/phpunit/includes/api/ApiTestCase.php", + 'MockApi' => "$testDir/phpunit/includes/api/ApiTestCase.php", + 'RandomImageGenerator' => "$testDir/phpunit/includes/api/RandomImageGenerator.php", + 'UserWrapper' => "$testDir/phpunit/includes/api/ApiTestCase.php", + + # tests/phpunit/includes/content + 'DummyContentHandlerForTesting' => "$testDir/phpunit/includes/content/ContentHandlerTest.php", + 'DummyContentForTesting' => "$testDir/phpunit/includes/content/ContentHandlerTest.php", + 'ContentHandlerTest' => "$testDir/phpunit/includes/content/ContentHandlerTest.php", + 'JavaScriptContentTest' => "$testDir/phpunit/includes/content/JavaScriptContentTest.php", + 'TextContentTest' => "$testDir/phpunit/includes/content/TextContentTest.php", + 'WikitextContentTest' => "$testDir/phpunit/includes/content/WikitextContentTest.php", + + # tests/phpunit/includes/db + 'ORMRowTest' => "$testDir/phpunit/includes/db/ORMRowTest.php", + + # tests/phpunit/includes/parser + 'NewParserTest' => "$testDir/phpunit/includes/parser/NewParserTest.php", + + # tests/phpunit/includes/libs + 'GenericArrayObjectTest' => "$testDir/phpunit/includes/libs/GenericArrayObjectTest.php", + + # tests/phpunit/includes/site + 'SiteTest' => "$testDir/phpunit/includes/site/SiteTest.php", + 'TestSites' => "$testDir/phpunit/includes/site/TestSites.php", + + # tests/phpunit/languages + 'LanguageClassesTestCase' => "$testDir/phpunit/languages/LanguageClassesTestCase.php", + + # tests/phpunit/maintenance + 'DumpTestCase' => "$testDir/phpunit/maintenance/DumpTestCase.php", + + # tests/parser + 'ParserTest' => "$testDir/parser/parserTest.inc", + 'ParserTestParserHook' => "$testDir/parser/parserTestsParserHook.php", + + # tests/selenium + 'Selenium' => "$testDir/selenium/Selenium.php", + 'SeleniumLoader' => "$testDir/selenium/SeleniumLoader.php", + 'SeleniumTestCase' => "$testDir/selenium/SeleniumTestCase.php", + 'SeleniumTestConsoleLogger' => "$testDir/selenium/SeleniumTestConsoleLogger.php", + 'SeleniumTestConstants' => "$testDir/selenium/SeleniumTestConstants.php", + 'SeleniumTestHTMLLogger' => "$testDir/selenium/SeleniumTestHTMLLogger.php", + 'SeleniumTestListener' => "$testDir/selenium/SeleniumTestListener.php", + 'SeleniumTestSuite' => "$testDir/selenium/SeleniumTestSuite.php", + 'SeleniumConfig' => "$testDir/selenium/SeleniumConfig.php", +); diff --git a/tests/parser/README b/tests/parser/README new file mode 100644 index 00000000..8b413376 --- /dev/null +++ b/tests/parser/README @@ -0,0 +1,8 @@ +Parser tests are run using our PHPUnit test suite in tests/phpunit: + + $ cd tests/phpunit + ./phpunit.php --group Parser + +You can optionally filter by title using --regex. I.e. : + + ./phpunit.php --group Parser --regex="Bug 6200" diff --git a/tests/parser/extraParserTests.txt b/tests/parser/extraParserTests.txt Binary files differnew file mode 100644 index 00000000..bef8f506 --- /dev/null +++ b/tests/parser/extraParserTests.txt diff --git a/tests/parser/parserTest.inc b/tests/parser/parserTest.inc new file mode 100644 index 00000000..ce621f4e --- /dev/null +++ b/tests/parser/parserTest.inc @@ -0,0 +1,1349 @@ +<?php +/** + * Helper code for the MediaWiki parser test suite. + * + * Copyright © 2004, 2010 Brion Vibber <brion@pobox.com> + * http://www.mediawiki.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @todo Make this more independent of the configuration (and if possible the database) + * @todo document + * @file + * @ingroup Testing + */ + +/** + * @ingroup Testing + */ +class ParserTest { + /** + * boolean $color whereas output should be colorized + */ + private $color; + + /** + * boolean $showOutput Show test output + */ + private $showOutput; + + /** + * boolean $useTemporaryTables Use temporary tables for the temporary database + */ + private $useTemporaryTables = true; + + /** + * boolean $databaseSetupDone True if the database has been set up + */ + private $databaseSetupDone = false; + + /** + * Our connection to the database + * @var DatabaseBase + */ + private $db; + + /** + * Database clone helper + * @var CloneDatabase + */ + private $dbClone; + + /** + * string $oldTablePrefix Original table prefix + */ + private $oldTablePrefix; + + private $maxFuzzTestLength = 300; + private $fuzzSeed = 0; + private $memoryLimit = 50; + private $uploadDir = null; + + public $regex = ""; + private $savedGlobals = array(); + + /** + * Sets terminal colorization and diff/quick modes depending on OS and + * command-line options (--color and --quick). + */ + public function __construct( $options = array() ) { + # Only colorize output if stdout is a terminal. + $this->color = !wfIsWindows() && Maintenance::posix_isatty( 1 ); + + if ( isset( $options['color'] ) ) { + switch ( $options['color'] ) { + case 'no': + $this->color = false; + break; + case 'yes': + default: + $this->color = true; + break; + } + } + + $this->term = $this->color + ? new AnsiTermColorer() + : new DummyTermColorer(); + + $this->showDiffs = !isset( $options['quick'] ); + $this->showProgress = !isset( $options['quiet'] ); + $this->showFailure = !( + isset( $options['quiet'] ) + && ( isset( $options['record'] ) + || isset( $options['compare'] ) ) ); // redundant output + + $this->showOutput = isset( $options['show-output'] ); + + if ( isset( $options['filter'] ) ) { + $options['regex'] = $options['filter']; + } + + if ( isset( $options['regex'] ) ) { + if ( isset( $options['record'] ) ) { + echo "Warning: --record cannot be used with --regex, disabling --record\n"; + unset( $options['record'] ); + } + $this->regex = $options['regex']; + } else { + # Matches anything + $this->regex = ''; + } + + $this->setupRecorder( $options ); + $this->keepUploads = isset( $options['keep-uploads'] ); + + if ( isset( $options['seed'] ) ) { + $this->fuzzSeed = intval( $options['seed'] ) - 1; + } + + $this->runDisabled = isset( $options['run-disabled'] ); + $this->runParsoid = isset( $options['run-parsoid'] ); + + $this->hooks = array(); + $this->functionHooks = array(); + self::setUp(); + } + + static function setUp() { + global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc, + $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory, $wgEnableParserCache, + $wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo, + $parserMemc, $wgThumbnailScriptPath, $wgScriptPath, + $wgArticlePath, $wgStyleSheetPath, $wgScript, $wgStylePath, $wgExtensionAssetsPath, + $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType, $wgLockManagers; + + $wgScript = '/index.php'; + $wgScriptPath = '/'; + $wgArticlePath = '/wiki/$1'; + $wgStyleSheetPath = '/skins'; + $wgStylePath = '/skins'; + $wgExtensionAssetsPath = '/extensions'; + $wgThumbnailScriptPath = false; + $wgLockManagers = array( array( + 'name' => 'fsLockManager', + 'class' => 'FSLockManager', + 'lockDirectory' => wfTempDir() . '/test-repo/lockdir', + ), array( + 'name' => 'nullLockManager', + 'class' => 'NullLockManager', + ) ); + $wgLocalFileRepo = array( + 'class' => 'LocalRepo', + 'name' => 'local', + 'url' => 'http://example.com/images', + 'hashLevels' => 2, + 'transformVia404' => false, + 'backend' => new FSFileBackend( array( + 'name' => 'local-backend', + 'lockManager' => 'fsLockManager', + 'containerPaths' => array( + 'local-public' => wfTempDir() . '/test-repo/public', + 'local-thumb' => wfTempDir() . '/test-repo/thumb', + 'local-temp' => wfTempDir() . '/test-repo/temp', + 'local-deleted' => wfTempDir() . '/test-repo/deleted', + ) + ) ) + ); + $wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface'; + $wgNamespaceAliases['Image'] = NS_FILE; + $wgNamespaceAliases['Image_talk'] = NS_FILE_TALK; + + // XXX: tests won't run without this (for CACHE_DB) + if ( $wgMainCacheType === CACHE_DB ) { + $wgMainCacheType = CACHE_NONE; + } + if ( $wgMessageCacheType === CACHE_DB ) { + $wgMessageCacheType = CACHE_NONE; + } + if ( $wgParserCacheType === CACHE_DB ) { + $wgParserCacheType = CACHE_NONE; + } + + $wgEnableParserCache = false; + DeferredUpdates::clearPendingUpdates(); + $wgMemc = wfGetMainCache(); // checks $wgMainCacheType + $messageMemc = wfGetMessageCacheStorage(); + $parserMemc = wfGetParserCacheStorage(); + + // $wgContLang = new StubContLang; + $wgUser = new User; + $context = new RequestContext; + $wgLang = $context->getLanguage(); + $wgOut = $context->getOutput(); + $wgParser = new StubObject( 'wgParser', $wgParserConf['class'], array( $wgParserConf ) ); + $wgRequest = $context->getRequest(); + + if ( $wgStyleDirectory === false ) { + $wgStyleDirectory = "$IP/skins"; + } + + } + + public function setupRecorder( $options ) { + if ( isset( $options['record'] ) ) { + $this->recorder = new DbTestRecorder( $this ); + $this->recorder->version = isset( $options['setversion'] ) ? + $options['setversion'] : SpecialVersion::getVersion(); + } elseif ( isset( $options['compare'] ) ) { + $this->recorder = new DbTestPreviewer( $this ); + } else { + $this->recorder = new TestRecorder( $this ); + } + } + + /** + * Remove last character if it is a newline + * @group utility + */ + public static function chomp( $s ) { + if ( substr( $s, -1 ) === "\n" ) { + return substr( $s, 0, -1 ); + } else { + return $s; + } + } + + /** + * Run a fuzz test series + * Draw input from a set of test files + */ + function fuzzTest( $filenames ) { + $GLOBALS['wgContLang'] = Language::factory( 'en' ); + $dict = $this->getFuzzInput( $filenames ); + $dictSize = strlen( $dict ); + $logMaxLength = log( $this->maxFuzzTestLength ); + $this->setupDatabase(); + ini_set( 'memory_limit', $this->memoryLimit * 1048576 ); + + $numTotal = 0; + $numSuccess = 0; + $user = new User; + $opts = ParserOptions::newFromUser( $user ); + $title = Title::makeTitle( NS_MAIN, 'Parser_test' ); + + while ( true ) { + // Generate test input + mt_srand( ++$this->fuzzSeed ); + $totalLength = mt_rand( 1, $this->maxFuzzTestLength ); + $input = ''; + + while ( strlen( $input ) < $totalLength ) { + $logHairLength = mt_rand( 0, 1000000 ) / 1000000 * $logMaxLength; + $hairLength = min( intval( exp( $logHairLength ) ), $dictSize ); + $offset = mt_rand( 0, $dictSize - $hairLength ); + $input .= substr( $dict, $offset, $hairLength ); + } + + $this->setupGlobals(); + $parser = $this->getParser(); + + // Run the test + try { + $parser->parse( $input, $title, $opts ); + $fail = false; + } catch ( Exception $exception ) { + $fail = true; + } + + if ( $fail ) { + echo "Test failed with seed {$this->fuzzSeed}\n"; + echo "Input:\n"; + printf( "string(%d) \"%s\"\n\n", strlen( $input ), $input ); + echo "$exception\n"; + } else { + $numSuccess++; + } + + $numTotal++; + $this->teardownGlobals(); + $parser->__destruct(); + + if ( $numTotal % 100 == 0 ) { + $usage = intval( memory_get_usage( true ) / $this->memoryLimit / 1048576 * 100 ); + echo "{$this->fuzzSeed}: $numSuccess/$numTotal (mem: $usage%)\n"; + if ( $usage > 90 ) { + echo "Out of memory:\n"; + $memStats = $this->getMemoryBreakdown(); + + foreach ( $memStats as $name => $usage ) { + echo "$name: $usage\n"; + } + $this->abort(); + } + } + } + } + + /** + * Get an input dictionary from a set of parser test files + */ + function getFuzzInput( $filenames ) { + $dict = ''; + + foreach ( $filenames as $filename ) { + $contents = file_get_contents( $filename ); + preg_match_all( '/!!\s*input\n(.*?)\n!!\s*result/s', $contents, $matches ); + + foreach ( $matches[1] as $match ) { + $dict .= $match . "\n"; + } + } + + return $dict; + } + + /** + * Get a memory usage breakdown + */ + function getMemoryBreakdown() { + $memStats = array(); + + foreach ( $GLOBALS as $name => $value ) { + $memStats['$' . $name] = strlen( serialize( $value ) ); + } + + $classes = get_declared_classes(); + + foreach ( $classes as $class ) { + $rc = new ReflectionClass( $class ); + $props = $rc->getStaticProperties(); + $memStats[$class] = strlen( serialize( $props ) ); + $methods = $rc->getMethods(); + + foreach ( $methods as $method ) { + $memStats[$class] += strlen( serialize( $method->getStaticVariables() ) ); + } + } + + $functions = get_defined_functions(); + + foreach ( $functions['user'] as $function ) { + $rf = new ReflectionFunction( $function ); + $memStats["$function()"] = strlen( serialize( $rf->getStaticVariables() ) ); + } + + asort( $memStats ); + + return $memStats; + } + + function abort() { + $this->abort(); + } + + /** + * Run a series of tests listed in the given text files. + * Each test consists of a brief description, wikitext input, + * and the expected HTML output. + * + * Prints status updates on stdout and counts up the total + * number and percentage of passed tests. + * + * @param $filenames Array of strings + * @return Boolean: true if passed all tests, false if any tests failed. + */ + public function runTestsFromFiles( $filenames ) { + $ok = false; + $GLOBALS['wgContLang'] = Language::factory( 'en' ); + $this->recorder->start(); + try { + $this->setupDatabase(); + $ok = true; + + foreach ( $filenames as $filename ) { + $tests = new TestFileIterator( $filename, $this ); + $ok = $this->runTests( $tests ) && $ok; + } + + $this->teardownDatabase(); + $this->recorder->report(); + } catch ( DBError $e ) { + echo $e->getMessage(); + } + $this->recorder->end(); + + return $ok; + } + + function runTests( $tests ) { + $ok = true; + + foreach ( $tests as $t ) { + $result = + $this->runTest( $t['test'], $t['input'], $t['result'], $t['options'], $t['config'] ); + $ok = $ok && $result; + $this->recorder->record( $t['test'], $result ); + } + + if ( $this->showProgress ) { + print "\n"; + } + + return $ok; + } + + /** + * Get a Parser object + */ + function getParser( $preprocessor = null ) { + global $wgParserConf; + + $class = $wgParserConf['class']; + $parser = new $class( array( 'preprocessorClass' => $preprocessor ) + $wgParserConf ); + + foreach ( $this->hooks as $tag => $callback ) { + $parser->setHook( $tag, $callback ); + } + + foreach ( $this->functionHooks as $tag => $bits ) { + list( $callback, $flags ) = $bits; + $parser->setFunctionHook( $tag, $callback, $flags ); + } + + wfRunHooks( 'ParserTestParser', array( &$parser ) ); + + return $parser; + } + + /** + * Run a given wikitext input through a freshly-constructed wiki parser, + * and compare the output against the expected results. + * Prints status and explanatory messages to stdout. + * + * @param $desc String: test's description + * @param $input String: wikitext to try rendering + * @param $result String: result to output + * @param $opts Array: test's options + * @param $config String: overrides for global variables, one per line + * @return Boolean + */ + public function runTest( $desc, $input, $result, $opts, $config ) { + if ( $this->showProgress ) { + $this->showTesting( $desc ); + } + + $opts = $this->parseOptions( $opts ); + $context = $this->setupGlobals( $opts, $config ); + + $user = $context->getUser(); + $options = ParserOptions::newFromContext( $context ); + + if ( isset( $opts['title'] ) ) { + $titleText = $opts['title']; + } else { + $titleText = 'Parser test'; + } + + $local = isset( $opts['local'] ); + $preprocessor = isset( $opts['preprocessor'] ) ? $opts['preprocessor'] : null; + $parser = $this->getParser( $preprocessor ); + $title = Title::newFromText( $titleText ); + + if ( isset( $opts['pst'] ) ) { + $out = $parser->preSaveTransform( $input, $title, $user, $options ); + } elseif ( isset( $opts['msg'] ) ) { + $out = $parser->transformMsg( $input, $options, $title ); + } elseif ( isset( $opts['section'] ) ) { + $section = $opts['section']; + $out = $parser->getSection( $input, $section ); + } elseif ( isset( $opts['replace'] ) ) { + $section = $opts['replace'][0]; + $replace = $opts['replace'][1]; + $out = $parser->replaceSection( $input, $section, $replace ); + } elseif ( isset( $opts['comment'] ) ) { + $out = Linker::formatComment( $input, $title, $local ); + } elseif ( isset( $opts['preload'] ) ) { + $out = $parser->getpreloadText( $input, $title, $options ); + } else { + $output = $parser->parse( $input, $title, $options, true, true, 1337 ); + $out = $output->getText(); + + if ( isset( $opts['showtitle'] ) ) { + if ( $output->getTitleText() ) { + $title = $output->getTitleText(); + } + + $out = "$title\n$out"; + } + + if ( isset( $opts['ill'] ) ) { + $out = $this->tidy( implode( ' ', $output->getLanguageLinks() ) ); + } elseif ( isset( $opts['cat'] ) ) { + $outputPage = $context->getOutput(); + $outputPage->addCategoryLinks( $output->getCategories() ); + $cats = $outputPage->getCategoryLinks(); + + if ( isset( $cats['normal'] ) ) { + $out = $this->tidy( implode( ' ', $cats['normal'] ) ); + } else { + $out = ''; + } + } + + $result = $this->tidy( $result ); + } + + $this->teardownGlobals(); + return $this->showTestResult( $desc, $result, $out ); + } + + /** + * + */ + function showTestResult( $desc, $result, $out ) { + if ( $result === $out ) { + $this->showSuccess( $desc ); + return true; + } else { + $this->showFailure( $desc, $result, $out ); + return false; + } + } + + /** + * Use a regex to find out the value of an option + * @param $key String: name of option val to retrieve + * @param $opts Options array to look in + * @param $default Mixed: default value returned if not found + */ + private static function getOptionValue( $key, $opts, $default ) { + $key = strtolower( $key ); + + if ( isset( $opts[$key] ) ) { + return $opts[$key]; + } else { + return $default; + } + } + + private function parseOptions( $instring ) { + $opts = array(); + // foo + // foo=bar + // foo="bar baz" + // foo=[[bar baz]] + // foo=bar,"baz quux" + $regex = '/\b + ([\w-]+) # Key + \b + (?:\s* + = # First sub-value + \s* + ( + " + [^"]* # Quoted val + " + | + \[\[ + [^]]* # Link target + \]\] + | + [\w-]+ # Plain word + ) + (?:\s* + , # Sub-vals 1..N + \s* + ( + "[^"]*" # Quoted val + | + \[\[[^]]*\]\] # Link target + | + [\w-]+ # Plain word + ) + )* + )? + /x'; + + if ( preg_match_all( $regex, $instring, $matches, PREG_SET_ORDER ) ) { + foreach ( $matches as $bits ) { + array_shift( $bits ); + $key = strtolower( array_shift( $bits ) ); + if ( count( $bits ) == 0 ) { + $opts[$key] = true; + } elseif ( count( $bits ) == 1 ) { + $opts[$key] = $this->cleanupOption( array_shift( $bits ) ); + } else { + // Array! + $opts[$key] = array_map( array( $this, 'cleanupOption' ), $bits ); + } + } + } + return $opts; + } + + private function cleanupOption( $opt ) { + if ( substr( $opt, 0, 1 ) == '"' ) { + return substr( $opt, 1, -1 ); + } + + if ( substr( $opt, 0, 2 ) == '[[' ) { + return substr( $opt, 2, -2 ); + } + return $opt; + } + + /** + * Set up the global variables for a consistent environment for each test. + * Ideally this should replace the global configuration entirely. + */ + private function setupGlobals( $opts = '', $config = '' ) { + # Find out values for some special options. + $lang = + self::getOptionValue( 'language', $opts, 'en' ); + $variant = + self::getOptionValue( 'variant', $opts, false ); + $maxtoclevel = + self::getOptionValue( 'wgMaxTocLevel', $opts, 999 ); + $linkHolderBatchSize = + self::getOptionValue( 'wgLinkHolderBatchSize', $opts, 1000 ); + + $settings = array( + 'wgServer' => 'http://example.org', + 'wgScript' => '/index.php', + 'wgScriptPath' => '/', + 'wgArticlePath' => '/wiki/$1', + 'wgActionPaths' => array(), + 'wgLockManagers' => array( array( + 'name' => 'fsLockManager', + 'class' => 'FSLockManager', + 'lockDirectory' => $this->uploadDir . '/lockdir', + ), array( + 'name' => 'nullLockManager', + 'class' => 'NullLockManager', + ) ), + 'wgLocalFileRepo' => array( + 'class' => 'LocalRepo', + 'name' => 'local', + 'url' => 'http://example.com/images', + 'hashLevels' => 2, + 'transformVia404' => false, + 'backend' => new FSFileBackend( array( + 'name' => 'local-backend', + 'lockManager' => 'fsLockManager', + 'containerPaths' => array( + 'local-public' => $this->uploadDir, + 'local-thumb' => $this->uploadDir . '/thumb', + 'local-temp' => $this->uploadDir . '/temp', + 'local-deleted' => $this->uploadDir . '/delete', + ) + ) ) + ), + 'wgEnableUploads' => self::getOptionValue( 'wgEnableUploads', $opts, true ), + 'wgStylePath' => '/skins', + 'wgStyleSheetPath' => '/skins', + 'wgSitename' => 'MediaWiki', + 'wgLanguageCode' => $lang, + 'wgDBprefix' => $this->db->getType() != 'oracle' ? 'parsertest_' : 'pt_', + 'wgRawHtml' => isset( $opts['rawhtml'] ), + 'wgLang' => null, + 'wgContLang' => null, + 'wgNamespacesWithSubpages' => array( 0 => isset( $opts['subpage'] ) ), + 'wgMaxTocLevel' => $maxtoclevel, + 'wgCapitalLinks' => true, + 'wgNoFollowLinks' => true, + 'wgNoFollowDomainExceptions' => array(), + 'wgThumbnailScriptPath' => false, + 'wgUseImageResize' => true, + 'wgLocaltimezone' => 'UTC', + 'wgAllowExternalImages' => true, + 'wgUseTidy' => false, + 'wgDefaultLanguageVariant' => $variant, + 'wgVariantArticlePath' => false, + 'wgGroupPermissions' => array( '*' => array( + 'createaccount' => true, + 'read' => true, + 'edit' => true, + 'createpage' => true, + 'createtalk' => true, + ) ), + 'wgNamespaceProtection' => array( NS_MEDIAWIKI => 'editinterface' ), + 'wgDefaultExternalStore' => array(), + 'wgForeignFileRepos' => array(), + 'wgLinkHolderBatchSize' => $linkHolderBatchSize, + 'wgExperimentalHtmlIds' => false, + 'wgExternalLinkTarget' => false, + 'wgAlwaysUseTidy' => false, + 'wgHtml5' => true, + 'wgWellFormedXml' => true, + 'wgAllowMicrodataAttributes' => true, + 'wgAdaptiveMessageCache' => true, + 'wgDisableLangConversion' => false, + 'wgDisableTitleConversion' => false, + ); + + if ( $config ) { + $configLines = explode( "\n", $config ); + + foreach ( $configLines as $line ) { + list( $var, $value ) = explode( '=', $line, 2 ); + + $settings[$var] = eval( "return $value;" ); + } + } + + $this->savedGlobals = array(); + + /** @since 1.20 */ + wfRunHooks( 'ParserTestGlobals', array( &$settings ) ); + + foreach ( $settings as $var => $val ) { + if ( array_key_exists( $var, $GLOBALS ) ) { + $this->savedGlobals[$var] = $GLOBALS[$var]; + } + + $GLOBALS[$var] = $val; + } + + $GLOBALS['wgContLang'] = Language::factory( $lang ); + $GLOBALS['wgMemc'] = new EmptyBagOStuff; + + $context = new RequestContext(); + $GLOBALS['wgLang'] = $context->getLanguage(); + $GLOBALS['wgOut'] = $context->getOutput(); + + $GLOBALS['wgUser'] = new User(); + + global $wgHooks; + + $wgHooks['ParserTestParser'][] = 'ParserTestParserHook::setup'; + $wgHooks['ParserGetVariableValueTs'][] = 'ParserTest::getFakeTimestamp'; + + MagicWord::clearCache(); + + return $context; + } + + /** + * List of temporary tables to create, without prefix. + * Some of these probably aren't necessary. + */ + private function listTables() { + $tables = array( 'user', 'user_properties', 'user_former_groups', 'page', 'page_restrictions', + 'protected_titles', 'revision', 'text', 'pagelinks', 'imagelinks', + 'categorylinks', 'templatelinks', 'externallinks', 'langlinks', 'iwlinks', + 'site_stats', 'hitcounter', 'ipblocks', 'image', 'oldimage', + 'recentchanges', 'watchlist', 'interwiki', 'logging', + 'querycache', 'objectcache', 'job', 'l10n_cache', 'redirect', 'querycachetwo', + 'archive', 'user_groups', 'page_props', 'category', 'msg_resource', 'msg_resource_links' + ); + + if ( in_array( $this->db->getType(), array( 'mysql', 'sqlite', 'oracle' ) ) ) { + array_push( $tables, 'searchindex' ); + } + + // Allow extensions to add to the list of tables to duplicate; + // may be necessary if they hook into page save or other code + // which will require them while running tests. + wfRunHooks( 'ParserTestTables', array( &$tables ) ); + + return $tables; + } + + /** + * Set up a temporary set of wiki tables to work with for the tests. + * Currently this will only be done once per run, and any changes to + * the db will be visible to later tests in the run. + */ + public function setupDatabase() { + global $wgDBprefix; + + if ( $this->databaseSetupDone ) { + return; + } + + $this->db = wfGetDB( DB_MASTER ); + $dbType = $this->db->getType(); + + if ( $wgDBprefix === 'parsertest_' || ( $dbType == 'oracle' && $wgDBprefix === 'pt_' ) ) { + throw new MWException( 'setupDatabase should be called before setupGlobals' ); + } + + $this->databaseSetupDone = true; + $this->oldTablePrefix = $wgDBprefix; + + # SqlBagOStuff broke when using temporary tables on r40209 (bug 15892). + # It seems to have been fixed since (r55079?), but regressed at some point before r85701. + # This works around it for now... + ObjectCache::$instances[CACHE_DB] = new HashBagOStuff; + + # CREATE TEMPORARY TABLE breaks if there is more than one server + if ( wfGetLB()->getServerCount() != 1 ) { + $this->useTemporaryTables = false; + } + + $temporary = $this->useTemporaryTables || $dbType == 'postgres'; + $prefix = $dbType != 'oracle' ? 'parsertest_' : 'pt_'; + + $this->dbClone = new CloneDatabase( $this->db, $this->listTables(), $prefix ); + $this->dbClone->useTemporaryTables( $temporary ); + $this->dbClone->cloneTableStructure(); + + if ( $dbType == 'oracle' ) { + $this->db->query( 'BEGIN FILL_WIKI_INFO; END;' ); + # Insert 0 user to prevent FK violations + + # Anonymous user + $this->db->insert( 'user', array( + 'user_id' => 0, + 'user_name' => 'Anonymous' ) ); + } + + # Hack: insert a few Wikipedia in-project interwiki prefixes, + # for testing inter-language links + $this->db->insert( 'interwiki', array( + array( 'iw_prefix' => 'wikipedia', + 'iw_url' => 'http://en.wikipedia.org/wiki/$1', + 'iw_api' => '', + 'iw_wikiid' => '', + 'iw_local' => 0 ), + array( 'iw_prefix' => 'meatball', + 'iw_url' => 'http://www.usemod.com/cgi-bin/mb.pl?$1', + 'iw_api' => '', + 'iw_wikiid' => '', + 'iw_local' => 0 ), + array( 'iw_prefix' => 'zh', + 'iw_url' => 'http://zh.wikipedia.org/wiki/$1', + 'iw_api' => '', + 'iw_wikiid' => '', + 'iw_local' => 1 ), + array( 'iw_prefix' => 'es', + 'iw_url' => 'http://es.wikipedia.org/wiki/$1', + 'iw_api' => '', + 'iw_wikiid' => '', + 'iw_local' => 1 ), + array( 'iw_prefix' => 'fr', + 'iw_url' => 'http://fr.wikipedia.org/wiki/$1', + 'iw_api' => '', + 'iw_wikiid' => '', + 'iw_local' => 1 ), + array( 'iw_prefix' => 'ru', + 'iw_url' => 'http://ru.wikipedia.org/wiki/$1', + 'iw_api' => '', + 'iw_wikiid' => '', + 'iw_local' => 1 ), + ) ); + + # Update certain things in site_stats + $this->db->insert( 'site_stats', array( 'ss_row_id' => 1, 'ss_images' => 2, 'ss_good_articles' => 1 ) ); + + # Reinitialise the LocalisationCache to match the database state + Language::getLocalisationCache()->unloadAll(); + + # Clear the message cache + MessageCache::singleton()->clear(); + + $this->uploadDir = $this->setupUploadDir(); + $user = User::createNew( 'WikiSysop' ); + $image = wfLocalFile( Title::makeTitle( NS_FILE, 'Foobar.jpg' ) ); + $image->recordUpload2( '', 'Upload of some lame file', 'Some lame file', array( + 'size' => 12345, + 'width' => 1941, + 'height' => 220, + 'bits' => 24, + 'media_type' => MEDIATYPE_BITMAP, + 'mime' => 'image/jpeg', + 'metadata' => serialize( array() ), + 'sha1' => wfBaseConvert( '', 16, 36, 31 ), + 'fileExists' => true + ), $this->db->timestamp( '20010115123500' ), $user ); + + # This image will be blacklisted in [[MediaWiki:Bad image list]] + $image = wfLocalFile( Title::makeTitle( NS_FILE, 'Bad.jpg' ) ); + $image->recordUpload2( '', 'zomgnotcensored', 'Borderline image', array( + 'size' => 12345, + 'width' => 320, + 'height' => 240, + 'bits' => 24, + 'media_type' => MEDIATYPE_BITMAP, + 'mime' => 'image/jpeg', + 'metadata' => serialize( array() ), + 'sha1' => wfBaseConvert( '', 16, 36, 31 ), + 'fileExists' => true + ), $this->db->timestamp( '20010115123500' ), $user ); + } + + public function teardownDatabase() { + if ( !$this->databaseSetupDone ) { + $this->teardownGlobals(); + return; + } + $this->teardownUploadDir( $this->uploadDir ); + + $this->dbClone->destroy(); + $this->databaseSetupDone = false; + + if ( $this->useTemporaryTables ) { + if ( $this->db->getType() == 'sqlite' ) { + # Under SQLite the searchindex table is virtual and need + # to be explicitly destroyed. See bug 29912 + # See also MediaWikiTestCase::destroyDB() + wfDebug( __METHOD__ . " explicitly destroying sqlite virtual table parsertest_searchindex\n" ); + $this->db->query( "DROP TABLE `parsertest_searchindex`" ); + } + # Don't need to do anything + $this->teardownGlobals(); + return; + } + + $tables = $this->listTables(); + + foreach ( $tables as $table ) { + $sql = $this->db->getType() == 'oracle' ? "DROP TABLE pt_$table DROP CONSTRAINTS" : "DROP TABLE `parsertest_$table`"; + $this->db->query( $sql ); + } + + if ( $this->db->getType() == 'oracle' ) { + $this->db->query( 'BEGIN FILL_WIKI_INFO; END;' ); + } + + $this->teardownGlobals(); + } + + /** + * Create a dummy uploads directory which will contain a couple + * of files in order to pass existence tests. + * + * @return String: the directory + */ + private function setupUploadDir() { + global $IP; + + if ( $this->keepUploads ) { + $dir = wfTempDir() . '/mwParser-images'; + + if ( is_dir( $dir ) ) { + return $dir; + } + } else { + $dir = wfTempDir() . "/mwParser-" . mt_rand() . "-images"; + } + + // wfDebug( "Creating upload directory $dir\n" ); + if ( file_exists( $dir ) ) { + wfDebug( "Already exists!\n" ); + return $dir; + } + + wfMkdirParents( $dir . '/3/3a', null, __METHOD__ ); + copy( "$IP/skins/monobook/headbg.jpg", "$dir/3/3a/Foobar.jpg" ); + wfMkdirParents( $dir . '/0/09', null, __METHOD__ ); + copy( "$IP/skins/monobook/headbg.jpg", "$dir/0/09/Bad.jpg" ); + + return $dir; + } + + /** + * Restore default values and perform any necessary clean-up + * after each test runs. + */ + private function teardownGlobals() { + RepoGroup::destroySingleton(); + FileBackendGroup::destroySingleton(); + LockManagerGroup::destroySingletons(); + LinkCache::singleton()->clear(); + + foreach ( $this->savedGlobals as $var => $val ) { + $GLOBALS[$var] = $val; + } + } + + /** + * Remove the dummy uploads directory + */ + private function teardownUploadDir( $dir ) { + if ( $this->keepUploads ) { + return; + } + + // delete the files first, then the dirs. + self::deleteFiles( + array( + "$dir/3/3a/Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/640px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/1280px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/20px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/30px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/400px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/40px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/70px-Foobar.jpg", + "$dir/thumb/3/3a/Foobar.jpg/960px-Foobar.jpg", + + "$dir/0/09/Bad.jpg", + + "$dir/math/f/a/5/fa50b8b616463173474302ca3e63586b.png", + ) + ); + + self::deleteDirs( + array( + "$dir/3/3a", + "$dir/3", + "$dir/thumb/6/65", + "$dir/thumb/6", + "$dir/thumb/3/3a/Foobar.jpg", + "$dir/thumb/3/3a", + "$dir/thumb/3", + + "$dir/0/09/", + "$dir/0/", + "$dir/thumb", + "$dir/math/f/a/5", + "$dir/math/f/a", + "$dir/math/f", + "$dir/math", + "$dir", + ) + ); + } + + /** + * Delete the specified files, if they exist. + * @param $files Array: full paths to files to delete. + */ + private static function deleteFiles( $files ) { + foreach ( $files as $file ) { + if ( file_exists( $file ) ) { + unlink( $file ); + } + } + } + + /** + * Delete the specified directories, if they exist. Must be empty. + * @param $dirs Array: full paths to directories to delete. + */ + private static function deleteDirs( $dirs ) { + foreach ( $dirs as $dir ) { + if ( is_dir( $dir ) ) { + rmdir( $dir ); + } + } + } + + /** + * "Running test $desc..." + */ + protected function showTesting( $desc ) { + print "Running test $desc... "; + } + + /** + * Print a happy success message. + * + * @param $desc String: the test name + * @return Boolean + */ + protected function showSuccess( $desc ) { + if ( $this->showProgress ) { + print $this->term->color( '1;32' ) . 'PASSED' . $this->term->reset() . "\n"; + } + + return true; + } + + /** + * Print a failure message and provide some explanatory output + * about what went wrong if so configured. + * + * @param $desc String: the test name + * @param $result String: expected HTML output + * @param $html String: actual HTML output + * @return Boolean + */ + protected function showFailure( $desc, $result, $html ) { + if ( $this->showFailure ) { + if ( !$this->showProgress ) { + # In quiet mode we didn't show the 'Testing' message before the + # test, in case it succeeded. Show it now: + $this->showTesting( $desc ); + } + + print $this->term->color( '31' ) . 'FAILED!' . $this->term->reset() . "\n"; + + if ( $this->showOutput ) { + print "--- Expected ---\n$result\n--- Actual ---\n$html\n"; + } + + if ( $this->showDiffs ) { + print $this->quickDiff( $result, $html ); + if ( !$this->wellFormed( $html ) ) { + print "XML error: $this->mXmlError\n"; + } + } + } + + return false; + } + + /** + * Run given strings through a diff and return the (colorized) output. + * Requires writable /tmp directory and a 'diff' command in the PATH. + * + * @param $input String + * @param $output String + * @param $inFileTail String: tailing for the input file name + * @param $outFileTail String: tailing for the output file name + * @return String + */ + protected function quickDiff( $input, $output, $inFileTail = 'expected', $outFileTail = 'actual' ) { + # Windows, or at least the fc utility, is retarded + $slash = wfIsWindows() ? '\\' : '/'; + $prefix = wfTempDir() . "{$slash}mwParser-" . mt_rand(); + + $infile = "$prefix-$inFileTail"; + $this->dumpToFile( $input, $infile ); + + $outfile = "$prefix-$outFileTail"; + $this->dumpToFile( $output, $outfile ); + + $shellInfile = wfEscapeShellArg( $infile ); + $shellOutfile = wfEscapeShellArg( $outfile ); + + global $wgDiff3; + // we assume that people with diff3 also have usual diff + $diff = ( wfIsWindows() && !$wgDiff3 ) + ? `fc $shellInfile $shellOutfile` + : `diff -au $shellInfile $shellOutfile`; + unlink( $infile ); + unlink( $outfile ); + + return $this->colorDiff( $diff ); + } + + /** + * Write the given string to a file, adding a final newline. + * + * @param $data String + * @param $filename String + */ + private function dumpToFile( $data, $filename ) { + $file = fopen( $filename, "wt" ); + fwrite( $file, $data . "\n" ); + fclose( $file ); + } + + /** + * Colorize unified diff output if set for ANSI color output. + * Subtractions are colored blue, additions red. + * + * @param $text String + * @return String + */ + protected function colorDiff( $text ) { + return preg_replace( + array( '/^(-.*)$/m', '/^(\+.*)$/m' ), + array( $this->term->color( 34 ) . '$1' . $this->term->reset(), + $this->term->color( 31 ) . '$1' . $this->term->reset() ), + $text ); + } + + /** + * Show "Reading tests from ..." + * + * @param $path String + */ + public function showRunFile( $path ) { + print $this->term->color( 1 ) . + "Reading tests from \"$path\"..." . + $this->term->reset() . + "\n"; + } + + /** + * Insert a temporary test article + * @param $name String: the title, including any prefix + * @param $text String: the article text + * @param $line Integer: the input line number, for reporting errors + * @param $ignoreDuplicate Boolean: whether to silently ignore duplicate pages + */ + public static function addArticle( $name, $text, $line = 'unknown', $ignoreDuplicate = '' ) { + global $wgCapitalLinks; + + $oldCapitalLinks = $wgCapitalLinks; + $wgCapitalLinks = true; // We only need this from SetupGlobals() See r70917#c8637 + + $text = self::chomp( $text ); + $name = self::chomp( $name ); + + $title = Title::newFromText( $name ); + + if ( is_null( $title ) ) { + throw new MWException( "invalid title '$name' at line $line\n" ); + } + + $page = WikiPage::factory( $title ); + $page->loadPageData( 'fromdbmaster' ); + + if ( $page->exists() ) { + if ( $ignoreDuplicate == 'ignoreduplicate' ) { + return; + } else { + throw new MWException( "duplicate article '$name' at line $line\n" ); + } + } + + $page->doEditContent( ContentHandler::makeContent( $text, $title ), '', EDIT_NEW ); + + $wgCapitalLinks = $oldCapitalLinks; + } + + /** + * Steal a callback function from the primary parser, save it for + * application to our scary parser. If the hook is not installed, + * abort processing of this file. + * + * @param $name String + * @return Bool true if tag hook is present + */ + public function requireHook( $name ) { + global $wgParser; + + $wgParser->firstCallInit(); // make sure hooks are loaded. + + if ( isset( $wgParser->mTagHooks[$name] ) ) { + $this->hooks[$name] = $wgParser->mTagHooks[$name]; + } else { + echo " This test suite requires the '$name' hook extension, skipping.\n"; + return false; + } + + return true; + } + + /** + * Steal a callback function from the primary parser, save it for + * application to our scary parser. If the hook is not installed, + * abort processing of this file. + * + * @param $name String + * @return Bool true if function hook is present + */ + public function requireFunctionHook( $name ) { + global $wgParser; + + $wgParser->firstCallInit(); // make sure hooks are loaded. + + if ( isset( $wgParser->mFunctionHooks[$name] ) ) { + $this->functionHooks[$name] = $wgParser->mFunctionHooks[$name]; + } else { + echo " This test suite requires the '$name' function hook extension, skipping.\n"; + return false; + } + + return true; + } + + /** + * Run the "tidy" command on text if the $wgUseTidy + * global is true + * + * @param $text String: the text to tidy + * @return String + */ + private function tidy( $text ) { + global $wgUseTidy; + + if ( $wgUseTidy ) { + $text = MWTidy::tidy( $text ); + } + + return $text; + } + + private function wellFormed( $text ) { + $html = + Sanitizer::hackDocType() . + '<html>' . + $text . + '</html>'; + + $parser = xml_parser_create( "UTF-8" ); + + # case folding violates XML standard, turn it off + xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false ); + + if ( !xml_parse( $parser, $html, true ) ) { + $err = xml_error_string( xml_get_error_code( $parser ) ); + $position = xml_get_current_byte_index( $parser ); + $fragment = $this->extractFragment( $html, $position ); + $this->mXmlError = "$err at byte $position:\n$fragment"; + xml_parser_free( $parser ); + + return false; + } + + xml_parser_free( $parser ); + + return true; + } + + private function extractFragment( $text, $position ) { + $start = max( 0, $position - 10 ); + $before = $position - $start; + $fragment = '...' . + $this->term->color( 34 ) . + substr( $text, $start, $before ) . + $this->term->color( 0 ) . + $this->term->color( 31 ) . + $this->term->color( 1 ) . + substr( $text, $position, 1 ) . + $this->term->color( 0 ) . + $this->term->color( 34 ) . + substr( $text, $position + 1, 9 ) . + $this->term->color( 0 ) . + '...'; + $display = str_replace( "\n", ' ', $fragment ); + $caret = ' ' . + str_repeat( ' ', $before ) . + $this->term->color( 31 ) . + '^' . + $this->term->color( 0 ); + + return "$display\n$caret"; + } + + static function getFakeTimestamp( &$parser, &$ts ) { + $ts = 123; + return true; + } +} diff --git a/tests/parser/parserTests.txt b/tests/parser/parserTests.txt new file mode 100644 index 00000000..e9218dec --- /dev/null +++ b/tests/parser/parserTests.txt @@ -0,0 +1,13859 @@ +# MediaWiki Parser test cases +# Some taken from http://meta.wikimedia.org/wiki/Parser_testing +# All (C) their respective authors and released under the GPL +# +# The syntax should be fairly self-explanatory. +# +# Currently supported test options: +# One of the following three: +# +# (default) generate HTML output +# pst apply pre-save transform +# msg apply message transform +# +# Plus any combination of these: +# +# cat add category links +# ill add inter-language links +# subpage enable subpages (disabled by default) +# noxml don't check for XML well formdness +# title=[[XXX]] run test using article title XXX +# language=XXX set content language to XXX for this test +# variant=XXX set the variant of language for this test (eg zh-tw) +# disabled do not run test +# parsoid parsoid-only test (not run by PHP parser) +# php php-only test (not run by the parsoid parser) +# showtitle make the first line the title +# comment run through Linker::formatComment() instead of main parser +# local format section links in edit comment text as local links +# +# For testing purposes, temporary articles can created: +# !!article / NAMESPACE:TITLE / !!text / ARTICLE TEXT / !!endarticle +# where '/' denotes a newline. + +# This is the standard article assumed to exist. +!! article +Main Page +!! text +blah blah +!! endarticle + +!!article +Template:Foo +!!text +FOO +!!endarticle + +!! article +Template:Blank +!! text +!! endarticle + +!! article +Template:pipe +!! text +| +!! endarticle + +!!article +MediaWiki:bad image list +!!text +* [[File:Bad.jpg]] except [[Nasty page]] +!!endarticle + +!! article +Template:inner list +!! text +* item 1 +!! endarticle + +!! article +Template:tbl-start +!! text +{| +!! endarticle + +!! article +Template:tbl-end +!! text +|} +!! endarticle + +!! article +Template:! +!! text +| +!! endarticle + +!! article +Template:echo +!! text +{{{1}}} +!! endarticle + +!! article +Template:echo_with_span +!! text +<span>{{{1}}}</span> +!! endarticle + +!! article +Template:echo_with_div +!! text +<div>{{{1}}}</div> +!! endarticle + +!! article +Template:attr_str +!! text +{{{1}}}="{{{2}}}" +!! endarticle + +!! article +Template:table_attribs +!! text +<noinclude> +|</noinclude>style="color: red"| Foo +!! endarticle + +!! article +A?b +!! text +Weirdo titles! +!! endarticle + +### +### Basic tests +### +!! test +Blank input +!! input +!! result +!! end + + +!! test +Simple paragraph +!! input +This is a simple paragraph. +!! result +<p>This is a simple paragraph. +</p> +!! end + +!! test +Paragraphs with extra newline spacing +!! input +foo + +bar + + +baz + + + +booz +!! result +<p>foo +</p><p>bar +</p><p><br /> +baz +</p><p><br /> +</p><p>booz +</p> +!! end + +!! test +Parsing an URL +!! input +http://fr.wikipedia.org/wiki/🍺 +<!-- EasterEgg we love beer, better be able be able to link to it --> +!! result +<p><a rel="nofollow" class="external free" href="http://fr.wikipedia.org/wiki/🍺">http://fr.wikipedia.org/wiki/🍺</a> +</p> +!! end + +!! test +Simple list +!! input +* Item 1 +* Item 2 +!! result +<ul><li> Item 1 +</li><li> Item 2 +</li></ul> + +!! end + +!! test +Italics and bold +!! input +* plain +* plain''italic''plain +* plain''italic''plain''italic''plain +* plain'''bold'''plain +* plain'''bold'''plain'''bold'''plain +* plain''italic''plain'''bold'''plain +* plain'''bold'''plain''italic''plain +* plain''italic'''bold-italic'''italic''plain +* plain'''bold''bold-italic''bold'''plain +* plain'''''bold-italic'''italic''plain +* plain'''''bold-italic''bold'''plain +* plain''italic'''bold-italic'''''plain +* plain'''bold''bold-italic'''''plain +* plain l'''italic''plain +* plain l''''bold''' plain +!! result +<ul><li> plain +</li><li> plain<i>italic</i>plain +</li><li> plain<i>italic</i>plain<i>italic</i>plain +</li><li> plain<b>bold</b>plain +</li><li> plain<b>bold</b>plain<b>bold</b>plain +</li><li> plain<i>italic</i>plain<b>bold</b>plain +</li><li> plain<b>bold</b>plain<i>italic</i>plain +</li><li> plain<i>italic<b>bold-italic</b>italic</i>plain +</li><li> plain<b>bold<i>bold-italic</i>bold</b>plain +</li><li> plain<i><b>bold-italic</b>italic</i>plain +</li><li> plain<b><i>bold-italic</i>bold</b>plain +</li><li> plain<i>italic<b>bold-italic</b></i>plain +</li><li> plain<b>bold<i>bold-italic</i></b>plain +</li><li> plain l'<i>italic</i>plain +</li><li> plain l'<b>bold</b> plain +</li></ul> + +!! end + +### +### 2-quote opening sequence tests +### +!! test +Italics and bold: 2-quote opening sequence: (2,2) +!! input +''foo'' +!! result +<p><i>foo</i> +</p> +!!end + + +!! test +Italics and bold: 2-quote opening sequence: (2,3) +!! input +''foo''' +!! result +<p><i>foo'</i> +</p> +!!end + + +!! test +Italics and bold: 2-quote opening sequence: (2,4) +!! input +''foo'''' +!! result +<p><i>foo''</i> +</p> +!!end + + +!! test +Italics and bold: 2-quote opening sequence: (2,5) +!! input +''foo''''' +!! result +<p><i>foo</i> +</p> +!!end + + +### +### 3-quote opening sequence tests +### + +!! test +Italics and bold: 3-quote opening sequence: (3,2) +!! input +'''foo'' +!! result +<p>'<i>foo</i> +</p> +!!end + + +!! test +Italics and bold: 3-quote opening sequence: (3,3) +!! input +'''foo''' +!! result +<p><b>foo</b> +</p> +!!end + + +!! test +Italics and bold: 3-quote opening sequence: (3,4) +!! input +'''foo'''' +!! result +<p><b>foo'</b> +</p> +!!end + + +!! test +Italics and bold: 3-quote opening sequence: (3,5) +!! input +'''foo''''' +!! result +<p><b>foo</b> +</p> +!!end + + +### +### 4-quote opening sequence tests +### + +!! test +Italics and bold: 4-quote opening sequence: (4,2) +!! input +''''foo'' +!! result +<p>''<i>foo</i> +</p> +!!end + + +!! test +Italics and bold: 4-quote opening sequence: (4,3) +!! input +''''foo''' +!! result +<p>'<b>foo</b> +</p> +!!end + + +!! test +Italics and bold: 4-quote opening sequence: (4,4) +!! input +''''foo'''' +!! result +<p>'<b>foo'</b> +</p> +!!end + + +!! test +Italics and bold: 4-quote opening sequence: (4,5) +!! input +''''foo''''' +!! result +<p>'<b>foo</b> +</p> +!!end + + +### +### 5-quote opening sequence tests +### + +!! test +Italics and bold: 5-quote opening sequence: (5,2) +!! input +'''''foo'' +!! result +<p><b><i>foo</i></b> +</p> +!!end + + +!! test +Italics and bold: 5-quote opening sequence: (5,3) +!! input +'''''foo''' +!! result +<p><i><b>foo</b></i> +</p> +!!end + + +!! test +Italics and bold: 5-quote opening sequence: (5,4) +!! input +'''''foo'''' +!! result +<p><i><b>foo'</b></i> +</p> +!!end + + +!! test +Italics and bold: 5-quote opening sequence: (5,5) +!! input +'''''foo''''' +!! result +<p><i><b>foo</b></i> +</p> +!!end + +### +### multiple quote sequences in a line +### +!! test +Italics and bold: multiple quote sequences: (2,4,2) +!! input +''foo''''bar'' +!! result +<p><i>foo'<b>bar</b></i> +</p> +!!end + + +!! test +Italics and bold: multiple quote sequences: (2,4,3) +!! input +''foo''''bar''' +!! result +<p><i>foo'<b>bar</b></i> +</p> +!!end + + +!! test +Italics and bold: multiple quote sequences: (2,4,4) +!! input +''foo''''bar'''' +!! result +<p><i>foo'<b>bar'</b></i> +</p> +!!end + + +!! test +Italics and bold: multiple quote sequences: (3,4,2) +!! input +'''foo''''bar'' +!! result +<p><b>foo'</b>bar +</p> +!!end + + +!! test +Italics and bold: multiple quote sequences: (3,4,3) +!! input +'''foo''''bar''' +!! result +<p><b>foo'</b>bar +</p> +!!end + +### +### other quote tests +### +!! test +Italics and bold: other quote tests: (2,3,5) +!! input +''this is about '''foo's family''''' +!! result +<p><i>this is about <b>foo's family</b></i> +</p> +!!end + + +!! test +Italics and bold: other quote tests: (2,(3,3),2) +!! input +''this is about '''foo's''' family'' +!! result +<p><i>this is about <b>foo's</b> family</i> +</p> +!!end + + +!! test +Italics and bold: other quote tests: (3,2,3,2) +!! input +'''this is about ''foo'''s family'' +!! result +<p><b>this is about <i>foo</i></b><i>s family</i> +</p> +!!end + + +!! test +Italics and bold: other quote tests: (3,2,3,3) +!! input +'''this is about ''foo'''s family''' +!! result +<p>'<i>this is about </i>foo<b>s family</b> +</p> +!!end + + +!! test +Italics and bold: other quote tests: (3,(2,2),3) +!! input +'''this is about ''foo's'' family''' +!! result +<p><b>this is about <i>foo's</i> family</b> +</p> +!!end + + +!! test +Italicized possessive +!! input +The ''[[Main Page]]'''s talk page. +!! result +<p>The <i><a href="/wiki/Main_Page" title="Main Page">Main Page</a>'</i>s talk page. +</p> +!! end + +### +### Non-html5 tags +### + +!! test +Non-html5 tags should be accepted +!! input +<center>''foo''</center> +<big>''foo''</big> +<font>''foo''</font> +<strike>''foo''</strike> +<tt>''foo''</tt> +!! result +<center><i>foo</i></center> +<p><big><i>foo</i></big> +<font><i>foo</i></font> +<strike><i>foo</i></strike> +<tt><i>foo</i></tt> +</p> +!! end + +### +### <nowiki> test cases +### + +!! test +<nowiki> unordered list +!! input +<nowiki>* This is not an unordered list item.</nowiki> +!! result +<p>* This is not an unordered list item. +</p> +!! end + +!! test +<nowiki> spacing +!! input +<nowiki>Lorem ipsum dolor + +sed abit. + sed nullum. + +:and a colon +</nowiki> +!! result +<p>Lorem ipsum dolor + +sed abit. + sed nullum. + +:and a colon + +</p> +!! end + +!! test +nowiki 3 +!! input +:There is not nowiki. +:There is <nowiki>nowiki</nowiki>. + +#There is not nowiki. +#There is <nowiki>nowiki</nowiki>. + +*There is not nowiki. +*There is <nowiki>nowiki</nowiki>. +!! result +<dl><dd>There is not nowiki. +</dd><dd>There is nowiki. +</dd></dl> +<ol><li>There is not nowiki. +</li><li>There is nowiki. +</li></ol> +<ul><li>There is not nowiki. +</li><li>There is nowiki. +</li></ul> + +!! end + +!! test +Entities inside <nowiki> +!! input +<nowiki><</nowiki> +!! result +<p>< +</p> +!! end + + +### +### Comments +### +!! test +Comments and Indent-Pre +!! input +<!-- comment 1 --> asdf + +<!-- comment 1 --> asdf +<!-- comment 2 --> + +<!-- comment 1 --> asdf +<!-- comment 2 -->xyz + +<!-- comment 1 --> asdf +<!-- comment 2 --> xyz +!! result +<pre>asdf +</pre> +<pre>asdf +</pre> +<pre>asdf +</pre> +<p>xyz +</p> +<pre>asdf +xyz +</pre> +!! end + +!! test +Comment test 2a +!! input +asdf +<!-- comment 1 --> +jkl +!! result +<p>asdf +jkl +</p> +!! end + +!! test +Comment test 2b +!! input +asdf +<!-- comment 1 --> + +jkl +!! result +<p>asdf +</p><p>jkl +</p> +!! end + +!! test +Comment test 3 +!! input +asdf +<!-- comment 1 --> +<!-- comment 2 --> +jkl +!! result +<p>asdf +jkl +</p> +!! end + +!! test +Comment test 4 +!! input +asdf<!-- comment 1 -->jkl +!! result +<p>asdfjkl +</p> +!! end + +!! test +Comment spacing +!! input +a + <!-- foo --> b <!-- bar --> +c +!! result +<p>a +</p> +<pre> b +</pre> +<p>c +</p> +!! end + +!! test +Comment whitespace +!! input +<!-- returns a single newline, not nothing, since the newline after > is not stripped --> +!! result + +!! end + +!! test +Comment semantics and delimiters +!! input +<!-- --><!----><!-----><!------> +!! result + +!! end + +!! test +Comment semantics and delimiters, redux +!! input +<!-- In SGML every "foo" here would actually show up in the text -- foo -- bar +-- foo -- funky huh? ... --> +!! result + +!! end + +!! test +Comment semantics and delimiters: directors cut +!! input +<!-- ... However we like to keep things simple and somewhat XML-ish so we eat +everything starting with < followed by !-- until the first -- and > we see, +that wouldn't be valid XML however, since in XML -- has to terminate a comment +-->--> +!! result +<p>--> +</p> +!! end + +!! test +Comment semantics: nesting +!! input +<!--<!-- no, we're not going to do anything fancy here -->--> +!! result +<p>--> +</p> +!! end + +!! test +Comment semantics: unclosed comment at end +!! input +<!--This comment will run out to the end of the document +!! result + +!! end + +!! test +Comment in template title +!! input +{{f<!---->oo}} +!! result +<p>FOO +</p> +!! end + +!! test +Comment on its own line post-expand +!! input +a +{{blank}}<!----> +b +!! result +<p>a +</p><p>b +</p> +!! end + +!! test +Comment on its own line post-expand with non-significant whitespace +!! input +a + {{blank}} <!----> +b +!! result +<p>a +</p><p>b +</p> +!! end + +### +### paragraph wraping tests +### +!! test +No block tags +!! input +a + +b +!! result +<p>a +</p><p>b +</p> +!! end +!! test +Block tag on one line +!! input +a <div>foo</div> + +b +!! result +a <div>foo</div> +<p>b +</p> +!! end + +!! test +Block tag on both lines +!! input +a <div>foo</div> + +b <div>foo</div> +!! result +a <div>foo</div> +b <div>foo</div> + +!! end + +!! test +Multiple lines without block tags +!! input +<div>foo</div> a +b +c +d<!--foo--> e +x <div>foo</div> z +!! result +<div>foo</div> a +<p>b +c +d e +</p> +x <div>foo</div> z + +!! end + +!! test +Empty lines between block tags to test open p-tags are closed between the block tags +!! input +<div></div> + + +<div></div>a + +b +!! result +<div></div> +<p><br /> +</p> +<div></div>a +<p>b +</p> +!! end + +### +### Preformatted text +### +!! test +Preformatted text +!! input + This is some + Preformatted text + With ''italic'' + And '''bold''' + And a [[Main Page|link]] +!! result +<pre>This is some +Preformatted text +With <i>italic</i> +And <b>bold</b> +And a <a href="/wiki/Main_Page" title="Main Page">link</a> +</pre> +!! end + +!! test +Ident preformatting with inline content +!! input + a + ''b'' +!! result +<pre>a +<i>b</i> +</pre> +!! end + +!! test +<pre> with <nowiki> inside (compatibility with 1.6 and earlier) +!! input +<pre><nowiki> +<b> +<cite> +<em> +</nowiki></pre> +!! result +<pre> +<b> +<cite> +<em> +</pre> + +!! end + +!! test +Regression with preformatted in <center> +!! input +<center> + Blah +</center> +!! result +<center> +<pre>Blah +</pre> +</center> + +!! end + +# Expected output in the following test is not really expected (there should be +# <pre> in the output) -- it's only testing for well-formedness. +!! test +Bug 6200: Preformatted in <blockquote> +!! input +<blockquote> + Blah +</blockquote> +!! result +<blockquote> + Blah +</blockquote> + +!! end + +!! test +<pre> with attributes (bug 3202) +!! input +<pre style="background: blue; color:white">Bluescreen of WikiDeath</pre> +!! result +<pre style="background: blue; color:white">Bluescreen of WikiDeath</pre> + +!! end + +!! test +<pre> with width attribute (bug 3202) +!! input +<pre width="8">Narrow screen goodies</pre> +!! result +<pre width="8">Narrow screen goodies</pre> + +!! end + +!! test +<pre> with forbidden attribute (bug 3202) +!! input +<pre width="8" onmouseover="alert(document.cookie)">Narrow screen goodies</pre> +!! result +<pre width="8">Narrow screen goodies</pre> + +!! end + +!! test +Entities inside <pre> +!! input +<pre><</pre> +!! result +<pre><</pre> + +!! end + +!! test +<pre> with forbidden attribute values (bug 3202) +!! input +<pre width="8" style="border-width: expression(alert(document.cookie))">Narrow screen goodies</pre> +!! result +<pre width="8" style="/* insecure input */">Narrow screen goodies</pre> + +!! end + +!! test +<nowiki> inside <pre> (bug 13238) +!! input +<pre> +<nowiki> +</pre> +<pre> +<nowiki></nowiki> +</pre> +<pre><nowiki><nowiki></nowiki>Foo<nowiki></nowiki></nowiki></pre> +!! result +<pre> +<nowiki> +</pre> +<pre> + +</pre> +<pre><nowiki>Foo</nowiki></pre> + +!! end + +!! test +<nowiki> and <pre> preference (first one wins) +!! input +<pre> +<nowiki> +</pre> +</nowiki> +</pre> + +<nowiki> +<pre> +<nowiki> +</pre> +</nowiki> +</pre> + +!! result +<pre> +<nowiki> +</pre> +<p></nowiki> +</pre> +</p><p> +<pre> +<nowiki> +</pre> + +</pre> +</p> +!! end + +!! test +</pre> inside nowiki +!! input +<nowiki></pre></nowiki> +!! result +<p></pre> +</p> +!! end + +!!test +Templates: Indent-Pre: 1a. Templates that break a line should suppress <pre> +!!input + {{echo|}} +!!result + +!!end + +!!test +Templates: Indent-Pre: 1b. Templates that break a line should suppress <pre> +!!input + {{echo| +foo}} +!!result +<p>foo +</p> +!!end + +!! test +Templates: Indent-Pre: 1c: Wrapping should be based on expanded content +!! input + {{echo|a +b}} +!!result +<pre>a +</pre> +<p>b +</p> +!!end + +!! test +Templates: Indent-Pre: 1d: Wrapping should be based on expanded content +!! input + {{echo|a +b +c + d +e +}} +!!result +<pre>a +</pre> +<p>b +c +</p> +<pre>d +</pre> +<p>e +</p> +!!end + +!!test +Templates: Indent-Pre: 1e. Wrapping should be based on expanded content +!!input +{{echo| foo}} + +{{echo| foo}}{{echo| bar}} + +{{echo| foo}} +{{echo| bar}} + +{{echo|<!--cmt--> foo}} + +<!--cmt-->{{echo| foo}} + +{{echo|{{echo| }}bar}} +!!result +<pre>foo +</pre> +<pre>foo bar +</pre> +<pre>foo +bar +</pre> +<pre>foo +</pre> +<pre>foo +</pre> +<pre>bar +</pre> +!!end + +!! test +Templates: Indent-Pre: 1f: Wrapping should be based on expanded content +!! input +{{echo| }}a + +{{echo| + }}a + +{{echo| + b}} + +{{echo|a + }}b + +{{echo|a +}} b +!!result +<pre>a +</pre> +<p><br /> +</p> +<pre>a +</pre> +<p><br /> +</p> +<pre>b +</pre> +<p>a +</p> +<pre>b +</pre> +<p>a +</p> +<pre>b +</pre> +!!end + +!! test +Templates: Single-line variant of parameter whitespace stripping test +!! input +{{echo| a}} + +{{echo|1= a}} + +{{echo|{{echo| a}}}} + +{{echo|1={{echo| a}}}} +!! result +<pre>a +</pre> +<p>a +</p> +<pre>a +</pre> +<p>a +</p> +!! end + +!! test +Templates: Strip whitespace from named parameters, but not positional ones +!! input +{{echo| + foo}} + +{{echo| +* foo}} + +{{echo| 1 = + foo}} + +{{echo| 1 = +* foo}} +!! result +<pre>foo +</pre> +<p><br /> +</p> +<ul><li> foo +</li></ul> +<p>foo +</p> +<ul><li> foo +</li></ul> + +!! end + +### +### Parsoid-centric tests for testing RT edge cases for pre +### + +!!test +1a. Indent-Pre and Comments +!!input + a +<!--a--> +c +!!result +<pre>a +</pre> +<p>c +</p> +!!end + +!!test +1b. Indent-Pre and Comments +!!input + a + <!--a--> +c +!!result +<pre>a +</pre> +<p>c +</p> +!!end + +!!test +1c. Indent-Pre and Comments +!!input +<!--a--> a + + <!--a--> a +!!result +<pre> a +</pre> +<pre> a +</pre> +!!end + +!!test +2a. Indent-Pre and tables +!!input + {| + |- + !h1!!h2 + |foo||bar + |} +!!result +<table> + +<tr> +<th>h1</th> +<th>h2 +</th> +<td>foo</td> +<td>bar +</td></tr></table> + +!!end + +!!test +2b. Indent-Pre and tables +!!input + {| + |- +|foo +|} +!!result +<table> + +<tr> +<td>foo +</td></tr></table> + +!!end + +!!test +2c. Indent-Pre and tables (bug 42252) +!!input +{| + |+ foo + ! | bar +|} +!!result +<table> +<caption> foo +</caption> +<tr> +<th> bar +</th></tr></table> + +!!end + +!!test +3a. Indent-Pre and block tags (single-line html) +!!input + <p> foo </p> + <div> foo </div> + <span> foo </span> +!!result + <p> foo </p> + <div> foo </div> +<pre><span> foo </span> +</pre> +!!end + +!!test +3b. Indent-Pre and block tags (pre-content on separate line) +!!input +<p> + foo +</p> + +<div> + foo +</div> + +<center> + foo +</center> + +<blockquote> + foo +</blockquote> + +<table><tr><td> + foo +</td></tr></table> + +<ul><li> + foo +</li></ul> + +!!result +<p> + foo +</p> +<div> +<pre>foo +</pre> +</div> +<center> +<pre>foo +</pre> +</center> +<blockquote> + foo +</blockquote> +<table><tr><td> +<pre>foo +</pre> +</td></tr></table> +<ul><li> + foo +</li></ul> + +!!end + +!!test +4. Multiple spaces at start-of-line +!!input + <p> foo </p> + foo + {| +|foo +|} +!!result + <p> foo </p> +<pre> foo +</pre> +<table> +<tr> +<td>foo +</td></tr></table> + +!!end + +!! test +5. White-space in indent-pre +NOTE: the white-space char on 2nd line is significant +!! input + a<br/> + + b +!! result +<pre>a<br /> + +b +</pre> +!! end + +### +### HTML-pre (some to spec PHP parser behavior and some Parsoid-RT-centric) +### + +!!test +HTML-pre: 1. embedded newlines +!!input +<pre>foo</pre> + +<pre> +foo +</pre> + +<pre> + +foo +</pre> + +<pre> + + +foo +</pre> +!!result +<pre>foo</pre> +<pre> +foo +</pre> +<pre> + +foo +</pre> +<pre> + + +foo +</pre> + +!!end + +!!test +HTML-pre: 2: indented text +!!input +<pre> + foo +</pre> +!!result +<pre> + foo +</pre> + +!!end + +!!test +HTML-pre: 3: other wikitext +!!input +<pre> +* foo +# bar += no-h = +'' no-italic '' +[[ NoLink ]] +</pre> +!!result +<pre> +* foo +# bar += no-h = +'' no-italic '' +[[ NoLink ]] +</pre> + +!!end + +### +### Definition lists +### +!! test +Simple definition +!! input +; name : Definition +!! result +<dl><dt> name </dt><dd> Definition +</dd></dl> + +!! end + +!! test +Definition list for indentation only +!! input +: Indented text +!! result +<dl><dd> Indented text +</dd></dl> + +!! end + +!! test +Definition list with no space +!! input +;name:Definition +!! result +<dl><dt>name</dt><dd>Definition +</dd></dl> + +!!end + +!! test +Definition list with URL link +!! input +; http://example.com/ : definition +!! result +<dl><dt> <a rel="nofollow" class="external free" href="http://example.com/">http://example.com/</a> </dt><dd> definition +</dd></dl> + +!! end + +!! test +Definition list with bracketed URL link +!! input +;[http://www.example.com/ Example]:Something about it +!! result +<dl><dt><a rel="nofollow" class="external text" href="http://www.example.com/">Example</a></dt><dd>Something about it +</dd></dl> + +!! end + +!! test +Definition list with wikilink containing colon +!! input +; [[Help:FAQ]]: The least-read page on Wikipedia +!! result +<dl><dt> <a href="/index.php?title=Help:FAQ&action=edit&redlink=1" class="new" title="Help:FAQ (page does not exist)">Help:FAQ</a></dt><dd> The least-read page on Wikipedia +</dd></dl> + +!! end + +# At Brion's and JeLuF's insistence... :) +!! test +Definition list with news link containing colon +!! input +; news:alt.wikipedia.rox: This isn't even a real newsgroup! +!! result +<dl><dt> <a rel="nofollow" class="external free" href="news:alt.wikipedia.rox">news:alt.wikipedia.rox</a></dt><dd> This isn't even a real newsgroup! +</dd></dl> + +!! end + +!! test +Malformed definition list with colon +!! input +; news:alt.wikipedia.rox -- don't crash or enter an infinite loop +!! result +<dl><dt> <a rel="nofollow" class="external free" href="news:alt.wikipedia.rox">news:alt.wikipedia.rox</a> -- don't crash or enter an infinite loop +</dt></dl> + +!! end + +!! test +Definition lists: colon in external link text +!! input +; [http://www.wikipedia2.org/ Wikipedia : The Next Generation]: OK, I made that up +!! result +<dl><dt> <a rel="nofollow" class="external text" href="http://www.wikipedia2.org/">Wikipedia : The Next Generation</a></dt><dd> OK, I made that up +</dd></dl> + +!! end + +!! test +Definition lists: colon in HTML attribute +!! input +;<b style="display: inline">bold</b> +!! result +<dl><dt><b style="display: inline">bold</b> +</dt></dl> + +!! end + +!! test +Definition lists: self-closed tag +!! input +;one<br/>two : two-line fun +!! result +<dl><dt>one<br />two </dt><dd> two-line fun +</dd></dl> + +!! end + +!! test +Bug 11748: Literal closing tags +!! input +<dl> +<dt>test 1</dt> +<dd>test test test test test</dd> +<dt>test 2</dt> +<dd>test test test test test</dd> +</dl> +!! result +<dl> +<dt>test 1</dt> +<dd>test test test test test</dd> +<dt>test 2</dt> +<dd>test test test test test</dd> +</dl> + +!! end + +!! test +Definition and unordered list using wiki syntax nested in unordered list using html tags. +!! input +<ul><li> +; term : description +* unordered +</li> +</ul> +!! result +<ul><li> +<dl><dt> term </dt><dd> description +</dd></dl> +<ul><li> unordered +</li></ul> +</li> +</ul> + +!! end + +!! test + +Definition list with empty definition and following paragraph +!! input +; term: +Paragraph text +!! result +<dl><dt> term</dt><dd> +</dd></dl> +<p>Paragraph text +</p> +!! end + +!! test +Nested definition lists using html syntax +!! input +<dl><dd> +<dl> +<dd>Foo</dd> +</dl> +</dd></dl> +!! result +<dl><dd> +<dl> +<dd>Foo</dd> +</dl> +</dd></dl> + +!! end + +!! test +Definition Lists: No nesting: Multiple dd's +!! input +;x +:a +:b +!! result +<dl><dt>x +</dt><dd>a +</dd><dd>b +</dd></dl> + +!! end + +!! test +Definition Lists: Indentation: Regular +!! input +:i1 +::i2 +:::i3 +!! result +<dl><dd>i1 +<dl><dd>i2 +<dl><dd>i3 +</dd></dl> +</dd></dl> +</dd></dl> + +!! end + +!! test +Definition Lists: Indentation: Missing 1st level +!! input +::i2 +:::i3 +!! result +<dl><dd><dl><dd>i2 +<dl><dd>i3 +</dd></dl> +</dd></dl> +</dd></dl> + +!! end + +!! test +Definition Lists: Indentation: Multi-level indent +!! input +:::i3 +!! result +<dl><dd><dl><dd><dl><dd>i3 +</dd></dl> +</dd></dl> +</dd></dl> + +!! end + +!! test +Definition Lists: Hacky use to indent tables +!! input +::{| +|foo +|bar +|} +this text +should be left alone +!! result +<dl><dd><dl><dd><table> +<tr> +<td>foo +</td> +<td>bar +</td></tr></table></dd></dl></dd></dl> +<p>this text +should be left alone +</p> +!! end +## The PHP parser treats : items (dd) without a corresponding ; item (dt) +## as an empty dt item. It also ignores all but the last ";" when followed +## by ":" later on. So, ";" are not ignored in ";;;t3" but are ignored in +## ";;;t3 :d1". So, PHP parser behavior is a little inconsistent wrt multiple +## ";"s. +## +## Ex: ";;t2 ::d2" is transformed into: +## +## <dl> +## <dt>t2 </dt> +## <dd> +## <dl> +## <dt></dt> +## <dd>d2</dd> +## </dl> +## </dd> +## </dl> +## +## But, Parsoid treats "; :" as a tight atomic unit and excess ":" as plain text +## So, the same wikitext above (;;t2 ::d2) is transformed into: +## +## <dl> +## <dt> +## <dl> +## <dt>t2 </dt> +## <dd>:d2</dd> +## </dl> +## </dt> +## </dl> +## +## All Parsoid only definition list tests have this difference. +## +## See also: https://bugzilla.wikimedia.org/show_bug.cgi?id=6569 +## and http://lists.wikimedia.org/pipermail/wikitext-l/2011-November/000483.html + +!! test +Table / list interaction: indented table with lists in table contents +!! input +:{| +|- +| a +* b +|- +| c +* d +|} +!! result +<dl><dd><table> + +<tr> +<td> a +<ul><li> b +</li></ul> +</td></tr> +<tr> +<td> c +<ul><li> d +</li></ul> +</td></tr></table></dd></dl> + +!! end + +!!test +Table / list interaction: lists nested in tables nested in indented lists +!!input +:{| +| +:a +:b +| +*c +*d +|} + +*e +*f +!!result +<dl><dd><table> +<tr> +<td> +<dl><dd>a +</dd><dd>b +</dd></dl> +</td> +<td> +<ul><li>c +</li><li>d +</li></ul> +</td></tr></table></dd></dl> +<ul><li>e +</li><li>f +</li></ul> + +!!end + +!! test +Definition Lists: Nesting: Multi-level (Parsoid only) +!! options +parsoid +!! input +;t1 :d1 +;;t2 ::d2 +;;;t3 :::d3 +!! result +<dl> + <dt>t1 </dt> + <dd>d1</dd> + <dt> + <dl> + <dt>t2 </dt> + <dd>:d2</dd> + <dt> + <dl> + <dt>t3 </dt> + <dd>::d3</dd> + </dl> + </dt> + </dl> + </dt> +</dl> + + +!! end + + +!! test +Definition Lists: Nesting: Test 2 (Parsoid only) +!! options +parsoid +!! input +;t1 +::d2 +!! result +<dl> + <dt>t1</dt> + <dd> + <dl> + <dd>d2</dd> + </dl> + </dd> +</dl> + +!! end + + +!! test +Definition Lists: Nesting: Test 3 (Parsoid only) +!! options +parsoid +!! input +:;t1 +::::d2 +!! result +<dl> + <dd> + <dl> + <dt>t1</dt> + <dd> + <dl> + <dd> + <dl> + <dd>d2</dd> + </dl> + </dd> + </dl> + </dd> + </dl> + </dd> +</dl> + +!! end + + +!! test +Definition Lists: Nesting: Test 4 +!! input +::;t3 +:::d3 +!! result +<dl><dd><dl><dd><dl><dt>t3 +</dt><dd>d3 +</dd></dl> +</dd></dl> +</dd></dl> + +!! end + + +!! test +Definition Lists: Mixed Lists: Test 1 +!! input +:;* foo +::* bar +:; baz +!! result +<dl><dd><dl><dt><ul><li> foo +</li><li> bar +</li></ul> +</dt></dl> +<dl><dt> baz +</dt></dl> +</dd></dl> + +!! end + + +!! test +Definition Lists: Mixed Lists: Test 2 +!! input +*: d1 +*: d2 +!! result +<ul><li><dl><dd> d1 +</dd><dd> d2 +</dd></dl> +</li></ul> + +!! end + + +!! test +Definition Lists: Mixed Lists: Test 3 +!! input +*::: d1 +*::: d2 +!! result +<ul><li><dl><dd><dl><dd><dl><dd> d1 +</dd><dd> d2 +</dd></dl> +</dd></dl> +</dd></dl> +</li></ul> + +!! end + + +!! test +Definition Lists: Mixed Lists: Test 4 +!! input +*;d1 :d2 +*;d3 :d4 +!! result +<ul><li><dl><dt>d1 </dt><dd>d2 +</dd><dt>d3 </dt><dd>d4 +</dd></dl> +</li></ul> + +!! end + + +!! test +Definition Lists: Mixed Lists: Test 5 +!! input +*:d1 +*:: d2 +!! result +<ul><li><dl><dd>d1 +<dl><dd> d2 +</dd></dl> +</dd></dl> +</li></ul> + +!! end + + +!! test +Definition Lists: Mixed Lists: Test 6 +!! input +#*:d1 +#*::: d3 +!! result +<ol><li><ul><li><dl><dd>d1 +<dl><dd><dl><dd> d3 +</dd></dl> +</dd></dl> +</dd></dl> +</li></ul> +</li></ol> + +!! end + + +!! test +Definition Lists: Mixed Lists: Test 7 +!! input +:* d1 +:* d2 +!! result +<dl><dd><ul><li> d1 +</li><li> d2 +</li></ul> +</dd></dl> + +!! end + + +!! test +Definition Lists: Mixed Lists: Test 8 +!! input +:* d1 +::* d2 +!! result +<dl><dd><ul><li> d1 +</li></ul> +<dl><dd><ul><li> d2 +</li></ul> +</dd></dl> +</dd></dl> + +!! end + + +!! test +Definition Lists: Mixed Lists: Test 9 +!! input +*;foo :bar +!! result +<ul><li><dl><dt>foo </dt><dd>bar +</dd></dl> +</li></ul> + +!! end + + +!! test +Definition Lists: Mixed Lists: Test 10 +!! input +*#;foo :bar +!! result +<ul><li><ol><li><dl><dt>foo </dt><dd>bar +</dd></dl> +</li></ol> +</li></ul> + +!! end + + +!! test +Definition Lists: Mixed Lists: Test 11 +!! input +*#*#;*;;foo :bar +*#*#;boo :baz +!! result +<ul><li><ol><li><ul><li><ol><li><dl><dt>foo </dt><dd><ul><li><dl><dt><dl><dt>bar +</dt></dl> +</dd></dl> +</li></ul> +</dd></dl> +<dl><dt>boo </dt><dd>baz +</dd></dl> +</li></ol> +</li></ul> +</li></ol> +</li></ul> + +!! end + + +!! test +Definition Lists: Weird Ones: Test 1 +!! input +*#;*::;; foo : bar (who uses this?) +!! result +<ul><li><ol><li><dl><dt> foo </dt><dd><ul><li><dl><dd><dl><dd><dl><dt><dl><dt> bar (who uses this?) +</dt></dl> +</dd></dl> +</dd></dl> +</dd></dl> +</li></ul> +</dd></dl> +</li></ol> +</li></ul> + +!! end + +### +### External links +### +!! test +External links: non-bracketed +!! input +Non-bracketed: http://example.com +!! result +<p>Non-bracketed: <a rel="nofollow" class="external free" href="http://example.com">http://example.com</a> +</p> +!! end + +!! test +External links: numbered +!! input +Numbered: [http://example.com] +Numbered: [http://example.net] +Numbered: [http://example.com] +!! result +<p>Numbered: <a rel="nofollow" class="external autonumber" href="http://example.com">[1]</a> +Numbered: <a rel="nofollow" class="external autonumber" href="http://example.net">[2]</a> +Numbered: <a rel="nofollow" class="external autonumber" href="http://example.com">[3]</a> +</p> +!!end + +!! test +External links: specified text +!! input +Specified text: [http://example.com link] +!! result +<p>Specified text: <a rel="nofollow" class="external text" href="http://example.com">link</a> +</p> +!!end + +!! test +External links: trail +!! input +Linktrails should not work for external links: [http://example.com link]s +!! result +<p>Linktrails should not work for external links: <a rel="nofollow" class="external text" href="http://example.com">link</a>s +</p> +!! end + +!! test +External links: dollar sign in URL +!! input +http://example.com/1$2345 +!! result +<p><a rel="nofollow" class="external free" href="http://example.com/1$2345">http://example.com/1$2345</a> +</p> +!! end + +!! test +External links: dollar sign in URL (named) +!! input +[http://example.com/1$2345] +!! result +<p><a rel="nofollow" class="external autonumber" href="http://example.com/1$2345">[1]</a> +</p> +!!end + +!! test +External links: open square bracket forbidden in URL (bug 4377) +!! input +http://example.com/1[2345 +!! result +<p><a rel="nofollow" class="external free" href="http://example.com/1">http://example.com/1</a>[2345 +</p> +!! end + +!! test +External links: open square bracket forbidden in URL (named) (bug 4377) +!! input +[http://example.com/1[2345] +!! result +<p><a rel="nofollow" class="external text" href="http://example.com/1">[2345</a> +</p> +!!end + +!! test +External links: nowiki in URL link text (bug 6230) +!!input +[http://example.com/ <nowiki>''example site''</nowiki>] +!! result +<p><a rel="nofollow" class="external text" href="http://example.com/">''example site''</a> +</p> +!! end + +!! test +External links: newline forbidden in text (bug 6230 regression check) +!! input +[http://example.com/ first +second] +!! result +<p>[<a rel="nofollow" class="external free" href="http://example.com/">http://example.com/</a> first +second] +</p> +!!end + +!! test +External links: Pipe char between url and text +!! input +[http://example.com | link] +!! result +<p><a rel="nofollow" class="external text" href="http://example.com">| link</a> +</p> +!!end + +!! test +External links: protocol-relative URL in brackets +!! input +[//example.com/ Test] +!! result +<p><a rel="nofollow" class="external text" href="//example.com/">Test</a> +</p> +!! end + +!! test +External links: protocol-relative URL in brackets without text +!! input +[//example.com] +!! result +<p><a rel="nofollow" class="external autonumber" href="//example.com">[1]</a> +</p> +!! end + +!! test +External links: protocol-relative URL in free text is left alone +!! input +//example.com/Foo +!! result +<p>//example.com/Foo +</p> +!!end + +!! test +External links: protocol-relative URL in the middle of a word is left alone (bug 30269) +!! input +foo//example.com/Foo +!! result +<p>foo//example.com/Foo +</p> +!! end + +!! test +External image +!! input +External image: http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png +!! result +<p>External image: <img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png" /> +</p> +!! end + +!! test +External image from https +!! input +External image from https: https://meta.wikimedia.org/upload/f/f1/Ncwikicol.png +!! result +<p>External image from https: <img src="https://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png" /> +</p> +!! end + +!! test +Link to non-http image, no img tag +!! input +Link to non-http image, no img tag: ftp://example.com/test.jpg +!! result +<p>Link to non-http image, no img tag: <a rel="nofollow" class="external free" href="ftp://example.com/test.jpg">ftp://example.com/test.jpg</a> +</p> +!! end + +!! test +External links: terminating separator +!! input +Terminating separator: http://example.com/thing, +!! result +<p>Terminating separator: <a rel="nofollow" class="external free" href="http://example.com/thing">http://example.com/thing</a>, +</p> +!! end + +!! test +External links: intervening separator +!! input +Intervening separator: http://example.com/1,2,3 +!! result +<p>Intervening separator: <a rel="nofollow" class="external free" href="http://example.com/1,2,3">http://example.com/1,2,3</a> +</p> +!! end + +!! test +External links: old bug with URL in query +!! input +Old bug with URL in query: [http://example.com/thing?url=http://example.com link] +!! result +<p>Old bug with URL in query: <a rel="nofollow" class="external text" href="http://example.com/thing?url=http://example.com">link</a> +</p> +!! end + +!! test +External links: old URL-in-URL bug, mixed protocols +!! input +And again with mixed protocols: [ftp://example.com?url=http://example.com link] +!! result +<p>And again with mixed protocols: <a rel="nofollow" class="external text" href="ftp://example.com?url=http://example.com">link</a> +</p> +!!end + +!! test +External links: URL in text +!! input +URL in text: [http://example.com http://example.com] +!! result +<p>URL in text: <a rel="nofollow" class="external free" href="http://example.com">http://example.com</a> +</p> +!! end + +!! test +External links: Clickable images +!! input +ja-style clickable images: [http://example.com http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png] +!! result +<p>ja-style clickable images: <a rel="nofollow" class="external text" href="http://example.com"><img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png" /></a> +</p> +!!end + +!! test +External links: raw ampersand +!! input +Old & use: http://x&y +!! result +<p>Old & use: <a rel="nofollow" class="external free" href="http://x&y">http://x&y</a> +</p> +!! end + +!! test +External links: encoded ampersand +!! input +Old & use: http://x&y +!! result +<p>Old & use: <a rel="nofollow" class="external free" href="http://x&y">http://x&y</a> +</p> +!! end + +!! test +External links: encoded equals (bug 6102) +!! input +http://example.com/?foo=bar +!! result +<p><a rel="nofollow" class="external free" href="http://example.com/?foo=bar">http://example.com/?foo=bar</a> +</p> +!! end + +!! test +External links: [raw ampersand] +!! input +Old & use: [http://x&y] +!! result +<p>Old & use: <a rel="nofollow" class="external autonumber" href="http://x&y">[1]</a> +</p> +!! end + +!! test +External links: [encoded ampersand] +!! input +Old & use: [http://x&y] +!! result +<p>Old & use: <a rel="nofollow" class="external autonumber" href="http://x&y">[1]</a> +</p> +!! end + +!! test +External links: [encoded equals] (bug 6102) +!! input +[http://example.com/?foo=bar] +!! result +<p><a rel="nofollow" class="external autonumber" href="http://example.com/?foo=bar">[1]</a> +</p> +!! end + +!! test +External links: [IDN ignored character reference in hostname; strip it right off] +!! input +[http://e‌xample.com/] +!! result +<p><a rel="nofollow" class="external autonumber" href="http://example.com/">[1]</a> +</p> +!! end + +# FIXME: This test (the IDN characters in the text of a link) is an inconsistency. +# Where an external link could easily circumvent the sanitization of the text of +# a link like this (where an IDN-ignore character is in the URL somewhere), this +# test demands a higher standard. That's a bit strange. +# +# Example: +# +# http://example.com -> [http://example.com|http://example.com] +# [http://example.com|http://example.com] -> [http://example.com|http://example.com] +# +# The first example is sanitized, but the second is not. Any security benefits +# from this production are trivial to circumvent. Either remove this test and +# let the parser(s) do their thing unaccosted, or fix the inconsistency and change +# the test accordingly. +# +# All our love, +# The Parsoid team. +!! test +External links: IDN ignored character reference in hostname; strip it right off +!! input +http://e‌xample.com/ +!! result +<p><a rel="nofollow" class="external free" href="http://example.com/">http://example.com/</a> +</p> +!! end + +!! test +External links: www.jpeg.org (bug 554) +!! input +http://www.jpeg.org +!!result +<p><a rel="nofollow" class="external free" href="http://www.jpeg.org">http://www.jpeg.org</a> +</p> +!! end + +!! test +External links: URL within URL (original bug 2) +!! input +[http://www.unausa.org/newindex.asp?place=http://www.unausa.org/programs/mun.asp] +!! result +<p><a rel="nofollow" class="external autonumber" href="http://www.unausa.org/newindex.asp?place=http://www.unausa.org/programs/mun.asp">[1]</a> +</p> +!! end + +!! test +BUG 361: URL inside bracketed URL +!! input +[http://www.example.com/foo http://www.example.com/bar] +!! result +<p><a rel="nofollow" class="external text" href="http://www.example.com/foo">http://www.example.com/bar</a> +</p> +!! end + +!! test +BUG 361: URL within URL, not bracketed +!! input +http://www.example.com/foo?=http://www.example.com/bar +!! result +<p><a rel="nofollow" class="external free" href="http://www.example.com/foo?=http://www.example.com/bar">http://www.example.com/foo?=http://www.example.com/bar</a> +</p> +!! end + +!! test +BUG 289: ">"-token in URL-tail +!! input +http://www.example.com/<hello> +!! result +<p><a rel="nofollow" class="external free" href="http://www.example.com/">http://www.example.com/</a><hello> +</p> +!!end + +!! test +BUG 289: literal ">"-token in URL-tail +!! input +http://www.example.com/<b>html</b> +!! result +<p><a rel="nofollow" class="external free" href="http://www.example.com/">http://www.example.com/</a><b>html</b> +</p> +!!end + +!! test +BUG 289: ">"-token in bracketed URL +!! input +[http://www.example.com/<hello> stuff] +!! result +<p><a rel="nofollow" class="external text" href="http://www.example.com/"><hello> stuff</a> +</p> +!!end + +!! test +BUG 289: literal ">"-token in bracketed URL +!! input +[http://www.example.com/<b>html</b> stuff] +!! result +<p><a rel="nofollow" class="external text" href="http://www.example.com/"><b>html</b> stuff</a> +</p> +!!end + +!! test +BUG 289: literal double quote at end of URL +!! input +http://www.example.com/"hello" +!! result +<p><a rel="nofollow" class="external free" href="http://www.example.com/">http://www.example.com/</a>"hello" +</p> +!!end + +!! test +BUG 289: literal double quote in bracketed URL +!! input +[http://www.example.com/"hello" stuff] +!! result +<p><a rel="nofollow" class="external text" href="http://www.example.com/">"hello" stuff</a> +</p> +!!end + +!! test +External links: multiple legal whitespace is fine, Magnus. Don't break it please. (bug 5081) +!! input +[http://www.example.com test] +!! result +<p><a rel="nofollow" class="external text" href="http://www.example.com">test</a> +</p> +!! end + +!! test +External links: link text with spaces +!! input +[http://www.example.com a b c] +[http://www.example.com ''a'' ''b''] +!! result +<p><a rel="nofollow" class="external text" href="http://www.example.com">a b c</a> +<a rel="nofollow" class="external text" href="http://www.example.com"><i>a</i> <i>b</i></a> +</p> +!! end + +!! test +External links: wiki links within external link (Bug 3695) +!! input +[http://example.com [[wikilink]] embedded in ext link] +!! result +<p><a rel="nofollow" class="external text" href="http://example.com"></a><a href="/index.php?title=Wikilink&action=edit&redlink=1" class="new" title="Wikilink (page does not exist)">wikilink</a><a rel="nofollow" class="external text" href="http://example.com"> embedded in ext link</a> +</p> +!! end + +!! test +BUG 787: Links with one slash after the url protocol are invalid +!! input +http:/example.com + +[http:/example.com title] +!! result +<p>http:/example.com +</p><p>[http:/example.com title] +</p> +!! end + +!! test +Bracketed external links with template-generated invalid target +!! input +[{{echo|http:/example.com}} title] +!! result +<p>[http:/example.com title] +</p> +!! end + +!! test +Bug 2702: Mismatched <i>, <b> and <a> tags are invalid +!! input +''[http://example.com text''] +[http://example.com '''text]''' +''Something [http://example.com in italic''] +''Something [http://example.com mixed''''', even bold]''' +'''''Now [http://example.com both'''''] +!! result +<p><a rel="nofollow" class="external text" href="http://example.com"><i>text</i></a> +<a rel="nofollow" class="external text" href="http://example.com"><b>text</b></a> +<i>Something </i><a rel="nofollow" class="external text" href="http://example.com"><i>in italic</i></a> +<i>Something </i><a rel="nofollow" class="external text" href="http://example.com"><i>mixed</i><b>, even bold</b></a> +<i><b>Now </b></i><a rel="nofollow" class="external text" href="http://example.com"><i><b>both</b></i></a> +</p> +!! end + + +!! test +Bug 4781: %26 in URL +!! input +http://www.example.com/?title=AT%26T +!! result +<p><a rel="nofollow" class="external free" href="http://www.example.com/?title=AT%26T">http://www.example.com/?title=AT%26T</a> +</p> +!! end + +# According to http://dev.w3.org/html5/spec/Overview.html#parsing-urls a plain +# % is actually legal in HTML5. Any change in output would need testing though. +!! test +Bug 4781, 5267: %25 in URL +!! input +http://www.example.com/?title=100%25_Bran +!! result +<p><a rel="nofollow" class="external free" href="http://www.example.com/?title=100%25_Bran">http://www.example.com/?title=100%25_Bran</a> +</p> +!! end + +!! test +Bug 4781, 5267: %28, %29 in URL +!! input +http://www.example.com/?title=Ben-Hur_%281959_film%29 +!! result +<p><a rel="nofollow" class="external free" href="http://www.example.com/?title=Ben-Hur_%281959_film%29">http://www.example.com/?title=Ben-Hur_%281959_film%29</a> +</p> +!! end + + +!! test +Bug 4781: %26 in autonumber URL +!! input +[http://www.example.com/?title=AT%26T] +!! result +<p><a rel="nofollow" class="external autonumber" href="http://www.example.com/?title=AT%26T">[1]</a> +</p> +!! end + +!! test +Bug 4781, 5267: %26 in autonumber URL +!! input +[http://www.example.com/?title=100%25_Bran] +!! result +<p><a rel="nofollow" class="external autonumber" href="http://www.example.com/?title=100%25_Bran">[1]</a> +</p> +!! end + +!! test +Bug 4781, 5267: %28, %29 in autonumber URL +!! input +[http://www.example.com/?title=Ben-Hur_%281959_film%29] +!! result +<p><a rel="nofollow" class="external autonumber" href="http://www.example.com/?title=Ben-Hur_%281959_film%29">[1]</a> +</p> +!! end + + +!! test +Bug 4781: %26 in bracketed URL +!! input +[http://www.example.com/?title=AT%26T link] +!! result +<p><a rel="nofollow" class="external text" href="http://www.example.com/?title=AT%26T">link</a> +</p> +!! end + +!! test +Bug 4781, 5267: %26 in bracketed URL +!! input +[http://www.example.com/?title=100%25_Bran link] +!! result +<p><a rel="nofollow" class="external text" href="http://www.example.com/?title=100%25_Bran">link</a> +</p> +!! end + +!! test +Bug 4781, 5267: %28, %29 in bracketed URL +!! input +[http://www.example.com/?title=Ben-Hur_%281959_film%29 link] +!! result +<p><a rel="nofollow" class="external text" href="http://www.example.com/?title=Ben-Hur_%281959_film%29">link</a> +</p> +!! end + +!! test +External link containing double-single-quotes in text '' (bug 4598 sanity check) +!! input +Some [http://example.com/ pretty ''italics'' and stuff]! +!! result +<p>Some <a rel="nofollow" class="external text" href="http://example.com/">pretty <i>italics</i> and stuff</a>! +</p> +!! end + +!! test +External link containing double-single-quotes in text embedded in italics (bug 4598 sanity check) +!! input +''Some [http://example.com/ pretty ''italics'' and stuff]!'' +!! result +<p><i>Some </i><a rel="nofollow" class="external text" href="http://example.com/"><i>pretty </i>italics<i> and stuff</i></a><i>!</i> +</p> +!! end + +!! test +External link containing double-single-quotes with no space separating the url from text in italics +!! input +[http://www.musee-picasso.fr/pages/page_id18528_u1l2.htm''La muerte de Casagemas'' (1901) en el sitio de [[Museo Picasso (París)|Museo Picasso]].] +!! result +<p><a rel="nofollow" class="external text" href="http://www.musee-picasso.fr/pages/page_id18528_u1l2.htm"><i>La muerte de Casagemas</i> (1901) en el sitio de <a href="/index.php?title=Museo_Picasso_(Par%C3%ADs)&action=edit&redlink=1" class="new" title="Museo Picasso (París) (page does not exist)">Museo Picasso</a>.</a> +</p> +!! end + +!! test +URL-encoding in URL functions (single parameter) +!! input +{{localurl:Some page|amp=&}} +!! result +<p>/index.php?title=Some_page&amp=& +</p> +!! end + +!! test +URL-encoding in URL functions (multiple parameters) +!! input +{{localurl:Some page|q=?&=&}} +!! result +<p>/index.php?title=Some_page&q=?&amp=& +</p> +!! end + +!! test +Brackets in urls +!! input +http://example.com/index.php?foozoid%5B%5D=bar + +http://example.com/index.php?foozoid[]=bar +!! result +<p><a rel="nofollow" class="external free" href="http://example.com/index.php?foozoid%5B%5D=bar">http://example.com/index.php?foozoid%5B%5D=bar</a> +</p><p><a rel="nofollow" class="external free" href="http://example.com/index.php?foozoid%5B%5D=bar">http://example.com/index.php?foozoid%5B%5D=bar</a> +</p> +!! end + +!! test +IPv6 urls (bug 21261) +!! options +disabled +!! input +http://[2404:130:0:1000::187:2]/index.php +!! result +<p><a rel="nofollow" class="external free" href="http://[2404:130:0:1000::187:2]/index.php">http://[2404:130:0:1000::187:2]/index.php</a> +</p> +!! end + +!! test +Non-extlinks in brackets +!! input +[foo] +[foo bar] +[foo ''bar''] +[fool's] errand +[fool's errand] +[{{echo|foo}}] +[{{echo|foo}} bar] +[{{echo|foo}} ''bar''] +[{{echo|foo}}l's] errand +[{{echo|foo}}l's errand] +[url={{echo|foo}}] +[url=http://example.com] +!! result +<p>[foo] +[foo bar] +[foo <i>bar</i>] +[fool's] errand +[fool's errand] +[foo] +[foo bar] +[foo <i>bar</i>] +[fool's] errand +[fool's errand] +[url=foo] +[url=<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>] +</p> +!! end + +### +### Quotes +### + +!! test +Quotes +!! input +Normal text. '''Bold text.''' Normal text. ''Italic text.'' + +Normal text. '''''Bold italic text.''''' Normal text. +!!result +<p>Normal text. <b>Bold text.</b> Normal text. <i>Italic text.</i> +</p><p>Normal text. <i><b>Bold italic text.</b></i> Normal text. +</p> +!! end + + +!! test +Unclosed and unmatched quotes +!! input +'''''Bold italic text '''with bold deactivated''' in between.''''' + +'''''Bold italic text ''with italic deactivated'' in between.''''' + +'''Bold text.. + +..spanning two paragraphs (should not work).''' + +'''Bold tag left open + +''Italic tag left open + +Normal text. + +<!-- Unmatching number of opening, closing tags: --> +'''This year''''s election ''should'' beat '''last year''''s. + +''Tom'''s car is bigger than ''Susan'''s. + +Plain ''italic'''s plain +!! result +<p><i><b>Bold italic text </b>with bold deactivated<b> in between.</b></i> +</p><p><b><i>Bold italic text </i>with italic deactivated<i> in between.</i></b> +</p><p><b>Bold text..</b> +</p><p>..spanning two paragraphs (should not work). +</p><p><b>Bold tag left open</b> +</p><p><i>Italic tag left open</i> +</p><p>Normal text. +</p><p><b>This year'</b>s election <i>should</i> beat <b>last year'</b>s. +</p><p><i>Tom<b>s car is bigger than </b></i><b>Susan</b>s. +</p><p>Plain <i>italic'</i>s plain +</p> +!! end + +### +### Tables +### +### some content taken from http://meta.wikimedia.org/wiki/MediaWiki_User%27s_Guide:_Using_tables +### + +# This should not produce <table></table> as <table><tr><td></td></tr></table> +# is the bare minimun required by the spec, see: +# http://www.w3.org/TR/xhtml-modularization/dtd_module_defs.html#a_module_Basic_Tables +!! test +A table with no data. +!! input +{||} +!! result +!! end + +# A table with nothing but a caption is invalid XHTML, we might want to render +# this as <p>caption</p> +!! test +A table with nothing but a caption +!! input +{| +|+ caption +|} +!! result +<table> +<caption> caption +</caption><tr><td></td></tr></table> + +!! end + +!! test +A table with caption with default-spaced attributes and a table row +!! input +{| +|+ style="color: red;" | caption1 +|- +| foo +|} +!! result +<table> +<caption style="color: red;"> caption1 +</caption> +<tr> +<td> foo +</td></tr></table> + +!! end + +!! test +A table with captions with non-default spaced attributes and a table row +!! input +{| +|+style="color: red;"|caption2 +|+ style="color: red;"| caption3 +|- +| foo +|} +!! result +<table> +<caption style="color: red;">caption2 +</caption> +<caption style="color: red;"> caption3 +</caption> +<tr> +<td> foo +</td></tr></table> + +!! end + +!! test +Table td-cell syntax variations +!! input +{| +| foo bar foo | baz +| foo bar foo || baz +| style='color:red;' | baz +| style='color:red;' || baz +|} +!! result +<table> +<tr> +<td> baz +</td> +<td> foo bar foo </td> +<td> baz +</td> +<td style="color:red;"> baz +</td> +<td> style='color:red;' </td> +<td> baz +</td></tr></table> + +!! end + +!! test +Simple table +!! input +{| +| 1 || 2 +|- +| 3 || 4 +|} +!! result +<table> +<tr> +<td> 1 </td> +<td> 2 +</td></tr> +<tr> +<td> 3 </td> +<td> 4 +</td></tr></table> + +!! end + +!! test +Simple table but with multiple dashes for row wikitext +!! input +{| +| foo +|----- +| bar +|} +!! result +<table> +<tr> +<td> foo +</td></tr> +<tr> +<td> bar +</td></tr></table> + +!! end +!! test +Multiplication table +!! input +{| border="1" cellpadding="2" +|+Multiplication table +|- +! × !! 1 !! 2 !! 3 +|- +! 1 +| 1 || 2 || 3 +|- +! 2 +| 2 || 4 || 6 +|- +! 3 +| 3 || 6 || 9 +|- +! 4 +| 4 || 8 || 12 +|- +! 5 +| 5 || 10 || 15 +|} +!! result +<table border="1" cellpadding="2"> +<caption>Multiplication table +</caption> +<tr> +<th> × </th> +<th> 1 </th> +<th> 2 </th> +<th> 3 +</th></tr> +<tr> +<th> 1 +</th> +<td> 1 </td> +<td> 2 </td> +<td> 3 +</td></tr> +<tr> +<th> 2 +</th> +<td> 2 </td> +<td> 4 </td> +<td> 6 +</td></tr> +<tr> +<th> 3 +</th> +<td> 3 </td> +<td> 6 </td> +<td> 9 +</td></tr> +<tr> +<th> 4 +</th> +<td> 4 </td> +<td> 8 </td> +<td> 12 +</td></tr> +<tr> +<th> 5 +</th> +<td> 5 </td> +<td> 10 </td> +<td> 15 +</td></tr></table> + +!! end + +!! test +Accept "||" in table headings +!! input +{| +!h1 || h2 +|} +!! result +<table> +<tr> +<th>h1 </th> +<th> h2 +</th></tr></table> + +!! end + +!! test +Accept "||" in indented table headings +!! input +:{| +!h1 || h2 +|} +!! result +<dl><dd><table> +<tr> +<th>h1 </th> +<th> h2 +</th></tr></table></dd></dl> + +!! end + +!! test +Accept empty attributes in td/th cells (td/th cells starting with leading ||) +!! input +{| +!| h1 +|| a +|} +!! result +<table> +<tr> +<th> h1 +</th> +<td> a +</td></tr></table> + +!! end + +!!test +Accept "| !" at start of line in tables (ignore !-attribute) +!!input +{| +|- +| !style="color:red" | bar +|} +!!result +<table> + +<tr> +<td> bar +</td></tr></table> + +!!end + +!!test +Allow +/- in 2nd and later cells in a row, in 1st cell when td-attrs are present, or in 1st cell when there is a space between "|" and +/- +!!input +{| +|- +|style='color:red;'|+1 +|style='color:blue;'|-1 +|- +| 1 || 2 || 3 +| 1 ||+2 ||-3 +|- +| +1 +| -1 +|} +!!result +<table> + +<tr> +<td style="color:red;">+1 +</td> +<td style="color:blue;">-1 +</td></tr> +<tr> +<td> 1 </td> +<td> 2 </td> +<td> 3 +</td> +<td> 1 </td> +<td>+2 </td> +<td>-3 +</td></tr> +<tr> +<td> +1 +</td> +<td> -1 +</td></tr></table> + +!!end + +!! test +Table rowspan +!! input +{| border=1 +| Cell 1, row 1 +|rowspan=2| Cell 2, row 1 (and 2) +| Cell 3, row 1 +|- +| Cell 1, row 2 +| Cell 3, row 2 +|} +!! result +<table border="1"> +<tr> +<td> Cell 1, row 1 +</td> +<td rowspan="2"> Cell 2, row 1 (and 2) +</td> +<td> Cell 3, row 1 +</td></tr> +<tr> +<td> Cell 1, row 2 +</td> +<td> Cell 3, row 2 +</td></tr></table> + +!! end + +!! test +Nested table +!! input +{| border=1 +| α +| +{| bgcolor=#ABCDEF border=2 +|nested +|- +|table +|} +|the original table again +|} +!! result +<table border="1"> +<tr> +<td> α +</td> +<td> +<table bgcolor="#ABCDEF" border="2"> +<tr> +<td>nested +</td></tr> +<tr> +<td>table +</td></tr></table> +</td> +<td>the original table again +</td></tr></table> + +!! end + +!! test +Invalid attributes in table cell (bug 1830) +!! input +{| +|Cell:|broken +|} +!! result +<table> +<tr> +<td>broken +</td></tr></table> + +!! end + + +!! test +Table security: embedded pipes (http://lists.wikimedia.org/mailman/htdig/wikitech-l/2006-April/022293.html) +!! input +{| +| |[ftp://|x||]" onmouseover="alert(document.cookie)">test +!! result +<table> +<tr> +<td>[<a rel="nofollow" class="external free" href="ftp://%7Cx">ftp://%7Cx</a></td> +<td>]" onmouseover="alert(document.cookie)">test +</td> +</tr> +</table> + +!! end + + +!! test +Indented table markup mixed with indented pre content (proposed in bug 6200) +!! input + <table> + <tr> + <td> + Text that should be rendered preformatted + </td> + </tr> + </table> +!! result + <table> + <tr> + <td> +<pre>Text that should be rendered preformatted +</pre> + </td> + </tr> + </table> + +!! end + +!! test +Template-generated table cell attributes and cell content +!! input +{| +|{{table_attribs}} +|} +!! result +<table> +<tr> +<td style="color: red"> Foo +</td></tr></table> + +!! end + +!! test +Table with row followed by newlines and table heading +!! input +{| +|- + +! foo +|} +!! result +<table> + + +<tr> +<th> foo +</th></tr></table> + +!! end + +# FIXME: Preserve the attribute properly (with an empty string as value) in +# the PHP parser. Parsoid implements the behavior below. +!! test +Table attributes with empty value +!! options +disabled +!! input +{| +| style=| hello +|} +!! result +<table> +<tr> +<td style=""> hello +</td></tr></table> + +!! end + +!! test +Wikitext table with a lot of comments +!! input +{| +<!-- c0 --> +| foo +<!-- c1 --> +|- <!-- c2 --> +<!-- c3 --> +|<!-- c4 --> +<!-- c5 --> +|} +!! result +<table> +<tr> +<td> foo +</td></tr> +<tr> +<td> +</td></tr></table> + +!! end + +### +### Internal links +### +!! test +Plain link, capitalized +!! input +[[Main Page]] +!! result +<p><a href="/wiki/Main_Page" title="Main Page">Main Page</a> +</p> +!! end + +!! test +Plain link, uncapitalized +!! input +[[main Page]] +!! result +<p><a href="/wiki/Main_Page" title="Main Page">main Page</a> +</p> +!! end + +!! test +Piped link +!! input +[[Main Page|The Main Page]] +!! result +<p><a href="/wiki/Main_Page" title="Main Page">The Main Page</a> +</p> +!! end + +!! test +Broken link +!! input +[[Zigzagzogzagzig]] +!! result +<p><a href="/index.php?title=Zigzagzogzagzig&action=edit&redlink=1" class="new" title="Zigzagzogzagzig (page does not exist)">Zigzagzogzagzig</a> +</p> +!! end + +!! test +Broken link with fragment +!! input +[[Zigzagzogzagzig#zug]] +!! result +<p><a href="/index.php?title=Zigzagzogzagzig&action=edit&redlink=1" class="new" title="Zigzagzogzagzig (page does not exist)">Zigzagzogzagzig#zug</a> +</p> +!! end + +!! test +Special page link with fragment +!! input +[[Special:Version#anchor]] +!! result +<p><a href="/wiki/Special:Version#anchor" title="Special:Version">Special:Version#anchor</a> +</p> +!! end + +!! test +Nonexistent special page link with fragment +!! input +[[Special:ThisNameWillHopefullyNeverBeUsed#anchor]] +!! result +<p><a href="/wiki/Special:ThisNameWillHopefullyNeverBeUsed" class="new" title="Special:ThisNameWillHopefullyNeverBeUsed (page does not exist)">Special:ThisNameWillHopefullyNeverBeUsed#anchor</a> +</p> +!! end + +!! test +Link with prefix +!! input +xxx[[main Page]], xxx[[Main Page]], Xxx[[main Page]] XXX[[main Page]], XXX[[Main Page]] +!! result +<p>xxx<a href="/wiki/Main_Page" title="Main Page">main Page</a>, xxx<a href="/wiki/Main_Page" title="Main Page">Main Page</a>, Xxx<a href="/wiki/Main_Page" title="Main Page">main Page</a> XXX<a href="/wiki/Main_Page" title="Main Page">main Page</a>, XXX<a href="/wiki/Main_Page" title="Main Page">Main Page</a> +</p> +!! end + +!! test +Link with suffix +!! input +[[Main Page]]xxx, [[Main Page]]XXX, [[Main Page]]!!! +!! result +<p><a href="/wiki/Main_Page" title="Main Page">Main Pagexxx</a>, <a href="/wiki/Main_Page" title="Main Page">Main Page</a>XXX, <a href="/wiki/Main_Page" title="Main Page">Main Page</a>!!! +</p> +!! end + +!! article +prefixed article +!! text +Some text +!! endarticle + +!! test +Bug 43661: Piped links with identical prefixes +!! input +[[prefixed article|prefixed articles with spaces]] + +[[prefixed article|prefixed articlesaoeu]] + +[[Main Page|Main Page test]] +!! result +<p><a href="/wiki/Prefixed_article" title="Prefixed article">prefixed articles with spaces</a> +</p><p><a href="/wiki/Prefixed_article" title="Prefixed article">prefixed articlesaoeu</a> +</p><p><a href="/wiki/Main_Page" title="Main Page">Main Page test</a> +</p> +!! end + + +!! test +Link with HTML entity in suffix / tail +!! input +[[Main Page]]", [[Main Page]]a +!! result +<p><a href="/wiki/Main_Page" title="Main Page">Main Page</a>", <a href="/wiki/Main_Page" title="Main Page">Main Page</a>a +</p> +!! end + +!! test +Link with 3 brackets +!! input +[[[main page]]] +!! result +<p>[[[main page]]] +</p> +!! end + +!! test +Piped link with 3 brackets +!! input +[[[main page|the main page]]] +!! result +<p>[[[main page|the main page]]] +</p> +!! end + +!! test +Link with multiple pipes +!! input +[[Main Page|The|Main|Page]] +!! result +<p><a href="/wiki/Main_Page" title="Main Page">The|Main|Page</a> +</p> +!! end + +!! test +Link to namespaces +!! input +[[Talk:Parser testing]], [[Meta:Disclaimers]] +!! result +<p><a href="/index.php?title=Talk:Parser_testing&action=edit&redlink=1" class="new" title="Talk:Parser testing (page does not exist)">Talk:Parser testing</a>, <a href="/index.php?title=Meta:Disclaimers&action=edit&redlink=1" class="new" title="Meta:Disclaimers (page does not exist)">Meta:Disclaimers</a> +</p> +!! end + +!! test +Piped link to namespace +!! input +[[Meta:Disclaimers|The disclaimers]] +!! result +<p><a href="/index.php?title=Meta:Disclaimers&action=edit&redlink=1" class="new" title="Meta:Disclaimers (page does not exist)">The disclaimers</a> +</p> +!! end + +!! test +Link containing } +!! input +[[Usually caused by a typo (oops}]] +!! result +<p>[[Usually caused by a typo (oops}]] +</p> +!! end + +!! test +Link containing % (not as a hex sequence) +!! input +[[7% Solution]] +!! result +<p><a href="/index.php?title=7%25_Solution&action=edit&redlink=1" class="new" title="7% Solution (page does not exist)">7% Solution</a> +</p> +!! end + +!! test +Link containing % as a single hex sequence interpreted to char +!! input +[[7%25 Solution]] +!! result +<p><a href="/index.php?title=7%25_Solution&action=edit&redlink=1" class="new" title="7% Solution (page does not exist)">7% Solution</a> +</p> +!!end + +!! test +Link containing % as a double hex sequence interpreted to hex sequence +!! input +[[7%2525 Solution]] +!! result +<p>[[7%2525 Solution]] +</p> +!!end + +!! test +Link containing "#<" and "#>" % as a hex sequences- these are valid section anchors +Example for such a section: == < == +!! input +[[%23%3c]][[%23%3e]] +!! result +<p><a href="#.3C">#<</a><a href="#.3E">#></a> +</p> +!! end + +!! test +Link containing "<#" and ">#" as a hex sequences +!! input +[[%3c%23]][[%3e%23]] +!! result +<p>[[%3c%23]][[%3e%23]] +</p> +!! end + +!! test +Link containing double-single-quotes '' (bug 4598) +!! input +[[Lista d''e paise d''o munno]] +!! result +<p><a href="/index.php?title=Lista_d%27%27e_paise_d%27%27o_munno&action=edit&redlink=1" class="new" title="Lista d''e paise d''o munno (page does not exist)">Lista d''e paise d''o munno</a> +</p> +!! end + +!! test +Link containing double-single-quotes '' in text (bug 4598 sanity check) +!! input +Some [[Link|pretty ''italics'' and stuff]]! +!! result +<p>Some <a href="/index.php?title=Link&action=edit&redlink=1" class="new" title="Link (page does not exist)">pretty <i>italics</i> and stuff</a>! +</p> +!! end + +!! test +Link containing double-single-quotes '' in text embedded in italics (bug 4598 sanity check) +!! input +''Some [[Link|pretty ''italics'' and stuff]]! +!! result +<p><i>Some <a href="/index.php?title=Link&action=edit&redlink=1" class="new" title="Link (page does not exist)">pretty <i>italics</i> and stuff</a>!</i> +</p> +!! end + +!! test +Link with double quotes in title part (literal) and alternate part (interpreted) +!! input +[[File:Denys Savchenko ''Pentecoste''.jpg]] + +[[''Pentecoste'']] + +[[''Pentecoste''|Pentecoste]] + +[[''Pentecoste''|''Pentecoste'']] +!! result +<p><a href="/index.php?title=Special:Upload&wpDestFile=Denys_Savchenko_%27%27Pentecoste%27%27.jpg" class="new" title="File:Denys Savchenko ''Pentecoste''.jpg">File:Denys Savchenko <i>Pentecoste</i>.jpg</a> +</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&action=edit&redlink=1" class="new" title="''Pentecoste'' (page does not exist)">''Pentecoste''</a> +</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&action=edit&redlink=1" class="new" title="''Pentecoste'' (page does not exist)">Pentecoste</a> +</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&action=edit&redlink=1" class="new" title="''Pentecoste'' (page does not exist)"><i>Pentecoste</i></a> +</p> +!! end + +!! test +Broken image links with HTML captions (bug 39700) +!! input +[[File:Nonexistent|<script></script>]] +[[File:Nonexistent|100px|<script></script>]] +[[File:Nonexistent|<]] +[[File:Nonexistent|a<i>b</i>c]] +!! result +<p><a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><script></script></a> +<a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><script></script></a> +<a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><</a> +<a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent">abc</a> +</p> +!! end + +!! test +Plain link to URL +!! input +[[http://www.example.com]] +!! result +<p>[<a rel="nofollow" class="external autonumber" href="http://www.example.com">[1]</a>] +</p> +!! end + +!! test +Plain link to URL with link text +!! input +[[http://www.example.com Link text]] +!! result +<p>[<a rel="nofollow" class="external text" href="http://www.example.com">Link text</a>] +</p> +!! end + +!! test +Plain link to protocol-relative URL +!! input +[[//www.example.com]] +!! result +<p>[<a rel="nofollow" class="external autonumber" href="//www.example.com">[1]</a>] +</p> +!! end + +!! test +Plain link to protocol-relative URL with link text +!! input +[[//www.example.com Link text]] +!! result +<p>[<a rel="nofollow" class="external text" href="//www.example.com">Link text</a>] +</p> +!! end + +!! test +Plain link to page with question mark in title +!! input +[[A?b]] + +[[A?b|Baz]] +!! result +<p><a href="/wiki/A%3Fb" title="A?b">A?b</a> +</p><p><a href="/wiki/A%3Fb" title="A?b">Baz</a> +</p> +!! end + + +# I'm fairly sure the expected result here is wrong. +# We want these to be URL links, not pseudo-pages with URLs for titles.... +# However the current output is also pretty screwy. +# +# ---- +# I'm changing it to match the current output--it arguably makes more +# sense in the light of the test above. Old expected result was: +#<p>Piped link to URL: <a href="/index.php?title=Http://www.example.com&action=edit" class="new">an example URL</a> +#</p> +# But I think this test is bordering on "garbage in, garbage out" anyway. +# -- wtm +!! test +Piped link to URL +!! input +Piped link to URL: [[http://www.example.com|an example URL]] +!! result +<p>Piped link to URL: [<a rel="nofollow" class="external text" href="http://www.example.com%7Can">example URL</a>] +</p> +!! end + +!! test +BUG 2: [[page|http://url/]] should link to page, not http://url/ +!! input +[[Main Page|http://url/]] +!! result +<p><a href="/wiki/Main_Page" title="Main Page">http://url/</a> +</p> +!! end + +!! test +BUG 337: Escaped self-links should be bold +!! options +title=[[Bug462]] +!! input +[[Bug462]] [[Bug462]] +!! result +<p><strong class="selflink">Bug462</strong> <strong class="selflink">Bug462</strong> +</p> +!! end + +!! test +Self-link to section should not be bold +!! options +title=[[Main Page]] +!! input +[[Main Page#section]] +!! result +<p><a href="/wiki/Main_Page#section" title="Main Page">Main Page#section</a> +</p> +!! end + +!! article +00 +!! text +This is 00. +!! endarticle + +!!test +Self-link to numeric title +!!options +title=[[0]] +!!input +[[0]] +!!result +<p><strong class="selflink">0</strong> +</p> +!!end + +!!test +Link to numeric-equivalent title +!!options +title=[[0]] +!!input +[[00]] +!!result +<p><a href="/wiki/00" title="00">00</a> +</p> +!!end + +!! test +<nowiki> inside a link +!! input +[[Main<nowiki> Page</nowiki>]] [[Main Page|the main page <nowiki>[it's not very good]</nowiki>]] +!! result +<p>[[Main Page]] <a href="/wiki/Main_Page" title="Main Page">the main page [it's not very good]</a> +</p> +!! end + +!! test +Non-breaking spaces in title +!! input +[[ Main Page ]] +!! result +<p><a href="/wiki/Main_Page" title="Main Page">  Main   Page  </a> +</p> +!!end + +!! test +Internal link with ca linktrail, surrounded by bold apostrophes (bug 27473 primary issue) +!! options +language=ca +!! input +'''[[Main Page]]''' +!! result +<p><b><a href="/wiki/Main_Page" title="Main Page">Main Page</a></b> +</p> +!! end + +!! test +Internal link with ca linktrail, surrounded by italic apostrophes (bug 27473 primary issue) +!! options +language=ca +!! input +''[[Main Page]]'' +!! result +<p><i><a href="/wiki/Main_Page" title="Main Page">Main Page</a></i> +</p> +!! end + +!! test +Internal link with en linktrail: no apostrophes (bug 27473) +!! options +language=en +!! input +[[Something]]'nice +!! result +<p><a href="/index.php?title=Something&action=edit&redlink=1" class="new" title="Something (page does not exist)">Something</a>'nice +</p> +!! end + +!! test +Internal link with ca linktrail with apostrophes (bug 27473) +!! options +language=ca +!! input +[[Something]]'nice +!! result +<p><a href="/index.php?title=Something&action=edit&redlink=1" class="new" title="Something (encara no existeix)">Something'nice</a> +</p> +!! end + +!! test +Internal link with kaa linktrail with apostrophes (bug 27473) +!! options +language=kaa +!! input +[[Something]]'nice +!! result +<p><a href="/index.php?title=Something&action=edit&redlink=1" class="new" title="Something (bet ele jaratılmag'an)">Something'nice</a> +</p> +!! end + +!! test +Parsoid-centric test: Whitespace in ext- and wiki-links should be preserved +!! input +[[Foo| bar]] + +[[Foo| ''bar'']] + +[http://wp.org foo] + +[http://wp.org ''foo''] +!! result +<p><a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)"> bar</a> +</p><p><a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)"> <i>bar</i></a> +</p><p><a rel="nofollow" class="external text" href="http://wp.org">foo</a> +</p><p><a rel="nofollow" class="external text" href="http://wp.org"><i>foo</i></a> +</p> +!! end + +### +### Interwiki links (see maintenance/interwiki.sql) +### + +!! test +Inline interwiki link +!! input +[[MeatBall:SoftSecurity]] +!! result +<p><a href="http://www.usemod.com/cgi-bin/mb.pl?SoftSecurity" class="extiw" title="meatball:SoftSecurity">MeatBall:SoftSecurity</a> +</p> +!! end + +!! test +Inline interwiki link with empty title (bug 2372) +!! input +[[MeatBall:]] +!! result +<p><a href="http://www.usemod.com/cgi-bin/mb.pl" class="extiw" title="meatball:">MeatBall:</a> +</p> +!! end + +!! test +Interwiki link encoding conversion (bug 1636) +!! input +*[[Wikipedia:ro:Olteniţa]] +*[[Wikipedia:ro:Olteniţa]] +!! result +<ul><li><a href="http://en.wikipedia.org/wiki/ro:Olteni%C5%A3a" class="extiw" title="wikipedia:ro:Olteniţa">Wikipedia:ro:Olteniţa</a> +</li><li><a href="http://en.wikipedia.org/wiki/ro:Olteni%C5%A3a" class="extiw" title="wikipedia:ro:Olteniţa">Wikipedia:ro:Olteniţa</a> +</li></ul> + +!! end + +!! test +Interwiki link with fragment (bug 2130) +!! input +[[MeatBall:SoftSecurity#foo]] +!! result +<p><a href="http://www.usemod.com/cgi-bin/mb.pl?SoftSecurity#foo" class="extiw" title="meatball:SoftSecurity">MeatBall:SoftSecurity#foo</a> +</p> +!! end + +!! test +Interlanguage link +!! input +Blah blah blah +[[zh:Chinese]] +!!result +<p>Blah blah blah +</p> +!! end + +!! test +Double interlanguage link +!! input +Blah blah blah +[[es:Spanish]] +[[zh:Chinese]] +!!result +<p>Blah blah blah +</p> +!! end + +!! test +Interlanguage link, with prefix links +!! options +language=ln +!! input +Blah blah blah +[[zh:Chinese]] +!!result +<p>Blah blah blah +</p> +!! end + +!! test +Double interlanguage link, with prefix links (bug 8897) +!! options +language=ln +!! input +Blah blah blah +[[es:Spanish]] +[[zh:Chinese]] +!!result +<p>Blah blah blah +</p> +!! end + +!! test +Parsoid-specific test: Wikilinks with should RT properly +!! options +language=ln +!! input +[[WW II]] +!!result +<p><a href="/index.php?title=WW_II&action=edit&redlink=1" class="new" title="WW II (lonkásá ezalí tɛ̂)">WW II</a> +</p> +!! end + +## +## XHTML tidiness +### + +!! test +<br> to <br /> +!! input +1<br>2<br />3 +!! result +<p>1<br />2<br />3 +</p> +!! end + +!! test +Broken br tag sanitization +!! input +</br> +!! result +<p></br> +</p> +!! end + +!! test +Incorrecly removing closing slashes from correctly formed XHTML +!! input +<br style="clear:both;" /> +!! result +<p><br style="clear:both;" /> +</p> +!! end + +!! test +Failing to transform badly formed HTML into correct XHTML +!! input +<br style="clear: left;"> +<br style="clear: right;"> +<br style="clear: both;"> +!! result +<p><br style="clear: left;" /> +<br style="clear: right;" /> +<br style="clear: both;" /> +</p> +!!end + +!! test +Handling html with a div self-closing tag +!! input +<div title /> +<div title/> +<div title/ > +<div title=bar /> +<div title=bar/> +<div title=bar/ > +!! result +<p><div title /> +<div title/> +</p> +<div> +<p><div title=bar /> +<div title=bar/> +</p> +<div title="bar/"></div> +</div> + +!! end + +!! test +Handling html with a br self-closing tag +!! input +<br title /> +<br title/> +<br title/ > +<br title=bar /> +<br title=bar/> +<br title=bar/ > +!! result +<p><br title="title" /> +<br title="title" /> +<br /> +<br title="bar" /> +<br title="bar" /> +<br title="bar/" /> +</p> +!! end + +!! test +Horizontal ruler (should it add that extra space?) +!! input +<hr> +<hr > +foo <hr +> bar +!! result +<hr /> +<hr /> +foo <hr /> bar + +!! end + +!! test +Horizontal ruler -- 4+ dashes render hr +!! input +---- +!! result +<hr /> + +!! end + +!! test +Horizontal ruler -- eats additional dashes on the same line +!! input +--------- +!! result +<hr /> + +!! end + +!! test +Horizontal ruler -- does not collaps dashes on consecutive lines +!! input +---- +---- +!! result +<hr /> +<hr /> + +!! end + +!! test +Horizontal ruler -- <4 dashes render as plain text +!! input +--- +!! result +<p>--- +</p> +!! end + +!! test +Horizontal ruler -- Supports content following dashes on same line +!! input +---- Foo +!! result +<hr /> Foo + +!! end + +### +### Block-level elements +### +!! test +Common list +!! input +*Common list +* item 2 +*item 3 +!! result +<ul><li>Common list +</li><li> item 2 +</li><li>item 3 +</li></ul> + +!! end + +!! test +Numbered list +!! input +#Numbered list +#item 2 +# item 3 +!! result +<ol><li>Numbered list +</li><li>item 2 +</li><li> item 3 +</li></ol> + +!! end + +!! test +Mixed list +!! input +*Mixed list +*# with numbers +** and bullets +*# and numbers +*bullets again +**bullet level 2 +***bullet level 3 +***#Number on level 4 +**bullet level 2 +**#Number on level 3 +**#Number on level 3 +*#number level 2 +*Level 1 +*** Level 3 +#** Level 3, but ordered +!! result +<ul><li>Mixed list +<ol><li> with numbers +</li></ol> +<ul><li> and bullets +</li></ul> +<ol><li> and numbers +</li></ol> +</li><li>bullets again +<ul><li>bullet level 2 +<ul><li>bullet level 3 +<ol><li>Number on level 4 +</li></ol> +</li></ul> +</li><li>bullet level 2 +<ol><li>Number on level 3 +</li><li>Number on level 3 +</li></ol> +</li></ul> +<ol><li>number level 2 +</li></ol> +</li><li>Level 1 +<ul><li><ul><li> Level 3 +</li></ul> +</li></ul> +</li></ul> +<ol><li><ul><li><ul><li> Level 3, but ordered +</li></ul> +</li></ul> +</li></ol> + +!! end + +!! test +Nested lists 1 +!! input +*foo +**bar +!! result +<ul><li>foo +<ul><li>bar +</li></ul> +</li></ul> + +!! end + +!! test +Nested lists 2 +!! input +**foo +*bar +!! result +<ul><li><ul><li>foo +</li></ul> +</li><li>bar +</li></ul> + +!! end + +!! test +Nested lists 3 (first element empty) +!! input +* +**bar +!! result +<ul><li> +<ul><li>bar +</li></ul> +</li></ul> + +!! end + +!! test +Nested lists 4 (first element empty) +!! input +** +*bar +!! result +<ul><li><ul><li> +</li></ul> +</li><li>bar +</li></ul> + +!! end + +!! test +Nested lists 5 (both elements empty) +!! input +** +* +!! result +<ul><li><ul><li> +</li></ul> +</li><li> +</li></ul> + +!! end + +!! test +Nested lists 6 (both elements empty) +!! input +* +** +!! result +<ul><li> +<ul><li> +</li></ul> +</li></ul> + +!! end + +!! test +Nested lists 7 (skip initial nesting levels) +!! input +*** foo +!! result +<ul><li><ul><li><ul><li> foo +</li></ul> +</li></ul> +</li></ul> + +!! end + +!! test +Nested lists 8 (multiple nesting transitions) +!! input +* foo +*** bar +** baz +* boo +!! result +<ul><li> foo +<ul><li><ul><li> bar +</li></ul> +</li><li> baz +</li></ul> +</li><li> boo +</li></ul> + +!! end + +!! test +1. Lists with start-of-line-transparent tokens before bullets: Comments +!! input +*foo +*<!--cmt-->bar +<!--cmt-->*baz +!! result +<ul><li>foo +</li><li>bar +</li><li>baz +</li></ul> + +!! end + +!! test +2. Lists with start-of-line-transparent tokens before bullets: Template close +!! input +*foo {{echo|bar +}}*baz +!! result +<ul><li>foo bar +</li><li>baz +</li></ul> + +!! end + +!! test +Unbalanced closing block tags break a list +(Disabled since php parser generates broken html -- relies on Tidy to fix up) +!! options +disabled +!! input +<div> +*a</div><div> +*b</div> +!! result +<div> +<ul><li>a +</li></ul></div><div> +<ul><li>b +</li></ul></div> +!! end + +!! test +Unbalanced closing non-block tags don't break a list +(Disabled since php parser generates broken html -- relies on Tidy to fix up) +!! options +disabled +!! input +<span> +*a</span><span> +*b</span> +!! result +<p><span></span> +</p> +<ul><li>a<span></span> +</li><li>b +</li></ul> +!! end + +!! test +Unclosed formatting tags that straddle lists are closed and reopened +(Disabled since php parser generates broken html -- relies on Tidy to fix up) +!! options +disabled +!! input +# <s> a +# b </s> +!! result +<ol><li> <s> a </s> +</li><li> <s> b </s> +</li></ol> +!! end + +!!test +List embedded in a non-block tag +(Ugly Parsoid output -- worth fixing; Disabled for PHP parser since it relies on Tidy) +!! options +parsoid +!!input +<small> +* foo +</small> +!!result +<p><small></small></p> +<small> +<ul> +<li> foo</li> +</ul> +</small> +<p><small></small></p> +!!end + +!! test +List items are not parsed correctly following a <pre> block (bug 785) +!! input +* <pre>foo</pre> +* <pre>bar</pre> +* zar +!! result +<ul><li> <pre>foo</pre> +</li><li> <pre>bar</pre> +</li><li> zar +</li></ul> + +!! end + +!! test +List items from template +!! input + +{{inner list}} +* item 2 + +* item 0 +{{inner list}} +* item 2 + +* item 0 +* notSOL{{inner list}} +* item 2 +!! result +<ul><li> item 1 +</li><li> item 2 +</li></ul> +<ul><li> item 0 +</li><li> item 1 +</li><li> item 2 +</li></ul> +<ul><li> item 0 +</li><li> notSOL +</li><li> item 1 +</li><li> item 2 +</li></ul> + +!! end + +!! test +List interrupted by empty line or heading +!! input +* foo + +** bar +== A heading == +* Another list item +!! result +<ul><li> foo +</li></ul> +<ul><li><ul><li> bar +</li></ul> +</li></ul> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: A heading">edit</a>]</span> <span class="mw-headline" id="A_heading"> A heading </span></h2> +<ul><li> Another list item +</li></ul> + +!!end + +!!test +Multiple list tags generated by templates +!!input +{{echo|<li>}}a +{{echo|<li>}}b +{{echo|<li>}}c +!!result +<li>a +<li>b +<li>c</li> +</li> +</li> + +!!end + +### +### Magic Words +### + +!! test +Magic Word: {{CURRENTDAY}} +!! input +{{CURRENTDAY}} +!! result +<p>1 +</p> +!! end + +!! test +Magic Word: {{CURRENTDAY2}} +!! input +{{CURRENTDAY2}} +!! result +<p>01 +</p> +!! end + +!! test +Magic Word: {{CURRENTDAYNAME}} +!! input +{{CURRENTDAYNAME}} +!! result +<p>Thursday +</p> +!! end + +!! test +Magic Word: {{CURRENTDOW}} +!! input +{{CURRENTDOW}} +!! result +<p>4 +</p> +!! end + +!! test +Magic Word: {{CURRENTMONTH}} +!! input +{{CURRENTMONTH}} +!! result +<p>01 +</p> +!! end + +!! test +Magic Word: {{CURRENTMONTHABBREV}} +!! input +{{CURRENTMONTHABBREV}} +!! result +<p>Jan +</p> +!! end + +!! test +Magic Word: {{CURRENTMONTHNAME}} +!! input +{{CURRENTMONTHNAME}} +!! result +<p>January +</p> +!! end + +!! test +Magic Word: {{CURRENTMONTHNAMEGEN}} +!! input +{{CURRENTMONTHNAMEGEN}} +!! result +<p>January +</p> +!! end + +!! test +Magic Word: {{CURRENTTIME}} +!! input +{{CURRENTTIME}} +!! result +<p>00:02 +</p> +!! end + +!! test +Magic Word: {{CURRENTWEEK}} (@bug 4594) +!! input +{{CURRENTWEEK}} +!! result +<p>1 +</p> +!! end + +!! test +Magic Word: {{CURRENTYEAR}} +!! input +{{CURRENTYEAR}} +!! result +<p>1970 +</p> +!! end + +!! test +Magic Word: {{FULLPAGENAME}} +!! options +title=[[User:Ævar Arnfjörð Bjarmason]] +!! input +{{FULLPAGENAME}} +!! result +<p>User:Ævar Arnfjörð Bjarmason +</p> +!! end + +!! test +Magic Word: {{FULLPAGENAMEE}} +!! options +title=[[User:Ævar Arnfjörð Bjarmason]] +!! input +{{FULLPAGENAMEE}} +!! result +<p>User:%C3%86var_Arnfj%C3%B6r%C3%B0_Bjarmason +</p> +!! end + +!! test +Magic Word: {{NAMESPACE}} +!! options +title=[[User:Ævar Arnfjörð Bjarmason]] +!! input +{{NAMESPACE}} +!! result +<p>User +</p> +!! end + +!! test +Magic Word: {{NAMESPACEE}} +!! options +title=[[User:Ævar Arnfjörð Bjarmason]] +!! input +{{NAMESPACEE}} +!! result +<p>User +</p> +!! end + +!! test +Magic Word: {{NAMESPACENUMBER}} +!! options +title=[[User:Ævar Arnfjörð Bjarmason]] +!! input +{{NAMESPACENUMBER}} +!! result +<p>2 +</p> +!! end + +!! test +Magic Word: {{NUMBEROFFILES}} +!! input +{{NUMBEROFFILES}} +!! result +<p>2 +</p> +!! end + +!! test +Magic Word: {{PAGENAME}} +!! options +title=[[User:Ævar Arnfjörð Bjarmason]] +!! input +{{PAGENAME}} +!! result +<p>Ævar Arnfjörð Bjarmason +</p> +!! end + +!! test +Magic Word: {{PAGENAME}} with metacharacters +!! options +title=[['foo & bar = baz']] +!! input +''{{PAGENAME}}'' +!! result +<p><i>'foo & bar = baz'</i> +</p> +!! end + +!! test +Magic Word: {{PAGENAME}} with metacharacters (bug 26781) +!! options +title=[[*RFC 1234 http://example.com/]] +!! input +{{PAGENAME}} +!! result +<p>*RFC 1234 http://example.com/ +</p> +!! end + +!! test +Magic Word: {{PAGENAMEE}} +!! options +title=[[User:Ævar Arnfjörð Bjarmason]] +!! input +{{PAGENAMEE}} +!! result +<p>%C3%86var_Arnfj%C3%B6r%C3%B0_Bjarmason +</p> +!! end + +!! test +Magic Word: {{PAGENAMEE}} with metacharacters (bug 26781) +!! options +title=[[*RFC 1234 http://example.com/]] +!! input +{{PAGENAMEE}} +!! result +<p>*RFC_1234_http://example.com/ +</p> +!! end + +!! test +Magic Word: {{REVISIONID}} +!! input +{{REVISIONID}} +!! result +<p>1337 +</p> +!! end + +!! test +Magic Word: {{SCRIPTPATH}} +!! input +{{SCRIPTPATH}} +!! result +<p>/ +</p> +!! end + +!! test +Magic Word: {{SERVER}} +!! input +{{SERVER}} +!! result +<p><a rel="nofollow" class="external free" href="http://example.org">http://example.org</a> +</p> +!! end + +!! test +Magic Word: {{SERVERNAME}} +!! input +{{SERVERNAME}} +!! result +<p>example.org +</p> +!! end + +!! test +Magic Word: {{SITENAME}} +!! input +{{SITENAME}} +!! result +<p>MediaWiki +</p> +!! end + +!! test +Namespace 1 {{ns:1}} +!! input +{{ns:1}} +!! result +<p>Talk +</p> +!! end + +!! test +Namespace 1 {{ns:01}} +!! input +{{ns:01}} +!! result +<p>Talk +</p> +!! end + +!! test +Namespace 0 {{ns:0}} (bug 4783) +!! input +{{ns:0}} +!! result + +!! end + +!! test +Namespace 0 {{ns:00}} (bug 4783) +!! input +{{ns:00}} +!! result + +!! end + +!! test +Namespace -1 {{ns:-1}} +!! input +{{ns:-1}} +!! result +<p>Special +</p> +!! end + +!! test +Namespace User {{ns:User}} +!! input +{{ns:User}} +!! result +<p>User +</p> +!! end + +!! test +Namespace User talk {{ns:User_talk}} +!! input +{{ns:User_talk}} +!! result +<p>User talk +</p> +!! end + +!! test +Namespace User talk {{ns:uSeR tAlK}} +!! input +{{ns:uSeR tAlK}} +!! result +<p>User talk +</p> +!! end + +!! test +Namespace File {{ns:File}} +!! input +{{ns:File}} +!! result +<p>File +</p> +!! end + +!! test +Namespace File {{ns:Image}} +!! input +{{ns:Image}} +!! result +<p>File +</p> +!! end + +!! test +Namespace (lang=de) Benutzer {{ns:User}} +!! options +language=de +!! input +{{ns:User}} +!! result +<p>Benutzer +</p> +!! end + +!! test +Namespace (lang=de) Benutzer Diskussion {{ns:3}} +!! options +language=de +!! input +{{ns:3}} +!! result +<p>Benutzer Diskussion +</p> +!! end + + +!! test +Urlencode +!! input +{{urlencode:hi world?!}} +{{urlencode:hi world?!|WIKI}} +{{urlencode:hi world?!|PATH}} +{{urlencode:hi world?!|QUERY}} +!! result +<p>hi+world%3F%21 +hi_world%3F! +hi%20world%3F%21 +hi+world%3F%21 +</p> +!! end + +### +### Magic links +### +!! test +Magic links: internal link to RFC (bug 479) +!! input +[[RFC 123]] +!! result +<p><a href="/index.php?title=RFC_123&action=edit&redlink=1" class="new" title="RFC 123 (page does not exist)">RFC 123</a> +</p> +!! end + +!! test +Magic links: RFC (bug 479) +!! input +RFC 822 +!! result +<p><a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc822">RFC 822</a> +</p> +!! end + +!! test +Magic links: ISBN (bug 1937) +!! input +ISBN 0-306-40615-2 +!! result +<p><a href="/wiki/Special:BookSources/0306406152" class="internal mw-magiclink-isbn">ISBN 0-306-40615-2</a> +</p> +!! end + +!! test +Magic links: PMID incorrectly converts space to underscore +!! input +PMID 1234 +!! result +<p><a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract">PMID 1234</a> +</p> +!! end + +### +### Templates +#### + +!! test +Nonexistent template +!! input +{{thistemplatedoesnotexist}} +!! result +<p><a href="/index.php?title=Template:Thistemplatedoesnotexist&action=edit&redlink=1" class="new" title="Template:Thistemplatedoesnotexist (page does not exist)">Template:Thistemplatedoesnotexist</a> +</p> +!! end + +!! test +Template with invalid target containing tags +!! input +{{a<b>b</b>|{{echo|foo}}|{{echo|a}}={{echo|b}}|a = b}} +!! result +<p>{{a<b>b</b>|foo|a=b|a = b}} +</p> +!! end + +!! test +Template with invalid target containing unclosed tag +!! input +{{a<b>|{{echo|foo}}|{{echo|a}}={{echo|b}}|a = b}} +!! result +<p>{{a<b>|foo|a=b|a = b}}</b> +</p> +!! end + +!! article +Template:test +!! text +This is a test template +!! endarticle + +!! test +Simple template +!! input +{{test}} +!! result +<p>This is a test template +</p> +!! end + +!! test +Template with explicit namespace +!! input +{{Template:test}} +!! result +<p>This is a test template +</p> +!! end + + +!! article +Template:paramtest +!! text +This is a test template with parameter {{{param}}} +!! endarticle + +!! test +Template parameter +!! input +{{paramtest|param=foo}} +!! result +<p>This is a test template with parameter foo +</p> +!! end + +!! article +Template:paramtestnum +!! text +[[{{{1}}}|{{{2}}}]] +!! endarticle + +!! test +Template unnamed parameter +!! input +{{paramtestnum|Main Page|the main page}} +!! result +<p><a href="/wiki/Main_Page" title="Main Page">the main page</a> +</p> +!! end + +!! article +Template:templatesimple +!! text +(test) +!! endarticle + +!! article +Template:templateredirect +!! text +#redirect [[Template:templatesimple]] +!! endarticle + +!! article +Template:templateasargtestnum +!! text +{{{{{1}}}}} +!! endarticle + +!! article +Template:templateasargtest +!! text +{{template{{{templ}}}}} +!! endarticle + +!! article +Template:templateasargtest2 +!! text +{{{{{templ}}}}} +!! endarticle + +!! test +Template with template name as unnamed argument +!! input +{{templateasargtestnum|templatesimple}} +!! result +<p>(test) +</p> +!! end + +!! test +Template with template name as argument +!! input +{{templateasargtest|templ=simple}} +!! result +<p>(test) +</p> +!! end + +!! test +Template with template name as argument (2) +!! input +{{templateasargtest2|templ=templatesimple}} +!! result +<p>(test) +</p> +!! end + +!! article +Template:templateasargtestdefault +!! text +{{{{{templ|templatesimple}}}}} +!! endarticle + +!! article +Template:templa +!! text +'''templ''' +!! endarticle + +!! test +Template with default value +!! input +{{templateasargtestdefault}} +!! result +<p>(test) +</p> +!! end + +!! test +Template with default value (value set) +!! input +{{templateasargtestdefault|templ=templa}} +!! result +<p><b>templ</b> +</p> +!! end + +!! test +Template redirect +!! input +{{templateredirect}} +!! result +<p>(test) +</p> +!! end + +!! test +Template with argument in separate line +!! input +{{ templateasargtest | + templ = simple }} +!! result +<p>(test) +</p> +!! end + +!! test +Template with complex template as argument +!! input +{{paramtest| + param ={{ templateasargtest | + templ = simple }}}} +!! result +<p>This is a test template with parameter (test) +</p> +!! end + +!! test +Template with thumb image (with link in description) +!! input +{{paramtest| + param =[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]}} +!! result +This is a test template with parameter <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&wpDestFile=Noimage.png" class="new" title="File:Noimage.png">File:Noimage.png</a> <div class="thumbcaption"><a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (page does not exist)">link</a> <a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (page does not exist)">caption</a></div></div></div> + +!! end + +!! article +Template:complextemplate +!! text +{{{1}}} {{paramtest| + param ={{{param}}}}} +!! endarticle + +!! test +Template with complex arguments +!! input +{{complextemplate| + param ={{ templateasargtest | + templ = simple }}|[[Template:complextemplate|link]]}} +!! result +<p><a href="/wiki/Template:Complextemplate" title="Template:Complextemplate">link</a> This is a test template with parameter (test) +</p> +!! end + +!! test +BUG 553: link with two variables in a piped link +!! input +{| +|[[{{{1}}}|{{{2}}}]] +|} +!! result +<table> +<tr> +<td>[[{{{1}}}|{{{2}}}]] +</td></tr></table> + +!! end + +!! test +Magic variable as template parameter +!! input +{{paramtest|param={{SITENAME}}}} +!! result +<p>This is a test template with parameter MediaWiki +</p> +!! end + +!! article +Template:linktest +!! text +[[{{{param}}}|link]] +!! endarticle + +!! test +Template parameter as link source +!! input +{{linktest|param=Main Page}} +!! result +<p><a href="/wiki/Main_Page" title="Main Page">link</a> +</p> +!! end + +!!test +Template-generated attribute string (k='v') +!!input +<span {{attr_str|id|v1}}>bar</span> +!!result +<p><span id="v1">bar</span> +</p> +!!end + +!!article +Template:paramtest2 +!! text +including another template, {{paramtest|param={{{arg}}}}} +!! endarticle + +!! test +Template passing argument to another template +!! input +{{paramtest2|arg='hmm'}} +!! result +<p>including another template, This is a test template with parameter 'hmm' +</p> +!! end + +!! article +Template:Linktest2 +!! text +Main Page +!! endarticle + +!! test +Template as link source +!! input +[[{{linktest2}}]] + +[[{{linktest2}}|Main Page]] + +[[{{linktest2}}]]Page +!! result +<p><a href="/wiki/Main_Page" title="Main Page">Main Page</a> +</p><p><a href="/wiki/Main_Page" title="Main Page">Main Page</a> +</p><p><a href="/wiki/Main_Page" title="Main Page">Main Page</a>Page +</p> +!! end + + +!! article +Template:loop1 +!! text +{{loop2}} +!! endarticle + +!! article +Template:loop2 +!! text +{{loop1}} +!! endarticle + +!! test +Template infinite loop +!! input +{{loop1}} +!! result +<p><span class="error">Template loop detected: <a href="/wiki/Template:Loop1" title="Template:Loop1">Template:Loop1</a></span> +</p> +!! end + +!! test +Template from main namespace +!! input +{{:Main Page}} +!! result +<p>blah blah +</p> +!! end + +!! article +Template:table +!! text +{| +| 1 || 2 +|- +| 3 || 4 +|} +!! endarticle + +!! test +BUG 529: Template with table, not included at beginning of line +!! input +foo {{table}} +!! result +<p>foo +</p> +<table> +<tr> +<td> 1 </td> +<td> 2 +</td></tr> +<tr> +<td> 3 </td> +<td> 4 +</td></tr></table> + +!! end + +!! test +BUG 523: Template shouldn't eat newline (or add an extra one before table) +!! input +foo +{{table}} +!! result +<p>foo +</p> +<table> +<tr> +<td> 1 </td> +<td> 2 +</td></tr> +<tr> +<td> 3 </td> +<td> 4 +</td></tr></table> + +!! end + +!! test +BUG 41: Template parameters shown as broken links +!! input +{{{parameter}}} +!! result +<p>{{{parameter}}} +</p> +!! end + +!! test +Template with targets containing wikilinks +!! input +{{[[foo]]}} + +{{[[{{echo|foo}}]]}} + +{{{{echo|[[foo}}]]}} +!! result +<p>{{<a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)">foo</a>}} +</p><p>{{<a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)">foo</a>}} +</p><p>{{[[foo}}]] +</p> +!! end + +!! article +Template:MSGNW test +!! text +''None'' of '''this''' should be +* interpreted + but rather passed unmodified +{{test}} +!! endarticle + +# hmm, fix this or just deprecate msgnw and document its behavior? +!! test +msgnw keyword +!! options +disabled +!! input +{{msgnw:MSGNW test}} +!! result +<p>''None'' of '''this''' should be +* interpreted + but rather passed unmodified +{{test}} +</p> +!! end + +!! test +int keyword +!! input +{{int:youhavenewmessages|lots of money|not!}} +!! result +<p>You have lots of money (not!). +</p> +!! end + +!! article +Template:Includes +!! text +Foo<noinclude>zar</noinclude><includeonly>bar</includeonly> +!! endarticle + +!! test +<includeonly> and <noinclude> being included +!! input +{{Includes}} +!! result +<p>Foobar +</p> +!! end + +!! article +Template:Includes2 +!! text +<onlyinclude>Foo</onlyinclude>bar +!! endarticle + +!! test +<onlyinclude> being included +!! input +{{Includes2}} +!! result +<p>Foo +</p> +!! end + + +!! article +Template:Includes3 +!! text +<onlyinclude>Foo</onlyinclude>bar<includeonly>zar</includeonly> +!! endarticle + +!! test +<onlyinclude> and <includeonly> being included +!! input +{{Includes3}} +!! result +<p>Foo +</p> +!! end + +!! test +<includeonly> and <noinclude> on a page +!! input +Foo<noinclude>zar</noinclude><includeonly>bar</includeonly> +!! result +<p>Foozar +</p> +!! end + +!! test +Un-closed <noinclude> +!! input +<noinclude> +!! result +!! end + +!! test +<onlyinclude> on a page +!! input +<onlyinclude>Foo</onlyinclude>bar +!! result +<p>Foobar +</p> +!! end + +!! test +Un-closed <onlyinclude> +!! input +<onlyinclude> +!! result +!! end + +!!test +Self-closed noinclude, includeonly, onlyinclude tags +!!input +<noinclude /> +<includeonly /> +<onlyinclude /> +!!result +<p><br /> +</p> +!!end + +!!test +Unbalanced includeonly and noinclude tags +!!input +{| +|a</noinclude> +|b</noinclude></noinclude> +|c</noinclude></includeonly> +|d</includeonly></includeonly> +|} +!!result +<table> +<tr> +<td>a +</td> +<td>b +</td> +<td>c</includeonly> +</td> +<td>d</includeonly></includeonly> +</td></tr></table> + +!!end + +!! article +Template:Includeonly section +!! text +<includeonly> +==Includeonly section== +</includeonly> +==Section T-1== +!!endarticle + +!! test +Bug 6563: Edit link generation for section shown by <includeonly> +!! input +{{includeonly section}} +!! result +<h2><span class="editsection">[<a href="/index.php?title=Template:Includeonly_section&action=edit&section=T-1" title="Template:Includeonly section">edit</a>]</span> <span class="mw-headline" id="Includeonly_section">Includeonly section</span></h2> +<h2><span class="editsection">[<a href="/index.php?title=Template:Includeonly_section&action=edit&section=T-2" title="Template:Includeonly section">edit</a>]</span> <span class="mw-headline" id="Section_T-1">Section T-1</span></h2> + +!! end + +# Uses same input as the contents of [[Template:Includeonly section]] +!! test +Bug 6563: Section extraction for section shown by <includeonly> +!! options +section=T-2 +!! input +<includeonly> +==Includeonly section== +</includeonly> +==Section T-2== +!! result +==Section T-2== +!! end + +!! test +Bug 6563: Edit link generation for section suppressed by <includeonly> +!! input +<includeonly> +==Includeonly section== +</includeonly> +==Section 1== +!! result +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Section 1">edit</a>]</span> <span class="mw-headline" id="Section_1">Section 1</span></h2> + +!! end + +!! test +Bug 6563: Section extraction for section suppressed by <includeonly> +!! options +section=1 +!! input +<includeonly> +==Includeonly section== +</includeonly> +==Section 1== +!! result +==Section 1== +!! end + +!! test +Un-closed <includeonly> +!! input +<includeonly> +!! result +!! end + +### +### <includeonly> and <noinclude> in attributes +### +!!test +0. includeonly around the entire attribute +!!input +<span <includeonly>id="v1"</includeonly><noinclude>id="v2"</noinclude>>bar</span> +!!result +<p><span id="v2">bar</span> +</p> +!!end + +!!test +1. includeonly in html attr key +!!input +<span <noinclude>id</noinclude><includeonly>about</includeonly>="foo">bar</span> +!!result +<p><span id="foo">bar</span> +</p> +!!end + +!!test +2. includeonly in html attr value +!!input +<span id="<noinclude>v1</noinclude><includeonly>v2</includeonly>">bar</span> +<span id=<noinclude>"v1"</noinclude><includeonly>"v2"</includeonly>>bar</span> +!!result +<p><span id="v1">bar</span> +<span id="v1">bar</span> +</p> +!!end + +!!test +3. includeonly in part of an attr value +!!input +<span style="color:<noinclude>red</noinclude><includeonly>blue</includeonly>;">bar</span> +!!result +<p><span style="color:red;">bar</span> +</p> +!!end + +### +### Testing parsing of templates where a template arg +### has the same name as the template itself. +### + +!! article +Template:quote +!! text +{{{quote|{{{1}}}}}} +!! endarticle + +!!test +Templates: Template Name/Arg clash: 1. Use of positional param +!!input +{{quote|foo}} +!!result +<p>foo +</p> +!!end + +!!test +Templates: Template Name/Arg clash: 2. Use of named param +!!input +{{quote|quote=foo}} +!!result +<p>foo +</p> +!!end + +!!test +Templates: Template Name/Arg clash: 3. Use of named param with empty input +!!input +{{quote|quote}} +!!result +<p>quote +</p> +!!end + +### +### Parsoid-centric tests to stress Parsoid's ability to RT them unchanged +### + +!!test +Templates: 1. Simple use +!!input +{{echo|Foo}} +!!result +<p>Foo +</p> +!!end + +!!test +Templates: 2. Inside a block tag +!!input +<div>{{echo|Foo}}</div> +!!result +<div>Foo</div> + +!!end + +!!test +Templates: P-wrapping: 1a. Templates on consecutive lines +!!input +{{echo|Foo}} +{{echo|bar}} +!!result +<p>Foo +bar +</p> +!!end + +!!test +Templates: P-wrapping: 1b. Templates on consecutive lines +!!input +Foo + +{{echo|bar}} +{{echo|baz}} +!!result +<p>Foo +</p><p>bar +baz +</p> +!!end + +!!test +Templates: P-wrapping: 1c. Templates on consecutive lines +!!input +{{echo|Foo}} +{{echo|bar}} <div>baz</div> +!!result +<p>Foo +</p> +bar <div>baz</div> + +!!end + +!!test +Templates: Inline Text: 1. Multiple tmeplate uses +!!input +{{echo|Foo}}bar{{echo|baz}} +!!result +<p>Foobarbaz +</p> +!!end + +!!test +Templates: Inline Text: 2. Back-to-back template uses +!!input +{{echo|Foo}}{{echo|bar}} +!!result +<p>Foobar +</p> +!!end + +!!test +Templates: Block Tags: 1. Multiple template uses +!!input +{{echo|<div>Foo</div>}}<div>bar</div>{{echo|<div>baz</div>}} +!!result +<div>Foo</div><div>bar</div><div>baz</div> + +!!end + +!!test +Templates: Block Tags: 2. Back-to-back template uses +!!input +{{echo|<div>Foo</div>}}{{echo|<div>bar</div>}} +!!result +<div>Foo</div><div>bar</div> + +!!end + +!!test +Templates: Links: 1. Simple example +!!input +{{echo|[[Foo|bar]]}} +!!result +<p><a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)">bar</a> +</p> +!!end + +!!test +Templates: Links: 2. Generation of link href +!!input +[[{{echo|Foo}}|bar]] +!!result +<p><a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)">bar</a> +</p> +!!end + +!!test +Templates: Links: 3. Generation of part of a link href +!!input +[[Fo{{echo|o}}|bar]] + +[[Foo{{echo|bar}}]] + +[[Foo{{echo|bar}}baz]] + +[[Foo{{echo|bar}}|bar]] + +[[:Foo{{echo|bar}}]] + +[[:Foo{{echo|bar}}|bar]] +!!result +<p><a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)">bar</a> +</p><p><a href="/index.php?title=Foobar&action=edit&redlink=1" class="new" title="Foobar (page does not exist)">Foobar</a> +</p><p><a href="/index.php?title=Foobarbaz&action=edit&redlink=1" class="new" title="Foobarbaz (page does not exist)">Foobarbaz</a> +</p><p><a href="/index.php?title=Foobar&action=edit&redlink=1" class="new" title="Foobar (page does not exist)">bar</a> +</p><p><a href="/index.php?title=Foobar&action=edit&redlink=1" class="new" title="Foobar (page does not exist)">Foobar</a> +</p><p><a href="/index.php?title=Foobar&action=edit&redlink=1" class="new" title="Foobar (page does not exist)">bar</a> +</p> +!!end + +!!test +Templates: Links: 4. Multiple templates generating link href +!!input +[[{{echo|F}}{{echo|o}}ob{{echo|ar}}]] +!!result +<p><a href="/index.php?title=Foobar&action=edit&redlink=1" class="new" title="Foobar (page does not exist)">Foobar</a> +</p> +!!end + +!!test +Templates: Links: 5. Generation of link text +!!input +[[Foo|{{echo|bar}}]] +!!result +<p><a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)">bar</a> +</p> +!!end + +!!test +Templates: Links: 5. Nested templates (only outermost template should be marked) +!!input +{{echo|[[{{echo|Foo}}|bar]]}} +!!result +<p><a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)">bar</a> +</p> +!!end + +!!test +Templates: HTML Tag: 1. Generation of HTML attr. key +!!input +<div {{echo|style}}="color:red;">foo</div> +!!result +<div style="color:red;">foo</div> + +!!end + +!!test +Templates: HTML Tag: 2. Generation of HTML attr. value +!!input +<div style={{echo|'color:red;'}}>foo</div> +!!result +<div style="color:red;">foo</div> + +!!end + +!!test +Templates: HTML Tag: 3. Generation of HTML attr key and value +!!input +<div {{echo|style}}={{echo|'color:red;'}}>foo</div> +!!result +<div style="color:red;">foo</div> + +!!end + +!!test +Templates: HTML Tag: 4. Generation of starting piece of HTML attr value +!!input +<div title="{{echo|This is a long title}} with just one piece templated">foo</div> +!!result +<div title="This is a long title with just one piece templated">foo</div> + +!!end + +!!test +Templates: HTML Tag: 5. Generation of middle piece of HTML attr value +!!input +<div title="This is a long title with just {{echo|one piece}} templated">foo</div> +!!result +<div title="This is a long title with just one piece templated">foo</div> + +!!end + +!!test +Templates: HTML Tag: 6. Generation of end piece of HTML attr value +!!input +<div title="This is a long title with just one piece {{echo|templated}}">foo</div> +!!result +<div title="This is a long title with just one piece templated">foo</div> + +!!end + +!!test +Templates: HTML Tables: 1. Generating start of a HTML table +!!input +{{echo|<table><tr><td>foo</td>}}</tr></table> +!!result +<table><tr><td>foo</td></tr></table> + +!!end + +!!test +Templates: HTML Tables: 2a. Generating middle of a HTML table +!!input +<table><tr>{{echo|<td>foo</td>}}</tr></table> +!!result +<table><tr><td>foo</td></tr></table> + +!!end + +!!test +Templates: HTML Tables: 2b. Generating middle of a HTML table +!!input +<table>{{echo|<tr><td>foo</td></tr>}}</table> +!!result +<table><tr><td>foo</td></tr></table> + +!!end + +!!test +Templates: HTML Tables: 3. Generating end of a HTML table +!!input +<table><tr>{{echo|<td>foo</td></tr></table>}} +!!result +<table><tr><td>foo</td></tr></table> + +!!end + +!!test +Templates: HTML Tables: 4a. Generating a single tag of a HTML table +!!input +{{echo|<table>}}<tr><td>foo</td></tr></table> +!!result +<table><tr><td>foo</td></tr></table> + +!!end + +!!test +Templates: HTML Tables: 4b. Generating a single tag of a HTML table +!!input +<table>{{echo|<tr>}}<td>foo</td></tr></table> +!!result +<table><tr><td>foo</td></tr></table> + +!!end + +!!test +Templates: HTML Tables: 4c. Generating a single tag of a HTML table +!!input +<table><tr>{{echo|<td>}}foo</td></tr></table> +!!result +<table><tr><td>foo</td></tr></table> + +!!end + +!!test +Templates: HTML Tables: 4d. Generating a single tag of a HTML table +!!input +<table><tr><td>foo{{echo|</td>}}</tr></table> +!!result +<table><tr><td>foo</td></tr></table> + +!!end + +!!test +Templates: HTML Tables: 4e. Generating a single tag of a HTML table +!!input +<table><tr><td>foo</td>{{echo|</tr>}}</table> +!!result +<table><tr><td>foo</td></tr></table> + +!!end + +!!test +Templates: HTML Tables: 4f. Generating a single tag of a HTML table +!!input +<table><tr><td>foo</td></tr>{{echo|</table>}} +!!result +<table><tr><td>foo</td></tr></table> + +!!end + +!!test +Templates: Wiki Tables: 1a. Fostering of entire template content +!!input +{| +{{echo|a}} +|} +!!result +<table> +a +<tr><td></td></tr></table> + +!!end + +!!test +Templates: Wiki Tables: 1b. Fostering of entire template content +!!input +{| +{{echo|<div>}} +foo +{{echo|</div>}} +|} +!!result +<table> +<div> +<p>foo +</p> +</div> +<tr><td></td></tr></table> + +!!end + +!!test +Templates: Wiki Tables: 2. Fostering of partial template content +!!input +{| +{{echo|a +<div>b</div>}} +|} +!!result +<table> +a +<div>b</div> +<tr><td></td></tr></table> + +!!end + +!!test +Templates: Wiki Tables: 3. td-content via multiple templates +!!input +{| +{{echo|{{pipe}}a}}{{echo|b}} +|} +!!result +<table> +<tr> +<td>ab +</td></tr></table> + +!!end + +!!test +Templates: Wiki Tables: 4. Templated tags, no content +!!input +{{tbl-start}} +{{tbl-end}} +!!result +<table> +<tr><td></td></tr></table> + +!!end + +!!test +Templates: Wiki Tables: 5. Templated tags, regular td-tags +!!input +{{tbl-start}} +|foo +{{tbl-end}} +!!result +<table> +<tr> +<td>foo +</td></tr></table> + +!!end + +!!test +Templates: Wiki Tables: 6. Templated tags, templated td-tags +!!input +{{tbl-start}} +{{!}}foo +{{tbl-end}} +!!result +<table> +<tr> +<td>foo +</td></tr></table> + +!!end + +!!test +Templates: Lists: Multi-line list-items via templates +!!input +*{{echo|a {{nonexistent| +unused}}}} +*{{echo|b {{nonexistent| +unused}}}} +!!result +<ul><li>a <a href="/index.php?title=Template:Nonexistent&action=edit&redlink=1" class="new" title="Template:Nonexistent (page does not exist)">Template:Nonexistent</a> +</li><li>b <a href="/index.php?title=Template:Nonexistent&action=edit&redlink=1" class="new" title="Template:Nonexistent (page does not exist)">Template:Nonexistent</a> +</li></ul> + +!!end + +!!test +Templates: Ugly nesting: 1. Quotes opened/closed across templates (echo) +!!input +{{echo|''a}}{{echo|b''c''d}}{{echo|''e}} +!!result +<p><i>ab</i>c<i>d</i>e +</p> +!!end + +!!test +Templates: Ugly nesting: 2. Quotes opened/closed across templates (echo_with_span) +(PHP parser generates misnested html) +!! options +disabled +!!input +{{echo_with_span|''a}}{{echo_with_span|b''c''d}}{{echo_with_span|''e}} +!!result +<p><span><i>a</i></span><i><span>b</span></i><span>c</span><i>d</i><span>e</span></p> +!!end + +!!test +Templates: Ugly nesting: 3. Quotes opened/closed across templates (echo_with_div) +(PHP parser generates misnested html) +!! options +disabled +!!input +{{echo_with_div|''a}}{{echo_with_div|b''c''d}}{{echo_with_div|''e}} +!!result +<div><i>a</i></div> +<div><i>b</i>c<i>d</i></div> +<div>e</div> +!!end + +!!test +Templates: Ugly nesting: 4. Divs opened/closed across templates +!!input +a<div>b{{echo|c</div>d}}e +!!result +a<div>bc</div>de + +!!end + +!!test +Templates: Ugly templates: 1. Navbox template parses badly leading to table misnesting +(Parsoid-centric) +!! options +parsoid +!!input +{| +|{{echo|foo</table>}} +|bar +|} +!!result +<table about="#mwt1" typeof="mw:Object/Template "> +<tbody><tr><td>foo</td></tr></tbody></table><span about="#mwt1"> +bar</span><span about="#mwt1"> +</span> +!!end + +!!test +Templates: Ugly templates: 2. Navbox template parses badly leading to table misnesting +(Parsoid-centric) +!! options +parsoid +!!input +<table> + <tr> + <td> + <table> + <tr> + <td>1. {{echo|foo </table>}}</td> + <td> bar </td> + <td>2. {{echo|baz </table>}}</td> + </tr> + <tr> + <td>abc</td> + </tr> + </table> + </td> + </tr> + <tr> + <td>xyz</td> + </tr> +</table> +!!result +<table about="#mwt1" typeof="mw:Object/Template"> + <tbody><tr > + <td > + <table > + <tbody><tr > + <td >1. foo </td></tr></tbody></table></td> + <td > bar </td> + <td >2. baz </td></tr></tbody></table><span about="#mwt1"> + </span><span about="#mwt1"> + + abc</span><span about="#mwt1"> + </span><span about="#mwt1"> + </span><span about="#mwt1"> + </span><span about="#mwt1"> + </span><span about="#mwt1"> + + xyz</span><span about="#mwt1"> + </span><span about="#mwt1"> +</span> +!!end + +!! test +Templates: Ugly templates: 3. newline-only template parameter +!! input +foo {{echo| +}} +!! result +<p>foo +</p> +!! end + +# This looks like a bug: a single newline triggers p/br for some reason. +!! test +Templates: Ugly templates: 4. newline-only template parameter inconsistency +!! input +{{echo| +}} +!! result +<p><br /> +</p> +!! end + + +!!test +Parser Functions: 1. Simple example +!!input +{{uc:foo}} +!!result +<p>FOO +</p> +!!end + +!!test +Parser Functions: 2. Nested use (only outermost should be marked up) +!!input +{{uc:{{lc:FOO}}}} +!!result +<p>FOO +</p> +!!end + +### +### Pre-save transform tests +### +!! test +pre-save transform: subst: +!! options +PST +!! input +{{subst:test}} +!! result +This is a test template +!! end + +!! test +pre-save transform: normal template +!! options +PST +!! input +{{test}} +!! result +{{test}} +!! end + +!! test +pre-save transform: nonexistent template +!! options +PST +!! input +{{thistemplatedoesnotexist}} +!! result +{{thistemplatedoesnotexist}} +!! end + + +!! test +pre-save transform: subst magic variables +!! options +PST +!! input +{{subst:SITENAME}} +!! result +MediaWiki +!! end + +# This is bug 89, which I fixed. -- wtm +!! test +pre-save transform: subst: templates with parameters +!! options +pst +!! input +{{subst:paramtest|param="something else"}} +!! result +This is a test template with parameter "something else" +!! end + +!! article +Template:nowikitest +!! text +<nowiki>'''not wiki'''</nowiki> +!! endarticle + +!! test +pre-save transform: nowiki in subst (bug 1188) +!! options +pst +!! input +{{subst:nowikitest}} +!! result +<nowiki>'''not wiki'''</nowiki> +!! end + + +!! article +Template:commenttest +!! text +This template has <!-- a comment --> in it. +!! endarticle + +!! test +pre-save transform: comment in subst (bug 1936) +!! options +pst +!! input +{{subst:commenttest}} +!! result +This template has <!-- a comment --> in it. +!! end + +!! test +pre-save transform: unclosed tag +!! options +pst noxml +!! input +<nowiki>'''not wiki''' +!! result +<nowiki>'''not wiki''' +!! end + +!! test +pre-save transform: mixed tag case +!! options +pst noxml +!! input +<NOwiki>'''not wiki'''</noWIKI> +!! result +<NOwiki>'''not wiki'''</noWIKI> +!! end + +!! test +pre-save transform: unclosed comment in <nowiki> +!! options +pst noxml +!! input +wiki<nowiki>nowiki<!--nowiki</nowiki>wiki +!! result +wiki<nowiki>nowiki<!--nowiki</nowiki>wiki +!!end + +!! article +Template:dangerous +!!text +<span onmouseover="alert('crap')">Oh no</span> +!!endarticle + +!!test +(confirming safety of fix for subst bug 1936) +!! input +{{Template:dangerous}} +!! result +<p><span>Oh no</span> +</p> +!! end + +!! test +pre-save transform: comment containing gallery (bug 5024) +!! options +pst +!! input +<!-- <gallery>data</gallery> --> +!!result +<!-- <gallery>data</gallery> --> +!!end + +!! test +pre-save transform: comment containing extension +!! options +pst +!! input +<!-- <tag>data</tag> --> +!!result +<!-- <tag>data</tag> --> +!!end + +!! test +pre-save transform: comment containing nowiki +!! options +pst +!! input +<!-- <nowiki>data</nowiki> --> +!!result +<!-- <nowiki>data</nowiki> --> +!!end + +!! test +pre-save transform: <noinclude> in subst (bug 3298) +!! options +pst +!! input +{{subst:Includes}} +!! result +Foobar +!! end + +!! test +pre-save transform: <onlyinclude> in subst (bug 3298) +!! options +pst +!! input +{{subst:Includes2}} +!! result +Foo +!! end + +!! article +Template:SubstTest +!!text +{{<includeonly>subst:</includeonly>Includes}} +!! endarticle + +!! article +Template:SafeSubstTest +!! text +{{<includeonly>safesubst:</includeonly>Includes}} +!! endarticle + +!! test +bug 22297: safesubst: works during PST +!! options +pst +!! input +{{subst:SafeSubstTest}}{{safesubst:SubstTest}} +!! result +FoobarFoobar +!! end + +!! test +bug 22297: safesubst: works during normal parse +!! input +{{SafeSubstTest}} +!! result +<p>Foobar +</p> +!! end + +!! test: +subst: does not work during normal parse +!! input +{{SubstTest}} +!! result +<p>{{subst:Includes}} +</p> +!! end + +!! test +pre-save transform: context links ("pipe trick") +!! options +pst +!! input +[[Article (context)|]] +[[Bar:Article|]] +[[:Bar:Article|]] +[[Bar:Article (context)|]] +[[:Bar:Article (context)|]] +[[|Article]] +[[|Article (context)]] +[[Bar:X (Y) Z|]] +[[:Bar:X (Y) Z|]] +!! result +[[Article (context)|Article]] +[[Bar:Article|Article]] +[[:Bar:Article|Article]] +[[Bar:Article (context)|Article]] +[[:Bar:Article (context)|Article]] +[[Article]] +[[Article (context)]] +[[Bar:X (Y) Z|X (Y) Z]] +[[:Bar:X (Y) Z|X (Y) Z]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with interwiki prefix +!! options +pst +!! input +[[interwiki:Article|]] +[[:interwiki:Article|]] +[[interwiki:Bar:Article|]] +[[:interwiki:Bar:Article|]] +!! result +[[interwiki:Article|Article]] +[[:interwiki:Article|Article]] +[[interwiki:Bar:Article|Bar:Article]] +[[:interwiki:Bar:Article|Bar:Article]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with parens in title +!! options +pst title=[[Somearticle (context)]] +!! input +[[|Article]] +!! result +[[Article (context)|Article]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with comma in title +!! options +pst title=[[Someplace, Somewhere]] +!! input +[[|Otherplace]] +[[Otherplace, Elsewhere|]] +[[Otherplace, Elsewhere, Anywhere|]] +!! result +[[Otherplace, Somewhere|Otherplace]] +[[Otherplace, Elsewhere|Otherplace]] +[[Otherplace, Elsewhere, Anywhere|Otherplace]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with parens and comma +!! options +pst title=[[Someplace (IGNORED), Somewhere]] +!! input +[[|Otherplace]] +[[Otherplace (place), Elsewhere|]] +!! result +[[Otherplace, Somewhere|Otherplace]] +[[Otherplace (place), Elsewhere|Otherplace]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with comma and parens +!! options +pst title=[[Who, me? (context)]] +!! input +[[|Yes, you.]] +[[Me, Myself, and I (1937 song)|]] +!! result +[[Yes, you. (context)|Yes, you.]] +[[Me, Myself, and I (1937 song)|Me, Myself, and I]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with namespace +!! options +pst title=[[Ns:Somearticle]] +!! input +[[|Article]] +!! result +[[Ns:Article|Article]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with namespace and parens +!! options +pst title=[[Ns:Somearticle (context)]] +!! input +[[|Article]] +!! result +[[Ns:Article (context)|Article]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with namespace and comma +!! options +pst title=[[Ns:Somearticle, Context, Whatever]] +!! input +[[|Article]] +!! result +[[Ns:Article, Context, Whatever|Article]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with namespace, comma and parens +!! options +pst title=[[Ns:Somearticle, Context (context)]] +!! input +[[|Article]] +!! result +[[Ns:Article (context)|Article]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with namespace, parens and comma +!! options +pst title=[[Ns:Somearticle (IGNORED), Context]] +!! input +[[|Article]] +!! result +[[Ns:Article, Context|Article]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with full-width parens and no space (Japanese and Chinese style, bug 30149) +!! options +pst +!! input +[[Article(context)|]] +[[Bar:Article(context)|]] +[[:Bar:Article(context)|]] +[[|Article(context)]] +[[Bar:X(Y)Z|]] +[[:Bar:X(Y)Z|]] +!! result +[[Article(context)|Article]] +[[Bar:Article(context)|Article]] +[[:Bar:Article(context)|Article]] +[[Article(context)]] +[[Bar:X(Y)Z|X(Y)Z]] +[[:Bar:X(Y)Z|X(Y)Z]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with full-width parens and space (Japanese and Chinese style, bug 30149) +!! options +pst +!! input +[[Article (context)|]] +[[Bar:Article (context)|]] +[[:Bar:Article (context)|]] +[[|Article (context)]] +[[Bar:X (Y) Z|]] +[[:Bar:X (Y) Z|]] +!! result +[[Article (context)|Article]] +[[Bar:Article (context)|Article]] +[[:Bar:Article (context)|Article]] +[[Article (context)]] +[[Bar:X (Y) Z|X (Y) Z]] +[[:Bar:X (Y) Z|X (Y) Z]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with parens and no space (Korean style, bug 30149) +!! options +pst +!! input +[[Article(context)|]] +[[Bar:Article(context)|]] +[[:Bar:Article(context)|]] +[[|Article(context)]] +[[Bar:X(Y)Z|]] +[[:Bar:X(Y)Z|]] +!! result +[[Article(context)|Article]] +[[Bar:Article(context)|Article]] +[[:Bar:Article(context)|Article]] +[[Article(context)]] +[[Bar:X(Y)Z|X(Y)Z]] +[[:Bar:X(Y)Z|X(Y)Z]] +!! end + +!! test +pre-save transform: context links ("pipe trick") with commas (bug 21660) +!! options +pst +!! input +[[Article (context), context|]] +[[Article (context),context|]] +[[Bar:Article (context), context|]] +[[Bar:Article (context),context|]] +[[:Bar:Article (context), context|]] +[[:Bar:Article (context),context|]] +!! result +[[Article (context), context|Article]] +[[Article (context),context|Article]] +[[Bar:Article (context), context|Article]] +[[Bar:Article (context),context|Article]] +[[:Bar:Article (context), context|Article]] +[[:Bar:Article (context),context|Article]] +!! end + +!! test +pre-save transform: trim trailing empty lines +!! options +pst +!! input +Empty lines are trimmed + + + + +!! result +Empty lines are trimmed +!! end + +!! test +pre-save transform: Signature expansion +!! options +pst +!! input +* ~~~ +* <noinclude>~~~</noinclude> +* <includeonly>~~~</includeonly> +* <onlyinclude>~~~</onlyinclude> +!! result +* [[Special:Contributions/127.0.0.1|127.0.0.1]] +* <noinclude>[[Special:Contributions/127.0.0.1|127.0.0.1]]</noinclude> +* <includeonly>[[Special:Contributions/127.0.0.1|127.0.0.1]]</includeonly> +* <onlyinclude>[[Special:Contributions/127.0.0.1|127.0.0.1]]</onlyinclude> +!! end + + +!! test +pre-save transform: Signature expansion in nowiki tags (bug 93) +!! options +pst disabled +!! input +Shall not expand: + +<nowiki>~~~~</nowiki> + +<includeonly><nowiki>~~~~</nowiki></includeonly> + +<noinclude><nowiki>~~~~</nowiki></noinclude> + +<onlyinclude><nowiki>~~~~</nowiki></onlyinclude> + +{{subst:Foo}} shall be converted to FOO + +As well as inside noinclude/onlyinclude +<noinclude>{{subst:Foo}}</noinclude> +<onlyinclude>{{subst:Foo}}</onlyinclude> + +But not inside includeonly +<includeonly>{{subst:Foo}}</includeonly> +!! result +Shall not expand: + +<nowiki>~~~~</nowiki> + +<includeonly><nowiki>~~~~</nowiki></includeonly> + +<noinclude><nowiki>~~~~</nowiki></noinclude> + +<onlyinclude><nowiki>~~~~</nowiki></onlyinclude> + +FOO shall be converted to FOO + +As well as inside noinclude/onlyinclude +<noinclude>FOO</noinclude> +<onlyinclude>FOO</onlyinclude> + +But not inside includeonly +<includeonly>{{subst:Foo}}</includeonly> +!! end + +### +### Message transform tests +### +!! test +message transform: magic variables +!! options +msg +!! input +{{SITENAME}} +!! result +MediaWiki +!! end + +!! test +message transform: should not transform wiki markup +!! options +msg +!! input +''test'' +!! result +''test'' +!! end + +!! test +message transform: <noinclude> in transcluded template (bug 4926) +!! options +msg +!! input +{{Includes}} +!! result +Foobar +!! end + +!! test +message transform: <onlyinclude> in transcluded template (bug 4926) +!! options +msg +!! input +{{Includes2}} +!! result +Foo +!! end + +!! test +{{#special:}} page name, known +!! options +msg +!! input +{{#special:Recentchanges}} +!! result +Special:RecentChanges +!! end + +!! test +{{#special:}} page name with subpage, known +!! options +msg +!! input +{{#special:Recentchanges/param}} +!! result +Special:RecentChanges/param +!! end + +!! test +{{#special:}} page name, unknown +!! options +msg +!! input +{{#special:foobarnonexistent}} +!! result +No such special page +!! end + +!! test +{{#speciale:}} page name, known +!! options +msg +!! input +{{#speciale:Recentchanges}} +!! result +Special:RecentChanges +!! end + +!! test +{{#speciale:}} page name with subpage, known +!! options +msg +!! input +{{#speciale:Recentchanges/param}} +!! result +Special:RecentChanges/param +!! end + +!! test +{{#speciale:}} page name, unknown +!! options +msg +!! input +{{#speciale:foobarnonexistent}} +!! result +No_such_special_page +!! end + +### +### Images +### +!! test +Simple image +!! input +[[Image:foobar.jpg]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Right-aligned image +!! input +[[Image:foobar.jpg|right]] +!! result +<div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> + +!! end + +!! test +Simple image (using File: namespace, now canonical) +!! input +[[File:foobar.jpg]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Image with caption +!! input +[[Image:foobar.jpg|right|Caption text]] +!! result +<div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption text"><img alt="Caption text" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> + +!! end + +!! test +Image with empty attribute +!! input +[[Image:foobar.jpg|right||Caption text]] +!! result +<div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption text"><img alt="Caption text" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> + +!! end + +!! test +Image with link tails +!! input +123[[Image:foobar.jpg]]456 +123[[Image:foobar.jpg|right]]456 +123[[Image:foobar.jpg|thumb]]456 +!! result +<p>123<a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>456 +</p> +123<div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div>456 +123<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div></div></div></div>456 + +!! end + +!! test +Image with multiple captions -- only last one is accepted +!! input +[[Image:foobar.jpg|right|Caption1 - ignored|[[Caption2]] - ignored|Caption3 - accepted]] +!! result +<div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption3 - accepted"><img alt="Caption3 - accepted" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> + +!! end + +!! test +Image with width attribute at different positions +!! input +[[Image:foobar.jpg|200px|right|Caption]] +[[Image:foobar.jpg|right|200px|Caption]] +[[Image:foobar.jpg|right|Caption|200px]] +!! result +<div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption"><img alt="Caption" src="http://example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" width="200" height="23" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/400px-Foobar.jpg 2x" /></a></div> +<div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption"><img alt="Caption" src="http://example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" width="200" height="23" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/400px-Foobar.jpg 2x" /></a></div> +<div class="floatright"><a href="/wiki/File:Foobar.jpg" class="image" title="Caption"><img alt="Caption" src="http://example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" width="200" height="23" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/400px-Foobar.jpg 2x" /></a></div> + +!! end + +!! test +Image with link parameter, wiki target +!! input +[[Image:foobar.jpg|link=Target page]] +!! result +<p><a href="/wiki/Target_page" title="Target page"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Image with link parameter, URL target +!! input +[[Image:foobar.jpg|link=http://example.com/]] +!! result +<p><a href="http://example.com/" rel="nofollow"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Image with link parameter, wgExternalLinkTarget +!! input +[[Image:foobar.jpg|link=http://example.com/]] +!! config +wgExternalLinkTarget='foobar' +!! result +<p><a href="http://example.com/" target="foobar" rel="nofollow"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Image with link parameter, wgNoFollowLinks set to false +!! input +[[Image:foobar.jpg|link=http://example.com/]] +!! config +wgNoFollowLinks=false +!! result +<p><a href="http://example.com/"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Image with link parameter, wgNoFollowDomainExceptions +!! input +[[Image:foobar.jpg|link=http://example.com/]] +!! config +wgNoFollowDomainExceptions='example.com' +!! result +<p><a href="http://example.com/"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Image with link parameter, wgExternalLinkTarget, unnamed parameter +!! input +[[Image:foobar.jpg|link=http://example.com/|Title]] +!! config +wgExternalLinkTarget='foobar' +!! result +<p><a href="http://example.com/" title="Title" target="foobar" rel="nofollow"><img alt="Title" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Image with empty link parameter +!! input +[[Image:foobar.jpg|link=]] +!! result +<p><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /> +</p> +!! end + +!! test +Image with link parameter (wiki target) and unnamed parameter +!! input +[[Image:foobar.jpg|link=Target page|Title]] +!! result +<p><a href="/wiki/Target_page" title="Title"><img alt="Title" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Image with link parameter (URL target) and unnamed parameter +!! input +[[Image:foobar.jpg|link=http://example.com/|Title]] +!! result +<p><a href="http://example.com/" title="Title" rel="nofollow"><img alt="Title" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Thumbnail image with link parameter +!! input +[[Image:foobar.jpg|thumb|link=http://example.com/|Title]] +!! result +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="http://example.com/"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>Title</div></div></div> + +!! end + +!! test +Image with frame and link +!! input +[[Image:Foobar.jpg|frame|left|This is a test image [[Main Page]]]] +!! result +<div class="thumb tleft"><div class="thumbinner" style="width:1943px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" class="thumbimage" /></a> <div class="thumbcaption">This is a test image <a href="/wiki/Main_Page" title="Main Page">Main Page</a></div></div></div> + +!! end + +!! test +Image with frame and link and explicit alt +!! input +[[Image:Foobar.jpg|frame|left|This is a test image [[Main Page]]|alt=Altitude]] +!! result +<div class="thumb tleft"><div class="thumbinner" style="width:1943px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Altitude" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" class="thumbimage" /></a> <div class="thumbcaption">This is a test image <a href="/wiki/Main_Page" title="Main Page">Main Page</a></div></div></div> + +!! end + +!! test +Image with wiki markup in implicit alt +!! input +[[Image:Foobar.jpg|testing '''bold''' in alt]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image" title="testing bold in alt"><img alt="testing bold in alt" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Image with wiki markup in explicit alt +!! input +[[Image:Foobar.jpg|alt=testing '''bold''' in alt]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image"><img alt="testing bold in alt" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Link to image page- image page normally doesn't exists, hence edit link +Add test with existing image page +#<p><a href="/wiki/File:Test" title="Image:Test">Image:test</a> +!! input +[[:Image:test]] +!! result +<p><a href="/index.php?title=File:Test&action=edit&redlink=1" class="new" title="File:Test (page does not exist)">Image:test</a> +</p> +!! end + +!! test +bug 18784 Link to non-existent image page with caption should use caption as link text +!! input +[[:Image:test|caption]] +!! result +<p><a href="/index.php?title=File:Test&action=edit&redlink=1" class="new" title="File:Test (page does not exist)">caption</a> +</p> +!! end + +!! test +Frameless image caption with a free URL +!! input +[[Image:foobar.jpg|http://example.com]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image" title="http://example.com"><img alt="http://example.com" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Thumbnail image caption with a free URL +!! input +[[Image:foobar.jpg|thumb|http://example.com]] +!! result +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></div></div></div> + +!! end + +!! test +Thumbnail image caption with a free URL and explicit alt +!! input +[[Image:foobar.jpg|thumb|http://example.com|alt=Alteration]] +!! result +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Alteration" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a></div></div></div> + +!! end + +!! test +BUG 1887: A ISBN with a thumbnail +!! input +[[Image:foobar.jpg|thumb|ISBN 1235467890]] +!! result +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><a href="/wiki/Special:BookSources/1235467890" class="internal mw-magiclink-isbn">ISBN 1235467890</a></div></div></div> + +!! end + +!! test +BUG 1887: A RFC with a thumbnail +!! input +[[Image:foobar.jpg|thumb|This is RFC 12354]] +!! result +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>This is <a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc12354">RFC 12354</a></div></div></div> + +!! end + +!! test +BUG 1887: A mailto link with a thumbnail +!! input +[[Image:foobar.jpg|thumb|Please mailto:nobody@example.com]] +!! result +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>Please <a rel="nofollow" class="external free" href="mailto:nobody@example.com">mailto:nobody@example.com</a></div></div></div> + +!! end + +# Pending resolution to bug 368 +!! test +BUG 648: Frameless image caption with a link +!! input +[[Image:foobar.jpg|text with a [[link]] in it]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a link in it"><img alt="text with a link in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +BUG 648: Frameless image caption with a link (suffix) +!! input +[[Image:foobar.jpg|text with a [[link]]foo in it]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a linkfoo in it"><img alt="text with a linkfoo in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +BUG 648: Frameless image caption with an interwiki link +!! input +[[Image:foobar.jpg|text with a [[MeatBall:Link]] in it]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a MeatBall:Link in it"><img alt="text with a MeatBall:Link in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +BUG 648: Frameless image caption with a piped interwiki link +!! input +[[Image:foobar.jpg|text with a [[MeatBall:Link|link]] in it]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image" title="text with a link in it"><img alt="text with a link in it" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Escape HTML special chars in image alt text +!! input +[[Image:foobar.jpg|& < > "]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image" title="& < > ""><img alt="& < > "" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +BUG 499: Alt text should have Ӓ, not &1234; +!! input +[[Image:foobar.jpg|♀]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image" title="♀"><img alt="♀" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!! end + +!! test +Broken image caption with link +!! input +[[Image:Foobar.jpg|thumb|This is a broken caption. But [[Main Page|this]] is just an ordinary link. +!! result +<p>[[Image:Foobar.jpg|thumb|This is a broken caption. But <a href="/wiki/Main_Page" title="Main Page">this</a> is just an ordinary link. +</p> +!! end + +!! test +Image caption containing another image +!! input +[[Image:Foobar.jpg|thumb|This is a caption with another [[Image:icon.png|image]] inside it!]] +!! result +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>This is a caption with another <a href="/index.php?title=Special:Upload&wpDestFile=Icon.png" class="new" title="File:Icon.png">image</a> inside it!</div></div></div> + +!! end + +!! test +Image caption containing a newline +!! input +[[Image:Foobar.jpg|This +*is some text]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image" title="This *is some text"><img alt="This *is some text" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!!end + +!!test +Parsoid: Image caption containing leading space +(The leading space should not trigger nowiki escaping in wt2wt mode) +!! input +[[Image:Foobar.jpg|thumb| bar]] +!! result +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>bar</div></div></div> + +!!end + +!! test +Bug 3090: External links other than http: in image captions +!! input +[[Image:Foobar.jpg|thumb|200px|This caption has [irc://example.net irc] and [https://example.com Secure] ext links in it.]] +!! result +<div class="thumb tright"><div class="thumbinner" style="width:202px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" width="200" height="23" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/400px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>This caption has <a rel="nofollow" class="external text" href="irc://example.net">irc</a> and <a rel="nofollow" class="external text" href="https://example.com">Secure</a> ext links in it.</div></div></div> + +!! end + +!! test +Custom class +!! input +[[Image:foobar.jpg|a|class=b]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image" title="a"><img alt="a" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" class="b" /></a> +</p> +!! end + +!! test +Localized image handling (1). +!! options +language=es +!! input +[[Archivo:Foobar.jpg|izquierda|enlace=foo|caption]] +!! result +<div class="floatleft"><a href="/wiki/Foo" title="caption"><img alt="caption" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></div> + +!! end + +!! test +Localized image handling (2). +!! options +language=es +!! input +[[Archivo:Foobar.jpg|miniatura|izquierda|enlace=foo|caption]] +!! result +<div class="thumb tleft"><div class="thumbinner" style="width:182px;"><a href="/wiki/Foo" title="Foo"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/Archivo:Foobar.jpg" class="internal" title="Aumentar"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>caption</div></div></div> + +!! end + +!! test +"border", "frameless" and "class" attributes on an image. +!! input +[[File:Foobar.jpg|frameless|border|class=extra|caption]] +!! result +<p><a href="/wiki/File:Foobar.jpg" class="image" title="caption"><img alt="caption" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="extra thumbborder" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> +</p> +!! end + +!! article +File:Barfoo.jpg +!! text +#REDIRECT [[File:Barfoo.jpg]] +!! endarticle + +!! test +Redirected image +!! input +[[Image:Barfoo.jpg]] +!! result +<p><a href="/wiki/File:Barfoo.jpg" title="File:Barfoo.jpg">File:Barfoo.jpg</a> +</p> +!! end + +!! test +Missing image with uploads disabled +!! options +wgEnableUploads=0 +!! input +[[Image:Foobaz.jpg]] +!! result +<p><a href="/wiki/File:Foobaz.jpg" title="File:Foobaz.jpg">File:Foobaz.jpg</a> +</p> +!! end + + +### +### Subpages +### +!! article +Subpage test/subpage +!! text +foo +!! endarticle + +!! test +Subpage link +!! options +subpage title=[[Subpage test]] +!! input +[[/subpage]] +!! result +<p><a href="/wiki/Subpage_test/subpage" title="Subpage test/subpage">/subpage</a> +</p> +!! end + +!! test +Subpage noslash link +!! options +subpage title=[[Subpage test]] +!!input +[[/subpage/]] +!! result +<p><a href="/wiki/Subpage_test/subpage" title="Subpage test/subpage">subpage</a> +</p> +!! end + +!! test +Disabled subpages +!! input +[[/subpage]] +!! result +<p><a href="/index.php?title=/subpage&action=edit&redlink=1" class="new" title="/subpage (page does not exist)">/subpage</a> +</p> +!! end + +!! test +BUG 561: {{/Subpage}} +!! options +subpage title=[[Page]] +!! input +{{/Subpage}} +!! result +<p><a href="/index.php?title=Page/Subpage&action=edit&redlink=1" class="new" title="Page/Subpage (page does not exist)">Page/Subpage</a> +</p> +!! end + +### +### Categories +### +!! article +Category:MediaWiki User's Guide +!! text +blah +!! endarticle + +!! test +Link to category +!! input +[[:Category:MediaWiki User's Guide]] +!! result +<p><a href="/wiki/Category:MediaWiki_User%27s_Guide" title="Category:MediaWiki User's Guide">Category:MediaWiki User's Guide</a> +</p> +!! end + +!! test +Simple category +!! options +cat +!! input +[[Category:MediaWiki User's Guide]] +!! result +<a href="/wiki/Category:MediaWiki_User%27s_Guide" title="Category:MediaWiki User's Guide">MediaWiki User's Guide</a> +!! end + +!! test +PAGESINCATEGORY invalid title fatal (r33546 fix) +!! input +{{PAGESINCATEGORY:<bogus>}} +!! result +<p>0 +</p> +!! end + +!! test +Category with different sort key +!! options +cat +!! input +[[Category:MediaWiki User's Guide|Foo]] +!! result +<a href="/wiki/Category:MediaWiki_User%27s_Guide" title="Category:MediaWiki User's Guide">MediaWiki User's Guide</a> +!! end + +!! test +Category with identical sort key +!! options +cat +!! input +[[Category:MediaWiki User's Guide|MediaWiki User's Guide]] +!! result +<a href="/wiki/Category:MediaWiki_User%27s_Guide" title="Category:MediaWiki User's Guide">MediaWiki User's Guide</a> +!! end + +!! test +Category with empty sort key +!! options +cat +pst +!! input +[[Category:MediaWiki User's Guide|]] +!! result +[[Category:MediaWiki User's Guide|MediaWiki User's Guide]] +!! end + +!! test +Category with empty sort key and parentheses +!! options +cat +pst +!! input +[[Category:Foo (bar)|]] +!! result +[[Category:Foo (bar)|Foo]] +!! end + +!! test +Category with link tail +!! options +cat +pst +!! input +123[[Category:Foo]]456 +!! result +123[[Category:Foo]]456 +!! end + +!! test +Category with template +!! options +cat +pst +!! input +[[Category:{{echo|Foo}}]] +!! result +[[Category:{{echo|Foo}}]] +!! end + +!! test +Category with template in sort key +!! options +cat +pst +!! input +[[Category:Foo|{{echo|Bar}}]] +!! result +[[Category:Foo|{{echo|Bar}}]] +!! end + +!! test +Category with template in sort key and title +!! options +cat +pst +!! input +[[Category:{{echo|Foo}}|{{echo|Bar}}]] +!! result +[[Category:{{echo|Foo}}|{{echo|Bar}}]] +!! end + +!! test +Category / paragraph interactions +!! input +Foo [[Category:Baz]] Bar + +Foo [[Category:Baz]] +Bar + +Foo +[[Category:Baz]] +Bar + +Foo +[[Category:Baz]] Bar + +Foo +[[Category:Baz]] + [[Category:Baz]] +[[Category:Baz]] +Bar + +[[Category:Baz]] + [[Category:Baz]] +[[Category:Baz]] + +[[Category:Baz]] + {{echo|[[Category:Baz]]}} +[[Category:Baz]] +!! result +<p>Foo Bar +</p><p>Foo +Bar +</p><p>Foo +Bar +</p><p>Foo Bar +</p><p>Foo +Bar +</p> +!! end + +### +### Inter-language links +### +!! test +Inter-language links +!! options +ill +!! input +[[es:Alimento]] +[[fr:Nourriture]] +[[zh:食品]] +!! result +es:Alimento fr:Nourriture zh:食品 +!! end + +!! test +Duplicate interlanguage links (bug 24502) +!! options +ill +!! input +[[es:1]] +[[es:2]] +[[fr:1]] +[[fr:2]] +!! result +es:1 fr:1 +!! end + +### +### Sections +### +!! test +Basic section headings +!! input +== Headline 1 == +Some text + +==Headline 2== +More +===Smaller headline=== +Blah blah +!! result +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Headline 1">edit</a>]</span> <span class="mw-headline" id="Headline_1"> Headline 1 </span></h2> +<p>Some text +</p> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: Headline 2">edit</a>]</span> <span class="mw-headline" id="Headline_2">Headline 2</span></h2> +<p>More +</p> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: Smaller headline">edit</a>]</span> <span class="mw-headline" id="Smaller_headline">Smaller headline</span></h3> +<p>Blah blah +</p> +!! end + +!! test +Section headings with TOC +!! input +== Headline 1 == +=== Subheadline 1 === +===== Skipping a level ===== +====== Skipping a level ====== + +== Headline 2 == +Some text +===Another headline=== +!! result +<table id="toc" class="toc"><tr><td><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#Headline_1"><span class="tocnumber">1</span> <span class="toctext">Headline 1</span></a> +<ul> +<li class="toclevel-2 tocsection-2"><a href="#Subheadline_1"><span class="tocnumber">1.1</span> <span class="toctext">Subheadline 1</span></a> +<ul> +<li class="toclevel-3 tocsection-3"><a href="#Skipping_a_level"><span class="tocnumber">1.1.1</span> <span class="toctext">Skipping a level</span></a> +<ul> +<li class="toclevel-4 tocsection-4"><a href="#Skipping_a_level_2"><span class="tocnumber">1.1.1.1</span> <span class="toctext">Skipping a level</span></a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +<li class="toclevel-1 tocsection-5"><a href="#Headline_2"><span class="tocnumber">2</span> <span class="toctext">Headline 2</span></a> +<ul> +<li class="toclevel-2 tocsection-6"><a href="#Another_headline"><span class="tocnumber">2.1</span> <span class="toctext">Another headline</span></a></li> +</ul> +</li> +</ul> +</td></tr></table> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Headline 1">edit</a>]</span> <span class="mw-headline" id="Headline_1"> Headline 1 </span></h2> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: Subheadline 1">edit</a>]</span> <span class="mw-headline" id="Subheadline_1"> Subheadline 1 </span></h3> +<h5><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: Skipping a level">edit</a>]</span> <span class="mw-headline" id="Skipping_a_level"> Skipping a level </span></h5> +<h6><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=4" title="Edit section: Skipping a level">edit</a>]</span> <span class="mw-headline" id="Skipping_a_level_2"> Skipping a level </span></h6> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=5" title="Edit section: Headline 2">edit</a>]</span> <span class="mw-headline" id="Headline_2"> Headline 2 </span></h2> +<p>Some text +</p> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=6" title="Edit section: Another headline">edit</a>]</span> <span class="mw-headline" id="Another_headline">Another headline</span></h3> + +!! end + +# perl -e 'print "="x$_," Level $_ heading","="x$_,"\n" for 1..10' +!! test +Handling of sections up to level 6 and beyond +!! input += Level 1 Heading= +== Level 2 Heading== +=== Level 3 Heading=== +==== Level 4 Heading==== +===== Level 5 Heading===== +====== Level 6 Heading====== +======= Level 7 Heading======= +======== Level 8 Heading======== +========= Level 9 Heading========= +========== Level 10 Heading========== +!! result +<table id="toc" class="toc"><tr><td><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#Level_1_Heading"><span class="tocnumber">1</span> <span class="toctext">Level 1 Heading</span></a> +<ul> +<li class="toclevel-2 tocsection-2"><a href="#Level_2_Heading"><span class="tocnumber">1.1</span> <span class="toctext">Level 2 Heading</span></a> +<ul> +<li class="toclevel-3 tocsection-3"><a href="#Level_3_Heading"><span class="tocnumber">1.1.1</span> <span class="toctext">Level 3 Heading</span></a> +<ul> +<li class="toclevel-4 tocsection-4"><a href="#Level_4_Heading"><span class="tocnumber">1.1.1.1</span> <span class="toctext">Level 4 Heading</span></a> +<ul> +<li class="toclevel-5 tocsection-5"><a href="#Level_5_Heading"><span class="tocnumber">1.1.1.1.1</span> <span class="toctext">Level 5 Heading</span></a> +<ul> +<li class="toclevel-6 tocsection-6"><a href="#Level_6_Heading"><span class="tocnumber">1.1.1.1.1.1</span> <span class="toctext">Level 6 Heading</span></a></li> +<li class="toclevel-6 tocsection-7"><a href="#.3D_Level_7_Heading.3D"><span class="tocnumber">1.1.1.1.1.2</span> <span class="toctext">= Level 7 Heading=</span></a></li> +<li class="toclevel-6 tocsection-8"><a href="#.3D.3D_Level_8_Heading.3D.3D"><span class="tocnumber">1.1.1.1.1.3</span> <span class="toctext">== Level 8 Heading==</span></a></li> +<li class="toclevel-6 tocsection-9"><a href="#.3D.3D.3D_Level_9_Heading.3D.3D.3D"><span class="tocnumber">1.1.1.1.1.4</span> <span class="toctext">=== Level 9 Heading===</span></a></li> +<li class="toclevel-6 tocsection-10"><a href="#.3D.3D.3D.3D_Level_10_Heading.3D.3D.3D.3D"><span class="tocnumber">1.1.1.1.1.5</span> <span class="toctext">==== Level 10 Heading====</span></a></li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +</ul> +</li> +</ul> +</td></tr></table> +<h1><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Level 1 Heading">edit</a>]</span> <span class="mw-headline" id="Level_1_Heading"> Level 1 Heading</span></h1> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: Level 2 Heading">edit</a>]</span> <span class="mw-headline" id="Level_2_Heading"> Level 2 Heading</span></h2> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: Level 3 Heading">edit</a>]</span> <span class="mw-headline" id="Level_3_Heading"> Level 3 Heading</span></h3> +<h4><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=4" title="Edit section: Level 4 Heading">edit</a>]</span> <span class="mw-headline" id="Level_4_Heading"> Level 4 Heading</span></h4> +<h5><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=5" title="Edit section: Level 5 Heading">edit</a>]</span> <span class="mw-headline" id="Level_5_Heading"> Level 5 Heading</span></h5> +<h6><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=6" title="Edit section: Level 6 Heading">edit</a>]</span> <span class="mw-headline" id="Level_6_Heading"> Level 6 Heading</span></h6> +<h6><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=7" title="Edit section: = Level 7 Heading=">edit</a>]</span> <span class="mw-headline" id=".3D_Level_7_Heading.3D">= Level 7 Heading=</span></h6> +<h6><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=8" title="Edit section: == Level 8 Heading==">edit</a>]</span> <span class="mw-headline" id=".3D.3D_Level_8_Heading.3D.3D">== Level 8 Heading==</span></h6> +<h6><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=9" title="Edit section: === Level 9 Heading===">edit</a>]</span> <span class="mw-headline" id=".3D.3D.3D_Level_9_Heading.3D.3D.3D">=== Level 9 Heading===</span></h6> +<h6><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=10" title="Edit section: ==== Level 10 Heading====">edit</a>]</span> <span class="mw-headline" id=".3D.3D.3D.3D_Level_10_Heading.3D.3D.3D.3D">==== Level 10 Heading====</span></h6> + +!! end + +!! test +TOC regression (bug 9764) +!! input +== title 1 == +=== title 1.1 === +==== title 1.1.1 ==== +=== title 1.2 === +== title 2 == +=== title 2.1 === +!! result +<table id="toc" class="toc"><tr><td><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#title_1"><span class="tocnumber">1</span> <span class="toctext">title 1</span></a> +<ul> +<li class="toclevel-2 tocsection-2"><a href="#title_1.1"><span class="tocnumber">1.1</span> <span class="toctext">title 1.1</span></a> +<ul> +<li class="toclevel-3 tocsection-3"><a href="#title_1.1.1"><span class="tocnumber">1.1.1</span> <span class="toctext">title 1.1.1</span></a></li> +</ul> +</li> +<li class="toclevel-2 tocsection-4"><a href="#title_1.2"><span class="tocnumber">1.2</span> <span class="toctext">title 1.2</span></a></li> +</ul> +</li> +<li class="toclevel-1 tocsection-5"><a href="#title_2"><span class="tocnumber">2</span> <span class="toctext">title 2</span></a> +<ul> +<li class="toclevel-2 tocsection-6"><a href="#title_2.1"><span class="tocnumber">2.1</span> <span class="toctext">title 2.1</span></a></li> +</ul> +</li> +</ul> +</td></tr></table> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: title 1">edit</a>]</span> <span class="mw-headline" id="title_1"> title 1 </span></h2> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: title 1.1">edit</a>]</span> <span class="mw-headline" id="title_1.1"> title 1.1 </span></h3> +<h4><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: title 1.1.1">edit</a>]</span> <span class="mw-headline" id="title_1.1.1"> title 1.1.1 </span></h4> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=4" title="Edit section: title 1.2">edit</a>]</span> <span class="mw-headline" id="title_1.2"> title 1.2 </span></h3> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=5" title="Edit section: title 2">edit</a>]</span> <span class="mw-headline" id="title_2"> title 2 </span></h2> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=6" title="Edit section: title 2.1">edit</a>]</span> <span class="mw-headline" id="title_2.1"> title 2.1 </span></h3> + +!! end + +!! test +TOC with wgMaxTocLevel=3 (bug 6204) +!! options +wgMaxTocLevel=3 +!! input +== title 1 == +=== title 1.1 === +==== title 1.1.1 ==== +=== title 1.2 === +== title 2 == +=== title 2.1 === +!! result +<table id="toc" class="toc"><tr><td><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#title_1"><span class="tocnumber">1</span> <span class="toctext">title 1</span></a> +<ul> +<li class="toclevel-2 tocsection-2"><a href="#title_1.1"><span class="tocnumber">1.1</span> <span class="toctext">title 1.1</span></a></li> +<li class="toclevel-2 tocsection-4"><a href="#title_1.2"><span class="tocnumber">1.2</span> <span class="toctext">title 1.2</span></a></li> +</ul> +</li> +<li class="toclevel-1 tocsection-5"><a href="#title_2"><span class="tocnumber">2</span> <span class="toctext">title 2</span></a> +<ul> +<li class="toclevel-2 tocsection-6"><a href="#title_2.1"><span class="tocnumber">2.1</span> <span class="toctext">title 2.1</span></a></li> +</ul> +</li> +</ul> +</td></tr></table> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: title 1">edit</a>]</span> <span class="mw-headline" id="title_1"> title 1 </span></h2> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: title 1.1">edit</a>]</span> <span class="mw-headline" id="title_1.1"> title 1.1 </span></h3> +<h4><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: title 1.1.1">edit</a>]</span> <span class="mw-headline" id="title_1.1.1"> title 1.1.1 </span></h4> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=4" title="Edit section: title 1.2">edit</a>]</span> <span class="mw-headline" id="title_1.2"> title 1.2 </span></h3> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=5" title="Edit section: title 2">edit</a>]</span> <span class="mw-headline" id="title_2"> title 2 </span></h2> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=6" title="Edit section: title 2.1">edit</a>]</span> <span class="mw-headline" id="title_2.1"> title 2.1 </span></h3> + +!! end + +!! test +TOC with wgMaxTocLevel=3 and two level four headings (bug 6204) +!! options +wgMaxTocLevel=3 +!! input +==Section 1== +===Section 1.1=== +====Section 1.1.1==== +====Section 1.1.1.1==== +==Section 2== +!! result +<table id="toc" class="toc"><tr><td><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a> +<ul> +<li class="toclevel-2 tocsection-2"><a href="#Section_1.1"><span class="tocnumber">1.1</span> <span class="toctext">Section 1.1</span></a></li> +</ul> +</li> +<li class="toclevel-1 tocsection-5"><a href="#Section_2"><span class="tocnumber">2</span> <span class="toctext">Section 2</span></a></li> +</ul> +</td></tr></table> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Section 1">edit</a>]</span> <span class="mw-headline" id="Section_1">Section 1</span></h2> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: Section 1.1">edit</a>]</span> <span class="mw-headline" id="Section_1.1">Section 1.1</span></h3> +<h4><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: Section 1.1.1">edit</a>]</span> <span class="mw-headline" id="Section_1.1.1">Section 1.1.1</span></h4> +<h4><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=4" title="Edit section: Section 1.1.1.1">edit</a>]</span> <span class="mw-headline" id="Section_1.1.1.1">Section 1.1.1.1</span></h4> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=5" title="Edit section: Section 2">edit</a>]</span> <span class="mw-headline" id="Section_2">Section 2</span></h2> + +!! end + + +!! test +Resolving duplicate section names +!! input +== Foo bar == +== Foo bar == +!! result +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Foo bar">edit</a>]</span> <span class="mw-headline" id="Foo_bar"> Foo bar </span></h2> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: Foo bar">edit</a>]</span> <span class="mw-headline" id="Foo_bar_2"> Foo bar </span></h2> + +!! end + +!! test +Resolving duplicate section names with differing case (bug 10721) +!! input +== Foo bar == +== Foo Bar == +!! result +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Foo bar">edit</a>]</span> <span class="mw-headline" id="Foo_bar"> Foo bar </span></h2> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: Foo Bar">edit</a>]</span> <span class="mw-headline" id="Foo_Bar_2"> Foo Bar </span></h2> + +!! end + +!! article +Template:sections +!! text +===Section 1=== +==Section 2== +!! endarticle + +!! test +Template with sections, __NOTOC__ +!! input +__NOTOC__ +==Section 0== +{{sections}} +==Section 4== +!! result +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Section 0">edit</a>]</span> <span class="mw-headline" id="Section_0">Section 0</span></h2> +<h3><span class="editsection">[<a href="/index.php?title=Template:Sections&action=edit&section=T-1" title="Template:Sections">edit</a>]</span> <span class="mw-headline" id="Section_1">Section 1</span></h3> +<h2><span class="editsection">[<a href="/index.php?title=Template:Sections&action=edit&section=T-2" title="Template:Sections">edit</a>]</span> <span class="mw-headline" id="Section_2">Section 2</span></h2> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: Section 4">edit</a>]</span> <span class="mw-headline" id="Section_4">Section 4</span></h2> + +!! end + +!! test +__NOEDITSECTION__ keyword +!! input +__NOEDITSECTION__ +==Section 1== +==Section 2== +!! result +<h2> <span class="mw-headline" id="Section_1">Section 1</span></h2> +<h2> <span class="mw-headline" id="Section_2">Section 2</span></h2> + +!! end + +!! test +Link inside a section heading +!! input +==Section with a [[Main Page|link]] in it== +!! result +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Section with a link in it">edit</a>]</span> <span class="mw-headline" id="Section_with_a_link_in_it">Section with a <a href="/wiki/Main_Page" title="Main Page">link</a> in it</span></h2> + +!! end + +!! test +TOC regression (bug 12077) +!! input +__TOC__ +== title 1 == +=== title 1.1 === +== title 2 == +!! result +<table id="toc" class="toc"><tr><td><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#title_1"><span class="tocnumber">1</span> <span class="toctext">title 1</span></a> +<ul> +<li class="toclevel-2 tocsection-2"><a href="#title_1.1"><span class="tocnumber">1.1</span> <span class="toctext">title 1.1</span></a></li> +</ul> +</li> +<li class="toclevel-1 tocsection-3"><a href="#title_2"><span class="tocnumber">2</span> <span class="toctext">title 2</span></a></li> +</ul> +</td></tr></table> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: title 1">edit</a>]</span> <span class="mw-headline" id="title_1"> title 1 </span></h2> +<h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: title 1.1">edit</a>]</span> <span class="mw-headline" id="title_1.1"> title 1.1 </span></h3> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: title 2">edit</a>]</span> <span class="mw-headline" id="title_2"> title 2 </span></h2> + +!! end + +!! test +BUG 1219 URL next to image (good) +!! input +http://example.com [[Image:foobar.jpg]] +!! result +<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a> <a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!!end + +!! test +Short headings with trailing space should match behavior of Parser::doHeadings (bug 19910) +!! input +=== +The line above must have a trailing space! +=== <!-- +--> <!-- --> +But just in case it doesn't... +!! result +<h1><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: =">edit</a>]</span> <span class="mw-headline" id=".3D">=</span></h1> +<p>The line above must have a trailing space! +</p> +<h1><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: =">edit</a>]</span> <span class="mw-headline" id=".3D_2">=</span></h1> +<p>But just in case it doesn't... +</p> +!! end + +!! test +Header with special characters (bug 25462) +!! input +The tooltips shall not show entities to the user (ie. be double escaped) + +== text > text == +section 1 + +== text < text == +section 2 + +== text & text == +section 3 + +== text ' text == +section 4 + +== text " text == +section 5 +!! result +<p>The tooltips shall not show entities to the user (ie. be double escaped) +</p> +<table id="toc" class="toc"><tr><td><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#text_.3E_text"><span class="tocnumber">1</span> <span class="toctext">text > text</span></a></li> +<li class="toclevel-1 tocsection-2"><a href="#text_.3C_text"><span class="tocnumber">2</span> <span class="toctext">text < text</span></a></li> +<li class="toclevel-1 tocsection-3"><a href="#text_.26_text"><span class="tocnumber">3</span> <span class="toctext">text & text</span></a></li> +<li class="toclevel-1 tocsection-4"><a href="#text_.27_text"><span class="tocnumber">4</span> <span class="toctext">text ' text</span></a></li> +<li class="toclevel-1 tocsection-5"><a href="#text_.22_text"><span class="tocnumber">5</span> <span class="toctext">text " text</span></a></li> +</ul> +</td></tr></table> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: text > text">edit</a>]</span> <span class="mw-headline" id="text_.3E_text"> text > text </span></h2> +<p>section 1 +</p> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: text < text">edit</a>]</span> <span class="mw-headline" id="text_.3C_text"> text < text </span></h2> +<p>section 2 +</p> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: text & text">edit</a>]</span> <span class="mw-headline" id="text_.26_text"> text & text </span></h2> +<p>section 3 +</p> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=4" title="Edit section: text ' text">edit</a>]</span> <span class="mw-headline" id="text_.27_text"> text ' text </span></h2> +<p>section 4 +</p> +<h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=5" title="Edit section: text " text">edit</a>]</span> <span class="mw-headline" id="text_.22_text"> text " text </span></h2> +<p>section 5 +</p> +!! end + +!! test +Headers with excess '=' characters +(Are similar tests necessary beyond the 1st level?) +!! input +=foo== +==foo= +=''italic'' heading== +==''italic'' heading= +!! result +<table id="toc" class="toc"><tr><td><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1 tocsection-1"><a href="#foo.3D"><span class="tocnumber">1</span> <span class="toctext">foo=</span></a></li> +<li class="toclevel-1 tocsection-2"><a href="#.3Dfoo"><span class="tocnumber">2</span> <span class="toctext">=foo</span></a></li> +<li class="toclevel-1 tocsection-3"><a href="#italic_heading.3D"><span class="tocnumber">3</span> <span class="toctext"><i>italic</i> heading=</span></a></li> +<li class="toclevel-1 tocsection-4"><a href="#.3Ditalic_heading"><span class="tocnumber">4</span> <span class="toctext">=<i>italic</i> heading</span></a></li> +</ul> +</td></tr></table> +<h1><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: foo=">edit</a>]</span> <span class="mw-headline" id="foo.3D">foo=</span></h1> +<h1><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: =foo">edit</a>]</span> <span class="mw-headline" id=".3Dfoo">=foo</span></h1> +<h1><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: italic heading=">edit</a>]</span> <span class="mw-headline" id="italic_heading.3D"><i>italic</i> heading=</span></h1> +<h1><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=4" title="Edit section: =italic heading">edit</a>]</span> <span class="mw-headline" id=".3Ditalic_heading">=<i>italic</i> heading</span></h1> + +!! end + +!! test +BUG 1219 URL next to image (broken) +!! input +http://example.com[[Image:foobar.jpg]] +!! result +<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a><a href="/wiki/File:Foobar.jpg" class="image"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> +</p> +!!end + +!! test +Bug 1186 news: in the middle of text +!! input +http://en.wikinews.org/wiki/Wikinews:Workplace +!! result +<p><a rel="nofollow" class="external free" href="http://en.wikinews.org/wiki/Wikinews:Workplace">http://en.wikinews.org/wiki/Wikinews:Workplace</a> +</p> +!!end + + +!! test +Namespaced link must have a title +!! input +[[Project:]] +!! result +<p>[[Project:]] +</p> +!!end + +!! test +Namespaced link must have a title (bad fragment version) +!! input +[[Project:#fragment]] +!! result +<p>[[Project:#fragment]] +</p> +!!end + + +### +### HTML tags and HTML attributes +### + +!! test +div with no attributes +!! input +<div>HTML rocks</div> +!! result +<div>HTML rocks</div> + +!! end + +!! test +div with double-quoted attribute +!! input +<div id="rock">HTML rocks</div> +!! result +<div id="rock">HTML rocks</div> + +!! end + +!! test +div with single-quoted attribute +!! input +<div id='rock'>HTML rocks</div> +!! result +<div id="rock">HTML rocks</div> + +!! end + +!! test +div with unquoted attribute +!! input +<div id=rock>HTML rocks</div> +!! result +<div id="rock">HTML rocks</div> + +!! end + +!! test +div with illegal double attributes +!! input +<div id="a" id="b">HTML rocks</div> +!! result +<div id="b">HTML rocks</div> + +!!end + +# FIXME: produce empty string instead of "class" in the PHP parser, following +# the HTML5 spec. +!! test +div with empty attribute value, space before equals +!! options +disabled +!! input +<div class =>HTML rocks</div> +!! result +<div class="">HTML rocks</div> + +!! end + +# The PHP parser escapes the opening brace to { for some reason, so +# disabled this test for it. +!! test +div with braces in attribute value +!! options +disabled +!! input +<div title="{}">Foo</div> +!! result +<div title="{}">Foo</div> +!! end + +# This it very inconsistent in the PHP parser: it returns +# class="class" if there is a space between the name and the equal sign (see +# 'div with empty attribute value, space before equals'), but strips the +# attribute completely if the space is missing. We hope that not much content +# depends on this, so are implementing the behavior below in Parsoid for +# consistencies' sake. Disabled for the PHP parser. +# FIXME: fix this behavior in the PHP parser? +!! test +div with empty attribute value, no space before equals +!! options +disabled +!! input +<div class=>HTML rocks</div> +!! result +<div class="">HTML rocks</div> + +!! end + +!! test +HTML multiple attributes correction +!! input +<p class="error" class="awesome">Awesome!</p> +!! result +<p class="awesome">Awesome!</p> + +!!end + +!! test +Table multiple attributes correction +!! input +{| +!+ class="error" class="awesome"| status +|} +!! result +<table> +<tr> +<th class="awesome"> status +</th></tr></table> + +!!end + +!! test +DIV IN UPPERCASE +!! input +<DIV ID="x">HTML ROCKS</DIV> +!! result +<div id="x">HTML ROCKS</div> + +!!end + +!! test +Non-ASCII pseudo-tags are rendered as text +!! input +<khyô> +!! result +<p><khyô> +</p> +!! end + +!! test +Pseudo-tag with URL 'name' renders as url link +!! input +<http://example.com/> +!! result +<p><<a rel="nofollow" class="external free" href="http://example.com/">http://example.com/</a>> +</p> +!! end + +!! test +text with amp in the middle of nowhere +!! input +Remember AT&T? +!!result +<p>Remember AT&T? +</p> +!! end + +!! test +text with character entity: eacute +!! input +I always thought é was a cute letter. +!! result +<p>I always thought é was a cute letter. +</p> +!! end + +!! test +text with entity-escaped character entity-like string: eacute +!! input +I always thought &eacute; was a cute letter. +!! result +<p>I always thought &eacute; was a cute letter. +</p> +!! end + +!! test +text with undefined character entity: xacute +!! input +I always thought &xacute; was a cute letter. +!! result +<p>I always thought &xacute; was a cute letter. +</p> +!! end + + +### +### Media links +### + +!! test +Media link +!! input +[[Media:Foobar.jpg]] +!! result +<p><a href="http://example.com/images/3/3a/Foobar.jpg" class="internal" title="Foobar.jpg">Media:Foobar.jpg</a> +</p> +!! end + +!! test +Media link with text +!! input +[[Media:Foobar.jpg|A neat file to look at]] +!! result +<p><a href="http://example.com/images/3/3a/Foobar.jpg" class="internal" title="Foobar.jpg">A neat file to look at</a> +</p> +!! end + +# FIXME: this is still bad HTML tag nesting +!! test +Media link with nasty text +fixme: doBlockLevels won't wrap this in a paragraph because it contains a div +!! input +[[Media:Foobar.jpg|Safe Link<div style=display:none>" onmouseover="alert(document.cookie)" onfoo="</div>]] +!! result +<a href="http://example.com/images/3/3a/Foobar.jpg" class="internal" title="Foobar.jpg">Safe Link<div style="display:none">" onmouseover="alert(document.cookie)" onfoo="</div></a> + +!! end + +!! test +Media link to nonexistent file (bug 1702) +!! input +[[Media:No such.jpg]] +!! result +<p><a href="/index.php?title=Special:Upload&wpDestFile=No_such.jpg" class="new" title="No such.jpg">Media:No such.jpg</a> +</p> +!! end + +!! test +Image link to nonexistent file (bug 1850 - good) +!! input +[[Image:No such.jpg]] +!! result +<p><a href="/index.php?title=Special:Upload&wpDestFile=No_such.jpg" class="new" title="File:No such.jpg">File:No such.jpg</a> +</p> +!! end + +!! test +:Image link to nonexistent file (bug 1850 - bad) +!! input +[[:Image:No such.jpg]] +!! result +<p><a href="/index.php?title=File:No_such.jpg&action=edit&redlink=1" class="new" title="File:No such.jpg (page does not exist)">Image:No such.jpg</a> +</p> +!! end + + + +!! test +Character reference normalization in link text (bug 1938) +!! input +[[Main Page|this&that]] +!! result +<p><a href="/wiki/Main_Page" title="Main Page">this&that</a> +</p> +!!end + +!! article +אַ +!! text +Test for unicode normalization + +The page's name is U+05d0 U+05b7, with non-canonical form U+FB2E +!! endarticle + +!! test +(bug 19451) Links should refer to the normalized form. +!! input +[[אַ]] +[[אַ]] +[[אַ]] +[[אַ]] +[[אַ]] +!! result +<p><a href="/wiki/%D7%90%D6%B7" title="אַ">אַ</a> +<a href="/wiki/%D7%90%D6%B7" title="אַ">אַ</a> +<a href="/wiki/%D7%90%D6%B7" title="אַ">אַ</a> +<a href="/wiki/%D7%90%D6%B7" title="אַ">אַ</a> +<a href="/wiki/%D7%90%D6%B7" title="אַ">אַ</a> +</p> +!! end + +!! test +Empty attribute crash test (bug 2067) +!! input +<font color="">foo</font> +!! result +<p><font color="">foo</font> +</p> +!! end + +!! test +Empty attribute crash test single-quotes (bug 2067) +!! input +<font color=''>foo</font> +!! result +<p><font color="">foo</font> +</p> +!! end + +!! test +Attribute test: equals, then nothing +!! input +<font color=>foo</font> +!! result +<p><font>foo</font> +</p> +!! end + +!! test +Attribute test: unquoted value +!! input +<font color=x>foo</font> +!! result +<p><font color="x">foo</font> +</p> +!! end + +!! test +Attribute test: unquoted but illegal value (hash) +!! input +<font color=#x>foo</font> +!! result +<p><font color="#x">foo</font> +</p> +!! end + +!! test +Attribute test: no value +!! input +<font color>foo</font> +!! result +<p><font color="color">foo</font> +</p> +!! end + +!! test +Bug 2095: link with three closing brackets +!! input +[[Main Page]]] +!! result +<p><a href="/wiki/Main_Page" title="Main Page">Main Page</a>] +</p> +!! end + +!! test +Bug 2095: link with pipe and three closing brackets +!! input +[[Main Page|link]]] +!! result +<p><a href="/wiki/Main_Page" title="Main Page">link</a>] +</p> +!! end + +!! test +Bug 2095: link with pipe and three closing brackets, version 2 +!! input +[[Main Page|[http://example.com/]]] +!! result +<p><a href="/wiki/Main_Page" title="Main Page">[http://example.com/]</a> +</p> +!! end + + +### +### Safety +### + +!! article +Template:Dangerous attribute +!! text +" onmouseover="alert(document.cookie) +!! endarticle + +!! article +Template:Dangerous style attribute +!! text +border-size: expression(alert(document.cookie)) +!! endarticle + +!! article +Template:Div style +!! text +<div style="float: right; {{{1}}}">Magic div</div> +!! endarticle + +!! test +Bug 2304: HTML attribute safety (safe template; regression bug 2309) +!! input +<div title="{{test}}"></div> +!! result +<div title="This is a test template"></div> + +!! end + +!! test +Bug 2304: HTML attribute safety (dangerous template; 2309) +!! input +<div title="{{dangerous attribute}}"></div> +!! result +<div title=""></div> + +!! end + +!! test +Bug 2304: HTML attribute safety (dangerous style template; 2309) +!! input +<div style="{{dangerous style attribute}}"></div> +!! result +<div style="/* insecure input */"></div> + +!! end + +!! test +Bug 2304: HTML attribute safety (safe parameter; 2309) +!! input +{{div style|width: 200px}} +!! result +<div style="float: right; width: 200px">Magic div</div> + +!! end + +!! test +Bug 2304: HTML attribute safety (unsafe parameter; 2309) +!! input +{{div style|width: expression(alert(document.cookie))}} +!! result +<div style="/* insecure input */">Magic div</div> + +!! end + +!! test +Bug 2304: HTML attribute safety (unsafe breakout parameter; 2309) +!! input +{{div style|"><script>alert(document.cookie)</script>}} +!! result +<div style="float: right;"><script>alert(document.cookie)</script>">Magic div</div> + +!! end + +!! test +Bug 2304: HTML attribute safety (unsafe breakout parameter 2; 2309) +!! input +{{div style|" ><script>alert(document.cookie)</script>}} +!! result +<div style="float: right;"><script>alert(document.cookie)</script>">Magic div</div> + +!! end + +!! test +Bug 2304: HTML attribute safety (link) +!! input +<div title="[[Main Page]]"></div> +!! result +<div title="[[Main Page]]"></div> + +!! end + +!! test +Bug 2304: HTML attribute safety (italics) +!! input +<div title="''foobar''"></div> +!! result +<div title="''foobar''"></div> + +!! end + +!! test +Bug 2304: HTML attribute safety (bold) +!! input +<div title="'''foobar'''"></div> +!! result +<div title="'''foobar'''"></div> + +!! end + + +!! test +Bug 2304: HTML attribute safety (ISBN) +!! input +<div title="ISBN 1234567890"></div> +!! result +<div title="ISBN 1234567890"></div> + +!! end + +!! test +Bug 2304: HTML attribute safety (RFC) +!! input +<div title="RFC 1234"></div> +!! result +<div title="RFC 1234"></div> + +!! end + +!! test +Bug 2304: HTML attribute safety (PMID) +!! input +<div title="PMID 1234567890"></div> +!! result +<div title="PMID 1234567890"></div> + +!! end + +!! test +Bug 2304: HTML attribute safety (web link) +!! input +<div title="http://example.com/"></div> +!! result +<div title="http://example.com/"></div> + +!! end + +!! test +Bug 2304: HTML attribute safety (named web link) +!! input +<div title="[http://example.com/ link]"></div> +!! result +<div title="[http://example.com/ link]"></div> + +!! end + +!! test +Bug 3244: HTML attribute safety (extension; safe) +!! input +<div style="<nowiki>background:blue</nowiki>"></div> +!! result +<div style="background:blue"></div> + +!! end + +!! test +Bug 3244: HTML attribute safety (extension; unsafe) +!! input +<div style="<nowiki>border-left:expression(alert(document.cookie))</nowiki>"></div> +!! result +<div style="/* insecure input */"></div> + +!! end + +# More MSIE fun discovered by Tom Gilder + +!! test +MSIE CSS safety test: spurious slash +!! input +<div style="background-image:u\rl(javascript:alert('boo'))">evil</div> +!! result +<div style="/* insecure input */">evil</div> + +!! end + +!! test +MSIE CSS safety test: hex code +!! input +<div style="background-image:u\72l(javascript:alert('boo'))">evil</div> +!! result +<div style="/* insecure input */">evil</div> + +!! end + +!! test +MSIE CSS safety test: comment in url +!! input +<div style="background-image:u/**/rl(javascript:alert('boo'))">evil</div> +!! result +<div style="background-image:u rl(javascript:alert('boo'))">evil</div> + +!! end + +!! test +MSIE CSS safety test: comment in expression +!! input +<div style="background-image:expres/**/sion(alert('boo4'))">evil4</div> +!! result +<div style="background-image:expres sion(alert('boo4'))">evil4</div> + +!! end + + +!! test +Table attribute legitimate extension +!! input +{| +!+ style="<nowiki>color:blue</nowiki>"| status +|} +!! result +<table> +<tr> +<th style="color:blue"> status +</th></tr></table> + +!!end + +!! test +Table attribute safety +!! input +{| +!+ style="<nowiki>border-width:expression(0+alert(document.cookie))</nowiki>"| status +|} +!! result +<table> +<tr> +<th style="/* insecure input */"> status +</th></tr></table> + +!! end + +!! test +CSS line continuation 1 +!! input +<div style="background-image: u\ rl(test.jpg);"></div> +!! result +<div style="/* insecure input */"></div> + +!! end + +!! test +CSS line continuation 2 +!! input +<div style="background-image: u\ rl(test.jpg); "></div> +!! result +<div style="/* insecure input */"></div> + +!! end + +!! article +Template:Identity +!! text +{{{1}}} +!! endarticle + +!! test +Expansion of multi-line templates in attribute values (bug 6255) +!! input +<div style="background: {{identity|#00FF00}}">-</div> +!! result +<div style="background: #00FF00">-</div> + +!! end + + +!! test +Expansion of multi-line templates in attribute values (bug 6255 sanity check) +!! input +<div style="background: +#00FF00">-</div> +!! result +<div style="background: #00FF00">-</div> + +!! end + +!! test +Expansion of multi-line templates in attribute values (bug 6255 sanity check 2) +!! input +<div style="background: #00FF00">-</div> +!! result +<div style="background: #00FF00">-</div> + +!! end + +### +### Parser hooks (see maintenance/parserTestsParserHook.php for the <tag> extension) +### +!! test +Parser hook: empty input +!! input +<tag></tag> +!! result +<pre> +'' +array ( +) +</pre> + +!! end + +!! test +Parser hook: empty input using terminated empty elements +!! input +<tag/> +!! result +<pre> +NULL +array ( +) +</pre> + +!! end + +!! test +Parser hook: empty input using terminated empty elements (space before) +!! input +<tag /> +!! result +<pre> +NULL +array ( +) +</pre> + +!! end + +!! test +Parser hook: basic input +!! input +<tag>input</tag> +!! result +<pre> +'input' +array ( +) +</pre> + +!! end + + +!! test +Parser hook: case insensitive +!! input +<TAG>input</TAG> +!! result +<pre> +'input' +array ( +) +</pre> + +!! end + + +!! test +Parser hook: case insensitive, redux +!! input +<TaG>input</TAg> +!! result +<pre> +'input' +array ( +) +</pre> + +!! end + +!! test +Parser hook: nested tags +!! options +noxml +!! input +<tag><tag></tag></tag> +!! result +<pre> +'<tag>' +array ( +) +</pre></tag> + +!! end + +!! test +Parser hook: basic arguments +!! input +<tag width=200 height = "100" depth = '50' square></tag> +!! result +<pre> +'' +array ( + 'width' => '200', + 'height' => '100', + 'depth' => '50', + 'square' => 'square', +) +</pre> + +!! end + +!! test +Parser hook: argument containing a forward slash (bug 5344) +!! input +<tag filename='/tmp/bla'></tag> +!! result +<pre> +'' +array ( + 'filename' => '/tmp/bla', +) +</pre> + +!! end + +!! test +Parser hook: empty input using terminated empty elements (bug 2374) +!! input +<tag foo=bar/>text +!! result +<pre> +NULL +array ( + 'foo' => 'bar', +) +</pre>text + +!! end + +# </tag> should be output literally since there is no matching tag that begins it +!! test +Parser hook: basic arguments using terminated empty elements (bug 2374) +!! input +<tag width=200 height = "100" depth = '50' square/> +other stuff +</tag> +!! result +<pre> +NULL +array ( + 'width' => '200', + 'height' => '100', + 'depth' => '50', + 'square' => 'square', +) +</pre> +<p>other stuff +</tag> +</p> +!! end + +### +### (see maintenance/parserTestsStaticParserHook.php for the <statictag> extension) +### + +!! test +Parser hook: static parser hook not inside a comment +!! input +<statictag>hello, world</statictag> +<statictag action=flush/> +!! result +<p>hello, world +</p> +!! end + + +!! test +Parser hook: static parser hook inside a comment +!! input +<!-- <statictag>hello, world</statictag> --> +<statictag action=flush/> +!! result +<p><br /> +</p> +!! end + +# Nested template calls; this case was broken by Parser.php rev 1.506, +# since reverted. + +!! article +Template:One-parameter +!! text +(My parameter is: {{{1}}}) +!! endarticle + +!! article +Template:Map-one-parameter +!! text +{{{{{1}}}|{{{2}}}}} +!! endarticle + +!! test +Nested template calls +!! input +{{Map-one-parameter|One-parameter|param}} +!! result +<p>(My parameter is: param) +</p> +!! end + + +### +### Sanitizer +### +!! test +Sanitizer: Closing of open tags +!! input +<s></s><table></table> +!! result +<s></s><table></table> + +!! end + +!! test +Sanitizer: Closing of open but not closed tags +!! input +<s>foo +!! result +<p><s>foo</s> +</p> +!! end + +!! test +Sanitizer: Closing of closed but not open tags +!! input +</s> +!! result +<p></s> +</p> +!! end + +!! test +Sanitizer: Closing of closed but not open table tags +!! input +Table not started</td></tr></table> +!! result +<p>Table not started</td></tr></table> +</p> +!! end + +!! test +Sanitizer: Escaping of spaces, multibyte characters, colons & other stuff in id="" +!! input +<span id="æ: v">byte</span>[[#æ: v|backlink]] +!! result +<p><span id=".C3.A6:_v">byte</span><a href="#.C3.A6:_v">backlink</a> +</p> +!! end + +!! test +Sanitizer: Validating the contents of the id attribute (bug 4515) +!! options +disabled +!! input +<br id=9 /> +!! result +Something, but definitely not <br id="9" />... +!! end + +!! test +Sanitizer: Validating id attribute uniqueness (bug 4515, bug 6301) +!! options +disabled +!! input +<br id="foo" /><br id="foo" /> +!! result +Something need to be done. foo-2 ? +!! end + +!! test +Sanitizer: Validating that <meta> and <link> work, but only for Microdata +!! input +<div itemscope> + <meta itemprop="hello" content="world"> + <meta http-equiv="refresh" content="5"> + <meta itemprop="hello" http-equiv="refresh" content="5"> + <link itemprop="hello" href="{{SERVER}}"> + <link rel="stylesheet" href="{{SERVER}}"> + <link rel="stylesheet" itemprop="hello" href="{{SERVER}}"> +</div> +!! result +<div itemscope="itemscope"> +<p> <meta itemprop="hello" content="world" /> + <meta http-equiv="refresh" content="5"> + <meta itemprop="hello" content="5" /> +</p> + <link itemprop="hello" href="http://example.org" /> + <link rel="stylesheet" href="<a rel="nofollow" class="external free" href="http://example.org">http://example.org</a>"> + <link itemprop="hello" href="http://example.org" /> +</div> + +!! end + +!! test +Language converter: output gets cut off unexpectedly (bug 5757) +!! options +language=zh +!! input +this bit is safe: }- + +but if we add a conversion instance: -{zh-cn:xxx;zh-tw:yyy}- + +then we get cut off here: }- + +all additional text is vanished +!! result +<p>this bit is safe: }- +</p><p>but if we add a conversion instance: xxx +</p><p>then we get cut off here: }- +</p><p>all additional text is vanished +</p> +!! end + +!! test +Self closed html pairs (bug 5487) +!! options +!! input +<center><font id="bug" />Centered text</center> +<div><font id="bug2" />In div text</div> +!! result +<center><font id="bug" />Centered text</center> +<div><font id="bug2" />In div text</div> + +!! end + +# +# +# + +!! test +Punctuation: nbsp before exclamation +!! input +C'est grave ! +!! result +<p>C'est grave ! +</p> +!! end + +!! test +Punctuation: CSS !important (bug 11874) +!! input +<div style="width:50% !important">important</div> +!! result +<div style="width:50% !important">important</div> + +!!end + +!! test +Punctuation: CSS ! important (bug 11874; with space after) +!! input +<div style="width:50% ! important">important</div> +!! result +<div style="width:50% ! important">important</div> + +!!end + + +!! test +HTML bullet list, closed tags (bug 5497) +!! input +<ul> +<li>One</li> +<li>Two</li> +</ul> +!! result +<ul> +<li>One</li> +<li>Two</li> +</ul> + +!! end + +!! test +HTML bullet list, unclosed tags (bug 5497) +!! options +disabled +!! input +<ul> +<li>One +<li>Two +</ul> +!! result +<ul> +<li>One +</li><li>Two +</li></ul> + +!! end + +!! test +HTML ordered list, closed tags (bug 5497) +!! input +<ol> +<li>One</li> +<li>Two</li> +</ol> +!! result +<ol> +<li>One</li> +<li>Two</li> +</ol> + +!! end + +!! test +HTML ordered list, unclosed tags (bug 5497) +!! options +disabled +!! input +<ol> +<li>One +<li>Two +</ol> +!! result +<ol> +<li>One +</li><li>Two +</li></ol> + +!! end + +!! test +HTML nested bullet list, closed tags (bug 5497) +!! input +<ul> +<li>One</li> +<li>Two: +<ul> +<li>Sub-one</li> +<li>Sub-two</li> +</ul> +</li> +</ul> +!! result +<ul> +<li>One</li> +<li>Two: +<ul> +<li>Sub-one</li> +<li>Sub-two</li> +</ul> +</li> +</ul> + +!! end + +!! test +HTML nested bullet list, open tags (bug 5497) +!! options +disabled +!! input +<ul> |