1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Graze\Silex\Tests\ControllerProvider; |
4
|
|
|
|
5
|
|
|
use Graze\Silex\ControllerProvider\TrailingSlashControllerProvider; |
6
|
|
|
use Mockery; |
7
|
|
|
use Psr\Log\LoggerInterface; |
8
|
|
|
use Silex\Application; |
9
|
|
|
use Silex\ControllerProviderInterface; |
10
|
|
|
use Silex\ServiceProviderInterface; |
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['url_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
|
|
View Code Duplication |
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
|
|
View Code Duplication |
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); |
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
|
|
View Code Duplication |
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 is just to show when defining routes with no trailing slash before |
269
|
|
|
* mounting the controller provider they should respond as expected. |
270
|
|
|
* |
271
|
|
|
* @dataProvider requestMethodProvider |
272
|
|
|
* |
273
|
|
|
* @param string $method |
274
|
|
|
*/ |
275
|
|
View Code Duplication |
public function testWillRespondWithOkForRouteWithNoTrailingSlashWhenMountedLast($method) |
|
|
|
|
276
|
|
|
{ |
277
|
|
|
$app = new Application(); |
278
|
|
|
|
279
|
|
|
$app->match('/foo', function () { |
280
|
|
|
return 'hunter42'; |
281
|
|
|
})->method($method); |
282
|
|
|
|
283
|
|
|
$app->match('/foo/bar', function () { |
284
|
|
|
return 'hunter42'; |
285
|
|
|
})->method($method); |
286
|
|
|
|
287
|
|
|
$app->register(new TrailingSlashControllerProvider()); |
288
|
|
|
$app->mount('/', new TrailingSlashControllerProvider()); |
289
|
|
|
|
290
|
|
|
$request = Request::create('/foo', $method); |
291
|
|
|
$response = $app->handle($request); |
292
|
|
|
|
293
|
|
|
$this->assertEquals(200, $response->getStatusCode()); |
294
|
|
|
|
295
|
|
|
$request = Request::create('/foo/bar', $method); |
296
|
|
|
$response = $app->handle($request); |
297
|
|
|
|
298
|
|
|
$this->assertEquals(200, $response->getStatusCode()); |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* Test the case in which a request should have both query |
303
|
|
|
* string params and body params |
304
|
|
|
*/ |
305
|
|
|
public function testWillHandleQueryAndBodySeparately() |
306
|
|
|
{ |
307
|
|
|
$app = new Application(); |
308
|
|
|
|
309
|
|
|
$app->match('/foo/', function (Request $request) { |
310
|
|
|
$response = [ |
311
|
|
|
'query' => $request->query->all(), |
312
|
|
|
'request' => $request->request->all() |
313
|
|
|
]; |
314
|
|
|
return json_encode($response, true); |
315
|
|
|
})->method('POST'); |
316
|
|
|
|
317
|
|
|
$app->register(new TrailingSlashControllerProvider()); |
318
|
|
|
$app->mount('/', new TrailingSlashControllerProvider()); |
319
|
|
|
|
320
|
|
|
$request = Request::create('/foo?q=1', 'POST', ['r' => 2]); |
321
|
|
|
$response = $app->handle($request); |
322
|
|
|
$this->assertEquals(200, $response->getStatusCode()); |
323
|
|
|
$body = json_decode($response->getContent(), true); |
324
|
|
|
$this->assertRequestQuery($body); |
325
|
|
|
|
326
|
|
|
$request = Request::create('/foo/?q=1', 'POST', ['r' => 2]); |
327
|
|
|
$response = $app->handle($request); |
328
|
|
|
$this->assertEquals(200, $response->getStatusCode()); |
329
|
|
|
$body = json_decode($response->getContent(), true); |
330
|
|
|
$this->assertRequestQuery($body); |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
/** |
334
|
|
|
* @param array $body |
335
|
|
|
*/ |
336
|
|
|
private function assertRequestQuery(array $body) |
337
|
|
|
{ |
338
|
|
|
$this->assertArrayHasKey('query', $body); |
339
|
|
|
$this->assertArrayHasKey('request', $body); |
340
|
|
|
|
341
|
|
|
$this->assertArrayHasKey('q', $body['query']); |
342
|
|
|
$this->assertEquals(1, $body['query']['q']); |
343
|
|
|
|
344
|
|
|
$this->assertArrayHasKey('r', $body['request']); |
345
|
|
|
$this->assertEquals(2, $body['request']['r']); |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
public function testLogging() |
349
|
|
|
{ |
350
|
|
|
$app = new Application(); |
351
|
|
|
|
352
|
|
|
$logger = Mockery::mock(LoggerInterface::class)->makePartial()->shouldIgnoreMissing(); |
353
|
|
|
$app['logger'] = $logger; |
354
|
|
|
|
355
|
|
|
$app->match('/foo/', function () { |
356
|
|
|
return 'hunter42'; |
357
|
|
|
})->method('GET'); |
358
|
|
|
|
359
|
|
|
$logger->shouldReceive('debug') |
360
|
|
|
->with('Appending a trailing slash for the request to `/foo`.') |
361
|
|
|
->once(); |
362
|
|
|
$logger->shouldReceive('debug') |
363
|
|
|
->with('Overriding the default Silex url matcher to Symfony\Component\Routing\Matcher\UrlMatcher.') |
364
|
|
|
->once(); |
365
|
|
|
|
366
|
|
|
$app->register(new TrailingSlashControllerProvider()); |
367
|
|
|
$app->mount('/', new TrailingSlashControllerProvider()); |
368
|
|
|
|
369
|
|
|
$request = Request::create('/foo', 'GET'); |
370
|
|
|
$response = $app->handle($request); |
371
|
|
|
$this->assertEquals(200, $response->getStatusCode()); |
372
|
|
|
} |
373
|
|
|
} |
374
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.