1<?php
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
11/**
12 * Logical NOT.
13 */
14class PHPUnit_Framework_Constraint_Not extends PHPUnit_Framework_Constraint
15{
16    /**
17     * @var PHPUnit_Framework_Constraint
18     */
19    protected $constraint;
20
21    /**
22     * @param PHPUnit_Framework_Constraint $constraint
23     */
24    public function __construct($constraint)
25    {
26        parent::__construct();
27
28        if (!($constraint instanceof PHPUnit_Framework_Constraint)) {
29            $constraint = new PHPUnit_Framework_Constraint_IsEqual($constraint);
30        }
31
32        $this->constraint = $constraint;
33    }
34
35    /**
36     * @param string $string
37     *
38     * @return string
39     */
40    public static function negate($string)
41    {
42        return str_replace(
43            [
44            'contains ',
45            'exists',
46            'has ',
47            'is ',
48            'are ',
49            'matches ',
50            'starts with ',
51            'ends with ',
52            'reference ',
53            'not not '
54            ],
55            [
56            'does not contain ',
57            'does not exist',
58            'does not have ',
59            'is not ',
60            'are not ',
61            'does not match ',
62            'starts not with ',
63            'ends not with ',
64            'don\'t reference ',
65            'not '
66            ],
67            $string
68        );
69    }
70
71    /**
72     * Evaluates the constraint for parameter $other
73     *
74     * If $returnResult is set to false (the default), an exception is thrown
75     * in case of a failure. null is returned otherwise.
76     *
77     * If $returnResult is true, the result of the evaluation is returned as
78     * a boolean value instead: true in case of success, false in case of a
79     * failure.
80     *
81     * @param mixed  $other        Value or object to evaluate.
82     * @param string $description  Additional information about the test
83     * @param bool   $returnResult Whether to return a result or throw an exception
84     *
85     * @return mixed
86     *
87     * @throws PHPUnit_Framework_ExpectationFailedException
88     */
89    public function evaluate($other, $description = '', $returnResult = false)
90    {
91        $success = !$this->constraint->evaluate($other, $description, true);
92
93        if ($returnResult) {
94            return $success;
95        }
96
97        if (!$success) {
98            $this->fail($other, $description);
99        }
100    }
101
102    /**
103     * Returns the description of the failure
104     *
105     * The beginning of failure messages is "Failed asserting that" in most
106     * cases. This method should return the second part of that sentence.
107     *
108     * @param mixed $other Evaluated value or object.
109     *
110     * @return string
111     */
112    protected function failureDescription($other)
113    {
114        switch (get_class($this->constraint)) {
115            case 'PHPUnit_Framework_Constraint_And':
116            case 'PHPUnit_Framework_Constraint_Not':
117            case 'PHPUnit_Framework_Constraint_Or':
118                return 'not( ' . $this->constraint->failureDescription($other) . ' )';
119
120            default:
121                return self::negate(
122                    $this->constraint->failureDescription($other)
123                );
124        }
125    }
126
127    /**
128     * Returns a string representation of the constraint.
129     *
130     * @return string
131     */
132    public function toString()
133    {
134        switch (get_class($this->constraint)) {
135            case 'PHPUnit_Framework_Constraint_And':
136            case 'PHPUnit_Framework_Constraint_Not':
137            case 'PHPUnit_Framework_Constraint_Or':
138                return 'not( ' . $this->constraint->toString() . ' )';
139
140            default:
141                return self::negate(
142                    $this->constraint->toString()
143                );
144        }
145    }
146
147    /**
148     * Counts the number of constraint elements.
149     *
150     * @return int
151     */
152    public function count()
153    {
154        return count($this->constraint);
155    }
156}
157