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