Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions src/Framework/MockObject/Stub/ReturnValueMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
namespace PHPUnit\Framework\MockObject\Stub;

use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\MockObject\Invocation;

/**
Expand All @@ -28,17 +29,19 @@ public function __construct(array $valueMap)

public function invoke(Invocation $invocation)
{
$parameterCount = \count($invocation->getParameters());
$parameters = $invocation->getParameters();

$parameterCount = \count($parameters);

foreach ($this->valueMap as $map) {
if (!\is_array($map) || $parameterCount !== (\count($map) - 1)) {
continue;
}

$return = \array_pop($map);
$returnValue = $this->getReturnValue(\array_pop($map));

if ($invocation->getParameters() === $map) {
return $return;
if ($this->compare($parameters, $map)) {
return $returnValue->invoke($invocation);
}
}
}
Expand All @@ -47,4 +50,30 @@ public function toString(): string
{
return 'return value from a map';
}

private function compare(array $actual, array $expected): bool
{
foreach ($expected as $index => $value) {
if ($value instanceof Constraint) {
if ($value->evaluate($actual[$index], '', true) === false) {
return false;
}
} else {
if ($value !== $actual[$index]) {
return false;
}
}
}

return true;
}

private function getReturnValue($value): Stub
{
if (!$value instanceof Stub) {
return new ReturnStub($value);
}

return $value;
}
}
30 changes: 0 additions & 30 deletions tests/unit/Framework/MockObject/MockObjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,36 +216,6 @@ public function testStubbedReturnValue(): void
$this->assertEquals('something', $mock->doSomething());
}

public function testStubbedReturnValueMap(): void
{
$map = [
['a', 'b', 'c', 'd'],
['e', 'f', 'g', 'h'],
];

$mock = $this->getMockBuilder(AnInterface::class)
->getMock();

$mock->expects($this->any())
->method('doSomething')
->will($this->returnValueMap($map));

$this->assertEquals('d', $mock->doSomething('a', 'b', 'c'));
$this->assertEquals('h', $mock->doSomething('e', 'f', 'g'));
$this->assertNull($mock->doSomething('foo', 'bar'));

$mock = $this->getMockBuilder(AnInterface::class)
->getMock();

$mock->expects($this->any())
->method('doSomething')
->willReturnMap($map);

$this->assertEquals('d', $mock->doSomething('a', 'b', 'c'));
$this->assertEquals('h', $mock->doSomething('e', 'f', 'g'));
$this->assertNull($mock->doSomething('foo', 'bar'));
}

public function testStubbedReturnArgument(): void
{
$mock = $this->getMockBuilder(AnInterface::class)
Expand Down
79 changes: 79 additions & 0 deletions tests/unit/Framework/MockObject/Stub/ReturnValueMapTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use PHPUnit\Framework\TestCase;

/**
* @small
*/
final class ReturnValueMapTest extends TestCase
{
public function testReturnsTheFirstMatchFound(): void
{
$map = [
['a', 'b', 'c', 'd'],
['a', 'b', 'c', 'e'],
['e', 'f', 'g', 'h'],
];
$mock = $this->getMockBuilder(AnInterface::class)
->getMock();
$mock->expects($this->any())
->method('doSomething')
->will($this->returnValueMap($map));
$this->assertEquals('d', $mock->doSomething('a', 'b', 'c'));
}

public function testAcceptsFrameworkMatchers(): void
{
$map = [
[$this->lessThan(2), 1],
[$this->greaterThanOrEqual(2), 2],
];
$mock = $this->getMockBuilder(AnInterface::class)
->getMock();
$mock->expects($this->any())
->method('doSomething')
->will($this->returnValueMap($map));
$this->assertEquals(1, $mock->doSomething(0));
$this->assertEquals(2, $mock->doSomething(100));
}

public function testAcceptsStubForReturnValue(): void
{
$callback = $this->returnCallback(
function ($arg) {
return $arg + 1;
}
);
$map = [
[$this->lessThan(2), 1],
[$this->greaterThanOrEqual(2), $callback],
];
$mock = $this->getMockBuilder(AnInterface::class)
->getMock();
$mock->expects($this->any())
->method('doSomething')
->will($this->returnValueMap($map));
$this->assertEquals(3, $mock->doSomething(2));
}

public function testReturnsNullIfNoMatchFound(): void
{
$map = [
['a', 'b', 'c', 'd'],
];
$mock = $this->getMockBuilder(AnInterface::class)
->getMock();
$mock->expects($this->any())
->method('doSomething')
->will($this->returnValueMap($map));
$this->assertEquals(null, $mock->doSomething('foo', 'bar'));
}
}