Parameters.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <?php
  2. /*
  3. * This file is part of the phpunit-mock-objects package.
  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\MockObject\Matcher;
  11. use PHPUnit\Framework\Constraint\Constraint;
  12. use PHPUnit\Framework\Constraint\IsAnything;
  13. use PHPUnit\Framework\Constraint\IsEqual;
  14. use PHPUnit\Framework\ExpectationFailedException;
  15. use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
  16. /**
  17. * Invocation matcher which looks for specific parameters in the invocations.
  18. *
  19. * Checks the parameters of all incoming invocations, the parameter list is
  20. * checked against the defined constraints in $parameters. If the constraint
  21. * is met it will return true in matches().
  22. */
  23. class Parameters extends StatelessInvocation
  24. {
  25. /**
  26. * @var Constraint[]
  27. */
  28. private $parameters = [];
  29. /**
  30. * @var BaseInvocation
  31. */
  32. private $invocation;
  33. /**
  34. * @var ExpectationFailedException
  35. */
  36. private $parameterVerificationResult;
  37. /**
  38. * @param array $parameters
  39. *
  40. * @throws \PHPUnit\Framework\Exception
  41. */
  42. public function __construct(array $parameters)
  43. {
  44. foreach ($parameters as $parameter) {
  45. if (!($parameter instanceof Constraint)) {
  46. $parameter = new IsEqual(
  47. $parameter
  48. );
  49. }
  50. $this->parameters[] = $parameter;
  51. }
  52. }
  53. /**
  54. * @return string
  55. */
  56. public function toString()
  57. {
  58. $text = 'with parameter';
  59. foreach ($this->parameters as $index => $parameter) {
  60. if ($index > 0) {
  61. $text .= ' and';
  62. }
  63. $text .= ' ' . $index . ' ' . $parameter->toString();
  64. }
  65. return $text;
  66. }
  67. /**
  68. * @param BaseInvocation $invocation
  69. *
  70. * @return bool
  71. *
  72. * @throws \Exception
  73. */
  74. public function matches(BaseInvocation $invocation)
  75. {
  76. $this->invocation = $invocation;
  77. $this->parameterVerificationResult = null;
  78. try {
  79. $this->parameterVerificationResult = $this->verify();
  80. return $this->parameterVerificationResult;
  81. } catch (ExpectationFailedException $e) {
  82. $this->parameterVerificationResult = $e;
  83. throw $this->parameterVerificationResult;
  84. }
  85. }
  86. /**
  87. * Checks if the invocation $invocation matches the current rules. If it
  88. * does the matcher will get the invoked() method called which should check
  89. * if an expectation is met.
  90. *
  91. * @return bool
  92. *
  93. * @throws ExpectationFailedException
  94. */
  95. public function verify()
  96. {
  97. if (isset($this->parameterVerificationResult)) {
  98. return $this->guardAgainstDuplicateEvaluationOfParameterConstraints();
  99. }
  100. if ($this->invocation === null) {
  101. throw new ExpectationFailedException('Mocked method does not exist.');
  102. }
  103. if (\count($this->invocation->getParameters()) < \count($this->parameters)) {
  104. $message = 'Parameter count for invocation %s is too low.';
  105. // The user called `->with($this->anything())`, but may have meant
  106. // `->withAnyParameters()`.
  107. //
  108. // @see https://github.com/sebastianbergmann/phpunit-mock-objects/issues/199
  109. if (\count($this->parameters) === 1 &&
  110. \get_class($this->parameters[0]) === IsAnything::class) {
  111. $message .= "\nTo allow 0 or more parameters with any value, omit ->with() or use ->withAnyParameters() instead.";
  112. }
  113. throw new ExpectationFailedException(
  114. \sprintf($message, $this->invocation->toString())
  115. );
  116. }
  117. foreach ($this->parameters as $i => $parameter) {
  118. $parameter->evaluate(
  119. $this->invocation->getParameters()[$i],
  120. \sprintf(
  121. 'Parameter %s for invocation %s does not match expected ' .
  122. 'value.',
  123. $i,
  124. $this->invocation->toString()
  125. )
  126. );
  127. }
  128. return true;
  129. }
  130. /**
  131. * @return bool
  132. *
  133. * @throws ExpectationFailedException
  134. */
  135. private function guardAgainstDuplicateEvaluationOfParameterConstraints()
  136. {
  137. if ($this->parameterVerificationResult instanceof \Exception) {
  138. throw $this->parameterVerificationResult;
  139. }
  140. return (bool) $this->parameterVerificationResult;
  141. }
  142. }