aboutsummaryrefslogtreecommitdiffstats
path: root/tests/phpunit/unit/includes/Rest/Handler/HandlerTestTrait.php
blob: 1f6a876e8fc11a6f0a6df7a7355859ac45bcad8d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
<?php

namespace MediaWiki\Tests\Rest\Handler;

use MediaWiki\Permissions\PermissionManager;
use MediaWiki\Rest\Handler;
use MediaWiki\Rest\HttpException;
use MediaWiki\Rest\RequestInterface;
use MediaWiki\Rest\Response;
use MediaWiki\Rest\ResponseFactory;
use MediaWiki\Rest\Router;
use MediaWiki\Rest\Validator\Validator;
use MediaWiki\User\UserIdentityValue;
use MediaWikiTestCaseTrait;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\MockObject\MockObject;
use Title;
use Wikimedia\Message\ITextFormatter;
use Wikimedia\Message\MessageValue;
use Wikimedia\ObjectFactory;
use Wikimedia\Services\ServiceContainer;

/**
 * A trait providing utility functions for testing Handler classes.
 * This trait is intended to be used on subclasses of MediaWikiUnitTestCase
 * or MediaWikiIntegrationTestCase.
 *
 * @package MediaWiki\Tests\Rest\Handler
 */
trait HandlerTestTrait {

	use MediaWikiTestCaseTrait;

	/** @var int */
	private $pageIdCounter = 0;

	/**
	 * Expected to be provided by the class, probably inherited from TestCase.
	 *
	 * @param string $originalClassName
	 *
	 * @return MockObject
	 */
	abstract protected function createMock( $originalClassName ): MockObject;

	/**
	 * Executes the given Handler on the given request.
	 *
	 * @param Handler $handler
	 * @param RequestInterface $request
	 * @param array $config
	 *
	 * @return Response
	 */
	private function executeHandler( Handler $handler, RequestInterface $request, $config = [] ) {
		$formatter = $this->createMock( ITextFormatter::class );
		$formatter->method( 'format' )->willReturnCallback( function ( MessageValue $msg ) {
			return $msg->dump();
		} );

		/** @var ResponseFactory|MockObject $responseFactory */
		$responseFactory = new ResponseFactory( [ 'qqx' => $formatter ] );

		/** @var PermissionManager|MockObject $permissionManager */
		$permissionManager = $this->createNoOpMock(
			PermissionManager::class, [ 'userCan', 'userHasRight' ]
		);
		$permissionManager->method( 'userCan' )->willReturn( true );
		$permissionManager->method( 'userHasRight' )->willReturn( true );

		/** @var ServiceContainer|MockObject $serviceContainer */
		$serviceContainer = $this->createNoOpMock( ServiceContainer::class );
		$objectFactory = new ObjectFactory( $serviceContainer );

		$user = new UserIdentityValue( 0, 'Fake User', 0 );
		$validator = new Validator( $objectFactory, $permissionManager, $request, $user );

		/** @var Router|MockObject $router */
		$router = $this->createNoOpMock( Router::class, [ 'getRouteUrl' ] );
		$router->method( 'getRouteUrl' )->willReturnCallback( function ( $route, $query = [] ) {
			return wfAppendQuery( 'https://wiki.example.com/rest' . $route, $query );
		} );

		$handler->init( $router, $request, $config, $responseFactory );
		$handler->validate( $validator );
		$ret = $handler->execute();

		$response = $ret instanceof Response ? $ret
			: $responseFactory->createFromReturnValue( $ret );

		return $response;
	}

	/**
	 * Executes the given Handler on the given request, parses the response body as JSON,
	 * and returns the result.
	 *
	 * @param Handler $handler
	 * @param RequestInterface $request
	 * @param array $config
	 *
	 * @return array
	 */
	private function executeHandlerAndGetBodyData(
		Handler $handler,
		RequestInterface $request,
		$config = []
	) {
		$response = $this->executeHandler( $handler, $request, $config );

		$this->assertTrue( $response->getStatusCode() >= 200 && $response->getStatusCode() < 300 );
		$this->assertSame( 'application/json', $response->getHeaderLine( 'Content-Type' ) );

		$data = json_decode( $response->getBody(), true );
		$this->assertIsArray( $data, 'Body must be a JSON array' );

		return $data;
	}

	/**
	 * Executes the given Handler on the given request, and returns the HttpException thrown.
	 * Fails if no HttpException is thrown.
	 *
	 * @param Handler $handler
	 * @param RequestInterface $request
	 * @param array $config
	 *
	 * @return HttpException
	 */
	private function executeHandlerAndGetHttpException(
		Handler $handler,
		RequestInterface $request,
		$config = []
	) {
		try {
			$this->executeHandler( $handler, $request, $config );
			Assert::fail( 'Expected a HttpException to be thrown' );
		} catch ( HttpException $ex ) {
			return $ex;
		}
	}

	/**
	 * @return Title
	 */
	private function makeMockTitle( $text, $id = null, $model = 'UNKNOWN' ) {
		$id = $id ?? ++$this->pageIdCounter;

		/** @var Title|MockObject $title */
		$title = $this->createMock( Title::class );
		$title->method( 'getText' )->willReturn( str_replace( '_', ' ', $text ) );
		$title->method( 'getDBkey' )->willReturn( str_replace( ' ', '_', $text ) );
		$title->method( 'getPrefixedText' )->willReturn( str_replace( '_', ' ', $text ) );
		$title->method( 'getPrefixedDBkey' )->willReturn( str_replace( ' ', '_', $text ) );
		$title->method( 'getArticleID' )->willReturn( $id );
		$title->method( 'exists' )->willReturn( $id > 0 );
		$title->method( 'getContentModel' )->willReturn( $model );

		return $title;
	}

}