MatchesJsonSchema::matches()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 4
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 8
ccs 0
cts 5
cp 0
crap 2
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[]|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
        try {
90
            $document = json_encode($document, JSON_THROW_ON_ERROR);
91
            $document = json_decode($document, false, 512, JSON_THROW_ON_ERROR);
92
        } catch (\JsonException $e) {
93
            throw new \UnexpectedValueException($e->getMessage());
94
        }
95
96
        return $document;
97
    }
98
99
    private function getSchemaValidator(): Validator
100
    {
101
        $schemaStorage = new SchemaStorage();
102
        $schemaStorage->addSchema('file://schemas', $this->schema);
103
104
        return new Validator(new Factory($schemaStorage));
105
    }
106
}
107