fetchTextTest.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <?php
  2. require_once __DIR__ . "/../../../maintenance/fetchText.php";
  3. /**
  4. * Mock for the input/output of FetchText
  5. *
  6. * FetchText internally tries to access stdin and stdout. We mock those aspects
  7. * for testing.
  8. */
  9. class SemiMockedFetchText extends FetchText {
  10. /**
  11. * @var string|null Text to pass as stdin
  12. */
  13. private $mockStdinText = null;
  14. /**
  15. * @var bool Whether or not a text for stdin has been provided
  16. */
  17. private $mockSetUp = false;
  18. /**
  19. * @var array Invocation counters for the mocked aspects
  20. */
  21. private $mockInvocations = [ 'getStdin' => 0 ];
  22. /**
  23. * Data for the fake stdin
  24. *
  25. * @param string $stdin The string to be used instead of stdin
  26. */
  27. function mockStdin( $stdin ) {
  28. $this->mockStdinText = $stdin;
  29. $this->mockSetUp = true;
  30. }
  31. /**
  32. * Gets invocation counters for mocked methods.
  33. *
  34. * @return array An array, whose keys are function names. The corresponding values
  35. * denote the number of times the function has been invoked.
  36. */
  37. function mockGetInvocations() {
  38. return $this->mockInvocations;
  39. }
  40. // -----------------------------------------------------------------
  41. // Mocked functions from FetchText follow.
  42. function getStdin( $len = null ) {
  43. $this->mockInvocations['getStdin']++;
  44. if ( $len !== null ) {
  45. throw new PHPUnit_Framework_ExpectationFailedException(
  46. "Tried to get stdin with non null parameter" );
  47. }
  48. if ( !$this->mockSetUp ) {
  49. throw new PHPUnit_Framework_ExpectationFailedException(
  50. "Tried to get stdin before setting up rerouting" );
  51. }
  52. return fopen( 'data://text/plain,' . $this->mockStdinText, 'r' );
  53. }
  54. }
  55. /**
  56. * TestCase for FetchText
  57. *
  58. * @group Database
  59. * @group Dump
  60. * @covers FetchText
  61. */
  62. class FetchTextTest extends MediaWikiTestCase {
  63. // We add 5 Revisions for this test. Their corresponding text id's
  64. // are stored in the following 5 variables.
  65. private $textId1;
  66. private $textId2;
  67. private $textId3;
  68. private $textId4;
  69. private $textId5;
  70. /**
  71. * @var Exception|null As the current MediaWikiTestCase::run is not
  72. * robust enough to recover from thrown exceptions directly, we cannot
  73. * throw frow within addDBData, although it would be appropriate. Hence,
  74. * we catch the exception and store it until we are in setUp and may
  75. * finally rethrow the exception without crashing the test suite.
  76. */
  77. private $exceptionFromAddDBData;
  78. /**
  79. * @var FetchText The (mocked) FetchText that is to test
  80. */
  81. private $fetchText;
  82. /**
  83. * Adds a revision to a page, while returning the resuting text's id
  84. *
  85. * @param WikiPage $page The page to add the revision to
  86. * @param string $text The revisions text
  87. * @param string $summary The revisions summare
  88. * @return int
  89. * @throws MWException
  90. */
  91. private function addRevision( $page, $text, $summary ) {
  92. $status = $page->doEditContent(
  93. ContentHandler::makeContent( $text, $page->getTitle() ),
  94. $summary
  95. );
  96. if ( $status->isGood() ) {
  97. $value = $status->getValue();
  98. $revision = $value['revision'];
  99. $id = $revision->getTextId();
  100. if ( $id > 0 ) {
  101. return $id;
  102. }
  103. }
  104. throw new MWException( "Could not determine text id" );
  105. }
  106. function addDBData() {
  107. $this->tablesUsed[] = 'page';
  108. $this->tablesUsed[] = 'revision';
  109. $this->tablesUsed[] = 'text';
  110. $wikitextNamespace = $this->getDefaultWikitextNS();
  111. try {
  112. $title = Title::newFromText( 'FetchTextTestPage1', $wikitextNamespace );
  113. $page = WikiPage::factory( $title );
  114. $this->textId1 = $this->addRevision(
  115. $page,
  116. "FetchTextTestPage1Text1",
  117. "FetchTextTestPage1Summary1"
  118. );
  119. $title = Title::newFromText( 'FetchTextTestPage2', $wikitextNamespace );
  120. $page = WikiPage::factory( $title );
  121. $this->textId2 = $this->addRevision(
  122. $page,
  123. "FetchTextTestPage2Text1",
  124. "FetchTextTestPage2Summary1"
  125. );
  126. $this->textId3 = $this->addRevision(
  127. $page,
  128. "FetchTextTestPage2Text2",
  129. "FetchTextTestPage2Summary2"
  130. );
  131. $this->textId4 = $this->addRevision(
  132. $page,
  133. "FetchTextTestPage2Text3",
  134. "FetchTextTestPage2Summary3"
  135. );
  136. $this->textId5 = $this->addRevision(
  137. $page,
  138. "FetchTextTestPage2Text4 some additional Text ",
  139. "FetchTextTestPage2Summary4 extra "
  140. );
  141. } catch ( Exception $e ) {
  142. // We'd love to pass $e directly. However, ... see
  143. // documentation of exceptionFromAddDBData
  144. $this->exceptionFromAddDBData = $e;
  145. }
  146. }
  147. protected function setUp() {
  148. parent::setUp();
  149. // Check if any Exception is stored for rethrowing from addDBData
  150. if ( $this->exceptionFromAddDBData !== null ) {
  151. throw $this->exceptionFromAddDBData;
  152. }
  153. $this->fetchText = new SemiMockedFetchText();
  154. }
  155. /**
  156. * Helper to relate FetchText's input and output
  157. * @param string $input
  158. * @param string $expectedOutput
  159. */
  160. private function assertFilter( $input, $expectedOutput ) {
  161. $this->fetchText->mockStdin( $input );
  162. $this->fetchText->execute();
  163. $invocations = $this->fetchText->mockGetInvocations();
  164. $this->assertEquals( 1, $invocations['getStdin'],
  165. "getStdin invocation counter" );
  166. $this->expectOutputString( $expectedOutput );
  167. }
  168. // Instead of the following functions, a data provider would be great.
  169. // However, as data providers are evaluated /before/ addDBData, a data
  170. // provider would not know the required ids.
  171. function testExistingSimple() {
  172. $this->assertFilter( $this->textId2,
  173. $this->textId2 . "\n23\nFetchTextTestPage2Text1" );
  174. }
  175. function testExistingSimpleWithNewline() {
  176. $this->assertFilter( $this->textId2 . "\n",
  177. $this->textId2 . "\n23\nFetchTextTestPage2Text1" );
  178. }
  179. function testExistingSeveral() {
  180. $this->assertFilter( "$this->textId1\n$this->textId5\n"
  181. . "$this->textId3\n$this->textId3",
  182. implode( "", [
  183. $this->textId1 . "\n23\nFetchTextTestPage1Text1",
  184. $this->textId5 . "\n44\nFetchTextTestPage2Text4 "
  185. . "some additional Text",
  186. $this->textId3 . "\n23\nFetchTextTestPage2Text2",
  187. $this->textId3 . "\n23\nFetchTextTestPage2Text2"
  188. ] ) );
  189. }
  190. function testEmpty() {
  191. $this->assertFilter( "", null );
  192. }
  193. function testNonExisting() {
  194. $this->assertFilter( $this->textId5 + 10, ( $this->textId5 + 10 ) . "\n-1\n" );
  195. }
  196. function testNegativeInteger() {
  197. $this->assertFilter( "-42", "-42\n-1\n" );
  198. }
  199. function testFloatingPointNumberExisting() {
  200. // float -> int -> revision
  201. $this->assertFilter( $this->textId3 + 0.14159,
  202. $this->textId3 . "\n23\nFetchTextTestPage2Text2" );
  203. }
  204. function testFloatingPointNumberNonExisting() {
  205. $this->assertFilter( $this->textId5 + 3.14159,
  206. ( $this->textId5 + 3 ) . "\n-1\n" );
  207. }
  208. function testCharacters() {
  209. $this->assertFilter( "abc", "0\n-1\n" );
  210. }
  211. function testMix() {
  212. $this->assertFilter( "ab\n" . $this->textId4 . ".5cd\n\nefg\n" . $this->textId2
  213. . "\n" . $this->textId3,
  214. implode( "", [
  215. "0\n-1\n",
  216. $this->textId4 . "\n23\nFetchTextTestPage2Text3",
  217. "0\n-1\n",
  218. "0\n-1\n",
  219. $this->textId2 . "\n23\nFetchTextTestPage2Text1",
  220. $this->textId3 . "\n23\nFetchTextTestPage2Text2"
  221. ] ) );
  222. }
  223. }