1
|
|
|
<?php |
2
|
|
|
declare(strict_types = 1); |
3
|
|
|
|
4
|
|
|
namespace Mikemirten\Bundle\JsonApiBundle\Request; |
5
|
|
|
|
6
|
|
|
use Mikemirten\Component\JsonApi\Document\AbstractDocument; |
7
|
|
|
use Mikemirten\Component\JsonApi\Document\NoDataDocument; |
8
|
|
|
use Mikemirten\Component\JsonApi\Document\ResourceCollectionDocument; |
9
|
|
|
use Mikemirten\Component\JsonApi\Document\SingleResourceDocument; |
10
|
|
|
use Mikemirten\Component\JsonApi\Hydrator\DocumentHydrator; |
11
|
|
|
use PHPUnit\Framework\TestCase; |
12
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; |
13
|
|
|
use Symfony\Component\HttpFoundation\HeaderBag; |
14
|
|
|
use Symfony\Component\HttpFoundation\ParameterBag; |
15
|
|
|
use Symfony\Component\HttpFoundation\Request; |
16
|
|
|
|
17
|
|
|
class JsonApiDocumentParameterConverterTest extends TestCase |
18
|
|
|
{ |
19
|
|
|
/** |
20
|
|
|
* @dataProvider getSupportedClasses |
21
|
|
|
* |
22
|
|
|
* @param string $class |
23
|
|
|
*/ |
24
|
|
|
public function testSupports(string $class) |
25
|
|
|
{ |
26
|
|
|
$configuration = $this->createMock(ParamConverter::class); |
27
|
|
|
|
28
|
|
|
$configuration->expects($this->once()) |
29
|
|
|
->method('getClass') |
30
|
|
|
->willReturn($class); |
31
|
|
|
|
32
|
|
|
$hydrator = $this->createMock(DocumentHydrator::class); |
33
|
|
|
$converter = new JsonApiDocumentParameterConverter($hydrator); |
34
|
|
|
|
35
|
|
|
$converter->supports($configuration); |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
public function testOptionalEmptyRequest() |
39
|
|
|
{ |
40
|
|
|
$configuration = $this->createConfiguration(NoDataDocument::class, true); |
41
|
|
|
|
42
|
|
|
$request = $this->createRequest(); |
43
|
|
|
$hydrator = $this->createMock(DocumentHydrator::class); |
44
|
|
|
$converter = new JsonApiDocumentParameterConverter($hydrator); |
45
|
|
|
|
46
|
|
|
$result = $converter->apply($request, $configuration); |
47
|
|
|
|
48
|
|
|
$this->assertFalse($result); |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException |
53
|
|
|
* @expectedExceptionMessage Request body is empty |
54
|
|
|
*/ |
55
|
|
View Code Duplication |
public function testEmptyRequest() |
|
|
|
|
56
|
|
|
{ |
57
|
|
|
$configuration = $this->createConfiguration(); |
58
|
|
|
|
59
|
|
|
$request = $this->createRequest(); |
60
|
|
|
$hydrator = $this->createMock(DocumentHydrator::class); |
61
|
|
|
$converter = new JsonApiDocumentParameterConverter($hydrator); |
62
|
|
|
|
63
|
|
|
$converter->apply($request, $configuration); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException |
68
|
|
|
* @expectedExceptionMessageRegExp ~Invalid media\-type of request~ |
69
|
|
|
*/ |
70
|
|
View Code Duplication |
public function testInvalidContentType() |
|
|
|
|
71
|
|
|
{ |
72
|
|
|
$configuration = $this->createConfiguration(); |
73
|
|
|
|
74
|
|
|
$request = $this->createRequest('{}', false); |
75
|
|
|
$hydrator = $this->createMock(DocumentHydrator::class); |
76
|
|
|
$converter = new JsonApiDocumentParameterConverter($hydrator); |
77
|
|
|
|
78
|
|
|
$converter->apply($request, $configuration); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException |
83
|
|
|
* @expectedExceptionMessageRegExp ~Decoding error~ |
84
|
|
|
*/ |
85
|
|
View Code Duplication |
public function testInvalidBody() |
|
|
|
|
86
|
|
|
{ |
87
|
|
|
$configuration = $this->createConfiguration(); |
88
|
|
|
|
89
|
|
|
$request = $this->createRequest('{'); |
90
|
|
|
$hydrator = $this->createMock(DocumentHydrator::class); |
91
|
|
|
$converter = new JsonApiDocumentParameterConverter($hydrator); |
92
|
|
|
|
93
|
|
|
$converter->apply($request, $configuration); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException |
98
|
|
|
* @expectedExceptionMessageRegExp ~does not meet expected document~ |
99
|
|
|
*/ |
100
|
|
|
public function testNotExpectedDocument() |
101
|
|
|
{ |
102
|
|
|
$configuration = $this->createConfiguration(); |
103
|
|
|
|
104
|
|
|
$document = $this->createMock(SingleResourceDocument::class); |
105
|
|
|
$hydrator = $this->createMock(DocumentHydrator::class); |
106
|
|
|
$request = $this->createRequest('{}'); |
107
|
|
|
|
108
|
|
|
$hydrator->expects($this->once()) |
109
|
|
|
->method('hydrate') |
110
|
|
|
->with($this->isInstanceOf(\stdClass::class)) |
111
|
|
|
->willReturn($document); |
112
|
|
|
|
113
|
|
|
$converter = new JsonApiDocumentParameterConverter($hydrator); |
114
|
|
|
|
115
|
|
|
$converter->apply($request, $configuration); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* @dataProvider getPossibleConversions |
120
|
|
|
* |
121
|
|
|
* @param string $expectedClass |
122
|
|
|
* @param string $actualClass |
123
|
|
|
*/ |
124
|
|
|
public function testSucceedConversion(string $expectedClass, string $actualClass) |
125
|
|
|
{ |
126
|
|
|
$configuration = $this->createConfiguration($expectedClass); |
127
|
|
|
|
128
|
|
|
$document = $this->createMock($actualClass); |
129
|
|
|
$hydrator = $this->createMock(DocumentHydrator::class); |
130
|
|
|
|
131
|
|
|
$hydrator->expects($this->once()) |
132
|
|
|
->method('hydrate') |
133
|
|
|
->with($this->isInstanceOf(\stdClass::class)) |
134
|
|
|
->willReturn($document); |
135
|
|
|
|
136
|
|
|
$request = $this->createRequest('{}'); |
137
|
|
|
|
138
|
|
|
$request->attributes->expects($this->once()) |
139
|
|
|
->method('set') |
140
|
|
|
->with('document', $document); |
141
|
|
|
|
142
|
|
|
$converter = new JsonApiDocumentParameterConverter($hydrator); |
143
|
|
|
|
144
|
|
|
$result = $converter->apply($request, $configuration); |
145
|
|
|
|
146
|
|
|
$this->assertTrue($result); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Create mock of parameter converter configuration |
151
|
|
|
* |
152
|
|
|
* @param string $class |
153
|
|
|
* @param bool $optional |
154
|
|
|
* @return ParamConverter |
155
|
|
|
*/ |
156
|
|
|
protected function createConfiguration(string $class = NoDataDocument::class, bool $optional = false): ParamConverter |
157
|
|
|
{ |
158
|
|
|
$configuration = $this->createMock(ParamConverter::class); |
159
|
|
|
|
160
|
|
|
$configuration->method('getClass') |
161
|
|
|
->willReturn($class); |
162
|
|
|
|
163
|
|
|
$configuration->method('getName') |
164
|
|
|
->willReturn('document'); |
165
|
|
|
|
166
|
|
|
$configuration->method('isOptional') |
167
|
|
|
->willReturn($optional); |
168
|
|
|
|
169
|
|
|
return $configuration; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Create mock of request |
174
|
|
|
* |
175
|
|
|
* @param string $body |
176
|
|
|
* @param bool $apiJsonHeader |
177
|
|
|
* @return Request |
178
|
|
|
*/ |
179
|
|
|
protected function createRequest(string $body = '', bool $apiJsonHeader = true): Request |
180
|
|
|
{ |
181
|
|
|
$request = $this->createMock(Request::class); |
182
|
|
|
|
183
|
|
|
$request->method('getContent') |
184
|
|
|
->willReturn($body); |
185
|
|
|
|
186
|
|
|
$request->attributes = $this->createMock(ParameterBag::class); |
|
|
|
|
187
|
|
|
$request->headers = $this->createMock(HeaderBag::class); |
|
|
|
|
188
|
|
|
|
189
|
|
|
$request->headers->method('contains') |
|
|
|
|
190
|
|
|
->with( |
191
|
|
|
'Content-Type', |
192
|
|
|
'application/vnd.api+json' |
193
|
|
|
) |
194
|
|
|
->willReturn($apiJsonHeader); |
195
|
|
|
|
196
|
|
|
return $request; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Get supported classes for testing |
201
|
|
|
* |
202
|
|
|
* @return array |
203
|
|
|
*/ |
204
|
|
|
public function getSupportedClasses(): array |
205
|
|
|
{ |
206
|
|
|
return [ |
207
|
|
|
[ NoDataDocument::class ], |
208
|
|
|
[ AbstractDocument::class ], |
209
|
|
|
[ SingleResourceDocument::class ], |
210
|
|
|
[ ResourceCollectionDocument::class ] |
211
|
|
|
]; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Get possible classes conversion for testing |
216
|
|
|
* |
217
|
|
|
* @return array |
218
|
|
|
*/ |
219
|
|
|
public function getPossibleConversions(): array |
220
|
|
|
{ |
221
|
|
|
return [ |
222
|
|
|
// Expected Actual |
223
|
|
|
[ NoDataDocument::class, NoDataDocument::class ], |
224
|
|
|
[ SingleResourceDocument::class, SingleResourceDocument::class ], |
225
|
|
|
[ ResourceCollectionDocument::class, ResourceCollectionDocument::class ], |
226
|
|
|
[ AbstractDocument::class, NoDataDocument::class ], |
227
|
|
|
[ AbstractDocument::class, SingleResourceDocument::class ], |
228
|
|
|
[ AbstractDocument::class, ResourceCollectionDocument::class ], |
229
|
|
|
]; |
230
|
|
|
} |
231
|
|
|
} |
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.