merged from master
[lhc/web/wiklou.git] / tests / phpunit / includes / WikiPageTest.php
1 <?php
2 /**
3 * @group Database
4 * ^--- important, causes temporary tables to be used instead of the real database
5 **/
6
7 class WikiPageTest extends MediaWikiTestCase {
8
9 var $pages_to_delete;
10
11 public function setUp() {
12 $this->pages_to_delete = array();
13 }
14
15 public function tearDown() {
16 foreach ( $this->pages_to_delete as $p ) {
17 /* @var $p WikiPage */
18
19 try {
20 if ( $p->exists() ) {
21 $p->doDeleteArticle( "testing done." );
22 }
23 } catch ( MWException $ex ) {
24 // fail silently
25 }
26 }
27 }
28
29 protected function newPage( $title ) {
30 if ( is_string( $title ) ) $title = Title::newFromText( $title );
31
32 $p = new WikiPage( $title );
33
34 $this->pages_to_delete[] = $p;
35
36 return $p;
37 }
38
39 protected function createPage( $page, $text, $model = null ) {
40 if ( is_string( $page ) ) $page = Title::newFromText( $page );
41 if ( $page instanceof Title ) $page = $this->newPage( $page );
42
43 $content = ContentHandler::makeContent( $text, $page->getTitle(), $model );
44 $page->doEditContent( $content, "testing" );
45
46 return $page;
47 }
48
49 public function testDoEditContent() {
50 $title = Title::newFromText( "WikiPageTest_testDoEditContent" );
51
52 $page = $this->newPage( $title );
53
54 $content = ContentHandler::makeContent( "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam "
55 . " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.",
56 $title );
57
58 $page->doEditContent( $content, "testing 1" );
59
60 $this->assertTrue( $title->exists(), "Title object should indicate that the page now exists" );
61 $this->assertTrue( $page->exists(), "WikiPage object should indicate that the page now exists" );
62
63 # ------------------------
64 $page = new WikiPage( $title );
65
66 $retrieved = $page->getContent();
67 $this->assertTrue( $content->equals( $retrieved ), 'retrieved content doesn\'t equal original' );
68
69 # ------------------------
70 $content = ContentHandler::makeContent( "At vero eos et accusam et justo duo dolores et ea rebum. "
71 . "Stet clita kasd gubergren, no sea takimata sanctus est.",
72 $title );
73
74 $page->doEditContent( $content, "testing 2" );
75
76 # ------------------------
77 $page = new WikiPage( $title );
78
79 $retrieved = $page->getContent();
80 $this->assertTrue( $content->equals( $retrieved ), 'retrieved content doesn\'t equal original' );
81 }
82
83 public function testDoEdit() {
84 $title = Title::newFromText( "WikiPageTest_testDoEdit" );
85
86 $page = $this->newPage( $title );
87
88 $text = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam "
89 . " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.";
90
91 $page->doEdit( $text, "testing 1" );
92
93 $this->assertTrue( $title->exists(), "Title object should indicate that the page now exists" );
94 $this->assertTrue( $page->exists(), "WikiPage object should indicate that the page now exists" );
95
96 # ------------------------
97 $page = new WikiPage( $title );
98
99 $retrieved = $page->getText();
100 $this->assertEquals( $text, $retrieved, 'retrieved text doesn\'t equal original' );
101
102 # ------------------------
103 $text = "At vero eos et accusam et justo duo dolores et ea rebum. "
104 . "Stet clita kasd gubergren, no sea takimata sanctus est.";
105
106 $page->doEdit( $text, "testing 2" );
107
108 # ------------------------
109 $page = new WikiPage( $title );
110
111 $retrieved = $page->getText();
112 $this->assertEquals( $text, $retrieved, 'retrieved text doesn\'t equal original' );
113 }
114
115 public function testDoQuickEdit() {
116 global $wgUser;
117
118 $page = $this->createPage( "WikiPageTest_testDoQuickEdit", "original text" );
119
120 $text = "quick text";
121 $page->doQuickEdit( $text, $wgUser, "testing q" );
122
123 # ---------------------
124 $page = new WikiPage( $page->getTitle() );
125 $this->assertEquals( $text, $page->getText() );
126 }
127
128 public function testDoQuickEditContent() {
129 global $wgUser;
130
131 $page = $this->createPage( "WikiPageTest_testDoQuickEditContent", "original text" );
132
133 $content = ContentHandler::makeContent( "quick text", $page->getTitle() );
134 $page->doQuickEditContent( $content, $wgUser, "testing q" );
135
136 # ---------------------
137 $page = new WikiPage( $page->getTitle() );
138 $this->assertTrue( $content->equals( $page->getContent() ) );
139 }
140
141 public function testDoDeleteArticle() {
142 $page = $this->createPage( "WikiPageTest_testDoDeleteArticle", "original text" );
143
144 $page->doDeleteArticle( "testing deletion" );
145
146 $this->assertFalse( $page->exists() );
147
148 $this->assertNull( $page->getContent() );
149 $this->assertFalse( $page->getText() );
150
151 $t = Title::newFromText( $page->getTitle()->getPrefixedText() );
152 $this->assertFalse( $t->exists() );
153 }
154
155 public function testGetRevision() {
156 $page = $this->newPage( "WikiPageTest_testGetRevision" );
157
158 $rev = $page->getRevision();
159 $this->assertNull( $rev );
160
161 # -----------------
162 $this->createPage( $page, "some text" );
163
164 $rev = $page->getRevision();
165
166 $this->assertEquals( $page->getLatest(), $rev->getId() );
167 $this->assertEquals( "some text", $rev->getContent()->getNativeData() );
168 }
169
170 public function testGetContent() {
171 $page = $this->newPage( "WikiPageTest_testGetContent" );
172
173 $content = $page->getContent();
174 $this->assertNull( $content );
175
176 # -----------------
177 $this->createPage( $page, "some text" );
178
179 $content = $page->getContent();
180 $this->assertEquals( "some text", $content->getNativeData() );
181 }
182
183 public function testGetText() {
184 $page = $this->newPage( "WikiPageTest_testGetText" );
185
186 $text = $page->getText();
187 $this->assertFalse( $text );
188
189 # -----------------
190 $this->createPage( $page, "some text" );
191
192 $text = $page->getText();
193 $this->assertEquals( "some text", $text );
194 }
195
196 public function testGetRawText() {
197 $page = $this->newPage( "WikiPageTest_testGetRawText" );
198
199 $text = $page->getRawText();
200 $this->assertFalse( $text );
201
202 # -----------------
203 $this->createPage( $page, "some text" );
204
205 $text = $page->getRawText();
206 $this->assertEquals( "some text", $text );
207 }
208
209 public function testGetContentModelName() {
210 $page = $this->createPage( "WikiPageTest_testGetContentModelName", "some text", CONTENT_MODEL_JAVASCRIPT );
211
212 $page = new WikiPage( $page->getTitle() );
213 $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $page->getContentModelName() );
214 }
215
216 public function testGetContentHandler() {
217 $page = $this->createPage( "WikiPageTest_testGetContentHandler", "some text", CONTENT_MODEL_JAVASCRIPT );
218
219 $page = new WikiPage( $page->getTitle() );
220 $this->assertEquals( 'JavaScriptContentHandler', get_class( $page->getContentHandler() ) );
221 }
222
223 public function testExists() {
224 $page = $this->newPage( "WikiPageTest_testExists" );
225 $this->assertFalse( $page->exists() );
226
227 # -----------------
228 $this->createPage( $page, "some text" );
229 $this->assertTrue( $page->exists() );
230
231 $page = new WikiPage( $page->getTitle() );
232 $this->assertTrue( $page->exists() );
233
234 # -----------------
235 $page->doDeleteArticle( "done testing" );
236 $this->assertFalse( $page->exists() );
237
238 $page = new WikiPage( $page->getTitle() );
239 $this->assertFalse( $page->exists() );
240 }
241
242 public function dataHasViewableContent() {
243 return array(
244 array( 'WikiPageTest_testHasViewableContent', false, true ),
245 array( 'Special:WikiPageTest_testHasViewableContent', false ),
246 array( 'MediaWiki:WikiPageTest_testHasViewableContent', false ),
247 array( 'Special:Userlogin', true ),
248 array( 'MediaWiki:help', true ),
249 );
250 }
251
252 /**
253 * @dataProvider dataHasViewableContent
254 */
255 public function testHasViewableContent( $title, $viewable, $create = false ) {
256 $page = $this->newPage( $title );
257 $this->assertEquals( $viewable, $page->hasViewableContent() );
258
259 if ( $create ) {
260 $this->createPage( $page, "some text" );
261 $this->assertTrue( $page->hasViewableContent() );
262
263 $page = new WikiPage( $page->getTitle() );
264 $this->assertTrue( $page->hasViewableContent() );
265 }
266 }
267
268 public function dataGetRedirectTarget() {
269 return array(
270 array( 'WikiPageTest_testGetRedirectTarget_1', "hello world", null ),
271 array( 'WikiPageTest_testGetRedirectTarget_2', "#REDIRECT [[hello world]]", "Hello world" ),
272 );
273 }
274
275 /**
276 * @dataProvider dataGetRedirectTarget
277 */
278 public function testGetRedirectTarget( $title, $text, $target ) {
279 $page = $this->createPage( $title, $text );
280
281 $t = $page->getRedirectTarget();
282 $this->assertEquals( $target, is_null( $t ) ? null : $t->getPrefixedText() );
283 }
284
285 /**
286 * @dataProvider dataGetRedirectTarget
287 */
288 public function testIsRedirect( $title, $text, $target ) {
289 $page = $this->createPage( $title, $text );
290 $this->assertEquals( !is_null( $target ), $page->isRedirect() );
291 }
292
293 public function dataIsCountable() {
294 return array(
295
296 // any
297 array( 'WikiPageTest_testIsCountable',
298 '',
299 'any',
300 true
301 ),
302 array( 'WikiPageTest_testIsCountable',
303 'Foo',
304 'any',
305 true
306 ),
307
308 // comma
309 array( 'WikiPageTest_testIsCountable',
310 'Foo',
311 'comma',
312 false
313 ),
314 array( 'WikiPageTest_testIsCountable',
315 'Foo, bar',
316 'comma',
317 true
318 ),
319
320 // link
321 array( 'WikiPageTest_testIsCountable',
322 'Foo',
323 'link',
324 false
325 ),
326 array( 'WikiPageTest_testIsCountable',
327 'Foo [[bar]]',
328 'link',
329 true
330 ),
331
332 // redirects
333 array( 'WikiPageTest_testIsCountable',
334 '#REDIRECT [[bar]]',
335 'any',
336 false
337 ),
338 array( 'WikiPageTest_testIsCountable',
339 '#REDIRECT [[bar]]',
340 'comma',
341 false
342 ),
343 array( 'WikiPageTest_testIsCountable',
344 '#REDIRECT [[bar]]',
345 'link',
346 false
347 ),
348
349 // not a content namespace
350 array( 'Talk:WikiPageTest_testIsCountable',
351 'Foo',
352 'any',
353 false
354 ),
355 array( 'Talk:WikiPageTest_testIsCountable',
356 'Foo, bar',
357 'comma',
358 false
359 ),
360 array( 'Talk:WikiPageTest_testIsCountable',
361 'Foo [[bar]]',
362 'link',
363 false
364 ),
365
366 // not a content namespace, different model
367 array( 'MediaWiki:WikiPageTest_testIsCountable.js',
368 'Foo',
369 'any',
370 false
371 ),
372 array( 'MediaWiki:WikiPageTest_testIsCountable.js',
373 'Foo, bar',
374 'comma',
375 false
376 ),
377 array( 'MediaWiki:WikiPageTest_testIsCountable.js',
378 'Foo [[bar]]',
379 'link',
380 false
381 ),
382 );
383 }
384
385
386 /**
387 * @dataProvider dataIsCountable
388 */
389 public function testIsCountable( $title, $text, $mode, $expected ) {
390 global $wgArticleCountMethod;
391
392 $old = $wgArticleCountMethod;
393 $wgArticleCountMethod = $mode;
394
395 $page = $this->createPage( $title, $text );
396 $editInfo = $page->prepareContentForEdit( $page->getContent() );
397
398 $v = $page->isCountable();
399 $w = $page->isCountable( $editInfo );
400 $wgArticleCountMethod = $old;
401
402 $this->assertEquals( $expected, $v, "isCountable( null ) returned unexpected value " . var_export( $v, true )
403 . " instead of " . var_export( $expected, true ) . " in mode `$mode` for text \"$text\"" );
404
405 $this->assertEquals( $expected, $w, "isCountable( \$editInfo ) returned unexpected value " . var_export( $v, true )
406 . " instead of " . var_export( $expected, true ) . " in mode `$mode` for text \"$text\"" );
407 }
408
409 public function dataGetParserOutput() {
410 return array(
411 array("hello ''world''\n", "<p>hello <i>world</i>\n</p>"),
412 // @todo: more...?
413 );
414 }
415
416 /**
417 * @dataProvider dataGetParserOutput
418 */
419 public function testGetParserOutput( $text, $expectedHtml ) {
420 $page = $this->createPage( 'WikiPageTest_testGetParserOutput', $text );
421
422 $opt = new ParserOptions();
423 $po = $page->getParserOutput( $opt );
424 $text = $po->getText();
425
426 $text = trim( preg_replace( '/<!--.*?-->/sm', '', $text ) ); # strip injected comments
427
428 $this->assertEquals( $expectedHtml, $text );
429 return $po;
430 }
431
432 static $sections =
433
434 "Intro
435
436 == stuff ==
437 hello world
438
439 == test ==
440 just a test
441
442 == foo ==
443 more stuff
444 ";
445
446
447 public function dataReplaceSection() {
448 return array(
449 array( 'WikiPageTest_testReplaceSection',
450 WikiPageTest::$sections,
451 "0",
452 "No more",
453 null,
454 trim( preg_replace( '/^Intro/sm', 'No more', WikiPageTest::$sections ) )
455 ),
456 array( 'WikiPageTest_testReplaceSection',
457 WikiPageTest::$sections,
458 "",
459 "No more",
460 null,
461 "No more"
462 ),
463 array( 'WikiPageTest_testReplaceSection',
464 WikiPageTest::$sections,
465 "2",
466 "== TEST ==\nmore fun",
467 null,
468 trim( preg_replace( '/^== test ==.*== foo ==/sm', "== TEST ==\nmore fun\n\n== foo ==", WikiPageTest::$sections ) )
469 ),
470 array( 'WikiPageTest_testReplaceSection',
471 WikiPageTest::$sections,
472 "8",
473 "No more",
474 null,
475 trim( WikiPageTest::$sections )
476 ),
477 array( 'WikiPageTest_testReplaceSection',
478 WikiPageTest::$sections,
479 "new",
480 "No more",
481 "New",
482 trim( WikiPageTest::$sections ) . "\n\n== New ==\n\nNo more"
483 ),
484 );
485 }
486
487 /**
488 * @dataProvider dataReplaceSection
489 */
490 public function testReplaceSection( $title, $text, $section, $with, $sectionTitle, $expected ) {
491 $page = $this->createPage( $title, $text );
492 $text = $page->replaceSection( $section, $with, $sectionTitle );
493 $text = trim( $text );
494
495 $this->assertEquals( $expected, $text );
496 }
497
498 /**
499 * @dataProvider dataReplaceSection
500 */
501 public function testReplaceSectionContent( $title, $text, $section, $with, $sectionTitle, $expected ) {
502 $page = $this->createPage( $title, $text );
503
504 $content = ContentHandler::makeContent( $with, $page->getTitle(), $page->getContentModelName() );
505 $c = $page->replaceSectionContent( $section, $content, $sectionTitle );
506
507 $this->assertEquals( $expected, is_null( $c ) ? null : trim( $c->getNativeData() ) );
508 }
509
510 /* @FIXME: fix this!
511 public function testGetUndoText() {
512 global $wgDiff3;
513
514 wfSuppressWarnings();
515 $haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
516 wfRestoreWarnings();
517
518 if( !$haveDiff3 ) {
519 $this->markTestSkipped( "diff3 not installed or not found" );
520 return;
521 }
522
523 $text = "one";
524 $page = $this->createPage( "WikiPageTest_testGetUndoText", $text );
525 $rev1 = $page->getRevision();
526
527 $text .= "\n\ntwo";
528 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section two");
529 $rev2 = $page->getRevision();
530
531 $text .= "\n\nthree";
532 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section three");
533 $rev3 = $page->getRevision();
534
535 $text .= "\n\nfour";
536 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section four");
537 $rev4 = $page->getRevision();
538
539 $text .= "\n\nfive";
540 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section five");
541 $rev5 = $page->getRevision();
542
543 $text .= "\n\nsix";
544 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section six");
545 $rev6 = $page->getRevision();
546
547 $undo6 = $page->getUndoText( $rev6 );
548 if ( $undo6 === false ) $this->fail( "getUndoText failed for rev6" );
549 $this->assertEquals( "one\n\ntwo\n\nthree\n\nfour\n\nfive", $undo6 );
550
551 $undo3 = $page->getUndoText( $rev4, $rev2 );
552 if ( $undo3 === false ) $this->fail( "getUndoText failed for rev4..rev2" );
553 $this->assertEquals( "one\n\ntwo\n\nfive", $undo3 );
554
555 $undo2 = $page->getUndoText( $rev2 );
556 if ( $undo2 === false ) $this->fail( "getUndoText failed for rev2" );
557 $this->assertEquals( "one\n\nfive", $undo2 );
558 }
559 */
560
561 public function testDoRollback() {
562 $admin = new User();
563 $admin->setName("Admin");
564
565 $text = "one";
566 $page = $this->createPage( "WikiPageTest_testDoRollback", $text );
567
568 $user1 = new User();
569 $user1->setName( "127.0.1.11" );
570 $text .= "\n\ntwo";
571 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section two", 0, false, $user1 );
572
573 $user2 = new User();
574 $user2->setName( "127.0.2.13" );
575 $text .= "\n\nthree";
576 $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), "adding section three", 0, false, $user2 );
577
578 $admin->addGroup( "sysop" ); #XXX: make the test user a sysop...
579 $token = $admin->getEditToken( array( $page->getTitle()->getPrefixedText(), $user2->getName() ), null );
580 $errors = $page->doRollback( $user2->getName(), "testing revert", $token, false, $details, $admin );
581
582 if ( $errors ) {
583 $this->fail( "Rollback failed:\n" . print_r( $errors, true ) . ";\n" . print_r( $details, true ) );
584 }
585
586 $page = new WikiPage( $page->getTitle() );
587 $this->assertEquals( "one\n\ntwo", $page->getContent()->getNativeData() );
588 }
589
590 public function dataGetAutosummary( ) {
591 return array(
592 array(
593 'Hello there, world!',
594 '#REDIRECT [[Foo]]',
595 0,
596 '/^Redirected page .*Foo/'
597 ),
598
599 array(
600 null,
601 'Hello world!',
602 EDIT_NEW,
603 '/^Created page .*Hello/'
604 ),
605
606 array(
607 'Hello there, world!',
608 '',
609 0,
610 '/^Blanked/'
611 ),
612
613 array(
614 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut
615 labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et
616 ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
617 'Hello world!',
618 0,
619 '/^Replaced .*Hello/'
620 ),
621
622 array(
623 'foo',
624 'bar',
625 0,
626 '/^$/'
627 ),
628 );
629 }
630
631 /**
632 * @dataProvider dataGetAutoSummary
633 */
634 public function testGetAutosummary( $old, $new, $flags, $expected ) {
635 $page = $this->newPage( "WikiPageTest_testGetAutosummary" );
636
637 $summary = $page->getAutosummary( $old, $new, $flags );
638
639 $this->assertTrue( (bool)preg_match( $expected, $summary ), "Autosummary didn't match expected pattern $expected: $summary" );
640 }
641
642 public function dataGetAutoDeleteReason( ) {
643 return array(
644 array(
645 array(),
646 false,
647 false
648 ),
649
650 array(
651 array(
652 array( "first edit", null ),
653 ),
654 "/first edit.*only contributor/",
655 false
656 ),
657
658 array(
659 array(
660 array( "first edit", null ),
661 array( "second edit", null ),
662 ),
663 "/second edit.*only contributor/",
664 true
665 ),
666
667 array(
668 array(
669 array( "first edit", "127.0.2.22" ),
670 array( "second edit", "127.0.3.33" ),
671 ),
672 "/second edit/",
673 true
674 ),
675
676 array(
677 array(
678 array( "first edit: "
679 . "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam "
680 . " nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. "
681 . "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea "
682 . "takimata sanctus est Lorem ipsum dolor sit amet.'", null ),
683 ),
684 '/first edit:.*\.\.\."/',
685 false
686 ),
687
688 array(
689 array(
690 array( "first edit", "127.0.2.22" ),
691 array( "", "127.0.3.33" ),
692 ),
693 "/before blanking.*first edit/",
694 true
695 ),
696
697 );
698 }
699
700 /**
701 * @dataProvider dataGetAutoDeleteReason
702 */
703 public function testGetAutoDeleteReason( $edits, $expectedResult, $expectedHistory ) {
704 global $wgUser;
705
706 $page = $this->newPage( "WikiPageTest_testGetAutoDeleteReason" );
707
708 $c = 1;
709
710 foreach ( $edits as $edit ) {
711 $user = new User();
712
713 if ( !empty( $edit[1] ) ) $user->setName( $edit[1] );
714 else $user = $wgUser;
715
716 $content = ContentHandler::makeContent( $edit[0], $page->getTitle(), $page->getContentModelName() );
717
718 $page->doEditContent( $content, "test edit $c", $c < 2 ? EDIT_NEW : 0, false, $user );
719
720 $c += 1;
721 }
722
723 $reason = $page->getAutoDeleteReason( $hasHistory );
724
725 if ( is_bool( $expectedResult ) || is_null( $expectedResult ) ) $this->assertEquals( $expectedResult, $reason );
726 else $this->assertTrue( (bool)preg_match( $expectedResult, $reason ), "Autosummary didn't match expected pattern $expectedResult: $reason" );
727
728 $this->assertEquals( $expectedHistory, $hasHistory, "expected \$hasHistory to be " . var_export( $expectedHistory, true ) );
729 }
730
731 public function dataPreSaveTransform() {
732 return array(
733 array( 'hello this is ~~~',
734 "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
735 ),
736 array( 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
737 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
738 ),
739 );
740 }
741
742 /**
743 * @dataProvider dataPreSaveTransform
744 */
745 public function testPreSaveTransform( $text, $expected ) {
746 $user = new User();
747 $user->setName("127.0.0.1");
748
749 $page = $this->newPage( "WikiPageTest_testPreloadTransform" );
750 $text = $page->preSaveTransform( $text, $user );
751
752 $this->assertEquals( $expected, $text );
753 }
754
755 }
756