Passed
Push — master ( 46a695...6de73d )
by Julien
01:29 queued 11s
created

ContainsExactly   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 114
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 1 Features 1
Metric Value
wmc 17
eloc 47
c 2
b 1
f 1
dl 0
loc 114
ccs 52
cts 52
cp 1
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A buildFailure() 0 20 2
A getMissingElements() 0 3 1
B evaluate() 0 53 11
A __construct() 0 3 1
A getUnexpectedElements() 0 3 1
A toString() 0 3 1
1
<?php declare(strict_types=1);
2
3
4
namespace Pitchart\Phlunit\Constraint\Arrays;
5
6
use PHPUnit\Framework\Constraint\Constraint;
7
use PHPUnit\Framework\ExpectationFailedException;
8
use function Pitchart\Transformer\transform;
9
use SebastianBergmann\Comparator\ComparisonFailure;
10
11
class ContainsExactly extends Constraint
12
{
13
    /**
14
     * @var array<mixed>
15
     */
16
    private $elements;
17
18
    /**
19
     * ContainsExactly constructor.
20
     *
21
     * @param array<mixed> ...$elements
22
     */
23 24
    public function __construct(...$elements)
24
    {
25 24
        $this->elements = $elements;
26 24
    }
27
28
    /**
29
     * @param iterable $other
30
     * @param string $description
31
     * @param bool $returnResult
32
     *
33
     * @return bool|null
34
     */
35 21
    public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
36
    {
37
        //type cast $other & $this->subset as an array to allow
38
        //support in standard array functions.
39 21
        $other = \array_values(ArrayUtility::toArray($other));
40 21
        $elements = ArrayUtility::toArray($this->elements);
41 21
        $failureList = [];
42
43 21
        $missing = $this->getMissingElements($other, $elements);
44
45 21
        $success = $missing === [];
46
47 21
        if (!empty($missing)) {
48 6
            $count = \count($missing);
49 6
            $failureList[] = \sprintf(
50 6
                "%d %s missing",
51 6
                $count,
52 6
                $count == 1 ? 'element is' : 'elements are'
53
            );
54
        }
55
56 21
        $unexpected = $this->getUnexpectedElements($other, $elements);
57
58 21
        $success = $success && $unexpected === [];
59
60 21
        if (!empty($unexpected)) {
61 4
            $count = \count($unexpected);
62 4
            $failureList[] = \sprintf(
63 4
                "%d %s unexpected",
64 4
                $count,
65 4
                $count == 1 ? 'element is' : 'elements are'
66
            );
67
        }
68
69 21
        if ($success) {
70 13
            foreach ($elements as $key => $element) {
71 13
                if ($element != $other[$key]) {
72 2
                    $success = false;
73 2
                    $failureList[] = \sprintf("element at position %s is not the one expected", $key);
74 2
                    break;
75
                }
76
            }
77
        }
78
79 21
        if ($returnResult) {
80 14
            return $success;
81
        }
82
83 7
        if (!$success) {
84 5
            throw $this->buildFailure($other, $elements, $failureList, $description);
85
        }
86
87 2
        return null;
88
    }
89
90 5
    private function buildFailure(array $other, array $elements, array $failureList, string $description = ''): ExpectationFailedException
91
    {
92 5
        $failureDescription = \sprintf(
93 5
            'Failed asserting that ' . $this->toString(),
94 5
            \count($elements),
95 5
            \implode(' and ', $failureList)
96
        );
97
98 5
        if (!empty($description)) {
99 1
            $failureDescription = $description . "\n" . $failureDescription;
100
        }
101
102 5
        $comparisonFailure = new ComparisonFailure(
103 5
            $elements,
104
            $other,
105 5
            $this->exporter()->export($elements),
106 5
            $this->exporter()->export($other)
107
        );
108
109 5
        return new ExpectationFailedException($failureDescription, $comparisonFailure);
110
    }
111
112 21
    private function getMissingElements(array $other, array $elements): array
113
    {
114 21
        return  transform($elements)->diff($other)->toArray();
115
    }
116
117 21
    private function getUnexpectedElements(array $other, array $elements): array
118
    {
119 21
        return  transform($other)->diff($elements)->toArray();
120
    }
121
122 5
    public function toString(): string
123
    {
124 5
        return 'iterable contains %d expected elements because %s.';
125
    }
126
}
127