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