summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2014-03-28 05:41:12 +0100
committerPierre Schmitz <pierre@archlinux.de>2014-03-28 05:41:12 +0100
commit9441dde8bfb95277df073717ed7817dced40f948 (patch)
treeba31c10147e91bda378b77c8cae90c5651af9bfe
parentd417de70fcf39e0a7a15ba780b597914d16ca0f7 (diff)
Update to MediaWiki 1.22.5
-rw-r--r--.gitreview6
-rw-r--r--.jshintignore29
-rw-r--r--.jshintrc42
-rw-r--r--CREDITS1
-rw-r--r--RELEASE-NOTES-1.2224
-rw-r--r--extensions/Cite/.gitreview5
-rw-r--r--extensions/Cite/.jshintignore1
-rw-r--r--extensions/Cite/.jshintrc34
-rw-r--r--extensions/ConfirmEdit/.gitreview5
-rw-r--r--extensions/Gadgets/.gitreview5
-rw-r--r--extensions/Gadgets/tests/GadgetTest.php81
-rw-r--r--extensions/ImageMap/.gitreview5
-rw-r--r--extensions/InputBox/.gitreview5
-rw-r--r--extensions/Interwiki/.gitreview6
-rw-r--r--extensions/LocalisationUpdate/.gitreview5
-rw-r--r--extensions/LocalisationUpdate/tests/tokenTest.php91
-rw-r--r--extensions/Nuke/.gitreview5
-rw-r--r--extensions/ParserFunctions/.gitreview5
-rw-r--r--extensions/ParserFunctions/tests/ExpressionTest.php76
-rw-r--r--extensions/PdfHandler/.gitreview5
-rw-r--r--extensions/Poem/.gitreview5
-rw-r--r--extensions/Renameuser/.gitreview5
-rw-r--r--extensions/SpamBlacklist/.gitreview5
-rw-r--r--extensions/SyntaxHighlight_GeSHi/.gitreview5
-rw-r--r--extensions/TitleBlacklist/.gitreview5
-rw-r--r--extensions/TitleBlacklist/tests/ApiQueryTitleBlacklistTest.php110
-rw-r--r--extensions/TitleBlacklist/tests/testSource4
-rw-r--r--extensions/WikiEditor/.gitreview6
-rw-r--r--extensions/WikiEditor/.jshintignore2
-rw-r--r--extensions/WikiEditor/.jshintrc9
-rw-r--r--extensions/WikiEditor/tests/selenium/WikiDialogs_Links.php67
-rw-r--r--extensions/WikiEditor/tests/selenium/WikiDialogs_Links_Setup.php295
-rw-r--r--extensions/WikiEditor/tests/selenium/WikiEditorConstants.php84
-rw-r--r--extensions/WikiEditor/tests/selenium/WikiEditorSeleniumConfig.php27
-rw-r--r--extensions/WikiEditor/tests/selenium/WikiEditorTestSuite.php35
-rw-r--r--includes/DefaultSettings.php2
-rw-r--r--includes/EditPage.php21
-rw-r--r--includes/db/DatabaseMysqli.php13
-rw-r--r--includes/specials/SpecialChangePassword.php16
-rw-r--r--includes/templates/Userlogin.php13
-rw-r--r--languages/messages/MessagesEn.php15
-rw-r--r--languages/messages/MessagesQqq.php19
-rw-r--r--maintenance/importTextFile.php1
-rw-r--r--maintenance/language/messageTypes.inc2
-rw-r--r--maintenance/language/messages.inc2
-rw-r--r--resources/mediawiki/mediawiki.js9
-rw-r--r--skins/CologneBlue.php7
-rw-r--r--skins/common/images/icons/fileicon-djvu.xcfbin0 -> 83394 bytes
-rw-r--r--skins/common/images/icons/fileicon-ogg.xcfbin0 -> 40236 bytes
-rw-r--r--tests/.htaccess1
-rw-r--r--tests/TestsAutoLoader.php104
-rw-r--r--tests/parser/ParserTestResult.php42
-rw-r--r--tests/parser/README8
-rw-r--r--tests/parser/extraParserTests.txtbin0 -> 1261 bytes
-rw-r--r--tests/parser/parserTest.inc1465
-rw-r--r--tests/parser/parserTests.txt18591
-rw-r--r--tests/parser/parserTestsParserHook.php66
-rw-r--r--tests/parser/preprocess/All_system_messages.expected5625
-rw-r--r--tests/parser/preprocess/All_system_messages.txt5624
-rw-r--r--tests/parser/preprocess/Factorial.expected17
-rw-r--r--tests/parser/preprocess/Factorial.txt16
-rw-r--r--tests/parser/preprocess/Fundraising.expected18
-rw-r--r--tests/parser/preprocess/Fundraising.txt17
-rw-r--r--tests/parser/preprocess/NestedTemplates.expected90
-rw-r--r--tests/parser/preprocess/NestedTemplates.txt89
-rw-r--r--tests/parser/preprocess/QuoteQuran.expected140
-rw-r--r--tests/parser/preprocess/QuoteQuran.txt139
-rw-r--r--tests/parserTests.php94
-rw-r--r--tests/phpunit/Makefile91
-rw-r--r--tests/phpunit/MediaWikiLangTestCase.php33
-rw-r--r--tests/phpunit/MediaWikiPHPUnitCommand.php119
-rw-r--r--tests/phpunit/MediaWikiPHPUnitTestListener.php114
-rw-r--r--tests/phpunit/MediaWikiTestCase.php948
-rw-r--r--tests/phpunit/README53
-rw-r--r--tests/phpunit/TODO10
-rw-r--r--tests/phpunit/bootstrap.php15
-rw-r--r--tests/phpunit/data/db/mysql/functions.sql12
-rw-r--r--tests/phpunit/data/db/postgres/functions.sql12
-rw-r--r--tests/phpunit/data/db/sqlite/tables-1.13.sql342
-rw-r--r--tests/phpunit/data/db/sqlite/tables-1.15.sql454
-rw-r--r--tests/phpunit/data/db/sqlite/tables-1.16.sql478
-rw-r--r--tests/phpunit/data/db/sqlite/tables-1.17.sql511
-rw-r--r--tests/phpunit/data/db/sqlite/tables-1.18.sql530
-rw-r--r--tests/phpunit/data/less/common/test.common.mixins.less5
-rw-r--r--tests/phpunit/data/less/module/dependency.less3
-rw-r--r--tests/phpunit/data/less/module/styles.css6
-rw-r--r--tests/phpunit/data/less/module/styles.less6
-rw-r--r--tests/phpunit/data/media/1bit-png.pngbin0 -> 167 bytes
-rw-r--r--tests/phpunit/data/media/80x60-2layers.xcfbin0 -> 1162 bytes
-rw-r--r--tests/phpunit/data/media/80x60-Greyscale.xcfbin0 -> 667 bytes
-rw-r--r--tests/phpunit/data/media/80x60-RGB.xcfbin0 -> 677 bytes
-rw-r--r--tests/phpunit/data/media/Animated_PNG_example_bouncing_beach_ball.pngbin0 -> 72209 bytes
-rw-r--r--tests/phpunit/data/media/Gtk-media-play-ltr.svg35
-rw-r--r--tests/phpunit/data/media/Png-native-test.pngbin0 -> 4665 bytes
-rw-r--r--tests/phpunit/data/media/QA_icon.svg77
-rw-r--r--tests/phpunit/data/media/README38
-rw-r--r--tests/phpunit/data/media/Toll_Texas_1.svg150
-rw-r--r--tests/phpunit/data/media/US_states_by_total_state_tax_revenue.svg248
-rw-r--r--tests/phpunit/data/media/Wikimedia-logo.svg14
-rw-r--r--tests/phpunit/data/media/Xmp-exif-multilingual_test.jpgbin0 -> 12544 bytes
-rw-r--r--tests/phpunit/data/media/animated-xmp.gifbin0 -> 3864 bytes
-rw-r--r--tests/phpunit/data/media/animated.gifbin0 -> 497 bytes
-rw-r--r--tests/phpunit/data/media/broken_exif_date.jpgbin0 -> 3233 bytes
-rw-r--r--tests/phpunit/data/media/exif-gps.jpgbin0 -> 665 bytes
-rw-r--r--tests/phpunit/data/media/exif-user-comment.jpgbin0 -> 484 bytes
-rw-r--r--tests/phpunit/data/media/greyscale-na-png.pngbin0 -> 365 bytes
-rw-r--r--tests/phpunit/data/media/greyscale-png.pngbin0 -> 415 bytes
-rw-r--r--tests/phpunit/data/media/iptc-invalid-psir.jpgbin0 -> 9574 bytes
-rw-r--r--tests/phpunit/data/media/iptc-timetest-invalid.jpgbin0 -> 9573 bytes
-rw-r--r--tests/phpunit/data/media/iptc-timetest.jpgbin0 -> 9573 bytes
-rw-r--r--tests/phpunit/data/media/jpeg-comment-binary.jpgbin0 -> 448 bytes
-rw-r--r--tests/phpunit/data/media/jpeg-comment-iso8859-1.jpgbin0 -> 447 bytes
-rw-r--r--tests/phpunit/data/media/jpeg-comment-multiple.jpgbin0 -> 431 bytes
-rw-r--r--tests/phpunit/data/media/jpeg-comment-utf.jpgbin0 -> 445 bytes
-rw-r--r--tests/phpunit/data/media/jpeg-iptc-bad-hash.jpgbin0 -> 499 bytes
-rw-r--r--tests/phpunit/data/media/jpeg-iptc-good-hash.jpgbin0 -> 499 bytes
-rw-r--r--tests/phpunit/data/media/jpeg-padding-even.jpgbin0 -> 450 bytes
-rw-r--r--tests/phpunit/data/media/jpeg-padding-odd.jpgbin0 -> 451 bytes
-rw-r--r--tests/phpunit/data/media/jpeg-xmp-alt.jpgbin0 -> 3255 bytes
-rw-r--r--tests/phpunit/data/media/jpeg-xmp-psir.jpgbin0 -> 3308 bytes
-rw-r--r--tests/phpunit/data/media/jpeg-xmp-psir.xmp35
-rw-r--r--tests/phpunit/data/media/landscape-plain.jpgbin0 -> 38771 bytes
-rw-r--r--tests/phpunit/data/media/nonanimated.gifbin0 -> 200 bytes
-rw-r--r--tests/phpunit/data/media/portrait-rotated.jpgbin0 -> 38577 bytes
-rw-r--r--tests/phpunit/data/media/rgb-na-png.pngbin0 -> 593 bytes
-rw-r--r--tests/phpunit/data/media/rgb-png.pngbin0 -> 663 bytes
-rw-r--r--tests/phpunit/data/media/test.jpgbin0 -> 437 bytes
-rw-r--r--tests/phpunit/data/media/test.tiffbin0 -> 566 bytes
-rw-r--r--tests/phpunit/data/media/xmp.pngbin0 -> 582 bytes
-rw-r--r--tests/phpunit/data/xmp/1.result.php8
-rw-r--r--tests/phpunit/data/xmp/1.xmp11
-rw-r--r--tests/phpunit/data/xmp/2.result.php8
-rw-r--r--tests/phpunit/data/xmp/2.xmp12
-rw-r--r--tests/phpunit/data/xmp/3-invalid.result.php7
-rw-r--r--tests/phpunit/data/xmp/3-invalid.xmp31
-rw-r--r--tests/phpunit/data/xmp/3.result.php8
-rw-r--r--tests/phpunit/data/xmp/3.xmp29
-rw-r--r--tests/phpunit/data/xmp/4.result.php7
-rw-r--r--tests/phpunit/data/xmp/4.xmp22
-rw-r--r--tests/phpunit/data/xmp/5.result.php7
-rw-r--r--tests/phpunit/data/xmp/5.xmp16
-rw-r--r--tests/phpunit/data/xmp/6.result.php8
-rw-r--r--tests/phpunit/data/xmp/6.xmp18
-rw-r--r--tests/phpunit/data/xmp/7.result.php52
-rw-r--r--tests/phpunit/data/xmp/7.xmp67
-rw-r--r--tests/phpunit/data/xmp/README3
-rw-r--r--tests/phpunit/data/xmp/bag-for-seq.result.php10
-rw-r--r--tests/phpunit/data/xmp/bag-for-seq.xmp1
-rw-r--r--tests/phpunit/data/xmp/flash.result.php8
-rw-r--r--tests/phpunit/data/xmp/flash.xmp11
-rw-r--r--tests/phpunit/data/xmp/gps.result.php11
-rw-r--r--tests/phpunit/data/xmp/gps.xmp17
-rw-r--r--tests/phpunit/data/xmp/invalid-child-not-struct.result.php7
-rw-r--r--tests/phpunit/data/xmp/invalid-child-not-struct.xmp12
-rw-r--r--tests/phpunit/data/xmp/no-namespace.result.php7
-rw-r--r--tests/phpunit/data/xmp/no-namespace.xmp11
-rw-r--r--tests/phpunit/data/xmp/no-recognized-props.result.php2
-rw-r--r--tests/phpunit/data/xmp/no-recognized-props.xmp8
-rw-r--r--tests/phpunit/data/xmp/utf16BE.result.php12
-rw-r--r--tests/phpunit/data/xmp/utf16BE.xmpbin0 -> 930 bytes
-rw-r--r--tests/phpunit/data/xmp/utf16LE.result.php12
-rw-r--r--tests/phpunit/data/xmp/utf16LE.xmpbin0 -> 930 bytes
-rw-r--r--tests/phpunit/data/xmp/utf32BE.result.php12
-rw-r--r--tests/phpunit/data/xmp/utf32BE.xmpbin0 -> 1856 bytes
-rw-r--r--tests/phpunit/data/xmp/utf32LE.result.php12
-rw-r--r--tests/phpunit/data/xmp/utf32LE.xmpbin0 -> 1856 bytes
-rw-r--r--tests/phpunit/data/xmp/xmpExt.result.php8
-rw-r--r--tests/phpunit/data/xmp/xmpExt.xmp13
-rw-r--r--tests/phpunit/data/xmp/xmpExt2.xmp8
-rw-r--r--tests/phpunit/data/zip/cd-gap.zipbin0 -> 182 bytes
-rw-r--r--tests/phpunit/data/zip/cd-truncated.zipbin0 -> 171 bytes
-rw-r--r--tests/phpunit/data/zip/class-trailing-null.zipbin0 -> 173 bytes
-rw-r--r--tests/phpunit/data/zip/class-trailing-slash.zipbin0 -> 173 bytes
-rw-r--r--tests/phpunit/data/zip/class.zipbin0 -> 173 bytes
-rw-r--r--tests/phpunit/data/zip/empty.zipbin0 -> 22 bytes
-rw-r--r--tests/phpunit/data/zip/looks-like-zip64.zipbin0 -> 173 bytes
-rw-r--r--tests/phpunit/data/zip/nosig.zipbin0 -> 173 bytes
-rw-r--r--tests/phpunit/data/zip/split.zipbin0 -> 196 bytes
-rw-r--r--tests/phpunit/data/zip/trail.zipbin0 -> 181 bytes
-rw-r--r--tests/phpunit/data/zip/wrong-cd-start-disk.zipbin0 -> 173 bytes
-rw-r--r--tests/phpunit/data/zip/wrong-central-entry-sig.zipbin0 -> 173 bytes
-rw-r--r--tests/phpunit/docs/ExportDemoTest.php39
-rw-r--r--tests/phpunit/includes/ArticleTablesTest.php32
-rw-r--r--tests/phpunit/includes/ArticleTest.php92
-rw-r--r--tests/phpunit/includes/BlockTest.php354
-rw-r--r--tests/phpunit/includes/CdbTest.php88
-rw-r--r--tests/phpunit/includes/CollationTest.php111
-rw-r--r--tests/phpunit/includes/DiffHistoryBlobTest.php44
-rw-r--r--tests/phpunit/includes/EditPageTest.php491
-rw-r--r--tests/phpunit/includes/ExternalStoreTest.php81
-rw-r--r--tests/phpunit/includes/ExtraParserTest.php157
-rw-r--r--tests/phpunit/includes/FallbackTest.php73
-rw-r--r--tests/phpunit/includes/FauxRequestTest.php15
-rw-r--r--tests/phpunit/includes/FauxResponseTest.php74
-rw-r--r--tests/phpunit/includes/FormOptionsInitializationTest.php84
-rw-r--r--tests/phpunit/includes/FormOptionsTest.php91
-rw-r--r--tests/phpunit/includes/GlobalFunctions/GlobalTest.php652
-rw-r--r--tests/phpunit/includes/GlobalFunctions/GlobalWithDBTest.php31
-rw-r--r--tests/phpunit/includes/GlobalFunctions/README2
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfAssembleUrlTest.php111
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfBCP47Test.php120
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfBaseConvertTest.php182
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfBaseNameTest.php36
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfExpandUrlTest.php111
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfGetCallerTest.php40
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfParseUrlTest.php146
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfRemoveDotSegmentsTest.php91
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfShorthandToIntegerTest.php30
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php134
-rw-r--r--tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php119
-rw-r--r--tests/phpunit/includes/HTMLCheckMatrixTest.php102
-rw-r--r--tests/phpunit/includes/HashRingTest.php53
-rw-r--r--tests/phpunit/includes/HooksTest.php158
-rw-r--r--tests/phpunit/includes/HtmlFormatterTest.php81
-rw-r--r--tests/phpunit/includes/HtmlTest.php631
-rw-r--r--tests/phpunit/includes/HttpTest.php216
-rw-r--r--tests/phpunit/includes/IPTest.php595
-rw-r--r--tests/phpunit/includes/LanguageConverterTest.php148
-rw-r--r--tests/phpunit/includes/LicensesTest.php22
-rw-r--r--tests/phpunit/includes/LinkerTest.php71
-rw-r--r--tests/phpunit/includes/LinksUpdateTest.php175
-rw-r--r--tests/phpunit/includes/LocalFileTest.php107
-rw-r--r--tests/phpunit/includes/LocalisationCacheTest.php31
-rw-r--r--tests/phpunit/includes/MWExceptionHandlerTest.php73
-rw-r--r--tests/phpunit/includes/MWFunctionTest.php30
-rw-r--r--tests/phpunit/includes/MWNamespaceTest.php571
-rw-r--r--tests/phpunit/includes/MessageTest.php130
-rw-r--r--tests/phpunit/includes/OutputPageTest.php133
-rw-r--r--tests/phpunit/includes/PathRouterTest.php263
-rw-r--r--tests/phpunit/includes/PreferencesTest.php91
-rw-r--r--tests/phpunit/includes/RecentChangeTest.php280
-rw-r--r--tests/phpunit/includes/RequestContextTest.php73
-rw-r--r--tests/phpunit/includes/ResourceLoaderTest.php149
-rw-r--r--tests/phpunit/includes/RevisionStorageTest.php546
-rw-r--r--tests/phpunit/includes/RevisionStorageTest_ContentHandlerUseDB.php81
-rw-r--r--tests/phpunit/includes/RevisionTest.php481
-rw-r--r--tests/phpunit/includes/SampleTest.php105
-rw-r--r--tests/phpunit/includes/SanitizerTest.php302
-rw-r--r--tests/phpunit/includes/SanitizerValidateEmailTest.php103
-rw-r--r--tests/phpunit/includes/SiteConfigurationTest.php335
-rw-r--r--tests/phpunit/includes/StringUtilsTest.php147
-rw-r--r--tests/phpunit/includes/TemplateCategoriesTest.php53
-rw-r--r--tests/phpunit/includes/TestUser.php59
-rw-r--r--tests/phpunit/includes/TimeAdjustTest.php41
-rw-r--r--tests/phpunit/includes/TimestampTest.php304
-rw-r--r--tests/phpunit/includes/TitleMethodsTest.php300
-rw-r--r--tests/phpunit/includes/TitlePermissionTest.php742
-rw-r--r--tests/phpunit/includes/TitleTest.php485
-rw-r--r--tests/phpunit/includes/UIDGeneratorTest.php98
-rw-r--r--tests/phpunit/includes/UserMailerTest.php14
-rw-r--r--tests/phpunit/includes/UserTest.php237
-rw-r--r--tests/phpunit/includes/WebRequestTest.php310
-rw-r--r--tests/phpunit/includes/WikiPageTest.php1074
-rw-r--r--tests/phpunit/includes/WikiPageTest_ContentHandlerUseDB.php53
-rw-r--r--tests/phpunit/includes/XmlJsTest.php24
-rw-r--r--tests/phpunit/includes/XmlSelectTest.php173
-rw-r--r--tests/phpunit/includes/XmlTest.php402
-rw-r--r--tests/phpunit/includes/XmlTypeCheckTest.php30
-rw-r--r--tests/phpunit/includes/ZipDirectoryReaderTest.php85
-rw-r--r--tests/phpunit/includes/api/ApiAccountCreationTest.php159
-rw-r--r--tests/phpunit/includes/api/ApiBlockTest.php95
-rw-r--r--tests/phpunit/includes/api/ApiEditPageTest.php417
-rw-r--r--tests/phpunit/includes/api/ApiOptionsTest.php420
-rw-r--r--tests/phpunit/includes/api/ApiParseTest.php29
-rw-r--r--tests/phpunit/includes/api/ApiPurgeTest.php40
-rw-r--r--tests/phpunit/includes/api/ApiTest.php259
-rw-r--r--tests/phpunit/includes/api/ApiTestCase.php253
-rw-r--r--tests/phpunit/includes/api/ApiTestCaseUpload.php149
-rw-r--r--tests/phpunit/includes/api/ApiUploadTest.php561
-rw-r--r--tests/phpunit/includes/api/ApiWatchTest.php148
-rw-r--r--tests/phpunit/includes/api/PrefixUniquenessTest.php25
-rw-r--r--tests/phpunit/includes/api/RandomImageGenerator.php468
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatPhpTest.php17
-rw-r--r--tests/phpunit/includes/api/format/ApiFormatTestBase.php22
-rw-r--r--tests/phpunit/includes/api/generateRandomImages.php46
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryBasicTest.php395
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryContinue2Test.php68
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryContinueTest.php313
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php209
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryRevisionsTest.php39
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryTest.php66
-rw-r--r--tests/phpunit/includes/api/query/ApiQueryTestBase.php150
-rw-r--r--tests/phpunit/includes/api/words.txt1000
-rw-r--r--tests/phpunit/includes/cache/GenderCacheTest.php104
-rw-r--r--tests/phpunit/includes/cache/MessageCacheTest.php128
-rw-r--r--tests/phpunit/includes/cache/ProcessCacheLRUTest.php237
-rw-r--r--tests/phpunit/includes/content/ContentHandlerTest.php451
-rw-r--r--tests/phpunit/includes/content/CssContentTest.php87
-rw-r--r--tests/phpunit/includes/content/JavaScriptContentTest.php287
-rw-r--r--tests/phpunit/includes/content/TextContentTest.php458
-rw-r--r--tests/phpunit/includes/content/WikitextContentHandlerTest.php227
-rw-r--r--tests/phpunit/includes/content/WikitextContentTest.php404
-rw-r--r--tests/phpunit/includes/db/DatabaseMysqlBaseTest.php209
-rw-r--r--tests/phpunit/includes/db/DatabaseSQLTest.php721
-rw-r--r--tests/phpunit/includes/db/DatabaseSqliteTest.php421
-rw-r--r--tests/phpunit/includes/db/DatabaseTest.php234
-rw-r--r--tests/phpunit/includes/db/DatabaseTestHelper.php166
-rw-r--r--tests/phpunit/includes/db/ORMRowTest.php226
-rw-r--r--tests/phpunit/includes/db/ORMTableTest.php146
-rw-r--r--tests/phpunit/includes/db/TestORMRowTest.php215
-rw-r--r--tests/phpunit/includes/debug/MWDebugTest.php72
-rw-r--r--tests/phpunit/includes/filebackend/FileBackendTest.php2306
-rw-r--r--tests/phpunit/includes/filerepo/FileRepoTest.php55
-rw-r--r--tests/phpunit/includes/filerepo/StoreBatchTest.php134
-rw-r--r--tests/phpunit/includes/installer/InstallDocFormatterTest.php65
-rw-r--r--tests/phpunit/includes/installer/OracleInstallerTest.php48
-rw-r--r--tests/phpunit/includes/jobqueue/JobQueueTest.php329
-rw-r--r--tests/phpunit/includes/json/FormatJsonTest.php161
-rw-r--r--tests/phpunit/includes/libs/CSSJanusTest.php606
-rw-r--r--tests/phpunit/includes/libs/CSSMinTest.php133
-rw-r--r--tests/phpunit/includes/libs/GenericArrayObjectTest.php263
-rw-r--r--tests/phpunit/includes/libs/IEUrlExtensionTest.php126
-rw-r--r--tests/phpunit/includes/libs/JavaScriptMinifierTest.php170
-rw-r--r--tests/phpunit/includes/logging/LogFormatterTest.php207
-rw-r--r--tests/phpunit/includes/logging/LogTests.i18n.php15
-rw-r--r--tests/phpunit/includes/media/BitmapMetadataHandlerTest.php167
-rw-r--r--tests/phpunit/includes/media/BitmapScalingTest.php137
-rw-r--r--tests/phpunit/includes/media/ExifBitmapTest.php139
-rw-r--r--tests/phpunit/includes/media/ExifRotationTest.php248
-rw-r--r--tests/phpunit/includes/media/ExifTest.php46
-rw-r--r--tests/phpunit/includes/media/FakeDimensionFile.php28
-rw-r--r--tests/phpunit/includes/media/FormatMetadataTest.php59
-rw-r--r--tests/phpunit/includes/media/GIFMetadataExtractorTest.php107
-rw-r--r--tests/phpunit/includes/media/GIFTest.php120
-rw-r--r--tests/phpunit/includes/media/IPTCTest.php81
-rw-r--r--tests/phpunit/includes/media/JpegMetadataExtractorTest.php109
-rw-r--r--tests/phpunit/includes/media/JpegTest.php33
-rw-r--r--tests/phpunit/includes/media/MediaHandlerTest.php53
-rw-r--r--tests/phpunit/includes/media/PNGMetadataExtractorTest.php155
-rw-r--r--tests/phpunit/includes/media/PNGTest.php123
-rw-r--r--tests/phpunit/includes/media/SVGMetadataExtractorTest.php112
-rw-r--r--tests/phpunit/includes/media/TiffTest.php39
-rw-r--r--tests/phpunit/includes/media/XMPTest.php166
-rw-r--r--tests/phpunit/includes/media/XMPValidateTest.php46
-rw-r--r--tests/phpunit/includes/normal/CleanUpTest.php409
-rw-r--r--tests/phpunit/includes/objectcache/BagOStuffTest.php149
-rw-r--r--tests/phpunit/includes/parser/MagicVariableTest.php242
-rw-r--r--tests/phpunit/includes/parser/MediaWikiParserTest.php120
-rw-r--r--tests/phpunit/includes/parser/NewParserTest.php969
-rw-r--r--tests/phpunit/includes/parser/ParserMethodsTest.php95
-rw-r--r--tests/phpunit/includes/parser/ParserOutputTest.php59
-rw-r--r--tests/phpunit/includes/parser/ParserPreloadTest.php80
-rw-r--r--tests/phpunit/includes/parser/PreprocessorTest.php239
-rw-r--r--tests/phpunit/includes/parser/TagHooksTest.php82
-rw-r--r--tests/phpunit/includes/parser/TidyTest.php44
-rw-r--r--tests/phpunit/includes/search/SearchEngineTest.php176
-rw-r--r--tests/phpunit/includes/search/SearchUpdateTest.php74
-rw-r--r--tests/phpunit/includes/site/MediaWikiSiteTest.php90
-rw-r--r--tests/phpunit/includes/site/SiteListTest.php197
-rw-r--r--tests/phpunit/includes/site/SiteSQLStoreTest.php134
-rw-r--r--tests/phpunit/includes/site/SiteTest.php296
-rw-r--r--tests/phpunit/includes/site/TestSites.php100
-rw-r--r--tests/phpunit/includes/specials/QueryAllSpecialPagesTest.php79
-rw-r--r--tests/phpunit/includes/specials/SpecialPreferencesTest.php60
-rw-r--r--tests/phpunit/includes/specials/SpecialRecentchangesTest.php125
-rw-r--r--tests/phpunit/includes/specials/SpecialSearchTest.php139
-rw-r--r--tests/phpunit/includes/upload/UploadBaseTest.php147
-rw-r--r--tests/phpunit/includes/upload/UploadFromUrlTest.php350
-rw-r--r--tests/phpunit/includes/upload/UploadStashTest.php76
-rw-r--r--tests/phpunit/install-phpunit.sh37
-rw-r--r--tests/phpunit/languages/LanguageAmTest.php35
-rw-r--r--tests/phpunit/languages/LanguageArTest.php87
-rw-r--r--tests/phpunit/languages/LanguageBeTest.php42
-rw-r--r--tests/phpunit/languages/LanguageBe_taraskTest.php95
-rw-r--r--tests/phpunit/languages/LanguageBhoTest.php35
-rw-r--r--tests/phpunit/languages/LanguageBsTest.php42
-rw-r--r--tests/phpunit/languages/LanguageClassesTestCase.php74
-rw-r--r--tests/phpunit/languages/LanguageCsTest.php41
-rw-r--r--tests/phpunit/languages/LanguageCuTest.php42
-rw-r--r--tests/phpunit/languages/LanguageCyTest.php43
-rw-r--r--tests/phpunit/languages/LanguageDsbTest.php41
-rw-r--r--tests/phpunit/languages/LanguageFrTest.php35
-rw-r--r--tests/phpunit/languages/LanguageGaTest.php35
-rw-r--r--tests/phpunit/languages/LanguageGdTest.php53
-rw-r--r--tests/phpunit/languages/LanguageGvTest.php44
-rw-r--r--tests/phpunit/languages/LanguageHeTest.php132
-rw-r--r--tests/phpunit/languages/LanguageHiTest.php35
-rw-r--r--tests/phpunit/languages/LanguageHrTest.php42
-rw-r--r--tests/phpunit/languages/LanguageHsbTest.php41
-rw-r--r--tests/phpunit/languages/LanguageHuTest.php35
-rw-r--r--tests/phpunit/languages/LanguageHyTest.php35
-rw-r--r--tests/phpunit/languages/LanguageKshTest.php35
-rw-r--r--tests/phpunit/languages/LanguageLnTest.php35
-rw-r--r--tests/phpunit/languages/LanguageLtTest.php63
-rw-r--r--tests/phpunit/languages/LanguageLvTest.php44
-rw-r--r--tests/phpunit/languages/LanguageMgTest.php36
-rw-r--r--tests/phpunit/languages/LanguageMkTest.php40
-rw-r--r--tests/phpunit/languages/LanguageMlTest.php38
-rw-r--r--tests/phpunit/languages/LanguageMoTest.php45
-rw-r--r--tests/phpunit/languages/LanguageMtTest.php77
-rw-r--r--tests/phpunit/languages/LanguageNlTest.php24
-rw-r--r--tests/phpunit/languages/LanguageNsoTest.php34
-rw-r--r--tests/phpunit/languages/LanguagePlTest.php77
-rw-r--r--tests/phpunit/languages/LanguageRoTest.php45
-rw-r--r--tests/phpunit/languages/LanguageRuTest.php105
-rw-r--r--tests/phpunit/languages/LanguageSeTest.php53
-rw-r--r--tests/phpunit/languages/LanguageSgsTest.php71
-rw-r--r--tests/phpunit/languages/LanguageShTest.php42
-rw-r--r--tests/phpunit/languages/LanguageSkTest.php42
-rw-r--r--tests/phpunit/languages/LanguageSlTest.php44
-rw-r--r--tests/phpunit/languages/LanguageSmaTest.php53
-rw-r--r--tests/phpunit/languages/LanguageSrTest.php246
-rw-r--r--tests/phpunit/languages/LanguageTest.php1567
-rw-r--r--tests/phpunit/languages/LanguageTiTest.php34
-rw-r--r--tests/phpunit/languages/LanguageTlTest.php34
-rw-r--r--tests/phpunit/languages/LanguageTrTest.php59
-rw-r--r--tests/phpunit/languages/LanguageUkTest.php72
-rw-r--r--tests/phpunit/languages/LanguageUzTest.php121
-rw-r--r--tests/phpunit/languages/LanguageWaTest.php34
-rw-r--r--tests/phpunit/languages/utils/CLDRPluralRuleEvaluatorTest.php145
-rw-r--r--tests/phpunit/maintenance/DumpTestCase.php379
-rw-r--r--tests/phpunit/maintenance/MaintenanceTest.php816
-rw-r--r--tests/phpunit/maintenance/backupPrefetchTest.php275
-rw-r--r--tests/phpunit/maintenance/backupTextPassTest.php581
-rw-r--r--tests/phpunit/maintenance/backup_LogTest.php228
-rw-r--r--tests/phpunit/maintenance/backup_PageTest.php404
-rw-r--r--tests/phpunit/maintenance/fetchTextTest.php238
-rw-r--r--tests/phpunit/maintenance/getSlaveServerTest.php67
-rw-r--r--tests/phpunit/mocks/filebackend/MockFSFile.php69
-rw-r--r--tests/phpunit/mocks/filebackend/MockFileBackend.php122
-rw-r--r--tests/phpunit/mocks/media/MockBitmapHandler.php92
-rw-r--r--tests/phpunit/phpunit.php119
-rw-r--r--tests/phpunit/run-tests.bat1
-rw-r--r--tests/phpunit/skins/SideBarTest.php223
-rw-r--r--tests/phpunit/structure/AutoLoaderTest.php56
-rw-r--r--tests/phpunit/structure/ResourcesTest.php131
-rw-r--r--tests/phpunit/structure/StructureTest.php63
-rw-r--r--tests/phpunit/suite.xml51
-rw-r--r--tests/phpunit/suites/ExtensionsParserTestSuite.php8
-rw-r--r--tests/phpunit/suites/ExtensionsTestSuite.php33
-rw-r--r--tests/phpunit/suites/UploadFromUrlTestSuite.php207
-rw-r--r--tests/qunit/.htaccess1
-rw-r--r--tests/qunit/QUnitTestResources.php68
-rw-r--r--tests/qunit/data/callMwLoaderTestCallback.js1
-rw-r--r--tests/qunit/data/generateJqueryMsgData.php150
-rw-r--r--tests/qunit/data/load.mock.php59
-rw-r--r--tests/qunit/data/mediawiki.jqueryMsg.data.js492
-rw-r--r--tests/qunit/data/qunitOkCall.js2
-rw-r--r--tests/qunit/data/styleTest.css.php61
-rw-r--r--tests/qunit/data/testrunner.js431
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.autoEllipsis.test.js58
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.byteLength.test.js37
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.byteLimit.test.js252
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.client.test.js542
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.colorUtil.test.js63
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.delayedBind.test.js37
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.getAttrs.test.js13
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.hidpi.test.js22
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.highlightText.test.js235
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.localize.test.js135
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.makeCollapsible.test.js287
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js57
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.tabIndex.test.js35
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js1268
-rw-r--r--tests/qunit/suites/resources/jquery/jquery.textSelection.test.js275
-rw-r--r--tests/qunit/suites/resources/mediawiki.api/mediawiki.api.parse.test.js28
-rw-r--r--tests/qunit/suites/resources/mediawiki.api/mediawiki.api.test.js61
-rw-r--r--tests/qunit/suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js63
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js416
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.Uri.test.js433
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.cldr.test.js81
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js714
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.jscompat.test.js70
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.language.test.js443
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.test.js916
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.user.test.js57
-rw-r--r--tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js354
-rw-r--r--tests/qunit/suites/resources/startup.test.js129
-rw-r--r--tests/testHelpers.inc633
469 files changed, 91387 insertions, 28 deletions
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 00000000..bb83fd3b
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,6 @@
+[gerrit]
+host=gerrit.wikimedia.org
+port=29418
+project=mediawiki/core.git
+defaultbranch=REL1_22
+defaultrebase=0
diff --git a/.jshintignore b/.jshintignore
new file mode 100644
index 00000000..f740f137
--- /dev/null
+++ b/.jshintignore
@@ -0,0 +1,29 @@
+# Generated documentation
+docs/html/
+docs/js/
+
+# 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/
+resources/jquery.chosen/chosen.jquery.js
+
+# 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..c4e265a4
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,42 @@
+{
+ /* Common */
+
+ // Enforcing
+ "camelcase": true,
+ "curly": true,
+ "eqeqeq": true,
+ "immed": true,
+ "latedef": true,
+ "newcap": true,
+ "noarg": true,
+ "noempty": true,
+ "nonew": true,
+ "quotmark": "single",
+ "trailing": true,
+ "undef": true,
+ "unused": true,
+ // Legacy
+ "onevar": true,
+
+ /* Local */
+
+ // Enforcing
+ "bitwise": true,
+ "forin": false,
+ "regexp": false,
+ "strict": false,
+ // Relaxing
+ "laxbreak": true,
+ "smarttabs": true,
+ "multistr": true,
+ // Environment
+ "browser": true,
+ // Legacy
+ "nomen": true,
+
+ "predef": [
+ "mediaWiki",
+ "jQuery",
+ "QUnit"
+ ]
+}
diff --git a/CREDITS b/CREDITS
index 54aca716..c480e737 100644
--- a/CREDITS
+++ b/CREDITS
@@ -213,6 +213,7 @@ following names for their contribution to the product.
* Salvatore Ingala
* Santhosh Thottingal
* Scott Colcord
+* se4598
* Sébastien Santoro
* Simon Walker
* Solitarius
diff --git a/RELEASE-NOTES-1.22 b/RELEASE-NOTES-1.22
index 284ef1f8..99f893b6 100644
--- a/RELEASE-NOTES-1.22
+++ b/RELEASE-NOTES-1.22
@@ -3,6 +3,29 @@
Security reminder: MediaWiki does not require PHP's register_globals. If you
have it on, turn it '''off''' if you can.
+== MediaWiki 1.22.5 ==
+
+This is a security and maintenance release of the MediaWiki 1.22 branch.
+
+=== Changes since 1.22.4 ===
+
+* (bug 62497) SECURITY: Add CSRF token on Special:ChangePassword.
+* (bug 62467) Set a title for the context during import on the cli.
+* Fix custom local MediaWiki:Helppage values.
+* mediawiki.js: Fix documentation breakage.
+* (bug 58153) Make MySQLi work with non standard port.
+* (bug 53887) Reintroduced a link to help pages in the default sidebar, that
+ any sysop can customize by editing [[MediaWiki:Sidebar]] locally. The link
+ now points to a mediawiki.org page which is guaranteed to exist. Nothing needs
+ to be done on your end, but remember to adjust [[MediaWiki:Sidebar]] for the
+ needs of your wikis. Everyone can help with the shared documentation by
+ translating: https://www.mediawiki.org/wiki/Special:Translate/agg-Help_pages .
+* (bug 53888) Corrected a regression in 1.22 which introduced red links on the
+ login page. If you previously installed 1.22.x and have created a local page
+ to make the red link blue, write its title as in [[MediaWiki:helplogin-url]]
+ if you didn't already. Otherwise, you don't need to do anything, but you can
+ translate the help page at https://www.mediawiki.org/wiki/Help:Logging_in .
+
== MediaWiki 1.22.4 ==
This is a maintenance release of the MediaWiki 1.22 branch.
@@ -16,6 +39,7 @@ This is a maintenance release of the MediaWiki 1.22 branch.
This is a security and bugfix release of the MediaWiki 1.22 branch.
=== Changes since 1.22.2 ===
+
* (bug 60771) SECURITY: Disallow uploading SVG files using non-whitelisted
namespaces. Also disallow iframe elements. User will get an error
including the namespace name if they use a non- whitelisted namespace.
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/Cite/.jshintignore b/extensions/Cite/.jshintignore
new file mode 100644
index 00000000..df46ab97
--- /dev/null
+++ b/extensions/Cite/.jshintignore
@@ -0,0 +1 @@
+modules/jquery.tooltip/jquery.tooltip.js
diff --git a/extensions/Cite/.jshintrc b/extensions/Cite/.jshintrc
new file mode 100644
index 00000000..4b356f81
--- /dev/null
+++ b/extensions/Cite/.jshintrc
@@ -0,0 +1,34 @@
+{
+ "camelcase": true,
+ "curly": true,
+ "eqeqeq": true,
+ "immed": true,
+ "latedef": true,
+ "newcap": true,
+ "supernew": true,
+ "shadow": true,
+ "noarg": true,
+ "noempty": true,
+ "nonew": true,
+ "quotmark": false, // sometimes double quotes make sense, e.g. "foo's" is better readable than 'foo\'s'
+ "trailing": true,
+ "undef": true,
+ "unused": "vars", // we want to allow unused function parameters
+ "laxbreak": true,
+ "laxcomma": false,
+ "onevar": false,
+ "bitwise": false,
+ "forin": false,
+ "regexp": false,
+ "strict": true,
+ "scripturl": true,
+
+ // Environment
+ "browser": true,
+
+ // Globals
+ "predef": [
+ "jQuery",
+ "mediaWiki"
+ ]
+}
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/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['&lt;gadget-section-remove-section&gt;'] ), 'Must not show empty sections' );
+ $this->assertTrue( isset( $options['&lt;gadget-section-keep-section1&gt;'] ) );
+ $this->assertTrue( isset( $options['&lt;gadget-section-keep-section2&gt;'] ) );
+
+ // 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/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/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/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/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 2aa5b09f..c0228282 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -63,7 +63,7 @@ $wgConf = new SiteConfiguration;
* MediaWiki version number
* @since 1.2
*/
-$wgVersion = '1.22.4';
+$wgVersion = '1.22.5';
/**
* Name of the site. It must be changed in LocalSettings.php
diff --git a/includes/EditPage.php b/includes/EditPage.php
index 530e2674..16d9a5a4 100644
--- a/includes/EditPage.php
+++ b/includes/EditPage.php
@@ -2049,10 +2049,27 @@ class EditPage {
}
# Try to add a custom edit intro, or use the standard one if this is not possible.
if ( !$this->showCustomIntro() && !$this->mTitle->exists() ) {
+ $helpLink = wfExpandUrl( Skin::makeInternalOrExternalUrl(
+ wfMessage( 'helppage' )->inContentLanguage()->text()
+ ) );
if ( $wgUser->isLoggedIn() ) {
- $wgOut->wrapWikiMsg( "<div class=\"mw-newarticletext\">\n$1\n</div>", 'newarticletext' );
+ $wgOut->wrapWikiMsg(
+ // Suppress the external link icon, consider the help url an internal one
+ "<div class=\"mw-newarticletext plainlinks\">\n$1\n</div>",
+ array(
+ 'newarticletext',
+ $helpLink
+ )
+ );
} else {
- $wgOut->wrapWikiMsg( "<div class=\"mw-newarticletextanon\">\n$1\n</div>", 'newarticletextanon' );
+ $wgOut->wrapWikiMsg(
+ // Suppress the external link icon, consider the help url an internal one
+ "<div class=\"mw-newarticletextanon plainlinks\">\n$1\n</div>",
+ array(
+ 'newarticletextanon',
+ $helpLink
+ )
+ );
}
}
# Give a notice if the user is editing a deleted/moved page...
diff --git a/includes/db/DatabaseMysqli.php b/includes/db/DatabaseMysqli.php
index 7761abe9..0ec54314 100644
--- a/includes/db/DatabaseMysqli.php
+++ b/includes/db/DatabaseMysqli.php
@@ -51,6 +51,17 @@ class DatabaseMysqli extends DatabaseMysqlBase {
. " have you compiled PHP with the --with-mysqli option?\n" );
}
+ // Other than mysql_connect, mysqli_real_connect expects an explicit port
+ // parameter. So we need to parse the port out of $realServer
+ $port = null;
+ $hostAndPort = IP::splitHostAndPort( $realServer );
+ if ( $hostAndPort ) {
+ $realServer = $hostAndPort[0];
+ if ( $hostAndPort[1] ) {
+ $port = $hostAndPort[1];
+ }
+ }
+
$connFlags = 0;
if ( $this->mFlags & DBO_SSL ) {
$connFlags |= MYSQLI_CLIENT_SSL;
@@ -70,7 +81,7 @@ class DatabaseMysqli extends DatabaseMysqlBase {
usleep( 1000 );
}
if ( $mysqli->real_connect( $realServer, $this->mUser,
- $this->mPassword, $this->mDBname, null, null, $connFlags ) )
+ $this->mPassword, $this->mDBname, $port, null, $connFlags ) )
{
return $mysqli;
}
diff --git a/includes/specials/SpecialChangePassword.php b/includes/specials/SpecialChangePassword.php
index c54b5575..a75e7e83 100644
--- a/includes/specials/SpecialChangePassword.php
+++ b/includes/specials/SpecialChangePassword.php
@@ -52,6 +52,11 @@ class SpecialChangePassword extends UnlistedSpecialPage {
$this->mDomain = $request->getVal( 'wpDomain' );
$user = $this->getUser();
+
+ if ( !$user->isLoggedIn() && !LoginForm::getLoginToken() ) {
+ LoginForm::setLoginToken();
+ }
+
if ( !$request->wasPosted() && !$user->isLoggedIn() ) {
$this->error( $this->msg( 'resetpass-no-info' )->text() );
@@ -81,6 +86,14 @@ class SpecialChangePassword extends UnlistedSpecialPage {
return;
}
+ if ( !$user->isLoggedIn()
+ && $request->getVal( 'wpLoginOnChangeToken' ) !== LoginForm::getLoginToken()
+ ) {
+ // Potential CSRF (bug 62497)
+ $this->error( $this->msg( 'sessionfailure' )->text() );
+ return false;
+ }
+
$this->attemptReset( $this->mNewpass, $this->mRetype );
if ( $user->isLoggedIn() ) {
@@ -157,6 +170,9 @@ class SpecialChangePassword extends UnlistedSpecialPage {
'wpName' => $this->mUserName,
'wpDomain' => $this->mDomain,
) + $this->getRequest()->getValues( 'returnto', 'returntoquery' );
+ if ( !$user->isLoggedIn() ) {
+ $hiddenFields['wpLoginOnChangeToken'] = LoginForm::getLoginToken();
+ }
$hiddenFieldsStr = '';
foreach ( $hiddenFields as $fieldname => $fieldvalue ) {
$hiddenFieldsStr .= Html::hidden( $fieldname, $fieldvalue ) . "\n";
diff --git a/includes/templates/Userlogin.php b/includes/templates/Userlogin.php
index 5eb60948..9aedd3c7 100644
--- a/includes/templates/Userlogin.php
+++ b/includes/templates/Userlogin.php
@@ -154,9 +154,18 @@ class UserloginTemplate extends BaseTemplate {
) );
?>
</div>
-
<div id="mw-userlogin-help">
- <?php echo $this->getMsg( 'userlogin-helplink' )->parse(); ?>
+ <?php
+ echo Html::element(
+ 'a',
+ array(
+ 'href' => Skin::makeInternalOrExternalUrl(
+ wfMessage( 'helplogin-url' )->inContentLanguage()->text()
+ ),
+ ),
+ $this->getMsg( 'userlogin-helplink2' )->text()
+ );
+ ?>
</div>
<?php if ( $this->haveData( 'createOrLoginHref' ) ) { ?>
<?php if ( $this->data['loggedin'] ) { ?>
diff --git a/languages/messages/MessagesEn.php b/languages/messages/MessagesEn.php
index e0ff25e9..4f82b86d 100644
--- a/languages/messages/MessagesEn.php
+++ b/languages/messages/MessagesEn.php
@@ -644,6 +644,7 @@ future releases. Also note that since each list value is wrapped in a unique
** mainpage|mainpage-description
** recentchanges-url|recentchanges
** randompage-url|randompage
+** helppage|help
* SEARCH
* TOOLBOX
* LANGUAGES', # do not translate or duplicate this message to other languages
@@ -912,7 +913,7 @@ $1',
'disclaimerpage' => 'Project:General disclaimer',
'edithelp' => 'Editing help',
'edithelppage' => 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Editing_pages', # do not translate or duplicate this message to other languages
-'helppage' => 'Help:Contents',
+'helppage' => 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents',
'mainpage' => 'Main Page',
'mainpage-description' => 'Main page',
'policy-url' => 'Project:Policy',
@@ -1131,8 +1132,8 @@ You can change your {{SITENAME}} [[Special:Preferences|preferences]] if you wish
'gotaccountlink' => 'Log in',
'userlogin-resetlink' => 'Forgotten your login details?',
'userlogin-resetpassword-link' => 'Forgot your password?',
-'helplogin-url' => 'Help:Logging in',
-'userlogin-helplink' => '[[{{MediaWiki:helplogin-url}}|Help with logging in]]',
+'helplogin-url' => 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Logging_in',
+'userlogin-helplink2' => 'Help with logging in',
'userlogin-loggedin' => 'You are already logged in as {{GENDER:$1|$1}}.
Use the form below to log in as another user.',
'userlogin-createanother' => 'Create another account',
@@ -1432,10 +1433,10 @@ It may have been moved or deleted while you were viewing the page.',
'accmailtitle' => 'Password sent',
'accmailtext' => "A randomly generated password for [[User talk:$1|$1]] has been sent to $2. It can be changed on the ''[[Special:ChangePassword|change password]]'' page upon logging in.",
'newarticle' => '(New)',
-'newarticletext' => "You have followed a link to a page that does not exist yet.
-To create the page, start typing in the box below (see the [[{{MediaWiki:Helppage}}|help page]] for more info).
-If you are here by mistake, click your browser's '''back''' button.",
-'newarticletextanon' => '{{int:newarticletext}}', # do not translate or duplicate this message to other languages
+'newarticletext' => "You have followed a link to a page that does not exist yet.
+To create the page, start typing in the box below (see the [$1 help page] for more info).
+If you are here by mistake, click your browser's <strong>back</strong> button.",
+'newarticletextanon' => '{{int:newarticletext|$1}}', # do not translate or duplicate this message to other languages
'talkpagetext' => '<!-- MediaWiki:talkpagetext -->', # do not translate or duplicate this message to other languages
'anontalkpagetext' => "----
''This is the discussion page for an anonymous user who has not created an account yet, or who does not use it.''
diff --git a/languages/messages/MessagesQqq.php b/languages/messages/MessagesQqq.php
index 63dc8453..f30453a6 100644
--- a/languages/messages/MessagesQqq.php
+++ b/languages/messages/MessagesQqq.php
@@ -1343,13 +1343,13 @@ The link points to the local [[Special:PasswordReset]].
See example: [[Special:UserLogin]]
-userlogin-resetpassword-link may have to be shorter than the old {{msg-mw|userlogin-resetlink}}',
-'helplogin-url' => '{{doc-important|Do not translate the namespace name <code>Help</code>.}}
-Used as name of the page that provides information about logging into the wiki.
+userlogin-resetpassword-link may have to be shorter than the old {{msg-mw|userlogin-resetlink}}.
+{{Identical|Forgot your password}}',
+'helplogin-url' => '{{doc-important|Do not translate the target page, Special:MyLanguage handles it.}}
+Defines the URL to the page that provides information about logging into the wiki.
-Used as a link target in the message {{msg-mw|Userlogin-helplink}}.',
-'userlogin-helplink' => '{{doc-important|Do not change <code><nowiki>{{MediaWiki:helplogin-url}}</nowiki></code>.}}
-Wikitext linking to login help.
+Used as a link target for the link with label {{msg-mw|userlogin-helplink2}}; can be locally customised to be an URL or local page title.',
+'userlogin-helplink2' => 'Label for a link to login help.
See example: [[Special:UserLogin]]
@@ -1881,10 +1881,9 @@ Parameters:
* $1 - username
* $2 - email address",
'newarticle' => '{{Identical|New}}',
-'newarticletext' => '{{doc-important|Do not translate <code><nowiki>{{MediaWiki:Helppage}}</nowiki></code>.}}
-Text displayed above the edit box in editor when trying to create a new page.
-
-Refers to {{msg-mw|Helppage}}.',
+'newarticletext' => "Text displayed above the edit box in editor when trying to create a new page.
+Parameters:
+* $1 - The URL to the help page, defined in {{msg-mw|helppage}}",
'anontalkpagetext' => 'Displayed at the bottom of talk pages of anonymous users.',
'noarticletext' => 'This is the message that you get if you search for a term that has not yet got any entries on the wiki.
diff --git a/maintenance/importTextFile.php b/maintenance/importTextFile.php
index e081c20b..4a07f2c7 100644
--- a/maintenance/importTextFile.php
+++ b/maintenance/importTextFile.php
@@ -42,6 +42,7 @@ if ( count( $args ) < 1 || isset( $options['help'] ) ) {
echo "\nUsing title '" . $title->getPrefixedText() . "'...";
if ( !$title->exists() || !isset( $options['nooverwrite'] ) ) {
+ RequestContext::getMain()->setTitle( $title );
$text = file_get_contents( $filename );
$user = isset( $options['user'] ) ? $options['user'] : 'Maintenance script';
diff --git a/maintenance/language/messageTypes.inc b/maintenance/language/messageTypes.inc
index 0b9b7cb8..f9239b1c 100644
--- a/maintenance/language/messageTypes.inc
+++ b/maintenance/language/messageTypes.inc
@@ -266,7 +266,9 @@ $wgIgnoredMessages = array(
'createacct-benefit-icon3',
'today-at',
'redirect-text',
+ 'helppage',
'edithelppage',
+ 'helplogin-url',
'autocomment-prefix',
'move-redirect-text',
);
diff --git a/maintenance/language/messages.inc b/maintenance/language/messages.inc
index de163a61..e351549b 100644
--- a/maintenance/language/messages.inc
+++ b/maintenance/language/messages.inc
@@ -484,7 +484,7 @@ $wgMessageStructure = array(
'userlogin-resetlink',
'userlogin-resetpassword-link',
'helplogin-url',
- 'userlogin-helplink',
+ 'userlogin-helplink2',
'userlogin-loggedin',
'userlogin-createanother',
'createacct-join',
diff --git a/resources/mediawiki/mediawiki.js b/resources/mediawiki/mediawiki.js
index 80223e5d..5a4ff1b5 100644
--- a/resources/mediawiki/mediawiki.js
+++ b/resources/mediawiki/mediawiki.js
@@ -21,6 +21,7 @@ var mw = ( function ( $, undefined ) {
* fine. No need for optimization here, which would only result in losing logs.
*
* @private
+ * @method log_
* @param {string} msg text for the log entry.
* @param {Error} [e]
*/
@@ -318,6 +319,9 @@ var mw = ( function ( $, undefined ) {
}
};
+ /**
+ * @class mw
+ */
return {
/* Public Members */
@@ -1446,16 +1450,19 @@ var mw = ( function ( $, undefined ) {
* @param {Function|Array} script Function with module code or Array of URLs to
* be used as the src attribute of a new `<script>` tag.
* @param {Object} style Should follow one of the following patterns:
+ *
* { "css": [css, ..] }
* { "url": { <media>: [url, ..] } }
+ *
* And for backwards compatibility (needs to be supported forever due to caching):
+ *
* { <media>: css }
* { <media>: [url, ..] }
*
* The reason css strings are not concatenated anymore is bug 31676. We now check
* whether it's safe to extend the stylesheet (see #canExpandStylesheetWith).
*
- * @param {Object} msgs List of key/value pairs to be added to {@link mw#messages}.
+ * @param {Object} msgs List of key/value pairs to be added to mw#messages.
*/
implement: function ( module, script, style, msgs ) {
// Validate input
diff --git a/skins/CologneBlue.php b/skins/CologneBlue.php
index 0370e05b..04e0e6a4 100644
--- a/skins/CologneBlue.php
+++ b/skins/CologneBlue.php
@@ -369,9 +369,10 @@ class CologneBlueTemplate extends BaseTemplate {
Title::newFromText( wfMessage( 'aboutpage' )->inContentLanguage()->text() ),
wfMessage( 'about' )->text()
),
- Linker::linkKnown(
- Title::newFromText( wfMessage( 'helppage' )->inContentLanguage()->text() ),
- wfMessage( 'help' )->text()
+ Linker::makeExternalLink(
+ Skin::makeInternalOrExternalUrl( wfMessage( 'helppage' )->inContentLanguage()->text() ),
+ wfMessage( 'help' )->text(),
+ false
),
Linker::linkKnown(
Title::newFromText( wfMessage( 'faqpage' )->inContentLanguage()->text() ),
diff --git a/skins/common/images/icons/fileicon-djvu.xcf b/skins/common/images/icons/fileicon-djvu.xcf
new file mode 100644
index 00000000..8043dcdb
--- /dev/null
+++ b/skins/common/images/icons/fileicon-djvu.xcf
Binary files differ
diff --git a/skins/common/images/icons/fileicon-ogg.xcf b/skins/common/images/icons/fileicon-ogg.xcf
new file mode 100644
index 00000000..a91024bf
--- /dev/null
+++ b/skins/common/images/icons/fileicon-ogg.xcf
Binary files differ
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/TestsAutoLoader.php b/tests/TestsAutoLoader.php
new file mode 100644
index 00000000..00ce13c8
--- /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",
+ 'ParserTestResult' => "$testDir/parser/ParserTestResult.php",
+ 'TestFileIterator' => "$testDir/testHelpers.inc",
+ 'TestRecorder' => "$testDir/testHelpers.inc",
+ 'ITestRecorder' => "$testDir/testHelpers.inc",
+
+ # tests/phpunit
+ 'MediaWikiTestCase' => "$testDir/phpunit/MediaWikiTestCase.php",
+ 'MediaWikiPHPUnitCommand' => "$testDir/phpunit/MediaWikiPHPUnitCommand.php",
+ 'MediaWikiPHPUnitTestListener' => "$testDir/phpunit/MediaWikiPHPUnitTestListener.php",
+ 'MediaWikiLangTestCase' => "$testDir/phpunit/MediaWikiLangTestCase.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",
+ 'DatabaseTestHelper' => "$testDir/phpunit/includes/db/DatabaseTestHelper.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",
+ 'MediaWikiParserTest' => "$testDir/phpunit/includes/parser/MediaWikiParserTest.php",
+
+ # tests/phpunit/includes/libs
+ 'GenericArrayObjectTest' => "$testDir/phpunit/includes/libs/GenericArrayObjectTest.php",
+
+ # tests/phpunit/media
+ 'FakeDimensionFile' => "$testDir/phpunit/includes/media/FakeDimensionFile.php",
+
+ # tests/phpunit/includes/site
+ 'SiteTest' => "$testDir/phpunit/includes/site/SiteTest.php",
+ 'TestSites' => "$testDir/phpunit/includes/site/TestSites.php",
+
+ # tests/phpunit/mocks
+ 'MockFSFile' => "$testDir/phpunit/mocks/filebackend/MockFSFile.php",
+ 'MockFileBackend' => "$testDir/phpunit/mocks/filebackend/MockFileBackend.php",
+ 'MockBitmapHandler' => "$testDir/phpunit/mocks/media/MockBitmapHandler.php",
+ 'MockImageHandler' => "$testDir/phpunit/mocks/media/MockBitmapHandler.php",
+ 'MockSvgHandler' => "$testDir/phpunit/mocks/media/MockBitmapHandler.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",
+);
diff --git a/tests/parser/ParserTestResult.php b/tests/parser/ParserTestResult.php
new file mode 100644
index 00000000..d9ad773d
--- /dev/null
+++ b/tests/parser/ParserTestResult.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * @copyright Copyright © 2013, Antoine Musso
+ * @copyright Copyright © 2013, Wikimedia Foundation Inc.
+ * @license GNU GPL v2
+ *
+ * @file
+ */
+
+/**
+ * Represent the result of a parser test.
+ *
+ * @since 1.22
+ */
+class ParserTestResult {
+ /**
+ * Description of the parser test.
+ *
+ * This is usually the text used to describe a parser test in the .txt
+ * files. It is initialized on a construction and you most probably
+ * never want to change it.
+ */
+ public $description;
+ /** Text that was expected */
+ public $expected;
+ /** Actual text rendered */
+ public $actual;
+
+ /**
+ * @param $description string A short text describing the parser test
+ * usually the text in the parser test .txt file. The description
+ * is later available using the property $description.
+ */
+ public function __construct( $description ) {
+ $this->description = $description;
+ }
+
+ /** Whether the test passed */
+ public function isSuccess() {
+ return $this->expected === $this->actual;
+ }
+}
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
new file mode 100644
index 00000000..bef8f506
--- /dev/null
+++ b/tests/parser/extraParserTests.txt
Binary files differ
diff --git a/tests/parser/parserTest.inc b/tests/parser/parserTest.inc
new file mode 100644
index 00000000..58ea1ed0
--- /dev/null
+++ b/tests/parser/parserTest.inc
@@ -0,0 +1,1465 @@
+<?php
+/**
+ * Helper code for the MediaWiki parser test suite. Some code is duplicated
+ * in PHPUnit's NewParserTests.php, so you'll probably want to update both
+ * at the same time.
+ *
+ * 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 {
+ /**
+ * @var bool $color whereas output should be colorized
+ */
+ private $color;
+
+ /**
+ * @var bool $showOutput Show test output
+ */
+ private $showOutput;
+
+ /**
+ * @var bool $useTemporaryTables Use temporary tables for the temporary database
+ */
+ private $useTemporaryTables = true;
+
+ /**
+ * @var bool $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;
+
+ /**
+ * @var 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,
+ $wgExtraNamespaces, $wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo,
+ $parserMemc, $wgThumbnailScriptPath, $wgScriptPath,
+ $wgArticlePath, $wgScript, $wgStylePath, $wgExtensionAssetsPath,
+ $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType, $wgLockManagers;
+
+ $wgScript = '/index.php';
+ $wgScriptPath = '/';
+ $wgArticlePath = '/wiki/$1';
+ $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;
+ # add a namespace shadowing a interwiki link, to test
+ # proper precedence when resolving links. (bug 51680)
+ $wgExtraNamespaces[100] = 'MemoryAlpha';
+
+ // 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";
+ }
+
+ self::setupInterwikis();
+ }
+
+ /**
+ * Insert hardcoded interwiki in the lookup table.
+ *
+ * This function insert a set of well known interwikis that are used in
+ * the parser tests. They can be considered has fixtures are injected in
+ * the interwiki cache by using the 'InterwikiLoadPrefix' hook.
+ * Since we are not interested in looking up interwikis in the database,
+ * the hook completely replace the existing mechanism (hook returns false).
+ */
+ public static function setupInterwikis() {
+ # Hack: insert a few Wikipedia in-project interwiki prefixes,
+ # for testing inter-language links
+ Hooks::register( 'InterwikiLoadPrefix', function ( $prefix, &$iwData ) {
+ static $testInterwikis = array(
+ 'wikipedia' => array(
+ 'iw_url' => 'http://en.wikipedia.org/wiki/$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 0 ),
+ 'meatball' => array(
+ 'iw_url' => 'http://www.usemod.com/cgi-bin/mb.pl?$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 0 ),
+ 'memoryalpha' => array(
+ 'iw_url' => 'http://www.memory-alpha.org/en/index.php/$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 0 ),
+ 'zh' => array(
+ 'iw_url' => 'http://zh.wikipedia.org/wiki/$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 1 ),
+ 'es' => array(
+ 'iw_url' => 'http://es.wikipedia.org/wiki/$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 1 ),
+ 'fr' => array(
+ 'iw_url' => 'http://fr.wikipedia.org/wiki/$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 1 ),
+ 'ru' => array(
+ 'iw_url' => 'http://ru.wikipedia.org/wiki/$1',
+ 'iw_api' => '',
+ 'iw_wikiid' => '',
+ 'iw_local' => 1 ),
+ );
+ if ( array_key_exists( $prefix, $testInterwikis ) ) {
+ $iwData = $testInterwikis[$prefix];
+ }
+
+ // We only want to rely on the above fixtures
+ return false;
+ } );// hooks::register
+ }
+
+ /**
+ * Remove the hardcoded interwiki lookup table.
+ */
+ public static function tearDownInterwikis() {
+ Hooks::clear( 'InterwikiLoadPrefix' );
+ }
+
+ 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;
+
+ // be sure, ParserTest::addArticle has correct language set,
+ // so that system messages gets into the right language cache
+ $GLOBALS['wgLanguageCode'] = 'en';
+ $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
+ *
+ * @param string $preprocessor
+ * @return Parser
+ */
+ 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 );
+ $output->setTOCEnabled( !isset( $opts['notoc'] ) );
+ $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();
+
+ $testResult = new ParserTestResult( $desc );
+ $testResult->expected = $result;
+ $testResult->actual = $out;
+
+ return $this->showTestResult( $testResult );
+ }
+
+ /**
+ * Refactored in 1.22 to use ParserTestResult
+ */
+ function showTestResult( ParserTestResult $testResult ) {
+ if ( $testResult->isSuccess() ) {
+ $this->showSuccess( $testResult );
+ return true;
+ } else {
+ $this->showFailure( $testResult );
+ return false;
+ }
+ }
+
+ /**
+ * Use a regex to find out the value of an option
+ * @param $key String: name of option val to retrieve
+ * @param $opts array: 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',
+ 'wgSitename' => 'MediaWiki',
+ 'wgLanguageCode' => $lang,
+ 'wgDBprefix' => $this->db->getType() != 'oracle' ? 'parsertest_' : 'pt_',
+ 'wgRawHtml' => self::getOptionValue( 'wgRawHtml', $opts, false ),
+ 'wgLang' => null,
+ 'wgContLang' => null,
+ 'wgNamespacesWithSubpages' => array( 0 => isset( $opts['subpage'] ) ),
+ 'wgMaxTocLevel' => $maxtoclevel,
+ 'wgCapitalLinks' => true,
+ 'wgNoFollowLinks' => true,
+ 'wgNoFollowDomainExceptions' => array(),
+ 'wgThumbnailScriptPath' => false,
+ 'wgUseImageResize' => true,
+ 'wgSVGConverter' => 'null',
+ 'wgSVGConverters' => array( 'null' => 'echo "1">$output' ),
+ 'wgLocaltimezone' => 'UTC',
+ 'wgAllowExternalImages' => self::getOptionValue( 'wgAllowExternalImages', $opts, 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' ) );
+ }
+
+ # 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();
+
+ // Remember to update newParserTests.php after changing the below
+ // (and it uses a slightly different syntax just for teh lulz)
+ $this->uploadDir = $this->setupUploadDir();
+ $user = User::createNew( 'WikiSysop' );
+ $image = wfLocalFile( Title::makeTitle( NS_FILE, 'Foobar.jpg' ) );
+ # note that the size/width/height/bits/etc of the file
+ # are actually set by inspecting the file itself; the arguments
+ # to recordUpload2 have no effect. That said, we try to make things
+ # match up so it is less confusing to readers of the code & tests.
+ $image->recordUpload2( '', 'Upload of some lame file', 'Some lame file', array(
+ 'size' => 7881,
+ 'width' => 1941,
+ 'height' => 220,
+ 'bits' => 8,
+ 'media_type' => MEDIATYPE_BITMAP,
+ 'mime' => 'image/jpeg',
+ 'metadata' => serialize( array() ),
+ 'sha1' => wfBaseConvert( '1', 16, 36, 31 ),
+ 'fileExists' => true
+ ), $this->db->timestamp( '20010115123500' ), $user );
+
+ $image = wfLocalFile( Title::makeTitle( NS_FILE, 'Thumb.png' ) );
+ # again, note that size/width/height below are ignored; see above.
+ $image->recordUpload2( '', 'Upload of some lame thumbnail', 'Some lame thumbnail', array(
+ 'size' => 22589,
+ 'width' => 135,
+ 'height' => 135,
+ 'bits' => 8,
+ 'media_type' => MEDIATYPE_BITMAP,
+ 'mime' => 'image/png',
+ 'metadata' => serialize( array() ),
+ 'sha1' => wfBaseConvert( '2', 16, 36, 31 ),
+ 'fileExists' => true
+ ), $this->db->timestamp( '20130225203040' ), $user );
+
+ $image = wfLocalFile( Title::makeTitle( NS_FILE, 'Foobar.svg' ) );
+ $image->recordUpload2( '', 'Upload of some lame SVG', 'Some lame SVG', array(
+ 'size' => 12345,
+ 'width' => 240,
+ 'height' => 180,
+ 'bits' => 24,
+ 'media_type' => MEDIATYPE_DRAWING,
+ 'mime' => 'image/svg+xml',
+ '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( '3', 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 ) {
+ if ( $this->db->getType() == 'oracle' ) {
+ $this->db->query( "DROP TABLE pt_$table DROP CONSTRAINTS" );
+ } else {
+ $this->db->query( "DROP TABLE `parsertest_$table`" );
+ }
+ }
+
+ 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 . '/e/ea', null, __METHOD__ );
+ copy( "$IP/skins/monobook/wiki.png", "$dir/e/ea/Thumb.png" );
+ wfMkdirParents( $dir . '/0/09', null, __METHOD__ );
+ copy( "$IP/skins/monobook/headbg.jpg", "$dir/0/09/Bad.jpg" );
+ wfMkdirParents( $dir . '/f/ff', null, __METHOD__ );
+ copy( "$IP/skins/monobook/headbg.jpg", "$dir/f/ff/Foobar.svg" );
+ file_put_contents( "$dir/f/ff/Foobar.svg",
+ '<?xml version="1.0" encoding="utf-8"?>' .
+ '<svg xmlns="http://www.w3.org/2000/svg" />' );
+ 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/e/ea/Thumb.png",
+
+ "$dir/0/09/Bad.jpg",
+
+ "$dir/f/ff/Foobar.svg",
+ "$dir/thumb/f/ff/Foobar.svg/180px-Foobar.svg.png",
+ "$dir/thumb/f/ff/Foobar.svg/360px-Foobar.svg.png",
+ "$dir/thumb/f/ff/Foobar.svg/langde-270px-Foobar.svg.png",
+ "$dir/thumb/f/ff/Foobar.svg/270px-Foobar.svg.png",
+ "$dir/thumb/f/ff/Foobar.svg/langde-180px-Foobar.svg.png",
+ "$dir/thumb/f/ff/Foobar.svg/langde-360px-Foobar.svg.png",
+
+ "$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/e/ea",
+ "$dir/e",
+ "$dir/f/ff/",
+ "$dir/f/",
+ "$dir/thumb/f/ff/Foobar.svg",
+ "$dir/thumb/f/ff/",
+ "$dir/thumb/f/",
+ "$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.
+ *
+ * Refactored in 1.22 to use ParserTestResult
+ *
+ * @param $testResult ParserTestResult
+ * @return Boolean
+ */
+ protected function showSuccess( ParserTestResult $testResult ) {
+ 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.
+ *
+ * Refactored in 1.22 to use ParserTestResult
+ *
+ * @param $testResult ParserTestResult
+ * @return Boolean
+ */
+ protected function showFailure( ParserTestResult $testResult ) {
+ 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( $testResult->description );
+ }
+
+ print $this->term->color( '31' ) . 'FAILED!' . $this->term->reset() . "\n";
+
+ if ( $this->showOutput ) {
+ print "--- Expected ---\n{$testResult->expected}\n";
+ print "--- Actual ---\n{$testResult->actual}\n";
+ }
+
+ if ( $this->showDiffs ) {
+ print $this->quickDiff( $testResult->expected, $testResult->actual );
+ if ( !$this->wellFormed( $testResult->actual ) ) {
+ 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
+ $shellCommand = ( wfIsWindows() && !$wgDiff3 ) ? 'fc' : 'diff -au';
+
+ $diff = wfShellExec( "$shellCommand $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; //parsed as '1970-01-01T00:02:03Z'
+ return true;
+ }
+}
diff --git a/tests/parser/parserTests.txt b/tests/parser/parserTests.txt
new file mode 100644
index 00000000..9658e8f8
--- /dev/null
+++ b/tests/parser/parserTests.txt
@@ -0,0 +1,18591 @@
+# 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
+# notoc disable table of contents
+#
+# You can also set the following parser properties via test options:
+# wgEnableUploads, wgAllowExternalImages, wgMaxTocLevel,
+# wgLinkHolderBatchSize, wgRawHtml
+#
+# 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
+Template:table_cells
+!! text
+{{table_attribs}} || Bar || Baz
+!! endarticle
+
+!! article
+Template:image_attribs
+!! text
+<noinclude>
+[[File:foobar.jpg|</noinclude>right|Caption text<noinclude>]]</noinclude>
+!! endarticle
+
+!! article
+A?b
+!! text
+Weirdo titles!
+!! endarticle
+
+!!article
+Template:Bullet
+!!text
+* Bar
+!!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
+Paragraphs with newline spacing with comment lines in between
+!! input
+----
+a
+<!--foo-->
+b
+----
+a
+<!--foo--><!--More than 1 comment, still stripped-->
+b
+----
+a
+ <!--foo--> <!----> <!-- bar -->
+b
+----
+a
+<!--foo-->
+
+b
+----
+a
+
+<!--foo-->
+b
+----
+a
+<!--foo-->
+
+
+b
+----
+a
+
+
+<!--foo-->
+b
+----
+!! result
+<hr />
+<p>a
+b
+</p>
+<hr />
+<p>a
+b
+</p>
+<hr />
+<p>a
+b
+</p>
+<hr />
+<p>a
+</p><p>b
+</p>
+<hr />
+<p>a
+</p><p>b
+</p>
+<hr />
+<p>a
+</p><p><br />
+b
+</p>
+<hr />
+<p>a
+</p><p><br />
+b
+</p>
+<hr />
+
+!! end
+
+!! test
+Paragraphs with newline spacing with non-empty white-space lines in between
+!! input
+----
+a
+
+b
+----
+a
+
+
+b
+----
+!! result
+<hr />
+<p>a
+</p><p>b
+</p>
+<hr />
+<p>a
+</p><p><br />
+b
+</p>
+<hr />
+
+!! end
+
+!! test
+Paragraphs with newline spacing with non-empty mixed comment and white-space lines in between
+!! input
+----
+a
+ <!--foo-->
+b
+----
+a
+ <!--foo--><!--More than 1 comment doesn't disable stripping of this line!-->
+b
+----
+a
+
+<!--foo-->
+ <!--bar-->
+b
+----
+a
+
+ <!--foo-->
+ <!--bar-->
+
+b
+----
+!! result
+<hr />
+<p>a
+b
+</p>
+<hr />
+<p>a
+b
+</p>
+<hr />
+<p>a
+</p><p>b
+</p>
+<hr />
+<p>a
+</p><p><br />
+b
+</p>
+<hr />
+
+!! end
+
+!! test
+Extra newlines: More paragraphs with indented comment
+!! input
+a
+
+ <!--boo-->
+
+b
+!!result
+<p>a
+</p><p><br />
+b
+</p>
+!!end
+
+!! test
+Extra newlines followed by heading
+!! input
+a
+
+
+
+=b=
+[[a]]
+
+
+=b=
+!! result
+<p>a
+</p><p><br />
+</p>
+<h1><span class="mw-headline" id="b">b</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: b">edit</a><span class="mw-editsection-bracket">]</span></span></h1>
+<p><a href="/index.php?title=A&amp;action=edit&amp;redlink=1" class="new" title="A (page does not exist)">a</a>
+</p><p><br />
+</p>
+<h1><span class="mw-headline" id="b_2">b</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: b">edit</a><span class="mw-editsection-bracket">]</span></span></h1>
+
+!! end
+
+!! test
+Extra newlines between heading and content are swallowed
+!! input
+=b=
+
+
+
+[[a]]
+!! result
+<h1><span class="mw-headline" id="b">b</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: b">edit</a><span class="mw-editsection-bracket">]</span></span></h1>
+<p><a href="/index.php?title=A&amp;action=edit&amp;redlink=1" class="new" title="A (page does not exist)">a</a>
+</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
+
+# this example taken from the [[simple:Moon]] article (bug 47326)
+!! test
+Italics and possessives (1)
+!! input
+obtained by ''[[Lunar Prospector]]'''s gamma-ray spectrometer
+!! result
+<p>obtained by <i><a href="/index.php?title=Lunar_Prospector&amp;action=edit&amp;redlink=1" class="new" title="Lunar Prospector (page does not exist)">Lunar Prospector</a>'</i>s gamma-ray spectrometer
+</p>
+!! end
+
+# this example taken from [[en:Flaming Pie]] (bug 49926)
+!! test
+Italics and possessives (2)
+!! input
+'''''Flaming Pie''''' is ... released in 1997. In ''Flaming Pie'''s liner notes
+!! result
+<p><i><b>Flaming Pie</b></i> is ... released in 1997. In <i>Flaming Pie'</i>s liner notes
+</p>
+!! end
+
+# this example taken from [[en:Dictionary]] (bug 49926)
+!! test
+Italics and possessives (3)
+!! input
+The first monolingual dictionary written in a Romance language was ''Sebastián Covarrubias''' ''Tesoro de la lengua castellana o española'', published in 1611 in Madrid. In 1612 the first edition of the ''Vocabolario dell'[[Accademia della Crusca]]'', for Italian, was published. In 1690 in Rotterdam was published, posthumously, the ''Dictionnaire Universel''.
+!! result
+<p>The first monolingual dictionary written in a Romance language was <i>Sebastián Covarrubias'</i> <i>Tesoro de la lengua castellana o española</i>, published in 1611 in Madrid. In 1612 the first edition of the <i>Vocabolario dell'<a href="/index.php?title=Accademia_della_Crusca&amp;action=edit&amp;redlink=1" class="new" title="Accademia della Crusca (page does not exist)">Accademia della Crusca</a></i>, for Italian, was published. In 1690 in Rotterdam was published, posthumously, the <i>Dictionnaire Universel</i>.
+</p>
+!! 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) (php)
+!! options
+php
+!! input
+''foo'''''
+!! result
+<p><i>foo</i>
+</p>
+!!end
+# The PHP parser strips the empty tags out for giggles; parsoid doesn't.
+!! test
+Italics and bold: 2-quote opening sequence: (2,5) (parsoid)
+!! options
+parsoid
+!! input
+''foo'''''
+!! result
+<p><i>foo</i><b></b>
+</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) (php)
+!! options
+php
+!! input
+'''foo'''''
+!! result
+<p><b>foo</b>
+</p>
+!!end
+# The PHP parser strips the empty tags out for giggles; parsoid doesn't.
+!! test
+Italics and bold: 3-quote opening sequence: (3,5) (parsoid)
+!! options
+parsoid
+!! input
+'''foo'''''
+!! result
+<p><b>foo</b><i></i>
+</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) (php)
+!! options
+php
+!! input
+''''foo'''''
+!! result
+<p>'<b>foo</b>
+</p>
+!!end
+# The PHP parser strips the empty tags out for giggles; parsoid doesn't.
+!! test
+Italics and bold: 4-quote opening sequence: (4,5) (parsoid)
+!! options
+parsoid
+!! input
+''''foo'''''
+!! result
+<p>'<b>foo</b><i></i>
+</p>
+!!end
+
+
+###
+### 5-quote opening sequence tests
+###
+
+!! test
+Italics and bold: 5-quote opening sequence: (5,2)
+!! options
+!! 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) (php)
+!! options
+php
+!! input
+'''foo''''bar''
+!! result
+<p><b>foo'</b>bar
+</p>
+!!end
+# The PHP parser strips the empty tags out for giggles; parsoid doesn't.
+!! test
+Italics and bold: multiple quote sequences: (3,4,2) (parsoid)
+!! options
+parsoid
+!! input
+'''foo''''bar''
+!! result
+<p><b>foo'</b>bar<i></i>
+</p>
+!!end
+
+
+!! test
+Italics and bold: multiple quote sequences: (3,4,3) (php)
+!! options
+php
+!! input
+'''foo''''bar'''
+!! result
+<p><b>foo'</b>bar
+</p>
+!!end
+# The PHP parser strips the empty tags out for giggles; parsoid doesn't.
+!! test
+Italics and bold: multiple quote sequences: (3,4,3) (parsoid)
+!! options
+parsoid
+!! input
+'''foo''''bar'''
+!! result
+<p><b>foo'</b>bar<b></b>
+</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)
+!! options
+!! 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
+
+!! test
+Parsoid only: Quote balancing context should be restricted to td/th cells on the same wikitext line
+(Requires tidy for PHP parser output to be fixed up)
+!! options
+parsoid=wt2html,wt2wt
+!! input
+{|
+!''a!!''b
+|''a||''b
+|}
+!! result
+<table>
+<tbody><tr><th><i>a</i></th><th><i>b</i></th>
+<td><i>a</i></td><td><i>b</i></td></tr>
+</tbody></table>
+!! 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
+
+!! test
+<wbr> is valid wikitext (bug 52468)
+!! input
+<wbr>
+!! result
+<p><wbr />
+</p>
+!! end
+
+# <strike> is HTML4, <s> is HTML4/5.
+!! test
+<s> or <strike> for strikethrough
+!! input
+<strike>strike</strike>
+
+<s>s</s>
+!! result
+<p><strike>strike</strike>
+</p><p><s>s</s>
+</p>
+!! end
+
+!! test
+Non-word characters don't terminate tag names (bug 17663, 40670, 52022)
+!! input
+<b→> doesn't work! </b>
+
+<bä> doesn't work! </b>
+
+<boo> works fine </b>
+
+<s.foo>foo</s>
+
+<s.foo>s.foo</s.foo>
+
+<sub-ID#1>
+!! result
+<p>&lt;b→&gt; doesn't work! &lt;/b&gt;
+</p><p>&lt;bä&gt; doesn't work! &lt;/b&gt;
+</p><p>&lt;boo&gt; works fine &lt;/b&gt;
+</p><p>&lt;s.foo&gt;foo&lt;/s&gt;
+</p><p>&lt;s.foo&gt;s.foo&lt;/s.foo&gt;
+</p><p>&lt;sub-ID#1&gt;
+</p>
+!! end
+
+###
+### Special characters
+###
+
+!! test
+Bare pipe character (bug 52363)
+!! input
+|
+!! result
+<p>|
+</p>
+!! end
+
+!! test
+Bare pipe character from a template (bug 52363)
+!! input
+{{pipe}}
+!! result
+<p>|
+</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>&lt;</nowiki>
+!! result
+<p>&lt;
+</p>
+!! end
+
+!! test
+Entities inside template parameters
+!! options
+parsoid
+!! input
+{{echo|&ndash;}}
+!! result
+<p><span typeof="mw:Transclusion mw:Entity" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&amp;ndash;"}},"i":0}}]}'>&ndash;</span>
+</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>--&gt;
+</p>
+!! end
+
+!! test
+Comment semantics: nesting
+!! input
+<!--<!-- no, we're not going to do anything fancy here -->-->
+!! result
+<p>--&gt;
+</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 wrapping tests
+###
+!! test
+No block tags
+!! input
+a
+
+b
+!! result
+<p>a
+</p><p>b
+</p>
+!! end
+
+!! test
+Block tag on one line (<div>)
+!! input
+a <div>foo</div>
+
+b
+!! result
+a <div>foo</div>
+<p>b
+</p>
+!! end
+
+!! test
+Block tag on one line (<blockquote>)
+!! input
+a <blockquote>foo</blockquote>
+
+b
+!! result
+a <blockquote>foo</blockquote>
+<p>b
+</p>
+!! end
+
+!! test
+Block tag on both lines (<div>)
+!! input
+a <div>foo</div>
+
+b <div>foo</div>
+!! result
+a <div>foo</div>
+b <div>foo</div>
+
+!! end
+
+!! test
+Block tag on both lines (<blockquote>)
+!! input
+a <blockquote>foo</blockquote>
+
+b <blockquote>foo</blockquote>
+!! result
+a <blockquote>foo</blockquote>
+b <blockquote>foo</blockquote>
+
+!! 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 lines with block tags
+!! input
+<div></div>
+
+
+<div></div>a
+
+b
+<div>a</div>b
+
+<div>b</div>d
+
+
+<div>e</div>
+!! result
+<div></div>
+<p><br />
+</p>
+<div></div>a
+<p>b
+</p>
+<div>a</div>b
+<div>b</div>d
+<p><br />
+</p>
+<div>e</div>
+
+!! 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
+Tabs don't trigger preformatted text
+!! input
+ This is not
+ preformatted text.
+ This is preformatted text.
+ So is this.
+!! result
+<p> This is not
+ preformatted text.
+</p>
+<pre>This is preformatted text.
+ So is this.
+</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>
+&lt;b&gt;
+&lt;cite&gt;
+&lt;em&gt;
+</pre>
+
+!! end
+
+!! test
+Regression with preformatted in <center>
+!! input
+<center>
+ Blah
+</center>
+!! result
+<center>
+<pre>Blah
+</pre>
+</center>
+
+!! end
+
+!! test
+Bug 52763: Preformatted in <blockquote>
+!! input
+<blockquote>
+ Blah
+</blockquote>
+!! result
+<blockquote>
+<p> Blah
+</p>
+</blockquote>
+
+!! end
+
+!! test
+Bug 51086: Double newlines in blockquotes should be turned into paragraphs
+!! input
+<blockquote>
+Foo
+
+Bar
+</blockquote>
+!! result
+<blockquote>
+<p>Foo
+</p><p>Bar
+</p>
+</blockquote>
+
+!! end
+
+!! test
+Bug 15491: <ins>/<del> in blockquote
+!! input
+<blockquote>
+Foo <del>bar</del> <ins>baz</ins> quux
+</blockquote>
+!! result
+<blockquote>
+<p>Foo <del>bar</del> <ins>baz</ins> quux
+</p>
+</blockquote>
+
+!! end
+
+# Note that the p-wrapping is newline sensitive, which could be
+# considered a bug: tidy will wrap only the 'Foo' in the example
+# below in a <p> tag. (see comment 23-25 of bug #6200)
+!! test
+Bug 15491: <ins>/<del> in blockquote (2)
+!! input
+<blockquote>Foo <del>bar</del> <ins>baz</ins> quux
+</blockquote>
+!! result
+<blockquote>Foo <del>bar</del> <ins>baz</ins> quux
+</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>&lt;</pre>
+!! result
+<pre>&lt;</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>
+&lt;nowiki&gt;
+</pre>
+<pre>
+
+</pre>
+<pre>&lt;nowiki&gt;Foo&lt;/nowiki&gt;</pre>
+
+!! end
+
+!! test
+<nowiki> and <pre> preference (first one wins)
+!! input
+<pre>
+<nowiki>
+</pre>
+</nowiki>
+</pre>
+
+<nowiki>
+<pre>
+<nowiki>
+</pre>
+</nowiki>
+</pre>
+
+!! result
+<pre>
+&lt;nowiki&gt;
+</pre>
+<p>&lt;/nowiki&gt;
+&lt;/pre&gt;
+</p><p>
+&lt;pre&gt;
+&lt;nowiki&gt;
+&lt;/pre&gt;
+
+&lt;/pre&gt;
+</p>
+!! end
+
+!! test
+</pre> inside nowiki
+!! input
+<nowiki></pre></nowiki>
+!! result
+<p>&lt;/pre&gt;
+</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
+
+# TODO / maybe: fix wt2wt for this
+!! test
+Parsoid: Don't paragraph-wrap fosterable content
+!! options
+parsoid=wt2html
+!! input
+{|
+<td></td>
+<td></td>
+
+
+
+|}
+!! result
+<table>
+
+<tbody>
+<tr>
+<td></td>
+
+<td></td></tr>
+
+
+
+</tbody></table>
+!! end
+
+!! test
+Parsoid: Don't paragraph-wrap fosterable content even if table syntax is unbalanced
+!! options
+parsoid=wt2html
+!! input
+{|
+<td>
+<td>
+</td>
+
+
+
+|}
+!! result
+<table>
+
+<tbody>
+<tr>
+<td></td>
+
+<td>
+</td></tr>
+
+
+
+</tbody></table>
+!! end
+
+
+#--------------------------------------------------------------------
+# Transclusion parameter whitespace stripping tests
+# Behavior is different for positional and named parameters
+#--------------------------------------------------------------------
+!! test
+Templates: Strip leading and trailing whitespace from named-param values
+!! input
+{{echo|1= a }}
+
+{{echo|1= {{echo|b}} }}
+
+{{echo| 1 =
+ c }}
+
+{{echo| 1 =
+* d
+}}
+!! result
+<p>a
+</p><p>b
+</p><p>c
+</p>
+<ul>
+<li> d
+</li>
+</ul>
+
+!! end
+
+!! test
+Templates: Don't strip whitespace from positional-param values
+!! input
+{{echo|a }}
+
+{{echo|{{echo|b}} }}
+
+{{echo| c
+}}
+
+{{echo| {{echo|d}}
+}}
+
+{{echo|
+ e}}
+
+{{echo|
+* f}}
+
+{{echo|
+ }}g
+!! result
+<p>a
+</p><p>b
+</p>
+<pre>c
+</pre>
+<p><br />
+</p>
+<pre>d
+</pre>
+<p><br />
+</p>
+<pre>e
+</pre>
+<p><br />
+</p>
+<ul>
+<li> f
+</li>
+</ul>
+<p><br />
+</p>
+<pre>g
+</pre>
+!! end
+
+!! test
+Templates: Handle empty comment-and-ws-only lines correctly
+!! input
+{{echo|foo
+<!--should be ignored-->
+ <!--should be ignored as well-->
+bar}}
+!! result
+<p>foo
+bar
+</p>
+!! end
+
+#--------------------------------------------------------------------
+# Transclusion parameter escaping tests
+#--------------------------------------------------------------------
+!! test
+Templates: Parsoid parameter escaping test 1
+!! options
+parsoid
+!! input
+{{echo|[foo]|{{echo|[bar]}}}}
+!! result
+<p about="#mwt1" typeof="mw:Transclusion"
+data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[foo]"},"2":{"wt":"{{echo|[bar]}}"}},"i":0}}]}'>[foo]</p>
+!! end
+
+!! test
+Parsoid: Pipes in external links in template parameter
+!! options
+parsoid
+!! input
+{{echo|[{{echo|http://example.com}} link]}}
+!! result
+<p><a rel="mw:ExtLink" href="http://example.com" about="#mwt31" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[{{echo|http://example.com}} link]"}},"i":0}}]}'>link</a></p>
+!! end
+
+!! test
+Parsoid: pipe in transclusion parameter
+!! options
+parsoid
+!! input
+{{echo|http://foo.com/a&#124;b}}
+!! result
+<p><a rel="mw:ExtLink" href="http://foo.com/a|b" about="#mwt1"
+typeof="mw:Transclusion"
+data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"http://foo.com/a&amp;#124;b"}},"i":0}}]}'>http://foo.com/a|b</a></p>
+!! end
+
+!! test
+Parsoid: Pipe in external link target and content in template parameter
+!! options
+parsoid=html2wt,wt2wt
+!! input
+{{echo|[http://foo.com/a&#124;b a&#124;b]}}
+!! result
+<p><a rel="mw:ExtLink" href="http://foo.com/a|b" about="#mwt1"
+typeof="mw:Transclusion"
+data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},
+"params":{"1":{"wt":"[http://foo.com/a|b a|b]"}},"i":0}}]}'>a|b</a></p>
+!! end
+
+!! test
+Templates: Dont escape already nowiki-escaped text in template parameters
+!! options
+parsoid=html2wt,wt2wt
+!! input
+{{echo|foo<nowiki>|</nowiki>bar}}
+{{echo|<nowiki>&lt;div&gt;</nowiki>}}
+{{echo|<nowiki></nowiki>}}
+!! result
+<p><span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo<nowiki>|</nowiki>bar"}},"i":0}}]}'}'>foo</span><span typeof="mw:Nowiki" about="#mwt1">|</span><span about="#mwt1">bar</span>
+<span typeof="mw:Transclusion mw:Nowiki" about="#mwt2" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<nowiki>&amp;lt;div&amp;gt;</nowiki>"}},"i":0}}]}'><span typeof="mw:Entity">&lt;</span>div<span typeof="mw:Entity">&gt;</span></span>
+<span typeof="mw:Transclusion mw:Nowiki" about="#mwt3" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<nowiki></nowiki>"}},"i":0}}]}'></span>
+</p>
+!! end
+
+## Bug 52824
+!! test
+Templates: '=' char in nested transclusions should not trigger nowiki escapes or conversion to named param
+!! options
+parsoid=html2wt,wt2wt
+!! input
+{{echo|{{echo|1=bar}}}}
+!! result
+<p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"{{echo|1=bar}}"}},"i":0}}]}'>bar</p>
+!! 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
+1d. Indent-Pre and Comments
+(Pre-handler currently cannot distinguish between comment/ws order and normalizes them to [comment,ws] order)
+!!input
+<!--a--> a
+
+ <!--b-->b
+!!result
+<pre>a
+</pre>
+<pre>b
+</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>
+ <blockquote> foo </blockquote>
+ <span> foo </span>
+!!result
+ <p> foo </p>
+ <div> foo </div>
+ <blockquote> foo </blockquote>
+<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>
+
+<blockquote>
+<pre>
+foo
+</pre>
+</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>
+<p> foo
+</p>
+</blockquote>
+<blockquote>
+<pre>
+foo
+</pre>
+</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
+
+!! test
+6. Pre-blocks should extend across lines with leading WS even when there is no wrappable content
+!! input
+ a
+
+ <!-- continue -->
+ b
+
+ c
+
+d
+!! result
+<pre>a
+
+b
+</pre>
+<pre>c
+
+</pre>
+<p>d
+</p>
+!! end
+
+!! test
+7a. Indent-pre and category links
+!! options
+parsoid=wt2html,wt2wt
+!! input
+ [[Category:foo]] <!-- No pre-wrapping -->
+{{echo| [[Category:foo]]}} <!-- No pre-wrapping -->
+!! result
+ <link rel="mw:WikiLink/Category" href="./Category:Foo"> <!-- No pre-wrapping -->
+<span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":" [[Category:foo]]"}},"i":0}}]}'> </span>
+<link rel="mw:WikiLink/Category" href="./Category:Foo" about="#mwt1"> <!-- No pre-wrapping -->
+!! end
+
+!! test
+7b. Indent-pre and category links
+!! options
+parsoid=wt2html,wt2wt
+!! input
+ [[Category:foo]] a
+ [[Category:foo]] {{echo|b}}
+!! result
+<pre>
+<link rel="mw:WikiLink/Category" href="./Category:Foo"> a
+
+<link rel="mw:WikiLink/Category" href="./Category:Foo"> <span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"b"}},"i":0}}]}'>b</span></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&#160;</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>&#160;</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&amp;action=edit&amp;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&#160;: 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&#160;</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&#160;</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
+
+# Bug 52473
+!! test
+Definition Lists: Hacky use to indent tables (WS-insensitive)
+!! options
+parsoid
+!! input
+: {|
+|a
+|}
+!! result
+<dl>
+<dd> <table><tr><td>a</td></tr></table> </dd>
+</dl>
+!! 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
+
+
+## The Parsoid team believes the following three test exposes a
+## bug in the PHP parser. (Parsoid team thinks the PHP parser is
+## wrong to close the <dl> after the <dt> containing the <ul>.)
+!! test
+Definition Lists: Mixed Lists: Test 1 (php)
+!! options
+php
+!! 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 1 (parsoid)
+!! options
+parsoid
+!! input
+:;* foo
+::* bar
+:; baz
+!! result
+<dl>
+<dd><dl>
+<dt><ul>
+<li> foo
+</li>
+</ul></dt>
+<dd><ul>
+<li> bar
+</li>
+</ul></dd>
+<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&#160;</dt>
+<dd>d2
+</dd>
+<dt>d3&#160;</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&#160;</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&#160;</dt>
+<dd>bar
+</dd>
+</dl>
+</li>
+</ol>
+</li>
+</ul>
+
+!! end
+
+# The Parsoid team disagrees with the PHP parser's seemingly-random
+# rules regarding dd/dt on the next two tests. Parsoid is more
+# consistent, and recognizes the shared nesting and keeps the
+# still-open tags around until the nesting is complete.
+
+!! test
+Definition Lists: Mixed Lists: Test 11 (php)
+!! options
+php
+!! input
+*#*#;*;;foo :bar
+*#*#;boo :baz
+!! result
+<ul>
+<li><ol>
+<li><ul>
+<li><ol>
+<li><dl>
+<dt>foo&#160;</dt>
+<dd><ul>
+<li><dl>
+<dt><dl>
+<dt>bar
+</dt>
+</dl>
+</dd>
+</dl>
+</li>
+</ul>
+</dd>
+</dl>
+<dl>
+<dt>boo&#160;</dt>
+<dd>baz
+</dd>
+</dl>
+</li>
+</ol>
+</li>
+</ul>
+</li>
+</ol>
+</li>
+</ul>
+
+!! end
+!! test
+Definition Lists: Mixed Lists: Test 11 (parsoid)
+!! options
+parsoid
+!! input
+*#*#;*;;foo :bar
+*#*#;boo :baz
+!! result
+<ul>
+<li>
+<ol>
+<li>
+<ul>
+<li>
+<ol>
+<li>
+<dl>
+<dt>
+<ul>
+<li>
+<dl>
+<dt>
+<dl>
+<dt>foo<span typeof="mw:Placeholder" data-parsoid='{"src":" "}'>&nbsp;</span></dt>
+<dd data-parsoid='{"stx":"row"}'>bar</dd>
+</dl></dt>
+</dl></li>
+</ul></dt>
+<dt>boo<span typeof="mw:Placeholder" data-parsoid='{"src":" "}'>&nbsp;</span></dt>
+<dd data-parsoid='{"stx":"row"}'>baz</dd>
+</dl></li>
+</ol></li>
+</ul></li>
+</ol></li>
+</ul>
+!! end
+
+
+!! test
+Definition Lists: Weird Ones: Test 1 (php)
+!! options
+php
+!! input
+*#;*::;; foo : bar (who uses this?)
+!! result
+<ul>
+<li><ol>
+<li><dl>
+<dt> foo&#160;</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
+!! test
+Definition Lists: Weird Ones: Test 1 (parsoid)
+!! options
+parsoid
+!! input
+*#;*::;; foo : bar (who uses this?)
+!! result
+<ul>
+<li>
+<ol>
+<li>
+<dl>
+<dt>
+<ul>
+<li>
+<dl>
+<dd>
+<dl>
+<dd>
+<dl>
+<dt>
+<dl>
+<dt> foo<span typeof="mw:Placeholder" data-parsoid='{"src":" "}'>&nbsp;</span></dt>
+<dd data-parsoid='{"stx":"row"}'> bar (who uses this?)</dd>
+</dl></dt>
+</dl></dd>
+</dl></dd>
+</dl></li>
+</ul></dt>
+</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
+External image (when not allowed)
+!! options
+wgAllowExternalImages=0
+!! input
+External image: http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png
+!! result
+<p>External image: <a rel="nofollow" class="external free" href="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png">http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png</a>
+</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 &amp; use: http://x&y
+!! result
+<p>Old &amp; use: <a rel="nofollow" class="external free" href="http://x&amp;y">http://x&amp;y</a>
+</p>
+!! end
+
+!! test
+External links: encoded ampersand
+!! input
+Old &amp; use: http://x&amp;y
+!! result
+<p>Old &amp; use: <a rel="nofollow" class="external free" href="http://x&amp;y">http://x&amp;y</a>
+</p>
+!! end
+
+!! test
+External links: encoded equals (bug 6102)
+!! input
+http://example.com/?foo&#61;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 &amp; use: [http://x&y]
+!! result
+<p>Old &amp; use: <a rel="nofollow" class="external autonumber" href="http://x&amp;y">[1]</a>
+</p>
+!! end
+
+!! test
+External links: [encoded ampersand]
+!! input
+Old &amp; use: [http://x&amp;y]
+!! result
+<p>Old &amp; use: <a rel="nofollow" class="external autonumber" href="http://x&amp;y">[1]</a>
+</p>
+!! end
+
+!! test
+External links: [encoded equals] (bug 6102)
+!! input
+[http://example.com/?foo&#61;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&zwnj;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://e‌xample.com -> [http://example.com|http://example.com]
+# [http://example.com|http://e‌xample.com] -> [http://example.com|http://e‌xample.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&zwnj;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>&lt;hello&gt;
+</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/">&lt;hello&gt; 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&amp;action=edit&amp;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)&amp;action=edit&amp;redlink=1" class="new" title="Museo Picasso (París) (page does not exist)">Museo Picasso</a>.</a>
+</p>
+!! end
+
+!! test
+External link with comments in link text
+!! input
+[http://www.google.com Google <!-- comment -->]
+!! result
+<p><a rel="nofollow" class="external text" href="http://www.google.com">Google </a>
+</p>
+!! end
+
+!! test
+URL-encoding in URL functions (single parameter)
+!! input
+{{localurl:Some page|amp=&}}
+!! result
+<p>/index.php?title=Some_page&amp;amp=&amp;
+</p>
+!! end
+
+!! test
+URL-encoding in URL functions (multiple parameters)
+!! input
+{{localurl:Some page|q=?&amp=&}}
+!! result
+<p>/index.php?title=Some_page&amp;q=?&amp;amp=&amp;
+</p>
+!! end
+
+!! test
+Brackets in urls
+!! input
+http://example.com/index.php?foozoid%5B%5D=bar
+
+http://example.com/index.php?foozoid&#x5B;&#x5D;=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
+
+!! test
+Parsoid: Percent encoding in external links
+!! options
+parsoid
+!! input
+[https://github.com/search?l=&q=ResourceLoader+%40wikimedia Search]
+!! result
+<p><a rel="mw:ExtLink"
+href="https://github.com/search?l=&amp;q=ResourceLoader+%40wikimedia">Search</a></p>
+!! end
+
+!! test
+Parsoid: use url link syntax for links where the content is equal the link
+target
+!! options
+parsoid
+!! input
+http://example.com
+!! result
+<p><a rel="mw:ExtLink" 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 (php)
+!! options
+php
+!! 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
+# Parsoid inserts an empty bold tag pair at the end of the line, that the PHP
+# parser strips. The wikitext contains just the first half of the bold
+# quote pair.
+!! test
+Unclosed and unmatched quotes (parsoid)
+!! options
+parsoid
+!! 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).<b></b>
+</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 minimum 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. (php)
+!! options
+php
+!! input
+{||}
+!! result
+!! end
+# Parsoid team replies: empty table tags are legal in HTML5
+!! test
+A table with no data. (parsoid)
+!! options
+parsoid
+!! input
+{||}
+!! result
+<table></table>
+!! 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 (php)
+!! options
+php
+!! input
+{|
+|+ caption
+|}
+!! result
+<table>
+<caption> caption
+</caption><tr><td></td></tr></table>
+
+!! end
+# Parsoid team replies: table with only a caption is legal in HTML5
+!! test
+A table with nothing but a caption (parsoid)
+!! options
+parsoid
+!! input
+{|
+|+ caption
+|}
+!! result
+<table><caption> caption</caption></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
+|-
+! &times; !! 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> &#215; </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
+| &alpha;
+|
+{| bgcolor=#ABCDEF border=2
+|nested
+|-
+|table
+|}
+|the original table again
+|}
+!! result
+<table border="1">
+<tr>
+<td> &#945;
+</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)"&gt;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}}
+| {{table_attribs}}
+|}
+!! result
+<table>
+<tr>
+<td style="color: red"> Foo
+</td>
+<td style="color: red"> Foo
+</td></tr></table>
+
+!! end
+
+!! test
+Template-generated table cell attributes and cell content (2)
+!! input
+{|
+|align=center {{table_attribs}}
+|}
+!! result
+<table>
+<tr>
+<td align="center" style="color: red"> Foo
+</td></tr></table>
+
+!! end
+
+!! test
+Template-generated table cell attributes and cell content (3)
+!! input
+{|
+|align=center {{table_cells}}
+|}
+!! result
+<table>
+<tr>
+<td align="center" style="color: red"> Foo </td>
+<td> Bar </td>
+<td> Baz
+</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
+
+!! test
+Table with empty line following the start tag
+!! input
+{|
+
+|-
+| foo
+|}
+!! result
+<table>
+
+
+<tr>
+<td> foo
+</td></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
+parsoid
+!! input
+{|
+| style=| hello
+|}
+!! result
+<table>
+<tbody>
+<tr>
+<td style=""> hello
+</td></tr></tbody></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
+
+!! test
+Wikitext table with double-line table cell
+!! input
+{|
+|a
+b
+|}
+!! result
+<table>
+<tr>
+<td>a
+<p>b
+</p>
+</td></tr></table>
+
+!! end
+
+!! test
+Table cell with a single comment
+!! input
+{|
+| <!-- c1 -->
+| a
+|}
+!! result
+<table>
+<tr>
+<td>
+</td>
+<td> a
+</td></tr></table>
+
+!! end
+
+# The expected HTML structure in this test is debatable. The PHP parser does
+# not parse this kind of table at all. The main focus for Parsoid is on
+# round-tripping, so this output is ok for now. TODO: revisit!
+!! test
+Wikitext table with html-syntax row (Parsoid)
+!! options
+parsoid
+!! input
+{|
+|-
+<td>foo</td>
+|}
+!! result
+<table>
+<tbody>
+<tr>
+<td>foo</td></tr></tbody></table>
+!! end
+
+!! test
+Implicit <td> after a |-
+(PHP parser relies on Tidy to add the missing <td> tags)
+!! options
+parsoid=wt2html,wt2wt
+!! input
+{|
+|-
+a
+|}
+!! result
+<table>
+<tr><td>a</td></tr>
+</table>
+!! end
+
+!! test
+Pres should be recognized in an explicit <td> context, but not in an implicit <td> context
+(PHP parser relies on Tidy to add the missing <td> tags)
+!! options
+parsoid=wt2html,wt2wt
+!! input
+{|
+|-
+|
+ a
+|-
+ b
+|}
+!! result
+<table>
+<tbody>
+<tr><td><pre>a</pre></td></tr>
+<tr><td> b</td></tr>
+</tbody>
+</table>
+!! end
+
+!! test
+Lists should be recognized in an implicit <td> context
+(PHP parser relies on Tidy to add the missing <td> tags)
+!! options
+parsoid=wt2html,wt2wt
+!! input
+{|
+|-
+*a
+|}
+!! result
+<table>
+<tr>
+<td><ul>
+<li>a</li>
+</ul></td>
+</tr>
+</table>
+!! end
+
+!! test
+Parsoid: Round-trip tables directly followed by content (bug 51219)
+!! options
+parsoid=wt2html,wt2wt
+!! input
+{|
+|foo
+|} bar
+
+{|
+|baz
+|}<b>quux</b>
+!! result
+<table><tbody>
+<tr>
+<td>foo</td></tr></tbody></table> bar
+<table>
+<tbody>
+<tr>
+<td>baz</td></tr></tbody></table><b>quux</b>
+!! end
+
+!! test
+Parsoid: Default to a newline after tables in new content (bug 51219)
+!! options
+parsoid=html2wt
+!! input
+{|
+|foo
+|}
+<nowiki> </nowiki>bar
+{|
+|baz
+|}
+'''quux'''
+!! result
+<table><tbody>
+<tr><td>foo</td></tr></tbody></table> bar
+<table><tbody>
+<tr><td>baz</td></tr></tbody></table><b>quux</b>
+!! 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
+Piped link with comment in link text
+!! input
+[[Main Page|The Main<!--front--> 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&amp;action=edit&amp;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&amp;action=edit&amp;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]]&quot;, [[Main Page]]&#97;
+!! result
+<p><a href="/wiki/Main_Page" title="Main Page">Main Page</a>&quot;, <a href="/wiki/Main_Page" title="Main Page">Main Page</a>&#97;
+</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&amp;action=edit&amp;redlink=1" class="new" title="Talk:Parser testing (page does not exist)">Talk:Parser testing</a>, <a href="/index.php?title=Meta:Disclaimers&amp;action=edit&amp;redlink=1" class="new" title="Meta:Disclaimers (page does not exist)">Meta:Disclaimers</a>
+</p>
+!! end
+
+!! article
+MemoryAlpha:AlphaTest
+!! text
+This is an article in the MemoryAlpha namespace
+(which shadows the memoryalpha interwiki link).
+!! endarticle
+
+!! test
+Namespace takes precedence over interwiki link (bug 51680)
+!! input
+[[MemoryAlpha:AlphaTest]]
+!! result
+<p><a href="/wiki/MemoryAlpha:AlphaTest" title="MemoryAlpha:AlphaTest">MemoryAlpha:AlphaTest</a>
+</p>
+!! end
+
+!! test
+Piped link to namespace
+!! input
+[[Meta:Disclaimers|The disclaimers]]
+!! result
+<p><a href="/index.php?title=Meta:Disclaimers&amp;action=edit&amp;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&amp;action=edit&amp;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&amp;action=edit&amp;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">#&lt;</a><a href="#.3E">#&gt;</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 an equals sign
+!! input
+[[Special:BookSources/isbn=4-00-026157-6]]
+!! result
+<p><a href="/wiki/Special:BookSources/isbn%3D4-00-026157-6" title="Special:BookSources/isbn=4-00-026157-6">Special:BookSources/isbn=4-00-026157-6</a>
+</p>
+!! end
+
+!! article
+Foo~bar
+!! text
+Just a test of an article title containing a tilde.
+!! endarticle
+
+# note that links containing signatures, like [[Foo~~~~]], are
+# massaged by the pre-save transform (PST) and so the tildes are never
+# seen by the parser.
+!! test
+Link containing a tilde
+!! input
+[[Foo~bar]]
+!! result
+<p><a href="/wiki/Foo%7Ebar" title="Foo~bar">Foo~bar</a>
+</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&amp;action=edit&amp;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&amp;action=edit&amp;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&amp;action=edit&amp;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&amp;wpDestFile=Denys_Savchenko_%27%27Pentecoste%27%27.jpg" class="new" title="File:Denys Savchenko &#39;&#39;Pentecoste&#39;&#39;.jpg">File:Denys Savchenko <i>Pentecoste</i>.jpg</a>
+</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&amp;action=edit&amp;redlink=1" class="new" title="''Pentecoste'' (page does not exist)">''Pentecoste''</a>
+</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&amp;action=edit&amp;redlink=1" class="new" title="''Pentecoste'' (page does not exist)">Pentecoste</a>
+</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&amp;action=edit&amp;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|&lt;]]
+[[File:Nonexistent|a<i>b</i>c]]
+!! result
+<p><a href="/index.php?title=Special:Upload&amp;wpDestFile=Nonexistent" class="new" title="File:Nonexistent">&lt;script&gt;&lt;/script&gt;</a>
+<a href="/index.php?title=Special:Upload&amp;wpDestFile=Nonexistent" class="new" title="File:Nonexistent">&lt;script&gt;&lt;/script&gt;</a>
+<a href="/index.php?title=Special:Upload&amp;wpDestFile=Nonexistent" class="new" title="File:Nonexistent">&lt;</a>
+<a href="/index.php?title=Special:Upload&amp;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&amp;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
+[[Bu&#103;462]] [[Bug462]]
+!! result
+<p><strong class="selflink">Bu&#103;462</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
+[[&nbsp; Main &nbsp; Page &nbsp;]]
+!! result
+<p><a href="/wiki/Main_Page" title="Main Page">&#160; Main &#160; Page &#160;</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&amp;action=edit&amp;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&amp;action=edit&amp;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&amp;action=edit&amp;redlink=1" class="new" title="Something (bet ele jaratılmag'an)">Something'nice</a>
+</p>
+!! end
+
+!! article
+Söfnuður
+!! text
+Test.
+!! endarticle
+
+!! test
+Internal link with is link prefix
+!! options
+language=is
+!! input
+Aðrir mótmælenda[[söfnuður|söfnuðir]] og
+!! result
+<p>Aðrir <a href="/wiki/S%C3%B6fnu%C3%B0ur" title="Söfnuður">mótmælendasöfnuðir</a> og
+</p>
+!! end
+
+!! article
+Mótmælendatrú
+!! text
+Test.
+!! endarticle
+
+!! test
+Internal link with is link trail and link prefix
+!! options
+language=is
+!! input
+[[mótmælendatrú|xxx]]ar
+[[mótmælendatrú]]ar
+mótmælenda[[söfnuður]]
+mótmælenda[[söfnuður|söfnuðir]]
+mótmælenda[[söfnuður|söfnuðir]]xxx
+!! result
+<p><a href="/wiki/M%C3%B3tm%C3%A6lendatr%C3%BA" title="Mótmælendatrú">xxxar</a>
+<a href="/wiki/M%C3%B3tm%C3%A6lendatr%C3%BA" title="Mótmælendatrú">mótmælendatrúar</a>
+<a href="/wiki/S%C3%B6fnu%C3%B0ur" title="Söfnuður">mótmælendasöfnuður</a>
+<a href="/wiki/S%C3%B6fnu%C3%B0ur" title="Söfnuður">mótmælendasöfnuðir</a>
+<a href="/wiki/S%C3%B6fnu%C3%B0ur" title="Söfnuður">mótmælendasöfnuðirxxx</a>
+</p>
+!! end
+
+!! test
+Parsoid link trail escaping
+!! options
+parsoid=html2wt,html2html
+!! input
+[[apple]]<nowiki/>s
+!! result
+<p><a rel="mw:WikiLink" href="Apple">apple</a>s</p>
+!! end
+
+!! test
+Parsoid link prefix escaping
+!! options
+language=is
+parsoid=html2wt,html2html
+!! input
+Aðrir mótmælenda<nowiki/>[[söfnuður]]
+!! result
+<p>Aðrir mótmælenda<a rel="mw:WikiLink" href="Söfnuður">söfnuður</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&amp;action=edit&amp;redlink=1" class="new" title="Foo (page does not exist)"> bar</a>
+</p><p><a href="/index.php?title=Foo&amp;action=edit&amp;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&#0355;a]]
+*[[Wikipedia:ro:Olteni&#355;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&#355;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&#355;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
+
+
+###
+### Interlanguage links
+### Language links (so that searching for '### language' matches..)
+###
+
+!! 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 &nbsp; should RT properly
+!! options
+language=ln
+!! input
+[[WW&nbsp;II]]
+!!result
+<p><a href="/index.php?title=WW_II&amp;action=edit&amp;redlink=1" class="new" title="WW II (lonkásá ezalí tɛ̂)">WW&#160;II</a>
+</p>
+!! end
+
+!! test
+Parsoid bug 53221: Wikilinks should be properly entity-escaped
+!! options
+parsoid=html2wt
+!! input
+He&amp;nbsp;llo [[Foo|He&amp;nbsp;llo]]
+
+He&amp;nbsp;llo [[He&amp;nbsp;llo]]
+!!result
+<p>He&amp;nbsp;llo <a href="Foo" rel="mw:WikiLink">He&amp;nbsp;llo</a></p>
+<p>He&amp;nbsp;llo <a href="He&amp;nbsp;llo" rel="mw:WikiLink">He&amp;nbsp;llo</a></p>
+!! end
+
+!! test
+Parsoid: handle constructor well
+!! options
+parsoid
+!! input
+[[constructor]]
+
+[[constructor:foo]]
+!! result
+<p data-parsoid="{&quot;dsr&quot;:[0,15,0,0]}"><a rel="mw:WikiLink" href="./Constructor" data-parsoid="{&quot;stx&quot;:&quot;simple&quot;,&quot;a&quot;:{&quot;href&quot;:&quot;./Constructor&quot;},&quot;sa&quot;:{&quot;href&quot;:&quot;constructor&quot;},&quot;dsr&quot;:[0,15,2,2]}">constructor</a></p>
+
+
+<p data-parsoid="{&quot;dsr&quot;:[17,36,0,0]}"><a rel="mw:WikiLink" href="./Foo" data-parsoid="{&quot;stx&quot;:&quot;simple&quot;,&quot;a&quot;:{&quot;href&quot;:&quot;./Foo&quot;},&quot;sa&quot;:{&quot;href&quot;:&quot;constructor:foo&quot;},&quot;dsr&quot;:[17,36,2,2]}">constructor:foo</a></p>
+!! end
+
+!! test
+Parsoid: recognize interlanguage links without a target page
+!! options
+parsoid
+!! input
+[[ko:]]
+!! result
+<p>
+<link rel="mw:WikiLink/Language" href="http://ko.wikipedia.org/wiki/"></p>
+!! end
+
+!! test
+Parsoid: recognize interwiki links without a target page
+!! options
+parsoid
+!! input
+[[:ko:]]
+!! result
+<p><a rel="mw:WikiLink/Interwiki" href="http://ko.wikipedia.org/wiki/">ko:</a></p>
+!! end
+
+###
+### Redirects, Parsoid-only
+###
+!! test
+Simple redirect to page
+!! options
+parsoid
+!! input
+#REDIRECT [[Main Page]]
+!! result
+<link rel="mw:PageProp/redirect" href="./Main_Page">
+!! end
+
+!! test
+Optional colon in #REDIRECT
+!! options
+# the colon is archaic syntax. we support it for wt2html, but we
+# don't care that it roundtrips back to the modern syntax.
+parsoid=wt2html,html2html
+!! input
+#REDIRECT:[[Main Page]]
+!! result
+<link rel="mw:PageProp/redirect" href="./Main_Page">
+!! end
+
+!! test
+Whitespace in #REDIRECT with optional colon
+!! options
+# the colon and gratuitous whitespace is archaic syntax. we support
+# it for wt2html, but we don't care that it roundtrips back to the
+# modern syntax (without extra whitespace)
+parsoid=wt2html,html2html
+!! input
+
+ #REDIRECT
+:
+[[Main Page]]
+!! result
+<link rel="mw:PageProp/redirect" href="./Main_Page">
+!! end
+
+!! test
+Piped link in #REDIRECT
+!! options
+# content after piped link is ignored. we support this syntax,
+# but don't care that the piped link is lost when we roundtrip this.
+parsoid=wt2html
+!! input
+#REDIRECT [[Main Page|bar]]
+!! result
+<link rel="mw:PageProp/redirect" href="./Main_Page">
+!! end
+
+!! test
+Redirect to category
+!! options
+parsoid=wt2html
+!! input
+#REDIRECT [[Category:Foo]]
+!! result
+<link rel="mw:PageProp/redirect" href="./Category:Foo"><link rel="mw:WikiLink/Category" href="./Category:Foo">
+!! end
+
+!! test
+Redirect to category with URL encoding
+!! options
+parsoid=wt2html
+!! input
+#REDIRECT [[Category%3AFoo]]
+!! result
+<link rel="mw:PageProp/redirect" href="./Category:Foo"><link rel="mw:WikiLink/Category" href="./Category:Foo">
+!! end
+
+!! test
+Redirect to category page
+!! options
+parsoid=wt2html,html2html
+!! input
+#REDIRECT [[:Category:Foo]]
+!! result
+<p><a rel="mw:WikiLink" href="Category:Foo">Category:Foo</a></p>
+!! end
+
+!! test
+Redirect to image page (1)
+!! options
+parsoid
+!! input
+#REDIRECT [[File:Wiki.png]]
+!! result
+<link rel="mw:PageProp/redirect" href="./File:Wiki.png">
+!! end
+
+!! test
+Redirect to image page (2)
+!! options
+parsoid
+!! input
+#REDIRECT [[Image:Wiki.png]]
+!! result
+<link rel="mw:PageProp/redirect" href="./File:Wiki.png">
+!! end
+
+!! test
+Redirect to language
+!! options
+parsoid
+!! input
+#REDIRECT [[en:File:Wiki.png]]
+!! result
+<link rel="mw:PageProp/redirect" href="File:Wiki.png">
+!! end
+
+!! test
+Redirect to interwiki
+!! options
+parsoid
+!! input
+#REDIRECT [[meatball:File:Wiki.png]]
+!! result
+<link rel="mw:PageProp/redirect" href="File:Wiki.png">
+!! end
+
+!! test
+Non-English #REDIRECT
+!! options
+parsoid
+language=is
+!! input
+#TILVÍSUN [[Main Page]]
+!! result
+<link rel="mw:PageProp/redirect" href="./Main_Page">
+!! 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
+!! options
+php
+!! input
+</br>
+!! result
+<p>&lt;/br&gt;
+</p>
+!! end
+
+# TODO: Fix html2html mode (bug 51055)!
+!! test
+Parsoid: Broken br tag recognition
+!! options
+parsoid=wt2html
+!! 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>&lt;div title /&gt;
+&lt;div title/&gt;
+</p>
+<div>
+<p>&lt;div title=bar /&gt;
+&lt;div title=bar/&gt;
+</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 collapse 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
+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="mw-headline" id="A_heading">A heading</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: A heading">edit</a><span class="mw-editsection-bracket">]</span></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
+
+!!test
+Single-comment whitespace lines dont break lists, and neither do multi-comment whitespace lines
+!!input
+*a
+<!--This line will NOT split the list-->
+*b
+ <!--This line will NOT split the list either-->
+*c
+ <!--foo--> <!----> <!--This line NOT split the list either-->
+*d
+!!result
+<ul>
+<li>a
+</li>
+<li>b
+</li>
+<li>c
+</li>
+<li>d
+</li>
+</ul>
+
+!!end
+
+!!test
+Replacing whitespace with tabs still doesn't break the list (gerrit 78327)
+!!input
+*a
+<!--This line will NOT split the list-->
+*b
+ <!--This line will NOT split the list either-->
+*c
+ <!--foo--> <!----> <!--This line NOT split the list
+ either-->
+*d
+!!result
+<ul>
+<li>a
+</li>
+<li>b
+</li>
+<li>c
+</li>
+<li>d
+</li>
+</ul>
+
+!!end
+
+!!test
+Test the li-hack
+(Cannot test this with PHP parser since it relies on Tidy for the hack)
+!!options
+parsoid=wt2html,wt2wt
+!!input
+* foo
+* <li>li-hack
+* {{echo|<li>templated li-hack}}
+* <!--foo--> <li> unsupported li-hack with preceding comments
+
+<ul>
+<li><li>not a li-hack
+</li>
+</ul>
+!!result
+<ul>
+<li> foo</li>
+<li>li-hack</li>
+<li about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<li>templated li-hack"}}}}]}'>templated li-hack</li>
+<li> <!--foo--> </li>
+<li> li-hack with preceding comments</li>
+</ul>
+
+<ul>
+<li></li>
+<li>not a li-hack
+</li>
+</ul>
+!!end
+
+!! test
+Parsoid: Make sure nested lists are serialized on their own line even if HTML contains no newlines
+!! options
+parsoid
+!! input
+# foo
+## bar
+* foo
+** bar
+: foo
+:: bar
+!! result
+<ol>
+<li> foo<ol>
+<li> bar</li>
+</ol></li>
+</ol><ul>
+<li> foo<ul>
+<li> bar</li>
+</ul></li>
+</ul><dl>
+<dd> foo<dl>
+<dd> bar</dd>
+</dl></dd>
+</dl>
+!! end
+
+!! test
+Parsoid: Test of whitespace serialization with Templated bullets
+!! options
+parsoid
+!! input
+* {{bullet}}
+!! result
+<ul>
+<li> </li><li about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"bullet","href":"./Template:Bullet"},"params":{},"i":0}}]}'> Bar</li>
+</ul>
+!! end
+
+# ------------------------------------------------------------------------
+# The next set of tests are about Parsoid's ability to handle badly nested
+# tags (parse, minimize scope of fixup, and roundtrip back)
+# ------------------------------------------------------------------------
+
+!! test
+Unbalanced closing block tags break a list
+(Parsoid-only since php parser generates broken html -- relies on Tidy to fix up)
+!! options
+parsoid
+!! 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
+(Parsoid-only since php parser generates broken html -- relies on Tidy to fix up)
+!! options
+parsoid
+!! 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
+(Parsoid-only since php parser generates broken html -- relies on Tidy to fix up)
+!! options
+parsoid
+!! 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
+Table with missing opening <tr> tag
+!! options
+parsoid=wt2html,wt2wt
+!! input
+<table>
+<td>foo</td>
+</tr>
+</table>
+!! result
+<table>
+<tr>
+<td>foo</td>
+</tr>
+</table>
+!! end
+
+###
+### Magic Words
+###
+
+# Note that the current date is hard-coded as
+# 1970-01-01T00:02:03Z (a Thursday)
+# when running parser tests. The timezone is also fixed to GMT, so
+# local date will be identical to current date.
+
+!! 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: {{CURRENTMONTH1}}
+!! input
+{{CURRENTMONTH1}}
+!! result
+<p>1
+</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: {{CURRENTHOUR}}
+!! input
+{{CURRENTHOUR}}
+!! result
+<p>00
+</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: {{CURRENTTIMESTAMP}}
+!! input
+{{CURRENTTIMESTAMP}}
+!! result
+<p>19700101000203
+</p>
+!! end
+
+!! test
+Magic Words LOCAL (UTC)
+!! input
+* {{LOCALMONTH}}
+* {{LOCALMONTH1}}
+* {{LOCALMONTHNAME}}
+* {{LOCALMONTHNAMEGEN}}
+* {{LOCALMONTHABBREV}}
+* {{LOCALDAY}}
+* {{LOCALDAY2}}
+* {{LOCALDAYNAME}}
+* {{LOCALYEAR}}
+* {{LOCALTIME}}
+* {{LOCALHOUR}}
+* {{LOCALWEEK}}
+* {{LOCALDOW}}
+* {{LOCALTIMESTAMP}}
+!! result
+<ul>
+<li> 01
+</li>
+<li> 1
+</li>
+<li> January
+</li>
+<li> January
+</li>
+<li> Jan
+</li>
+<li> 1
+</li>
+<li> 01
+</li>
+<li> Thursday
+</li>
+<li> 1970
+</li>
+<li> 00:02
+</li>
+<li> 00
+</li>
+<li> 1
+</li>
+<li> 4
+</li>
+<li> 19700101000203
+</li>
+</ul>
+
+!! 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: {{TALKSPACE}}
+!! options
+title=[[User:Ævar Arnfjörð Bjarmason]]
+!! input
+{{TALKSPACE}}
+!! result
+<p>User talk
+</p>
+!! end
+
+!! test
+Magic Word: {{TALKSPACE}}, same namespace
+!! options
+title=[[User talk:Ævar Arnfjörð Bjarmason]]
+!! input
+{{TALKSPACE}}
+!! result
+<p>User talk
+</p>
+!! end
+
+!! test
+Magic Word: {{TALKSPACE}}, main namespace
+!! options
+title=[[Parser Test]]
+!! input
+{{TALKSPACE}}
+!! result
+<p>Talk
+</p>
+!! end
+
+!! test
+Magic Word: {{TALKSPACEE}}
+!! options
+title=[[User:Ævar Arnfjörð Bjarmason]]
+!! input
+{{TALKSPACEE}}
+!! result
+<p>User_talk
+</p>
+!! end
+
+!! test
+Magic Word: {{SUBJECTSPACE}}
+!! options
+title=[[User talk:Ævar Arnfjörð Bjarmason]]
+!! input
+{{SUBJECTSPACE}}
+!! result
+<p>User
+</p>
+!! end
+
+!! test
+Magic Word: {{SUBJECTSPACE}}, same namespace
+!! options
+title=[[User:Ævar Arnfjörð Bjarmason]]
+!! input
+{{SUBJECTSPACE}}
+!! result
+<p>User
+</p>
+!! end
+
+!! test
+Magic Word: {{SUBJECTSPACE}}, main namespace
+!! options
+title=[[Parser Test]]
+!! input
+{{SUBJECTSPACE}}
+!! result
+
+!! end
+
+!! test
+Magic Word: {{SUBJECTSPACEE}}
+!! options
+title=[[User talk:Ævar Arnfjörð Bjarmason]]
+!! input
+{{SUBJECTSPACEE}}
+!! result
+<p>User
+</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: {{SUBPAGENAME}}
+!! options
+title=[[Ævar Arnfjörð Bjarmason/sub ö]] subpage
+!! input
+{{SUBPAGENAME}}
+!! result
+<p>sub ö
+</p>
+!! end
+
+!! test
+Magic Word: {{SUBPAGENAMEE}}
+!! options
+title=[[Ævar Arnfjörð Bjarmason/sub ö]] subpage
+!! input
+{{SUBPAGENAMEE}}
+!! result
+<p>sub_%C3%B6
+</p>
+!! end
+
+!! test
+Magic Word: {{ROOTPAGENAME}}
+!! options
+title=[[Ævar Arnfjörð Bjarmason/sub/sub2]] subpage
+!! input
+{{ROOTPAGENAME}}
+!! result
+<p>Ævar Arnfjörð Bjarmason
+</p>
+!! end
+
+!! test
+Magic Word: {{ROOTPAGENAMEE}}
+!! options
+title=[[Ævar Arnfjörð Bjarmason/sub/sub2]] subpage
+!! input
+{{ROOTPAGENAMEE}}
+!! result
+<p>%C3%86var_Arnfj%C3%B6r%C3%B0_Bjarmason
+</p>
+!! end
+
+!! test
+Magic Word: {{BASEPAGENAME}}
+!! options
+title=[[Ævar Arnfjörð Bjarmason/sub]] subpage
+!! input
+{{BASEPAGENAME}}
+!! result
+<p>Ævar Arnfjörð Bjarmason
+</p>
+!! end
+
+!! test
+Magic Word: {{BASEPAGENAMEE}}
+!! options
+title=[[Ævar Arnfjörð Bjarmason/sub]] subpage
+!! input
+{{BASEPAGENAMEE}}
+!! result
+<p>%C3%86var_Arnfj%C3%B6r%C3%B0_Bjarmason
+</p>
+!! end
+
+!! test
+Magic Word: {{TALKPAGENAME}}
+!! options
+title=[[User:Ævar Arnfjörð Bjarmason]]
+!! input
+{{TALKPAGENAME}}
+!! result
+<p>User talk:Ævar Arnfjörð Bjarmason
+</p>
+!! end
+
+!! test
+Magic Word: {{TALKPAGENAMEE}}
+!! options
+title=[[User:Ævar Arnfjörð Bjarmason]]
+!! input
+{{TALKPAGENAMEE}}
+!! result
+<p>User_talk:%C3%86var_Arnfj%C3%B6r%C3%B0_Bjarmason
+</p>
+!! end
+
+!! test
+Magic Word: {{SUBJECTPAGENAME}}
+!! options
+title=[[User talk:Ævar Arnfjörð Bjarmason]]
+!! input
+{{SUBJECTPAGENAME}}
+!! result
+<p>User:Ævar Arnfjörð Bjarmason
+</p>
+!! end
+
+!! test
+Magic Word: {{SUBJECTPAGENAMEE}}
+!! options
+title=[[User talk:Ævar Arnfjörð Bjarmason]]
+!! input
+{{SUBJECTPAGENAMEE}}
+!! result
+<p>User:%C3%86var_Arnfj%C3%B6r%C3%B0_Bjarmason
+</p>
+!! end
+
+!! test
+Magic Word: {{NUMBEROFFILES}}
+!! input
+{{NUMBEROFFILES}}
+!! result
+<p>4
+</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>&#39;foo &#38; bar &#61; baz&#39;</i>
+</p>
+!! end
+
+!! test
+Magic Word: {{PAGENAME}} with metacharacters (bug 26781)
+!! options
+title=[[*RFC 1234 http://example.com/]]
+!! input
+{{PAGENAME}}
+!! result
+<p>&#42;RFC&#32;1234 http&#58;//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>&#42;RFC_1234_http&#58;//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: {{STYLEPATH}}
+!! input
+{{STYLEPATH}}
+!! result
+<p>/skins
+</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
+Case-sensitive magic words, when cased differently, should just be template transclusions
+!! input
+{{CurrentMonth}}
+{{currentday}}
+{{cURreNTweEK}}
+{{currentHour}}
+!! result
+<p><a href="/index.php?title=Template:CurrentMonth&amp;action=edit&amp;redlink=1" class="new" title="Template:CurrentMonth (page does not exist)">Template:CurrentMonth</a>
+<a href="/index.php?title=Template:Currentday&amp;action=edit&amp;redlink=1" class="new" title="Template:Currentday (page does not exist)">Template:Currentday</a>
+<a href="/index.php?title=Template:CURreNTweEK&amp;action=edit&amp;redlink=1" class="new" title="Template:CURreNTweEK (page does not exist)">Template:CURreNTweEK</a>
+<a href="/index.php?title=Template:CurrentHour&amp;action=edit&amp;redlink=1" class="new" title="Template:CurrentHour (page does not exist)">Template:CurrentHour</a>
+</p>
+!! end
+
+!! test
+Case-insensitive magic words should still work with weird casing.
+!! input
+{{sErVeRNaMe}}
+{{LCFirst:AOEU}}
+{{ucFIRST:aoeu}}
+{{SERver}}
+!! result
+<p>example.org
+aOEU
+Aoeu
+<a rel="nofollow" class="external free" href="http://example.org">http://example.org</a>
+</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&amp;action=edit&amp;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&amp;action=edit&amp;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&amp;wpDestFile=Noimage.png" class="new" title="File:Noimage.png">File:Noimage.png</a> <div class="thumbcaption"><a href="/index.php?title=No_link&amp;action=edit&amp;redlink=1" class="new" title="No link (page does not exist)">link</a> <a href="/index.php?title=No_link&amp;action=edit&amp;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&amp;action=edit&amp;redlink=1" class="new" title="Foo (page does not exist)">foo</a>}}
+</p><p>{{<a href="/index.php?title=Foo&amp;action=edit&amp;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&lt;/includeonly&gt;
+</td>
+<td>d&lt;/includeonly&gt;&lt;/includeonly&gt;
+</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="mw-headline" id="Includeonly_section">Includeonly section</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Template:Includeonly_section&amp;action=edit&amp;section=T-1" title="Template:Includeonly section">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h2><span class="mw-headline" id="Section_T-1">Section T-1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Template:Includeonly_section&amp;action=edit&amp;section=T-2" title="Template:Includeonly section">edit</a><span class="mw-editsection-bracket">]</span></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="mw-headline" id="Section_1">Section 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></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
+
+# TODO: test with DOM fragment reuse!
+!! test
+Parsoid: DOM fragment reuse
+!! options
+parsoid=wt2wt,wt2html
+!! input
+a{{echo|b<table></table>c}}d
+
+a{{echo|b
+<table></table>
+c}}d
+
+{{echo|a
+
+<table></table>
+
+b}}
+!! result
+a<span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"b
+<table></table>c"}},"i":0}}]}'>b</span>
+<table about="#mwt1"></table><span about="#mwt1">c</span>d
+
+
+<p about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":["a",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"b\n<table></table>\nc"}},"i":0}},"d"]}'>ab</p><span about="#mwt2">
+</span>
+<table about="#mwt2"></table><span about="#mwt2">
+</span>
+<p about="#mwt2">cd</p>
+
+
+<p about="#mwt3" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"a\n\n<table></table>\n\nb"}},"i":0}}]}'>a</p><span about="#mwt3">
+
+</span>
+<table about="#mwt3"></table><span about="#mwt3">
+
+</span>
+<p about="#mwt3">b</p>
+!! end
+
+!! test
+Parsoid: Merge double tds (bug 50603)
+!! options
+parsoid
+!! input
+{|
+|{{echo|{{!}} foo}}
+|}
+!! result
+<table><tbody>
+<tr><td about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":["|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"{{!}} foo"}},"i":0}}]}'> foo</td></tr>
+</tbody></table>
+!! end
+
+!! test
+Parsoid: Merge double tds in nested transclusion content (bug 50603)
+!! options
+parsoid
+!! input
+{{echo|<div>}}
+{|
+|{{echo|{{!}} foo}}
+|}
+{{echo|</div>}}
+!! result
+<div about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<div>"}},"i":0}},"\n{|\n|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"{{!}} foo"}},"i":1}},"\n|}\n",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"</div>"}},"i":2}}]}'>
+<table><tbody>
+<tr><td data-mw='{"parts":["|"]}'> foo</td></tr>
+</tbody></table>
+</div>
+!! 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>
+<blockquote>{{echo|Foo}}</blockquote>
+!!result
+<div>Foo</div>
+<blockquote>Foo</blockquote>
+
+!!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: P-wrapping: 1d. Template preceded by comment-only line
+!!options
+parsoid
+!!input
+<!-- foo -->
+{{echo|Bar}}
+!!result
+<!-- foo -->
+
+<p about="#mwt223" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"Bar"}},"i":0}}]}'>Bar</p>
+!!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&amp;action=edit&amp;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&amp;action=edit&amp;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&amp;action=edit&amp;redlink=1" class="new" title="Foo (page does not exist)">bar</a>
+</p><p><a href="/index.php?title=Foobar&amp;action=edit&amp;redlink=1" class="new" title="Foobar (page does not exist)">Foobar</a>
+</p><p><a href="/index.php?title=Foobarbaz&amp;action=edit&amp;redlink=1" class="new" title="Foobarbaz (page does not exist)">Foobarbaz</a>
+</p><p><a href="/index.php?title=Foobar&amp;action=edit&amp;redlink=1" class="new" title="Foobar (page does not exist)">bar</a>
+</p><p><a href="/index.php?title=Foobar&amp;action=edit&amp;redlink=1" class="new" title="Foobar (page does not exist)">Foobar</a>
+</p><p><a href="/index.php?title=Foobar&amp;action=edit&amp;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&amp;action=edit&amp;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&amp;action=edit&amp;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&amp;action=edit&amp;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 Tag: 7. Generation of partial attribute key string
+!!input
+<div st{{echo|yle}}="color:red;">foo</div>
+!!result
+<div style="color:red;">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: HTML Tables: 5. Proper fostering of categories from inside
+!!options
+parsoid=wt2html,wt2wt
+!!input
+<table>[[Category:foo1]]<tr><td>foo</td></tr></table>
+<!--Two categories (Bug 50330)-->
+<table>[[Category:bar1]][[Category:bar2]]<tr><td>foo</td></tr></table>
+!!result
+<link rel="mw:WikiLink/Category" href="./Category:Foo1"><table><tbody><tr><td>foo</td></tr></tbody></table>
+<!--Two categories (Bug 50330)-->
+<link rel="mw:WikiLink/Category" href="./Category:Bar1"><link rel="mw:WikiLink/Category" href="./Category:Bar2"><table><tbody><tr><td>foo</td></tr></tbody></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&amp;action=edit&amp;redlink=1" class="new" title="Template:Nonexistent (page does not exist)">Template:Nonexistent</a>
+</li>
+<li>b <a href="/index.php?title=Template:Nonexistent&amp;action=edit&amp;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
+parsoid
+!!input
+{{echo_with_span|''a}}{{echo_with_span|b''c''d}}{{echo_with_span|''e}}
+!!result
+<p><span about="#mwt1" typeof="mw:Transclusion" data-mw="{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo_with_span&quot;,&quot;href&quot;:&quot;./Template:Echo_with_span&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;''a&quot;}},&quot;i&quot;:0}}]}"><i>a</i></span><i about="#mwt2" typeof="mw:Transclusion" data-mw="{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo_with_span&quot;,&quot;href&quot;:&quot;./Template:Echo_with_span&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;b''c''d&quot;}},&quot;i&quot;:0}},{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo_with_span&quot;,&quot;href&quot;:&quot;./Template:Echo_with_span&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;''e&quot;}},&quot;i&quot;:1}}]}"><span>b</span></i><span about="#mwt2">c</span><i about="#mwt2">d<span></span></i><span about="#mwt2">e</span></p>
+!!end
+
+!!test
+Templates: Ugly nesting: 3. Quotes opened/closed across templates (echo_with_div)
+(PHP parser generates misnested html; Parsoid html2wt mode adds newlines between {{echo}}s)
+!! options
+parsoid=wt2html,wt2wt
+!!input
+{{echo_with_div|''a}}{{echo_with_div|b''c''d}}{{echo_with_div|''e}}
+!!result
+<div about="#mwt1" typeof="mw:Transclusion" data-mw="{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo_with_div&quot;,&quot;href&quot;:&quot;./Template:Echo_with_div&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;''a&quot;}},&quot;i&quot;:0}}]}"><i>a</i></div>
+<div about="#mwt2" typeof="mw:Transclusion" data-mw="{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo_with_div&quot;,&quot;href&quot;:&quot;./Template:Echo_with_div&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;b''c''d&quot;}},&quot;i&quot;:0}}]}"><i>b</i>c<i>d</i></div>
+<div about="#mwt3" typeof="mw:Transclusion" data-mw="{&quot;parts&quot;:[{&quot;template&quot;:{&quot;target&quot;:{&quot;wt&quot;:&quot;echo_with_div&quot;,&quot;href&quot;:&quot;./Template:Echo_with_div&quot;},&quot;params&quot;:{&quot;1&quot;:{&quot;wt&quot;:&quot;''e&quot;}},&quot;i&quot;:0}}]}">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:Transclusion" data-mw='{"parts":["{|\n|",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo</table>"}},"i":0}},"\n|bar\n|}"]}'>
+
+<tbody>
+<tr>
+<td>foo</td></tr></tbody></table><span about="#mwt1">
+</span><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="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":["<table>\n <tr>\n <td>\n <table>\n <tr>\n <td>1. ",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo </table>"}},"i":0}},"</td>\n <td> bar </td>\n <td>2. ",{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"baz </table>"}},"i":1}},"</td>\n </tr>\n <tr>\n <td>abc</td>\n </tr>\n </table>\n </td>\n </tr>\n <tr>\n <td>xyz</td>\n </tr>\n</table>"]}'>
+ <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="#mwt2">
+ </span><span about="#mwt2">
+ </span><span about="#mwt2">
+ </span><span about="#mwt2">abc</span><span about="#mwt2">
+ </span><span about="#mwt2">
+ </span><span about="#mwt2">
+ </span><span about="#mwt2">
+ </span><span about="#mwt2">
+ </span><span about="#mwt2">
+ </span><span about="#mwt2">xyz</span><span about="#mwt2">
+ </span><span about="#mwt2">
+</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
+
+# Leading @ in this template definition works around a limitation
+# in parsoid's parserTests which otherwise strips the <span> from the
+# result (confusing it for a template wrapper)
+!! 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
+
+!! test
+Parsoid: Recognize nowiki with trailing space in tags
+!! options
+parsoid=wt2html
+!! input
+<nowiki ><div>[[foo]]</nowiki >
+
+a<nowiki / >b
+
+c<nowiki />d
+
+e<nowiki/ >f
+!! result
+<p><span typeof="mw:Nowiki">&lt;div&gt;[[foo]]</span></p>
+<p>ab</p>
+<p>cd</p>
+<p>ef</p>
+!! end
+
+!! test
+Parsoid: Recognize nowiki with odd capitalization
+!! options
+parsoid=wt2html
+!! input
+<noWikI ><div>[[foo]]</Nowiki >
+!! result
+<p><span typeof="mw:Nowiki">&lt;div&gt;[[foo]]</span></p>
+!! end
+
+
+!! test
+Parsoid: Escape nowiki with trailing space in tags
+!! options
+parsoid=html2wt
+!! input
+&lt;nowiki &gt; foo &lt;/nowiki &gt;
+
+a&lt;nowiki /&gt;b
+
+c&lt;nowiki/ &gt;d
+!! result
+<p>&lt;nowiki &gt; foo &lt/nowiki ></p>
+<p>a&lt;nowiki /&gt;b</p>
+<p>c&lt;nowiki/ &gt;d</p>
+!! end
+
+!! test
+Parsoid: Escape weird noWikI capitalizations
+!! options
+parsoid=html2wt
+!! input
+&lt;noWikI &gt; foo &lt;/NoWikI &gt;
+!! result
+<p>&lt;noWikI &gt; foo &lt/NoWikI ></p>
+!! 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:foobar nonexistent}}
+!! result
+Special:Foobar nonexistent
+!! 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:foobar nonexistent}}
+!! result
+Special:Foobar_nonexistent
+!! end
+
+###
+### Images
+###
+### For Parsoid-specific tests, see
+#### http://www.mediawiki.org/wiki/Parsoid/MediaWiki_DOM_spec#Images
+
+!! test
+Simple image (php)
+!! options
+php
+!! 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
+Simple image (parsoid)
+!! options
+parsoid=wt2html
+!! input
+[[Image:foobar.jpg]]
+!! result
+<p><span class="mw-default-size" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span>
+</p>
+!! end
+
+!! test
+Simple image (using File: namespace, now canonical) (php)
+!! options
+php
+!! 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
+Simple image (using File: namespace, now canonical) (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg]]
+!! result
+<p><span class="mw-default-size" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span>
+</p>
+!! end
+
+!! test
+Right-aligned image (php)
+!! options
+php
+!! 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
+Right-aligned image (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg|right]]
+!! result
+<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></figure>
+!! end
+
+!! test
+Image with caption (php)
+!! options
+php
+!! input
+[[File: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 caption (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg|right|Caption text]]
+!! result
+<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption>Caption text</figcaption></figure>
+!! end
+
+!! test
+Image with empty attribute (php)
+!! options
+php
+!! input
+[[File: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 (parsoid)
+!! options
+parsoid=wt2html
+!! input
+[[File:Foobar.jpg|right||Caption text]]
+!! result
+<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption>Caption text</figcaption></figure>
+!! end
+
+!! test
+Image with attributes from template (php)
+!! options
+php
+!! input
+[[File:Foobar.jpg|{{image_attribs}}]]
+!! 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 attributes from template (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg|{{image_attribs}}]]
+!! result
+<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption>Caption text</figcaption></figure>
+!! end
+
+!! test
+Image with link tails (php)
+!! options
+php
+!! input
+123[[File:Foobar.jpg]]456
+123[[File:Foobar.jpg|right]]456
+123[[File: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 link tails (parsoid)
+!! options
+parsoid
+!! input
+123[[File:Foobar.jpg]]456
+123[[File:Foobar.jpg|right]]456
+123[[File:Foobar.jpg|thumb]]456
+!! result
+<p>123<span class="mw-default-size" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span>456</p>
+123<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></figure>456
+123<figure class="mw-default-size" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" height="20" width="180"></a></figure>456
+!! end
+
+!! test
+Image with multiple captions -- only last one is accepted (php)
+!! options
+php
+!! input
+[[File: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 multiple captions -- only last one is accepted (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg|right|Caption1 - ignored|[[Caption2]] - ignored|Caption3 - accepted]]
+!! result
+<figure class="mw-default-size mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a><figcaption>Caption3 - accepted</figcaption></figure>
+!! end
+
+!! test
+Image with width attribute at different positions (php)
+!! options
+php
+!! input
+[[File:Foobar.jpg|200px|right|Caption]]
+[[File:Foobar.jpg|right|200px|Caption]]
+[[File: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 width attribute at different positions (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg|200px|right|Caption]]
+[[File:Foobar.jpg|right|200px|Caption]]
+[[File:Foobar.jpg|right|Caption|200px]]
+!! result
+<figure class="mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" height="23" width="200"></a><figcaption>Caption</figcaption></figure>
+<figure class="mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" height="23" width="200"></a><figcaption>Caption</figcaption></figure>
+<figure class="mw-halign-right" typeof="mw:Image"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" height="23" width="200"></a><figcaption>Caption</figcaption></figure>
+!! end
+
+!! test
+Image with link parameter, wiki target (php)
+!! options
+php
+!! input
+[[File:Foobar.jpg|link=Main Page]]
+!! result
+<p><a href="/wiki/Main_Page" title="Main 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, wiki target (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg|link=Main Page]]
+!! result
+<p><span class="mw-default-size" typeof="mw:Image"><a href="Main_Page"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span></p>
+!! end
+
+!! test
+Image with link parameter, URL target (php)
+!! options
+php
+!! input
+[[File: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
+
+# parsoid bug 49293 (part 1)
+!! test
+Image with link parameter, URL target (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg|link=http://example.com/]]
+!! result
+<p><span class="mw-default-size" typeof="mw:Image"><a href="http://example.com/"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span></p>
+!! end
+
+!! test
+Image with link parameter, protocol-less URL target (php)
+!! options
+php
+!! input
+[[File:Foobar.jpg|link=//example.com/]]
+!! result
+<p><a href="//example.com/" rel="nofollow"><img alt="Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
+</p>
+!! end
+
+# parsoid bug 49293 (part 2)
+!! test
+Image with link parameter, protocol-less URL target (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg|link=//example.com/]]
+!! result
+<p><span class="mw-default-size" typeof="mw:Image"><a href="//example.com/"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span></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 (php)
+!! options
+php
+!! input
+[[File: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 empty link parameter (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg|link=]]
+!! result
+<p><span class="mw-default-size" typeof="mw:Image"><span><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></span></span></p>
+!! end
+
+!! test
+Image with link parameter (wiki target) and unnamed parameter (php)
+!! options
+php
+!! input
+[[File:Foobar.jpg|link=Main Page|Title]]
+!! result
+<p><a href="/wiki/Main_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 (wiki target) and unnamed parameter (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg|link=Main Page|Title]]
+!! result
+<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"Title"}'><a href="Main_Page"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span></p>
+!! end
+
+!! test
+Image with link parameter (URL target) and unnamed parameter (php)
+!! options
+php
+!! input
+[[File: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
+Image with link parameter (URL target) and unnamed parameter (parsoid)
+!! options
+parsoid
+!! input
+[[File:Foobar.jpg|link=http://example.com/|Title]]
+!! result
+<p><span class="mw-default-size" typeof="mw:Image" data-mw='{"caption":"Title"}'><a href="http://example.com/"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="220" width="1941"></a></span></p>
+!! end
+
+!! test
+Thumbnail image with link parameter
+!! options
+php
+!! 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
+Manually-specified thumbnail image
+!! options
+php
+!! input
+[[Image:Foobar.jpg|thumb=Thumb.png|Title]]
+!! result
+<div class="thumb tright"><div class="thumbinner" style="width:137px;"><a href="/wiki/File:Foobar.jpg"><img alt="" src="http://example.com/images/e/ea/Thumb.png" width="135" height="135" class="thumbimage" /></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
+Manually-specified thumbnail image with explicit link to wiki page
+!! options
+php
+!! input
+[[Image:Foobar.jpg|thumb=Thumb.png|link=Main Page|Title]]
+!! result
+<div class="thumb tright"><div class="thumbinner" style="width:137px;"><a href="/wiki/Main_Page" title="Main Page"><img alt="" src="http://example.com/images/e/ea/Thumb.png" width="135" height="135" class="thumbimage" /></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
+Manually-specified thumbnail image with explicit link to url
+!! options
+php
+!! input
+[[Image:Foobar.jpg|thumb=Thumb.png|link=http://example.com|Title]]
+!! result
+<div class="thumb tright"><div class="thumbinner" style="width:137px;"><a href="http://example.com"><img alt="" src="http://example.com/images/e/ea/Thumb.png" width="135" height="135" class="thumbimage" /></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
+Manually-specified thumbnail image with explicit no link
+!! options
+php
+!! input
+[[Image:Foobar.jpg|thumb=Thumb.png|link=|Title]]
+!! result
+<div class="thumb tright"><div class="thumbinner" style="width:137px;"><img alt="" src="http://example.com/images/e/ea/Thumb.png" width="135" height="135" class="thumbimage" /> <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
+Manually-specified thumbnail image with explicit link and alt text
+!! options
+php
+!! input
+[[Image:Foobar.jpg|thumb=Thumb.png|link=Main Page|alt=alttext|Title]]
+!! result
+<div class="thumb tright"><div class="thumbinner" style="width:137px;"><a href="/wiki/Main_Page" title="Main Page"><img alt="alttext" src="http://example.com/images/e/ea/Thumb.png" width="135" height="135" class="thumbimage" /></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&amp;action=edit&amp;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&amp;action=edit&amp;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
+SVG thumbnails with no language set
+!! options
+!! input
+[[File:Foobar.svg|thumb|width=200]]
+!! result
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.svg" class="image"><img alt="" src="http://example.com/images/thumb/f/ff/Foobar.svg/180px-Foobar.svg.png" width="180" height="180" class="thumbimage" srcset="http://example.com/images/thumb/f/ff/Foobar.svg/270px-Foobar.svg.png 1.5x, http://example.com/images/thumb/f/ff/Foobar.svg/360px-Foobar.svg.png 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.svg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>width=200</div></div></div>
+
+!! end
+
+!! test
+SVG thumbnails with language de
+!! options
+!! input
+[[File:Foobar.svg|thumb|width=200|lang=de]]
+!! result
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=File:Foobar.svg&amp;lang=de" class="image"><img alt="" src="http://example.com/images/thumb/f/ff/Foobar.svg/langde-180px-Foobar.svg.png" width="180" height="180" class="thumbimage" srcset="http://example.com/images/thumb/f/ff/Foobar.svg/langde-270px-Foobar.svg.png 1.5x, http://example.com/images/thumb/f/ff/Foobar.svg/langde-360px-Foobar.svg.png 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.svg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>width=200</div></div></div>
+
+!! end
+
+!! test
+SVG thumbnails with invalid language code
+!! options
+!! input
+[[File:Foobar.svg|thumb|width=200|lang=invalid.language.code]]
+!! result
+<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.svg" class="image"><img alt="" src="http://example.com/images/thumb/f/ff/Foobar.svg/180px-Foobar.svg.png" width="180" height="180" class="thumbimage" srcset="http://example.com/images/thumb/f/ff/Foobar.svg/270px-Foobar.svg.png 1.5x, http://example.com/images/thumb/f/ff/Foobar.svg/360px-Foobar.svg.png 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.svg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>lang=invalid.language.code</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="&amp; &lt; &gt; &quot;"><img alt="&amp; &lt; &gt; &quot;" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
+</p>
+!! end
+
+!! test
+BUG 499: Alt text should have &#1234;, not &amp;1234;
+!! input
+[[Image:foobar.jpg|&#9792;]]
+!! 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&amp;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
+
+# Parsoid-specific testing for images
+# http://www.mediawiki.org/wiki/Parsoid/MediaWiki_DOM_spec#Images
+# Currently imperfect due to a flaw in the Parsoid testrunner
+# Work in progress
+# THESE TESTS SHOULD BE MOVED UP and merged with the php-specific
+# image tests.
+
+!! test
+Parsoid-specific image handling - simple image with size and middle alignment
+!! options
+parsoid
+!! input
+[[Image:Foobar.jpg|50px|middle]]
+!! result
+<p>
+<span class="mw-valign-middle" typeof="mw:Image">
+<a href="File:Foobar.jpg">
+<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" height="6" width="50">
+</a>
+</span>
+</p>
+!! end
+
+!! test
+Parsoid-specific image handling - simple image with both sizes, a baseline alignment, and a caption
+!! options
+parsoid
+!! input
+[[Image:Foobar.jpg|500x10px|baseline|caption]]
+!! result
+<p>
+<span class="mw-valign-baseline" typeof="mw:Image" data-mw="{&quot;caption&quot;:&quot;caption&quot;}">
+<a href="File:Foobar.jpg">
+<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/89px-Foobar.jpg" height="10" width="89">
+</a>
+</span>
+</p>
+!! end
+
+!! test
+Parsoid-specific image handling - simple image with border and size spec
+!! options
+parsoid
+!! input
+[[Image:Foobar.jpg|50px|border|caption]]
+!! result
+<p>
+<span class="mw-image-border" typeof="mw:Image" data-mw="{&quot;caption&quot;:&quot;caption&quot;}">
+<a href="File:Foobar.jpg">
+<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" height="6" width="50">
+</a>
+</span>
+</p>
+!! end
+
+!! test
+Parsoid-specific image handling - thumbnail with halign, valign, and caption
+!! options
+parsoid
+!! input
+[[Image:Foobar.jpg|thumb|left|baseline|caption content]]
+!! result
+<figure class="mw-default-size mw-halign-left mw-valign-baseline" typeof="mw:Image/Thumb">
+<a href="File:Foobar.jpg">
+<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" height="21" width="180" />
+</a>
+<figcaption>caption content</figcaption>
+</figure>
+!! end
+
+!! test
+Parsoid-specific image handling - thumbnail with specific size, halign, valign, and caption
+!! options
+parsoid
+!! input
+[[Image:Foobar.jpg|thumb|50x50px|right|middle|caption]]
+!! result
+<figure class="mw-halign-right mw-valign-middle" typeof="mw:Image/Thumb">
+<a href="File:Foobar.jpg">
+<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/50px-Foobar.jpg" height="6" width="50" />
+</a>
+<figcaption>caption</figcaption>
+</figure>
+!! end
+
+!! test
+Parsoid-specific image handling - framed image with specific size and caption
+!! options
+parsoid
+!! input
+[[Image:Foobar.jpg|500x50px|frame|caption]]
+!! result
+<figure typeof="mw:Image/Frame">
+<a href="File:Foobar.jpg">
+<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/442px-Foobar.jpg" height="50" width="442" />
+</a>
+<figcaption>caption</figcaption>
+</figure>
+!! end
+
+!! test
+Parsoid-specific image handling - framed image with specific size, halign, valign, and caption
+!! options
+parsoid
+!! input
+[[Image:Foobar.jpg|500x50px|frame|left|baseline|caption]]
+!! result
+<figure class="mw-halign-left mw-valign-baseline" typeof="mw:Image/Frame">
+<a href="File:Foobar.jpg">
+<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/442px-Foobar.jpg" height="50" width="442" />
+</a>
+<figcaption>caption</figcaption>
+</figure>
+!! end
+
+!! test
+Parsoid-specific image handling - frameless image with specific size, border, and caption
+!! options
+parsoid
+!! input
+[[Image:Foobar.jpg|frameless|500x50px|border|caption]]
+!! result
+<p>
+<span class="mw-image-border" typeof="mw:Image/Frameless" data-mw="{&quot;caption&quot;:&quot;caption&quot;}">
+<a href="File:Foobar.jpg">
+<img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/442px-Foobar.jpg" height="50" width="442" />
+</a>
+</p>
+!! end
+
+#!! test
+#Parsoid-specific image handling - simple image with a formatted caption
+#!! options
+#parsoid
+#!! input
+#[[Image:Foobar.jpg|<table><tr><td>a</td><td>b</td></tr><tr><td>c</td></tr></table>]]
+#!! result
+#<p>
+#<span typeof="mw:Image">
+#<a class="mw-default-size" href="Image:Foobar.jpg">
+#<img alt="Foobar.jpg" class="mw-default-size" src="http://example.com/images/3/3a/Foobar.jpg" height="220" width="1941">
+#</a>
+#<span>abc</span>
+#</span>
+#</p>
+
+
+###
+### 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
+
+# TODO: make this PHP-parser compatible!
+!! test
+Relative subpage noslash link
+!! options
+parsoid=wt2wt,wt2html,html2html
+subpage title=[[Subpage test/1/2/3/4]]
+!!input
+[[../../subpage/]]
+
+[[../../subpage]]
+!! result
+<p><a rel="mw:WikiLink" href="Subpage_test/1/2/subpage/">subpage</a></p>
+<p><a rel="mw:WikiLink" href="Subpage_test/1/2/subpage">Subpage_test/1/2/subpage</a></p>
+!! end
+
+# TODO: make this PHP-parser compatible!
+!! test
+Parsoid: dot-slash prefixed wikilinks
+!! options
+parsoid=wt2wt,wt2html,html2html
+!!input
+[[./foo]]
+
+[[././bar]]
+
+[[././baz/]]
+!! result
+<p><a rel="mw:WikiLink" href="./Foo">foo</a></p>
+<p><a rel="mw:WikiLink" href="./Bar">bar</a></p>
+<p><a rel="mw:WikiLink" href="./Baz/">baz/</a></p>
+!! end
+
+!! test
+Disabled subpages
+!! input
+[[/subpage]]
+!! result
+<p><a href="/index.php?title=/subpage&amp;action=edit&amp;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&amp;action=edit&amp;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
+
+!! test
+Parsoid: Serialize link to category page with colon escape
+!! options
+parsoid
+!! input
+
+[[:Category:Foo]]
+[[:Category:Foo|Bar]]
+!! result
+<p>
+<a rel="mw:WikiLink" href="Category:Foo">Category:Foo</a>
+<a rel="mw:WikiLink" href="Category:Foo">Bar</a>
+</p>
+!! end
+
+!! test
+Parsoid: Link prefix/suffixes aren't applied to category links
+!! options
+parsoid=wt2html,wt2wt,html2html
+language=is
+!! input
+x[[Category:Foo]]y
+!! result
+<p>x<link rel="mw:WikiLink/Category" href="Category:Foo">y</p>
+!! end
+
+!! test
+Parsoid: Serialize link to file page with colon escape
+!! options
+parsoid
+!! input
+
+[[:File:Foo.png]]
+[[:File:Foo.png|Bar]]
+!! result
+<p>
+<a rel="mw:WikiLink" href="File:Foo.png">File:Foo.png</a>
+<a rel="mw:WikiLink" href="File:Foo.png">Bar</a>
+</p>
+!! end
+
+!! test
+Parsoid: Serialize a genuine category link without colon escape
+!! options
+parsoid
+!! input
+[[Category:Foo]]
+[[Category:Foo|Bar]]
+!! result
+<link rel="mw:WikiLink/Category" href="Category:Foo">
+<link rel="mw:WikiLink/Category" href="Category:Foo#Bar">
+!! end
+
+###
+### Inter-language links
+###
+!! test
+Inter-language links
+!! options
+ill
+!! input
+[[es:Alimento]]
+[[fr:Nourriture]]
+[[zh:&#39135;&#21697;]]
+!! 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="mw-headline" id="Headline_1">Headline 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Headline 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<p>Some text
+</p>
+<h2><span class="mw-headline" id="Headline_2">Headline 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: Headline 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<p>More
+</p>
+<h3><span class="mw-headline" id="Smaller_headline">Smaller headline</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Smaller headline">edit</a><span class="mw-editsection-bracket">]</span></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
+<div id="toc" class="toc"><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>
+</div>
+
+<h2><span class="mw-headline" id="Headline_1">Headline 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Headline 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h3><span class="mw-headline" id="Subheadline_1">Subheadline 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: Subheadline 1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
+<h5><span class="mw-headline" id="Skipping_a_level">Skipping a level</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Skipping a level">edit</a><span class="mw-editsection-bracket">]</span></span></h5>
+<h6><span class="mw-headline" id="Skipping_a_level_2">Skipping a level</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Skipping a level">edit</a><span class="mw-editsection-bracket">]</span></span></h6>
+<h2><span class="mw-headline" id="Headline_2">Headline 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: Headline 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<p>Some text
+</p>
+<h3><span class="mw-headline" id="Another_headline">Another headline</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Another headline">edit</a><span class="mw-editsection-bracket">]</span></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
+<div id="toc" class="toc"><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>
+</div>
+
+<h1><span class="mw-headline" id="Level_1_Heading">Level 1 Heading</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Level 1 Heading">edit</a><span class="mw-editsection-bracket">]</span></span></h1>
+<h2><span class="mw-headline" id="Level_2_Heading">Level 2 Heading</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: Level 2 Heading">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h3><span class="mw-headline" id="Level_3_Heading">Level 3 Heading</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Level 3 Heading">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
+<h4><span class="mw-headline" id="Level_4_Heading">Level 4 Heading</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Level 4 Heading">edit</a><span class="mw-editsection-bracket">]</span></span></h4>
+<h5><span class="mw-headline" id="Level_5_Heading">Level 5 Heading</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: Level 5 Heading">edit</a><span class="mw-editsection-bracket">]</span></span></h5>
+<h6><span class="mw-headline" id="Level_6_Heading">Level 6 Heading</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Level 6 Heading">edit</a><span class="mw-editsection-bracket">]</span></span></h6>
+<h6><span class="mw-headline" id=".3D_Level_7_Heading.3D">= Level 7 Heading=</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=7" title="Edit section: = Level 7 Heading=">edit</a><span class="mw-editsection-bracket">]</span></span></h6>
+<h6><span class="mw-headline" id=".3D.3D_Level_8_Heading.3D.3D">== Level 8 Heading==</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=8" title="Edit section: == Level 8 Heading==">edit</a><span class="mw-editsection-bracket">]</span></span></h6>
+<h6><span class="mw-headline" id=".3D.3D.3D_Level_9_Heading.3D.3D.3D">=== Level 9 Heading===</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=9" title="Edit section: === Level 9 Heading===">edit</a><span class="mw-editsection-bracket">]</span></span></h6>
+<h6><span class="mw-headline" id=".3D.3D.3D.3D_Level_10_Heading.3D.3D.3D.3D">==== Level 10 Heading====</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=10" title="Edit section: ==== Level 10 Heading====">edit</a><span class="mw-editsection-bracket">]</span></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
+<div id="toc" class="toc"><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>
+</div>
+
+<h2><span class="mw-headline" id="title_1">title 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: title 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h3><span class="mw-headline" id="title_1.1">title 1.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: title 1.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
+<h4><span class="mw-headline" id="title_1.1.1">title 1.1.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: title 1.1.1">edit</a><span class="mw-editsection-bracket">]</span></span></h4>
+<h3><span class="mw-headline" id="title_1.2">title 1.2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: title 1.2">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
+<h2><span class="mw-headline" id="title_2">title 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: title 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h3><span class="mw-headline" id="title_2.1">title 2.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: title 2.1">edit</a><span class="mw-editsection-bracket">]</span></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
+<div id="toc" class="toc"><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>
+</div>
+
+<h2><span class="mw-headline" id="title_1">title 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: title 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h3><span class="mw-headline" id="title_1.1">title 1.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: title 1.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
+<h4><span class="mw-headline" id="title_1.1.1">title 1.1.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: title 1.1.1">edit</a><span class="mw-editsection-bracket">]</span></span></h4>
+<h3><span class="mw-headline" id="title_1.2">title 1.2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: title 1.2">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
+<h2><span class="mw-headline" id="title_2">title 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: title 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h3><span class="mw-headline" id="title_2.1">title 2.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: title 2.1">edit</a><span class="mw-editsection-bracket">]</span></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
+<div id="toc" class="toc"><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>
+</div>
+
+<h2><span class="mw-headline" id="Section_1">Section 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Section 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h3><span class="mw-headline" id="Section_1.1">Section 1.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: Section 1.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
+<h4><span class="mw-headline" id="Section_1.1.1">Section 1.1.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Section 1.1.1">edit</a><span class="mw-editsection-bracket">]</span></span></h4>
+<h4><span class="mw-headline" id="Section_1.1.1.1">Section 1.1.1.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Section 1.1.1.1">edit</a><span class="mw-editsection-bracket">]</span></span></h4>
+<h2><span class="mw-headline" id="Section_2">Section 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: Section 2">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+
+!! end
+
+
+!! test
+Resolving duplicate section names
+!! input
+== Foo bar ==
+== Foo bar ==
+!! result
+<h2><span class="mw-headline" id="Foo_bar">Foo bar</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Foo bar">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h2><span class="mw-headline" id="Foo_bar_2">Foo bar</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: Foo bar">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+
+!! end
+
+!! test
+Resolving duplicate section names with differing case (bug 10721)
+!! input
+== Foo bar ==
+== Foo Bar ==
+!! result
+<h2><span class="mw-headline" id="Foo_bar">Foo bar</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Foo bar">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h2><span class="mw-headline" id="Foo_Bar_2">Foo Bar</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: Foo Bar">edit</a><span class="mw-editsection-bracket">]</span></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="mw-headline" id="Section_0">Section 0</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Section 0">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h3><span class="mw-headline" id="Section_1">Section 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Template:Sections&amp;action=edit&amp;section=T-1" title="Template:Sections">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
+<h2><span class="mw-headline" id="Section_2">Section 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Template:Sections&amp;action=edit&amp;section=T-2" title="Template:Sections">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h2><span class="mw-headline" id="Section_4">Section 4</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: Section 4">edit</a><span class="mw-editsection-bracket">]</span></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="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><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Section with a link in it">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+
+!! end
+
+!! test
+TOC regression (bug 12077)
+!! input
+__TOC__
+== title 1 ==
+=== title 1.1 ===
+== title 2 ==
+!! result
+<div id="toc" class="toc"><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>
+</div>
+
+<h2><span class="mw-headline" id="title_1">title 1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: title 1">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<h3><span class="mw-headline" id="title_1.1">title 1.1</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: title 1.1">edit</a><span class="mw-editsection-bracket">]</span></span></h3>
+<h2><span class="mw-headline" id="title_2">title 2</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: title 2">edit</a><span class="mw-editsection-bracket">]</span></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="mw-headline" id=".3D">=</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: =">edit</a><span class="mw-editsection-bracket">]</span></span></h1>
+<p>The line above must have a trailing space!
+</p>
+<h1><span class="mw-headline" id=".3D_2">=</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: =">edit</a><span class="mw-editsection-bracket">]</span></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>
+<div id="toc" class="toc"><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 &gt; text</span></a></li>
+<li class="toclevel-1 tocsection-2"><a href="#text_.3C_text"><span class="tocnumber">2</span> <span class="toctext">text &lt; text</span></a></li>
+<li class="toclevel-1 tocsection-3"><a href="#text_.26_text"><span class="tocnumber">3</span> <span class="toctext">text &amp; 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>
+</div>
+
+<h2><span class="mw-headline" id="text_.3E_text">text &gt; text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: text > text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<p>section 1
+</p>
+<h2><span class="mw-headline" id="text_.3C_text">text &lt; text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: text &lt; text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<p>section 2
+</p>
+<h2><span class="mw-headline" id="text_.26_text">text &amp; text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: text &amp; text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<p>section 3
+</p>
+<h2><span class="mw-headline" id="text_.27_text">text ' text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: text ' text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<p>section 4
+</p>
+<h2><span class="mw-headline" id="text_.22_text">text " text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: text &quot; text">edit</a><span class="mw-editsection-bracket">]</span></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
+<div id="toc" class="toc"><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>
+</div>
+
+<h1><span class="mw-headline" id="foo.3D">foo=</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: foo=">edit</a><span class="mw-editsection-bracket">]</span></span></h1>
+<h1><span class="mw-headline" id=".3Dfoo">=foo</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=2" title="Edit section: =foo">edit</a><span class="mw-editsection-bracket">]</span></span></h1>
+<h1><span class="mw-headline" id="italic_heading.3D"><i>italic</i> heading=</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: italic heading=">edit</a><span class="mw-editsection-bracket">]</span></span></h1>
+<h1><span class="mw-headline" id=".3Ditalic_heading">=<i>italic</i> heading</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: =italic heading">edit</a><span class="mw-editsection-bracket">]</span></span></h1>
+
+!! end
+
+!! test
+HTML headers vs TOC (bug 23393)
+(__NOEDITSECTION__ for clearer output, doesn't matter here)
+!! input
+<h1>Header 1</h1>
+== Header 1.1 ==
+== Header 1.2 ==
+
+<h1>Header 2
+</h1>
+== Header 2.1 ==
+== Header 2.2 ==
+__NOEDITSECTION__
+!! result
+<div id="toc" class="toc"><div id="toctitle"><h2>Contents</h2></div>
+<ul>
+<li class="toclevel-1"><a href="#Header_1"><span class="tocnumber">1</span> <span class="toctext">Header 1</span></a>
+<ul>
+<li class="toclevel-2 tocsection-1"><a href="#Header_1.1"><span class="tocnumber">1.1</span> <span class="toctext">Header 1.1</span></a></li>
+<li class="toclevel-2 tocsection-2"><a href="#Header_1.2"><span class="tocnumber">1.2</span> <span class="toctext">Header 1.2</span></a></li>
+</ul>
+</li>
+<li class="toclevel-1"><a href="#Header_2"><span class="tocnumber">2</span> <span class="toctext">Header 2</span></a>
+<ul>
+<li class="toclevel-2 tocsection-3"><a href="#Header_2.1"><span class="tocnumber">2.1</span> <span class="toctext">Header 2.1</span></a></li>
+<li class="toclevel-2 tocsection-4"><a href="#Header_2.2"><span class="tocnumber">2.2</span> <span class="toctext">Header 2.2</span></a></li>
+</ul>
+</li>
+</ul>
+</div>
+
+<h1><span class="mw-headline" id="Header_1">Header 1</span></h1>
+<h2><span class="mw-headline" id="Header_1.1">Header 1.1</span></h2>
+<h2><span class="mw-headline" id="Header_1.2">Header 1.2</span></h2>
+<h1><span class="mw-headline" id="Header_2">Header 2</span></h1>
+<h2><span class="mw-headline" id="Header_2.1">Header 2.1</span></h2>
+<h2><span class="mw-headline" id="Header_2.2">Header 2.2</span></h2>
+
+!! 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
+parsoid
+!! input
+<div class =>HTML rocks</div>
+!! result
+<div class="">HTML rocks</div>
+
+!! end
+
+# The PHP parser escapes the opening brace to &#123; for some reason, so
+# disabled this test for it.
+!! test
+div with braces in attribute value
+!! options
+parsoid
+!! 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
+parsoid
+!! 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>&lt;khyô&gt;
+</p>
+!! end
+
+!! test
+Pseudo-tag with URL 'name' renders as url link
+!! input
+<http://example.com/>
+!! result
+<p>&lt;<a rel="nofollow" class="external free" href="http://example.com/">http://example.com/</a>&gt;
+</p>
+!! end
+
+!! test
+text with amp in the middle of nowhere
+!! input
+Remember AT&T?
+!!result
+<p>Remember AT&amp;T?
+</p>
+!! end
+
+!! test
+text with character entity: eacute
+!! input
+I always thought &eacute; was a cute letter.
+!! result
+<p>I always thought &#233; was a cute letter.
+</p>
+!! end
+
+!! test
+text with entity-escaped character entity-like string: eacute
+!! input
+I always thought &amp;eacute; was a cute letter.
+!! result
+<p>I always thought &amp;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 &amp;xacute; was a cute letter.
+</p>
+!! end
+
+
+###
+### Nesting tests (see bug 41545, 50604, 51081)
+###
+
+# This test case is fixed in Parsoid by domino 1.0.12. (bug 50604)
+# Note that html2wt is considerably more difficult if we use <b> in
+# the test case, instead of <big>
+!! test
+Ensure that HTML adoption agency algorithm is properly implemented.
+!! input
+<big>X<big>Y</big>Z</big>
+!! result
+<p><big>X<big>Y</big>Z</big>
+</p>
+!! end
+
+# This was bug 41545 in the PHP parser.
+!! test
+Nesting of <kbd>
+!! input
+<kbd>X<kbd>Y</kbd>Z</kbd>
+!! result
+<p><kbd>X<kbd>Y</kbd>Z</kbd>
+</p>
+!! end
+
+# The following cases were bug 51081 in the PHP parser.
+# Note that there are some other nestable tags (b, i, etc) which are
+# not covered; see bug 51081 for discussion.
+!! test
+Nesting of <em>
+!! input
+<em>X<em>Y</em>Z</em>
+!! result
+<p><em>X<em>Y</em>Z</em>
+</p>
+!! end
+
+!! test
+Nesting of <strong>
+!! input
+<strong>X<strong>Y</strong>Z</strong>
+!! result
+<p><strong>X<strong>Y</strong>Z</strong>
+</p>
+!! end
+
+!! test
+Nesting of <q>
+!! input
+<q>X<q>Y</q>Z</q>
+!! result
+<p><q>X<q>Y</q>Z</q>
+</p>
+!! end
+
+!! test
+Nesting of <ruby>
+!! input
+<ruby>X<ruby>Y</ruby>Z</ruby>
+!! result
+<p><ruby>X<ruby>Y</ruby>Z</ruby>
+</p>
+!! end
+
+!! test
+Nesting of <bdo>
+!! input
+<bdo>X<bdo>Y</bdo>Z</bdo>
+!! result
+<p><bdo>X<bdo>Y</bdo>Z</bdo>
+</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&lt;div style="display:none"&gt;" onmouseover="alert(document.cookie)" onfoo="&lt;/div&gt;</a>
+
+!! end
+
+!! test
+Media link to nonexistent file (bug 1702)
+!! input
+[[Media:No such.jpg]]
+!! result
+<p><a href="/index.php?title=Special:Upload&amp;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&amp;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&amp;action=edit&amp;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&amp;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
+[[&#xFB2E;]]
+[[&#x5d0;&#x5b7;]]
+[[&#x5d0;ַ]]
+[[א&#x5b7;]]
+[[אַ]]
+!! result
+<p><a href="/wiki/%D7%90%D6%B7" title="אַ">&#xfb2e;</a>
+<a href="/wiki/%D7%90%D6%B7" title="אַ">&#x5d0;&#x5b7;</a>
+<a href="/wiki/%D7%90%D6%B7" title="אַ">&#x5d0;ַ</a>
+<a href="/wiki/%D7%90%D6%B7" title="אַ">א&#x5b7;</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;">&lt;script&gt;alert(document.cookie)&lt;/script&gt;"&gt;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;">&lt;script&gt;alert(document.cookie)&lt;/script&gt;"&gt;Magic div</div>
+
+!! end
+
+!! test
+Bug 2304: HTML attribute safety (link)
+!! input
+<div title="[[Main Page]]"></div>
+!! result
+<div title="&#91;&#91;Main Page]]"></div>
+
+!! end
+
+!! test
+Bug 2304: HTML attribute safety (italics)
+!! input
+<div title="''foobar''"></div>
+!! result
+<div title="&#39;&#39;foobar&#39;&#39;"></div>
+
+!! end
+
+!! test
+Bug 2304: HTML attribute safety (bold)
+!! input
+<div title="'''foobar'''"></div>
+!! result
+<div title="&#39;&#39;&#39;foobar&#39;&#39;&#39;"></div>
+
+!! end
+
+
+!! test
+Bug 2304: HTML attribute safety (ISBN)
+!! input
+<div title="ISBN 1234567890"></div>
+!! result
+<div title="&#73;SBN 1234567890"></div>
+
+!! end
+
+!! test
+Bug 2304: HTML attribute safety (RFC)
+!! input
+<div title="RFC 1234"></div>
+!! result
+<div title="&#82;FC 1234"></div>
+
+!! end
+
+!! test
+Bug 2304: HTML attribute safety (PMID)
+!! input
+<div title="PMID 1234567890"></div>
+!! result
+<div title="&#80;MID 1234567890"></div>
+
+!! end
+
+!! test
+Bug 2304: HTML attribute safety (web link)
+!! input
+<div title="http://example.com/"></div>
+!! result
+<div title="http&#58;//example.com/"></div>
+
+!! end
+
+!! test
+Bug 2304: HTML attribute safety (named web link)
+!! input
+<div title="[http://example.com/ link]"></div>
+!! result
+<div title="&#91;http&#58;//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
+
+!! test
+Opera -o-link CSS
+!! input
+<div
+title="&#100;&#97;&#116;&#97;&#58;&#116;&#101;&#120;&#116;&#47;&#104;&#116;&#109;&#108;&#44;&#60;&#105;&#109;&#103;&#32;&#115;&#114;&#99;&#61;&#49;&#32;&#111;&#110;&#101;&#114;&#114;&#111;&#114;&#61;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;&#62;"
+style="-o-link:attr(title);-o-link-source:current">X</div>
+!! result
+<div title="data:text/html,&lt;img src=1 onerror=alert(1)&gt;" style="/* insecure input */">X</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(&#39;boo&#39;))">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(&#39;boo4&#39;))">evil4</div>
+
+!! end
+
+!! test
+CSS safety test: vertical tab
+!! input
+<p style="font-size: 100px; background-image:url\b(https://www.google.com/images/srpr/logo6w.png)">A</p>
+!! result
+<p style="/* invalid control char */">A</p>
+
+!! end
+
+!! test
+MSIE CSS safety test: Fullwidth
+!! input
+<p style="font-size: 100px; color: expression((title='XSSed'),'red')">A</p>
+<div style="top:EXPRESSION(alert())">B</div>
+!! result
+<p style="/* insecure input */">A</p>
+<div style="/* insecure input */">B</div>
+
+!! end
+
+!! test
+MSIE CSS safety test: IPA extensions
+!! input
+<div style="background-image:uʀʟ(javascript:alert())">A</div>
+<p style="font-size: 100px; color: expʀessɪoɴ((title='XSSed'),'red')">B</p>
+!! result
+<div style="/* insecure input */">A</div>
+<p style="/* insecure input */">B</p>
+
+!! end
+
+!! test
+MSIE CSS safety test: sup/sub script
+!! input
+<div style="background-image:url⁽javascript:alert())">A</div>
+<div style="background-image:url₍javascript:alert())">B</div>
+<p style="font-size: 100px; color: expressioⁿ((title='XSSed'),'red')">C</p>
+!! result
+<div style="/* insecure input */">A</div>
+<div style="/* insecure input */">B</div>
+<p style="/* insecure input */">C</p>
+
+!! end
+
+!! test
+MSIE CSS safety test: Repetition markers
+!! input
+<p style="font-size: 100px; color: expres〱ion((title='XSSed'),'red')">A</p>
+<p style="font-size: 100px; color: expresゝion((title='XSSed'),'red')">B</p>
+<p style="font-size: 100px; color: expresーion((title='XSSed'),'red')">C</p>
+<p style="font-size: 100px; color: expresヽion((title='XSSed'),'red')">D</p>
+<p style="font-size: 100px; color: expresﹽion((title='XSSed'),'red')">E</p>
+<p style="font-size: 100px; color: expresﹼion((title='XSSed'),'red')">F</p>
+<p style="font-size: 100px; color: expresーion((title='XSSed'),'red')">G</p>
+!! result
+<p style="/* insecure input */">A</p>
+<p style="/* insecure input */">B</p>
+<p style="/* insecure input */">C</p>
+<p style="/* insecure input */">D</p>
+<p style="/* insecure input */">E</p>
+<p style="/* insecure input */">F</p>
+<p style="/* insecure input */">G</p>
+
+!! 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\&#10;rl(test.jpg);"></div>
+!! result
+<div style="/* insecure input */"></div>
+
+!! end
+
+!! test
+CSS line continuation 2
+!! input
+<div style="background-image: u\&#13;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: &#10;#00FF00">-</div>
+!! result
+<div style="background: &#10;#00FF00">-</div>
+
+!! end
+
+###
+### Parser hooks (see tests/parser/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>&lt;/tag&gt;
+
+!! 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
+&lt;/tag&gt;
+</p>
+!! end
+
+###
+### (see tests/parser/parserTestsParserHook.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>&lt;/s&gt;
+</p>
+!! end
+
+!! test
+Sanitizer: Closing of closed but not open table tags
+!! input
+Table not started</td></tr></table>
+!! result
+<p>Table not started&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
+</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" />
+ &lt;meta http-equiv="refresh" content="5"&gt;
+ <meta itemprop="hello" content="5" />
+</p>
+ <link itemprop="hello" href="http&#58;//example.org" />
+ &lt;link rel="stylesheet" href="<a rel="nofollow" class="external free" href="http://example.org">http://example.org</a>"&gt;
+ <link itemprop="hello" href="http&#58;//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>&lt;font id="bug" /&gt;Centered text</center>
+<div>&lt;font id="bug2" /&gt;In div text</div>
+
+!! end
+
+#
+#
+#
+
+!! test
+Punctuation: nbsp before exclamation
+!! input
+C'est grave !
+!! result
+<p>C'est grave&#160;!
+</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>
+<li>One
+<li>Two:
+<ul>
+<li>Sub-one
+<li>Sub-two
+</ul>
+</ul>
+!! result
+<ul>
+<li>One
+</li>
+<li>Two:
+<ul>
+<li>Sub-one
+</li>
+<li>Sub-two
+</li>
+</ul>
+</li>
+</ul>
+
+!! end
+
+!! test
+HTML nested ordered list, closed tags (bug 5497)
+!! input
+<ol>
+<li>One</li>
+<li>Two:
+<ol>
+<li>Sub-one</li>
+<li>Sub-two</li>
+</ol>
+</li>
+</ol>
+!! result
+<ol>
+<li>One</li>
+<li>Two:
+<ol>
+<li>Sub-one</li>
+<li>Sub-two</li>
+</ol>
+</li>
+</ol>
+
+!! end
+
+!! test
+HTML nested ordered list, open tags (bug 5497)
+!! options
+disabled
+!! input
+<ol>
+<li>One
+<li>Two:
+<ol>
+<li>Sub-one
+<li>Sub-two
+</ol>
+</ol>
+!! result
+<ol>
+<li>One
+</li>
+<li>Two:
+<ol>
+<li>Sub-one
+</li>
+<li>Sub-two
+</li>
+</ol>
+</li>
+</ol>
+
+!! end
+
+!! test
+HTML ordered list item with parameters oddity
+!! input
+<ol><li id="fragment">One</li>
+</ol>
+!! result
+<ol><li id="fragment">One</li>
+</ol>
+
+!! end
+
+!!test
+bug 5918: autonumbering
+!! input
+[http://first/] [http://second] [ftp://ftp]
+
+ftp://inlineftp
+
+[mailto:enclosed@mail.tld With target]
+
+[mailto:enclosed@mail.tld]
+
+mailto:inline@mail.tld
+!! result
+<p><a rel="nofollow" class="external autonumber" href="http://first/">[1]</a> <a rel="nofollow" class="external autonumber" href="http://second">[2]</a> <a rel="nofollow" class="external autonumber" href="ftp://ftp">[3]</a>
+</p><p><a rel="nofollow" class="external free" href="ftp://inlineftp">ftp://inlineftp</a>
+</p><p><a rel="nofollow" class="external text" href="mailto:enclosed@mail.tld">With target</a>
+</p><p><a rel="nofollow" class="external autonumber" href="mailto:enclosed@mail.tld">[4]</a>
+</p><p><a rel="nofollow" class="external free" href="mailto:inline@mail.tld">mailto:inline@mail.tld</a>
+</p>
+!! end
+
+
+#
+# Security and HTML correctness
+# From Nick Jenkins' fuzz testing
+#
+
+!! test
+Fuzz testing: Parser13
+!! input
+{|
+| http://a|
+!! result
+<table>
+<tr>
+<td>
+</td>
+</tr>
+</table>
+
+!! end
+
+!! test
+Fuzz testing: Parser14
+!! input
+== onmouseover= ==
+http://__TOC__
+!! result
+<h2><span class="mw-headline" id="onmouseover.3D">onmouseover=</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: onmouseover=">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+http://<div id="toc" class="toc"><div id="toctitle"><h2>Contents</h2></div>
+<ul>
+<li class="toclevel-1 tocsection-1"><a href="#onmouseover.3D"><span class="tocnumber">1</span> <span class="toctext">onmouseover=</span></a></li>
+</ul>
+</div>
+
+
+!! end
+
+!! test
+Fuzz testing: Parser14-table
+!! input
+==a==
+{| STYLE=__TOC__
+!! result
+<h2><span class="mw-headline" id="a">a</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: a">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
+<table style="&#95;_TOC&#95;_">
+<tr><td></td></tr>
+</table>
+
+!! end
+
+# Known to produce bogus xml (extra </td>)
+!! test
+Fuzz testing: Parser16
+!! options
+noxml
+!! input
+{|
+!https://||||||
+!! result
+<table>
+<tr>
+<th>https://</th>
+<th></th>
+<th></th>
+<th>
+</td>
+</tr>
+</table>
+
+!! end
+
+!! test
+Fuzz testing: Parser21
+!! input
+{|
+! irc://{{ftp://a" onmouseover="alert('hello world');"
+|
+!! result
+<table>
+<tr>
+<th> <a rel="nofollow" class="external free" href="irc://{{ftp://a">irc://{{ftp://a</a>" onmouseover="alert('hello world');"
+</th>
+<td>
+</td>
+</tr>
+</table>
+
+!! end
+
+!! test
+Fuzz testing: Parser22
+!! input
+http://===r:::https://b
+
+{|
+!!result
+<p><a rel="nofollow" class="external free" href="http://===r:::https://b">http://===r:::https://b</a>
+</p>
+<table>
+<tr><td></td></tr>
+</table>
+
+!! end
+
+# Known to produce bad XML for now
+!! test
+Fuzz testing: Parser24
+!! options
+noxml
+!! input
+{|
+{{{|
+<u CLASS=
+| {{{{SSSll!!!!!!!VVVV)]]][[Special:*xxxxxxx--><noinclude>}}}} >
+<br style="onmouseover='alert(document.cookie);' " />
+
+MOVE YOUR MOUSE CURSOR OVER THIS TEXT
+|
+!! result
+<table>
+{{{|
+<u class="&#124;">}}}} &gt;
+<br style="onmouseover=&#39;alert(document.cookie);&#39;" />
+
+MOVE YOUR MOUSE CURSOR OVER THIS TEXT
+<tr>
+<td></u>
+</td>
+</tr>
+</table>
+
+!! end
+
+# Note: the current result listed for this is not what the original one was,
+# but the original bug was JavaScript injection, which is fixed in any case.
+# It's not clear that the original result listed was any more correct than the
+# current one. Original result:
+# <p>{{{|
+# </p>
+# <li class="&#124;&#124;">
+# }}}blah" onmouseover="alert('hello world');" align="left"<b>MOVE MOUSE CURSOR OVER HERE</b>
+!!test
+Fuzz testing: Parser25 (bug 6055)
+!! input
+{{{
+|
+<LI CLASS=||
+ >
+}}}blah" onmouseover="alert('hello world');" align="left"'''MOVE MOUSE CURSOR OVER HERE
+!! result
+<p>&lt;LI CLASS=blah" onmouseover="alert('hello world');" align="left"<b>MOVE MOUSE CURSOR OVER HERE</b>
+</p>
+!! end
+
+!!test
+Fuzz testing: URL adjacent extension (with space, clean)
+!! options
+!! input
+http://example.com <nowiki>junk</nowiki>
+!! result
+<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a> junk
+</p>
+!!end
+
+!!test
+Fuzz testing: URL adjacent extension (no space, dirty; nowiki)
+!! options
+!! input
+http://example.com<nowiki>junk</nowiki>
+!! result
+<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>junk
+</p>
+!!end
+
+!!test
+Fuzz testing: URL adjacent extension (no space, dirty; pre)
+!! options
+!! input
+http://example.com<pre>junk</pre>
+!! result
+<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a><pre>junk</pre>
+
+!!end
+
+!!test
+Fuzz testing: image with bogus manual thumbnail
+!!input
+[[Image:foobar.jpg|thumbnail= ]]
+!!result
+<div class="thumb tright"><div class="thumbinner" style="width:182px;">Error creating thumbnail: <div class="thumbcaption"></div></div></div>
+
+!!end
+
+!! test
+Fuzz testing: encoded newline in generated HTML replacements (bug 6577)
+!! input
+<pre dir="&#10;"></pre>
+!! result
+<pre dir="&#10;"></pre>
+
+!! end
+
+!! test
+Parsing optional HTML elements (Bug 6171)
+!! options
+!! input
+<table>
+ <tr>
+ <td> Some tabular data</td>
+ <td> More tabular data ...
+ <td> And yet som tabular data</td>
+ </tr>
+</table>
+!! result
+<table>
+ <tr>
+ <td> Some tabular data</td>
+ <td> More tabular data ...
+ </td><td> And yet som tabular data</td>
+ </tr>
+</table>
+
+!! end
+
+!! test
+Correct handling of <td>, <tr> (Bug 6171)
+!! options
+!! input
+<table>
+ <tr>
+ <td> Some tabular data</td>
+ <td> More tabular data ...</td>
+ <td> And yet som tabular data</td>
+ </tr>
+</table>
+!! result
+<table>
+ <tr>
+ <td> Some tabular data</td>
+ <td> More tabular data ...</td>
+ <td> And yet som tabular data</td>
+ </tr>
+</table>
+
+!! end
+
+
+!! test
+Parsing crashing regression (fr:JavaScript)
+!! input
+</body></x>
+!! result
+<p>&lt;/body&gt;&lt;/x&gt;
+</p>
+!! end
+
+!! test
+Inline wiki vs wiki block nesting
+!! input
+'''Bold paragraph
+
+New wiki paragraph
+!! result
+<p><b>Bold paragraph</b>
+</p><p>New wiki paragraph
+</p>
+!! end
+
+!! test
+Inline HTML vs wiki block nesting
+!! options
+disabled
+!! input
+<b>Bold paragraph
+
+New wiki paragraph
+!! result
+<p><b>Bold paragraph</b>
+</p><p>New wiki paragraph
+</p>
+!! end
+
+# Original result was this:
+# <p><b>bold</b><b>bold<i>bolditalics</i></b>
+# </p>
+# While that might be marginally more intuitive, maybe, the six-apostrophe
+# construct is clearly pathological and the result stated here (which is what
+# the parser actually does) is about as reasonable as anything.
+!!test
+Mixing markup for italics and bold
+!! options
+!! input
+'''bold''''''bold''bolditalics'''''
+!! result
+<p>'<i>bold'</i><b>bold<i>bolditalics</i></b>
+</p>
+!! end
+
+
+!! article
+Xyzzyx
+!! text
+Article for special page transclusion test
+!! endarticle
+
+!! test
+Special page transclusion
+!! options
+!! input
+{{Special:Prefixindex/Xyzzyx}}
+!! result
+<table id="mw-prefixindex-list-table"><tr><td><a href="/wiki/Xyzzyx" title="Xyzzyx">Xyzzyx</a></td></tr></table>
+
+!! end
+
+!! test
+Special page transclusion twice (bug 5021)
+!! options
+!! input
+{{Special:Prefixindex/Xyzzyx}}
+{{Special:Prefixindex/Xyzzyx}}
+!! result
+<table id="mw-prefixindex-list-table"><tr><td><a href="/wiki/Xyzzyx" title="Xyzzyx">Xyzzyx</a></td></tr></table>
+<table id="mw-prefixindex-list-table"><tr><td><a href="/wiki/Xyzzyx" title="Xyzzyx">Xyzzyx</a></td></tr></table>
+
+!! end
+
+!! test
+Transclusion of default MediaWiki message
+!! input
+{{MediaWiki:Mainpage}}
+!!result
+<p>Main Page
+</p>
+!! end
+
+!! test
+Transclusion of nonexistent MediaWiki message
+!! input
+{{MediaWiki:Mainpagexxx}}
+!!result
+<p><a href="/index.php?title=MediaWiki:Mainpagexxx&amp;action=edit&amp;redlink=1" class="new" title="MediaWiki:Mainpagexxx (page does not exist)">MediaWiki:Mainpagexxx</a>
+</p>
+!! end
+
+!! test
+Transclusion of MediaWiki message with underscore
+!! input
+{{MediaWiki:history_short}}
+!! result
+<p>History
+</p>
+!! end
+
+!! test
+Transclusion of MediaWiki message with space
+!! input
+{{MediaWiki:history short}}
+!! result
+<p>History
+</p>
+!! end
+
+!! test
+Invalid header with following text
+!! input
+= x = y
+!! result
+<p>= x = y
+</p>
+!! end
+
+
+!! test
+Section extraction test (section 0)
+!! options
+section=0
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+start
+!! end
+
+!! test
+Section extraction test (section 1)
+!! options
+section=1
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+==a==
+===aa===
+====aaa====
+!! end
+
+!! test
+Section extraction test (section 2)
+!! options
+section=2
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+===aa===
+====aaa====
+!! end
+
+!! test
+Section extraction test (section 3)
+!! options
+section=3
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+====aaa====
+!! end
+
+!! test
+Section extraction test (section 4)
+!! options
+section=4
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+!! end
+
+!! test
+Section extraction test (section 5)
+!! options
+section=5
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+===ba===
+!! end
+
+!! test
+Section extraction test (section 6)
+!! options
+section=6
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+===bb===
+====bba====
+!! end
+
+!! test
+Section extraction test (section 7)
+!! options
+section=7
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+====bba====
+!! end
+
+!! test
+Section extraction test (section 8)
+!! options
+section=8
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+===bc===
+!! end
+
+!! test
+Section extraction test (section 9)
+!! options
+section=9
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+==c==
+===ca===
+!! end
+
+!! test
+Section extraction test (section 10)
+!! options
+section=10
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+===ca===
+!! end
+
+!! test
+Section extraction test (nonexistent section 11)
+!! options
+section=11
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+!! end
+
+!! test
+Section extraction test with bogus heading (section 1)
+!! options
+section=1
+!! input
+==a==
+==bogus== not a legal section
+==b==
+!! result
+==a==
+==bogus== not a legal section
+!! end
+
+!! test
+Section extraction test with bogus heading (section 2)
+!! options
+section=2
+!! input
+==a==
+==bogus== not a legal section
+==b==
+!! result
+==b==
+!! end
+
+!! test
+Section extraction test with comment after heading (section 1)
+!! options
+section=1
+!! input
+==a==
+==b== <!-- -->
+==c==
+!! result
+==a==
+!! end
+
+!! test
+Section extraction test with comment after heading (section 2)
+!! options
+section=2
+!! input
+==a==
+==b== <!-- -->
+==c==
+!! result
+==b== <!-- -->
+!! end
+
+!! test
+Section extraction test with bogus <nowiki> heading (section 1)
+!! options
+section=1
+!! input
+==a==
+==bogus== <nowiki>not a legal section</nowiki>
+==b==
+!! result
+==a==
+==bogus== <nowiki>not a legal section</nowiki>
+!! end
+
+!! test
+Section extraction test with bogus <nowiki> heading (section 2)
+!! options
+section=2
+!! input
+==a==
+==bogus== <nowiki>not a legal section</nowiki>
+==b==
+!! result
+==b==
+!! end
+
+
+# Formerly testing for bug 2587, now resolved by the use of unmarked sections
+# instead of respecting commented sections
+!! test
+Section extraction prefixed by comment (section 1)
+!! options
+section=1
+!! input
+<!-- -->==sec1==
+==sec2==
+!!result
+==sec2==
+!!end
+
+!! test
+Section extraction prefixed by comment (section 2)
+!! options
+section=2
+!! input
+<!-- -->==sec1==
+==sec2==
+!!result
+
+!!end
+
+
+# Formerly testing for bug 2607, now resolved by the use of unmarked sections
+# instead of respecting HTML-style headings
+!! test
+Section extraction, mixed wiki and html (section 1)
+!! options
+section=1
+!! input
+<h2>unmarked</h2>
+unmarked
+==1==
+one
+==2==
+two
+!! result
+==1==
+one
+!! end
+
+!! test
+Section extraction, mixed wiki and html (section 2)
+!! options
+section=2
+!! input
+<h2>unmarked</h2>
+unmarked
+==1==
+one
+==2==
+two
+!! result
+==2==
+two
+!! end
+
+
+# Formerly testing for bug 3342
+!! test
+Section extraction, heading surrounded by <noinclude>
+!! options
+section=1
+!! input
+<noinclude>==unmarked==</noinclude>
+==marked==
+!! result
+==marked==
+!!end
+
+# Test behavior of bug 19910
+!! test
+Sectiion with all-equals
+!! options
+section=2
+!! input
+===
+The line above must have a trailing space
+=== <!--
+--> <!-- -->
+But just in case it doesn't...
+!! result
+=== <!--
+--> <!-- -->
+But just in case it doesn't...
+!! end
+
+!! test
+Section replacement test (section 0)
+!! options
+replace=0,"xxx"
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+xxx
+
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! end
+
+!! test
+Section replacement test (section 1)
+!! options
+replace=1,"xxx"
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+start
+xxx
+
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! end
+
+!! test
+Section replacement test (section 2)
+!! options
+replace=2,"xxx"
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+start
+==a==
+xxx
+
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! end
+
+!! test
+Section replacement test (section 3)
+!! options
+replace=3,"xxx"
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+start
+==a==
+===aa===
+xxx
+
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! end
+
+!! test
+Section replacement test (section 4)
+!! options
+replace=4,"xxx"
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+start
+==a==
+===aa===
+====aaa====
+xxx
+
+==c==
+===ca===
+!! end
+
+!! test
+Section replacement test (section 5)
+!! options
+replace=5,"xxx"
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+start
+==a==
+===aa===
+====aaa====
+==b==
+xxx
+
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! end
+
+!! test
+Section replacement test (section 6)
+!! options
+replace=6,"xxx"
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+xxx
+
+===bc===
+==c==
+===ca===
+!! end
+
+!! test
+Section replacement test (section 7)
+!! options
+replace=7,"xxx"
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+xxx
+
+===bc===
+==c==
+===ca===
+!! end
+
+!! test
+Section replacement test (section 8)
+!! options
+replace=8,"xxx"
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+xxx
+
+==c==
+===ca===
+!!end
+
+!! test
+Section replacement test (section 9)
+!! options
+replace=9,"xxx"
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+xxx
+!! end
+
+!! test
+Section replacement test (section 10)
+!! options
+replace=10,"xxx"
+!! input
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+===ca===
+!! result
+start
+==a==
+===aa===
+====aaa====
+==b==
+===ba===
+===bb===
+====bba====
+===bc===
+==c==
+xxx
+!! end
+
+!! test
+Section replacement test with initial whitespace (bug 13728)
+!! options
+replace=2,"xxx"
+!! input
+ Preformatted initial line
+==a==
+===a===
+!! result
+ Preformatted initial line
+==a==
+xxx
+!! end
+
+
+!! test
+Section extraction, heading followed by pre with 20 spaces (bug 6398)
+!! options
+section=1
+!! input
+==a==
+ a
+!! result
+==a==
+ a
+!! end
+
+!! test
+Section extraction, heading followed by pre with 19 spaces (bug 6398 sanity check)
+!! options
+section=1
+!! input
+==a==
+ a
+!! result
+==a==
+ a
+!! end
+
+
+!! test
+Section extraction, <pre> around bogus header (bug 10309)
+!! options
+noxml section=2
+!! input
+== Section One ==
+<pre>
+=======
+</pre>
+
+== Section Two ==
+stuff
+!! result
+== Section Two ==
+stuff
+!! end
+
+!! test
+Section replacement, <pre> around bogus header (bug 10309)
+!! options
+noxml replace=2,"xxx"
+!! input
+== Section One ==
+<pre>
+=======
+</pre>
+
+== Section Two ==
+stuff
+!! result
+== Section One ==
+<pre>
+=======
+</pre>
+
+xxx
+!! end
+
+
+
+!! test
+Handling of &#x0A; in URLs
+!! input
+**irc://&#x0A;a
+!! result
+<ul>
+<li><ul>
+<li><a rel="nofollow" class="external free" href="irc://%0Aa">irc://%0Aa</a>
+</li>
+</ul>
+</li>
+</ul>
+
+!!end
+
+!! test
+5 quotes, code coverage +1 line (php)
+!! options
+php
+!! input
+'''''
+!! result
+!! end
+# The PHP parser strips the empty tags out for giggles; parsoid doesn't.
+!! test
+5 quotes, code coverage +1 line (parsoid)
+!! options
+parsoid
+!! input
+'''''
+!! result
+<p><b><i></i></b></p>
+!! end
+
+!! test
+Special:Search page linking.
+!! input
+{{Special:search}}
+!! result
+<p><a href="/wiki/Special:Search" t