YamlTest.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <?php
  2. namespace Drupal\Tests\Component\Serialization;
  3. use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
  4. use Drupal\Component\Serialization\SerializationInterface;
  5. use Drupal\Component\Serialization\Yaml;
  6. use Drupal\Component\Serialization\YamlPecl;
  7. use Drupal\Component\Serialization\YamlSymfony;
  8. use PHPUnit\Framework\TestCase;
  9. /**
  10. * @coversDefaultClass \Drupal\Component\Serialization\Yaml
  11. * @group Serialization
  12. */
  13. class YamlTest extends TestCase {
  14. /**
  15. * @var \PHPUnit_Framework_MockObject_MockObject
  16. */
  17. protected $mockParser;
  18. public function setUp() {
  19. parent::setUp();
  20. $this->mockParser = $this->getMockBuilder('\stdClass')
  21. ->setMethods(['encode', 'decode', 'getFileExtension'])
  22. ->getMock();
  23. YamlParserProxy::setMock($this->mockParser);
  24. }
  25. public function tearDown() {
  26. YamlParserProxy::setMock(NULL);
  27. parent::tearDown();
  28. }
  29. /**
  30. * @covers ::decode
  31. */
  32. public function testDecode() {
  33. $this->mockParser
  34. ->expects($this->once())
  35. ->method('decode');
  36. YamlStub::decode('test');
  37. }
  38. /**
  39. * @covers ::getFileExtension
  40. */
  41. public function testGetFileExtension() {
  42. $this->mockParser
  43. ->expects($this->never())
  44. ->method('getFileExtension');
  45. $this->assertEquals('yml', YamlStub::getFileExtension());
  46. }
  47. /**
  48. * Tests all YAML files are decoded in the same way with Symfony and PECL.
  49. *
  50. * This test is a little bit slow but it tests that we do not have any bugs in
  51. * our YAML that might not be decoded correctly in any of our implementations.
  52. *
  53. * @todo This should exist as an integration test not part of our unit tests.
  54. * https://www.drupal.org/node/2597730
  55. *
  56. * @requires extension yaml
  57. * @dataProvider providerYamlFilesInCore
  58. */
  59. public function testYamlFiles($file) {
  60. $data = file_get_contents($file);
  61. try {
  62. $this->assertEquals(YamlSymfony::decode($data), YamlPecl::decode($data), $file);
  63. }
  64. catch (InvalidDataTypeException $e) {
  65. // Provide file context to the failure so the exception message is useful.
  66. $this->fail("Exception thrown parsing $file:\n" . $e->getMessage());
  67. }
  68. }
  69. /**
  70. * Ensures that decoding php objects does not work in PECL.
  71. *
  72. * @requires extension yaml
  73. *
  74. * @see \Drupal\Tests\Component\Serialization\YamlTest::testObjectSupportDisabledSymfony()
  75. */
  76. public function testObjectSupportDisabledPecl() {
  77. $object = new \stdClass();
  78. $object->foo = 'bar';
  79. // In core all Yaml encoding is done via Symfony and it does not support
  80. // objects so in order to encode an object we have to use the PECL
  81. // extension.
  82. // @see \Drupal\Component\Serialization\Yaml::encode()
  83. $yaml = YamlPecl::encode([$object]);
  84. $this->assertEquals(['O:8:"stdClass":1:{s:3:"foo";s:3:"bar";}'], YamlPecl::decode($yaml));
  85. }
  86. /**
  87. * Ensures that decoding php objects does not work in Symfony.
  88. *
  89. * @requires extension yaml
  90. *
  91. * @see \Drupal\Tests\Component\Serialization\YamlTest::testObjectSupportDisabledPecl()
  92. */
  93. public function testObjectSupportDisabledSymfony() {
  94. if (method_exists($this, 'setExpectedExceptionRegExp')) {
  95. $this->setExpectedExceptionRegExp(InvalidDataTypeException::class, '/^Object support when parsing a YAML file has been disabled/');
  96. }
  97. else {
  98. $this->expectException(InvalidDataTypeException::class);
  99. $this->expectExceptionMessageRegExp('/^Object support when parsing a YAML file has been disabled/');
  100. }
  101. $object = new \stdClass();
  102. $object->foo = 'bar';
  103. // In core all Yaml encoding is done via Symfony and it does not support
  104. // objects so in order to encode an object we have to use the PECL
  105. // extension.
  106. // @see \Drupal\Component\Serialization\Yaml::encode()
  107. $yaml = YamlPecl::encode([$object]);
  108. YamlSymfony::decode($yaml);
  109. }
  110. /**
  111. * Data provider that lists all YAML files in core.
  112. */
  113. public function providerYamlFilesInCore() {
  114. $files = [];
  115. $dirs = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__ . '/../../../../../', \RecursiveDirectoryIterator::FOLLOW_SYMLINKS));
  116. foreach ($dirs as $dir) {
  117. $pathname = $dir->getPathname();
  118. // Exclude core/node_modules.
  119. if ($dir->getExtension() == 'yml' && strpos($pathname, '/../../../../../node_modules') === FALSE) {
  120. if (strpos($dir->getRealPath(), 'invalid_file') !== FALSE) {
  121. // There are some intentionally invalid files provided for testing
  122. // library API behaviours, ignore them.
  123. continue;
  124. }
  125. $files[] = [$dir->getRealPath()];
  126. }
  127. }
  128. return $files;
  129. }
  130. }
  131. class YamlStub extends Yaml {
  132. public static function getSerializer() {
  133. return '\Drupal\Tests\Component\Serialization\YamlParserProxy';
  134. }
  135. }
  136. class YamlParserProxy implements SerializationInterface {
  137. /**
  138. * @var \Drupal\Component\Serialization\SerializationInterface
  139. */
  140. protected static $mock;
  141. public static function setMock($mock) {
  142. static::$mock = $mock;
  143. }
  144. public static function encode($data) {
  145. return static::$mock->encode($data);
  146. }
  147. public static function decode($raw) {
  148. return static::$mock->decode($raw);
  149. }
  150. public static function getFileExtension() {
  151. return static::$mock->getFileExtension();
  152. }
  153. }