Skip to content

Commit 3ad340c

Browse files
Finish partial configuration testing feature, including docs
1 parent b68677c commit 3ad340c

11 files changed

+353
-25
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
- Use a breadcrumb path to test only one particular part of the configuration node tree.
6+
37
## v0.1.1
48

59
- Fixed issue #1: ``ProcessedConfigurationEqualsConstraint`` had expected and actual value mixed up

Partial/PartialNode.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,19 @@ class PartialNode
2020
*/
2121
public static function excludeEverythingNotInBreadcrumbPath(ArrayNode $node, $breadcrumbPath)
2222
{
23-
$breadcrumbPath = explode('.', $breadcrumbPath);
23+
if ($breadcrumbPath === null) {
24+
return;
25+
}
26+
27+
$path = explode('.', $breadcrumbPath);
2428

25-
self::excludeEverythingNotInPath($node, $breadcrumbPath);
29+
self::excludeEverythingNotInPath($node, $path);
2630
}
2731

2832
/**
2933
* @param array $path
3034
*/
31-
public static function excludeEverythingNotInPath(ArrayNode $node, array $path)
35+
public static function excludeEverythingNotInPath(ArrayNode $node, array $path = array())
3236
{
3337
if (empty($path)) {
3438
return;

PhpUnit/AbstractConfigurationConstraint.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,27 @@
22

33
namespace Matthias\SymfonyConfigTest\PhpUnit;
44

5+
use Matthias\SymfonyConfigTest\Partial\PartialProcessor;
56
use SebastianBergmann\Exporter\Exporter;
67
use Symfony\Component\Config\Definition\ConfigurationInterface;
7-
use Symfony\Component\Config\Definition\Processor;
88

99
abstract class AbstractConfigurationConstraint extends \PHPUnit_Framework_Constraint
1010
{
1111
protected $configuration;
12+
protected $breadcrumbPath;
1213

13-
public function __construct(ConfigurationInterface $configuration)
14+
public function __construct(ConfigurationInterface $configuration, $breadcrumbPath = null)
1415
{
1516
$this->configuration = $configuration;
17+
$this->breadcrumbPath = $breadcrumbPath;
1618
$this->exporter = new Exporter();
1719
}
1820

1921
protected function processConfiguration(array $configurationValues)
2022
{
21-
$processor = new Processor();
23+
$processor = new PartialProcessor();
2224

23-
return $processor->processConfiguration($this->configuration, $configurationValues);
25+
return $processor->processConfiguration($this->configuration, $this->breadcrumbPath, $configurationValues);
2426
}
2527

2628
protected function validateConfigurationValuesArray($configurationValues)

PhpUnit/AbstractConfigurationTestCase.php

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,36 +43,75 @@ protected function assertConfigurationIsInvalid(array $configurationValues, $exp
4343
);
4444
}
4545

46+
/**
47+
* Assert that the given configuration values are invalid.
48+
*
49+
* Optionally provide (part of) the exception message that you expect to receive.
50+
*
51+
* When running PHPUnit >=4.3.0, you need to set useRegExp to true if you'd like
52+
* to match the exception message using a regular expression.
53+
*
54+
* @param array $configurationValues
55+
* @param string $breadcrumbPath The path that should be validated, e.g. "doctrine.orm"
56+
* @param string|null $expectedMessage
57+
* @param bool $useRegExp
58+
*/
59+
protected function assertPartialConfigurationIsInvalid(
60+
array $configurationValues,
61+
$breadcrumbPath,
62+
$expectedMessage = null,
63+
$useRegExp = false
64+
) {
65+
self::assertThat(
66+
$configurationValues,
67+
new ConfigurationValuesAreInvalidConstraint(
68+
$this->getConfiguration(),
69+
$expectedMessage,
70+
$useRegExp,
71+
$breadcrumbPath
72+
)
73+
);
74+
}
75+
4676
/**
4777
* Assert that the given configuration values are valid.
4878
*
79+
* Optionally provide the part of the configuration that you want to test, e.g. "doctrine.orm"
80+
*
4981
* @param array $configurationValues
82+
* @param string|null $breadcrumbPath
5083
*/
51-
protected function assertConfigurationIsValid(array $configurationValues)
84+
protected function assertConfigurationIsValid(array $configurationValues, $breadcrumbPath = null)
5285
{
5386
self::assertThat(
5487
$configurationValues,
5588
new ConfigurationValuesAreValidConstraint(
56-
$this->getConfiguration()
89+
$this->getConfiguration(),
90+
$breadcrumbPath
5791
)
5892
);
5993
}
6094

6195
/**
62-
* Assert that the given configuration values, when processed, will equal to the given array
96+
* Assert that the given configuration values, when processed, will equal to the given array.
97+
*
98+
* Optionally provide the part of the configuration that you want to test, e.g. "doctrine.orm"
6399
*
64100
* @param array $configurationValues
65101
* @param array $expectedProcessedConfiguration
102+
* @param string|null $breadcrumbPath
66103
*/
67104
protected function assertProcessedConfigurationEquals(
68105
array $configurationValues,
69-
array $expectedProcessedConfiguration
106+
array $expectedProcessedConfiguration,
107+
$breadcrumbPath = null
70108
) {
71109
self::assertThat(
72110
$expectedProcessedConfiguration,
73111
new ProcessedConfigurationEqualsConstraint(
74112
$this->getConfiguration(),
75-
$configurationValues
113+
$configurationValues,
114+
$breadcrumbPath
76115
)
77116
);
78117
}

PhpUnit/ConfigurationValuesAreInvalidConstraint.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ class ConfigurationValuesAreInvalidConstraint extends AbstractConfigurationConst
1010
private $expectedMessage;
1111
private $useRegExp;
1212

13-
public function __construct(ConfigurationInterface $configuration, $expectedMessage = null, $useRegExp = false)
14-
{
15-
parent::__construct($configuration);
13+
public function __construct(
14+
ConfigurationInterface $configuration,
15+
$expectedMessage = null,
16+
$useRegExp = false,
17+
$breadcrumbPath = null
18+
) {
19+
parent::__construct($configuration, $breadcrumbPath);
1620

1721
$this->expectedMessage = $expectedMessage;
1822
$this->useRegExp = $useRegExp;
@@ -40,7 +44,7 @@ public function toString()
4044
$toString = 'is invalid for the given configuration';
4145

4246
if ($this->expectedMessage !== null) {
43-
$toString .= ' (expected exception message: '.$this->expectedMessage.')';
47+
$toString .= ' (expected exception message: ' . $this->expectedMessage . ')';
4448
}
4549

4650
return $toString;

PhpUnit/ConfigurationValuesAreValidConstraint.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
class ConfigurationValuesAreValidConstraint extends AbstractConfigurationConstraint
99
{
10-
public function __construct(ConfigurationInterface $configuration)
10+
public function __construct(ConfigurationInterface $configuration, $breadcrumbPath = null)
1111
{
12-
parent::__construct($configuration);
12+
parent::__construct($configuration, $breadcrumbPath);
1313
}
1414

1515
public function matches($other)

PhpUnit/ProcessedConfigurationEqualsConstraint.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@ class ProcessedConfigurationEqualsConstraint extends AbstractConfigurationConstr
88
{
99
private $configurationValues;
1010

11-
public function __construct(ConfigurationInterface $configuration, array $configurationValues)
12-
{
11+
public function __construct(
12+
ConfigurationInterface $configuration,
13+
array $configurationValues,
14+
$breadcrumbPath = null
15+
) {
1316
$this->validateConfigurationValuesArray($configurationValues);
1417
$this->configurationValues = $configurationValues;
1518

16-
parent::__construct($configuration);
19+
parent::__construct($configuration, $breadcrumbPath);
1720
}
1821

1922
public function evaluate($other, $description = '', $returnResult = false)

README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class ConfigurationTest extends AbstractConfigurationTestCase
5252
}
5353
```
5454

55+
### Test invalid configuration values
56+
5557
Let's assume the ``Configuration`` class you want to test looks like this:
5658

5759
```php
@@ -103,6 +105,8 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
103105
}
104106
```
105107

108+
### Test processed configuration values
109+
106110
You may also want to verify that after processing an array of configuration values the result will be as expected:
107111

108112
```php
@@ -128,3 +132,74 @@ Please note: the first argument of each of the ``assert*`` methods is an *array
128132
allows you to test the merge process. See also the section [Merging
129133
options](http://symfony.com/doc/current/components/config/definition.html#merging-options) of the Config Component
130134
documentation.
135+
136+
### Test a subset of the configuration tree
137+
138+
Using this library it's possible to test just one branch of your configuration tree. Consider the following node tree
139+
definition, which contains the branches `array_node_1` and `array_node_2`:
140+
141+
```php
142+
<?php
143+
144+
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
145+
use Symfony\Component\Config\Definition\ConfigurationInterface;
146+
147+
class ConfigurationWithTwoBranches implements ConfigurationInterface
148+
{
149+
public function getConfigTreeBuilder()
150+
{
151+
$treeBuilder = new TreeBuilder();
152+
153+
$rootNode = $treeBuilder->root('root');
154+
$rootNode
155+
->children()
156+
->arrayNode('array_node_1')
157+
->isRequired()
158+
->children()
159+
->scalarNode('required_value_1')
160+
->isRequired()
161+
->end()
162+
->end()
163+
->end()
164+
->arrayNode('array_node_2')
165+
->isRequired()
166+
->children()
167+
->scalarNode('required_value_2')
168+
->isRequired()
169+
->end()
170+
->end()
171+
->end()
172+
->end();
173+
174+
return $treeBuilder;
175+
}
176+
}
177+
```
178+
179+
If you want to test, for instance, only the `array_node_1` branch from the example below, and ignore the `array_node_2`,
180+
provide `array_node_1` as the argument for the `$breadcrumbPath` parameter of the test helper functions, for example:
181+
182+
```php
183+
/**
184+
* @test
185+
*/
186+
public function processed_configuration_for_array_node_1()
187+
{
188+
$this->assertProcessedConfigurationEquals(
189+
array(
190+
array('array_node_1' => array('required_value_1' => 'original value'),
191+
array('array_node_1' => array('required_value_1' => 'final value')
192+
),
193+
array(
194+
'array_node_1' => array(
195+
'required_value_1' => 'final value'
196+
)
197+
)
198+
);
199+
}
200+
```
201+
202+
This would trigger no validation errors for any value in the `array_node_2` branch.
203+
204+
Note that the `$breadcrumbPath` can be even more specific, e.g. `"doctrine.orm"` (which would skip configuration
205+
processing for branch `"doctrine.dbal"`).

Tests/Partial/PartialNodeTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public function it_strips_children_that_are_not_in_the_given_path_with_one_name(
3030
$node = $treeBuilder->buildTree();
3131
/** @var ArrayNode $node */
3232

33-
PartialNode::excludeEverythingNotInPath($node, ['node_2']);
33+
PartialNode::excludeEverythingNotInPath($node, array('node_2'));
3434

3535
$this->nodeOnlyHasChild($node, 'node_2');
3636
}
@@ -67,7 +67,7 @@ public function it_strips_children_that_are_not_in_the_given_path_with_several_n
6767
$node = $treeBuilder->buildTree();
6868
/** @var ArrayNode $node */
6969

70-
PartialNode::excludeEverythingNotInPath($node, ['node_1', 'node_1_b']);
70+
PartialNode::excludeEverythingNotInPath($node, array('node_1', 'node_1_b'));
7171

7272
$node1 = $this->nodeOnlyHasChild($node, 'node_1');
7373
$this->nodeOnlyHasChild($node1, 'node_1_b');
@@ -92,7 +92,7 @@ public function it_fails_when_a_requested_child_node_does_not_exist()
9292
'Matthias\SymfonyConfigTest\Partial\Exception\UndefinedChildNode',
9393
'Undefined child node "non_existing_node" (the part of the path that was successful: "root.sub_node")'
9494
);
95-
PartialNode::excludeEverythingNotInPath($node, ['sub_node', 'non_existing_node']);
95+
PartialNode::excludeEverythingNotInPath($node, array('sub_node', 'non_existing_node'));
9696
}
9797

9898
/**
@@ -114,7 +114,7 @@ public function it_fails_when_a_requested_child_node_is_no_array_node_itself()
114114
'Matthias\SymfonyConfigTest\Partial\Exception\ChildIsNotAnArrayNode',
115115
'Child node "scalar_node" is not an array node (current path: "root.sub_node")'
116116
);
117-
PartialNode::excludeEverythingNotInPath($node, ['sub_node', 'scalar_node']);
117+
PartialNode::excludeEverythingNotInPath($node, array('sub_node', 'scalar_node'));
118118
}
119119

120120
private function nodeOnlyHasChild(ArrayNode $node, $nodeName)
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\Tests\PhpUnit\Fixtures;
4+
5+
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
6+
use Symfony\Component\Config\Definition\ConfigurationInterface;
7+
8+
class ConfigurationWithMultipleArrayKeys implements ConfigurationInterface
9+
{
10+
public function getConfigTreeBuilder()
11+
{
12+
$treeBuilder = new TreeBuilder();
13+
$rootNode = $treeBuilder->root('root');
14+
$rootNode
15+
->children()
16+
->arrayNode('array_node_1')
17+
->isRequired()
18+
->children()
19+
->scalarNode('required_value_1')
20+
->isRequired()
21+
->end()
22+
->end()
23+
->end()
24+
->arrayNode('array_node_2')
25+
->isRequired()
26+
->children()
27+
->scalarNode('required_value_2')
28+
->isRequired()
29+
->end()
30+
->end()
31+
->end()
32+
->end();
33+
34+
return $treeBuilder;
35+
}
36+
}

0 commit comments

Comments
 (0)