Completed
Branch master (2a0c83)
by Michael
02:20
created

testEmptyRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 10
Ratio 100 %

Importance

Changes 0
Metric Value
dl 10
loc 10
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
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 View Code Duplication
    public function testEmptyRequest()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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);
0 ignored issues
show
Bug introduced by
Accessing attributes on the interface PHPUnit_Framework_MockObject_MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
187
        $request->headers    = $this->createMock(HeaderBag::class);
0 ignored issues
show
Bug introduced by
Accessing headers on the interface PHPUnit_Framework_MockObject_MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
188
189
        $request->headers->method('contains')
0 ignored issues
show
Bug introduced by
Accessing headers on the interface PHPUnit_Framework_MockObject_MockObject suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
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
}