Skip to content

Commit

Permalink
Prevent shouldNotReceive from getting overridden (#1329)
Browse files Browse the repository at this point in the history
Co-authored-by: Danny-Smart <113538899+Danny-Smart@users.noreply.github.com>
  • Loading branch information
ghostwriter and Danny-Smart committed Aug 23, 2023
2 parents b8e0bb7 + fe754a2 commit fab5c13
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
20 changes: 20 additions & 0 deletions library/Mockery/Expectation.php
Expand Up @@ -19,6 +19,7 @@

class Expectation implements ExpectationInterface
{
public const ERROR_ZERO_INVOCATION = 'shouldNotReceive(), never(), times(0) chaining additional invocation count methods has been deprecated and will throw an exception in a future version of Mockery';
/**
* Mock object to which this expectation belongs
*
Expand All @@ -40,6 +41,13 @@ class Expectation implements ExpectationInterface
*/
protected $_because = null;

/**
* Expected count of calls to this expectation
*
* @var int
*/
protected $_expectedCount = -1;

/**
* Arguments expected by this expectation
*
Expand Down Expand Up @@ -719,6 +727,18 @@ public function times($limit = null)
if (!is_int($limit)) {
throw new \InvalidArgumentException('The passed Times limit should be an integer value');
}

if ($this->_expectedCount === 0) {
@trigger_error(self::ERROR_ZERO_INVOCATION, E_USER_DEPRECATED);
// throw new \InvalidArgumentException(self::ERROR_ZERO_INVOCATION);
}

if ($limit === 0) {
$this->_countValidators = [];
}

$this->_expectedCount = $limit;

$this->_countValidators[$this->_countValidatorClass] = new $this->_countValidatorClass($this, $limit);

if ('Mockery\CountValidator\Exact' !== $this->_countValidatorClass) {
Expand Down
70 changes: 70 additions & 0 deletions tests/Unit/Regression/Issue1328Test.php
@@ -0,0 +1,70 @@
<?php

namespace Mockery\Tests\Unit\Regression;

use DateTime;
use InvalidArgumentException;
use Mockery;
use Mockery\Exception\InvalidCountException;
use Mockery\Expectation;
use PHPUnit\Framework\TestCase;

final class Issue1328Test extends TestCase
{
public function testShouldFailWithAnInvocationCountError(): void
{
$this->expectException(InvalidCountException::class);

$mock = Mockery::mock(DateTime::class);

$mock->shouldNotReceive("format");

$mock->format("Y");

Mockery::close();
}

public function testThrowsInvalidArgumentExceptionWhenInvocationCountChanges(): void
{
set_error_handler(
static function (int $errorCode, string $errorMessage): void {
restore_error_handler();
throw new InvalidArgumentException($errorMessage, $errorCode);
},
E_ALL
);

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(Expectation::ERROR_ZERO_INVOCATION);

$mock = Mockery::mock(DateTime::class);

$mock->shouldNotReceive("format")->once();

$mock->format("Y");

Mockery::close();
}

public function testThrowsInvalidArgumentExceptionForChainingAdditionalInvocationCountMethod(): void
{
set_error_handler(
static function (int $errorCode, string $errorMessage): void {
restore_error_handler();
throw new InvalidArgumentException($errorMessage, $errorCode);
},
E_ALL
);

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(Expectation::ERROR_ZERO_INVOCATION);

$mock = Mockery::mock(DateTime::class);

$mock->shouldNotReceive("format")->times(0);

$mock->format("Y");

Mockery::close();
}
}

0 comments on commit fab5c13

Please sign in to comment.