martin-helmich/phpunit-json-assert

View on GitHub
src/Constraint/JsonValueMatches.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
namespace Helmich\JsonAssert\Constraint;

use Flow\JSONPath\JSONPath;
use PHPUnit\Framework\Constraint\Constraint;

/**
 * A simple constraints that asserts that a single value of a JSON document
 * matches a given constraint.
 *
 * @package    Helmich\JsonAssert
 * @subpackage Constraint
 */
class JsonValueMatches extends Constraint
{

    /** @var string */
    private $jsonPath;

    /** @var Constraint */
    private $constraint;

    /** @var bool */
    private $matchAll;

    /**
     * JsonValueMatches constructor.
     *
     * @param string     $jsonPath   The JSON path that identifies the value(s)
     *                               in the JSON document that the constraint
     *                               should match
     * @param Constraint $constraint The actual constraint that the selected
     *                               value(s) must match
     * @param bool       $matchAll   This flag controls how this constraint
     *                               handles multiple values. Usually, this
     *                               constraint will match successfully, when
     *                               (at least) one found value matches the
     *                               given constraint. When this flag is set,
     *                               _all_ found values must match the
     *                               constraint.
     */
    public function __construct(string $jsonPath, Constraint $constraint, bool $matchAll = false)
    {
        $this->jsonPath   = $jsonPath;
        $this->constraint = $constraint;
        $this->matchAll   = $matchAll;
    }

    /**
     * Returns a string representation of the object.
     *
     * @return string
     */
    public function toString(): string
    {
        return "matches " . $this->constraint->toString() . " at JSON path '{$this->jsonPath}'";
    }

    /**
     * @inheritdoc
     */
    protected function matches($other): bool
    {
        if (is_string($other)) {
            $other = json_decode($other, true);
        }

        $result = (new JSONPath($other))->find($this->jsonPath);
        if (!isset($result[0])) {
            return false;
        }

        $combineFunc = $this->buildCombinationFunction();
        $matches     = null;

        foreach ($result as $v) {
            if ($v instanceof JSONPath) {
                $v = $v->getData();
            }

            $singleMatchResult = $this->constraint->evaluate($v, '', true);
            $matches           = $combineFunc($matches, $singleMatchResult);
        }

        return $matches;
    }

    /**
     * @return callable
     */
    protected function buildCombinationFunction(): callable
    {
        if ($this->matchAll) {
            return function ($first, $second) {
                return ($first === null) ? $second : $first && $second;
            };
        }

        return function ($first, $second) {
            return ($first === null) ? $second : $first || $second;
        };
    }
}