Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php declare(strict_types=1);
2
/*
3
 * This file is part of PHPUnit.
4
 *
5
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace PHPUnit\Framework\Constraint;
11
 
12
use function sprintf;
13
use Countable;
14
use PHPUnit\Framework\ExpectationFailedException;
15
use PHPUnit\Framework\SelfDescribing;
16
use SebastianBergmann\Comparator\ComparisonFailure;
17
use SebastianBergmann\Exporter\Exporter;
18
 
19
/**
20
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
21
 */
22
abstract class Constraint implements Countable, SelfDescribing
23
{
24
    /**
25
     * @var ?Exporter
26
     */
27
    private $exporter;
28
 
29
    /**
30
     * Evaluates the constraint for parameter $other.
31
     *
32
     * If $returnResult is set to false (the default), an exception is thrown
33
     * in case of a failure. null is returned otherwise.
34
     *
35
     * If $returnResult is true, the result of the evaluation is returned as
36
     * a boolean value instead: true in case of success, false in case of a
37
     * failure.
38
     *
39
     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
40
     * @throws ExpectationFailedException
41
     */
42
    public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
43
    {
44
        $success = false;
45
 
46
        if ($this->matches($other)) {
47
            $success = true;
48
        }
49
 
50
        if ($returnResult) {
51
            return $success;
52
        }
53
 
54
        if (!$success) {
55
            $this->fail($other, $description);
56
        }
57
 
58
        return null;
59
    }
60
 
61
    /**
62
     * Counts the number of constraint elements.
63
     */
64
    public function count(): int
65
    {
66
        return 1;
67
    }
68
 
69
    protected function exporter(): Exporter
70
    {
71
        if ($this->exporter === null) {
72
            $this->exporter = new Exporter;
73
        }
74
 
75
        return $this->exporter;
76
    }
77
 
78
    /**
79
     * Evaluates the constraint for parameter $other. Returns true if the
80
     * constraint is met, false otherwise.
81
     *
82
     * This method can be overridden to implement the evaluation algorithm.
83
     *
84
     * @param mixed $other value or object to evaluate
85
     *
86
     * @codeCoverageIgnore
87
     */
88
    protected function matches($other): bool
89
    {
90
        return false;
91
    }
92
 
93
    /**
94
     * Throws an exception for the given compared value and test description.
95
     *
96
     * @param mixed             $other             evaluated value or object
97
     * @param string            $description       Additional information about the test
98
     * @param ComparisonFailure $comparisonFailure
99
     *
100
     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
101
     * @throws ExpectationFailedException
102
     *
103
     * @psalm-return never-return
104
     */
105
    protected function fail($other, $description, ComparisonFailure $comparisonFailure = null): void
106
    {
107
        $failureDescription = sprintf(
108
            'Failed asserting that %s.',
109
            $this->failureDescription($other)
110
        );
111
 
112
        $additionalFailureDescription = $this->additionalFailureDescription($other);
113
 
114
        if ($additionalFailureDescription) {
115
            $failureDescription .= "\n" . $additionalFailureDescription;
116
        }
117
 
118
        if (!empty($description)) {
119
            $failureDescription = $description . "\n" . $failureDescription;
120
        }
121
 
122
        throw new ExpectationFailedException(
123
            $failureDescription,
124
            $comparisonFailure
125
        );
126
    }
127
 
128
    /**
129
     * Return additional failure description where needed.
130
     *
131
     * The function can be overridden to provide additional failure
132
     * information like a diff
133
     *
134
     * @param mixed $other evaluated value or object
135
     */
136
    protected function additionalFailureDescription($other): string
137
    {
138
        return '';
139
    }
140
 
141
    /**
142
     * Returns the description of the failure.
143
     *
144
     * The beginning of failure messages is "Failed asserting that" in most
145
     * cases. This method should return the second part of that sentence.
146
     *
147
     * To provide additional failure information additionalFailureDescription
148
     * can be used.
149
     *
150
     * @param mixed $other evaluated value or object
151
     *
152
     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
153
     */
154
    protected function failureDescription($other): string
155
    {
156
        return $this->exporter()->export($other) . ' ' . $this->toString();
157
    }
158
 
159
    /**
160
     * Returns a custom string representation of the constraint object when it
161
     * appears in context of an $operator expression.
162
     *
163
     * The purpose of this method is to provide meaningful descriptive string
164
     * in context of operators such as LogicalNot. Native PHPUnit constraints
165
     * are supported out of the box by LogicalNot, but externally developed
166
     * ones had no way to provide correct strings in this context.
167
     *
168
     * The method shall return empty string, when it does not handle
169
     * customization by itself.
170
     *
171
     * @param Operator $operator the $operator of the expression
172
     * @param mixed    $role     role of $this constraint in the $operator expression
173
     */
174
    protected function toStringInContext(Operator $operator, $role): string
175
    {
176
        return '';
177
    }
178
 
179
    /**
180
     * Returns the description of the failure when this constraint appears in
181
     * context of an $operator expression.
182
     *
183
     * The purpose of this method is to provide meaningful failure description
184
     * in context of operators such as LogicalNot. Native PHPUnit constraints
185
     * are supported out of the box by LogicalNot, but externally developed
186
     * ones had no way to provide correct messages in this context.
187
     *
188
     * The method shall return empty string, when it does not handle
189
     * customization by itself.
190
     *
191
     * @param Operator $operator the $operator of the expression
192
     * @param mixed    $role     role of $this constraint in the $operator expression
193
     * @param mixed    $other    evaluated value or object
194
     */
195
    protected function failureDescriptionInContext(Operator $operator, $role, $other): string
196
    {
197
        $string = $this->toStringInContext($operator, $role);
198
 
199
        if ($string === '') {
200
            return '';
201
        }
202
 
203
        return $this->exporter()->export($other) . ' ' . $string;
204
    }
205
 
206
    /**
207
     * Reduces the sub-expression starting at $this by skipping degenerate
208
     * sub-expression and returns first descendant constraint that starts
209
     * a non-reducible sub-expression.
210
     *
211
     * Returns $this for terminal constraints and for operators that start
212
     * non-reducible sub-expression, or the nearest descendant of $this that
213
     * starts a non-reducible sub-expression.
214
     *
215
     * A constraint expression may be modelled as a tree with non-terminal
216
     * nodes (operators) and terminal nodes. For example:
217
     *
218
     *      LogicalOr           (operator, non-terminal)
219
     *      + LogicalAnd        (operator, non-terminal)
220
     *      | + IsType('int')   (terminal)
221
     *      | + GreaterThan(10) (terminal)
222
     *      + LogicalNot        (operator, non-terminal)
223
     *        + IsType('array') (terminal)
224
     *
225
     * A degenerate sub-expression is a part of the tree, that effectively does
226
     * not contribute to the evaluation of the expression it appears in. An example
227
     * of degenerate sub-expression is a BinaryOperator constructed with single
228
     * operand or nested BinaryOperators, each with single operand. An
229
     * expression involving a degenerate sub-expression is equivalent to a
230
     * reduced expression with the degenerate sub-expression removed, for example
231
     *
232
     *      LogicalAnd          (operator)
233
     *      + LogicalOr         (degenerate operator)
234
     *      | + LogicalAnd      (degenerate operator)
235
     *      |   + IsType('int') (terminal)
236
     *      + GreaterThan(10)   (terminal)
237
     *
238
     * is equivalent to
239
     *
240
     *      LogicalAnd          (operator)
241
     *      + IsType('int')     (terminal)
242
     *      + GreaterThan(10)   (terminal)
243
     *
244
     * because the subexpression
245
     *
246
     *      + LogicalOr
247
     *        + LogicalAnd
248
     *          + -
249
     *
250
     * is degenerate. Calling reduce() on the LogicalOr object above, as well
251
     * as on LogicalAnd, shall return the IsType('int') instance.
252
     *
253
     * Other specific reductions can be implemented, for example cascade of
254
     * LogicalNot operators
255
     *
256
     *      + LogicalNot
257
     *        + LogicalNot
258
     *          +LogicalNot
259
     *           + IsTrue
260
     *
261
     * can be reduced to
262
     *
263
     *      LogicalNot
264
     *      + IsTrue
265
     */
266
    protected function reduce(): self
267
    {
268
        return $this;
269
    }
270
}