ArrayNodeTest.php 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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\Component\Config\Definition\ArrayNode;
  13. use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
  14. use Symfony\Component\Config\Definition\ScalarNode;
  15. class ArrayNodeTest extends TestCase
  16. {
  17. /**
  18. * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidTypeException
  19. */
  20. public function testNormalizeThrowsExceptionWhenFalseIsNotAllowed()
  21. {
  22. $node = new ArrayNode('root');
  23. $node->normalize(false);
  24. }
  25. /**
  26. * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
  27. * @expectedExceptionMessage Unrecognized option "foo" under "root"
  28. */
  29. public function testExceptionThrownOnUnrecognizedChild()
  30. {
  31. $node = new ArrayNode('root');
  32. $node->normalize(['foo' => 'bar']);
  33. }
  34. /**
  35. * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
  36. * @expectedExceptionMessage Did you mean "alpha1", "alpha2"?
  37. */
  38. public function testNormalizeWithProposals()
  39. {
  40. $node = new ArrayNode('root');
  41. $node->addChild(new ArrayNode('alpha1'));
  42. $node->addChild(new ArrayNode('alpha2'));
  43. $node->addChild(new ArrayNode('beta'));
  44. $node->normalize(['alpha3' => 'foo']);
  45. }
  46. /**
  47. * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
  48. * @expectedExceptionMessage Available options are "alpha1", "alpha2".
  49. */
  50. public function testNormalizeWithoutProposals()
  51. {
  52. $node = new ArrayNode('root');
  53. $node->addChild(new ArrayNode('alpha1'));
  54. $node->addChild(new ArrayNode('alpha2'));
  55. $node->normalize(['beta' => 'foo']);
  56. }
  57. public function ignoreAndRemoveMatrixProvider()
  58. {
  59. $unrecognizedOptionException = new InvalidConfigurationException('Unrecognized option "foo" under "root"');
  60. return [
  61. [true, true, [], 'no exception is thrown for an unrecognized child if the ignoreExtraKeys option is set to true'],
  62. [true, false, ['foo' => 'bar'], 'extra keys are not removed when ignoreExtraKeys second option is set to false'],
  63. [false, true, $unrecognizedOptionException],
  64. [false, false, $unrecognizedOptionException],
  65. ];
  66. }
  67. /**
  68. * @dataProvider ignoreAndRemoveMatrixProvider
  69. */
  70. public function testIgnoreAndRemoveBehaviors($ignore, $remove, $expected, $message = '')
  71. {
  72. if ($expected instanceof \Exception) {
  73. if (method_exists($this, 'expectException')) {
  74. $this->expectException(\get_class($expected));
  75. $this->expectExceptionMessage($expected->getMessage());
  76. } else {
  77. $this->setExpectedException(\get_class($expected), $expected->getMessage());
  78. }
  79. }
  80. $node = new ArrayNode('root');
  81. $node->setIgnoreExtraKeys($ignore, $remove);
  82. $result = $node->normalize(['foo' => 'bar']);
  83. $this->assertSame($expected, $result, $message);
  84. }
  85. /**
  86. * @dataProvider getPreNormalizationTests
  87. */
  88. public function testPreNormalize($denormalized, $normalized)
  89. {
  90. $node = new ArrayNode('foo');
  91. $r = new \ReflectionMethod($node, 'preNormalize');
  92. $r->setAccessible(true);
  93. $this->assertSame($normalized, $r->invoke($node, $denormalized));
  94. }
  95. public function getPreNormalizationTests()
  96. {
  97. return [
  98. [
  99. ['foo-bar' => 'foo'],
  100. ['foo_bar' => 'foo'],
  101. ],
  102. [
  103. ['foo-bar_moo' => 'foo'],
  104. ['foo-bar_moo' => 'foo'],
  105. ],
  106. [
  107. ['anything-with-dash-and-no-underscore' => 'first', 'no_dash' => 'second'],
  108. ['anything_with_dash_and_no_underscore' => 'first', 'no_dash' => 'second'],
  109. ],
  110. [
  111. ['foo-bar' => null, 'foo_bar' => 'foo'],
  112. ['foo-bar' => null, 'foo_bar' => 'foo'],
  113. ],
  114. ];
  115. }
  116. /**
  117. * @dataProvider getZeroNamedNodeExamplesData
  118. */
  119. public function testNodeNameCanBeZero($denormalized, $normalized)
  120. {
  121. $zeroNode = new ArrayNode(0);
  122. $zeroNode->addChild(new ScalarNode('name'));
  123. $fiveNode = new ArrayNode(5);
  124. $fiveNode->addChild(new ScalarNode(0));
  125. $fiveNode->addChild(new ScalarNode('new_key'));
  126. $rootNode = new ArrayNode('root');
  127. $rootNode->addChild($zeroNode);
  128. $rootNode->addChild($fiveNode);
  129. $rootNode->addChild(new ScalarNode('string_key'));
  130. $r = new \ReflectionMethod($rootNode, 'normalizeValue');
  131. $r->setAccessible(true);
  132. $this->assertSame($normalized, $r->invoke($rootNode, $denormalized));
  133. }
  134. public function getZeroNamedNodeExamplesData()
  135. {
  136. return [
  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. 0 => [
  150. 'name' => 'something',
  151. ],
  152. 5 => [
  153. 0 => 'this won\'t work too',
  154. 'new_key' => 'some other value',
  155. ],
  156. 'string_key' => 'just value',
  157. ],
  158. ],
  159. ];
  160. }
  161. /**
  162. * @dataProvider getPreNormalizedNormalizedOrderedData
  163. */
  164. public function testChildrenOrderIsMaintainedOnNormalizeValue($prenormalized, $normalized)
  165. {
  166. $scalar1 = new ScalarNode('1');
  167. $scalar2 = new ScalarNode('2');
  168. $scalar3 = new ScalarNode('3');
  169. $node = new ArrayNode('foo');
  170. $node->addChild($scalar1);
  171. $node->addChild($scalar3);
  172. $node->addChild($scalar2);
  173. $r = new \ReflectionMethod($node, 'normalizeValue');
  174. $r->setAccessible(true);
  175. $this->assertSame($normalized, $r->invoke($node, $prenormalized));
  176. }
  177. public function getPreNormalizedNormalizedOrderedData()
  178. {
  179. return [
  180. [
  181. ['2' => 'two', '1' => 'one', '3' => 'three'],
  182. ['2' => 'two', '1' => 'one', '3' => 'three'],
  183. ],
  184. ];
  185. }
  186. /**
  187. * @expectedException \InvalidArgumentException
  188. * @expectedExceptionMessage Child nodes must be named.
  189. */
  190. public function testAddChildEmptyName()
  191. {
  192. $node = new ArrayNode('root');
  193. $childNode = new ArrayNode('');
  194. $node->addChild($childNode);
  195. }
  196. /**
  197. * @expectedException \InvalidArgumentException
  198. * @expectedExceptionMessage A child node named "foo" already exists.
  199. */
  200. public function testAddChildNameAlreadyExists()
  201. {
  202. $node = new ArrayNode('root');
  203. $childNode = new ArrayNode('foo');
  204. $node->addChild($childNode);
  205. $childNodeWithSameName = new ArrayNode('foo');
  206. $node->addChild($childNodeWithSameName);
  207. }
  208. /**
  209. * @expectedException \RuntimeException
  210. * @expectedExceptionMessage The node at path "foo" has no default value.
  211. */
  212. public function testGetDefaultValueWithoutDefaultValue()
  213. {
  214. $node = new ArrayNode('foo');
  215. $node->getDefaultValue();
  216. }
  217. public function testSetDeprecated()
  218. {
  219. $childNode = new ArrayNode('foo');
  220. $childNode->setDeprecated('"%node%" is deprecated');
  221. $this->assertTrue($childNode->isDeprecated());
  222. $this->assertSame('"foo" is deprecated', $childNode->getDeprecationMessage($childNode->getName(), $childNode->getPath()));
  223. $node = new ArrayNode('root');
  224. $node->addChild($childNode);
  225. $deprecationTriggered = false;
  226. $deprecationHandler = function ($level, $message, $file, $line) use (&$prevErrorHandler, &$deprecationTriggered) {
  227. if (E_USER_DEPRECATED === $level) {
  228. return $deprecationTriggered = true;
  229. }
  230. return $prevErrorHandler ? $prevErrorHandler($level, $message, $file, $line) : false;
  231. };
  232. $prevErrorHandler = set_error_handler($deprecationHandler);
  233. $node->finalize([]);
  234. restore_error_handler();
  235. $this->assertFalse($deprecationTriggered, '->finalize() should not trigger if the deprecated node is not set');
  236. $prevErrorHandler = set_error_handler($deprecationHandler);
  237. $node->finalize(['foo' => []]);
  238. restore_error_handler();
  239. $this->assertTrue($deprecationTriggered, '->finalize() should trigger if the deprecated node is set');
  240. }
  241. }