YamlTest.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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. $this->expectException(InvalidDataTypeException::class);
  95. $this->expectExceptionMessageRegExp('/^Object support when parsing a YAML file has been disabled/');
  96. $object = new \stdClass();
  97. $object->foo = 'bar';
  98. // In core all Yaml encoding is done via Symfony and it does not support
  99. // objects so in order to encode an object we have to use the PECL
  100. // extension.
  101. // @see \Drupal\Component\Serialization\Yaml::encode()
  102. $yaml = YamlPecl::encode([$object]);
  103. YamlSymfony::decode($yaml);
  104. }
  105. /**
  106. * Data provider that lists all YAML files in core.
  107. */
  108. public function providerYamlFilesInCore() {
  109. $files = [];
  110. $dirs = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__ . '/../../../../../', \RecursiveDirectoryIterator::FOLLOW_SYMLINKS));
  111. foreach ($dirs as $dir) {
  112. $pathname = $dir->getPathname();
  113. // Exclude core/node_modules.
  114. if ($dir->getExtension() == 'yml' && strpos($pathname, '/../../../../../node_modules') === FALSE) {
  115. if (strpos($dir->getRealPath(), 'invalid_file') !== FALSE) {
  116. // There are some intentionally invalid files provided for testing
  117. // library API behaviors, ignore them.
  118. continue;
  119. }
  120. $files[] = [$dir->getRealPath()];
  121. }
  122. }
  123. return $files;
  124. }
  125. }
  126. class YamlStub extends Yaml {
  127. public static function getSerializer() {
  128. return '\Drupal\Tests\Component\Serialization\YamlParserProxy';
  129. }
  130. }
  131. class YamlParserProxy implements SerializationInterface {
  132. /**
  133. * @var \Drupal\Component\Serialization\SerializationInterface
  134. */
  135. protected static $mock;
  136. public static function setMock($mock) {
  137. static::$mock = $mock;
  138. }
  139. public static function encode($data) {
  140. return static::$mock->encode($data);
  141. }
  142. public static function decode($raw) {
  143. return static::$mock->decode($raw);
  144. }
  145. public static function getFileExtension() {
  146. return static::$mock->getFileExtension();
  147. }
  148. }