Passed
Push — master ( 1e6084...cf392e )
by Vincent
02:40
created

AssertStructure   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 253
Duplicated Lines 0 %

Test Coverage

Coverage 99.11%

Importance

Changes 0
Metric Value
eloc 100
dl 0
loc 253
ccs 111
cts 112
cp 0.9911
rs 9.44
c 0
b 0
f 0
wmc 37

10 Methods

Rating   Name   Duplication   Size   Complexity  
A assertIsValidTopLevelLinksMember() 0 4 1
A existsInArray() 0 9 4
A assertIsValidResourceCollection() 0 21 4
B getAllResourceIdentifierObjects() 0 25 8
A assertIsValidSingleResource() 0 8 2
A dataIsResourceObject() 0 5 1
A assertHasValidTopLevelMembers() 0 23 3
A assertIsValidIncludedCollection() 0 25 3
A assertIsValidPrimaryData() 0 24 4
B assertHasValidStructure() 0 26 7
1
<?php
2
namespace VGirol\JsonApiAssert\Asserts;
3
4
use PHPUnit\Framework\Assert as PHPUnit;
5
use VGirol\JsonApiAssert\Messages;
6
use PHPUnit\Framework\ExpectationFailedException;
7
8
trait AssertStructure
9
{
10
    /**
11
     * Asserts that a json document has valid structure.
12
     *
13
     * @param array     $json
14
     * @param boolean   $strict     If true, excludes not safe characters when checking members name
15
     *
16
     * @throws PHPUnit\Framework\ExpectationFailedException
17
     */
18 9
    public static function assertHasValidStructure($json, $strict)
19
    {
20 9
        static::assertHasValidTopLevelMembers($json);
21
22 8
        if (isset($json['data'])) {
23 6
            static::assertIsValidPrimaryData($json['data'], $strict);
24
        }
25
26 7
        if (isset($json['errors'])) {
27 2
            static::assertIsValidErrorsObject($json['errors'], $strict);
28
        }
29
30 6
        if (isset($json['meta'])) {
31 2
            static::assertIsValidMetaObject($json['meta'], $strict);
32
        }
33
34 5
        if (isset($json['jsonapi'])) {
35 2
            static::assertIsValidJsonapiObject($json['jsonapi'], $strict);
36
        }
37
38 4
        if (isset($json['links'])) {
39 2
            static::assertIsValidTopLevelLinksMember($json['links'], $strict);
40
        }
41
42 3
        if (isset($json['included'])) {
43 2
            static::assertIsValidIncludedCollection($json['included'], $json['data'], $strict);
44
        }
45 2
    }
46
47
    /**
48
     * Asserts that a json document has valid top-level structure.
49
     *
50
     * @param array $json
51
     *
52
     * @throws PHPUnit\Framework\ExpectationFailedException
53
     */
54 14
    public static function assertHasValidTopLevelMembers($json)
55
    {
56 14
        $expected = ['data', 'errors', 'meta'];
57 14
        static::assertContainsAtLeastOneMember(
58 14
            $expected,
59 14
            $json,
60 14
            \sprintf(Messages::TOP_LEVEL_MEMBERS, implode('", "', $expected))
61
        );
62
63 13
        PHPUnit::assertFalse(
64 13
            isset($json['data']) && isset($json['errors']),
65 13
            Messages::TOP_LEVEL_DATA_AND_ERROR
66
        );
67
68 12
        $allowed = ['data', 'errors', 'meta', 'jsonapi', 'links', 'included'];
69 12
        static::assertContainsOnlyAllowedMembers(
70 12
            $allowed,
71 12
            $json
72
        );
73
74 10
        PHPUnit::assertFALSE(
75 10
            !isset($json['data']) && isset($json['included']),
76 10
            Messages::TOP_LEVEL_DATA_AND_INCLUDED
77
        );
78 9
    }
79
80
    /**
81
     * Asserts that top-level links member of a json document is valid.
82
     *
83
     * @param array     $links
84
     * @param boolean   $strict     If true, excludes not safe characters when checking members name
85
     *
86
     * @throws PHPUnit\Framework\ExpectationFailedException
87
     */
88 4
    public static function assertIsValidTopLevelLinksMember($links, $strict)
89
    {
90 4
        $allowed = ['self', 'related', 'first', 'last', 'next', 'prev'];
91 4
        static::assertIsValidLinksObject($links, $allowed, $strict);
92 2
    }
93
94
    /**
95
     * Asserts that the primary data of a json document is valid.
96
     *
97
     * @param array     $data
98
     * @param boolean   $strict     If true, excludes not safe characters when checking members name
99
     *
100
     * @throws PHPUnit\Framework\ExpectationFailedException
101
     */
102 13
    public static function assertIsValidPrimaryData($data, $strict)
103
    {
104
        try {
105 13
            PHPUnit::assertIsArray(
106 13
                $data,
107 13
                Messages::PRIMARY_DATA_NOT_ARRAY
108
            );
109 11
            if (empty($data)) {
110 11
                return;
111
            }
112 2
        } catch (ExpectationFailedException $e) {
113 2
            PHPUnit::assertNull(
114 2
                $data,
115 2
                Messages::PRIMARY_DATA_NOT_ARRAY
116
            );
117 1
            return;
118
        }
119
120 10
        if (static::isArrayOfObjects($data)) {
121
            // Resource collection (Resource Objects or Resource Identifier Objects)
122 3
            static::assertIsValidResourceCollection($data, true, $strict);
123
        } else {
124
            // Single Resource (Resource Object or Resource Identifier Object)
125 7
            static::assertIsValidSingleResource($data, $strict);
126
        }
127 7
    }
128
129
    /**
130
     * Asserts that a collection of resource object is valid.
131
     *
132
     * @param array     $list
133
     * @param boolean   $checkType      If true, asserts that all resources of the collection are of same type.
134
     * @param boolean   $strict         If true, excludes not safe characters when checking members name
135
     *
136
     * @throws PHPUnit\Framework\ExpectationFailedException
137
     */
138 18
    public static function assertIsValidResourceCollection($list, $checkType, $strict)
139
    {
140 18
        static::assertIsArrayOfObjects($list);
141
142 14
        $isResourceObjectCollection = null;
143 14
        foreach ($list as $index => $resource) {
144 13
            if ($checkType) {
145
                // Assert that all resources of the collection are of same type.
146 8
                if ($index == 0) {
147 8
                    $isResourceObjectCollection = static::dataIsResourceObject($resource);
148
                } else {
149 6
                    PHPUnit::assertEquals(
150 6
                        $isResourceObjectCollection,
151 6
                        static::dataIsResourceObject($resource),
152 6
                        Messages::PRIMARY_DATA_SAME_TYPE
153
                    );
154
                }
155
            }
156
157
            // Check the resource
158 13
            static::assertIsValidSingleResource($resource, $strict);
159
        }
160 11
    }
161
162
    /**
163
     * Assert that a single resource object is valid.
164
     *
165
     * @param array     $resource
166
     * @param boolean   $strict     If true, excludes not safe characters when checking members name
167
     *
168
     * @throws PHPUnit\Framework\ExpectationFailedException
169
     */
170 26
    public static function assertIsValidSingleResource($resource, $strict)
171
    {
172 26
        static::assertIsNotArrayOfObjects($resource);
173
174 25
        if (static::dataIsResourceObject($resource)) {
175 16
            static::assertIsValidResourceObject($resource, $strict);
0 ignored issues
show
Bug introduced by
The method assertIsValidResourceObject() does not exist on VGirol\JsonApiAssert\Asserts\AssertStructure. Did you maybe mean assertIsValidResourceCollection()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

175
            static::/** @scrutinizer ignore-call */ 
176
                    assertIsValidResourceObject($resource, $strict);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
176
        } else {
177 10
            static::assertIsValidResourceIdentifierObject($resource, $strict);
0 ignored issues
show
Bug introduced by
The method assertIsValidResourceIdentifierObject() does not exist on VGirol\JsonApiAssert\Asserts\AssertStructure. Did you maybe mean assertIsValidResourceCollection()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

177
            static::/** @scrutinizer ignore-call */ 
178
                    assertIsValidResourceIdentifierObject($resource, $strict);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
178
        }
179 19
    }
180
181
    /**
182
     * Asserts that a collection of included resources is valid.
183
     *
184
     * @param array     $included   The included top-level member of a json document.
185
     * @param array     $data       The primary data of a json document.
186
     * @param boolean   $strict     If true, excludes not safe characters when checking members name
187
     *
188
     * @throws PHPUnit\Framework\ExpectationFailedException
189
     */
190 9
    public static function assertIsValidIncludedCollection($included, $data, $strict)
191
    {
192 9
        static::assertIsValidResourceCollection($included, false, $strict);
193
194 6
        $resIdentifiers = array_merge(
195 6
            static::getAllResourceIdentifierObjects($data),
196 6
            static::getAllResourceIdentifierObjects($included)
197
        );
198
199 6
        $present = [];
200 6
        foreach ($included as $inc) {
201 6
            PHPUnit::assertTrue(
202 6
                self::existsInArray($inc, $resIdentifiers),
203 6
                Messages::INCLUDED_RESOURCE_NOT_LINKED
204
            );
205
206 5
            if (!isset($present[$inc['type']])) {
207 5
                $present[$inc['type']] = [];
208
            }
209 5
            PHPUnit::assertNotContains(
210 5
                $inc['id'],
211 5
                $present[$inc['type']],
212 5
                Messages::COMPOUND_DOCUMENT_ONLY_ONE_RESOURCE
213
            );
214 5
            array_push($present[$inc['type']], $inc['id']);
215
        }
216 3
    }
217
218 25
    private static function dataIsResourceObject($resource)
219
    {
220 25
        $expected = ['attributes', 'relationships', 'links'];
221
222 25
        return static::containsAtLeastOneMember($expected, $resource);
223
    }
224
225 6
    private static function getAllResourceIdentifierObjects($data)
226
    {
227 6
        $arr = [];
228 6
        if (empty($data)) {
229
            return $arr;
230
        }
231 6
        if (!static::isArrayOfObjects($data)) {
232 4
            $data = [$data];
233
        }
234 6
        foreach ($data as $obj) {
235 6
            if (!isset($obj['relationships'])) {
236 6
                continue;
237
            }
238 6
            foreach ($obj['relationships'] as $key => $relationship) {
239 6
                if (!isset($relationship['data'])) {
240 1
                    continue;
241
                }
242 6
                $arr = array_merge(
243 6
                    $arr,
244 6
                    static::isArrayOfObjects($relationship['data']) ? $relationship['data'] : [$relationship['data']]
245
                );
246
            }
247
        }
248
249 6
        return $arr;
250
    }
251
252 6
    private static function existsInArray($needle, $arr)
253
    {
254 6
        foreach ($arr as $resIdentifier) {
255 6
            if (($resIdentifier['type'] === $needle['type']) && ($resIdentifier['id'] === $needle['id'])) {
256 5
                return true;
257
            }
258
        }
259
260 2
        return false;
261
    }
262
}
263