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