1: <?php
2: namespace Peridot\Leo\Matcher;
3:
4: use Countable;
5: use InvalidArgumentException;
6: use Peridot\Leo\Matcher\Template\ArrayTemplate;
7: use Peridot\Leo\Matcher\Template\TemplateInterface;
8:
9: /**
10: * LengthMatcher determines if an actual array, string, or Countable has a length equivalent
11: * to the expected value.
12: *
13: * @package Peridot\Leo\Matcher
14: */
15: class LengthMatcher extends AbstractMatcher
16: {
17: /**
18: * @var int
19: */
20: protected $count;
21:
22: /**
23: * {@inheritdoc}
24: *
25: * @return TemplateInterface
26: */
27: public function getDefaultTemplate()
28: {
29: $template = new ArrayTemplate([
30: 'default' => 'Expected {{actual}} to have a length of {{expected}} but got {{count}}',
31: 'negated' => 'Expected {{actual}} to not have a length of {{expected}}'
32: ]);
33:
34: return $template->setTemplateVars(['count' => $this->count]);
35: }
36:
37: /**
38: * Match the length of the countable interface or string against
39: * the expected value.
40: *
41: * @param string|array|Countable $actual
42: * @return mixed
43: */
44: protected function doMatch($actual)
45: {
46: if ($this->isCountable($actual)) {
47: $this->count = count($actual);
48: }
49:
50: if (is_string($actual)) {
51: $this->count = strlen($actual);
52: }
53:
54: if (isset($this->count)) {
55: return $this->expected === $this->count;
56: }
57:
58: throw new InvalidArgumentException("Length matcher requires a string, array, or Countable");
59: }
60:
61: /**
62: * Determine if the native count() function can return a valid result
63: * on the actual value.
64: *
65: * @param mixed $actual
66: * @return bool
67: */
68: protected function isCountable($actual)
69: {
70: return is_array($actual) || $actual instanceof Countable;
71: }
72: }
73: