3 * @group ContentHandler
5 * ^--- important, causes temporary tables to be used instead of the real database
8 class WikiPageTest
extends MediaWikiTestCase
{
12 function __construct( $name = null, array $data = array(), $dataName = '' ) {
13 parent
::__construct( $name, $data, $dataName );
15 $this->tablesUsed
= array_merge ( $this->tablesUsed
,
33 public function setUp() {
34 $this->pages_to_delete
= array();
37 public function tearDown() {
38 foreach ( $this->pages_to_delete
as $p ) {
39 /* @var $p WikiPage */
43 $p->doDeleteArticle( "testing done." );
45 } catch ( MWException
$ex ) {
51 protected function newPage( $title ) {
52 if ( is_string( $title ) ) $title = Title
::newFromText( $title );
54 $p = new WikiPage( $title );
56 $this->pages_to_delete
[] = $p;
61 protected function createPage( $page, $text, $model = null ) {
62 if ( is_string( $page ) ) $page = Title
::newFromText( $page );
63 if ( $page instanceof Title
) $page = $this->newPage( $page );
65 $content = ContentHandler
::makeContent( $text, $page->getTitle(), $model );
66 $page->doEditContent( $content, "testing", EDIT_NEW
);
71 public function testDoEditContent() {
72 $title = Title
::newFromText( "WikiPageTest_testDoEditContent" );
74 $page = $this->newPage( $title );
76 $content = ContentHandler
::makeContent( "[[Lorem ipsum]] dolor sit amet, consetetur sadipscing elitr, sed diam "
77 . " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
80 $page->doEditContent( $content, "testing 1" );
82 $this->assertTrue( $title->exists(), "Title object should indicate that the page now exists" );
83 $this->assertTrue( $page->exists(), "WikiPage object should indicate that the page now exists" );
87 # ------------------------
88 $page = new WikiPage( $title );
90 $retrieved = $page->getContent();
91 $this->assertTrue( $content->equals( $retrieved ), 'retrieved content doesn\'t equal original' );
93 # ------------------------
94 $content = ContentHandler
::makeContent( "At vero eos et accusam et justo duo [[dolores]] et ea rebum. "
95 . "Stet clita kasd [[gubergren]], no sea takimata sanctus est.",
98 $page->doEditContent( $content, "testing 2" );
100 # ------------------------
101 $page = new WikiPage( $title );
103 $retrieved = $page->getContent();
104 $this->assertTrue( $content->equals( $retrieved ), 'retrieved content doesn\'t equal original' );
106 # ------------------------
107 $dbr = wfGetDB( DB_SLAVE
);
108 $res = $dbr->select( 'pagelinks', '*', array( 'pl_from' => $id ) );
109 $n = $res->numRows();
112 $this->assertEquals( 2, $n, 'pagelinks should contain two links from the page' );
115 public function testDoEdit() {
116 $title = Title
::newFromText( "WikiPageTest_testDoEdit" );
118 $page = $this->newPage( $title );
120 $text = "[[Lorem ipsum]] dolor sit amet, consetetur sadipscing elitr, sed diam "
121 . " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.";
123 $page->doEdit( $text, "testing 1" );
125 $this->assertTrue( $title->exists(), "Title object should indicate that the page now exists" );
126 $this->assertTrue( $page->exists(), "WikiPage object should indicate that the page now exists" );
128 $id = $page->getId();
130 # ------------------------
131 $page = new WikiPage( $title );
133 $retrieved = $page->getText();
134 $this->assertEquals( $text, $retrieved, 'retrieved text doesn\'t equal original' );
136 # ------------------------
137 $text = "At vero eos et accusam et justo duo [[dolores]] et ea rebum. "
138 . "Stet clita kasd [[gubergren]], no sea takimata sanctus est.";
140 $page->doEdit( $text, "testing 2" );
142 # ------------------------
143 $page = new WikiPage( $title );
145 $retrieved = $page->getText();
146 $this->assertEquals( $text, $retrieved, 'retrieved text doesn\'t equal original' );
148 # ------------------------
149 $dbr = wfGetDB( DB_SLAVE
);
150 $res = $dbr->select( 'pagelinks', '*', array( 'pl_from' => $id ) );
151 $n = $res->numRows();
154 $this->assertEquals( 2, $n, 'pagelinks should contain two links from the page' );
157 public function testDoQuickEdit() {
160 $page = $this->createPage( "WikiPageTest_testDoQuickEdit", "original text" );
162 $text = "quick text";
163 $page->doQuickEdit( $text, $wgUser, "testing q" );
165 # ---------------------
166 $page = new WikiPage( $page->getTitle() );
167 $this->assertEquals( $text, $page->getText() );
170 public function testDoQuickEditContent() {
173 $page = $this->createPage( "WikiPageTest_testDoQuickEditContent", "original text" );
175 $content = ContentHandler
::makeContent( "quick text", $page->getTitle() );
176 $page->doQuickEditContent( $content, $wgUser, "testing q" );
178 # ---------------------
179 $page = new WikiPage( $page->getTitle() );
180 $this->assertTrue( $content->equals( $page->getContent() ) );
183 public function testDoDeleteArticle() {
184 $page = $this->createPage( "WikiPageTest_testDoDeleteArticle", "[[original text]] foo" );
185 $id = $page->getId();
187 $page->doDeleteArticle( "testing deletion" );
189 $this->assertFalse( $page->exists(), "WikiPage::exists should return false after page was deleted" );
190 $this->assertNull( $page->getContent(), "WikiPage::getContent should return null after page was deleted" );
191 $this->assertFalse( $page->getText(), "WikiPage::getText should return false after page was deleted" );
193 $t = Title
::newFromText( $page->getTitle()->getPrefixedText() );
194 $this->assertFalse( $t->exists(), "Title::exists should return false after page was deleted" );
196 # ------------------------
197 $dbr = wfGetDB( DB_SLAVE
);
198 $res = $dbr->select( 'pagelinks', '*', array( 'pl_from' => $id ) );
199 $n = $res->numRows();
202 $this->assertEquals( 0, $n, 'pagelinks should contain no more links from the page' );
205 public function testGetRevision() {
206 $page = $this->newPage( "WikiPageTest_testGetRevision" );
208 $rev = $page->getRevision();
209 $this->assertNull( $rev );
212 $this->createPage( $page, "some text" );
214 $rev = $page->getRevision();
216 $this->assertEquals( $page->getLatest(), $rev->getId() );
217 $this->assertEquals( "some text", $rev->getContent()->getNativeData() );
220 public function testGetContent() {
221 $page = $this->newPage( "WikiPageTest_testGetContent" );
223 $content = $page->getContent();
224 $this->assertNull( $content );
227 $this->createPage( $page, "some text" );
229 $content = $page->getContent();
230 $this->assertEquals( "some text", $content->getNativeData() );
233 public function testGetText() {
234 $page = $this->newPage( "WikiPageTest_testGetText" );
236 $text = $page->getText();
237 $this->assertFalse( $text );
240 $this->createPage( $page, "some text" );
242 $text = $page->getText();
243 $this->assertEquals( "some text", $text );
246 public function testGetRawText() {
247 $page = $this->newPage( "WikiPageTest_testGetRawText" );
249 $text = $page->getRawText();
250 $this->assertFalse( $text );
253 $this->createPage( $page, "some text" );
255 $text = $page->getRawText();
256 $this->assertEquals( "some text", $text );
259 public function testGetContentModel() {
260 $page = $this->createPage( "WikiPageTest_testGetContentModel", "some text", CONTENT_MODEL_JAVASCRIPT
);
262 $page = new WikiPage( $page->getTitle() );
263 $this->assertEquals( CONTENT_MODEL_JAVASCRIPT
, $page->getContentModel() );
266 public function testGetContentHandler() {
267 $page = $this->createPage( "WikiPageTest_testGetContentHandler", "some text", CONTENT_MODEL_JAVASCRIPT
);
269 $page = new WikiPage( $page->getTitle() );
270 $this->assertEquals( 'JavaScriptContentHandler', get_class( $page->getContentHandler() ) );
273 public function testExists() {
274 $page = $this->newPage( "WikiPageTest_testExists" );
275 $this->assertFalse( $page->exists() );
278 $this->createPage( $page, "some text" );
279 $this->assertTrue( $page->exists() );
281 $page = new WikiPage( $page->getTitle() );
282 $this->assertTrue( $page->exists() );
285 $page->doDeleteArticle( "done testing" );
286 $this->assertFalse( $page->exists() );
288 $page = new WikiPage( $page->getTitle() );
289 $this->assertFalse( $page->exists() );
292 public function dataHasViewableContent() {
294 array( 'WikiPageTest_testHasViewableContent', false, true ),
295 array( 'Special:WikiPageTest_testHasViewableContent', false ),
296 array( 'MediaWiki:WikiPageTest_testHasViewableContent', false ),
297 array( 'Special:Userlogin', true ),
298 array( 'MediaWiki:help', true ),
303 * @dataProvider dataHasViewableContent
305 public function testHasViewableContent( $title, $viewable, $create = false ) {
306 $page = $this->newPage( $title );
307 $this->assertEquals( $viewable, $page->hasViewableContent() );
310 $this->createPage( $page, "some text" );
311 $this->assertTrue( $page->hasViewableContent() );
313 $page = new WikiPage( $page->getTitle() );
314 $this->assertTrue( $page->hasViewableContent() );
318 public function dataGetRedirectTarget() {
320 array( 'WikiPageTest_testGetRedirectTarget_1', "hello world", null ),
321 array( 'WikiPageTest_testGetRedirectTarget_2', "#REDIRECT [[hello world]]", "Hello world" ),
326 * @dataProvider dataGetRedirectTarget
328 public function testGetRedirectTarget( $title, $text, $target ) {
329 $page = $this->createPage( $title, $text );
331 # sanity check, because this test seems to fail for no reason for some people.
332 $c = $page->getContent();
333 $this->assertEquals( 'WikitextContent', get_class( $c ) );
335 # now, test the actual redirect
336 $t = $page->getRedirectTarget();
337 $this->assertEquals( $target, is_null( $t ) ?
null : $t->getPrefixedText() );
341 * @dataProvider dataGetRedirectTarget
343 public function testIsRedirect( $title, $text, $target ) {
344 $page = $this->createPage( $title, $text );
345 $this->assertEquals( !is_null( $target ), $page->isRedirect() );
348 public function dataIsCountable() {
352 array( 'WikiPageTest_testIsCountable',
357 array( 'WikiPageTest_testIsCountable',
364 array( 'WikiPageTest_testIsCountable',
369 array( 'WikiPageTest_testIsCountable',
376 array( 'WikiPageTest_testIsCountable',
381 array( 'WikiPageTest_testIsCountable',
388 array( 'WikiPageTest_testIsCountable',
393 array( 'WikiPageTest_testIsCountable',
398 array( 'WikiPageTest_testIsCountable',
404 // not a content namespace
405 array( 'Talk:WikiPageTest_testIsCountable',
410 array( 'Talk:WikiPageTest_testIsCountable',
415 array( 'Talk:WikiPageTest_testIsCountable',
421 // not a content namespace, different model
422 array( 'MediaWiki:WikiPageTest_testIsCountable.js',
427 array( 'MediaWiki:WikiPageTest_testIsCountable.js',
432 array( 'MediaWiki:WikiPageTest_testIsCountable.js',
442 * @dataProvider dataIsCountable
444 public function testIsCountable( $title, $text, $mode, $expected ) {
445 global $wgArticleCountMethod;
447 $old = $wgArticleCountMethod;
448 $wgArticleCountMethod = $mode;
450 $page = $this->createPage( $title, $text );
451 $editInfo = $page->prepareContentForEdit( $page->getContent() );
453 $v = $page->isCountable();
454 $w = $page->isCountable( $editInfo );
455 $wgArticleCountMethod = $old;
457 $this->assertEquals( $expected, $v, "isCountable( null ) returned unexpected value " . var_export( $v, true )
458 . " instead of " . var_export( $expected, true ) . " in mode `$mode` for text \"$text\"" );
460 $this->assertEquals( $expected, $w, "isCountable( \$editInfo ) returned unexpected value " . var_export( $v, true )
461 . " instead of " . var_export( $expected, true ) . " in mode `$mode` for text \"$text\"" );
464 public function dataGetParserOutput() {
466 array("hello ''world''\n", "<p>hello <i>world</i></p>"),
472 * @dataProvider dataGetParserOutput
474 public function testGetParserOutput( $text, $expectedHtml ) {
475 $page = $this->createPage( 'WikiPageTest_testGetParserOutput', $text );
477 $opt = new ParserOptions();
478 $po = $page->getParserOutput( $opt );
479 $text = $po->getText();
481 $text = trim( preg_replace( '/<!--.*?-->/sm', '', $text ) ); # strip injected comments
482 $text = preg_replace( '!\s*(</p>)!sm', '\1', $text ); # don't let tidy confuse us
484 $this->assertEquals( $expectedHtml, $text );
503 public function dataReplaceSection() {
505 array( 'WikiPageTest_testReplaceSection',
506 WikiPageTest
::$sections,
510 trim( preg_replace( '/^Intro/sm', 'No more', WikiPageTest
::$sections ) )
512 array( 'WikiPageTest_testReplaceSection',
513 WikiPageTest
::$sections,
519 array( 'WikiPageTest_testReplaceSection',
520 WikiPageTest
::$sections,
522 "== TEST ==\nmore fun",
524 trim( preg_replace( '/^== test ==.*== foo ==/sm', "== TEST ==\nmore fun\n\n== foo ==", WikiPageTest
::$sections ) )
526 array( 'WikiPageTest_testReplaceSection',
527 WikiPageTest
::$sections,
531 trim( WikiPageTest
::$sections )
533 array( 'WikiPageTest_testReplaceSection',
534 WikiPageTest
::$sections,
538 trim( WikiPageTest
::$sections ) . "\n\n== New ==\n\nNo more"
544 * @dataProvider dataReplaceSection
546 public function testReplaceSection( $title, $text, $section, $with, $sectionTitle, $expected ) {
547 $page = $this->createPage( $title, $text );
548 $text = $page->replaceSection( $section, $with, $sectionTitle );
549 $text = trim( $text );
551 $this->assertEquals( $expected, $text );
555 * @dataProvider dataReplaceSection
557 public function testReplaceSectionContent( $title, $text, $section, $with, $sectionTitle, $expected ) {
558 $page = $this->createPage( $title, $text );
560 $content = ContentHandler
::makeContent( $with, $page->getTitle(), $page->getContentModel() );
561 $c = $page->replaceSectionContent( $section, $content, $sectionTitle );
563 $this->assertEquals( $expected, is_null( $c ) ?
null : trim( $c->getNativeData() ) );
567 public function testGetUndoText() {
570 wfSuppressWarnings();
571 $haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
575 $this->markTestSkipped( "diff3 not installed or not found" );
580 $page = $this->createPage( "WikiPageTest_testGetUndoText", $text );
581 $rev1 = $page->getRevision();
584 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section two");
585 $rev2 = $page->getRevision();
587 $text .= "\n\nthree";
588 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section three");
589 $rev3 = $page->getRevision();
592 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section four");
593 $rev4 = $page->getRevision();
596 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section five");
597 $rev5 = $page->getRevision();
600 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section six");
601 $rev6 = $page->getRevision();
603 $undo6 = $page->getUndoText( $rev6 );
604 if ( $undo6 === false ) $this->fail( "getUndoText failed for rev6" );
605 $this->assertEquals( "one\n\ntwo\n\nthree\n\nfour\n\nfive", $undo6 );
607 $undo3 = $page->getUndoText( $rev4, $rev2 );
608 if ( $undo3 === false ) $this->fail( "getUndoText failed for rev4..rev2" );
609 $this->assertEquals( "one\n\ntwo\n\nfive", $undo3 );
611 $undo2 = $page->getUndoText( $rev2 );
612 if ( $undo2 === false ) $this->fail( "getUndoText failed for rev2" );
613 $this->assertEquals( "one\n\nfive", $undo2 );
618 * @todo FIXME: this is a better rollback test than the one below, but it keeps failing in jenkins for some reason.
620 public function broken_testDoRollback() {
622 $admin->setName("Admin");
625 $page = $this->newPage( "WikiPageTest_testDoRollback" );
626 $page->doEditContent( ContentHandler
::makeContent( $text, $page->getTitle() ), "section one", EDIT_NEW
, false, $admin );
629 $user1->setName( "127.0.1.11" );
631 $page = new WikiPage( $page->getTitle() );
632 $page->doEditContent( ContentHandler
::makeContent( $text, $page->getTitle() ), "adding section two", 0, false, $user1 );
635 $user2->setName( "127.0.2.13" );
636 $text .= "\n\nthree";
637 $page = new WikiPage( $page->getTitle() );
638 $page->doEditContent( ContentHandler
::makeContent( $text, $page->getTitle() ), "adding section three", 0, false, $user2 );
640 # we are having issues with doRollback spuriously failing. apparently the last revision somehow goes missing
641 # or not committed under some circumstances. so, make sure the last revision has the right user name.
642 $dbr = wfGetDB( DB_SLAVE
);
643 $this->assertEquals( 3, Revision
::countByPageId( $dbr, $page->getId() ) );
645 $page = new WikiPage( $page->getTitle() );
646 $rev3 = $page->getRevision();
647 $this->assertEquals( '127.0.2.13', $rev3->getUserText() );
649 $rev2 = $rev3->getPrevious();
650 $this->assertEquals( '127.0.1.11', $rev2->getUserText() );
652 $rev1 = $rev2->getPrevious();
653 $this->assertEquals( 'Admin', $rev1->getUserText() );
655 # now, try the actual rollback
656 $admin->addGroup( "sysop" ); #XXX: make the test user a sysop...
657 $token = $admin->getEditToken( array( $page->getTitle()->getPrefixedText(), $user2->getName() ), null );
658 $errors = $page->doRollback( $user2->getName(), "testing revert", $token, false, $details, $admin );
661 $this->fail( "Rollback failed:\n" . print_r( $errors, true ) . ";\n" . print_r( $details, true ) );
664 $page = new WikiPage( $page->getTitle() );
665 $this->assertEquals( $rev2->getSha1(), $page->getRevision()->getSha1(), "rollback did not revert to the correct revision" );
666 $this->assertEquals( "one\n\ntwo", $page->getContent()->getNativeData() );
670 * @todo FIXME: the above rollback test is better, but it keeps failing in jenkins for some reason.
672 public function testDoRollback() {
674 $admin->setName("Admin");
677 $page = $this->newPage( "WikiPageTest_testDoRollback" );
678 $page->doEditContent( ContentHandler
::makeContent( $text, $page->getTitle() ), "section one", EDIT_NEW
, false, $admin );
679 $rev1 = $page->getRevision();
682 $user1->setName( "127.0.1.11" );
684 $page = new WikiPage( $page->getTitle() );
685 $page->doEditContent( ContentHandler
::makeContent( $text, $page->getTitle() ), "adding section two", 0, false, $user1 );
687 # now, try the rollback
688 $admin->addGroup( "sysop" ); #XXX: make the test user a sysop...
689 $token = $admin->getEditToken( array( $page->getTitle()->getPrefixedText(), $user1->getName() ), null );
690 $errors = $page->doRollback( $user1->getName(), "testing revert", $token, false, $details, $admin );
693 $this->fail( "Rollback failed:\n" . print_r( $errors, true ) . ";\n" . print_r( $details, true ) );
696 $page = new WikiPage( $page->getTitle() );
697 $this->assertEquals( $rev1->getSha1(), $page->getRevision()->getSha1(), "rollback did not revert to the correct revision" );
698 $this->assertEquals( "one", $page->getContent()->getNativeData() );
701 public function dataGetAutosummary( ) {
704 'Hello there, world!',
707 '/^Redirected page .*Foo/'
714 '/^Created page .*Hello/'
718 'Hello there, world!',
725 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut
726 labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et
727 ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
730 '/^Replaced .*Hello/'
743 * @dataProvider dataGetAutoSummary
745 public function testGetAutosummary( $old, $new, $flags, $expected ) {
746 $page = $this->newPage( "WikiPageTest_testGetAutosummary" );
748 $summary = $page->getAutosummary( $old, $new, $flags );
750 $this->assertTrue( (bool)preg_match( $expected, $summary ), "Autosummary didn't match expected pattern $expected: $summary" );
753 public function dataGetAutoDeleteReason( ) {
763 array( "first edit", null ),
765 "/first edit.*only contributor/",
771 array( "first edit", null ),
772 array( "second edit", null ),
774 "/second edit.*only contributor/",
780 array( "first edit", "127.0.2.22" ),
781 array( "second edit", "127.0.3.33" ),
789 array( "first edit: "
790 . "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam "
791 . " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. "
792 . "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea "
793 . "takimata sanctus est Lorem ipsum dolor sit amet.'", null ),
795 '/first edit:.*\.\.\."/',
801 array( "first edit", "127.0.2.22" ),
802 array( "", "127.0.3.33" ),
804 "/before blanking.*first edit/",
812 * @dataProvider dataGetAutoDeleteReason
814 public function testGetAutoDeleteReason( $edits, $expectedResult, $expectedHistory ) {
817 $page = $this->newPage( "WikiPageTest_testGetAutoDeleteReason" );
821 foreach ( $edits as $edit ) {
824 if ( !empty( $edit[1] ) ) $user->setName( $edit[1] );
825 else $user = $wgUser;
827 $content = ContentHandler
::makeContent( $edit[0], $page->getTitle(), $page->getContentModel() );
829 $page->doEditContent( $content, "test edit $c", $c < 2 ? EDIT_NEW
: 0, false, $user );
834 $reason = $page->getAutoDeleteReason( $hasHistory );
836 if ( is_bool( $expectedResult ) ||
is_null( $expectedResult ) ) $this->assertEquals( $expectedResult, $reason );
837 else $this->assertTrue( (bool)preg_match( $expectedResult, $reason ), "Autosummary didn't match expected pattern $expectedResult: $reason" );
839 $this->assertEquals( $expectedHistory, $hasHistory, "expected \$hasHistory to be " . var_export( $expectedHistory, true ) );
841 $page->doDeleteArticle( "done" );
844 public function dataPreSaveTransform() {
846 array( 'hello this is ~~~',
847 "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
849 array( 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
850 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
856 * @dataProvider dataPreSaveTransform
858 public function testPreSaveTransform( $text, $expected ) {
860 $user->setName("127.0.0.1");
862 $page = $this->newPage( "WikiPageTest_testPreloadTransform" );
863 $text = $page->preSaveTransform( $text, $user );
865 $this->assertEquals( $expected, $text );