Skip to content

Commit

Permalink
Support for named arguments (#79)
Browse files Browse the repository at this point in the history
* Support for named arguments

Since 3.3, Symfony supports named arguments. Therefore casting the argumentIndex to an integer does not support all cases anymore.

* Better wording for named arguments.

* Throws an exception, if the argument is a named but the empty string

* test fixed
  • Loading branch information
rejinka authored and Nyholm committed Nov 30, 2017
1 parent 86f757d commit f582683
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 13 deletions.
61 changes: 48 additions & 13 deletions PhpUnit/DefinitionHasArgumentConstraint.php
Expand Up @@ -9,6 +9,10 @@

class DefinitionHasArgumentConstraint extends Constraint
{

/**
* @var int|string
*/
private $argumentIndex;
private $expectedValue;
private $checkExpectedValue;
Expand All @@ -17,13 +21,36 @@ public function __construct($argumentIndex, $expectedValue, $checkExpectedValue
{
parent::__construct();

$this->argumentIndex = (integer)$argumentIndex;
if (!(is_string($argumentIndex) || (is_int($argumentIndex) && $argumentIndex >= 0))) {
throw new \InvalidArgumentException('Expected either a string or a positive integer for $argumentIndex.');
}

if (is_string($argumentIndex)) {
if ('' === $argumentIndex) {
throw new \InvalidArgumentException('A named argument must begin with a "$".');
}

if ('$' !== $argumentIndex[0]) {
throw new \InvalidArgumentException(
sprintf('Unknown argument "%s". Did you mean "$%s"?', $argumentIndex, $argumentIndex)
);
}
}

$this->argumentIndex = $argumentIndex;
$this->expectedValue = $expectedValue;
$this->checkExpectedValue = $checkExpectedValue;
}

public function toString()
{
if (is_string($this->argumentIndex)) {
return sprintf(
'has an argument named "%s" with the given value',
$this->argumentIndex
);
}

return sprintf(
'has an argument with index %d with the given value',
$this->argumentIndex
Expand Down Expand Up @@ -65,13 +92,13 @@ private function evaluateArgumentIndex(Definition $definition, $returnResult)
return false;
}

$this->fail(
$definition,
sprintf(
'The definition has no argument with index %d',
$this->argumentIndex
)
);
if (is_string($this->argumentIndex)) {
$message = sprintf('The definition has no argument named "%s"', $this->argumentIndex);
} else {
$message = sprintf('The definition has no argument with index %d', $this->argumentIndex);
}

$this->fail($definition, $message);
}

return true;
Expand All @@ -88,15 +115,23 @@ private function evaluateArgumentValue(Definition $definition, $returnResult)
return false;
}

$this->fail(
$definition,
sprintf(
if (is_string($this->argumentIndex)) {
$message = sprintf(
'The value of argument named "%s" (%s) is not equal to the expected value (%s)',
$this->argumentIndex,
$this->exporter->export($actualValue),
$this->exporter->export($this->expectedValue)
);
} else {
$message = sprintf(
'The value of argument with index %d (%s) is not equal to the expected value (%s)',
$this->argumentIndex,
$this->exporter->export($actualValue),
$this->exporter->export($this->expectedValue)
)
);
);
}

$this->fail($definition, $message);
}

return true;
Expand Down
131 changes: 131 additions & 0 deletions Tests/PhpUnit/DefinitionHasArgumentConstraintTest.php
Expand Up @@ -3,7 +3,9 @@
namespace Matthias\SymfonyDependencyInjectionTest\Tests\PhpUnit\DependencyInjection;

use Matthias\SymfonyDependencyInjectionTest\PhpUnit\DefinitionHasArgumentConstraint;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\TestCase;
use stdClass;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;

Expand Down Expand Up @@ -45,4 +47,133 @@ public function definitionProvider()
array($decoratedDefinitionWithArguments, 1, $rightValue, true),
);
}

/**
* @test
* @dataProvider invalid_definition_indexes
*
* @param mixed $argument
* @param string $exceptionMessage
*/
public function validates_definitionIndex($argument, $exceptionMessage)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage($exceptionMessage);

new DefinitionHasArgumentConstraint($argument, 0);
}

/**
* @return \Generator
*/
public function invalid_definition_indexes()
{
yield [
new stdClass(), 'Expected either a string or a positive integer for $argumentIndex.'
];

yield [
1.0, 'Expected either a string or a positive integer for $argumentIndex.'
];

yield [
'1', 'Unknown argument "1". Did you mean "$1"?',
];

yield [
'a', 'Unknown argument "a". Did you mean "$a"?',
];

yield [
'', 'A named argument must begin with a "$".'
];
}

/**
* @test
* @dataProvider indexed_arguments
* @param int $argumentIndex
*/
public function supports_indexed_arguments($argumentIndex)
{
$expectedValue = 'bar';

$constraint = new DefinitionHasArgumentConstraint($argumentIndex, $expectedValue);
$definition = new Definition(stdClass::class, array_fill(0, $argumentIndex + 1, $expectedValue));

self::assertTrue($constraint->evaluate($definition));
self::assertSame("has an argument with index $argumentIndex with the given value", $constraint->toString());

$failingExpectation = $expectedValue . $expectedValue;
$constraint = new DefinitionHasArgumentConstraint($argumentIndex, $failingExpectation);

try {
$constraint->evaluate($definition);
$this->fail('The expression above should throw an exception.');
} catch (ExpectationFailedException $e) {
self::assertStringStartsWith(
sprintf(
'The value of argument with index %d (\'%s\') is not equal to the expected value (\'%s\')',
$argumentIndex, $expectedValue, $failingExpectation
),
$e->getMessage()
);
}
}

/**
* @return \Generator
*/
public function indexed_arguments()
{
// yield [0];
yield [1];
yield [2];
yield [3];
}

/**
* @test
* @dataProvider named_arguments
* @param string $argument
*/
public function supports_named_arguments($argument)
{
$expectedValue = 'bar';

$constraint = new DefinitionHasArgumentConstraint($argument, $expectedValue);
$definition = new Definition(stdClass::class, [
$argument => $expectedValue,
]);

self::assertTrue($constraint->evaluate($definition));
self::assertSame(sprintf('has an argument named "%s" with the given value', $argument), $constraint->toString());

$failingExpectation = $expectedValue . $expectedValue;
$constraint = new DefinitionHasArgumentConstraint($argument, $failingExpectation);

try {
$constraint->evaluate($definition);
$this->fail('The expression above should throw an exception.');
} catch (ExpectationFailedException $e) {
self::assertStringStartsWith(
sprintf(
'The value of argument named "%s" (\'%s\') is not equal to the expected value (\'%s\')',
$argument, $expectedValue, $failingExpectation
),
$e->getMessage()
);
}
}

/**
* @return \Generator
*/
public function named_arguments()
{
yield ['$foo'];
yield ['$bar'];
yield ['$a'];
}

}

0 comments on commit f582683

Please sign in to comment.