Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Testing;
4
 
5
use ArrayAccess;
6
use Closure;
7
use Countable;
8
use Illuminate\Contracts\Support\Jsonable;
9
use Illuminate\Support\Arr;
10
use Illuminate\Support\Str;
11
use Illuminate\Testing\Assert as PHPUnit;
12
use JsonSerializable;
13
 
14
class AssertableJsonString implements ArrayAccess, Countable
15
{
16
    /**
17
     * The original encoded json.
18
     *
19
     * @var \Illuminate\Contracts\Support\Jsonable|\JsonSerializable|array|string
20
     */
21
    public $json;
22
 
23
    /**
24
     * The decoded json contents.
25
     *
26
     * @var array|null
27
     */
28
    protected $decoded;
29
 
30
    /**
31
     * Create a new assertable JSON string instance.
32
     *
33
     * @param  \Illuminate\Contracts\Support\Jsonable|\JsonSerializable|array|string  $jsonable
34
     * @return void
35
     */
36
    public function __construct($jsonable)
37
    {
38
        $this->json = $jsonable;
39
 
40
        if ($jsonable instanceof JsonSerializable) {
41
            $this->decoded = $jsonable->jsonSerialize();
42
        } elseif ($jsonable instanceof Jsonable) {
43
            $this->decoded = json_decode($jsonable->toJson(), true);
44
        } elseif (is_array($jsonable)) {
45
            $this->decoded = $jsonable;
46
        } else {
47
            $this->decoded = json_decode($jsonable, true);
48
        }
49
    }
50
 
51
    /**
52
     * Validate and return the decoded response JSON.
53
     *
54
     * @param  string|null  $key
55
     * @return mixed
56
     */
57
    public function json($key = null)
58
    {
59
        return data_get($this->decoded, $key);
60
    }
61
 
62
    /**
63
     * Assert that the response JSON has the expected count of items at the given key.
64
     *
65
     * @param  int  $count
66
     * @param  string|null  $key
67
     * @return $this
68
     */
69
    public function assertCount(int $count, $key = null)
70
    {
71
        if (! is_null($key)) {
72
            PHPUnit::assertCount(
73
                $count, data_get($this->decoded, $key),
74
                "Failed to assert that the response count matched the expected {$count}"
75
            );
76
 
77
            return $this;
78
        }
79
 
80
        PHPUnit::assertCount($count,
81
            $this->decoded,
82
            "Failed to assert that the response count matched the expected {$count}"
83
        );
84
 
85
        return $this;
86
    }
87
 
88
    /**
89
     * Assert that the response has the exact given JSON.
90
     *
91
     * @param  array  $data
92
     * @return $this
93
     */
94
    public function assertExact(array $data)
95
    {
96
        $actual = $this->reorderAssocKeys((array) $this->decoded);
97
 
98
        $expected = $this->reorderAssocKeys($data);
99
 
100
        PHPUnit::assertEquals(
101
            json_encode($expected, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES),
102
            json_encode($actual, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
103
        );
104
 
105
        return $this;
106
    }
107
 
108
    /**
109
     * Assert that the response has the similar JSON as given.
110
     *
111
     * @param  array  $data
112
     * @return $this
113
     */
114
    public function assertSimilar(array $data)
115
    {
116
        $actual = json_encode(
117
            Arr::sortRecursive((array) $this->decoded),
118
            JSON_UNESCAPED_UNICODE
119
        );
120
 
121
        PHPUnit::assertEquals(json_encode(Arr::sortRecursive($data), JSON_UNESCAPED_UNICODE), $actual);
122
 
123
        return $this;
124
    }
125
 
126
    /**
127
     * Assert that the response contains the given JSON fragment.
128
     *
129
     * @param  array  $data
130
     * @return $this
131
     */
132
    public function assertFragment(array $data)
133
    {
134
        $actual = json_encode(
135
            Arr::sortRecursive((array) $this->decoded),
136
            JSON_UNESCAPED_UNICODE
137
        );
138
 
139
        foreach (Arr::sortRecursive($data) as $key => $value) {
140
            $expected = $this->jsonSearchStrings($key, $value);
141
 
142
            PHPUnit::assertTrue(
143
                Str::contains($actual, $expected),
144
                'Unable to find JSON fragment: '.PHP_EOL.PHP_EOL.
145
                '['.json_encode([$key => $value], JSON_UNESCAPED_UNICODE).']'.PHP_EOL.PHP_EOL.
146
                'within'.PHP_EOL.PHP_EOL.
147
                "[{$actual}]."
148
            );
149
        }
150
 
151
        return $this;
152
    }
153
 
154
    /**
155
     * Assert that the response does not contain the given JSON fragment.
156
     *
157
     * @param  array  $data
158
     * @param  bool  $exact
159
     * @return $this
160
     */
161
    public function assertMissing(array $data, $exact = false)
162
    {
163
        if ($exact) {
164
            return $this->assertMissingExact($data);
165
        }
166
 
167
        $actual = json_encode(
168
            Arr::sortRecursive((array) $this->decoded),
169
            JSON_UNESCAPED_UNICODE
170
        );
171
 
172
        foreach (Arr::sortRecursive($data) as $key => $value) {
173
            $unexpected = $this->jsonSearchStrings($key, $value);
174
 
175
            PHPUnit::assertFalse(
176
                Str::contains($actual, $unexpected),
177
                'Found unexpected JSON fragment: '.PHP_EOL.PHP_EOL.
178
                '['.json_encode([$key => $value], JSON_UNESCAPED_UNICODE).']'.PHP_EOL.PHP_EOL.
179
                'within'.PHP_EOL.PHP_EOL.
180
                "[{$actual}]."
181
            );
182
        }
183
 
184
        return $this;
185
    }
186
 
187
    /**
188
     * Assert that the response does not contain the exact JSON fragment.
189
     *
190
     * @param  array  $data
191
     * @return $this
192
     */
193
    public function assertMissingExact(array $data)
194
    {
195
        $actual = json_encode(
196
            Arr::sortRecursive((array) $this->decoded),
197
            JSON_UNESCAPED_UNICODE
198
        );
199
 
200
        foreach (Arr::sortRecursive($data) as $key => $value) {
201
            $unexpected = $this->jsonSearchStrings($key, $value);
202
 
203
            if (! Str::contains($actual, $unexpected)) {
204
                return $this;
205
            }
206
        }
207
 
208
        PHPUnit::fail(
209
            'Found unexpected JSON fragment: '.PHP_EOL.PHP_EOL.
210
            '['.json_encode($data, JSON_UNESCAPED_UNICODE).']'.PHP_EOL.PHP_EOL.
211
            'within'.PHP_EOL.PHP_EOL.
212
            "[{$actual}]."
213
        );
214
 
215
        return $this;
216
    }
217
 
218
    /**
219
     * Assert that the response does not contain the given path.
220
     *
221
     * @param  string  $path
222
     * @return $this
223
     */
224
    public function assertMissingPath($path)
225
    {
226
        PHPUnit::assertFalse(Arr::has($this->json(), $path));
227
 
228
        return $this;
229
    }
230
 
231
    /**
232
     * Assert that the expected value and type exists at the given path in the response.
233
     *
234
     * @param  string  $path
235
     * @param  mixed  $expect
236
     * @return $this
237
     */
238
    public function assertPath($path, $expect)
239
    {
240
        if ($expect instanceof Closure) {
241
            PHPUnit::assertTrue($expect($this->json($path)));
242
        } else {
243
            PHPUnit::assertSame($expect, $this->json($path));
244
        }
245
 
246
        return $this;
247
    }
248
 
249
    /**
250
     * Assert that the response has a given JSON structure.
251
     *
252
     * @param  array|null  $structure
253
     * @param  array|null  $responseData
254
     * @return $this
255
     */
256
    public function assertStructure(array $structure = null, $responseData = null)
257
    {
258
        if (is_null($structure)) {
259
            return $this->assertSimilar($this->decoded);
260
        }
261
 
262
        if (! is_null($responseData)) {
263
            return (new static($responseData))->assertStructure($structure);
264
        }
265
 
266
        foreach ($structure as $key => $value) {
267
            if (is_array($value) && $key === '*') {
268
                PHPUnit::assertIsArray($this->decoded);
269
 
270
                foreach ($this->decoded as $responseDataItem) {
271
                    $this->assertStructure($structure['*'], $responseDataItem);
272
                }
273
            } elseif (is_array($value)) {
274
                PHPUnit::assertArrayHasKey($key, $this->decoded);
275
 
276
                $this->assertStructure($structure[$key], $this->decoded[$key]);
277
            } else {
278
                PHPUnit::assertArrayHasKey($value, $this->decoded);
279
            }
280
        }
281
 
282
        return $this;
283
    }
284
 
285
    /**
286
     * Assert that the response is a superset of the given JSON.
287
     *
288
     * @param  array  $data
289
     * @param  bool  $strict
290
     * @return $this
291
     */
292
    public function assertSubset(array $data, $strict = false)
293
    {
294
        PHPUnit::assertArraySubset(
295
            $data, $this->decoded, $strict, $this->assertJsonMessage($data)
296
        );
297
 
298
        return $this;
299
    }
300
 
301
    /**
302
     * Reorder associative array keys to make it easy to compare arrays.
303
     *
304
     * @param  array  $data
305
     * @return array
306
     */
307
    protected function reorderAssocKeys(array $data)
308
    {
309
        $data = Arr::dot($data);
310
        ksort($data);
311
 
312
        $result = [];
313
 
314
        foreach ($data as $key => $value) {
315
            Arr::set($result, $key, $value);
316
        }
317
 
318
        return $result;
319
    }
320
 
321
    /**
322
     * Get the assertion message for assertJson.
323
     *
324
     * @param  array  $data
325
     * @return string
326
     */
327
    protected function assertJsonMessage(array $data)
328
    {
329
        $expected = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
330
 
331
        $actual = json_encode($this->decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
332
 
333
        return 'Unable to find JSON: '.PHP_EOL.PHP_EOL.
334
            "[{$expected}]".PHP_EOL.PHP_EOL.
335
            'within response JSON:'.PHP_EOL.PHP_EOL.
336
            "[{$actual}].".PHP_EOL.PHP_EOL;
337
    }
338
 
339
    /**
340
     * Get the strings we need to search for when examining the JSON.
341
     *
342
     * @param  string  $key
343
     * @param  string  $value
344
     * @return array
345
     */
346
    protected function jsonSearchStrings($key, $value)
347
    {
348
        $needle = Str::substr(json_encode([$key => $value], JSON_UNESCAPED_UNICODE), 1, -1);
349
 
350
        return [
351
            $needle.']',
352
            $needle.'}',
353
            $needle.',',
354
        ];
355
    }
356
 
357
    /**
358
     * Get the total number of items in the underlying JSON array.
359
     *
360
     * @return int
361
     */
362
    public function count(): int
363
    {
364
        return count($this->decoded);
365
    }
366
 
367
    /**
368
     * Determine whether an offset exists.
369
     *
370
     * @param  mixed  $offset
371
     * @return bool
372
     */
373
    public function offsetExists($offset): bool
374
    {
375
        return isset($this->decoded[$offset]);
376
    }
377
 
378
    /**
379
     * Get the value at the given offset.
380
     *
381
     * @param  string  $offset
382
     * @return mixed
383
     */
384
    public function offsetGet($offset): mixed
385
    {
386
        return $this->decoded[$offset];
387
    }
388
 
389
    /**
390
     * Set the value at the given offset.
391
     *
392
     * @param  string  $offset
393
     * @param  mixed  $value
394
     * @return void
395
     */
396
    public function offsetSet($offset, $value): void
397
    {
398
        $this->decoded[$offset] = $value;
399
    }
400
 
401
    /**
402
     * Unset the value at the given offset.
403
     *
404
     * @param  string  $offset
405
     * @return void
406
     */
407
    public function offsetUnset($offset): void
408
    {
409
        unset($this->decoded[$offset]);
410
    }
411
}