10 class ApiMoveTest
extends ApiTestCase
{
12 * @param string $from Prefixed name of source
13 * @param string $to Prefixed name of destination
14 * @param string $id Page id of the page to move
15 * @param array|string|null $opts Options: 'noredirect' to expect no redirect
17 protected function assertMoved( $from, $to, $id, $opts = null ) {
20 $fromTitle = Title
::newFromText( $from );
21 $toTitle = Title
::newFromText( $to );
23 $this->assertTrue( $toTitle->exists(),
24 "Destination {$toTitle->getPrefixedText()} does not exist" );
26 if ( in_array( 'noredirect', $opts ) ) {
27 $this->assertFalse( $fromTitle->exists(),
28 "Source {$fromTitle->getPrefixedText()} exists" );
30 $this->assertTrue( $fromTitle->exists(),
31 "Source {$fromTitle->getPrefixedText()} does not exist" );
32 $this->assertTrue( $fromTitle->isRedirect(),
33 "Source {$fromTitle->getPrefixedText()} is not a redirect" );
35 $target = Revision
::newFromTitle( $fromTitle )->getContent()->getRedirectTarget();
36 $this->assertSame( $toTitle->getPrefixedText(), $target->getPrefixedText() );
39 $this->assertSame( $id, $toTitle->getArticleID() );
43 * Shortcut function to create a page and return its id.
45 * @param string $name Page to create
46 * @return int ID of created page
48 protected function createPage( $name ) {
49 return $this->editPage( $name, 'Content' )->value
['revision']->getPage();
52 public function testFromWithFromid() {
53 $this->setExpectedException( ApiUsageException
::class,
54 'The parameters "from" and "fromid" can not be used together.' );
56 $this->doApiRequestWithToken( [
58 'from' => 'Some page',
60 'to' => 'Some other page',
64 public function testMove() {
65 $name = ucfirst( __FUNCTION__
);
67 $id = $this->createPage( $name );
69 $res = $this->doApiRequestWithToken( [
75 $this->assertMoved( $name, "$name 2", $id );
76 $this->assertArrayNotHasKey( 'warnings', $res[0] );
79 public function testMoveById() {
80 $name = ucfirst( __FUNCTION__
);
82 $id = $this->createPage( $name );
84 $res = $this->doApiRequestWithToken( [
90 $this->assertMoved( $name, "$name 2", $id );
91 $this->assertArrayNotHasKey( 'warnings', $res[0] );
94 public function testMoveNonexistent() {
95 $this->setExpectedException( ApiUsageException
::class,
96 "The page you specified doesn't exist." );
98 $this->doApiRequestWithToken( [
100 'from' => 'Nonexistent page',
101 'to' => 'Different page'
105 public function testMoveNonexistentId() {
106 $this->setExpectedException( ApiUsageException
::class,
107 'There is no page with ID 2147483647.' );
109 $this->doApiRequestWithToken( [
111 'fromid' => pow( 2, 31 ) - 1,
112 'to' => 'Different page',
116 public function testMoveToInvalidPageName() {
117 $this->setExpectedException( ApiUsageException
::class, 'Bad title "[".' );
119 $name = ucfirst( __FUNCTION__
);
120 $id = $this->createPage( $name );
123 $this->doApiRequestWithToken( [
129 $this->assertSame( $id, Title
::newFromText( $name )->getArticleID() );
135 public function testPingLimiter() {
136 $this->setExpectedException( ApiUsageException
::class,
137 "You've exceeded your rate limit. Please wait some time and try again." );
139 $name = ucfirst( __FUNCTION__
);
141 $this->setMwGlobals( 'wgMainCacheType', 'hash' );
143 $this->mergeMwGlobalArrayValue( 'wgRateLimits',
144 [ 'move' => [ '&can-bypass' => false, 'user' => [ 1, 60 ] ] ] );
146 $id = $this->createPage( $name );
148 $res = $this->doApiRequestWithToken( [
154 $this->assertMoved( $name, "$name 2", $id );
155 $this->assertArrayNotHasKey( 'warnings', $res[0] );
158 $this->doApiRequestWithToken( [
164 $this->assertSame( $id, Title
::newFromText( "$name 2" )->getArticleID() );
165 $this->assertFalse( Title
::newFromText( "$name 3" )->exists(),
166 "\"$name 3\" should not exist" );
170 public function testTagsNoPermission() {
171 $this->setExpectedException( ApiUsageException
::class,
172 'You do not have permission to apply change tags along with your changes.' );
174 $name = ucfirst( __FUNCTION__
);
176 ChangeTags
::defineTag( 'custom tag' );
178 $this->setGroupPermissions( 'user', 'applychangetags', false );
180 $id = $this->createPage( $name );
183 $this->doApiRequestWithToken( [
187 'tags' => 'custom tag',
190 $this->assertSame( $id, Title
::newFromText( $name )->getArticleID() );
191 $this->assertFalse( Title
::newFromText( "$name 2" )->exists(),
192 "\"$name 2\" should not exist" );
196 public function testSelfMove() {
197 $this->setExpectedException( ApiUsageException
::class,
198 'The title is the same; cannot move a page over itself.' );
200 $name = ucfirst( __FUNCTION__
);
201 $this->createPage( $name );
203 $this->doApiRequestWithToken( [
210 public function testMoveTalk() {
211 $name = ucfirst( __FUNCTION__
);
213 $id = $this->createPage( $name );
214 $talkId = $this->createPage( "Talk:$name" );
216 $res = $this->doApiRequestWithToken( [
223 $this->assertMoved( $name, "$name 2", $id );
224 $this->assertMoved( "Talk:$name", "Talk:$name 2", $talkId );
226 $this->assertArrayNotHasKey( 'warnings', $res[0] );
229 public function testMoveTalkFailed() {
230 $name = ucfirst( __FUNCTION__
);
232 $id = $this->createPage( $name );
233 $talkId = $this->createPage( "Talk:$name" );
234 $talkDestinationId = $this->createPage( "Talk:$name 2" );
236 $res = $this->doApiRequestWithToken( [
243 $this->assertMoved( $name, "$name 2", $id );
244 $this->assertSame( $talkId, Title
::newFromText( "Talk:$name" )->getArticleID() );
245 $this->assertSame( $talkDestinationId,
246 Title
::newFromText( "Talk:$name 2" )->getArticleID() );
247 $this->assertSame( [ [
248 'message' => 'articleexists',
250 'code' => 'articleexists',
252 ] ], $res[0]['move']['talkmove-errors'] );
254 $this->assertArrayNotHasKey( 'warnings', $res[0] );
257 public function testMoveSubpages() {
258 $name = ucfirst( __FUNCTION__
);
260 $this->mergeMwGlobalArrayValue( 'wgNamespacesWithSubpages', [ NS_MAIN
=> true ] );
262 $pages = [ $name, "$name/1", "$name/2", "Talk:$name", "Talk:$name/1", "Talk:$name/3" ];
264 foreach ( array_merge( $pages, [ "$name/error", "$name 2/error" ] ) as $page ) {
265 $ids[$page] = $this->createPage( $page );
268 $res = $this->doApiRequestWithToken( [
273 'movesubpages' => '',
276 foreach ( $pages as $page ) {
277 $this->assertMoved( $page, str_replace( $name, "$name 2", $page ), $ids[$page] );
280 $this->assertSame( $ids["$name/error"],
281 Title
::newFromText( "$name/error" )->getArticleID() );
282 $this->assertSame( $ids["$name 2/error"],
283 Title
::newFromText( "$name 2/error" )->getArticleID() );
285 $results = array_merge( $res[0]['move']['subpages'], $res[0]['move']['subpages-talk'] );
286 foreach ( $results as $arr ) {
287 if ( $arr['from'] === "$name/error" ) {
288 $this->assertSame( [ [
289 'message' => 'articleexists',
291 'code' => 'articleexists',
293 ] ], $arr['errors'] );
295 $this->assertSame( str_replace( $name, "$name 2", $arr['from'] ), $arr['to'] );
297 $this->assertCount( 2, $arr );
300 $this->assertArrayNotHasKey( 'warnings', $res[0] );
303 public function testMoveNoPermission() {
304 $this->setExpectedException( ApiUsageException
::class,
305 'You must be a registered user and [[Special:UserLogin|logged in]] to move a page.' );
307 $name = ucfirst( __FUNCTION__
);
309 $id = $this->createPage( $name );
314 $this->doApiRequestWithToken( [
320 $this->assertSame( $id, Title
::newFromText( "$name" )->getArticleID() );
321 $this->assertFalse( Title
::newFromText( "$name 2" )->exists(),
322 "\"$name 2\" should not exist" );
326 public function testSuppressRedirect() {
327 $name = ucfirst( __FUNCTION__
);
329 $id = $this->createPage( $name );
331 $res = $this->doApiRequestWithToken( [
338 $this->assertMoved( $name, "$name 2", $id, 'noredirect' );
339 $this->assertArrayNotHasKey( 'warnings', $res[0] );
342 public function testSuppressRedirectNoPermission() {
343 $name = ucfirst( __FUNCTION__
);
345 $this->setGroupPermissions( 'sysop', 'suppressredirect', false );
347 $id = $this->createPage( $name );
349 $res = $this->doApiRequestWithToken( [
356 $this->assertMoved( $name, "$name 2", $id );
357 $this->assertArrayNotHasKey( 'warnings', $res[0] );
360 public function testMoveSubpagesError() {
361 $name = ucfirst( __FUNCTION__
);
363 // Subpages are allowed in talk but not main
364 $idBase = $this->createPage( "Talk:$name" );
365 $idSub = $this->createPage( "Talk:$name/1" );
367 $res = $this->doApiRequestWithToken( [
369 'from' => "Talk:$name",
371 'movesubpages' => '',
374 $this->assertMoved( "Talk:$name", $name, $idBase );
375 $this->assertSame( $idSub, Title
::newFromText( "Talk:$name/1" )->getArticleID() );
376 $this->assertFalse( Title
::newFromText( "$name/1" )->exists(),
377 "\"$name/1\" should not exist" );
379 $this->assertSame( [ 'errors' => [ [
380 'message' => 'namespace-nosubpages',
382 'code' => 'namespace-nosubpages',
384 ] ] ], $res[0]['move']['subpages'] );
386 $this->assertArrayNotHasKey( 'warnings', $res[0] );