4 * Tests for MediaWiki api.php?action=edit.
6 * @author Daniel Kinzler
14 class ApiEditPageTest
extends ApiTestCase
{
16 public function setUp() {
17 global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
21 $wgExtraNamespaces[12312] = 'Dummy';
22 $wgExtraNamespaces[12313] = 'Dummy_talk';
24 $wgNamespaceContentModels[12312] = "testing";
25 $wgContentHandlers["testing"] = 'DummyContentHandlerForTesting';
27 MWNamespace
::getCanonicalNamespaces( true ); # reset namespace cache
28 $wgContLang->resetNamespaces(); # reset namespace cache
33 public function tearDown() {
34 global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
36 unset( $wgExtraNamespaces[12312] );
37 unset( $wgExtraNamespaces[12313] );
39 unset( $wgNamespaceContentModels[12312] );
40 unset( $wgContentHandlers["testing"] );
42 MWNamespace
::getCanonicalNamespaces( true ); # reset namespace cache
43 $wgContLang->resetNamespaces(); # reset namespace cache
48 public function testEdit() {
49 $name = 'Help:ApiEditPageTest_testEdit'; // assume Help namespace to default to wikitext
51 // -- test new page --------------------------------------------
52 $apiResult = $this->doApiRequestWithToken( array(
55 'text' => 'some text',
57 $apiResult = $apiResult[0];
59 // Validate API result data
60 $this->assertArrayHasKey( 'edit', $apiResult );
61 $this->assertArrayHasKey( 'result', $apiResult['edit'] );
62 $this->assertEquals( 'Success', $apiResult['edit']['result'] );
64 $this->assertArrayHasKey( 'new', $apiResult['edit'] );
65 $this->assertArrayNotHasKey( 'nochange', $apiResult['edit'] );
67 $this->assertArrayHasKey( 'pageid', $apiResult['edit'] );
69 // -- test existing page, no change ----------------------------
70 $data = $this->doApiRequestWithToken( array(
73 'text' => 'some text',
76 $this->assertEquals( 'Success', $data[0]['edit']['result'] );
78 $this->assertArrayNotHasKey( 'new', $data[0]['edit'] );
79 $this->assertArrayHasKey( 'nochange', $data[0]['edit'] );
81 // -- test existing page, with change --------------------------
82 $data = $this->doApiRequestWithToken( array(
85 'text' => 'different text'
88 $this->assertEquals( 'Success', $data[0]['edit']['result'] );
90 $this->assertArrayNotHasKey( 'new', $data[0]['edit'] );
91 $this->assertArrayNotHasKey( 'nochange', $data[0]['edit'] );
93 $this->assertArrayHasKey( 'oldrevid', $data[0]['edit'] );
94 $this->assertArrayHasKey( 'newrevid', $data[0]['edit'] );
95 $this->assertNotEquals(
96 $data[0]['edit']['newrevid'],
97 $data[0]['edit']['oldrevid'],
98 "revision id should change after edit"
102 public function testNonTextEdit() {
103 $name = 'Dummy:ApiEditPageTest_testNonTextEdit';
104 $data = serialize( 'some bla bla text' );
106 // -- test new page --------------------------------------------
107 $apiResult = $this->doApiRequestWithToken( array(
110 'text' => $data, ) );
111 $apiResult = $apiResult[0];
113 // Validate API result data
114 $this->assertArrayHasKey( 'edit', $apiResult );
115 $this->assertArrayHasKey( 'result', $apiResult['edit'] );
116 $this->assertEquals( 'Success', $apiResult['edit']['result'] );
118 $this->assertArrayHasKey( 'new', $apiResult['edit'] );
119 $this->assertArrayNotHasKey( 'nochange', $apiResult['edit'] );
121 $this->assertArrayHasKey( 'pageid', $apiResult['edit'] );
123 // validate resulting revision
124 $page = WikiPage
::factory( Title
::newFromText( $name ) );
125 $this->assertEquals( "testing", $page->getContentModel() );
126 $this->assertEquals( $data, $page->getContent()->serialize() );
132 public static function provideEditAppend() {
135 'foo', 'append', 'bar', "foobar"
138 'foo', 'prepend', 'bar', "barfoo"
140 array( #2: append to empty page
141 '', 'append', 'foo', "foo"
143 array( #3: prepend to empty page
144 '', 'prepend', 'foo', "foo"
146 array( #4: append to non-existing page
147 null, 'append', 'foo', "foo"
149 array( #5: prepend to non-existing page
150 null, 'prepend', 'foo', "foo"
156 * @dataProvider provideEditAppend
158 public function testEditAppend( $text, $op, $append, $expected ) {
162 // assume NS_HELP defaults to wikitext
163 $name = "Help:ApiEditPageTest_testEditAppend_$count";
165 // -- create page (or not) -----------------------------------------
166 if ( $text !== null ) {
167 if ( $text === '' ) {
168 // can't create an empty page, so create it with some content
169 $this->doApiRequestWithToken( array(
172 'text' => '(dummy)', ) );
175 list( $re ) = $this->doApiRequestWithToken( array(
178 'text' => $text, ) );
180 $this->assertEquals( 'Success', $re['edit']['result'] ); // sanity
183 // -- try append/prepend --------------------------------------------
184 list( $re ) = $this->doApiRequestWithToken( array(
187 $op . 'text' => $append, ) );
189 $this->assertEquals( 'Success', $re['edit']['result'] );
191 // -- validate -----------------------------------------------------
192 $page = new WikiPage( Title
::newFromText( $name ) );
193 $content = $page->getContent();
194 $this->assertNotNull( $content, 'Page should have been created' );
196 $text = $content->getNativeData();
198 $this->assertEquals( $expected, $text );
202 * Test editing of sections
204 public function testEditSection() {
205 $name = 'Help:ApiEditPageTest_testEditSection';
206 $page = WikiPage
::factory( Title
::newFromText( $name ) );
207 $text = "==section 1==\ncontent 1\n==section 2==\ncontent2";
208 // Preload the page with some text
209 $page->doEditContent( ContentHandler
::makeContent( $text, $page->getTitle() ), 'summary' );
211 list( $re ) = $this->doApiRequestWithToken( array(
215 'text' => "==section 1==\nnew content 1",
217 $this->assertEquals( 'Success', $re['edit']['result'] );
218 $newtext = WikiPage
::factory( Title
::newFromText( $name ) )->getContent( Revision
::RAW
)->getNativeData();
219 $this->assertEquals( $newtext, "==section 1==\nnew content 1\n\n==section 2==\ncontent2" );
221 // Test that we raise a 'nosuchsection' error
223 $this->doApiRequestWithToken( array(
229 $this->fail( "Should have raised a UsageException" );
230 } catch ( UsageException
$e ) {
231 $this->assertEquals( $e->getCodeString(), 'nosuchsection' );
236 * Test action=edit§ion=new
237 * Run it twice so we test adding a new section on a
238 * page that doesn't exist (bug 52830) and one that
241 public function testEditNewSection() {
242 $name = 'Help:ApiEditPageTest_testEditNewSection';
244 // Test on a page that does not already exist
245 $this->assertFalse( Title
::newFromText( $name )->exists() );
246 list( $re ) = $this->doApiRequestWithToken( array(
251 'summary' => 'header',
254 $this->assertEquals( 'Success', $re['edit']['result'] );
255 // Check the page text is correct
256 $text = WikiPage
::factory( Title
::newFromText( $name ) )->getContent( Revision
::RAW
)->getNativeData();
257 $this->assertEquals( $text, "== header ==\n\ntest" );
259 // Now on one that does
260 $this->assertTrue( Title
::newFromText( $name )->exists() );
261 list( $re2 ) = $this->doApiRequestWithToken( array(
266 'summary' => 'header',
269 $this->assertEquals( 'Success', $re2['edit']['result'] );
270 $text = WikiPage
::factory( Title
::newFromText( $name ) )->getContent( Revision
::RAW
)->getNativeData();
271 $this->assertEquals( $text, "== header ==\n\ntest\n\n== header ==\n\ntest" );
274 public function testEditConflict() {
278 // assume NS_HELP defaults to wikitext
279 $name = "Help:ApiEditPageTest_testEditConflict_$count";
280 $title = Title
::newFromText( $name );
282 $page = WikiPage
::factory( $title );
285 $page->doEditContent( new WikitextContent( "Foo" ),
286 "testing 1", EDIT_NEW
, false, self
::$users['sysop']->user
);
287 $this->forceRevisionDate( $page, '20120101000000' );
288 $baseTime = $page->getRevision()->getTimestamp();
291 $page->doEditContent( new WikitextContent( "Foo bar" ),
292 "testing 2", EDIT_UPDATE
, $page->getLatest(), self
::$users['uploader']->user
);
293 $this->forceRevisionDate( $page, '20120101020202' );
295 // try to save edit, expect conflict
297 $this->doApiRequestWithToken( array(
300 'text' => 'nix bar!',
301 'basetimestamp' => $baseTime,
302 ), null, self
::$users['sysop']->user
);
304 $this->fail( 'edit conflict expected' );
305 } catch ( UsageException
$ex ) {
306 $this->assertEquals( 'editconflict', $ex->getCodeString() );
310 public function testEditConflict_redirect() {
314 // assume NS_HELP defaults to wikitext
315 $name = "Help:ApiEditPageTest_testEditConflict_redirect_$count";
316 $title = Title
::newFromText( $name );
317 $page = WikiPage
::factory( $title );
319 $rname = "Help:ApiEditPageTest_testEditConflict_redirect_r$count";
320 $rtitle = Title
::newFromText( $rname );
321 $rpage = WikiPage
::factory( $rtitle );
323 // base edit for content
324 $page->doEditContent( new WikitextContent( "Foo" ),
325 "testing 1", EDIT_NEW
, false, self
::$users['sysop']->user
);
326 $this->forceRevisionDate( $page, '20120101000000' );
327 $baseTime = $page->getRevision()->getTimestamp();
329 // base edit for redirect
330 $rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
331 "testing 1", EDIT_NEW
, false, self
::$users['sysop']->user
);
332 $this->forceRevisionDate( $rpage, '20120101000000' );
334 // conflicting edit to redirect
335 $rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]\n\n[[Category:Test]]" ),
336 "testing 2", EDIT_UPDATE
, $page->getLatest(), self
::$users['uploader']->user
);
337 $this->forceRevisionDate( $rpage, '20120101020202' );
339 // try to save edit; should work, because we follow the redirect
340 list( $re, , ) = $this->doApiRequestWithToken( array(
343 'text' => 'nix bar!',
344 'basetimestamp' => $baseTime,
346 ), null, self
::$users['sysop']->user
);
348 $this->assertEquals( 'Success', $re['edit']['result'],
349 "no edit conflict expected when following redirect" );
351 // try again, without following the redirect. Should fail.
353 $this->doApiRequestWithToken( array(
356 'text' => 'nix bar!',
357 'basetimestamp' => $baseTime,
358 ), null, self
::$users['sysop']->user
);
360 $this->fail( 'edit conflict expected' );
361 } catch ( UsageException
$ex ) {
362 $this->assertEquals( 'editconflict', $ex->getCodeString() );
366 public function testEditConflict_bug41990() {
371 * bug 41990: if the target page has a newer revision than the redirect, then editing the
372 * redirect while specifying 'redirect' and *not* specifying 'basetimestamp' erroneously
373 * caused an edit conflict to be detected.
376 // assume NS_HELP defaults to wikitext
377 $name = "Help:ApiEditPageTest_testEditConflict_redirect_bug41990_$count";
378 $title = Title
::newFromText( $name );
379 $page = WikiPage
::factory( $title );
381 $rname = "Help:ApiEditPageTest_testEditConflict_redirect_bug41990_r$count";
382 $rtitle = Title
::newFromText( $rname );
383 $rpage = WikiPage
::factory( $rtitle );
385 // base edit for content
386 $page->doEditContent( new WikitextContent( "Foo" ),
387 "testing 1", EDIT_NEW
, false, self
::$users['sysop']->user
);
388 $this->forceRevisionDate( $page, '20120101000000' );
390 // base edit for redirect
391 $rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
392 "testing 1", EDIT_NEW
, false, self
::$users['sysop']->user
);
393 $this->forceRevisionDate( $rpage, '20120101000000' );
394 $baseTime = $rpage->getRevision()->getTimestamp();
396 // new edit to content
397 $page->doEditContent( new WikitextContent( "Foo bar" ),
398 "testing 2", EDIT_UPDATE
, $page->getLatest(), self
::$users['uploader']->user
);
399 $this->forceRevisionDate( $rpage, '20120101020202' );
401 // try to save edit; should work, following the redirect.
402 list( $re, , ) = $this->doApiRequestWithToken( array(
405 'text' => 'nix bar!',
407 ), null, self
::$users['sysop']->user
);
409 $this->assertEquals( 'Success', $re['edit']['result'],
410 "no edit conflict expected here" );
414 * @param WikiPage $page
415 * @param string|int $timestamp
417 protected function forceRevisionDate( WikiPage
$page, $timestamp ) {
418 $dbw = wfGetDB( DB_MASTER
);
420 $dbw->update( 'revision',
421 array( 'rev_timestamp' => $dbw->timestamp( $timestamp ) ),
422 array( 'rev_id' => $page->getLatest() ) );