Passed
Push — master ( 2a0c83...54b4a1 )
by Michael
03:26
created

JsonApiDocumentParameterConverterTest::testOptionalEmptyRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 0
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
    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
    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
    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
}