1<?php
2
3/*
4 * This file is part of the Prophecy.
5 * (c) Konstantin Kudryashov <ever.zet@gmail.com>
6 *     Marcello Duarte <marcello.duarte@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Prophecy\Argument\Token;
13
14use SebastianBergmann\Comparator\ComparisonFailure;
15use Prophecy\Comparator\Factory as ComparatorFactory;
16use Prophecy\Util\StringUtil;
17
18/**
19 * Exact value token.
20 *
21 * @author Konstantin Kudryashov <ever.zet@gmail.com>
22 */
23class ExactValueToken implements TokenInterface
24{
25    private $value;
26    private $string;
27    private $util;
28    private $comparatorFactory;
29
30    /**
31     * Initializes token.
32     *
33     * @param mixed             $value
34     * @param StringUtil        $util
35     * @param ComparatorFactory $comparatorFactory
36     */
37    public function __construct($value, StringUtil $util = null, ComparatorFactory $comparatorFactory = null)
38    {
39        $this->value = $value;
40        $this->util  = $util ?: new StringUtil();
41
42        $this->comparatorFactory = $comparatorFactory ?: ComparatorFactory::getInstance();
43    }
44
45    /**
46     * Scores 10 if argument matches preset value.
47     *
48     * @param $argument
49     *
50     * @return bool|int
51     */
52    public function scoreArgument($argument)
53    {
54        if (is_object($argument) && is_object($this->value)) {
55            $comparator = $this->comparatorFactory->getComparatorFor(
56                $argument, $this->value
57            );
58
59            try {
60                $comparator->assertEquals($argument, $this->value);
61                return 10;
62            } catch (ComparisonFailure $failure) {}
63        }
64
65        // If either one is an object it should be castable to a string
66        if (is_object($argument) xor is_object($this->value)) {
67            if (is_object($argument) && !method_exists($argument, '__toString')) {
68                return false;
69            }
70
71            if (is_object($this->value) && !method_exists($this->value, '__toString')) {
72                return false;
73            }
74        } elseif (is_numeric($argument) && is_numeric($this->value)) {
75            // noop
76        } elseif (gettype($argument) !== gettype($this->value)) {
77            return false;
78        }
79
80        return $argument == $this->value ? 10 : false;
81    }
82
83    /**
84     * Returns preset value against which token checks arguments.
85     *
86     * @return mixed
87     */
88    public function getValue()
89    {
90        return $this->value;
91    }
92
93    /**
94     * Returns false.
95     *
96     * @return bool
97     */
98    public function isLast()
99    {
100        return false;
101    }
102
103    /**
104     * Returns string representation for token.
105     *
106     * @return string
107     */
108    public function __toString()
109    {
110        if (null === $this->string) {
111            $this->string = sprintf('exact(%s)', $this->util->stringify($this->value));
112        }
113
114        return $this->string;
115    }
116}
117