EditPageTest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. <?php
  2. use MediaWiki\MediaWikiServices;
  3. /**
  4. * @group Editing
  5. *
  6. * @group Database
  7. * ^--- tell jenkins this test needs the database
  8. *
  9. * @group medium
  10. * ^--- tell phpunit that these test cases may take longer than 2 seconds.
  11. */
  12. class EditPageTest extends MediaWikiLangTestCase {
  13. protected function setUp() {
  14. parent::setUp();
  15. $contLang = MediaWikiServices::getInstance()->getContentLanguage();
  16. $this->setContentLang( $contLang );
  17. $this->setMwGlobals( [
  18. 'wgExtraNamespaces' => [
  19. 12312 => 'Dummy',
  20. 12313 => 'Dummy_talk',
  21. ],
  22. 'wgNamespaceContentModels' => [ 12312 => 'testing' ],
  23. ] );
  24. $this->mergeMwGlobalArrayValue(
  25. 'wgContentHandlers',
  26. [ 'testing' => 'DummyContentHandlerForTesting' ]
  27. );
  28. }
  29. /**
  30. * @dataProvider provideExtractSectionTitle
  31. * @covers EditPage::extractSectionTitle
  32. */
  33. public function testExtractSectionTitle( $section, $title ) {
  34. $extracted = EditPage::extractSectionTitle( $section );
  35. $this->assertEquals( $title, $extracted );
  36. }
  37. public static function provideExtractSectionTitle() {
  38. return [
  39. [
  40. "== Test ==\n\nJust a test section.",
  41. "Test"
  42. ],
  43. [
  44. "An initial section, no header.",
  45. false
  46. ],
  47. [
  48. "An initial section with a fake heder (T34617)\n\n== Test == ??\nwtf",
  49. false
  50. ],
  51. [
  52. "== Section ==\nfollowed by a fake == Non-section == ??\nnoooo",
  53. "Section"
  54. ],
  55. [
  56. "== Section== \t\r\n followed by whitespace (T37051)",
  57. 'Section',
  58. ],
  59. ];
  60. }
  61. protected function forceRevisionDate( WikiPage $page, $timestamp ) {
  62. $dbw = wfGetDB( DB_MASTER );
  63. $dbw->update( 'revision',
  64. [ 'rev_timestamp' => $dbw->timestamp( $timestamp ) ],
  65. [ 'rev_id' => $page->getLatest() ] );
  66. $page->clear();
  67. }
  68. /**
  69. * User input text is passed to rtrim() by edit page. This is a simple
  70. * wrapper around assertEquals() which calls rrtrim() to normalize the
  71. * expected and actual texts.
  72. * @param string $expected
  73. * @param string $actual
  74. * @param string $msg
  75. */
  76. protected function assertEditedTextEquals( $expected, $actual, $msg = '' ) {
  77. $this->assertEquals( rtrim( $expected ), rtrim( $actual ), $msg );
  78. }
  79. /**
  80. * Performs an edit and checks the result.
  81. *
  82. * @param string|Title $title The title of the page to edit
  83. * @param string|null $baseText Some text to create the page with before attempting the edit.
  84. * @param User|string|null $user The user to perform the edit as.
  85. * @param array $edit An array of request parameters used to define the edit to perform.
  86. * Some well known fields are:
  87. * * wpTextbox1: the text to submit
  88. * * wpSummary: the edit summary
  89. * * wpEditToken: the edit token (will be inserted if not provided)
  90. * * wpEdittime: timestamp of the edit's base revision (will be inserted
  91. * if not provided)
  92. * * wpStarttime: timestamp when the edit started (will be inserted if not provided)
  93. * * wpSectionTitle: the section to edit
  94. * * wpMinorEdit: mark as minor edit
  95. * * wpWatchthis: whether to watch the page
  96. * @param int|null $expectedCode The expected result code (EditPage::AS_XXX constants).
  97. * Set to null to skip the check.
  98. * @param string|null $expectedText The text expected to be on the page after the edit.
  99. * Set to null to skip the check.
  100. * @param string|null $message An optional message to show along with any error message.
  101. *
  102. * @return WikiPage The page that was just edited, useful for getting the edit's rev_id, etc.
  103. */
  104. protected function assertEdit( $title, $baseText, $user = null, array $edit,
  105. $expectedCode = null, $expectedText = null, $message = null
  106. ) {
  107. if ( is_string( $title ) ) {
  108. $ns = $this->getDefaultWikitextNS();
  109. $title = Title::newFromText( $title, $ns );
  110. }
  111. $this->assertNotNull( $title );
  112. if ( is_string( $user ) ) {
  113. $user = User::newFromName( $user );
  114. if ( $user->getId() === 0 ) {
  115. $user->addToDatabase();
  116. }
  117. }
  118. $page = WikiPage::factory( $title );
  119. if ( $baseText !== null ) {
  120. $content = ContentHandler::makeContent( $baseText, $title );
  121. $page->doEditContent( $content, "base text for test" );
  122. $this->forceRevisionDate( $page, '20120101000000' );
  123. // sanity check
  124. $page->clear();
  125. $currentText = ContentHandler::getContentText( $page->getContent() );
  126. # EditPage rtrim() the user input, so we alter our expected text
  127. # to reflect that.
  128. $this->assertEditedTextEquals( $baseText, $currentText );
  129. }
  130. if ( $user == null ) {
  131. $user = $GLOBALS['wgUser'];
  132. } else {
  133. $this->setMwGlobals( 'wgUser', $user );
  134. }
  135. if ( !isset( $edit['wpEditToken'] ) ) {
  136. $edit['wpEditToken'] = $user->getEditToken();
  137. }
  138. if ( !isset( $edit['wpEdittime'] ) ) {
  139. $edit['wpEdittime'] = $page->exists() ? $page->getTimestamp() : '';
  140. }
  141. if ( !isset( $edit['wpStarttime'] ) ) {
  142. $edit['wpStarttime'] = wfTimestampNow();
  143. }
  144. if ( !isset( $edit['wpUnicodeCheck'] ) ) {
  145. $edit['wpUnicodeCheck'] = EditPage::UNICODE_CHECK;
  146. }
  147. $req = new FauxRequest( $edit, true ); // session ??
  148. $article = new Article( $title );
  149. $article->getContext()->setTitle( $title );
  150. $ep = new EditPage( $article );
  151. $ep->setContextTitle( $title );
  152. $ep->importFormData( $req );
  153. $bot = isset( $edit['bot'] ) ? (bool)$edit['bot'] : false;
  154. // this is where the edit happens!
  155. // Note: don't want to use EditPage::AttemptSave, because it messes with $wgOut
  156. // and throws exceptions like PermissionsError
  157. $status = $ep->internalAttemptSave( $result, $bot );
  158. if ( $expectedCode !== null ) {
  159. // check edit code
  160. $this->assertEquals( $expectedCode, $status->value,
  161. "Expected result code mismatch. $message" );
  162. }
  163. $page = WikiPage::factory( $title );
  164. if ( $expectedText !== null ) {
  165. // check resulting page text
  166. $content = $page->getContent();
  167. $text = ContentHandler::getContentText( $content );
  168. # EditPage rtrim() the user input, so we alter our expected text
  169. # to reflect that.
  170. $this->assertEditedTextEquals( $expectedText, $text,
  171. "Expected article text mismatch. $message" );
  172. }
  173. return $page;
  174. }
  175. public static function provideCreatePages() {
  176. return [
  177. [ 'expected article being created',
  178. 'EditPageTest_testCreatePage',
  179. null,
  180. 'Hello World!',
  181. EditPage::AS_SUCCESS_NEW_ARTICLE,
  182. 'Hello World!'
  183. ],
  184. [ 'expected article not being created if empty',
  185. 'EditPageTest_testCreatePage',
  186. null,
  187. '',
  188. EditPage::AS_BLANK_ARTICLE,
  189. null
  190. ],
  191. [ 'expected MediaWiki: page being created',
  192. 'MediaWiki:January',
  193. 'UTSysop',
  194. 'Not January',
  195. EditPage::AS_SUCCESS_NEW_ARTICLE,
  196. 'Not January'
  197. ],
  198. [ 'expected not-registered MediaWiki: page not being created if empty',
  199. 'MediaWiki:EditPageTest_testCreatePage',
  200. 'UTSysop',
  201. '',
  202. EditPage::AS_BLANK_ARTICLE,
  203. null
  204. ],
  205. [ 'expected registered MediaWiki: page being created even if empty',
  206. 'MediaWiki:January',
  207. 'UTSysop',
  208. '',
  209. EditPage::AS_SUCCESS_NEW_ARTICLE,
  210. ''
  211. ],
  212. [ 'expected registered MediaWiki: page whose default content is empty'
  213. . ' not being created if empty',
  214. 'MediaWiki:Ipb-default-expiry',
  215. 'UTSysop',
  216. '',
  217. EditPage::AS_BLANK_ARTICLE,
  218. ''
  219. ],
  220. [ 'expected MediaWiki: page not being created if text equals default message',
  221. 'MediaWiki:January',
  222. 'UTSysop',
  223. 'January',
  224. EditPage::AS_BLANK_ARTICLE,
  225. null
  226. ],
  227. [ 'expected empty article being created',
  228. 'EditPageTest_testCreatePage',
  229. null,
  230. '',
  231. EditPage::AS_SUCCESS_NEW_ARTICLE,
  232. '',
  233. true
  234. ],
  235. ];
  236. }
  237. /**
  238. * @dataProvider provideCreatePages
  239. * @covers EditPage
  240. */
  241. public function testCreatePage(
  242. $desc, $pageTitle, $user, $editText, $expectedCode, $expectedText, $ignoreBlank = false
  243. ) {
  244. $checkId = null;
  245. $this->setMwGlobals( 'wgHooks', [
  246. 'PageContentInsertComplete' => [ function (
  247. WikiPage &$page, User &$user, Content $content,
  248. $summary, $minor, $u1, $u2, &$flags, Revision $revision
  249. ) {
  250. // types/refs checked
  251. } ],
  252. 'PageContentSaveComplete' => [ function (
  253. WikiPage &$page, User &$user, Content $content,
  254. $summary, $minor, $u1, $u2, &$flags, Revision $revision,
  255. Status &$status, $baseRevId
  256. ) use ( &$checkId ) {
  257. $checkId = $status->value['revision']->getId();
  258. // types/refs checked
  259. } ],
  260. ] );
  261. $edit = [ 'wpTextbox1' => $editText ];
  262. if ( $ignoreBlank ) {
  263. $edit['wpIgnoreBlankArticle'] = 1;
  264. }
  265. $page = $this->assertEdit( $pageTitle, null, $user, $edit, $expectedCode, $expectedText, $desc );
  266. if ( $expectedCode != EditPage::AS_BLANK_ARTICLE ) {
  267. $latest = $page->getLatest();
  268. $page->doDeleteArticleReal( $pageTitle );
  269. $this->assertGreaterThan( 0, $latest, "Page revision ID updated in object" );
  270. $this->assertEquals( $latest, $checkId, "Revision in Status for hook" );
  271. }
  272. }
  273. /**
  274. * @dataProvider provideCreatePages
  275. * @covers EditPage
  276. */
  277. public function testCreatePageTrx(
  278. $desc, $pageTitle, $user, $editText, $expectedCode, $expectedText, $ignoreBlank = false
  279. ) {
  280. $checkIds = [];
  281. $this->setMwGlobals( 'wgHooks', [
  282. 'PageContentInsertComplete' => [ function (
  283. WikiPage &$page, User &$user, Content $content,
  284. $summary, $minor, $u1, $u2, &$flags, Revision $revision
  285. ) {
  286. // types/refs checked
  287. } ],
  288. 'PageContentSaveComplete' => [ function (
  289. WikiPage &$page, User &$user, Content $content,
  290. $summary, $minor, $u1, $u2, &$flags, Revision $revision,
  291. Status &$status, $baseRevId
  292. ) use ( &$checkIds ) {
  293. $checkIds[] = $status->value['revision']->getId();
  294. // types/refs checked
  295. } ],
  296. ] );
  297. wfGetDB( DB_MASTER )->begin( __METHOD__ );
  298. $edit = [ 'wpTextbox1' => $editText ];
  299. if ( $ignoreBlank ) {
  300. $edit['wpIgnoreBlankArticle'] = 1;
  301. }
  302. $page = $this->assertEdit(
  303. $pageTitle, null, $user, $edit, $expectedCode, $expectedText, $desc );
  304. $pageTitle2 = (string)$pageTitle . '/x';
  305. $page2 = $this->assertEdit(
  306. $pageTitle2, null, $user, $edit, $expectedCode, $expectedText, $desc );
  307. wfGetDB( DB_MASTER )->commit( __METHOD__ );
  308. $this->assertEquals( 0, DeferredUpdates::pendingUpdatesCount(), 'No deferred updates' );
  309. if ( $expectedCode != EditPage::AS_BLANK_ARTICLE ) {
  310. $latest = $page->getLatest();
  311. $page->doDeleteArticleReal( $pageTitle );
  312. $this->assertGreaterThan( 0, $latest, "Page #1 revision ID updated in object" );
  313. $this->assertEquals( $latest, $checkIds[0], "Revision #1 in Status for hook" );
  314. $latest2 = $page2->getLatest();
  315. $page2->doDeleteArticleReal( $pageTitle2 );
  316. $this->assertGreaterThan( 0, $latest2, "Page #2 revision ID updated in object" );
  317. $this->assertEquals( $latest2, $checkIds[1], "Revision #2 in Status for hook" );
  318. }
  319. }
  320. public function testUpdatePage() {
  321. $checkIds = [];
  322. $this->setMwGlobals( 'wgHooks', [
  323. 'PageContentInsertComplete' => [ function (
  324. WikiPage &$page, User &$user, Content $content,
  325. $summary, $minor, $u1, $u2, &$flags, Revision $revision
  326. ) {
  327. // types/refs checked
  328. } ],
  329. 'PageContentSaveComplete' => [ function (
  330. WikiPage &$page, User &$user, Content $content,
  331. $summary, $minor, $u1, $u2, &$flags, Revision $revision,
  332. Status &$status, $baseRevId
  333. ) use ( &$checkIds ) {
  334. $checkIds[] = $status->value['revision']->getId();
  335. // types/refs checked
  336. } ],
  337. ] );
  338. $text = "one";
  339. $edit = [
  340. 'wpTextbox1' => $text,
  341. 'wpSummary' => 'first update',
  342. ];
  343. $page = $this->assertEdit( 'EditPageTest_testUpdatePage', "zero", null, $edit,
  344. EditPage::AS_SUCCESS_UPDATE, $text,
  345. "expected successful update with given text" );
  346. $this->assertGreaterThan( 0, $checkIds[0], "First event rev ID set" );
  347. $this->forceRevisionDate( $page, '20120101000000' );
  348. $text = "two";
  349. $edit = [
  350. 'wpTextbox1' => $text,
  351. 'wpSummary' => 'second update',
  352. ];
  353. $this->assertEdit( 'EditPageTest_testUpdatePage', null, null, $edit,
  354. EditPage::AS_SUCCESS_UPDATE, $text,
  355. "expected successful update with given text" );
  356. $this->assertGreaterThan( 0, $checkIds[1], "Second edit hook rev ID set" );
  357. $this->assertGreaterThan( $checkIds[0], $checkIds[1], "Second event rev ID is higher" );
  358. }
  359. public function testUpdatePageTrx() {
  360. $text = "one";
  361. $edit = [
  362. 'wpTextbox1' => $text,
  363. 'wpSummary' => 'first update',
  364. ];
  365. $page = $this->assertEdit( 'EditPageTest_testTrxUpdatePage', "zero", null, $edit,
  366. EditPage::AS_SUCCESS_UPDATE, $text,
  367. "expected successful update with given text" );
  368. $this->forceRevisionDate( $page, '20120101000000' );
  369. $checkIds = [];
  370. $this->setMwGlobals( 'wgHooks', [
  371. 'PageContentSaveComplete' => [ function (
  372. WikiPage &$page, User &$user, Content $content,
  373. $summary, $minor, $u1, $u2, &$flags, Revision $revision,
  374. Status &$status, $baseRevId
  375. ) use ( &$checkIds ) {
  376. $checkIds[] = $status->value['revision']->getId();
  377. // types/refs checked
  378. } ],
  379. ] );
  380. wfGetDB( DB_MASTER )->begin( __METHOD__ );
  381. $text = "two";
  382. $edit = [
  383. 'wpTextbox1' => $text,
  384. 'wpSummary' => 'second update',
  385. ];
  386. $this->assertEdit( 'EditPageTest_testTrxUpdatePage', null, null, $edit,
  387. EditPage::AS_SUCCESS_UPDATE, $text,
  388. "expected successful update with given text" );
  389. $text = "three";
  390. $edit = [
  391. 'wpTextbox1' => $text,
  392. 'wpSummary' => 'third update',
  393. ];
  394. $this->assertEdit( 'EditPageTest_testTrxUpdatePage', null, null, $edit,
  395. EditPage::AS_SUCCESS_UPDATE, $text,
  396. "expected successful update with given text" );
  397. wfGetDB( DB_MASTER )->commit( __METHOD__ );
  398. $this->assertGreaterThan( 0, $checkIds[0], "First event rev ID set" );
  399. $this->assertGreaterThan( 0, $checkIds[1], "Second edit hook rev ID set" );
  400. $this->assertGreaterThan( $checkIds[0], $checkIds[1], "Second event rev ID is higher" );
  401. }
  402. public static function provideSectionEdit() {
  403. $text = 'Intro
  404. == one ==
  405. first section.
  406. == two ==
  407. second section.
  408. ';
  409. $sectionOne = '== one ==
  410. hello
  411. ';
  412. $newSection = '== new section ==
  413. hello
  414. ';
  415. $textWithNewSectionOne = preg_replace(
  416. '/== one ==.*== two ==/ms',
  417. "$sectionOne\n== two ==", $text
  418. );
  419. $textWithNewSectionAdded = "$text\n$newSection";
  420. return [
  421. [ # 0
  422. $text,
  423. '',
  424. 'hello',
  425. 'replace all',
  426. 'hello'
  427. ],
  428. [ # 1
  429. $text,
  430. '1',
  431. $sectionOne,
  432. 'replace first section',
  433. $textWithNewSectionOne,
  434. ],
  435. [ # 2
  436. $text,
  437. 'new',
  438. 'hello',
  439. 'new section',
  440. $textWithNewSectionAdded,
  441. ],
  442. ];
  443. }
  444. /**
  445. * @dataProvider provideSectionEdit
  446. * @covers EditPage
  447. */
  448. public function testSectionEdit( $base, $section, $text, $summary, $expected ) {
  449. $edit = [
  450. 'wpTextbox1' => $text,
  451. 'wpSummary' => $summary,
  452. 'wpSection' => $section,
  453. ];
  454. $this->assertEdit( 'EditPageTest_testSectionEdit', $base, null, $edit,
  455. EditPage::AS_SUCCESS_UPDATE, $expected,
  456. "expected successful update of section" );
  457. }
  458. public static function provideAutoMerge() {
  459. $tests = [];
  460. $tests[] = [ # 0: plain conflict
  461. "Elmo", # base edit user
  462. "one\n\ntwo\n\nthree\n",
  463. [ # adam's edit
  464. 'wpStarttime' => 1,
  465. 'wpTextbox1' => "ONE\n\ntwo\n\nthree\n",
  466. ],
  467. [ # berta's edit
  468. 'wpStarttime' => 2,
  469. 'wpTextbox1' => "(one)\n\ntwo\n\nthree\n",
  470. ],
  471. EditPage::AS_CONFLICT_DETECTED, # expected code
  472. "ONE\n\ntwo\n\nthree\n", # expected text
  473. 'expected edit conflict', # message
  474. ];
  475. $tests[] = [ # 1: successful merge
  476. "Elmo", # base edit user
  477. "one\n\ntwo\n\nthree\n",
  478. [ # adam's edit
  479. 'wpStarttime' => 1,
  480. 'wpTextbox1' => "ONE\n\ntwo\n\nthree\n",
  481. ],
  482. [ # berta's edit
  483. 'wpStarttime' => 2,
  484. 'wpTextbox1' => "one\n\ntwo\n\nTHREE\n",
  485. ],
  486. EditPage::AS_SUCCESS_UPDATE, # expected code
  487. "ONE\n\ntwo\n\nTHREE\n", # expected text
  488. 'expected automatic merge', # message
  489. ];
  490. $text = "Intro\n\n";
  491. $text .= "== first section ==\n\n";
  492. $text .= "one\n\ntwo\n\nthree\n\n";
  493. $text .= "== second section ==\n\n";
  494. $text .= "four\n\nfive\n\nsix\n\n";
  495. // extract the first section.
  496. $section = preg_replace( '/.*(== first section ==.*)== second section ==.*/sm', '$1', $text );
  497. // generate expected text after merge
  498. $expected = str_replace( 'one', 'ONE', str_replace( 'three', 'THREE', $text ) );
  499. $tests[] = [ # 2: merge in section
  500. "Elmo", # base edit user
  501. $text,
  502. [ # adam's edit
  503. 'wpStarttime' => 1,
  504. 'wpTextbox1' => str_replace( 'one', 'ONE', $section ),
  505. 'wpSection' => '1'
  506. ],
  507. [ # berta's edit
  508. 'wpStarttime' => 2,
  509. 'wpTextbox1' => str_replace( 'three', 'THREE', $section ),
  510. 'wpSection' => '1'
  511. ],
  512. EditPage::AS_SUCCESS_UPDATE, # expected code
  513. $expected, # expected text
  514. 'expected automatic section merge', # message
  515. ];
  516. // see whether it makes a difference who did the base edit
  517. $testsWithAdam = array_map( function ( $test ) {
  518. $test[0] = 'Adam'; // change base edit user
  519. return $test;
  520. }, $tests );
  521. $testsWithBerta = array_map( function ( $test ) {
  522. $test[0] = 'Berta'; // change base edit user
  523. return $test;
  524. }, $tests );
  525. return array_merge( $tests, $testsWithAdam, $testsWithBerta );
  526. }
  527. /**
  528. * @dataProvider provideAutoMerge
  529. * @covers EditPage
  530. */
  531. public function testAutoMerge( $baseUser, $text, $adamsEdit, $bertasEdit,
  532. $expectedCode, $expectedText, $message = null
  533. ) {
  534. $this->markTestSkippedIfNoDiff3();
  535. // create page
  536. $ns = $this->getDefaultWikitextNS();
  537. $title = Title::newFromText( 'EditPageTest_testAutoMerge', $ns );
  538. $page = WikiPage::factory( $title );
  539. if ( $page->exists() ) {
  540. $page->doDeleteArticle( "clean slate for testing" );
  541. }
  542. $baseEdit = [
  543. 'wpTextbox1' => $text,
  544. ];
  545. $page = $this->assertEdit( 'EditPageTest_testAutoMerge', null,
  546. $baseUser, $baseEdit, null, null, __METHOD__ );
  547. $this->forceRevisionDate( $page, '20120101000000' );
  548. $edittime = $page->getTimestamp();
  549. // start timestamps for conflict detection
  550. if ( !isset( $adamsEdit['wpStarttime'] ) ) {
  551. $adamsEdit['wpStarttime'] = 1;
  552. }
  553. if ( !isset( $bertasEdit['wpStarttime'] ) ) {
  554. $bertasEdit['wpStarttime'] = 2;
  555. }
  556. $starttime = wfTimestampNow();
  557. $adamsTime = wfTimestamp(
  558. TS_MW,
  559. (int)wfTimestamp( TS_UNIX, $starttime ) + (int)$adamsEdit['wpStarttime']
  560. );
  561. $bertasTime = wfTimestamp(
  562. TS_MW,
  563. (int)wfTimestamp( TS_UNIX, $starttime ) + (int)$bertasEdit['wpStarttime']
  564. );
  565. $adamsEdit['wpStarttime'] = $adamsTime;
  566. $bertasEdit['wpStarttime'] = $bertasTime;
  567. $adamsEdit['wpSummary'] = 'Adam\'s edit';
  568. $bertasEdit['wpSummary'] = 'Bertas\'s edit';
  569. $adamsEdit['wpEdittime'] = $edittime;
  570. $bertasEdit['wpEdittime'] = $edittime;
  571. // first edit
  572. $this->assertEdit( 'EditPageTest_testAutoMerge', null, 'Adam', $adamsEdit,
  573. EditPage::AS_SUCCESS_UPDATE, null, "expected successful update" );
  574. // second edit
  575. $this->assertEdit( 'EditPageTest_testAutoMerge', null, 'Berta', $bertasEdit,
  576. $expectedCode, $expectedText, $message );
  577. }
  578. /**
  579. * @depends testAutoMerge
  580. */
  581. public function testCheckDirectEditingDisallowed_forNonTextContent() {
  582. $title = Title::newFromText( 'Dummy:NonTextPageForEditPage' );
  583. $page = WikiPage::factory( $title );
  584. $article = new Article( $title );
  585. $article->getContext()->setTitle( $title );
  586. $ep = new EditPage( $article );
  587. $ep->setContextTitle( $title );
  588. $user = $GLOBALS['wgUser'];
  589. $edit = [
  590. 'wpTextbox1' => serialize( 'non-text content' ),
  591. 'wpEditToken' => $user->getEditToken(),
  592. 'wpEdittime' => '',
  593. 'wpStarttime' => wfTimestampNow(),
  594. 'wpUnicodeCheck' => EditPage::UNICODE_CHECK,
  595. ];
  596. $req = new FauxRequest( $edit, true );
  597. $ep->importFormData( $req );
  598. $this->setExpectedException(
  599. MWException::class,
  600. 'This content model is not supported: testing'
  601. );
  602. $ep->internalAttemptSave( $result, false );
  603. }
  604. }