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