Passed
Push — master ( 06fb26...109dc7 )
by Paweł
02:17
created

MatchesJsonSchema::toString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
/**
3
 * Copyright (c) 2020.
4
 * @author Paweł Antosiak <[email protected]>
5
 */
6
7
declare(strict_types=1);
8
9
namespace Gorynych\Testing\Constraint;
10
11
use JsonSchema\Constraints\Factory;
12
use JsonSchema\SchemaStorage;
13
use JsonSchema\Validator;
14
use PHPUnit\Framework\Constraint\Constraint;
15
16
final class MatchesJsonSchema extends Constraint
17
{
18
    private object $schema;
19
    private ?int $checkMode;
20
21
    public function __construct(object $schema, ?int $checkMode = null)
22
    {
23
        $this->schema = $schema;
24
        $this->checkMode = $checkMode;
25
    }
26
27
    /**
28
     * {@inheritdoc}
29
     */
30
    public function toString(): string
31
    {
32
        return 'matches provided JSON Schema';
33
    }
34
35
    /**
36
     * {@inheritdoc}
37
     */
38
    protected function matches($other): bool
39
    {
40
        $other = $this->normalizeJson($other);
41
42
        $validator = $this->getSchemaValidator();
43
        $validator->validate($other, $this->schema, $this->checkMode);
44
45
        return $validator->isValid();
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51
    protected function additionalFailureDescription($other): string
52
    {
53
        $other = $this->normalizeJson($other);
54
55
        $validator = $this->getSchemaValidator();
56
        $validator->validate($other, $this->schema, $this->checkMode);
57
58
        $errors = array_map(
59
            static function (array $error): string {
60
                return ($error['property'] ? $error['property'] . ': ' : '') . $error['message'];
61
            },
62
            $validator->getErrors()
63
        );
64
65
        return implode("\n", $errors);
66
    }
67
68
    /**
69
     * Normalizes a JSON document
70
     *
71
     * Specifically, we should ensure that:
72
     * 1. a JSON object is represented as a PHP object, not as an associative array
73
     *
74
     * @param mixed $document
75
     * @return object|mixed[]
76
     * @throws \InvalidArgumentException
77
     * @throws \UnexpectedValueException
78
     */
79
    private function normalizeJson($document)
80
    {
81
        if (true === is_scalar($document) || true === is_object($document)) {
82
            return $document;
83
        }
84
85
        if (false === is_array($document)) {
86
            throw new \InvalidArgumentException('Document must be scalar, array or object.');
87
        }
88
89
        $document = json_encode($document);
90
91
        if (false === is_string($document)) {
0 ignored issues
show
introduced by
The condition false === is_string($document) is always false.
Loading history...
92
            throw new \UnexpectedValueException('JSON encode failed.');
93
        }
94
95
        $document = json_decode($document);
96
97
        if (false === is_array($document) && false === is_object($document)) {
98
            throw new \UnexpectedValueException('JSON decode failed.');
99
        }
100
101
        return $document;
102
    }
103
104
    private function getSchemaValidator(): Validator
105
    {
106
        $schemaStorage = new SchemaStorage();
107
        $schemaStorage->addSchema('file://schemas', $this->schema);
108
109
        return new Validator(new Factory($schemaStorage));
110
    }
111
}
112