Localisation updates from https://translatewiki.net.
[mediawiki.git] / tests / phpunit / includes / linkeddata / PageDataRequestHandlerTest.php
blob9add7ab8bc533c3f0b9de0144ea6197e00e660ea
1 <?php
3 use MediaWiki\Context\DerivativeContext;
4 use MediaWiki\Context\RequestContext;
5 use MediaWiki\LinkedData\PageDataRequestHandler;
6 use MediaWiki\Output\OutputPage;
7 use MediaWiki\Request\FauxRequest;
8 use MediaWiki\Request\FauxResponse;
9 use MediaWiki\Title\Title;
10 use MediaWiki\Title\TitleFactory;
12 /**
13 * @covers \MediaWiki\LinkedData\PageDataRequestHandler
14 * @group PageData
16 class PageDataRequestHandlerTest extends \MediaWikiLangTestCase {
18 /**
19 * @var Title
21 private $interfaceTitle;
23 /**
24 * @var int
26 private $obLevel;
28 protected function setUp(): void {
29 parent::setUp();
31 $this->interfaceTitle = Title::newFromText( __CLASS__ );
32 // Force the content model to avoid DB queries.
33 $this->interfaceTitle->setContentModel( CONTENT_MODEL_WIKITEXT );
34 $this->obLevel = ob_get_level();
37 protected function assertPostConditions(): void {
38 $obLevel = ob_get_level();
39 if ( $obLevel !== $this->obLevel ) {
40 $this->fail( "Test changed output buffer level: was {$this->obLevel}" .
41 "before test, but $obLevel after test."
44 parent::assertPostConditions();
47 protected function tearDown(): void {
48 while ( ob_get_level() > $this->obLevel ) {
49 ob_end_clean();
51 parent::tearDown();
54 /**
55 * @return PageDataRequestHandler
57 protected function newHandler() {
58 return new PageDataRequestHandler();
61 /**
62 * @param array $params
63 * @param string[] $headers
65 * @return OutputPage
67 protected function makeOutputPage( array $params, array $headers ) {
68 // construct request
69 $request = new FauxRequest( $params );
70 $request->response()->header( 'Status: 200 OK', true, 200 ); // init/reset
72 foreach ( $headers as $name => $value ) {
73 $request->setHeader( strtoupper( $name ), $value );
76 // construct Context and OutputPage
77 $context = new DerivativeContext( RequestContext::getMain() );
78 $context->setRequest( $request );
80 $output = new OutputPage( $context );
81 $output->setTitle( $this->interfaceTitle );
82 $context->setOutput( $output );
84 return $output;
87 public static function handleRequestProvider() {
88 $cases = [];
90 $cases[] = [ '', [], [], 'Invalid title', 400 ];
92 $cases[] = [
93 '',
94 [ 'target' => 'Helsinki' ],
95 [],
96 '',
97 303,
98 [ 'Location' => '?title=Helsinki&action=raw' ]
101 $subpageCases = [];
102 foreach ( $cases as $c ) {
103 $case = $c;
104 $case[0] = 'main/';
106 if ( isset( $case[1]['target'] ) ) {
107 $case[0] .= $case[1]['target'];
108 unset( $case[1]['target'] );
111 $subpageCases[] = $case;
114 $cases = array_merge( $cases, $subpageCases );
116 $cases[] = [
118 [ 'target' => 'Helsinki' ],
119 [ 'Accept' => 'text/HTML' ],
121 303,
122 [ 'Location' => '/wiki/Helsinki' ]
125 $cases[] = [
128 'target' => 'Helsinki',
129 'revision' => '4242',
131 [ 'Accept' => 'text/HTML' ],
133 303,
134 [ 'Location' => '?title=Helsinki&oldid=4242' ]
137 $cases[] = [
138 '/Helsinki',
142 303,
143 [ 'Location' => '?title=Helsinki&action=raw' ]
146 // #31: /Q5 with "Accept: text/foobar" triggers a 406
147 $cases[] = [
148 'main/Helsinki',
150 [ 'Accept' => 'text/foobar' ],
151 'No matching format found',
152 406,
155 $cases[] = [
156 'no slash',
158 [ 'Accept' => 'text/HTML' ],
159 'Invalid title',
160 400,
163 $cases[] = [
164 'main',
166 [ 'Accept' => 'text/HTML' ],
167 'Invalid title',
168 400,
171 $cases[] = [
172 'xyz/Helsinki',
174 [ 'Accept' => 'text/HTML' ],
175 'Invalid title',
176 400,
179 $cases[] = [
180 'main/Helsinki',
182 [ 'Accept' => 'text/HTML' ],
184 303,
185 [ 'Location' => '/wiki/Helsinki' ]
188 $cases[] = [
189 '/Helsinki',
191 [ 'Accept' => 'text/HTML' ],
193 303,
194 [ 'Location' => '/wiki/Helsinki' ]
197 $cases[] = [
198 'main/AC/DC',
200 [ 'Accept' => 'text/HTML' ],
202 303,
203 [ 'Location' => '/wiki/AC/DC' ]
206 return $cases;
210 * @dataProvider handleRequestProvider
212 * @param string $subpage The subpage to request (or '')
213 * @param array $params Request parameters
214 * @param array $headers Request headers
215 * @param string $expectedOutput
216 * @param int $expectedStatusCode Expected HTTP status code.
217 * @param string[] $expectedHeaders Expected HTTP response headers.
219 public function testHandleRequest(
220 $subpage,
221 array $params,
222 array $headers,
223 $expectedOutput = '',
224 $expectedStatusCode = 200,
225 array $expectedHeaders = []
227 $titleFactory = $this->createMock( TitleFactory::class );
228 $titleFactory->method( 'newFromTextThrow' )->willReturnCallback( static function ( $text, $ns ) {
229 // Force the content model to avoid DB queries.
230 $ret = Title::newFromTextThrow( $text, $ns );
231 $ret->setContentModel( CONTENT_MODEL_WIKITEXT );
232 return $ret;
233 } );
234 $this->setService( 'TitleFactory', $titleFactory );
235 $output = $this->makeOutputPage( $params, $headers );
236 $request = $output->getRequest();
238 /** @var FauxResponse $response */
239 $response = $request->response();
241 // construct handler
242 $handler = $this->newHandler();
244 try {
245 ob_start();
246 $handler->handleRequest( $subpage, $request, $output );
248 if ( $output->getRedirect() !== '' ) {
249 // hack to apply redirect to web response
250 $output->output();
253 $text = ob_get_clean();
255 $this->assertEquals( $expectedStatusCode, $response->getStatusCode(), 'status code' );
256 $this->assertSame( $expectedOutput, $text, 'output' );
258 foreach ( $expectedHeaders as $name => $exp ) {
259 $value = $response->getHeader( $name );
260 $this->assertNotNull( $value, "header: $name" );
261 $this->assertIsString( $value, "header: $name" );
262 $this->assertStringEndsWith( $exp, $value, "header: $name" );
264 } catch ( HttpError $e ) {
265 ob_end_clean();
266 $this->assertEquals( $expectedStatusCode, $e->getStatusCode(), 'status code' );
267 $this->assertStringContainsString( $expectedOutput, $e->getHTML(), 'error output' );
270 // We always set "Access-Control-Allow-Origin: *"
271 $this->assertSame( '*', $response->getHeader( 'Access-Control-Allow-Origin' ) );
274 public static function provideHttpContentNegotiation() {
275 $helsinki = Title::makeTitle( NS_MAIN, 'Helsinki' );
276 // Force the content model to avoid DB queries.
277 $helsinki->setContentModel( CONTENT_MODEL_WIKITEXT );
278 return [
279 'Accept Header of HTML' => [
280 $helsinki,
281 [ 'ACCEPT' => 'text/html' ], // headers
282 'Helsinki'
284 'Accept Header without weights' => [
285 $helsinki,
286 [ 'ACCEPT' => '*/*, text/html, text/x-wiki' ],
287 'Helsinki&action=raw'
289 'Accept Header with weights' => [
290 $helsinki,
291 [ 'ACCEPT' => 'text/*; q=0.5, text/json; q=0.7, application/rdf+xml; q=0.8' ],
292 'Helsinki&action=raw'
294 'Accept Header accepting evertyhing and HTML' => [
295 $helsinki,
296 [ 'ACCEPT' => 'text/html, */*' ],
297 'Helsinki&action=raw'
299 'No Accept Header' => [
300 $helsinki,
302 'Helsinki&action=raw'
308 * @dataProvider provideHttpContentNegotiation
310 * @param Title $title
311 * @param array $headers Request headers
312 * @param string $expectedRedirectSuffix Expected suffix of the HTTP Location header.
314 public function testHttpContentNegotiation(
315 Title $title,
316 array $headers,
317 $expectedRedirectSuffix
319 /** @var FauxResponse $response */
320 $output = $this->makeOutputPage( [], $headers );
321 $request = $output->getRequest();
323 $handler = $this->newHandler();
324 $handler->httpContentNegotiation( $request, $output, $title );
326 $this->assertStringEndsWith(
327 $expectedRedirectSuffix,
328 $output->getRedirect(),
329 'redirect target'