XmlUtilsTest.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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\Util;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\Config\Util\XmlUtils;
  13. class XmlUtilsTest extends TestCase
  14. {
  15. public function testLoadFile()
  16. {
  17. $fixtures = __DIR__.'/../Fixtures/Util/';
  18. try {
  19. XmlUtils::loadFile($fixtures.'invalid.xml');
  20. $this->fail();
  21. } catch (\InvalidArgumentException $e) {
  22. $this->assertContains('ERROR 77', $e->getMessage());
  23. }
  24. try {
  25. XmlUtils::loadFile($fixtures.'document_type.xml');
  26. $this->fail();
  27. } catch (\InvalidArgumentException $e) {
  28. $this->assertContains('Document types are not allowed', $e->getMessage());
  29. }
  30. try {
  31. XmlUtils::loadFile($fixtures.'invalid_schema.xml', $fixtures.'schema.xsd');
  32. $this->fail();
  33. } catch (\InvalidArgumentException $e) {
  34. $this->assertContains('ERROR 1845', $e->getMessage());
  35. }
  36. try {
  37. XmlUtils::loadFile($fixtures.'invalid_schema.xml', 'invalid_callback_or_file');
  38. $this->fail();
  39. } catch (\InvalidArgumentException $e) {
  40. $this->assertContains('XSD file or callable', $e->getMessage());
  41. }
  42. $mock = $this->getMockBuilder(__NAMESPACE__.'\Validator')->getMock();
  43. $mock->expects($this->exactly(2))->method('validate')->will($this->onConsecutiveCalls(false, true));
  44. try {
  45. XmlUtils::loadFile($fixtures.'valid.xml', [$mock, 'validate']);
  46. $this->fail();
  47. } catch (\InvalidArgumentException $e) {
  48. $this->assertRegExp('/The XML file ".+" is not valid\./', $e->getMessage());
  49. }
  50. $this->assertInstanceOf('DOMDocument', XmlUtils::loadFile($fixtures.'valid.xml', [$mock, 'validate']));
  51. $this->assertSame([], libxml_get_errors());
  52. }
  53. /**
  54. * @expectedException \Symfony\Component\Config\Util\Exception\InvalidXmlException
  55. * @expectedExceptionMessage The XML is not valid
  56. */
  57. public function testParseWithInvalidValidatorCallable()
  58. {
  59. $fixtures = __DIR__.'/../Fixtures/Util/';
  60. $mock = $this->getMockBuilder(__NAMESPACE__.'\Validator')->getMock();
  61. $mock->expects($this->once())->method('validate')->willReturn(false);
  62. XmlUtils::parse(file_get_contents($fixtures.'valid.xml'), [$mock, 'validate']);
  63. }
  64. public function testLoadFileWithInternalErrorsEnabled()
  65. {
  66. $internalErrors = libxml_use_internal_errors(true);
  67. $this->assertSame([], libxml_get_errors());
  68. $this->assertInstanceOf('DOMDocument', XmlUtils::loadFile(__DIR__.'/../Fixtures/Util/invalid_schema.xml'));
  69. $this->assertSame([], libxml_get_errors());
  70. libxml_clear_errors();
  71. libxml_use_internal_errors($internalErrors);
  72. }
  73. /**
  74. * @dataProvider getDataForConvertDomToArray
  75. */
  76. public function testConvertDomToArray($expected, $xml, $root = false, $checkPrefix = true)
  77. {
  78. $dom = new \DOMDocument();
  79. $dom->loadXML($root ? $xml : '<root>'.$xml.'</root>');
  80. $this->assertSame($expected, XmlUtils::convertDomElementToArray($dom->documentElement, $checkPrefix));
  81. }
  82. public function getDataForConvertDomToArray()
  83. {
  84. return [
  85. [null, ''],
  86. ['bar', 'bar'],
  87. [['bar' => 'foobar'], '<foo bar="foobar" />', true],
  88. [['foo' => null], '<foo />'],
  89. [['foo' => 'bar'], '<foo>bar</foo>'],
  90. [['foo' => ['foo' => 'bar']], '<foo foo="bar"/>'],
  91. [['foo' => ['foo' => 0]], '<foo><foo>0</foo></foo>'],
  92. [['foo' => ['foo' => 'bar']], '<foo><foo>bar</foo></foo>'],
  93. [['foo' => ['foo' => 'bar', 'value' => 'text']], '<foo foo="bar">text</foo>'],
  94. [['foo' => ['attr' => 'bar', 'foo' => 'text']], '<foo attr="bar"><foo>text</foo></foo>'],
  95. [['foo' => ['bar', 'text']], '<foo>bar</foo><foo>text</foo>'],
  96. [['foo' => [['foo' => 'bar'], ['foo' => 'text']]], '<foo foo="bar"/><foo foo="text" />'],
  97. [['foo' => ['foo' => ['bar', 'text']]], '<foo foo="bar"><foo>text</foo></foo>'],
  98. [['foo' => 'bar'], '<foo><!-- Comment -->bar</foo>'],
  99. [['foo' => 'text'], '<foo xmlns:h="http://www.example.org/bar" h:bar="bar">text</foo>'],
  100. [['foo' => ['bar' => 'bar', 'value' => 'text']], '<foo xmlns:h="http://www.example.org/bar" h:bar="bar">text</foo>', false, false],
  101. [['attr' => 1, 'b' => 'hello'], '<foo:a xmlns:foo="http://www.example.org/foo" xmlns:h="http://www.example.org/bar" attr="1" h:bar="bar"><foo:b>hello</foo:b><h:c>2</h:c></foo:a>', true],
  102. ];
  103. }
  104. /**
  105. * @dataProvider getDataForPhpize
  106. */
  107. public function testPhpize($expected, $value)
  108. {
  109. $this->assertSame($expected, XmlUtils::phpize($value));
  110. }
  111. public function getDataForPhpize()
  112. {
  113. return [
  114. ['', ''],
  115. [null, 'null'],
  116. [true, 'true'],
  117. [false, 'false'],
  118. [null, 'Null'],
  119. [true, 'True'],
  120. [false, 'False'],
  121. [0, '0'],
  122. [1, '1'],
  123. [-1, '-1'],
  124. [0777, '0777'],
  125. [255, '0xFF'],
  126. [100.0, '1e2'],
  127. [-120.0, '-1.2E2'],
  128. [-10100.1, '-10100.1'],
  129. ['-10,100.1', '-10,100.1'],
  130. ['1234 5678 9101 1121 3141', '1234 5678 9101 1121 3141'],
  131. ['1,2,3,4', '1,2,3,4'],
  132. ['11,22,33,44', '11,22,33,44'],
  133. ['11,222,333,4', '11,222,333,4'],
  134. ['1,222,333,444', '1,222,333,444'],
  135. ['11,222,333,444', '11,222,333,444'],
  136. ['111,222,333,444', '111,222,333,444'],
  137. ['1111,2222,3333,4444,5555', '1111,2222,3333,4444,5555'],
  138. ['foo', 'foo'],
  139. [6, '0b0110'],
  140. ];
  141. }
  142. public function testLoadEmptyXmlFile()
  143. {
  144. $file = __DIR__.'/../Fixtures/foo.xml';
  145. if (method_exists($this, 'expectException')) {
  146. $this->expectException('InvalidArgumentException');
  147. $this->expectExceptionMessage(sprintf('File %s does not contain valid XML, it is empty.', $file));
  148. } else {
  149. $this->setExpectedException('InvalidArgumentException', sprintf('File %s does not contain valid XML, it is empty.', $file));
  150. }
  151. XmlUtils::loadFile($file);
  152. }
  153. // test for issue https://github.com/symfony/symfony/issues/9731
  154. public function testLoadWrongEmptyXMLWithErrorHandler()
  155. {
  156. $originalDisableEntities = libxml_disable_entity_loader(false);
  157. $errorReporting = error_reporting(-1);
  158. set_error_handler(function ($errno, $errstr) {
  159. throw new \Exception($errstr, $errno);
  160. });
  161. $file = __DIR__.'/../Fixtures/foo.xml';
  162. try {
  163. try {
  164. XmlUtils::loadFile($file);
  165. $this->fail('An exception should have been raised');
  166. } catch (\InvalidArgumentException $e) {
  167. $this->assertEquals(sprintf('File %s does not contain valid XML, it is empty.', $file), $e->getMessage());
  168. }
  169. } finally {
  170. restore_error_handler();
  171. error_reporting($errorReporting);
  172. }
  173. $disableEntities = libxml_disable_entity_loader(true);
  174. libxml_disable_entity_loader($disableEntities);
  175. libxml_disable_entity_loader($originalDisableEntities);
  176. $this->assertFalse($disableEntities);
  177. // should not throw an exception
  178. XmlUtils::loadFile(__DIR__.'/../Fixtures/Util/valid.xml', __DIR__.'/../Fixtures/Util/schema.xsd');
  179. }
  180. }
  181. interface Validator
  182. {
  183. public function validate();
  184. }