1 | <?php |
||||
2 | |||||
3 | namespace Graze\Silex\Tests\ControllerProvider; |
||||
4 | |||||
5 | use Graze\Silex\ControllerProvider\TrailingSlashControllerProvider; |
||||
6 | use Mockery; |
||||
7 | use Pimple\ServiceProviderInterface; |
||||
8 | use Psr\Log\LoggerInterface; |
||||
9 | use Silex\Application; |
||||
10 | use Silex\Api\ControllerProviderInterface; |
||||
11 | use Symfony\Component\HttpFoundation\Request; |
||||
12 | use Symfony\Component\Routing\Matcher\UrlMatcher; |
||||
13 | |||||
14 | /** |
||||
15 | * TrailingSlashControllerProvider test cases. |
||||
16 | */ |
||||
17 | class TrailingSlashControllerProviderTest extends \PHPUnit_Framework_TestCase |
||||
18 | { |
||||
19 | public function testShouldInitalize() |
||||
20 | { |
||||
21 | $provider = new TrailingSlashControllerProvider(); |
||||
22 | |||||
23 | $this->assertInstanceOf(ControllerProviderInterface::class, $provider); |
||||
24 | $this->assertInstanceOf(ServiceProviderInterface::class, $provider); |
||||
25 | } |
||||
26 | |||||
27 | public function testShouldRegisterUrlMatcher() |
||||
28 | { |
||||
29 | $app = new Application(); |
||||
30 | |||||
31 | $app->register(new TrailingSlashControllerProvider()); |
||||
32 | |||||
33 | $this->assertInstanceOf(UrlMatcher::class, $app['request_matcher']); |
||||
34 | } |
||||
35 | |||||
36 | public function testShouldMount() |
||||
37 | { |
||||
38 | $app = new Application(); |
||||
39 | |||||
40 | // `mount` should return the application. |
||||
41 | $this->assertSame( |
||||
42 | $app, |
||||
43 | $app->mount('/', new TrailingSlashControllerProvider()) |
||||
44 | ); |
||||
45 | } |
||||
46 | |||||
47 | /** |
||||
48 | * @dataProvider requestMethodProvider |
||||
49 | * |
||||
50 | * @param string $method |
||||
51 | */ |
||||
52 | public function testShouldRespondOkWithoutTrailingSlash($method) |
||||
53 | { |
||||
54 | $app = new Application(); |
||||
55 | |||||
56 | $app->match('/foo/', function () { |
||||
57 | return 'hunter42'; |
||||
58 | })->method($method); |
||||
59 | |||||
60 | $app->match('/foo/bar/', function () { |
||||
61 | return 'What\'s the question?'; |
||||
62 | })->method($method); |
||||
63 | |||||
64 | $app->match('/foo/bar/baz/', function () { |
||||
65 | return 'Fizz Buzz'; |
||||
66 | })->method($method); |
||||
67 | |||||
68 | $app->register(new TrailingSlashControllerProvider()); |
||||
69 | $app->mount('/', new TrailingSlashControllerProvider()); |
||||
70 | |||||
71 | $request = Request::create('/foo', $method); |
||||
72 | $response = $app->handle($request); |
||||
73 | |||||
74 | $this->assertEquals(200, $response->getStatusCode()); |
||||
75 | |||||
76 | $request = Request::create('/foo/bar', $method); |
||||
77 | $response = $app->handle($request); |
||||
78 | |||||
79 | $this->assertEquals(200, $response->getStatusCode()); |
||||
80 | |||||
81 | $request = Request::create('/foo/bar/baz', $method); |
||||
82 | $response = $app->handle($request); |
||||
83 | |||||
84 | $this->assertEquals(200, $response->getStatusCode()); |
||||
85 | } |
||||
86 | |||||
87 | /** |
||||
88 | * This just shows that the mount order for the controller provider doesn't |
||||
89 | * matter when all routes are defined with a trailing slash. |
||||
90 | * |
||||
91 | * @dataProvider requestMethodProvider |
||||
92 | * |
||||
93 | * @param string $method |
||||
94 | */ |
||||
95 | public function testShouldRespondOkWithoutTrailingSlashWhenMountedFirst($method) |
||||
96 | { |
||||
97 | $app = new Application(); |
||||
98 | |||||
99 | $app->register(new TrailingSlashControllerProvider()); |
||||
100 | $app->mount('/', new TrailingSlashControllerProvider()); |
||||
101 | |||||
102 | $app->match('/foo/', function () { |
||||
103 | return 'hunter42'; |
||||
104 | })->method($method); |
||||
105 | |||||
106 | $app->match('/foo/bar/', function () { |
||||
107 | return 'What\'s the question?'; |
||||
108 | })->method($method); |
||||
109 | |||||
110 | $app->match('/foo/bar/baz/', function () { |
||||
111 | return 'Fizz Buzz'; |
||||
112 | })->method($method); |
||||
113 | |||||
114 | $request = Request::create('/foo', $method); |
||||
115 | $response = $app->handle($request); |
||||
116 | |||||
117 | $this->assertEquals(200, $response->getStatusCode()); |
||||
118 | |||||
119 | $request = Request::create('/foo/bar', $method); |
||||
120 | $response = $app->handle($request); |
||||
121 | |||||
122 | $this->assertEquals(200, $response->getStatusCode()); |
||||
123 | |||||
124 | $request = Request::create('/foo/bar/baz', $method); |
||||
125 | $response = $app->handle($request); |
||||
126 | |||||
127 | $this->assertEquals(200, $response->getStatusCode()); |
||||
128 | } |
||||
129 | |||||
130 | /** |
||||
131 | * This just shows that the controller provider is compatiable with other |
||||
132 | * controller providers. |
||||
133 | * |
||||
134 | * @dataProvider requestMethodProvider |
||||
135 | * |
||||
136 | * @param string $method |
||||
137 | */ |
||||
138 | public function testShouldRespondOkWithoutTrailingSlashWithMountedControllers($method) |
||||
139 | { |
||||
140 | $app = new Application(); |
||||
141 | |||||
142 | $app->register(new TrailingSlashControllerProvider()); |
||||
143 | $app->mount('/', new TrailingSlashControllerProvider()); |
||||
144 | |||||
145 | $controller = $app['controllers_factory']; |
||||
146 | |||||
147 | $controller->match('/foo/', function () { |
||||
148 | return 'hunter42'; |
||||
149 | })->method($method); |
||||
150 | |||||
151 | $controller->match('/foo/bar/', function () { |
||||
152 | return 'hunter42'; |
||||
153 | })->method($method); |
||||
154 | |||||
155 | $controller->match('/foo/bar/baz/', function () { |
||||
156 | return 'hunter42'; |
||||
157 | })->method($method); |
||||
158 | |||||
159 | $provider = Mockery::mock(ControllerProviderInterface::class); |
||||
160 | $provider->shouldReceive('connect')->andReturn($controller); |
||||
161 | |||||
162 | $app->mount('/', $provider); |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
163 | |||||
164 | $request = Request::create('/foo', $method); |
||||
165 | $response = $app->handle($request); |
||||
166 | |||||
167 | $this->assertEquals(200, $response->getStatusCode()); |
||||
168 | |||||
169 | $request = Request::create('/foo/bar', $method); |
||||
170 | $response = $app->handle($request); |
||||
171 | |||||
172 | $this->assertEquals(200, $response->getStatusCode()); |
||||
173 | |||||
174 | $request = Request::create('/foo/bar/baz', $method); |
||||
175 | $response = $app->handle($request); |
||||
176 | |||||
177 | $this->assertEquals(200, $response->getStatusCode()); |
||||
178 | } |
||||
179 | |||||
180 | /** |
||||
181 | * @return array |
||||
182 | */ |
||||
183 | public function requestMethodProvider() |
||||
184 | { |
||||
185 | return [ |
||||
186 | ['GET'], |
||||
187 | ['POST'], |
||||
188 | ['PUT'], |
||||
189 | ['PATCH'], |
||||
190 | ['DELETE'], |
||||
191 | ['PURGE'], |
||||
192 | ['OPTIONS'], |
||||
193 | ['TRACE'], |
||||
194 | ['CONNECT'], |
||||
195 | ]; |
||||
196 | } |
||||
197 | |||||
198 | public function testShouldRespondOkToHeadWithoutTrailingSlash() |
||||
199 | { |
||||
200 | $app = new Application(); |
||||
201 | |||||
202 | $app->get('/foo/', function () { |
||||
203 | return 'hunter42'; |
||||
204 | }); |
||||
205 | |||||
206 | $app->get('/foo/bar/', function () { |
||||
207 | return 'What\'s the question?'; |
||||
208 | }); |
||||
209 | |||||
210 | $app->get('/foo/bar/baz/', function () { |
||||
211 | return 'Fizz Buzz'; |
||||
212 | }); |
||||
213 | |||||
214 | $app->register(new TrailingSlashControllerProvider()); |
||||
215 | $app->mount('/', new TrailingSlashControllerProvider()); |
||||
216 | |||||
217 | $request = Request::create('/foo', 'HEAD'); |
||||
218 | $response = $app->handle($request); |
||||
219 | |||||
220 | $this->assertEquals(200, $response->getStatusCode()); |
||||
221 | |||||
222 | $request = Request::create('/foo/bar', 'HEAD'); |
||||
223 | $response = $app->handle($request); |
||||
224 | |||||
225 | $this->assertEquals(200, $response->getStatusCode()); |
||||
226 | |||||
227 | $request = Request::create('/foo/bar/baz', 'HEAD'); |
||||
228 | $response = $app->handle($request); |
||||
229 | |||||
230 | $this->assertEquals(200, $response->getStatusCode()); |
||||
231 | } |
||||
232 | |||||
233 | /** |
||||
234 | * This is just to show when defining routes that the trailing slash is |
||||
235 | * required when the controller provider is mounted before any other routes. |
||||
236 | * |
||||
237 | * @dataProvider requestMethodProvider |
||||
238 | * |
||||
239 | * @param string $method |
||||
240 | */ |
||||
241 | public function testWillRespondWithNotFoundForRouteWithNoTrailingSlashWhenMountedFirst($method) |
||||
242 | { |
||||
243 | $app = new Application(); |
||||
244 | |||||
245 | $app->register(new TrailingSlashControllerProvider()); |
||||
246 | $app->mount('/', new TrailingSlashControllerProvider()); |
||||
247 | |||||
248 | $app->match('/foo', function () { |
||||
249 | return 'hunter42'; |
||||
250 | })->method($method); |
||||
251 | |||||
252 | $app->match('/foo/bar', function () { |
||||
253 | return 'hunter42'; |
||||
254 | })->method($method); |
||||
255 | |||||
256 | $request = Request::create('/foo', $method); |
||||
257 | $response = $app->handle($request); |
||||
258 | |||||
259 | $this->assertEquals(404, $response->getStatusCode()); |
||||
260 | |||||
261 | $request = Request::create('/foo/bar', $method); |
||||
262 | $response = $app->handle($request); |
||||
263 | |||||
264 | $this->assertEquals(404, $response->getStatusCode()); |
||||
265 | } |
||||
266 | |||||
267 | /** |
||||
268 | * This shows that by default it will return 404 when the routes are defined with trailing slashes |
||||
269 | * |
||||
270 | * @dataProvider requestMethodProvider |
||||
271 | * |
||||
272 | * @param string $method |
||||
273 | */ |
||||
274 | public function testWillRespondWillNotFoundForRouteWithTrailingSlashWhenNotMounted($method) |
||||
275 | { |
||||
276 | $app = new Application(); |
||||
277 | |||||
278 | $app->match('/foo/', function () { |
||||
279 | return 'hunter42'; |
||||
280 | })->method($method); |
||||
281 | |||||
282 | $app->match('/foo/bar/', function () { |
||||
283 | return 'hunter42'; |
||||
284 | })->method($method); |
||||
285 | |||||
286 | $app->register(new TrailingSlashControllerProvider()); |
||||
287 | |||||
288 | $request = Request::create('/foo', $method); |
||||
289 | $response = $app->handle($request); |
||||
290 | |||||
291 | $this->assertEquals(404, $response->getStatusCode()); |
||||
292 | |||||
293 | $request = Request::create('/foo/bar', $method); |
||||
294 | $response = $app->handle($request); |
||||
295 | |||||
296 | $this->assertEquals(404, $response->getStatusCode()); |
||||
297 | } |
||||
298 | |||||
299 | /** |
||||
300 | * This is just to show when defining routes with no trailing slash before |
||||
301 | * mounting the controller provider they should respond as expected. |
||||
302 | * |
||||
303 | * @dataProvider requestMethodProvider |
||||
304 | * |
||||
305 | * @param string $method |
||||
306 | */ |
||||
307 | public function testWillRespondWithOkForRouteWithNoTrailingSlashWhenMountedLast($method) |
||||
308 | { |
||||
309 | $app = new Application(); |
||||
310 | |||||
311 | $app->match('/foo', function () { |
||||
312 | return 'hunter42'; |
||||
313 | })->method($method); |
||||
314 | |||||
315 | $app->match('/foo/bar', function () { |
||||
316 | return 'hunter42'; |
||||
317 | })->method($method); |
||||
318 | |||||
319 | $app->register(new TrailingSlashControllerProvider()); |
||||
320 | $app->mount('/', new TrailingSlashControllerProvider()); |
||||
321 | |||||
322 | $request = Request::create('/foo', $method); |
||||
323 | $response = $app->handle($request); |
||||
324 | |||||
325 | $this->assertEquals(200, $response->getStatusCode()); |
||||
326 | |||||
327 | $request = Request::create('/foo/bar', $method); |
||||
328 | $response = $app->handle($request); |
||||
329 | |||||
330 | $this->assertEquals(200, $response->getStatusCode()); |
||||
331 | } |
||||
332 | |||||
333 | /** |
||||
334 | * Test the case in which a request should have both query |
||||
335 | * string params and body params |
||||
336 | */ |
||||
337 | public function testWillHandleQueryAndBodySeparately() |
||||
338 | { |
||||
339 | $app = new Application(); |
||||
340 | |||||
341 | $app->match('/foo/', function (Request $request) { |
||||
342 | $response = [ |
||||
343 | 'query' => $request->query->all(), |
||||
344 | 'request' => $request->request->all() |
||||
345 | ]; |
||||
346 | return json_encode($response, true); |
||||
0 ignored issues
–
show
true of type true is incompatible with the type integer expected by parameter $options of json_encode() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
347 | })->method('POST'); |
||||
348 | |||||
349 | $app->register(new TrailingSlashControllerProvider()); |
||||
350 | $app->mount('/', new TrailingSlashControllerProvider()); |
||||
351 | |||||
352 | $request = Request::create('/foo?q=1', 'POST', ['r' => 2]); |
||||
353 | $response = $app->handle($request); |
||||
354 | $this->assertEquals(200, $response->getStatusCode()); |
||||
355 | $body = json_decode($response->getContent(), true); |
||||
356 | $this->assertRequestQuery($body); |
||||
357 | |||||
358 | $request = Request::create('/foo/?q=1', 'POST', ['r' => 2]); |
||||
359 | $response = $app->handle($request); |
||||
360 | $this->assertEquals(200, $response->getStatusCode()); |
||||
361 | $body = json_decode($response->getContent(), true); |
||||
362 | $this->assertRequestQuery($body); |
||||
363 | } |
||||
364 | |||||
365 | /** |
||||
366 | * @param array $body |
||||
367 | */ |
||||
368 | private function assertRequestQuery(array $body) |
||||
369 | { |
||||
370 | $this->assertArrayHasKey('query', $body); |
||||
371 | $this->assertArrayHasKey('request', $body); |
||||
372 | |||||
373 | $this->assertArrayHasKey('q', $body['query']); |
||||
374 | $this->assertEquals(1, $body['query']['q']); |
||||
375 | |||||
376 | $this->assertArrayHasKey('r', $body['request']); |
||||
377 | $this->assertEquals(2, $body['request']['r']); |
||||
378 | } |
||||
379 | |||||
380 | public function testLogging() |
||||
381 | { |
||||
382 | $app = new Application(); |
||||
383 | |||||
384 | $logger = Mockery::mock(LoggerInterface::class)->makePartial()->shouldIgnoreMissing(); |
||||
385 | $app['logger'] = $logger; |
||||
386 | |||||
387 | $app->match('/foo/', function () { |
||||
388 | return 'hunter42'; |
||||
389 | })->method('GET'); |
||||
390 | |||||
391 | $logger->shouldReceive('debug') |
||||
392 | ->with('Appending a trailing slash for the request to `/foo`.') |
||||
393 | ->once(); |
||||
394 | $logger->shouldReceive('debug') |
||||
395 | ->with('Overriding the default Silex url matcher to Symfony\Component\Routing\Matcher\UrlMatcher.') |
||||
396 | ->once(); |
||||
397 | |||||
398 | $app->register(new TrailingSlashControllerProvider()); |
||||
399 | $app->mount('/', new TrailingSlashControllerProvider()); |
||||
400 | |||||
401 | $request = Request::create('/foo', 'GET'); |
||||
402 | $response = $app->handle($request); |
||||
403 | $this->assertEquals(200, $response->getStatusCode()); |
||||
404 | } |
||||
405 | } |
||||
406 |