Add $wgDiffEngine
[lhc/web/wiklou.git] / tests / phpunit / includes / api / ApiComparePagesTest.php
1 <?php
2
3 /**
4 * @group API
5 * @group Database
6 * @group medium
7 * @covers ApiComparePages
8 */
9 class ApiComparePagesTest extends ApiTestCase {
10
11 protected static $repl = [];
12
13 protected function addPage( $page, $text, $model = CONTENT_MODEL_WIKITEXT ) {
14 $title = Title::newFromText( 'ApiComparePagesTest ' . $page );
15 $content = ContentHandler::makeContent( $text, $title, $model );
16
17 $page = WikiPage::factory( $title );
18 $user = static::getTestSysop()->getUser();
19 $status = $page->doEditContent(
20 $content, 'Test for ApiComparePagesTest: ' . $text, 0, false, $user
21 );
22 if ( !$status->isOK() ) {
23 $this->fail( "Failed to create $title: " . $status->getWikiText( false, false, 'en' ) );
24 }
25 return $status->value['revision']->getId();
26 }
27
28 public function addDBDataOnce() {
29 $user = static::getTestSysop()->getUser();
30 self::$repl['creator'] = $user->getName();
31 self::$repl['creatorid'] = $user->getId();
32
33 self::$repl['revA1'] = $this->addPage( 'A', 'A 1' );
34 self::$repl['revA2'] = $this->addPage( 'A', 'A 2' );
35 self::$repl['revA3'] = $this->addPage( 'A', 'A 3' );
36 self::$repl['revA4'] = $this->addPage( 'A', 'A 4' );
37 self::$repl['pageA'] = Title::newFromText( 'ApiComparePagesTest A' )->getArticleID();
38
39 self::$repl['revB1'] = $this->addPage( 'B', 'B 1' );
40 self::$repl['revB2'] = $this->addPage( 'B', 'B 2' );
41 self::$repl['revB3'] = $this->addPage( 'B', 'B 3' );
42 self::$repl['revB4'] = $this->addPage( 'B', 'B 4' );
43 self::$repl['pageB'] = Title::newFromText( 'ApiComparePagesTest B' )->getArticleID();
44
45 self::$repl['revC1'] = $this->addPage( 'C', 'C 1' );
46 self::$repl['revC2'] = $this->addPage( 'C', 'C 2' );
47 self::$repl['revC3'] = $this->addPage( 'C', 'C 3' );
48 self::$repl['pageC'] = Title::newFromText( 'ApiComparePagesTest C' )->getArticleID();
49
50 $id = $this->addPage( 'D', 'D 1' );
51 self::$repl['pageD'] = Title::newFromText( 'ApiComparePagesTest D' )->getArticleID();
52 wfGetDB( DB_MASTER )->delete( 'revision', [ 'rev_id' => $id ] );
53
54 self::$repl['revE1'] = $this->addPage( 'E', 'E 1' );
55 self::$repl['revE2'] = $this->addPage( 'E', 'E 2' );
56 self::$repl['revE3'] = $this->addPage( 'E', 'E 3' );
57 self::$repl['revE4'] = $this->addPage( 'E', 'E 4' );
58 self::$repl['pageE'] = Title::newFromText( 'ApiComparePagesTest E' )->getArticleID();
59 wfGetDB( DB_MASTER )->update(
60 'page', [ 'page_latest' => 0 ], [ 'page_id' => self::$repl['pageE'] ]
61 );
62
63 self::$repl['revF1'] = $this->addPage( 'F', "== Section 1 ==\nF 1.1\n\n== Section 2 ==\nF 1.2" );
64 self::$repl['pageF'] = Title::newFromText( 'ApiComparePagesTest F' )->getArticleID();
65
66 self::$repl['revG1'] = $this->addPage( 'G', "== Section 1 ==\nG 1.1", CONTENT_MODEL_TEXT );
67 self::$repl['pageG'] = Title::newFromText( 'ApiComparePagesTest G' )->getArticleID();
68
69 WikiPage::factory( Title::newFromText( 'ApiComparePagesTest C' ) )
70 ->doDeleteArticleReal( 'Test for ApiComparePagesTest' );
71
72 RevisionDeleter::createList(
73 'revision',
74 RequestContext::getMain(),
75 Title::newFromText( 'ApiComparePagesTest B' ),
76 [ self::$repl['revB2'] ]
77 )->setVisibility( [
78 'value' => [
79 Revision::DELETED_TEXT => 1,
80 Revision::DELETED_USER => 1,
81 Revision::DELETED_COMMENT => 1,
82 ],
83 'comment' => 'Test for ApiComparePages',
84 ] );
85
86 RevisionDeleter::createList(
87 'revision',
88 RequestContext::getMain(),
89 Title::newFromText( 'ApiComparePagesTest B' ),
90 [ self::$repl['revB3'] ]
91 )->setVisibility( [
92 'value' => [
93 Revision::DELETED_USER => 1,
94 Revision::DELETED_COMMENT => 1,
95 Revision::DELETED_RESTRICTED => 1,
96 ],
97 'comment' => 'Test for ApiComparePages',
98 ] );
99
100 Title::clearCaches(); // Otherwise it has the wrong latest revision for some reason
101 }
102
103 protected function doReplacements( &$value ) {
104 if ( is_string( $value ) ) {
105 if ( preg_match( '/^{{REPL:(.+?)}}$/', $value, $m ) ) {
106 $value = self::$repl[$m[1]];
107 } else {
108 $value = preg_replace_callback( '/{{REPL:(.+?)}}/', function ( $m ) {
109 return self::$repl[$m[1]] ?? $m[0];
110 }, $value );
111 }
112 } elseif ( is_array( $value ) || is_object( $value ) ) {
113 foreach ( $value as &$v ) {
114 $this->doReplacements( $v );
115 }
116 unset( $v );
117 }
118 }
119
120 /**
121 * @dataProvider provideDiff
122 */
123 public function testDiff( $params, $expect, $exceptionCode = false, $sysop = false ) {
124 $this->setMwGlobals( [ 'wgDiffEngine' => 'php' ] );
125
126 $this->doReplacements( $params );
127
128 $params += [
129 'action' => 'compare',
130 'errorformat' => 'none',
131 ];
132
133 $user = $sysop
134 ? static::getTestSysop()->getUser()
135 : static::getTestUser()->getUser();
136 if ( $exceptionCode ) {
137 try {
138 $this->doApiRequest( $params, null, false, $user );
139 $this->fail( 'Expected exception not thrown' );
140 } catch ( ApiUsageException $ex ) {
141 $this->assertTrue( $this->apiExceptionHasCode( $ex, $exceptionCode ),
142 "Exception with code $exceptionCode" );
143 }
144 } else {
145 $apiResult = $this->doApiRequest( $params, null, false, $user );
146 $apiResult = $apiResult[0];
147 $this->doReplacements( $expect );
148 $this->assertEquals( $expect, $apiResult );
149 }
150 }
151
152 private static function makeDeprecationWarnings( ...$params ) {
153 $warn = [];
154 foreach ( $params as $p ) {
155 $warn[] = [
156 'code' => 'deprecation',
157 'data' => [ 'feature' => "action=compare&{$p}" ],
158 'module' => 'compare',
159 ];
160 if ( count( $warn ) === 1 ) {
161 $warn[] = [
162 'code' => 'deprecation-help',
163 'module' => 'main',
164 ];
165 }
166 }
167
168 return $warn;
169 }
170
171 public static function provideDiff() {
172 // phpcs:disable Generic.Files.LineLength.TooLong
173 return [
174 'Basic diff, titles' => [
175 [
176 'fromtitle' => 'ApiComparePagesTest A',
177 'totitle' => 'ApiComparePagesTest B',
178 ],
179 [
180 'compare' => [
181 'fromid' => '{{REPL:pageA}}',
182 'fromrevid' => '{{REPL:revA4}}',
183 'fromns' => 0,
184 'fromtitle' => 'ApiComparePagesTest A',
185 'toid' => '{{REPL:pageB}}',
186 'torevid' => '{{REPL:revB4}}',
187 'tons' => 0,
188 'totitle' => 'ApiComparePagesTest B',
189 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
190 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
191 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">A </del>4</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">B </ins>4</div></td></tr>' . "\n",
192 ]
193 ],
194 ],
195 'Basic diff, page IDs' => [
196 [
197 'fromid' => '{{REPL:pageA}}',
198 'toid' => '{{REPL:pageB}}',
199 ],
200 [
201 'compare' => [
202 'fromid' => '{{REPL:pageA}}',
203 'fromrevid' => '{{REPL:revA4}}',
204 'fromns' => 0,
205 'fromtitle' => 'ApiComparePagesTest A',
206 'toid' => '{{REPL:pageB}}',
207 'torevid' => '{{REPL:revB4}}',
208 'tons' => 0,
209 'totitle' => 'ApiComparePagesTest B',
210 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
211 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
212 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">A </del>4</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">B </ins>4</div></td></tr>' . "\n",
213 ]
214 ],
215 ],
216 'Basic diff, revision IDs' => [
217 [
218 'fromrev' => '{{REPL:revA2}}',
219 'torev' => '{{REPL:revA3}}',
220 ],
221 [
222 'compare' => [
223 'fromid' => '{{REPL:pageA}}',
224 'fromrevid' => '{{REPL:revA2}}',
225 'fromns' => 0,
226 'fromtitle' => 'ApiComparePagesTest A',
227 'toid' => '{{REPL:pageA}}',
228 'torevid' => '{{REPL:revA3}}',
229 'tons' => 0,
230 'totitle' => 'ApiComparePagesTest A',
231 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
232 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
233 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div>A <del class="diffchange diffchange-inline">2</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div>A <ins class="diffchange diffchange-inline">3</ins></div></td></tr>' . "\n",
234 ]
235 ],
236 ],
237 'Basic diff, deleted revision ID as sysop' => [
238 [
239 'fromrev' => '{{REPL:revA2}}',
240 'torev' => '{{REPL:revC2}}',
241 ],
242 [
243 'compare' => [
244 'fromid' => '{{REPL:pageA}}',
245 'fromrevid' => '{{REPL:revA2}}',
246 'fromns' => 0,
247 'fromtitle' => 'ApiComparePagesTest A',
248 'toid' => 0,
249 'torevid' => '{{REPL:revC2}}',
250 'tons' => 0,
251 'totitle' => 'ApiComparePagesTest C',
252 'toarchive' => true,
253 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
254 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
255 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">A </del>2</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">C </ins>2</div></td></tr>' . "\n",
256 ]
257 ],
258 false, true
259 ],
260 'Basic diff, revdel as sysop' => [
261 [
262 'fromrev' => '{{REPL:revA2}}',
263 'torev' => '{{REPL:revB2}}',
264 ],
265 [
266 'compare' => [
267 'fromid' => '{{REPL:pageA}}',
268 'fromrevid' => '{{REPL:revA2}}',
269 'fromns' => 0,
270 'fromtitle' => 'ApiComparePagesTest A',
271 'toid' => '{{REPL:pageB}}',
272 'torevid' => '{{REPL:revB2}}',
273 'tons' => 0,
274 'totitle' => 'ApiComparePagesTest B',
275 'totexthidden' => true,
276 'touserhidden' => true,
277 'tocommenthidden' => true,
278 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
279 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
280 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">A </del>2</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">B </ins>2</div></td></tr>' . "\n",
281 ]
282 ],
283 false, true
284 ],
285 'Basic diff, text' => [
286 [
287 'fromslots' => 'main',
288 'fromtext-main' => 'From text',
289 'fromcontentmodel-main' => 'wikitext',
290 'toslots' => 'main',
291 'totext-main' => 'To text {{subst:PAGENAME}}',
292 'tocontentmodel-main' => 'wikitext',
293 ],
294 [
295 'compare' => [
296 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
297 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
298 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">{{subst:PAGENAME}}</ins></div></td></tr>' . "\n",
299 ]
300 ],
301 ],
302 'Basic diff, text 2' => [
303 [
304 'fromslots' => 'main',
305 'fromtext-main' => 'From text',
306 'toslots' => 'main',
307 'totext-main' => 'To text {{subst:PAGENAME}}',
308 'tocontentmodel-main' => 'wikitext',
309 ],
310 [
311 'compare' => [
312 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
313 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
314 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">{{subst:PAGENAME}}</ins></div></td></tr>' . "\n",
315 ]
316 ],
317 ],
318 'Basic diff, guessed model' => [
319 [
320 'fromslots' => 'main',
321 'fromtext-main' => 'From text',
322 'toslots' => 'main',
323 'totext-main' => 'To text',
324 ],
325 [
326 'warnings' => [ [ 'code' => 'compare-nocontentmodel', 'module' => 'compare' ] ],
327 'compare' => [
328 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
329 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
330 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text</div></td></tr>' . "\n",
331 ]
332 ],
333 ],
334 'Basic diff, text with title and PST' => [
335 [
336 'fromslots' => 'main',
337 'fromtext-main' => 'From text',
338 'totitle' => 'Test',
339 'toslots' => 'main',
340 'totext-main' => 'To text {{subst:PAGENAME}}',
341 'topst' => true,
342 ],
343 [
344 'compare' => [
345 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
346 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
347 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">Test</ins></div></td></tr>' . "\n",
348 ]
349 ],
350 ],
351 'Basic diff, text with page ID and PST' => [
352 [
353 'fromslots' => 'main',
354 'fromtext-main' => 'From text',
355 'toid' => '{{REPL:pageB}}',
356 'toslots' => 'main',
357 'totext-main' => 'To text {{subst:PAGENAME}}',
358 'topst' => true,
359 ],
360 [
361 'compare' => [
362 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
363 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
364 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">ApiComparePagesTest B</ins></div></td></tr>' . "\n",
365 ]
366 ],
367 ],
368 'Basic diff, text with revision and PST' => [
369 [
370 'fromslots' => 'main',
371 'fromtext-main' => 'From text',
372 'torev' => '{{REPL:revB2}}',
373 'toslots' => 'main',
374 'totext-main' => 'To text {{subst:PAGENAME}}',
375 'topst' => true,
376 ],
377 [
378 'compare' => [
379 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
380 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
381 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">ApiComparePagesTest B</ins></div></td></tr>' . "\n",
382 ]
383 ],
384 ],
385 'Basic diff, text with deleted revision and PST' => [
386 [
387 'fromslots' => 'main',
388 'fromtext-main' => 'From text',
389 'torev' => '{{REPL:revC2}}',
390 'toslots' => 'main',
391 'totext-main' => 'To text {{subst:PAGENAME}}',
392 'topst' => true,
393 ],
394 [
395 'compare' => [
396 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
397 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
398 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">ApiComparePagesTest C</ins></div></td></tr>' . "\n",
399 ]
400 ],
401 false, true
402 ],
403 'Basic diff, test with sections' => [
404 [
405 'fromtitle' => 'ApiComparePagesTest F',
406 'fromslots' => 'main',
407 'fromtext-main' => "== Section 2 ==\nFrom text?",
408 'fromsection-main' => 2,
409 'totitle' => 'ApiComparePagesTest F',
410 'toslots' => 'main',
411 'totext-main' => "== Section 1 ==\nTo text?",
412 'tosection-main' => 1,
413 ],
414 [
415 'compare' => [
416 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
417 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
418 . '<tr><td class=\'diff-marker\'> </td><td class=\'diff-context\'><div>== Section 1 ==</div></td><td class=\'diff-marker\'> </td><td class=\'diff-context\'><div>== Section 1 ==</div></td></tr>' . "\n"
419 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">F 1.1</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To text?</ins></div></td></tr>' . "\n"
420 . '<tr><td class=\'diff-marker\'> </td><td class=\'diff-context\'></td><td class=\'diff-marker\'> </td><td class=\'diff-context\'></td></tr>' . "\n"
421 . '<tr><td class=\'diff-marker\'> </td><td class=\'diff-context\'><div>== Section 2 ==</div></td><td class=\'diff-marker\'> </td><td class=\'diff-context\'><div>== Section 2 ==</div></td></tr>' . "\n"
422 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From text?</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">F 1.2</ins></div></td></tr>' . "\n",
423 ]
424 ],
425 ],
426 'Diff with all props' => [
427 [
428 'fromrev' => '{{REPL:revB1}}',
429 'torev' => '{{REPL:revB3}}',
430 'totitle' => 'ApiComparePagesTest B',
431 'prop' => 'diff|diffsize|rel|ids|title|user|comment|parsedcomment|size'
432 ],
433 [
434 'compare' => [
435 'fromid' => '{{REPL:pageB}}',
436 'fromrevid' => '{{REPL:revB1}}',
437 'fromns' => 0,
438 'fromtitle' => 'ApiComparePagesTest B',
439 'fromsize' => 3,
440 'fromuser' => '{{REPL:creator}}',
441 'fromuserid' => '{{REPL:creatorid}}',
442 'fromcomment' => 'Test for ApiComparePagesTest: B 1',
443 'fromparsedcomment' => 'Test for ApiComparePagesTest: B 1',
444 'toid' => '{{REPL:pageB}}',
445 'torevid' => '{{REPL:revB3}}',
446 'tons' => 0,
447 'totitle' => 'ApiComparePagesTest B',
448 'tosize' => 3,
449 'touserhidden' => true,
450 'tocommenthidden' => true,
451 'tosuppressed' => true,
452 'next' => '{{REPL:revB4}}',
453 'diffsize' => 391,
454 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
455 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
456 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div>B <del class="diffchange diffchange-inline">1</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div>B <ins class="diffchange diffchange-inline">3</ins></div></td></tr>' . "\n",
457 ]
458 ],
459 ],
460 'Diff with all props as sysop' => [
461 [
462 'fromrev' => '{{REPL:revB2}}',
463 'torev' => '{{REPL:revB3}}',
464 'totitle' => 'ApiComparePagesTest B',
465 'prop' => 'diff|diffsize|rel|ids|title|user|comment|parsedcomment|size'
466 ],
467 [
468 'compare' => [
469 'fromid' => '{{REPL:pageB}}',
470 'fromrevid' => '{{REPL:revB2}}',
471 'fromns' => 0,
472 'fromtitle' => 'ApiComparePagesTest B',
473 'fromsize' => 3,
474 'fromtexthidden' => true,
475 'fromuserhidden' => true,
476 'fromuser' => '{{REPL:creator}}',
477 'fromuserid' => '{{REPL:creatorid}}',
478 'fromcommenthidden' => true,
479 'fromcomment' => 'Test for ApiComparePagesTest: B 2',
480 'fromparsedcomment' => 'Test for ApiComparePagesTest: B 2',
481 'toid' => '{{REPL:pageB}}',
482 'torevid' => '{{REPL:revB3}}',
483 'tons' => 0,
484 'totitle' => 'ApiComparePagesTest B',
485 'tosize' => 3,
486 'touserhidden' => true,
487 'tocommenthidden' => true,
488 'tosuppressed' => true,
489 'prev' => '{{REPL:revB1}}',
490 'next' => '{{REPL:revB4}}',
491 'diffsize' => 391,
492 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
493 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
494 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div>B <del class="diffchange diffchange-inline">2</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div>B <ins class="diffchange diffchange-inline">3</ins></div></td></tr>' . "\n",
495 ]
496 ],
497 false, true
498 ],
499 'Relative diff, cur' => [
500 [
501 'fromrev' => '{{REPL:revA2}}',
502 'torelative' => 'cur',
503 'prop' => 'ids',
504 ],
505 [
506 'compare' => [
507 'fromid' => '{{REPL:pageA}}',
508 'fromrevid' => '{{REPL:revA2}}',
509 'toid' => '{{REPL:pageA}}',
510 'torevid' => '{{REPL:revA4}}',
511 ]
512 ],
513 ],
514 'Relative diff, next' => [
515 [
516 'fromrev' => '{{REPL:revE2}}',
517 'torelative' => 'next',
518 'prop' => 'ids|rel',
519 ],
520 [
521 'compare' => [
522 'fromid' => '{{REPL:pageE}}',
523 'fromrevid' => '{{REPL:revE2}}',
524 'toid' => '{{REPL:pageE}}',
525 'torevid' => '{{REPL:revE3}}',
526 'prev' => '{{REPL:revE1}}',
527 'next' => '{{REPL:revE4}}',
528 ]
529 ],
530 ],
531 'Relative diff, prev' => [
532 [
533 'fromrev' => '{{REPL:revE3}}',
534 'torelative' => 'prev',
535 'prop' => 'ids|rel',
536 ],
537 [
538 'compare' => [
539 'fromid' => '{{REPL:pageE}}',
540 'fromrevid' => '{{REPL:revE2}}',
541 'toid' => '{{REPL:pageE}}',
542 'torevid' => '{{REPL:revE3}}',
543 'prev' => '{{REPL:revE1}}',
544 'next' => '{{REPL:revE4}}',
545 ]
546 ],
547 ],
548 'Relative diff, no prev' => [
549 [
550 'fromrev' => '{{REPL:revA1}}',
551 'torelative' => 'prev',
552 'prop' => 'ids|rel|diff|title|user|comment',
553 ],
554 [
555 'warnings' => [
556 [
557 'code' => 'compare-no-prev',
558 'module' => 'compare',
559 ],
560 ],
561 'compare' => [
562 'toid' => '{{REPL:pageA}}',
563 'torevid' => '{{REPL:revA1}}',
564 'tons' => 0,
565 'totitle' => 'ApiComparePagesTest A',
566 'touser' => '{{REPL:creator}}',
567 'touserid' => '{{REPL:creatorid}}',
568 'tocomment' => 'Test for ApiComparePagesTest: A 1',
569 'toparsedcomment' => 'Test for ApiComparePagesTest: A 1',
570 'next' => '{{REPL:revA2}}',
571 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
572 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
573 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div> </div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">A 1</ins></div></td></tr>' . "\n",
574 ],
575 ],
576 ],
577 'Relative diff, no next' => [
578 [
579 'fromrev' => '{{REPL:revA4}}',
580 'torelative' => 'next',
581 'prop' => 'ids|rel|diff|title|user|comment',
582 ],
583 [
584 'warnings' => [
585 [
586 'code' => 'compare-no-next',
587 'module' => 'compare',
588 ],
589 ],
590 'compare' => [
591 'fromid' => '{{REPL:pageA}}',
592 'fromrevid' => '{{REPL:revA4}}',
593 'fromns' => 0,
594 'fromtitle' => 'ApiComparePagesTest A',
595 'fromuser' => '{{REPL:creator}}',
596 'fromuserid' => '{{REPL:creatorid}}',
597 'fromcomment' => 'Test for ApiComparePagesTest: A 4',
598 'fromparsedcomment' => 'Test for ApiComparePagesTest: A 4',
599 'prev' => '{{REPL:revA3}}',
600 'body' => '',
601 ],
602 ],
603 ],
604 'Diff for specific slots' => [
605 // @todo Use a page with multiple slots here
606 [
607 'fromrev' => '{{REPL:revA1}}',
608 'torev' => '{{REPL:revA3}}',
609 'prop' => 'diff',
610 'slots' => 'main',
611 ],
612 [
613 'compare' => [
614 'bodies' => [
615 'main' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
616 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
617 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div>A <del class="diffchange diffchange-inline">1</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div>A <ins class="diffchange diffchange-inline">3</ins></div></td></tr>' . "\n",
618 ],
619 ],
620 ],
621 ],
622 // @todo Add a test for diffing with a deleted slot. Deleting 'main' doesn't work.
623
624 'Basic diff, deprecated text' => [
625 [
626 'fromtext' => 'From text',
627 'fromcontentmodel' => 'wikitext',
628 'totext' => 'To text {{subst:PAGENAME}}',
629 'tocontentmodel' => 'wikitext',
630 ],
631 [
632 'warnings' => self::makeDeprecationWarnings( 'fromtext', 'fromcontentmodel', 'totext', 'tocontentmodel' ),
633 'compare' => [
634 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
635 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
636 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">{{subst:PAGENAME}}</ins></div></td></tr>' . "\n",
637 ]
638 ],
639 ],
640 'Basic diff, deprecated text 2' => [
641 [
642 'fromtext' => 'From text',
643 'totext' => 'To text {{subst:PAGENAME}}',
644 'tocontentmodel' => 'wikitext',
645 ],
646 [
647 'warnings' => self::makeDeprecationWarnings( 'fromtext', 'totext', 'tocontentmodel' ),
648 'compare' => [
649 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
650 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
651 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">{{subst:PAGENAME}}</ins></div></td></tr>' . "\n",
652 ]
653 ],
654 ],
655 'Basic diff, deprecated text, guessed model' => [
656 [
657 'fromtext' => 'From text',
658 'totext' => 'To text',
659 ],
660 [
661 'warnings' => array_merge( self::makeDeprecationWarnings( 'fromtext', 'totext' ), [
662 [ 'code' => 'compare-nocontentmodel', 'module' => 'compare' ],
663 ] ),
664 'compare' => [
665 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
666 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
667 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text</div></td></tr>' . "\n",
668 ]
669 ],
670 ],
671 'Basic diff, deprecated text with title and PST' => [
672 [
673 'fromtext' => 'From text',
674 'totitle' => 'Test',
675 'totext' => 'To text {{subst:PAGENAME}}',
676 'topst' => true,
677 ],
678 [
679 'warnings' => self::makeDeprecationWarnings( 'fromtext', 'totext' ),
680 'compare' => [
681 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
682 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
683 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">Test</ins></div></td></tr>' . "\n",
684 ]
685 ],
686 ],
687 'Basic diff, deprecated text with page ID and PST' => [
688 [
689 'fromtext' => 'From text',
690 'toid' => '{{REPL:pageB}}',
691 'totext' => 'To text {{subst:PAGENAME}}',
692 'topst' => true,
693 ],
694 [
695 'warnings' => self::makeDeprecationWarnings( 'fromtext', 'totext' ),
696 'compare' => [
697 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
698 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
699 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">ApiComparePagesTest B</ins></div></td></tr>' . "\n",
700 ]
701 ],
702 ],
703 'Basic diff, deprecated text with revision and PST' => [
704 [
705 'fromtext' => 'From text',
706 'torev' => '{{REPL:revB2}}',
707 'totext' => 'To text {{subst:PAGENAME}}',
708 'topst' => true,
709 ],
710 [
711 'warnings' => self::makeDeprecationWarnings( 'fromtext', 'totext' ),
712 'compare' => [
713 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
714 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
715 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">ApiComparePagesTest B</ins></div></td></tr>' . "\n",
716 ]
717 ],
718 ],
719 'Basic diff, deprecated text with deleted revision and PST' => [
720 [
721 'fromtext' => 'From text',
722 'torev' => '{{REPL:revC2}}',
723 'totext' => 'To text {{subst:PAGENAME}}',
724 'topst' => true,
725 ],
726 [
727 'warnings' => self::makeDeprecationWarnings( 'fromtext', 'totext' ),
728 'compare' => [
729 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
730 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
731 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">From </del>text</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To </ins>text <ins class="diffchange diffchange-inline">ApiComparePagesTest C</ins></div></td></tr>' . "\n",
732 ]
733 ],
734 false, true
735 ],
736 'Basic diff, test with deprecated sections' => [
737 [
738 'fromtitle' => 'ApiComparePagesTest F',
739 'fromsection' => 1,
740 'totext' => "== Section 1 ==\nTo text\n\n== Section 2 ==\nTo text?",
741 'tosection' => 2,
742 ],
743 [
744 'warnings' => self::makeDeprecationWarnings( 'fromsection', 'totext', 'tosection' ),
745 'compare' => [
746 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
747 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
748 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div>== Section <del class="diffchange diffchange-inline">1 </del>==</div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div>== Section <ins class="diffchange diffchange-inline">2 </ins>==</div></td></tr>' . "\n"
749 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div><del class="diffchange diffchange-inline">F 1.1</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div><ins class="diffchange diffchange-inline">To text?</ins></div></td></tr>' . "\n",
750 'fromid' => '{{REPL:pageF}}',
751 'fromrevid' => '{{REPL:revF1}}',
752 'fromns' => '0',
753 'fromtitle' => 'ApiComparePagesTest F',
754 ]
755 ],
756 ],
757 'Basic diff, test with deprecated sections and revdel, non-sysop' => [
758 [
759 'fromrev' => '{{REPL:revB2}}',
760 'fromsection' => 0,
761 'torev' => '{{REPL:revB4}}',
762 'tosection' => 0,
763 ],
764 [],
765 'missingcontent'
766 ],
767 'Basic diff, test with deprecated sections and revdel, sysop' => [
768 [
769 'fromrev' => '{{REPL:revB2}}',
770 'fromsection' => 0,
771 'torev' => '{{REPL:revB4}}',
772 'tosection' => 0,
773 ],
774 [
775 'warnings' => self::makeDeprecationWarnings( 'fromsection', 'tosection' ),
776 'compare' => [
777 'body' => '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l1" >Line 1:</td>' . "\n"
778 . '<td colspan="2" class="diff-lineno">Line 1:</td></tr>' . "\n"
779 . '<tr><td class=\'diff-marker\'>−</td><td class=\'diff-deletedline\'><div>B <del class="diffchange diffchange-inline">2</del></div></td><td class=\'diff-marker\'>+</td><td class=\'diff-addedline\'><div>B <ins class="diffchange diffchange-inline">4</ins></div></td></tr>' . "\n",
780 'fromid' => '{{REPL:pageB}}',
781 'fromrevid' => '{{REPL:revB2}}',
782 'fromns' => 0,
783 'fromtitle' => 'ApiComparePagesTest B',
784 'fromtexthidden' => true,
785 'fromuserhidden' => true,
786 'fromcommenthidden' => true,
787 'toid' => '{{REPL:pageB}}',
788 'torevid' => '{{REPL:revB4}}',
789 'tons' => 0,
790 'totitle' => 'ApiComparePagesTest B',
791 ]
792 ],
793 false, true,
794 ],
795
796 'Error, missing title' => [
797 [
798 'fromtitle' => 'ApiComparePagesTest X',
799 'totitle' => 'ApiComparePagesTest B',
800 ],
801 [],
802 'missingtitle',
803 ],
804 'Error, invalid title' => [
805 [
806 'fromtitle' => '<bad>',
807 'totitle' => 'ApiComparePagesTest B',
808 ],
809 [],
810 'invalidtitle',
811 ],
812 'Error, missing page ID' => [
813 [
814 'fromid' => 8817900,
815 'totitle' => 'ApiComparePagesTest B',
816 ],
817 [],
818 'nosuchpageid',
819 ],
820 'Error, page with missing revision' => [
821 [
822 'fromtitle' => 'ApiComparePagesTest D',
823 'totitle' => 'ApiComparePagesTest B',
824 ],
825 [],
826 'nosuchrevid',
827 ],
828 'Error, page with no revision' => [
829 [
830 'fromtitle' => 'ApiComparePagesTest E',
831 'totitle' => 'ApiComparePagesTest B',
832 ],
833 [],
834 'nosuchrevid',
835 ],
836 'Error, bad rev ID' => [
837 [
838 'fromrev' => 8817900,
839 'totitle' => 'ApiComparePagesTest B',
840 ],
841 [],
842 'nosuchrevid',
843 ],
844 'Error, deleted revision ID, non-sysop' => [
845 [
846 'fromrev' => '{{REPL:revA2}}',
847 'torev' => '{{REPL:revC2}}',
848 ],
849 [],
850 'nosuchrevid',
851 ],
852 'Error, deleted revision ID and torelative=prev' => [
853 [
854 'fromrev' => '{{REPL:revC2}}',
855 'torelative' => 'prev',
856 ],
857 [],
858 'compare-relative-to-deleted', true
859 ],
860 'Error, deleted revision ID and torelative=next' => [
861 [
862 'fromrev' => '{{REPL:revC2}}',
863 'torelative' => 'next',
864 ],
865 [],
866 'compare-relative-to-deleted', true
867 ],
868 'Deleted revision ID and torelative=cur' => [
869 [
870 'fromrev' => '{{REPL:revC2}}',
871 'torelative' => 'cur',
872 ],
873 [],
874 'nosuchrevid', true
875 ],
876 'Error, revision-deleted content' => [
877 [
878 'fromrev' => '{{REPL:revA2}}',
879 'torev' => '{{REPL:revB2}}',
880 ],
881 [],
882 'missingcontent',
883 ],
884 'Error, text with no title and PST' => [
885 [
886 'fromtext' => 'From text',
887 'totext' => 'To text {{subst:PAGENAME}}',
888 'topst' => true,
889 ],
890 [],
891 'compare-no-title',
892 ],
893 'Error, test with invalid from section ID' => [
894 [
895 'fromtitle' => 'ApiComparePagesTest F',
896 'fromsection' => 5,
897 'totext' => "== Section 1 ==\nTo text\n\n== Section 2 ==\nTo text?",
898 'tosection' => 2,
899 ],
900 [],
901 'nosuchfromsection',
902 ],
903 'Error, test with invalid to section ID' => [
904 [
905 'fromtitle' => 'ApiComparePagesTest F',
906 'fromsection' => 1,
907 'totext' => "== Section 1 ==\nTo text\n\n== Section 2 ==\nTo text?",
908 'tosection' => 5,
909 ],
910 [],
911 'nosuchtosection',
912 ],
913 'Error, Relative diff, no from revision' => [
914 [
915 'fromtext' => 'Foo',
916 'torelative' => 'cur',
917 'prop' => 'ids',
918 ],
919 [],
920 'compare-relative-to-nothing'
921 ],
922 'Error, Relative diff, cur with no current revision' => [
923 [
924 'fromrev' => '{{REPL:revE2}}',
925 'torelative' => 'cur',
926 'prop' => 'ids',
927 ],
928 [],
929 'nosuchrevid'
930 ],
931 'Error, Relative diff, next revdeleted' => [
932 [
933 'fromrev' => '{{REPL:revB1}}',
934 'torelative' => 'next',
935 'prop' => 'ids',
936 ],
937 [],
938 'missingcontent'
939 ],
940 'Error, Relative diff, prev revdeleted' => [
941 [
942 'fromrev' => '{{REPL:revB3}}',
943 'torelative' => 'prev',
944 'prop' => 'ids',
945 ],
946 [],
947 'missingcontent'
948 ],
949 'Error, section diff with no revision' => [
950 [
951 'fromtitle' => 'ApiComparePagesTest F',
952 'toslots' => 'main',
953 'totext-main' => "== Section 1 ==\nTo text?",
954 'tosection-main' => 1,
955 ],
956 [],
957 'compare-notorevision',
958 ],
959 'Error, section diff with revdeleted revision' => [
960 [
961 'fromtitle' => 'ApiComparePagesTest F',
962 'torev' => '{{REPL:revB2}}',
963 'toslots' => 'main',
964 'totext-main' => "== Section 1 ==\nTo text?",
965 'tosection-main' => 1,
966 ],
967 [],
968 'missingcontent',
969 ],
970 'Error, section diff with a content model not supporting sections' => [
971 [
972 'fromtitle' => 'ApiComparePagesTest G',
973 'torev' => '{{REPL:revG1}}',
974 'toslots' => 'main',
975 'totext-main' => "== Section 1 ==\nTo text?",
976 'tosection-main' => 1,
977 ],
978 [],
979 'sectionsnotsupported',
980 ],
981 'Error, section diff with bad content model' => [
982 [
983 'fromtitle' => 'ApiComparePagesTest F',
984 'torev' => '{{REPL:revF1}}',
985 'toslots' => 'main',
986 'totext-main' => "== Section 1 ==\nTo text?",
987 'tosection-main' => 1,
988 'tocontentmodel-main' => CONTENT_MODEL_TEXT,
989 ],
990 [],
991 'sectionreplacefailed',
992 ],
993 'Error, deleting the main slot' => [
994 [
995 'fromtitle' => 'ApiComparePagesTest A',
996 'totitle' => 'ApiComparePagesTest A',
997 'toslots' => 'main',
998 ],
999 [],
1000 'compare-maintextrequired',
1001 ],
1002 // @todo Add a test for using 'tosection-foo' without 'totext-foo' (can't do it with main)
1003 ];
1004 // phpcs:enable
1005 }
1006 }