PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php

http://github.com/fabpot/symfony
PHP | 357 lines | 270 code | 52 blank | 35 comment | 2 complexity | dc8ba879099b5e02ed235cf489127c70 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Config\Tests\Definition;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
  13. use Symfony\Component\Config\Definition\ArrayNode;
  14. use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
  15. use Symfony\Component\Config\Definition\ScalarNode;
  16. class ArrayNodeTest extends TestCase
  17. {
  18. use ExpectDeprecationTrait;
  19. public function testNormalizeThrowsExceptionWhenFalseIsNotAllowed()
  20. {
  21. $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidTypeException');
  22. $node = new ArrayNode('root');
  23. $node->normalize(false);
  24. }
  25. public function testExceptionThrownOnUnrecognizedChild()
  26. {
  27. $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException');
  28. $this->expectExceptionMessage('Unrecognized option "foo" under "root"');
  29. $node = new ArrayNode('root');
  30. $node->normalize(['foo' => 'bar']);
  31. }
  32. public function testNormalizeWithProposals()
  33. {
  34. $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException');
  35. $this->expectExceptionMessage('Did you mean "alpha1", "alpha2"?');
  36. $node = new ArrayNode('root');
  37. $node->addChild(new ArrayNode('alpha1'));
  38. $node->addChild(new ArrayNode('alpha2'));
  39. $node->addChild(new ArrayNode('beta'));
  40. $node->normalize(['alpha3' => 'foo']);
  41. }
  42. public function testNormalizeWithoutProposals()
  43. {
  44. $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException');
  45. $this->expectExceptionMessage('Available options are "alpha1", "alpha2".');
  46. $node = new ArrayNode('root');
  47. $node->addChild(new ArrayNode('alpha1'));
  48. $node->addChild(new ArrayNode('alpha2'));
  49. $node->normalize(['beta' => 'foo']);
  50. }
  51. public function ignoreAndRemoveMatrixProvider()
  52. {
  53. $unrecognizedOptionException = new InvalidConfigurationException('Unrecognized option "foo" under "root"');
  54. return [
  55. [true, true, [], 'no exception is thrown for an unrecognized child if the ignoreExtraKeys option is set to true'],
  56. [true, false, ['foo' => 'bar'], 'extra keys are not removed when ignoreExtraKeys second option is set to false'],
  57. [false, true, $unrecognizedOptionException],
  58. [false, false, $unrecognizedOptionException],
  59. ];
  60. }
  61. /**
  62. * @dataProvider ignoreAndRemoveMatrixProvider
  63. */
  64. public function testIgnoreAndRemoveBehaviors($ignore, $remove, $expected, $message = '')
  65. {
  66. if ($expected instanceof \Exception) {
  67. $this->expectException(\get_class($expected));
  68. $this->expectExceptionMessage($expected->getMessage());
  69. }
  70. $node = new ArrayNode('root');
  71. $node->setIgnoreExtraKeys($ignore, $remove);
  72. $result = $node->normalize(['foo' => 'bar']);
  73. $this->assertSame($expected, $result, $message);
  74. }
  75. /**
  76. * @dataProvider getPreNormalizationTests
  77. */
  78. public function testPreNormalize($denormalized, $normalized)
  79. {
  80. $node = new ArrayNode('foo');
  81. $r = new \ReflectionMethod($node, 'preNormalize');
  82. $r->setAccessible(true);
  83. $this->assertSame($normalized, $r->invoke($node, $denormalized));
  84. }
  85. public function getPreNormalizationTests()
  86. {
  87. return [
  88. [
  89. ['foo-bar' => 'foo'],
  90. ['foo_bar' => 'foo'],
  91. ],
  92. [
  93. ['foo-bar_moo' => 'foo'],
  94. ['foo-bar_moo' => 'foo'],
  95. ],
  96. [
  97. ['anything-with-dash-and-no-underscore' => 'first', 'no_dash' => 'second'],
  98. ['anything_with_dash_and_no_underscore' => 'first', 'no_dash' => 'second'],
  99. ],
  100. [
  101. ['foo-bar' => null, 'foo_bar' => 'foo'],
  102. ['foo-bar' => null, 'foo_bar' => 'foo'],
  103. ],
  104. ];
  105. }
  106. /**
  107. * @dataProvider getZeroNamedNodeExamplesData
  108. */
  109. public function testNodeNameCanBeZero($denormalized, $normalized)
  110. {
  111. $zeroNode = new ArrayNode(0);
  112. $zeroNode->addChild(new ScalarNode('name'));
  113. $fiveNode = new ArrayNode(5);
  114. $fiveNode->addChild(new ScalarNode(0));
  115. $fiveNode->addChild(new ScalarNode('new_key'));
  116. $rootNode = new ArrayNode('root');
  117. $rootNode->addChild($zeroNode);
  118. $rootNode->addChild($fiveNode);
  119. $rootNode->addChild(new ScalarNode('string_key'));
  120. $r = new \ReflectionMethod($rootNode, 'normalizeValue');
  121. $r->setAccessible(true);
  122. $this->assertSame($normalized, $r->invoke($rootNode, $denormalized));
  123. }
  124. public function getZeroNamedNodeExamplesData()
  125. {
  126. return [
  127. [
  128. [
  129. 0 => [
  130. 'name' => 'something',
  131. ],
  132. 5 => [
  133. 0 => 'this won\'t work too',
  134. 'new_key' => 'some other value',
  135. ],
  136. 'string_key' => 'just value',
  137. ],
  138. [
  139. 0 => [
  140. 'name' => 'something',
  141. ],
  142. 5 => [
  143. 0 => 'this won\'t work too',
  144. 'new_key' => 'some other value',
  145. ],
  146. 'string_key' => 'just value',
  147. ],
  148. ],
  149. ];
  150. }
  151. /**
  152. * @dataProvider getPreNormalizedNormalizedOrderedData
  153. */
  154. public function testChildrenOrderIsMaintainedOnNormalizeValue($prenormalized, $normalized)
  155. {
  156. $scalar1 = new ScalarNode('1');
  157. $scalar2 = new ScalarNode('2');
  158. $scalar3 = new ScalarNode('3');
  159. $node = new ArrayNode('foo');
  160. $node->addChild($scalar1);
  161. $node->addChild($scalar3);
  162. $node->addChild($scalar2);
  163. $r = new \ReflectionMethod($node, 'normalizeValue');
  164. $r->setAccessible(true);
  165. $this->assertSame($normalized, $r->invoke($node, $prenormalized));
  166. }
  167. public function getPreNormalizedNormalizedOrderedData()
  168. {
  169. return [
  170. [
  171. ['2' => 'two', '1' => 'one', '3' => 'three'],
  172. ['2' => 'two', '1' => 'one', '3' => 'three'],
  173. ],
  174. ];
  175. }
  176. public function testAddChildEmptyName()
  177. {
  178. $this->expectException('InvalidArgumentException');
  179. $this->expectExceptionMessage('Child nodes must be named.');
  180. $node = new ArrayNode('root');
  181. $childNode = new ArrayNode('');
  182. $node->addChild($childNode);
  183. }
  184. public function testAddChildNameAlreadyExists()
  185. {
  186. $this->expectException('InvalidArgumentException');
  187. $this->expectExceptionMessage('A child node named "foo" already exists.');
  188. $node = new ArrayNode('root');
  189. $childNode = new ArrayNode('foo');
  190. $node->addChild($childNode);
  191. $childNodeWithSameName = new ArrayNode('foo');
  192. $node->addChild($childNodeWithSameName);
  193. }
  194. public function testGetDefaultValueWithoutDefaultValue()
  195. {
  196. $this->expectException('RuntimeException');
  197. $this->expectExceptionMessage('The node at path "foo" has no default value.');
  198. $node = new ArrayNode('foo');
  199. $node->getDefaultValue();
  200. }
  201. public function testSetDeprecated()
  202. {
  203. $childNode = new ArrayNode('foo');
  204. $childNode->setDeprecated('vendor/package', '1.1', '"%node%" is deprecated');
  205. $this->assertTrue($childNode->isDeprecated());
  206. $deprecation = $childNode->getDeprecation($childNode->getName(), $childNode->getPath());
  207. $this->assertSame('"foo" is deprecated', $deprecation['message']);
  208. $this->assertSame('vendor/package', $deprecation['package']);
  209. $this->assertSame('1.1', $deprecation['version']);
  210. $node = new ArrayNode('root');
  211. $node->addChild($childNode);
  212. $deprecationTriggered = false;
  213. $deprecationHandler = function ($level, $message, $file, $line) use (&$prevErrorHandler, &$deprecationTriggered) {
  214. if (E_USER_DEPRECATED === $level) {
  215. return $deprecationTriggered = true;
  216. }
  217. return $prevErrorHandler ? $prevErrorHandler($level, $message, $file, $line) : false;
  218. };
  219. $prevErrorHandler = set_error_handler($deprecationHandler);
  220. $node->finalize([]);
  221. restore_error_handler();
  222. $this->assertFalse($deprecationTriggered, '->finalize() should not trigger if the deprecated node is not set');
  223. $prevErrorHandler = set_error_handler($deprecationHandler);
  224. $node->finalize(['foo' => []]);
  225. restore_error_handler();
  226. $this->assertTrue($deprecationTriggered, '->finalize() should trigger if the deprecated node is set');
  227. }
  228. /**
  229. * @group legacy
  230. */
  231. public function testUnDeprecateANode()
  232. {
  233. $this->expectDeprecation('Since symfony/config 5.1: The signature of method "Symfony\Component\Config\Definition\BaseNode::setDeprecated()" requires 3 arguments: "string $package, string $version, string $message", not defining them is deprecated.');
  234. $this->expectDeprecation('Since symfony/config 5.1: Passing a null message to un-deprecate a node is deprecated.');
  235. $node = new ArrayNode('foo');
  236. $node->setDeprecated('"%node%" is deprecated');
  237. $node->setDeprecated(null);
  238. $this->assertFalse($node->isDeprecated());
  239. }
  240. /**
  241. * @group legacy
  242. */
  243. public function testSetDeprecatedWithoutPackageAndVersion()
  244. {
  245. $this->expectDeprecation('Since symfony/config 5.1: The signature of method "Symfony\Component\Config\Definition\BaseNode::setDeprecated()" requires 3 arguments: "string $package, string $version, string $message", not defining them is deprecated.');
  246. $node = new ArrayNode('foo');
  247. $node->setDeprecated('"%node%" is deprecated');
  248. $deprecation = $node->getDeprecation($node->getName(), $node->getPath());
  249. $this->assertSame('"foo" is deprecated', $deprecation['message']);
  250. $this->assertSame('', $deprecation['package']);
  251. $this->assertSame('', $deprecation['version']);
  252. }
  253. /**
  254. * @dataProvider getDataWithIncludedExtraKeys
  255. */
  256. public function testMergeWithoutIgnoringExtraKeys($prenormalizeds, $merged)
  257. {
  258. $this->expectException('RuntimeException');
  259. $this->expectExceptionMessage('merge() expects a normalized config array.');
  260. $node = new ArrayNode('root');
  261. $node->addChild(new ScalarNode('foo'));
  262. $node->addChild(new ScalarNode('bar'));
  263. $node->setIgnoreExtraKeys(false);
  264. $r = new \ReflectionMethod($node, 'mergeValues');
  265. $r->setAccessible(true);
  266. $r->invoke($node, ...$prenormalizeds);
  267. }
  268. /**
  269. * @dataProvider getDataWithIncludedExtraKeys
  270. */
  271. public function testMergeWithIgnoringAndRemovingExtraKeys($prenormalizeds, $merged)
  272. {
  273. $this->expectException('RuntimeException');
  274. $this->expectExceptionMessage('merge() expects a normalized config array.');
  275. $node = new ArrayNode('root');
  276. $node->addChild(new ScalarNode('foo'));
  277. $node->addChild(new ScalarNode('bar'));
  278. $node->setIgnoreExtraKeys(true);
  279. $r = new \ReflectionMethod($node, 'mergeValues');
  280. $r->setAccessible(true);
  281. $r->invoke($node, ...$prenormalizeds);
  282. }
  283. /**
  284. * @dataProvider getDataWithIncludedExtraKeys
  285. */
  286. public function testMergeWithIgnoringExtraKeys($prenormalizeds, $merged)
  287. {
  288. $node = new ArrayNode('root');
  289. $node->addChild(new ScalarNode('foo'));
  290. $node->addChild(new ScalarNode('bar'));
  291. $node->setIgnoreExtraKeys(true, false);
  292. $r = new \ReflectionMethod($node, 'mergeValues');
  293. $r->setAccessible(true);
  294. $this->assertEquals($merged, $r->invoke($node, ...$prenormalizeds));
  295. }
  296. public function getDataWithIncludedExtraKeys()
  297. {
  298. return [
  299. [
  300. [['foo' => 'bar', 'baz' => 'not foo'], ['bar' => 'baz', 'baz' => 'foo']],
  301. ['foo' => 'bar', 'bar' => 'baz', 'baz' => 'foo'],
  302. ],
  303. ];
  304. }
  305. }