Merge "Change 'editfont' default preference to 'monospace'"
[lhc/web/wiklou.git] / tests / phpunit / includes / page / WikiPageTest.php
1 <?php
2
3 /**
4 * @group ContentHandler
5 * @group Database
6 * ^--- important, causes temporary tables to be used instead of the real database
7 * @group medium
8 */
9 class WikiPageTest extends MediaWikiLangTestCase {
10
11 protected $pages_to_delete;
12
13 function __construct( $name = null, array $data = [], $dataName = '' ) {
14 parent::__construct( $name, $data, $dataName );
15
16 $this->tablesUsed = array_merge(
17 $this->tablesUsed,
18 [ 'page',
19 'revision',
20 'text',
21
22 'recentchanges',
23 'logging',
24
25 'page_props',
26 'pagelinks',
27 'categorylinks',
28 'langlinks',
29 'externallinks',
30 'imagelinks',
31 'templatelinks',
32 'iwlinks' ] );
33 }
34
35 protected function setUp() {
36 parent::setUp();
37 $this->pages_to_delete = [];
38
39 LinkCache::singleton()->clear(); # avoid cached redirect status, etc
40 }
41
42 protected function tearDown() {
43 foreach ( $this->pages_to_delete as $p ) {
44 /* @var $p WikiPage */
45
46 try {
47 if ( $p->exists() ) {
48 $p->doDeleteArticle( "testing done." );
49 }
50 } catch ( MWException $ex ) {
51 // fail silently
52 }
53 }
54 parent::tearDown();
55 }
56
57 /**
58 * @param Title|string $title
59 * @param string|null $model
60 * @return WikiPage
61 */
62 protected function newPage( $title, $model = null ) {
63 if ( is_string( $title ) ) {
64 $ns = $this->getDefaultWikitextNS();
65 $title = Title::newFromText( $title, $ns );
66 }
67
68 $p = new WikiPage( $title );
69
70 $this->pages_to_delete[] = $p;
71
72 return $p;
73 }
74
75 /**
76 * @param string|Title|WikiPage $page
77 * @param string $text
78 * @param int $model
79 *
80 * @return WikiPage
81 */
82 protected function createPage( $page, $text, $model = null ) {
83 if ( is_string( $page ) || $page instanceof Title ) {
84 $page = $this->newPage( $page, $model );
85 }
86
87 $content = ContentHandler::makeContent( $text, $page->getTitle(), $model );
88 $page->doEditContent( $content, "testing", EDIT_NEW );
89
90 return $page;
91 }
92
93 /**
94 * @covers WikiPage::doEditContent
95 * @covers WikiPage::doModify
96 * @covers WikiPage::doCreate
97 * @covers WikiPage::doEditUpdates
98 */
99 public function testDoEditContent() {
100 $page = $this->newPage( "WikiPageTest_testDoEditContent" );
101 $title = $page->getTitle();
102
103 $content = ContentHandler::makeContent(
104 "[[Lorem ipsum]] dolor sit amet, consetetur sadipscing elitr, sed diam "
105 . " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
106 $title,
107 CONTENT_MODEL_WIKITEXT
108 );
109
110 $page->doEditContent( $content, "[[testing]] 1" );
111
112 $this->assertTrue( $title->getArticleID() > 0, "Title object should have new page id" );
113 $this->assertTrue( $page->getId() > 0, "WikiPage should have new page id" );
114 $this->assertTrue( $title->exists(), "Title object should indicate that the page now exists" );
115 $this->assertTrue( $page->exists(), "WikiPage object should indicate that the page now exists" );
116
117 $id = $page->getId();
118
119 # ------------------------
120 $dbr = wfGetDB( DB_REPLICA );
121 $res = $dbr->select( 'pagelinks', '*', [ 'pl_from' => $id ] );
122 $n = $res->numRows();
123 $res->free();
124
125 $this->assertEquals( 1, $n, 'pagelinks should contain one link from the page' );
126
127 # ------------------------
128 $page = new WikiPage( $title );
129
130 $retrieved = $page->getContent();
131 $this->assertTrue( $content->equals( $retrieved ), 'retrieved content doesn\'t equal original' );
132
133 # ------------------------
134 $content = ContentHandler::makeContent(
135 "At vero eos et accusam et justo duo [[dolores]] et ea rebum. "
136 . "Stet clita kasd [[gubergren]], no sea takimata sanctus est.",
137 $title,
138 CONTENT_MODEL_WIKITEXT
139 );
140
141 $page->doEditContent( $content, "testing 2" );
142
143 # ------------------------
144 $page = new WikiPage( $title );
145
146 $retrieved = $page->getContent();
147 $this->assertTrue( $content->equals( $retrieved ), 'retrieved content doesn\'t equal original' );
148
149 # ------------------------
150 $dbr = wfGetDB( DB_REPLICA );
151 $res = $dbr->select( 'pagelinks', '*', [ 'pl_from' => $id ] );
152 $n = $res->numRows();
153 $res->free();
154
155 $this->assertEquals( 2, $n, 'pagelinks should contain two links from the page' );
156 }
157
158 /**
159 * @covers WikiPage::doDeleteArticle
160 */
161 public function testDoDeleteArticle() {
162 $page = $this->createPage(
163 "WikiPageTest_testDoDeleteArticle",
164 "[[original text]] foo",
165 CONTENT_MODEL_WIKITEXT
166 );
167 $id = $page->getId();
168
169 $page->doDeleteArticle( "testing deletion" );
170
171 $this->assertFalse(
172 $page->getTitle()->getArticleID() > 0,
173 "Title object should now have page id 0"
174 );
175 $this->assertFalse( $page->getId() > 0, "WikiPage should now have page id 0" );
176 $this->assertFalse(
177 $page->exists(),
178 "WikiPage::exists should return false after page was deleted"
179 );
180 $this->assertNull(
181 $page->getContent(),
182 "WikiPage::getContent should return null after page was deleted"
183 );
184
185 $t = Title::newFromText( $page->getTitle()->getPrefixedText() );
186 $this->assertFalse(
187 $t->exists(),
188 "Title::exists should return false after page was deleted"
189 );
190
191 // Run the job queue
192 JobQueueGroup::destroySingletons();
193 $jobs = new RunJobs;
194 $jobs->loadParamsAndArgs( null, [ 'quiet' => true ], null );
195 $jobs->execute();
196
197 # ------------------------
198 $dbr = wfGetDB( DB_REPLICA );
199 $res = $dbr->select( 'pagelinks', '*', [ 'pl_from' => $id ] );
200 $n = $res->numRows();
201 $res->free();
202
203 $this->assertEquals( 0, $n, 'pagelinks should contain no more links from the page' );
204 }
205
206 /**
207 * @covers WikiPage::doDeleteUpdates
208 */
209 public function testDoDeleteUpdates() {
210 $page = $this->createPage(
211 "WikiPageTest_testDoDeleteArticle",
212 "[[original text]] foo",
213 CONTENT_MODEL_WIKITEXT
214 );
215 $id = $page->getId();
216
217 // Similar to MovePage logic
218 wfGetDB( DB_MASTER )->delete( 'page', [ 'page_id' => $id ], __METHOD__ );
219 $page->doDeleteUpdates( $id );
220
221 // Run the job queue
222 JobQueueGroup::destroySingletons();
223 $jobs = new RunJobs;
224 $jobs->loadParamsAndArgs( null, [ 'quiet' => true ], null );
225 $jobs->execute();
226
227 # ------------------------
228 $dbr = wfGetDB( DB_REPLICA );
229 $res = $dbr->select( 'pagelinks', '*', [ 'pl_from' => $id ] );
230 $n = $res->numRows();
231 $res->free();
232
233 $this->assertEquals( 0, $n, 'pagelinks should contain no more links from the page' );
234 }
235
236 /**
237 * @covers WikiPage::getRevision
238 */
239 public function testGetRevision() {
240 $page = $this->newPage( "WikiPageTest_testGetRevision" );
241
242 $rev = $page->getRevision();
243 $this->assertNull( $rev );
244
245 # -----------------
246 $this->createPage( $page, "some text", CONTENT_MODEL_WIKITEXT );
247
248 $rev = $page->getRevision();
249
250 $this->assertEquals( $page->getLatest(), $rev->getId() );
251 $this->assertEquals( "some text", $rev->getContent()->getNativeData() );
252 }
253
254 /**
255 * @covers WikiPage::getContent
256 */
257 public function testGetContent() {
258 $page = $this->newPage( "WikiPageTest_testGetContent" );
259
260 $content = $page->getContent();
261 $this->assertNull( $content );
262
263 # -----------------
264 $this->createPage( $page, "some text", CONTENT_MODEL_WIKITEXT );
265
266 $content = $page->getContent();
267 $this->assertEquals( "some text", $content->getNativeData() );
268 }
269
270 /**
271 * @covers WikiPage::getContentModel
272 */
273 public function testGetContentModel() {
274 global $wgContentHandlerUseDB;
275
276 if ( !$wgContentHandlerUseDB ) {
277 $this->markTestSkipped( '$wgContentHandlerUseDB is disabled' );
278 }
279
280 $page = $this->createPage(
281 "WikiPageTest_testGetContentModel",
282 "some text",
283 CONTENT_MODEL_JAVASCRIPT
284 );
285
286 $page = new WikiPage( $page->getTitle() );
287 $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $page->getContentModel() );
288 }
289
290 /**
291 * @covers WikiPage::getContentHandler
292 */
293 public function testGetContentHandler() {
294 global $wgContentHandlerUseDB;
295
296 if ( !$wgContentHandlerUseDB ) {
297 $this->markTestSkipped( '$wgContentHandlerUseDB is disabled' );
298 }
299
300 $page = $this->createPage(
301 "WikiPageTest_testGetContentHandler",
302 "some text",
303 CONTENT_MODEL_JAVASCRIPT
304 );
305
306 $page = new WikiPage( $page->getTitle() );
307 $this->assertEquals( 'JavaScriptContentHandler', get_class( $page->getContentHandler() ) );
308 }
309
310 /**
311 * @covers WikiPage::exists
312 */
313 public function testExists() {
314 $page = $this->newPage( "WikiPageTest_testExists" );
315 $this->assertFalse( $page->exists() );
316
317 # -----------------
318 $this->createPage( $page, "some text", CONTENT_MODEL_WIKITEXT );
319 $this->assertTrue( $page->exists() );
320
321 $page = new WikiPage( $page->getTitle() );
322 $this->assertTrue( $page->exists() );
323
324 # -----------------
325 $page->doDeleteArticle( "done testing" );
326 $this->assertFalse( $page->exists() );
327
328 $page = new WikiPage( $page->getTitle() );
329 $this->assertFalse( $page->exists() );
330 }
331
332 public static function provideHasViewableContent() {
333 return [
334 [ 'WikiPageTest_testHasViewableContent', false, true ],
335 [ 'Special:WikiPageTest_testHasViewableContent', false ],
336 [ 'MediaWiki:WikiPageTest_testHasViewableContent', false ],
337 [ 'Special:Userlogin', true ],
338 [ 'MediaWiki:help', true ],
339 ];
340 }
341
342 /**
343 * @dataProvider provideHasViewableContent
344 * @covers WikiPage::hasViewableContent
345 */
346 public function testHasViewableContent( $title, $viewable, $create = false ) {
347 $page = $this->newPage( $title );
348 $this->assertEquals( $viewable, $page->hasViewableContent() );
349
350 if ( $create ) {
351 $this->createPage( $page, "some text", CONTENT_MODEL_WIKITEXT );
352 $this->assertTrue( $page->hasViewableContent() );
353
354 $page = new WikiPage( $page->getTitle() );
355 $this->assertTrue( $page->hasViewableContent() );
356 }
357 }
358
359 public static function provideGetRedirectTarget() {
360 return [
361 [ 'WikiPageTest_testGetRedirectTarget_1', CONTENT_MODEL_WIKITEXT, "hello world", null ],
362 [
363 'WikiPageTest_testGetRedirectTarget_2',
364 CONTENT_MODEL_WIKITEXT,
365 "#REDIRECT [[hello world]]",
366 "Hello world"
367 ],
368 ];
369 }
370
371 /**
372 * @dataProvider provideGetRedirectTarget
373 * @covers WikiPage::getRedirectTarget
374 */
375 public function testGetRedirectTarget( $title, $model, $text, $target ) {
376 $this->setMwGlobals( [
377 'wgCapitalLinks' => true,
378 ] );
379
380 $page = $this->createPage( $title, $text, $model );
381
382 # sanity check, because this test seems to fail for no reason for some people.
383 $c = $page->getContent();
384 $this->assertEquals( 'WikitextContent', get_class( $c ) );
385
386 # now, test the actual redirect
387 $t = $page->getRedirectTarget();
388 $this->assertEquals( $target, is_null( $t ) ? null : $t->getPrefixedText() );
389 }
390
391 /**
392 * @dataProvider provideGetRedirectTarget
393 * @covers WikiPage::isRedirect
394 */
395 public function testIsRedirect( $title, $model, $text, $target ) {
396 $page = $this->createPage( $title, $text, $model );
397 $this->assertEquals( !is_null( $target ), $page->isRedirect() );
398 }
399
400 public static function provideIsCountable() {
401 return [
402
403 // any
404 [ 'WikiPageTest_testIsCountable',
405 CONTENT_MODEL_WIKITEXT,
406 '',
407 'any',
408 true
409 ],
410 [ 'WikiPageTest_testIsCountable',
411 CONTENT_MODEL_WIKITEXT,
412 'Foo',
413 'any',
414 true
415 ],
416
417 // comma
418 [ 'WikiPageTest_testIsCountable',
419 CONTENT_MODEL_WIKITEXT,
420 'Foo',
421 'comma',
422 false
423 ],
424 [ 'WikiPageTest_testIsCountable',
425 CONTENT_MODEL_WIKITEXT,
426 'Foo, bar',
427 'comma',
428 true
429 ],
430
431 // link
432 [ 'WikiPageTest_testIsCountable',
433 CONTENT_MODEL_WIKITEXT,
434 'Foo',
435 'link',
436 false
437 ],
438 [ 'WikiPageTest_testIsCountable',
439 CONTENT_MODEL_WIKITEXT,
440 'Foo [[bar]]',
441 'link',
442 true
443 ],
444
445 // redirects
446 [ 'WikiPageTest_testIsCountable',
447 CONTENT_MODEL_WIKITEXT,
448 '#REDIRECT [[bar]]',
449 'any',
450 false
451 ],
452 [ 'WikiPageTest_testIsCountable',
453 CONTENT_MODEL_WIKITEXT,
454 '#REDIRECT [[bar]]',
455 'comma',
456 false
457 ],
458 [ 'WikiPageTest_testIsCountable',
459 CONTENT_MODEL_WIKITEXT,
460 '#REDIRECT [[bar]]',
461 'link',
462 false
463 ],
464
465 // not a content namespace
466 [ 'Talk:WikiPageTest_testIsCountable',
467 CONTENT_MODEL_WIKITEXT,
468 'Foo',
469 'any',
470 false
471 ],
472 [ 'Talk:WikiPageTest_testIsCountable',
473 CONTENT_MODEL_WIKITEXT,
474 'Foo, bar',
475 'comma',
476 false
477 ],
478 [ 'Talk:WikiPageTest_testIsCountable',
479 CONTENT_MODEL_WIKITEXT,
480 'Foo [[bar]]',
481 'link',
482 false
483 ],
484
485 // not a content namespace, different model
486 [ 'MediaWiki:WikiPageTest_testIsCountable.js',
487 null,
488 'Foo',
489 'any',
490 false
491 ],
492 [ 'MediaWiki:WikiPageTest_testIsCountable.js',
493 null,
494 'Foo, bar',
495 'comma',
496 false
497 ],
498 [ 'MediaWiki:WikiPageTest_testIsCountable.js',
499 null,
500 'Foo [[bar]]',
501 'link',
502 false
503 ],
504 ];
505 }
506
507 /**
508 * @dataProvider provideIsCountable
509 * @covers WikiPage::isCountable
510 */
511 public function testIsCountable( $title, $model, $text, $mode, $expected ) {
512 global $wgContentHandlerUseDB;
513
514 $this->setMwGlobals( 'wgArticleCountMethod', $mode );
515
516 $title = Title::newFromText( $title );
517
518 if ( !$wgContentHandlerUseDB
519 && $model
520 && ContentHandler::getDefaultModelFor( $title ) != $model
521 ) {
522 $this->markTestSkipped( "Can not use non-default content model $model for "
523 . $title->getPrefixedDBkey() . " with \$wgContentHandlerUseDB disabled." );
524 }
525
526 $page = $this->createPage( $title, $text, $model );
527
528 $editInfo = $page->prepareContentForEdit( $page->getContent() );
529
530 $v = $page->isCountable();
531 $w = $page->isCountable( $editInfo );
532
533 $this->assertEquals(
534 $expected,
535 $v,
536 "isCountable( null ) returned unexpected value " . var_export( $v, true )
537 . " instead of " . var_export( $expected, true )
538 . " in mode `$mode` for text \"$text\""
539 );
540
541 $this->assertEquals(
542 $expected,
543 $w,
544 "isCountable( \$editInfo ) returned unexpected value " . var_export( $v, true )
545 . " instead of " . var_export( $expected, true )
546 . " in mode `$mode` for text \"$text\""
547 );
548 }
549
550 public static function provideGetParserOutput() {
551 return [
552 [
553 CONTENT_MODEL_WIKITEXT,
554 "hello ''world''\n",
555 "<div class=\"mw-parser-output\"><p>hello <i>world</i></p></div>"
556 ],
557 // @todo more...?
558 ];
559 }
560
561 /**
562 * @dataProvider provideGetParserOutput
563 * @covers WikiPage::getParserOutput
564 */
565 public function testGetParserOutput( $model, $text, $expectedHtml ) {
566 $page = $this->createPage( 'WikiPageTest_testGetParserOutput', $text, $model );
567
568 $opt = $page->makeParserOptions( 'canonical' );
569 $po = $page->getParserOutput( $opt );
570 $text = $po->getText();
571
572 $text = trim( preg_replace( '/<!--.*?-->/sm', '', $text ) ); # strip injected comments
573 $text = preg_replace( '!\s*(</p>|</div>)!sm', '\1', $text ); # don't let tidy confuse us
574
575 $this->assertEquals( $expectedHtml, $text );
576
577 return $po;
578 }
579
580 /**
581 * @covers WikiPage::getParserOutput
582 */
583 public function testGetParserOutput_nonexisting() {
584 static $count = 0;
585 $count++;
586
587 $page = new WikiPage( new Title( "WikiPageTest_testGetParserOutput_nonexisting_$count" ) );
588
589 $opt = new ParserOptions();
590 $po = $page->getParserOutput( $opt );
591
592 $this->assertFalse( $po, "getParserOutput() shall return false for non-existing pages." );
593 }
594
595 /**
596 * @covers WikiPage::getParserOutput
597 */
598 public function testGetParserOutput_badrev() {
599 $page = $this->createPage( 'WikiPageTest_testGetParserOutput', "dummy", CONTENT_MODEL_WIKITEXT );
600
601 $opt = new ParserOptions();
602 $po = $page->getParserOutput( $opt, $page->getLatest() + 1234 );
603
604 // @todo would be neat to also test deleted revision
605
606 $this->assertFalse( $po, "getParserOutput() shall return false for non-existing revisions." );
607 }
608
609 public static $sections =
610
611 "Intro
612
613 == stuff ==
614 hello world
615
616 == test ==
617 just a test
618
619 == foo ==
620 more stuff
621 ";
622
623 public function dataReplaceSection() {
624 // NOTE: assume the Help namespace to contain wikitext
625 return [
626 [ 'Help:WikiPageTest_testReplaceSection',
627 CONTENT_MODEL_WIKITEXT,
628 self::$sections,
629 "0",
630 "No more",
631 null,
632 trim( preg_replace( '/^Intro/sm', 'No more', self::$sections ) )
633 ],
634 [ 'Help:WikiPageTest_testReplaceSection',
635 CONTENT_MODEL_WIKITEXT,
636 self::$sections,
637 "",
638 "No more",
639 null,
640 "No more"
641 ],
642 [ 'Help:WikiPageTest_testReplaceSection',
643 CONTENT_MODEL_WIKITEXT,
644 self::$sections,
645 "2",
646 "== TEST ==\nmore fun",
647 null,
648 trim( preg_replace( '/^== test ==.*== foo ==/sm',
649 "== TEST ==\nmore fun\n\n== foo ==",
650 self::$sections ) )
651 ],
652 [ 'Help:WikiPageTest_testReplaceSection',
653 CONTENT_MODEL_WIKITEXT,
654 self::$sections,
655 "8",
656 "No more",
657 null,
658 trim( self::$sections )
659 ],
660 [ 'Help:WikiPageTest_testReplaceSection',
661 CONTENT_MODEL_WIKITEXT,
662 self::$sections,
663 "new",
664 "No more",
665 "New",
666 trim( self::$sections ) . "\n\n== New ==\n\nNo more"
667 ],
668 ];
669 }
670
671 /**
672 * @dataProvider dataReplaceSection
673 * @covers WikiPage::replaceSectionContent
674 */
675 public function testReplaceSectionContent( $title, $model, $text, $section,
676 $with, $sectionTitle, $expected
677 ) {
678 $page = $this->createPage( $title, $text, $model );
679
680 $content = ContentHandler::makeContent( $with, $page->getTitle(), $page->getContentModel() );
681 $c = $page->replaceSectionContent( $section, $content, $sectionTitle );
682
683 $this->assertEquals( $expected, is_null( $c ) ? null : trim( $c->getNativeData() ) );
684 }
685
686 /**
687 * @dataProvider dataReplaceSection
688 * @covers WikiPage::replaceSectionAtRev
689 */
690 public function testReplaceSectionAtRev( $title, $model, $text, $section,
691 $with, $sectionTitle, $expected
692 ) {
693 $page = $this->createPage( $title, $text, $model );
694 $baseRevId = $page->getLatest();
695
696 $content = ContentHandler::makeContent( $with, $page->getTitle(), $page->getContentModel() );
697 $c = $page->replaceSectionAtRev( $section, $content, $sectionTitle, $baseRevId );
698
699 $this->assertEquals( $expected, is_null( $c ) ? null : trim( $c->getNativeData() ) );
700 }
701
702 /* @todo FIXME: fix this!
703 public function testGetUndoText() {
704 $this->markTestSkippedIfNoDiff3();
705
706 $text = "one";
707 $page = $this->createPage( "WikiPageTest_testGetUndoText", $text );
708 $rev1 = $page->getRevision();
709
710 $text .= "\n\ntwo";
711 $page->doEditContent(
712 ContentHandler::makeContent( $text, $page->getTitle() ),
713 "adding section two"
714 );
715 $rev2 = $page->getRevision();
716
717 $text .= "\n\nthree";
718 $page->doEditContent(
719 ContentHandler::makeContent( $text, $page->getTitle() ),
720 "adding section three"
721 );
722 $rev3 = $page->getRevision();
723
724 $text .= "\n\nfour";
725 $page->doEditContent(
726 ContentHandler::makeContent( $text, $page->getTitle() ),
727 "adding section four"
728 );
729 $rev4 = $page->getRevision();
730
731 $text .= "\n\nfive";
732 $page->doEditContent(
733 ContentHandler::makeContent( $text, $page->getTitle() ),
734 "adding section five"
735 );
736 $rev5 = $page->getRevision();
737
738 $text .= "\n\nsix";
739 $page->doEditContent(
740 ContentHandler::makeContent( $text, $page->getTitle() ),
741 "adding section six"
742 );
743 $rev6 = $page->getRevision();
744
745 $undo6 = $page->getUndoText( $rev6 );
746 if ( $undo6 === false ) $this->fail( "getUndoText failed for rev6" );
747 $this->assertEquals( "one\n\ntwo\n\nthree\n\nfour\n\nfive", $undo6 );
748
749 $undo3 = $page->getUndoText( $rev4, $rev2 );
750 if ( $undo3 === false ) $this->fail( "getUndoText failed for rev4..rev2" );
751 $this->assertEquals( "one\n\ntwo\n\nfive", $undo3 );
752
753 $undo2 = $page->getUndoText( $rev2 );
754 if ( $undo2 === false ) $this->fail( "getUndoText failed for rev2" );
755 $this->assertEquals( "one\n\nfive", $undo2 );
756 }
757 */
758
759 /**
760 * @covers WikiPage::getOldestRevision
761 */
762 public function testGetOldestRevision() {
763 $page = $this->newPage( "WikiPageTest_testGetOldestRevision" );
764 $page->doEditContent(
765 new WikitextContent( 'one' ),
766 "first edit",
767 EDIT_NEW
768 );
769 $rev1 = $page->getRevision();
770
771 $page = new WikiPage( $page->getTitle() );
772 $page->doEditContent(
773 new WikitextContent( 'two' ),
774 "second edit",
775 EDIT_UPDATE
776 );
777
778 $page = new WikiPage( $page->getTitle() );
779 $page->doEditContent(
780 new WikitextContent( 'three' ),
781 "third edit",
782 EDIT_UPDATE
783 );
784
785 // sanity check
786 $this->assertNotEquals(
787 $rev1->getId(),
788 $page->getRevision()->getId(),
789 '$page->getRevision()->getId()'
790 );
791
792 // actual test
793 $this->assertEquals(
794 $rev1->getId(),
795 $page->getOldestRevision()->getId(),
796 '$page->getOldestRevision()->getId()'
797 );
798 }
799
800 /**
801 * @todo FIXME: this is a better rollback test than the one below, but it
802 * keeps failing in jenkins for some reason.
803 */
804 public function broken_testDoRollback() {
805 $admin = new User();
806 $admin->setName( "Admin" );
807
808 $text = "one";
809 $page = $this->newPage( "WikiPageTest_testDoRollback" );
810 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ),
811 "section one", EDIT_NEW, false, $admin );
812
813 $user1 = new User();
814 $user1->setName( "127.0.1.11" );
815 $text .= "\n\ntwo";
816 $page = new WikiPage( $page->getTitle() );
817 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ),
818 "adding section two", 0, false, $user1 );
819
820 $user2 = new User();
821 $user2->setName( "127.0.2.13" );
822 $text .= "\n\nthree";
823 $page = new WikiPage( $page->getTitle() );
824 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ),
825 "adding section three", 0, false, $user2 );
826
827 # we are having issues with doRollback spuriously failing. Apparently
828 # the last revision somehow goes missing or not committed under some
829 # circumstances. So, make sure the last revision has the right user name.
830 $dbr = wfGetDB( DB_REPLICA );
831 $this->assertEquals( 3, Revision::countByPageId( $dbr, $page->getId() ) );
832
833 $page = new WikiPage( $page->getTitle() );
834 $rev3 = $page->getRevision();
835 $this->assertEquals( '127.0.2.13', $rev3->getUserText() );
836
837 $rev2 = $rev3->getPrevious();
838 $this->assertEquals( '127.0.1.11', $rev2->getUserText() );
839
840 $rev1 = $rev2->getPrevious();
841 $this->assertEquals( 'Admin', $rev1->getUserText() );
842
843 # now, try the actual rollback
844 $admin->addToDatabase();
845 $admin->addGroup( "sysop" ); # XXX: make the test user a sysop...
846 $token = $admin->getEditToken(
847 [ $page->getTitle()->getPrefixedText(), $user2->getName() ],
848 null
849 );
850 $errors = $page->doRollback(
851 $user2->getName(),
852 "testing revert",
853 $token,
854 false,
855 $details,
856 $admin
857 );
858
859 if ( $errors ) {
860 $this->fail( "Rollback failed:\n" . print_r( $errors, true )
861 . ";\n" . print_r( $details, true ) );
862 }
863
864 $page = new WikiPage( $page->getTitle() );
865 $this->assertEquals( $rev2->getSha1(), $page->getRevision()->getSha1(),
866 "rollback did not revert to the correct revision" );
867 $this->assertEquals( "one\n\ntwo", $page->getContent()->getNativeData() );
868 }
869
870 /**
871 * @todo FIXME: the above rollback test is better, but it keeps failing in jenkins for some reason.
872 * @covers WikiPage::doRollback
873 */
874 public function testDoRollback() {
875 $admin = new User();
876 $admin->setName( "Admin" );
877 $admin->addToDatabase();
878
879 $text = "one";
880 $page = $this->newPage( "WikiPageTest_testDoRollback" );
881 $page->doEditContent(
882 ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ),
883 "section one",
884 EDIT_NEW,
885 false,
886 $admin
887 );
888 $rev1 = $page->getRevision();
889
890 $user1 = new User();
891 $user1->setName( "127.0.1.11" );
892 $text .= "\n\ntwo";
893 $page = new WikiPage( $page->getTitle() );
894 $page->doEditContent(
895 ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ),
896 "adding section two",
897 0,
898 false,
899 $user1
900 );
901
902 # now, try the rollback
903 $admin->addGroup( "sysop" ); # XXX: make the test user a sysop...
904 $token = $admin->getEditToken( 'rollback' );
905 $errors = $page->doRollback(
906 $user1->getName(),
907 "testing revert",
908 $token,
909 false,
910 $details,
911 $admin
912 );
913
914 if ( $errors ) {
915 $this->fail( "Rollback failed:\n" . print_r( $errors, true )
916 . ";\n" . print_r( $details, true ) );
917 }
918
919 $page = new WikiPage( $page->getTitle() );
920 $this->assertEquals( $rev1->getSha1(), $page->getRevision()->getSha1(),
921 "rollback did not revert to the correct revision" );
922 $this->assertEquals( "one", $page->getContent()->getNativeData() );
923 }
924
925 /**
926 * @covers WikiPage::doRollback
927 */
928 public function testDoRollbackFailureSameContent() {
929 $admin = new User();
930 $admin->setName( "Admin" );
931 $admin->addToDatabase();
932 $admin->addGroup( "sysop" ); # XXX: make the test user a sysop...
933
934 $text = "one";
935 $page = $this->newPage( "WikiPageTest_testDoRollback" );
936 $page->doEditContent(
937 ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ),
938 "section one",
939 EDIT_NEW,
940 false,
941 $admin
942 );
943 $rev1 = $page->getRevision();
944
945 $user1 = new User();
946 $user1->setName( "127.0.1.11" );
947 $user1->addToDatabase();
948 $user1->addGroup( "sysop" ); # XXX: make the test user a sysop...
949 $text .= "\n\ntwo";
950 $page = new WikiPage( $page->getTitle() );
951 $page->doEditContent(
952 ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ),
953 "adding section two",
954 0,
955 false,
956 $user1
957 );
958
959 # now, do a the rollback from the same user was doing the edit before
960 $resultDetails = [];
961 $token = $user1->getEditToken( 'rollback' );
962 $errors = $page->doRollback(
963 $user1->getName(),
964 "testing revert same user",
965 $token,
966 false,
967 $resultDetails,
968 $admin
969 );
970
971 $this->assertEquals( [], $errors, "Rollback failed same user" );
972
973 # now, try the rollback
974 $resultDetails = [];
975 $token = $admin->getEditToken( 'rollback' );
976 $errors = $page->doRollback(
977 $user1->getName(),
978 "testing revert",
979 $token,
980 false,
981 $resultDetails,
982 $admin
983 );
984
985 $this->assertEquals( [ [ 'alreadyrolled', 'WikiPageTest testDoRollback',
986 '127.0.1.11', 'Admin' ] ], $errors, "Rollback not failed" );
987
988 $page = new WikiPage( $page->getTitle() );
989 $this->assertEquals( $rev1->getSha1(), $page->getRevision()->getSha1(),
990 "rollback did not revert to the correct revision" );
991 $this->assertEquals( "one", $page->getContent()->getNativeData() );
992 }
993
994 public static function provideGetAutoDeleteReason() {
995 return [
996 [
997 [],
998 false,
999 false
1000 ],
1001
1002 [
1003 [
1004 [ "first edit", null ],
1005 ],
1006 "/first edit.*only contributor/",
1007 false
1008 ],
1009
1010 [
1011 [
1012 [ "first edit", null ],
1013 [ "second edit", null ],
1014 ],
1015 "/second edit.*only contributor/",
1016 true
1017 ],
1018
1019 [
1020 [
1021 [ "first edit", "127.0.2.22" ],
1022 [ "second edit", "127.0.3.33" ],
1023 ],
1024 "/second edit/",
1025 true
1026 ],
1027
1028 [
1029 [
1030 [
1031 "first edit: "
1032 . "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam "
1033 . " nonumy eirmod tempor invidunt ut labore et dolore magna "
1034 . "aliquyam erat, sed diam voluptua. At vero eos et accusam "
1035 . "et justo duo dolores et ea rebum. Stet clita kasd gubergren, "
1036 . "no sea takimata sanctus est Lorem ipsum dolor sit amet.'",
1037 null
1038 ],
1039 ],
1040 '/first edit:.*\.\.\."/',
1041 false
1042 ],
1043
1044 [
1045 [
1046 [ "first edit", "127.0.2.22" ],
1047 [ "", "127.0.3.33" ],
1048 ],
1049 "/before blanking.*first edit/",
1050 true
1051 ],
1052
1053 ];
1054 }
1055
1056 /**
1057 * @dataProvider provideGetAutoDeleteReason
1058 * @covers WikiPage::getAutoDeleteReason
1059 */
1060 public function testGetAutoDeleteReason( $edits, $expectedResult, $expectedHistory ) {
1061 global $wgUser;
1062
1063 // NOTE: assume Help namespace to contain wikitext
1064 $page = $this->newPage( "Help:WikiPageTest_testGetAutoDeleteReason" );
1065
1066 $c = 1;
1067
1068 foreach ( $edits as $edit ) {
1069 $user = new User();
1070
1071 if ( !empty( $edit[1] ) ) {
1072 $user->setName( $edit[1] );
1073 } else {
1074 $user = $wgUser;
1075 }
1076
1077 $content = ContentHandler::makeContent( $edit[0], $page->getTitle(), $page->getContentModel() );
1078
1079 $page->doEditContent( $content, "test edit $c", $c < 2 ? EDIT_NEW : 0, false, $user );
1080
1081 $c += 1;
1082 }
1083
1084 $reason = $page->getAutoDeleteReason( $hasHistory );
1085
1086 if ( is_bool( $expectedResult ) || is_null( $expectedResult ) ) {
1087 $this->assertEquals( $expectedResult, $reason );
1088 } else {
1089 $this->assertTrue( (bool)preg_match( $expectedResult, $reason ),
1090 "Autosummary didn't match expected pattern $expectedResult: $reason" );
1091 }
1092
1093 $this->assertEquals( $expectedHistory, $hasHistory,
1094 "expected \$hasHistory to be " . var_export( $expectedHistory, true ) );
1095
1096 $page->doDeleteArticle( "done" );
1097 }
1098
1099 public static function providePreSaveTransform() {
1100 return [
1101 [ 'hello this is ~~~',
1102 "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
1103 ],
1104 [ 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
1105 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
1106 ],
1107 ];
1108 }
1109
1110 /**
1111 * @covers WikiPage::factory
1112 */
1113 public function testWikiPageFactory() {
1114 $title = Title::makeTitle( NS_FILE, 'Someimage.png' );
1115 $page = WikiPage::factory( $title );
1116 $this->assertEquals( 'WikiFilePage', get_class( $page ) );
1117
1118 $title = Title::makeTitle( NS_CATEGORY, 'SomeCategory' );
1119 $page = WikiPage::factory( $title );
1120 $this->assertEquals( 'WikiCategoryPage', get_class( $page ) );
1121
1122 $title = Title::makeTitle( NS_MAIN, 'SomePage' );
1123 $page = WikiPage::factory( $title );
1124 $this->assertEquals( 'WikiPage', get_class( $page ) );
1125 }
1126 }