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