3 * @group ContentHandler
5 * ^--- important, causes temporary tables to be used instead of the real database
8 class WikiPageTest
extends MediaWikiTestCase
{
12 public function setUp() {
13 $this->pages_to_delete
= array();
16 public function tearDown() {
17 foreach ( $this->pages_to_delete
as $p ) {
18 /* @var $p WikiPage */
22 $p->doDeleteArticle( "testing done." );
24 } catch ( MWException
$ex ) {
30 protected function newPage( $title ) {
31 if ( is_string( $title ) ) $title = Title
::newFromText( $title );
33 $p = new WikiPage( $title );
35 $this->pages_to_delete
[] = $p;
40 protected function createPage( $page, $text, $model = null ) {
41 if ( is_string( $page ) ) $page = Title
::newFromText( $page );
42 if ( $page instanceof Title
) $page = $this->newPage( $page );
44 $content = ContentHandler
::makeContent( $text, $page->getTitle(), $model );
45 $page->doEditContent( $content, "testing", EDIT_NEW
);
50 public function testDoEditContent() {
51 $title = Title
::newFromText( "WikiPageTest_testDoEditContent" );
53 $page = $this->newPage( $title );
55 $content = ContentHandler
::makeContent( "[[Lorem ipsum]] dolor sit amet, consetetur sadipscing elitr, sed diam "
56 . " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
59 $page->doEditContent( $content, "testing 1" );
61 $this->assertTrue( $title->exists(), "Title object should indicate that the page now exists" );
62 $this->assertTrue( $page->exists(), "WikiPage object should indicate that the page now exists" );
66 # ------------------------
67 $page = new WikiPage( $title );
69 $retrieved = $page->getContent();
70 $this->assertTrue( $content->equals( $retrieved ), 'retrieved content doesn\'t equal original' );
72 # ------------------------
73 $content = ContentHandler
::makeContent( "At vero eos et accusam et justo duo [[dolores]] et ea rebum. "
74 . "Stet clita kasd [[gubergren]], no sea takimata sanctus est.",
77 $page->doEditContent( $content, "testing 2" );
79 # ------------------------
80 $page = new WikiPage( $title );
82 $retrieved = $page->getContent();
83 $this->assertTrue( $content->equals( $retrieved ), 'retrieved content doesn\'t equal original' );
85 # ------------------------
86 $dbr = wfGetDB( DB_SLAVE
);
87 $res = $dbr->select( 'pagelinks', '*', array( 'pl_from' => $id ) );
91 $this->assertEquals( 2, $n, 'pagelinks should contain two links from the page' );
94 public function testDoEdit() {
95 $title = Title
::newFromText( "WikiPageTest_testDoEdit" );
97 $page = $this->newPage( $title );
99 $text = "[[Lorem ipsum]] dolor sit amet, consetetur sadipscing elitr, sed diam "
100 . " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.";
102 $page->doEdit( $text, "testing 1" );
104 $this->assertTrue( $title->exists(), "Title object should indicate that the page now exists" );
105 $this->assertTrue( $page->exists(), "WikiPage object should indicate that the page now exists" );
107 $id = $page->getId();
109 # ------------------------
110 $page = new WikiPage( $title );
112 $retrieved = $page->getText();
113 $this->assertEquals( $text, $retrieved, 'retrieved text doesn\'t equal original' );
115 # ------------------------
116 $text = "At vero eos et accusam et justo duo [[dolores]] et ea rebum. "
117 . "Stet clita kasd [[gubergren]], no sea takimata sanctus est.";
119 $page->doEdit( $text, "testing 2" );
121 # ------------------------
122 $page = new WikiPage( $title );
124 $retrieved = $page->getText();
125 $this->assertEquals( $text, $retrieved, 'retrieved text doesn\'t equal original' );
127 # ------------------------
128 $dbr = wfGetDB( DB_SLAVE
);
129 $res = $dbr->select( 'pagelinks', '*', array( 'pl_from' => $id ) );
130 $n = $res->numRows();
133 $this->assertEquals( 2, $n, 'pagelinks should contain two links from the page' );
136 public function testDoQuickEdit() {
139 $page = $this->createPage( "WikiPageTest_testDoQuickEdit", "original text" );
141 $text = "quick text";
142 $page->doQuickEdit( $text, $wgUser, "testing q" );
144 # ---------------------
145 $page = new WikiPage( $page->getTitle() );
146 $this->assertEquals( $text, $page->getText() );
149 public function testDoQuickEditContent() {
152 $page = $this->createPage( "WikiPageTest_testDoQuickEditContent", "original text" );
154 $content = ContentHandler
::makeContent( "quick text", $page->getTitle() );
155 $page->doQuickEditContent( $content, $wgUser, "testing q" );
157 # ---------------------
158 $page = new WikiPage( $page->getTitle() );
159 $this->assertTrue( $content->equals( $page->getContent() ) );
162 public function testDoDeleteArticle() {
163 $page = $this->createPage( "WikiPageTest_testDoDeleteArticle", "[[original text]] foo" );
164 $id = $page->getId();
166 $page->doDeleteArticle( "testing deletion" );
168 $this->assertFalse( $page->exists(), "WikiPage::exists should return false after page was deleted" );
170 $this->assertNull( $page->getContent(), "WikiPage::getContent should return null after page was deleted" );
171 $this->assertFalse( $page->getText(), "WikiPage::getText should return false after page was deleted" );
173 $t = Title
::newFromText( $page->getTitle()->getPrefixedText() );
174 $this->assertFalse( $t->exists(), "Title::exists should return false after page was deleted" );
176 # ------------------------
177 $dbr = wfGetDB( DB_SLAVE
);
178 $res = $dbr->select( 'pagelinks', '*', array( 'pl_from' => $id ) );
179 $n = $res->numRows();
182 $this->assertEquals( 0, $n, 'pagelinks should contain no more links from the page' );
185 public function testGetRevision() {
186 $page = $this->newPage( "WikiPageTest_testGetRevision" );
188 $rev = $page->getRevision();
189 $this->assertNull( $rev );
192 $this->createPage( $page, "some text" );
194 $rev = $page->getRevision();
196 $this->assertEquals( $page->getLatest(), $rev->getId() );
197 $this->assertEquals( "some text", $rev->getContent()->getNativeData() );
200 public function testGetContent() {
201 $page = $this->newPage( "WikiPageTest_testGetContent" );
203 $content = $page->getContent();
204 $this->assertNull( $content );
207 $this->createPage( $page, "some text" );
209 $content = $page->getContent();
210 $this->assertEquals( "some text", $content->getNativeData() );
213 public function testGetText() {
214 $page = $this->newPage( "WikiPageTest_testGetText" );
216 $text = $page->getText();
217 $this->assertFalse( $text );
220 $this->createPage( $page, "some text" );
222 $text = $page->getText();
223 $this->assertEquals( "some text", $text );
226 public function testGetRawText() {
227 $page = $this->newPage( "WikiPageTest_testGetRawText" );
229 $text = $page->getRawText();
230 $this->assertFalse( $text );
233 $this->createPage( $page, "some text" );
235 $text = $page->getRawText();
236 $this->assertEquals( "some text", $text );
239 public function testGetContentModel() {
240 $page = $this->createPage( "WikiPageTest_testGetContentModel", "some text", CONTENT_MODEL_JAVASCRIPT
);
242 $page = new WikiPage( $page->getTitle() );
243 $this->assertEquals( CONTENT_MODEL_JAVASCRIPT
, $page->getContentModel() );
246 public function testGetContentHandler() {
247 $page = $this->createPage( "WikiPageTest_testGetContentHandler", "some text", CONTENT_MODEL_JAVASCRIPT
);
249 $page = new WikiPage( $page->getTitle() );
250 $this->assertEquals( 'JavaScriptContentHandler', get_class( $page->getContentHandler() ) );
253 public function testExists() {
254 $page = $this->newPage( "WikiPageTest_testExists" );
255 $this->assertFalse( $page->exists() );
258 $this->createPage( $page, "some text" );
259 $this->assertTrue( $page->exists() );
261 $page = new WikiPage( $page->getTitle() );
262 $this->assertTrue( $page->exists() );
265 $page->doDeleteArticle( "done testing" );
266 $this->assertFalse( $page->exists() );
268 $page = new WikiPage( $page->getTitle() );
269 $this->assertFalse( $page->exists() );
272 public function dataHasViewableContent() {
274 array( 'WikiPageTest_testHasViewableContent', false, true ),
275 array( 'Special:WikiPageTest_testHasViewableContent', false ),
276 array( 'MediaWiki:WikiPageTest_testHasViewableContent', false ),
277 array( 'Special:Userlogin', true ),
278 array( 'MediaWiki:help', true ),
283 * @dataProvider dataHasViewableContent
285 public function testHasViewableContent( $title, $viewable, $create = false ) {
286 $page = $this->newPage( $title );
287 $this->assertEquals( $viewable, $page->hasViewableContent() );
290 $this->createPage( $page, "some text" );
291 $this->assertTrue( $page->hasViewableContent() );
293 $page = new WikiPage( $page->getTitle() );
294 $this->assertTrue( $page->hasViewableContent() );
298 public function dataGetRedirectTarget() {
300 array( 'WikiPageTest_testGetRedirectTarget_1', "hello world", null ),
301 array( 'WikiPageTest_testGetRedirectTarget_2', "#REDIRECT [[hello world]]", "Hello world" ),
306 * @dataProvider dataGetRedirectTarget
308 public function testGetRedirectTarget( $title, $text, $target ) {
309 $page = $this->createPage( $title, $text );
311 # sanity check, because this test seems to fail for no reason for some people.
312 $c = $page->getContent();
313 $this->assertEquals( 'WikitextContent', get_class( $c ) );
315 # now, test the actual redirect
316 $t = $page->getRedirectTarget();
317 $this->assertEquals( $target, is_null( $t ) ?
null : $t->getPrefixedText() );
321 * @dataProvider dataGetRedirectTarget
323 public function testIsRedirect( $title, $text, $target ) {
324 $page = $this->createPage( $title, $text );
325 $this->assertEquals( !is_null( $target ), $page->isRedirect() );
328 public function dataIsCountable() {
332 array( 'WikiPageTest_testIsCountable',
337 array( 'WikiPageTest_testIsCountable',
344 array( 'WikiPageTest_testIsCountable',
349 array( 'WikiPageTest_testIsCountable',
356 array( 'WikiPageTest_testIsCountable',
361 array( 'WikiPageTest_testIsCountable',
368 array( 'WikiPageTest_testIsCountable',
373 array( 'WikiPageTest_testIsCountable',
378 array( 'WikiPageTest_testIsCountable',
384 // not a content namespace
385 array( 'Talk:WikiPageTest_testIsCountable',
390 array( 'Talk:WikiPageTest_testIsCountable',
395 array( 'Talk:WikiPageTest_testIsCountable',
401 // not a content namespace, different model
402 array( 'MediaWiki:WikiPageTest_testIsCountable.js',
407 array( 'MediaWiki:WikiPageTest_testIsCountable.js',
412 array( 'MediaWiki:WikiPageTest_testIsCountable.js',
422 * @dataProvider dataIsCountable
424 public function testIsCountable( $title, $text, $mode, $expected ) {
425 global $wgArticleCountMethod;
427 $old = $wgArticleCountMethod;
428 $wgArticleCountMethod = $mode;
430 $page = $this->createPage( $title, $text );
431 $editInfo = $page->prepareContentForEdit( $page->getContent() );
433 $v = $page->isCountable();
434 $w = $page->isCountable( $editInfo );
435 $wgArticleCountMethod = $old;
437 $this->assertEquals( $expected, $v, "isCountable( null ) returned unexpected value " . var_export( $v, true )
438 . " instead of " . var_export( $expected, true ) . " in mode `$mode` for text \"$text\"" );
440 $this->assertEquals( $expected, $w, "isCountable( \$editInfo ) returned unexpected value " . var_export( $v, true )
441 . " instead of " . var_export( $expected, true ) . " in mode `$mode` for text \"$text\"" );
444 public function dataGetParserOutput() {
446 array("hello ''world''\n", "<p>hello <i>world</i></p>"),
452 * @dataProvider dataGetParserOutput
454 public function testGetParserOutput( $text, $expectedHtml ) {
455 $page = $this->createPage( 'WikiPageTest_testGetParserOutput', $text );
457 $opt = new ParserOptions();
458 $po = $page->getParserOutput( $opt );
459 $text = $po->getText();
461 $text = trim( preg_replace( '/<!--.*?-->/sm', '', $text ) ); # strip injected comments
462 $text = preg_replace( '!\s*(</p>)!sm', '\1', $text ); # don't let tidy confuse us
464 $this->assertEquals( $expectedHtml, $text );
483 public function dataReplaceSection() {
485 array( 'WikiPageTest_testReplaceSection',
486 WikiPageTest
::$sections,
490 trim( preg_replace( '/^Intro/sm', 'No more', WikiPageTest
::$sections ) )
492 array( 'WikiPageTest_testReplaceSection',
493 WikiPageTest
::$sections,
499 array( 'WikiPageTest_testReplaceSection',
500 WikiPageTest
::$sections,
502 "== TEST ==\nmore fun",
504 trim( preg_replace( '/^== test ==.*== foo ==/sm', "== TEST ==\nmore fun\n\n== foo ==", WikiPageTest
::$sections ) )
506 array( 'WikiPageTest_testReplaceSection',
507 WikiPageTest
::$sections,
511 trim( WikiPageTest
::$sections )
513 array( 'WikiPageTest_testReplaceSection',
514 WikiPageTest
::$sections,
518 trim( WikiPageTest
::$sections ) . "\n\n== New ==\n\nNo more"
524 * @dataProvider dataReplaceSection
526 public function testReplaceSection( $title, $text, $section, $with, $sectionTitle, $expected ) {
527 $page = $this->createPage( $title, $text );
528 $text = $page->replaceSection( $section, $with, $sectionTitle );
529 $text = trim( $text );
531 $this->assertEquals( $expected, $text );
535 * @dataProvider dataReplaceSection
537 public function testReplaceSectionContent( $title, $text, $section, $with, $sectionTitle, $expected ) {
538 $page = $this->createPage( $title, $text );
540 $content = ContentHandler
::makeContent( $with, $page->getTitle(), $page->getContentModel() );
541 $c = $page->replaceSectionContent( $section, $content, $sectionTitle );
543 $this->assertEquals( $expected, is_null( $c ) ?
null : trim( $c->getNativeData() ) );
547 public function testGetUndoText() {
550 wfSuppressWarnings();
551 $haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
555 $this->markTestSkipped( "diff3 not installed or not found" );
560 $page = $this->createPage( "WikiPageTest_testGetUndoText", $text );
561 $rev1 = $page->getRevision();
564 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section two");
565 $rev2 = $page->getRevision();
567 $text .= "\n\nthree";
568 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section three");
569 $rev3 = $page->getRevision();
572 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section four");
573 $rev4 = $page->getRevision();
576 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section five");
577 $rev5 = $page->getRevision();
580 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section six");
581 $rev6 = $page->getRevision();
583 $undo6 = $page->getUndoText( $rev6 );
584 if ( $undo6 === false ) $this->fail( "getUndoText failed for rev6" );
585 $this->assertEquals( "one\n\ntwo\n\nthree\n\nfour\n\nfive", $undo6 );
587 $undo3 = $page->getUndoText( $rev4, $rev2 );
588 if ( $undo3 === false ) $this->fail( "getUndoText failed for rev4..rev2" );
589 $this->assertEquals( "one\n\ntwo\n\nfive", $undo3 );
591 $undo2 = $page->getUndoText( $rev2 );
592 if ( $undo2 === false ) $this->fail( "getUndoText failed for rev2" );
593 $this->assertEquals( "one\n\nfive", $undo2 );
600 * ^--- marked as broken, because it fails in jenkins, though it passes locally for everyone. or so it seems.
602 public function testDoRollback() {
604 $admin->setName("Admin");
607 $page = $this->newPage( "WikiPageTest_testDoRollback" );
608 $page->doEditContent( ContentHandler
::makeContent( $text, $page->getTitle() ), "section one", EDIT_NEW
, false, $admin );
611 $user1->setName( "127.0.1.11" );
613 $page = new WikiPage( $page->getTitle() );
614 $page->doEditContent( ContentHandler
::makeContent( $text, $page->getTitle() ), "adding section two", 0, false, $user1 );
617 $user2->setName( "127.0.2.13" );
618 $text .= "\n\nthree";
619 $page = new WikiPage( $page->getTitle() );
620 $page->doEditContent( ContentHandler
::makeContent( $text, $page->getTitle() ), "adding section three", 0, false, $user2 );
622 # we are having issues with doRollback spuriously failing. apparently the last revision somehow goes missing
623 # or not committed under some circumstances. so, make sure the last revision has the right user name.
624 $dbr = wfGetDB( DB_SLAVE
);
625 $this->assertEquals( 3, Revision
::countByPageId( $dbr, $page->getId() ) );
627 $page = new WikiPage( $page->getTitle() );
628 $rev3 = $page->getRevision();
629 $this->assertEquals( '127.0.2.13', $rev3->getUserText() );
631 $rev2 = $rev3->getPrevious();
632 $this->assertEquals( '127.0.1.11', $rev2->getUserText() );
634 $rev1 = $rev2->getPrevious();
635 $this->assertEquals( 'Admin', $rev1->getUserText() );
637 # now, try the actual rollback
638 $admin->addGroup( "sysop" ); #XXX: make the test user a sysop...
639 $token = $admin->getEditToken( array( $page->getTitle()->getPrefixedText(), $user2->getName() ), null );
640 $errors = $page->doRollback( $user2->getName(), "testing revert", $token, false, $details, $admin );
643 $this->fail( "Rollback failed:\n" . print_r( $errors, true ) . ";\n" . print_r( $details, true ) );
646 $page = new WikiPage( $page->getTitle() );
647 $this->assertEquals( $rev2->getSha1(), $page->getRevision()->getSha1(), "rollback did not revert to the correct revision" );
648 $this->assertEquals( "one\n\ntwo", $page->getContent()->getNativeData() );
651 public function dataGetAutosummary( ) {
654 'Hello there, world!',
657 '/^Redirected page .*Foo/'
664 '/^Created page .*Hello/'
668 'Hello there, world!',
675 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut
676 labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et
677 ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
680 '/^Replaced .*Hello/'
693 * @dataProvider dataGetAutoSummary
695 public function testGetAutosummary( $old, $new, $flags, $expected ) {
696 $page = $this->newPage( "WikiPageTest_testGetAutosummary" );
698 $summary = $page->getAutosummary( $old, $new, $flags );
700 $this->assertTrue( (bool)preg_match( $expected, $summary ), "Autosummary didn't match expected pattern $expected: $summary" );
703 public function dataGetAutoDeleteReason( ) {
713 array( "first edit", null ),
715 "/first edit.*only contributor/",
721 array( "first edit", null ),
722 array( "second edit", null ),
724 "/second edit.*only contributor/",
730 array( "first edit", "127.0.2.22" ),
731 array( "second edit", "127.0.3.33" ),
739 array( "first edit: "
740 . "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam "
741 . " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. "
742 . "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea "
743 . "takimata sanctus est Lorem ipsum dolor sit amet.'", null ),
745 '/first edit:.*\.\.\."/',
751 array( "first edit", "127.0.2.22" ),
752 array( "", "127.0.3.33" ),
754 "/before blanking.*first edit/",
762 * @dataProvider dataGetAutoDeleteReason
764 public function testGetAutoDeleteReason( $edits, $expectedResult, $expectedHistory ) {
767 $page = $this->newPage( "WikiPageTest_testGetAutoDeleteReason" );
771 foreach ( $edits as $edit ) {
774 if ( !empty( $edit[1] ) ) $user->setName( $edit[1] );
775 else $user = $wgUser;
777 $content = ContentHandler
::makeContent( $edit[0], $page->getTitle(), $page->getContentModel() );
779 $page->doEditContent( $content, "test edit $c", $c < 2 ? EDIT_NEW
: 0, false, $user );
784 $reason = $page->getAutoDeleteReason( $hasHistory );
786 if ( is_bool( $expectedResult ) ||
is_null( $expectedResult ) ) $this->assertEquals( $expectedResult, $reason );
787 else $this->assertTrue( (bool)preg_match( $expectedResult, $reason ), "Autosummary didn't match expected pattern $expectedResult: $reason" );
789 $this->assertEquals( $expectedHistory, $hasHistory, "expected \$hasHistory to be " . var_export( $expectedHistory, true ) );
791 $page->doDeleteArticle( "done" );
794 public function dataPreSaveTransform() {
796 array( 'hello this is ~~~',
797 "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
799 array( 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
800 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
806 * @dataProvider dataPreSaveTransform
808 public function testPreSaveTransform( $text, $expected ) {
810 $user->setName("127.0.0.1");
812 $page = $this->newPage( "WikiPageTest_testPreloadTransform" );
813 $text = $page->preSaveTransform( $text, $user );
815 $this->assertEquals( $expected, $text );