tests: Replace PHPUnit's loose assertEquals(null) with assertNull()
[lhc/web/wiklou.git] / tests / phpunit / includes / content / WikitextContentTest.php
1 <?php
2
3 use MediaWiki\MediaWikiServices;
4
5 /**
6 * @group ContentHandler
7 *
8 * @group Database
9 * ^--- needed, because we do need the database to test link updates
10 */
11 class WikitextContentTest extends TextContentTest {
12 public static $sections = "Intro
13
14 == stuff ==
15 hello world
16
17 == test ==
18 just a test
19
20 == foo ==
21 more stuff
22 ";
23
24 public function newContent( $text ) {
25 return new WikitextContent( $text );
26 }
27
28 public static function dataGetParserOutput() {
29 return [
30 [
31 "WikitextContentTest_testGetParserOutput",
32 CONTENT_MODEL_WIKITEXT,
33 "hello ''world''\n",
34 "<div class=\"mw-parser-output\"><p>hello <i>world</i>\n</p>\n\n\n</div>"
35 ],
36 // TODO: more...?
37 ];
38 }
39
40 public static function dataGetSecondaryDataUpdates() {
41 return [
42 [ "WikitextContentTest_testGetSecondaryDataUpdates_1",
43 CONTENT_MODEL_WIKITEXT, "hello ''world''\n",
44 [
45 LinksUpdate::class => [
46 'mRecursive' => true,
47 'mLinks' => []
48 ]
49 ]
50 ],
51 [ "WikitextContentTest_testGetSecondaryDataUpdates_2",
52 CONTENT_MODEL_WIKITEXT, "hello [[world test 21344]]\n",
53 [
54 LinksUpdate::class => [
55 'mRecursive' => true,
56 'mLinks' => [
57 [ 'World_test_21344' => 0 ]
58 ]
59 ]
60 ]
61 ],
62 // TODO: more...?
63 ];
64 }
65
66 /**
67 * @dataProvider dataGetSecondaryDataUpdates
68 * @group Database
69 * @covers WikitextContent::getSecondaryDataUpdates
70 */
71 public function testGetSecondaryDataUpdates( $title, $model, $text, $expectedStuff ) {
72 $ns = $this->getDefaultWikitextNS();
73 $title = Title::newFromText( $title, $ns );
74
75 $content = ContentHandler::makeContent( $text, $title, $model );
76
77 $page = WikiPage::factory( $title );
78 $page->doEditContent( $content, '' );
79
80 $updates = $content->getSecondaryDataUpdates( $title );
81
82 // make updates accessible by class name
83 foreach ( $updates as $update ) {
84 $class = get_class( $update );
85 $updates[$class] = $update;
86 }
87
88 foreach ( $expectedStuff as $class => $fieldValues ) {
89 $this->assertArrayHasKey( $class, $updates, "missing an update of type $class" );
90
91 $update = $updates[$class];
92
93 foreach ( $fieldValues as $field => $value ) {
94 $v = $update->$field; # if the field doesn't exist, just crash and burn
95 $this->assertEquals(
96 $value,
97 $v,
98 "unexpected value for field $field in instance of $class"
99 );
100 }
101 }
102
103 $page->doDeleteArticle( '' );
104 }
105
106 public static function dataGetSection() {
107 return [
108 [ self::$sections,
109 "0",
110 "Intro"
111 ],
112 [ self::$sections,
113 "2",
114 "== test ==
115 just a test"
116 ],
117 [ self::$sections,
118 "8",
119 false
120 ],
121 ];
122 }
123
124 /**
125 * @dataProvider dataGetSection
126 * @covers WikitextContent::getSection
127 */
128 public function testGetSection( $text, $sectionId, $expectedText ) {
129 $content = $this->newContent( $text );
130
131 $sectionContent = $content->getSection( $sectionId );
132 if ( is_object( $sectionContent ) ) {
133 $sectionText = $sectionContent->getText();
134 } else {
135 $sectionText = $sectionContent;
136 }
137
138 $this->assertEquals( $expectedText, $sectionText );
139 }
140
141 public static function dataReplaceSection() {
142 return [
143 [ self::$sections,
144 "0",
145 "No more",
146 null,
147 trim( preg_replace( '/^Intro/sm', 'No more', self::$sections ) )
148 ],
149 [ self::$sections,
150 "",
151 "No more",
152 null,
153 "No more"
154 ],
155 [ self::$sections,
156 "2",
157 "== TEST ==\nmore fun",
158 null,
159 trim( preg_replace(
160 '/^== test ==.*== foo ==/sm', "== TEST ==\nmore fun\n\n== foo ==",
161 self::$sections
162 ) )
163 ],
164 [ self::$sections,
165 "8",
166 "No more",
167 null,
168 self::$sections
169 ],
170 [ self::$sections,
171 "new",
172 "No more",
173 "New",
174 trim( self::$sections ) . "\n\n\n== New ==\n\nNo more"
175 ],
176 ];
177 }
178
179 /**
180 * @dataProvider dataReplaceSection
181 * @covers WikitextContent::replaceSection
182 */
183 public function testReplaceSection( $text, $section, $with, $sectionTitle, $expected ) {
184 $content = $this->newContent( $text );
185 /** @var WikitextContent $c */
186 $c = $content->replaceSection( $section, $this->newContent( $with ), $sectionTitle );
187
188 $this->assertEquals( $expected, $c ? $c->getText() : null );
189 }
190
191 /**
192 * @covers WikitextContent::addSectionHeader
193 */
194 public function testAddSectionHeader() {
195 $content = $this->newContent( 'hello world' );
196 $content = $content->addSectionHeader( 'test' );
197
198 $this->assertEquals( "== test ==\n\nhello world", $content->getText() );
199 }
200
201 public static function dataPreSaveTransform() {
202 return [
203 [ 'hello this is ~~~',
204 "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
205 ],
206 [ 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
207 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
208 ],
209 [ // rtrim
210 " Foo \n ",
211 " Foo",
212 ],
213 ];
214 }
215
216 public static function dataPreloadTransform() {
217 return [
218 [
219 'hello this is ~~~',
220 "hello this is ~~~",
221 ],
222 [
223 'hello \'\'this\'\' is <noinclude>foo</noinclude><includeonly>bar</includeonly>',
224 'hello \'\'this\'\' is bar',
225 ],
226 ];
227 }
228
229 public static function dataGetRedirectTarget() {
230 return [
231 [ '#REDIRECT [[Test]]',
232 'Test',
233 ],
234 [ '#REDIRECT Test',
235 null,
236 ],
237 [ '* #REDIRECT [[Test]]',
238 null,
239 ],
240 ];
241 }
242
243 public static function dataGetTextForSummary() {
244 return [
245 [ "hello\nworld.",
246 16,
247 'hello world.',
248 ],
249 [ 'hello world.',
250 8,
251 'hello...',
252 ],
253 [ '[[hello world]].',
254 8,
255 'hel...',
256 ],
257 ];
258 }
259
260 public static function dataIsCountable() {
261 return [
262 [ '',
263 null,
264 'any',
265 true
266 ],
267 [ 'Foo',
268 null,
269 'any',
270 true
271 ],
272 [ 'Foo',
273 null,
274 'link',
275 false
276 ],
277 [ 'Foo [[bar]]',
278 null,
279 'link',
280 true
281 ],
282 [ 'Foo',
283 true,
284 'link',
285 true
286 ],
287 [ 'Foo [[bar]]',
288 false,
289 'link',
290 false
291 ],
292 [ '#REDIRECT [[bar]]',
293 true,
294 'any',
295 false
296 ],
297 [ '#REDIRECT [[bar]]',
298 true,
299 'link',
300 false
301 ],
302 ];
303 }
304
305 /**
306 * @covers WikitextContent::matchMagicWord
307 */
308 public function testMatchMagicWord() {
309 $mw = MediaWikiServices::getInstance()->getMagicWordFactory()->get( "staticredirect" );
310
311 $content = $this->newContent( "#REDIRECT [[FOO]]\n__STATICREDIRECT__" );
312 $this->assertTrue( $content->matchMagicWord( $mw ), "should have matched magic word" );
313
314 $content = $this->newContent( "#REDIRECT [[FOO]]" );
315 $this->assertFalse(
316 $content->matchMagicWord( $mw ),
317 "should not have matched magic word"
318 );
319 }
320
321 /**
322 * @covers WikitextContent::updateRedirect
323 */
324 public function testUpdateRedirect() {
325 $target = Title::newFromText( "testUpdateRedirect_target" );
326
327 // test with non-redirect page
328 $content = $this->newContent( "hello world." );
329 $newContent = $content->updateRedirect( $target );
330
331 $this->assertTrue( $content->equals( $newContent ), "content should be unchanged" );
332
333 // test with actual redirect
334 $content = $this->newContent( "#REDIRECT [[Someplace]]" );
335 $newContent = $content->updateRedirect( $target );
336
337 $this->assertFalse( $content->equals( $newContent ), "content should have changed" );
338 $this->assertTrue( $newContent->isRedirect(), "new content should be a redirect" );
339
340 $this->assertEquals(
341 $target->getFullText(),
342 $newContent->getRedirectTarget()->getFullText()
343 );
344 }
345
346 /**
347 * @covers WikitextContent::getModel
348 */
349 public function testGetModel() {
350 $content = $this->newContent( "hello world." );
351
352 $this->assertEquals( CONTENT_MODEL_WIKITEXT, $content->getModel() );
353 }
354
355 /**
356 * @covers WikitextContent::getContentHandler
357 */
358 public function testGetContentHandler() {
359 $content = $this->newContent( "hello world." );
360
361 $this->assertEquals( CONTENT_MODEL_WIKITEXT, $content->getContentHandler()->getModelID() );
362 }
363
364 /**
365 * @covers ParserOptions::getRedirectTarget
366 * @covers ParserOptions::setRedirectTarget
367 */
368 public function testRedirectParserOption() {
369 $title = Title::newFromText( 'testRedirectParserOption' );
370
371 // Set up hook and its reporting variables
372 $wikitext = null;
373 $redirectTarget = null;
374 $this->mergeMwGlobalArrayValue( 'wgHooks', [
375 'InternalParseBeforeLinks' => [
376 function ( &$parser, &$text, &$stripState ) use ( &$wikitext, &$redirectTarget ) {
377 $wikitext = $text;
378 $redirectTarget = $parser->getOptions()->getRedirectTarget();
379 }
380 ]
381 ] );
382
383 // Test with non-redirect page
384 $wikitext = false;
385 $redirectTarget = false;
386 $content = $this->newContent( 'hello world.' );
387 $options = ParserOptions::newCanonical( 'canonical' );
388 $options->setRedirectTarget( $title );
389 $content->getParserOutput( $title, null, $options );
390 $this->assertEquals( 'hello world.', $wikitext,
391 'Wikitext passed to hook was not as expected'
392 );
393 $this->assertNull( $redirectTarget, 'Redirect seen in hook was not null' );
394 $this->assertEquals( $title, $options->getRedirectTarget(),
395 'ParserOptions\' redirectTarget was changed'
396 );
397
398 // Test with a redirect page
399 $wikitext = false;
400 $redirectTarget = false;
401 $content = $this->newContent(
402 "#REDIRECT [[TestRedirectParserOption/redir]]\nhello redirect."
403 );
404 $options = ParserOptions::newCanonical( 'canonical' );
405 $content->getParserOutput( $title, null, $options );
406 $this->assertEquals(
407 'hello redirect.',
408 $wikitext,
409 'Wikitext passed to hook was not as expected'
410 );
411 $this->assertNotEquals(
412 null,
413 $redirectTarget,
414 'Redirect seen in hook was null' );
415 $this->assertEquals(
416 'TestRedirectParserOption/redir',
417 $redirectTarget->getFullText(),
418 'Redirect seen in hook was not the expected title'
419 );
420 $this->assertNull(
421 $options->getRedirectTarget(),
422 'ParserOptions\' redirectTarget was changed'
423 );
424 }
425
426 public static function dataEquals() {
427 return [
428 [ new WikitextContent( "hallo" ), null, false ],
429 [ new WikitextContent( "hallo" ), new WikitextContent( "hallo" ), true ],
430 [ new WikitextContent( "hallo" ), new JavaScriptContent( "hallo" ), false ],
431 [ new WikitextContent( "hallo" ), new TextContent( "hallo" ), false ],
432 [ new WikitextContent( "hallo" ), new WikitextContent( "HALLO" ), false ],
433 ];
434 }
435
436 public static function dataGetDeletionUpdates() {
437 return [
438 [
439 CONTENT_MODEL_WIKITEXT, "hello ''world''\n",
440 [ LinksDeletionUpdate::class => [] ]
441 ],
442 [
443 CONTENT_MODEL_WIKITEXT, "hello [[world test 21344]]\n",
444 [ LinksDeletionUpdate::class => [] ]
445 ],
446 // @todo more...?
447 ];
448 }
449
450 /**
451 * @covers WikitextContent::preSaveTransform
452 * @covers WikitextContent::fillParserOutput
453 */
454 public function testHadSignature() {
455 $titleObj = Title::newFromText( __CLASS__ );
456
457 $content = new WikitextContent( '~~~~' );
458 $pstContent = $content->preSaveTransform(
459 $titleObj, $this->getTestUser()->getUser(), new ParserOptions()
460 );
461
462 $this->assertTrue( $pstContent->getParserOutput( $titleObj )->getFlag( 'user-signature' ) );
463 }
464 }