Skip to content

Commit 7a10a24

Browse files
Initial commit
0 parents  commit 7a10a24

15 files changed

+621
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
composer.lock
2+
phpunit.xml
3+
vendor

.travis.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
language: php
2+
3+
php:
4+
- 5.3
5+
- 5.4
6+
7+
before_script: composer install --dev
8+
9+
notifications:
10+

LICENSE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2013 Matthias Noback
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Matthias\SymfonyConfigTest\PhpUnit;
4+
5+
use Symfony\Component\Config\Definition\ConfigurationInterface;
6+
use Symfony\Component\Config\Definition\Processor;
7+
8+
abstract class AbstractConfigurationConstraint extends \PHPUnit_Framework_Constraint
9+
{
10+
protected $configuration;
11+
12+
public function __construct(ConfigurationInterface $configuration)
13+
{
14+
$this->configuration = $configuration;
15+
}
16+
17+
protected function processConfiguration(array $configurationValues)
18+
{
19+
$processor = new Processor();
20+
21+
return $processor->processConfiguration($this->configuration, $configurationValues);
22+
}
23+
24+
protected function validateConfigurationValuesArray($configurationValues)
25+
{
26+
if (!is_array($configurationValues)) {
27+
throw new \InvalidArgumentException('Configuration values should be an array');
28+
}
29+
30+
foreach ($configurationValues as $values) {
31+
if (!is_array($values)) {
32+
throw new \InvalidArgumentException('Configuration values should be an array of arrays');
33+
}
34+
}
35+
}
36+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace Matthias\SymfonyConfigTest\PhpUnit;
4+
5+
/**
6+
* Extend your test case from this abstract class to test a class that implements
7+
* Symfony\Component\Config\Definition\ConfigurationInterface
8+
*/
9+
abstract class AbstractConfigurationTestCase extends \PHPUnit_Framework_TestCase
10+
{
11+
/**
12+
* Return the instance of ConfigurationInterface that should be used by the
13+
* Configuration-specific assertions in this test-case
14+
*
15+
* @return \Symfony\Component\Config\Definition\ConfigurationInterface
16+
*/
17+
abstract protected function getConfiguration();
18+
19+
/**
20+
* Assert that the given configuration values are invalid.
21+
*
22+
* Optionally provide (part of) the exception message that you expect to receive.
23+
*
24+
* @param array $configurationValues
25+
* @param string|null $expectedMessage
26+
*/
27+
protected function assertConfigurationIsInvalid(array $configurationValues, $expectedMessage = null)
28+
{
29+
self::assertThat(
30+
$configurationValues,
31+
new ConfigurationValuesAreInvalidConstraint(
32+
$this->getConfiguration(),
33+
$expectedMessage
34+
)
35+
);
36+
}
37+
38+
/**
39+
* Assert that the given configuration values, when processed, will equal to the given array
40+
*
41+
* @param array $configurationValues
42+
* @param array $expectedProcessedConfiguration
43+
*/
44+
protected function assertProcessedConfigurationEquals(
45+
array $configurationValues,
46+
array $expectedProcessedConfiguration
47+
) {
48+
self::assertThat(
49+
$expectedProcessedConfiguration,
50+
new ProcessedConfigurationEqualsConstraint(
51+
$this->getConfiguration(),
52+
$configurationValues
53+
)
54+
);
55+
}
56+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace Matthias\SymfonyConfigTest\PhpUnit;
4+
5+
use Symfony\Component\Config\Definition\ConfigurationInterface;
6+
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
7+
8+
class ConfigurationValuesAreInvalidConstraint extends AbstractConfigurationConstraint
9+
{
10+
private $expectedMessage;
11+
12+
public function __construct(ConfigurationInterface $configuration, $expectedMessage = null)
13+
{
14+
parent::__construct($configuration);
15+
16+
$this->expectedMessage = $expectedMessage;
17+
}
18+
19+
public function evaluate($other, $description = '', $returnResult = false)
20+
{
21+
$this->validateConfigurationValuesArray($other);
22+
23+
try {
24+
$this->processConfiguration($other);
25+
} catch (InvalidConfigurationException $exception) {
26+
return $this->evaluateException($exception, $description, $returnResult);
27+
}
28+
29+
if ($returnResult) {
30+
return false;
31+
}
32+
33+
$this->fail($other, $description);
34+
}
35+
36+
public function toString()
37+
{
38+
$toString = 'is invalid for the given configuration';
39+
40+
if ($this->expectedMessage !== null) {
41+
$toString .= ' (expected exception message: '.$this->expectedMessage.')';
42+
}
43+
44+
return $toString;
45+
}
46+
47+
private function evaluateException(\Exception $exception, $description, $returnResult)
48+
{
49+
if ($this->expectedMessage === null) {
50+
return true;
51+
}
52+
53+
// reuse the exception message constraint from PHPUnit itself
54+
$constraint = new \PHPUnit_Framework_Constraint_ExceptionMessage($this->expectedMessage);
55+
56+
return $constraint->evaluate($exception, $description, $returnResult);
57+
}
58+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace Matthias\SymfonyConfigTest\PhpUnit;
4+
5+
use Symfony\Component\Config\Definition\ConfigurationInterface;
6+
7+
class ProcessedConfigurationEqualsConstraint extends AbstractConfigurationConstraint
8+
{
9+
private $configurationValues;
10+
11+
public function __construct(ConfigurationInterface $configuration, array $configurationValues)
12+
{
13+
$this->validateConfigurationValuesArray($configurationValues);
14+
$this->configurationValues = $configurationValues;
15+
16+
parent::__construct($configuration);
17+
}
18+
19+
public function evaluate($other, $description = '', $returnResult = false)
20+
{
21+
$processedConfiguration = $this->processConfiguration($this->configurationValues);
22+
23+
$constraint = new \PHPUnit_Framework_Constraint_IsEqual($processedConfiguration);
24+
25+
return $constraint->evaluate($other, '', $returnResult);
26+
}
27+
28+
public function toString()
29+
{
30+
// won't be used, this constraint only wraps \PHPUnit_Framework_Constraint_IsEqual
31+
}
32+
}

README.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# SymfonyConfigTest
2+
3+
*By Matthias Noback*
4+
5+
Writing configuration classes using the [Symfony Config
6+
Component](http://symfony.com/doc/current/components/config/definition.html) can be quite hard. To help you verify the
7+
validity of the resulting config node tree, this library provides a PHPUnit test case and some custom assertions.
8+
9+
## Installation
10+
11+
Using Composer:
12+
13+
php composer.phar require matthiasnoback/symfony-config-test 0.*
14+
15+
## Usage
16+
17+
Create a test case and extend from ``Matthias\SymfonyConfigTest\PhpUnit\AbstractConfigurationTestCase``. Then implement
18+
``getConfiguration()``:
19+
20+
<?php
21+
22+
class ConfigurationTest extends AbstractConfigurationTestCase
23+
{
24+
protected function getConfiguration()
25+
{
26+
return new Configuration();
27+
}
28+
}
29+
30+
Let's assume the ``Configuration`` class you want to test looks like this:
31+
32+
<?php
33+
34+
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
35+
use Symfony\Component\Config\Definition\ConfigurationInterface;
36+
37+
class ConfigurationWithRequiredValue implements ConfigurationInterface
38+
{
39+
public function getConfigTreeBuilder()
40+
{
41+
$treeBuilder = new TreeBuilder();
42+
43+
$rootNode = $treeBuilder->root('root');
44+
$rootNode
45+
->isRequired()
46+
->children()
47+
->scalarNode('required_value')
48+
->isRequired()
49+
->end()
50+
->end();
51+
52+
return $treeBuilder;
53+
}
54+
}
55+
56+
When you provide an empty array as the values for this configuration, you would expect an exception since the
57+
``required_value`` node is required. You can assert that a given set of configuration values is invalid using the
58+
``assertConfigurationIsInvalid()`` method:
59+
60+
<?php
61+
62+
class ConfigurationTest extends AbstractConfigurationTestCase
63+
{
64+
public function testValuesAreInvalidIfRequiredValueIsNotProvided()
65+
{
66+
$this->assertConfigurationIsInvalid(
67+
array(
68+
array() // no values at all
69+
),
70+
'required_value' // (part of) the expected exception message - optional
71+
);
72+
}
73+
}
74+
75+
You may also want to verify that after processing an array of configuration values the result will be as expected:
76+
77+
<?php
78+
79+
class ConfigurationTest extends AbstractConfigurationTestCase
80+
{
81+
public function testProcessedValueContainsRequiredValue()
82+
{
83+
$this->assertProcessedConfigurationEquals(array(
84+
array('required_value' => 'first value'),
85+
array('required_value' => 'last value')
86+
), array(
87+
'required_value'=> 'last value'
88+
));
89+
}
90+
}
91+
92+
Please note: the first argument of each of the ``assert*`` methods is an *array of arrays*. The extra nesting level
93+
allows you to test the merge process. See also the section [Merging
94+
options](http://symfony.com/doc/current/components/config/definition.html#merging-options) of the Config Component
95+
documentation.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace Matthias\SymfonyConfigTest\Tests;
4+
5+
use Matthias\SymfonyConfigTest\PhpUnit\AbstractConfigurationTestCase;
6+
use Matthias\SymfonyConfigTest\Tests\PhpUnit\Fixtures\ConfigurationWithRequiredValue;
7+
8+
class AbstractConfigurationTestCaseTest extends AbstractConfigurationTestCase
9+
{
10+
protected function getConfiguration()
11+
{
12+
return new ConfigurationWithRequiredValue();
13+
}
14+
15+
/**
16+
* @test
17+
*/
18+
public function it_can_assert_that_a_configuration_is_invalid()
19+
{
20+
$this->assertConfigurationIsInvalid(array(
21+
array() // no configuration values
22+
), 'required_value');
23+
}
24+
25+
/**
26+
* @test
27+
*/
28+
public function it_fails_when_a_configuration_is_valid_when_it_should_have_been_invalid()
29+
{
30+
$this->setExpectedException('\PHPUnit_Framework_ExpectationFailedException', 'invalid');
31+
32+
$this->assertConfigurationIsInvalid(array(
33+
array('required_value' => 'some value')
34+
));
35+
}
36+
37+
/**
38+
* @test
39+
*/
40+
public function it_can_assert_that_a_processed_configuration_matches_the_expected_array_of_values()
41+
{
42+
$value = 'some value';
43+
44+
$this->assertProcessedConfigurationEquals(array(
45+
array(),
46+
array('required_value' => $value)
47+
), array(
48+
'required_value'=> $value
49+
));
50+
}
51+
52+
/**
53+
* @test
54+
*/
55+
public function it_fails_when_a_processed_configuration_does_not_match_the_expected_array_of_values()
56+
{
57+
$value = 'some value';
58+
59+
$this->setExpectedException('\PHPUnit_Framework_ExpectationFailedException', 'equal');
60+
$this->assertProcessedConfigurationEquals(array(
61+
array('required_value' => $value)
62+
), array(
63+
'invalid_key'=> 'invalid_value'
64+
));
65+
}
66+
}

0 commit comments

Comments
 (0)