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 * Constraint that asserts that one value is identical to another.
13 *
14 * Identical check is performed with PHP's === operator, the operator is
15 * explained in detail at
16 * {@url http://www.php.net/manual/en/types.comparisons.php}.
17 * Two values are identical if they have the same value and are of the same
18 * type.
19 *
20 * The expected value is passed in the constructor.
21 */
22class PHPUnit_Framework_Constraint_IsIdentical extends PHPUnit_Framework_Constraint
23{
24    /**
25     * @var float
26     */
27    const EPSILON = 0.0000000001;
28
29    /**
30     * @var mixed
31     */
32    protected $value;
33
34    /**
35     * @param mixed $value
36     */
37    public function __construct($value)
38    {
39        parent::__construct();
40        $this->value = $value;
41    }
42
43    /**
44     * Evaluates the constraint for parameter $other
45     *
46     * If $returnResult is set to false (the default), an exception is thrown
47     * in case of a failure. null is returned otherwise.
48     *
49     * If $returnResult is true, the result of the evaluation is returned as
50     * a boolean value instead: true in case of success, false in case of a
51     * failure.
52     *
53     * @param mixed  $other        Value or object to evaluate.
54     * @param string $description  Additional information about the test
55     * @param bool   $returnResult Whether to return a result or throw an exception
56     *
57     * @return mixed
58     *
59     * @throws PHPUnit_Framework_ExpectationFailedException
60     */
61    public function evaluate($other, $description = '', $returnResult = false)
62    {
63        if (is_float($this->value) && is_float($other) &&
64            !is_infinite($this->value) && !is_infinite($other) &&
65            !is_nan($this->value) && !is_nan($other)) {
66            $success = abs($this->value - $other) < self::EPSILON;
67        } else {
68            $success = $this->value === $other;
69        }
70
71        if ($returnResult) {
72            return $success;
73        }
74
75        if (!$success) {
76            $f = null;
77
78            // if both values are strings, make sure a diff is generated
79            if (is_string($this->value) && is_string($other)) {
80                $f = new SebastianBergmann\Comparator\ComparisonFailure(
81                    $this->value,
82                    $other,
83                    $this->value,
84                    $other
85                );
86            }
87
88            $this->fail($other, $description, $f);
89        }
90    }
91
92    /**
93     * Returns the description of the failure
94     *
95     * The beginning of failure messages is "Failed asserting that" in most
96     * cases. This method should return the second part of that sentence.
97     *
98     * @param mixed $other Evaluated value or object.
99     *
100     * @return string
101     */
102    protected function failureDescription($other)
103    {
104        if (is_object($this->value) && is_object($other)) {
105            return 'two variables reference the same object';
106        }
107
108        if (is_string($this->value) && is_string($other)) {
109            return 'two strings are identical';
110        }
111
112        return parent::failureDescription($other);
113    }
114
115    /**
116     * Returns a string representation of the constraint.
117     *
118     * @return string
119     */
120    public function toString()
121    {
122        if (is_object($this->value)) {
123            return 'is identical to an object of class "' .
124                   get_class($this->value) . '"';
125        } else {
126            return 'is identical to ' .
127                   $this->exporter->export($this->value);
128        }
129    }
130}
131