Fix documentation in Linker::formatTemplates.
[lhc/web/wiklou.git] / tests / phpunit / includes / api / ApiEditPageTest.php
1 <?php
2
3 /**
4 * Tests for MediaWiki api.php?action=edit.
5 *
6 * @author Daniel Kinzler
7 *
8 * @group API
9 * @group Database
10 * @group medium
11 */
12 class ApiEditPageTest extends ApiTestCase {
13
14 public function setup() {
15 global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
16
17 parent::setup();
18
19 $wgExtraNamespaces[12312] = 'Dummy';
20 $wgExtraNamespaces[12313] = 'Dummy_talk';
21
22 $wgNamespaceContentModels[12312] = "testing";
23 $wgContentHandlers["testing"] = 'DummyContentHandlerForTesting';
24
25 MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
26 $wgContLang->resetNamespaces(); # reset namespace cache
27
28 $this->doLogin();
29 }
30
31 public function teardown() {
32 global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
33
34 unset( $wgExtraNamespaces[12312] );
35 unset( $wgExtraNamespaces[12313] );
36
37 unset( $wgNamespaceContentModels[12312] );
38 unset( $wgContentHandlers["testing"] );
39
40 MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
41 $wgContLang->resetNamespaces(); # reset namespace cache
42
43 parent::teardown();
44 }
45
46 function testEdit( ) {
47 $name = 'Help:ApiEditPageTest_testEdit'; // assume Help namespace to default to wikitext
48
49 // -- test new page --------------------------------------------
50 $apiResult = $this->doApiRequestWithToken( array(
51 'action' => 'edit',
52 'title' => $name,
53 'text' => 'some text', ) );
54 $apiResult = $apiResult[0];
55
56 // Validate API result data
57 $this->assertArrayHasKey( 'edit', $apiResult );
58 $this->assertArrayHasKey( 'result', $apiResult['edit'] );
59 $this->assertEquals( 'Success', $apiResult['edit']['result'] );
60
61 $this->assertArrayHasKey( 'new', $apiResult['edit'] );
62 $this->assertArrayNotHasKey( 'nochange', $apiResult['edit'] );
63
64 $this->assertArrayHasKey( 'pageid', $apiResult['edit'] );
65
66 // -- test existing page, no change ----------------------------
67 $data = $this->doApiRequestWithToken( array(
68 'action' => 'edit',
69 'title' => $name,
70 'text' => 'some text', ) );
71
72 $this->assertEquals( 'Success', $data[0]['edit']['result'] );
73
74 $this->assertArrayNotHasKey( 'new', $data[0]['edit'] );
75 $this->assertArrayHasKey( 'nochange', $data[0]['edit'] );
76
77 // -- test existing page, with change --------------------------
78 $data = $this->doApiRequestWithToken( array(
79 'action' => 'edit',
80 'title' => $name,
81 'text' => 'different text' ) );
82
83 $this->assertEquals( 'Success', $data[0]['edit']['result'] );
84
85 $this->assertArrayNotHasKey( 'new', $data[0]['edit'] );
86 $this->assertArrayNotHasKey( 'nochange', $data[0]['edit'] );
87
88 $this->assertArrayHasKey( 'oldrevid', $data[0]['edit'] );
89 $this->assertArrayHasKey( 'newrevid', $data[0]['edit'] );
90 $this->assertNotEquals(
91 $data[0]['edit']['newrevid'],
92 $data[0]['edit']['oldrevid'],
93 "revision id should change after edit"
94 );
95 }
96
97 function testNonTextEdit( ) {
98 $name = 'Dummy:ApiEditPageTest_testNonTextEdit';
99 $data = serialize( 'some bla bla text' );
100
101 // -- test new page --------------------------------------------
102 $apiResult = $this->doApiRequestWithToken( array(
103 'action' => 'edit',
104 'title' => $name,
105 'text' => $data, ) );
106 $apiResult = $apiResult[0];
107
108 // Validate API result data
109 $this->assertArrayHasKey( 'edit', $apiResult );
110 $this->assertArrayHasKey( 'result', $apiResult['edit'] );
111 $this->assertEquals( 'Success', $apiResult['edit']['result'] );
112
113 $this->assertArrayHasKey( 'new', $apiResult['edit'] );
114 $this->assertArrayNotHasKey( 'nochange', $apiResult['edit'] );
115
116 $this->assertArrayHasKey( 'pageid', $apiResult['edit'] );
117
118 // validate resulting revision
119 $page = WikiPage::factory( Title::newFromText( $name ) );
120 $this->assertEquals( "testing", $page->getContentModel() );
121 $this->assertEquals( $data, $page->getContent()->serialize() );
122 }
123
124 static function provideEditAppend() {
125 return array(
126 array( #0: append
127 'foo', 'append', 'bar', "foobar"
128 ),
129 array( #1: prepend
130 'foo', 'prepend', 'bar', "barfoo"
131 ),
132 array( #2: append to empty page
133 '', 'append', 'foo', "foo"
134 ),
135 array( #3: prepend to empty page
136 '', 'prepend', 'foo', "foo"
137 ),
138 array( #4: append to non-existing page
139 null, 'append', 'foo', "foo"
140 ),
141 array( #5: prepend to non-existing page
142 null, 'prepend', 'foo', "foo"
143 ),
144 );
145 }
146
147 /**
148 * @dataProvider provideEditAppend
149 */
150 function testEditAppend( $text, $op, $append, $expected ) {
151 static $count = 0;
152 $count++;
153
154 // assume NS_HELP defaults to wikitext
155 $name = "Help:ApiEditPageTest_testEditAppend_$count";
156
157 // -- create page (or not) -----------------------------------------
158 if ( $text !== null ) {
159 if ( $text === '' ) {
160 // can't create an empty page, so create it with some content
161 list( $re,, ) = $this->doApiRequestWithToken( array(
162 'action' => 'edit',
163 'title' => $name,
164 'text' => '(dummy)', ) );
165 }
166
167 list( $re,, ) = $this->doApiRequestWithToken( array(
168 'action' => 'edit',
169 'title' => $name,
170 'text' => $text, ) );
171
172 $this->assertEquals( 'Success', $re['edit']['result'] ); // sanity
173 }
174
175 // -- try append/prepend --------------------------------------------
176 list( $re,, ) = $this->doApiRequestWithToken( array(
177 'action' => 'edit',
178 'title' => $name,
179 $op . 'text' => $append, ) );
180
181 $this->assertEquals( 'Success', $re['edit']['result'] );
182
183 // -- validate -----------------------------------------------------
184 $page = new WikiPage( Title::newFromText( $name ) );
185 $content = $page->getContent();
186 $this->assertNotNull( $content, 'Page should have been created' );
187
188 $text = $content->getNativeData();
189
190 $this->assertEquals( $expected, $text );
191 }
192
193 function testEditSection() {
194 $this->markTestIncomplete( "not yet implemented" );
195 }
196
197 function testUndo() {
198 $this->markTestIncomplete( "not yet implemented" );
199 }
200
201 function testEditConflict() {
202 static $count = 0;
203 $count++;
204
205 // assume NS_HELP defaults to wikitext
206 $name = "Help:ApiEditPageTest_testEditConflict_$count";
207 $title = Title::newFromText( $name );
208
209 $page = WikiPage::factory( $title );
210
211 // base edit
212 $page->doEditContent( new WikitextContent( "Foo" ),
213 "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
214 $this->forceRevisionDate( $page, '20120101000000' );
215 $baseTime = $page->getRevision()->getTimestamp();
216
217 // conflicting edit
218 $page->doEditContent( new WikitextContent( "Foo bar" ),
219 "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
220 $this->forceRevisionDate( $page, '20120101020202' );
221
222 // try to save edit, expect conflict
223 try {
224 list( $re,, ) = $this->doApiRequestWithToken( array(
225 'action' => 'edit',
226 'title' => $name,
227 'text' => 'nix bar!',
228 'basetimestamp' => $baseTime,
229 ), null, self::$users['sysop']->user );
230
231 $this->fail( 'edit conflict expected' );
232 } catch ( UsageException $ex ) {
233 $this->assertEquals( 'editconflict', $ex->getCodeString() );
234 }
235 }
236
237 function testEditConflict_redirect() {
238 static $count = 0;
239 $count++;
240
241 // assume NS_HELP defaults to wikitext
242 $name = "Help:ApiEditPageTest_testEditConflict_redirect_$count";
243 $title = Title::newFromText( $name );
244 $page = WikiPage::factory( $title );
245
246 $rname = "Help:ApiEditPageTest_testEditConflict_redirect_r$count";
247 $rtitle = Title::newFromText( $rname );
248 $rpage = WikiPage::factory( $rtitle );
249
250 // base edit for content
251 $page->doEditContent( new WikitextContent( "Foo" ),
252 "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
253 $this->forceRevisionDate( $page, '20120101000000' );
254 $baseTime = $page->getRevision()->getTimestamp();
255
256 // base edit for redirect
257 $rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
258 "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
259 $this->forceRevisionDate( $rpage, '20120101000000' );
260
261 // conflicting edit to redirect
262 $rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]\n\n[[Category:Test]]" ),
263 "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
264 $this->forceRevisionDate( $rpage, '20120101020202' );
265
266 // try to save edit; should work, because we follow the redirect
267 list( $re,, ) = $this->doApiRequestWithToken( array(
268 'action' => 'edit',
269 'title' => $rname,
270 'text' => 'nix bar!',
271 'basetimestamp' => $baseTime,
272 'redirect' => true,
273 ), null, self::$users['sysop']->user );
274
275 $this->assertEquals( 'Success', $re['edit']['result'],
276 "no edit conflict expected when following redirect" );
277
278 // try again, without following the redirect. Should fail.
279 try {
280 list( $re,, ) = $this->doApiRequestWithToken( array(
281 'action' => 'edit',
282 'title' => $rname,
283 'text' => 'nix bar!',
284 'basetimestamp' => $baseTime,
285 ), null, self::$users['sysop']->user );
286
287 $this->fail( 'edit conflict expected' );
288 } catch ( UsageException $ex ) {
289 $this->assertEquals( 'editconflict', $ex->getCodeString() );
290 }
291 }
292
293 function testEditConflict_bug41990() {
294 static $count = 0;
295 $count++;
296
297 /*
298 * bug 41990: if the target page has a newer revision than the redirect, then editing the
299 * redirect while specifying 'redirect' and *not* specifying 'basetimestamp' erronously
300 * caused an edit conflict to be detected.
301 */
302
303 // assume NS_HELP defaults to wikitext
304 $name = "Help:ApiEditPageTest_testEditConflict_redirect_bug41990_$count";
305 $title = Title::newFromText( $name );
306 $page = WikiPage::factory( $title );
307
308 $rname = "Help:ApiEditPageTest_testEditConflict_redirect_bug41990_r$count";
309 $rtitle = Title::newFromText( $rname );
310 $rpage = WikiPage::factory( $rtitle );
311
312 // base edit for content
313 $page->doEditContent( new WikitextContent( "Foo" ),
314 "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
315 $this->forceRevisionDate( $page, '20120101000000' );
316
317 // base edit for redirect
318 $rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
319 "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
320 $this->forceRevisionDate( $rpage, '20120101000000' );
321 $baseTime = $rpage->getRevision()->getTimestamp();
322
323 // new edit to content
324 $page->doEditContent( new WikitextContent( "Foo bar" ),
325 "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
326 $this->forceRevisionDate( $rpage, '20120101020202' );
327
328 // try to save edit; should work, following the redirect.
329 list( $re,, ) = $this->doApiRequestWithToken( array(
330 'action' => 'edit',
331 'title' => $rname,
332 'text' => 'nix bar!',
333 'redirect' => true,
334 ), null, self::$users['sysop']->user );
335
336 $this->assertEquals( 'Success', $re['edit']['result'],
337 "no edit conflict expected here" );
338 }
339
340 protected function forceRevisionDate( WikiPage $page, $timestamp ) {
341 $dbw = wfGetDB( DB_MASTER );
342
343 $dbw->update( 'revision',
344 array( 'rev_timestamp' => $timestamp ),
345 array( 'rev_id' => $page->getLatest() ) );
346
347 $page->clear();
348 }
349 }