XmlUtilsTest.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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', array($mock, 'validate'));
  46. $this->fail();
  47. } catch (\InvalidArgumentException $e) {
  48. $this->assertContains('is not valid', $e->getMessage());
  49. }
  50. $this->assertInstanceOf('DOMDocument', XmlUtils::loadFile($fixtures.'valid.xml', array($mock, 'validate')));
  51. $this->assertSame(array(), libxml_get_errors());
  52. }
  53. public function testLoadFileWithInternalErrorsEnabled()
  54. {
  55. $internalErrors = libxml_use_internal_errors(true);
  56. $this->assertSame(array(), libxml_get_errors());
  57. $this->assertInstanceOf('DOMDocument', XmlUtils::loadFile(__DIR__.'/../Fixtures/Util/invalid_schema.xml'));
  58. $this->assertSame(array(), libxml_get_errors());
  59. libxml_clear_errors();
  60. libxml_use_internal_errors($internalErrors);
  61. }
  62. /**
  63. * @dataProvider getDataForConvertDomToArray
  64. */
  65. public function testConvertDomToArray($expected, $xml, $root = false, $checkPrefix = true)
  66. {
  67. $dom = new \DOMDocument();
  68. $dom->loadXML($root ? $xml : '<root>'.$xml.'</root>');
  69. $this->assertSame($expected, XmlUtils::convertDomElementToArray($dom->documentElement, $checkPrefix));
  70. }
  71. public function getDataForConvertDomToArray()
  72. {
  73. return array(
  74. array(null, ''),
  75. array('bar', 'bar'),
  76. array(array('bar' => 'foobar'), '<foo bar="foobar" />', true),
  77. array(array('foo' => null), '<foo />'),
  78. array(array('foo' => 'bar'), '<foo>bar</foo>'),
  79. array(array('foo' => array('foo' => 'bar')), '<foo foo="bar"/>'),
  80. array(array('foo' => array('foo' => 0)), '<foo><foo>0</foo></foo>'),
  81. array(array('foo' => array('foo' => 'bar')), '<foo><foo>bar</foo></foo>'),
  82. array(array('foo' => array('foo' => 'bar', 'value' => 'text')), '<foo foo="bar">text</foo>'),
  83. array(array('foo' => array('attr' => 'bar', 'foo' => 'text')), '<foo attr="bar"><foo>text</foo></foo>'),
  84. array(array('foo' => array('bar', 'text')), '<foo>bar</foo><foo>text</foo>'),
  85. array(array('foo' => array(array('foo' => 'bar'), array('foo' => 'text'))), '<foo foo="bar"/><foo foo="text" />'),
  86. array(array('foo' => array('foo' => array('bar', 'text'))), '<foo foo="bar"><foo>text</foo></foo>'),
  87. array(array('foo' => 'bar'), '<foo><!-- Comment -->bar</foo>'),
  88. array(array('foo' => 'text'), '<foo xmlns:h="http://www.example.org/bar" h:bar="bar">text</foo>'),
  89. array(array('foo' => array('bar' => 'bar', 'value' => 'text')), '<foo xmlns:h="http://www.example.org/bar" h:bar="bar">text</foo>', false, false),
  90. array(array('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),
  91. );
  92. }
  93. /**
  94. * @dataProvider getDataForPhpize
  95. */
  96. public function testPhpize($expected, $value)
  97. {
  98. $this->assertSame($expected, XmlUtils::phpize($value));
  99. }
  100. public function getDataForPhpize()
  101. {
  102. return array(
  103. array('', ''),
  104. array(null, 'null'),
  105. array(true, 'true'),
  106. array(false, 'false'),
  107. array(null, 'Null'),
  108. array(true, 'True'),
  109. array(false, 'False'),
  110. array(0, '0'),
  111. array(1, '1'),
  112. array(-1, '-1'),
  113. array(0777, '0777'),
  114. array(255, '0xFF'),
  115. array(100.0, '1e2'),
  116. array(-120.0, '-1.2E2'),
  117. array(-10100.1, '-10100.1'),
  118. array('-10,100.1', '-10,100.1'),
  119. array('1234 5678 9101 1121 3141', '1234 5678 9101 1121 3141'),
  120. array('1,2,3,4', '1,2,3,4'),
  121. array('11,22,33,44', '11,22,33,44'),
  122. array('11,222,333,4', '11,222,333,4'),
  123. array('1,222,333,444', '1,222,333,444'),
  124. array('11,222,333,444', '11,222,333,444'),
  125. array('111,222,333,444', '111,222,333,444'),
  126. array('1111,2222,3333,4444,5555', '1111,2222,3333,4444,5555'),
  127. array('foo', 'foo'),
  128. array(6, '0b0110'),
  129. );
  130. }
  131. public function testLoadEmptyXmlFile()
  132. {
  133. $file = __DIR__.'/../Fixtures/foo.xml';
  134. if (method_exists($this, 'expectException')) {
  135. $this->expectException('InvalidArgumentException');
  136. $this->expectExceptionMessage(sprintf('File %s does not contain valid XML, it is empty.', $file));
  137. } else {
  138. $this->setExpectedException('InvalidArgumentException', sprintf('File %s does not contain valid XML, it is empty.', $file));
  139. }
  140. XmlUtils::loadFile($file);
  141. }
  142. // test for issue https://github.com/symfony/symfony/issues/9731
  143. public function testLoadWrongEmptyXMLWithErrorHandler()
  144. {
  145. $originalDisableEntities = libxml_disable_entity_loader(false);
  146. $errorReporting = error_reporting(-1);
  147. set_error_handler(function ($errno, $errstr) {
  148. throw new \Exception($errstr, $errno);
  149. });
  150. $file = __DIR__.'/../Fixtures/foo.xml';
  151. try {
  152. try {
  153. XmlUtils::loadFile($file);
  154. $this->fail('An exception should have been raised');
  155. } catch (\InvalidArgumentException $e) {
  156. $this->assertEquals(sprintf('File %s does not contain valid XML, it is empty.', $file), $e->getMessage());
  157. }
  158. } catch (\Exception $e) {
  159. restore_error_handler();
  160. error_reporting($errorReporting);
  161. throw $e;
  162. }
  163. restore_error_handler();
  164. error_reporting($errorReporting);
  165. $disableEntities = libxml_disable_entity_loader(true);
  166. libxml_disable_entity_loader($disableEntities);
  167. libxml_disable_entity_loader($originalDisableEntities);
  168. $this->assertFalse($disableEntities);
  169. // should not throw an exception
  170. XmlUtils::loadFile(__DIR__.'/../Fixtures/Util/valid.xml', __DIR__.'/../Fixtures/Util/schema.xsd');
  171. }
  172. }
  173. interface Validator
  174. {
  175. public function validate();
  176. }