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