YamlTest.php 5.2 KB
Newer Older
1 2 3 4
<?php

namespace Drupal\Tests\Component\Serialization;

5 6
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Drupal\Component\Serialization\SerializationInterface;
7
use Drupal\Component\Serialization\Yaml;
8 9
use Drupal\Component\Serialization\YamlPecl;
use Drupal\Component\Serialization\YamlSymfony;
10
use PHPUnit\Framework\TestCase;
11 12 13 14 15

/**
 * @coversDefaultClass \Drupal\Component\Serialization\Yaml
 * @group Serialization
 */
16
class YamlTest extends TestCase {
17 18

  /**
19
   * @var \PHPUnit_Framework_MockObject_MockObject
20
   */
21 22 23 24 25 26 27 28 29 30 31 32 33
  protected $mockParser;

  public function setUp() {
    parent::setUp();
    $this->mockParser = $this->getMockBuilder('\stdClass')
      ->setMethods(['encode', 'decode', 'getFileExtension'])
      ->getMock();
    YamlParserProxy::setMock($this->mockParser);
  }

  public function tearDown() {
    YamlParserProxy::setMock(NULL);
    parent::tearDown();
34 35 36
  }

  /**
37
   * @covers ::decode
38
   */
39 40 41 42 43
  public function testDecode() {
    $this->mockParser
      ->expects($this->once())
      ->method('decode');
    YamlStub::decode('test');
44 45 46 47 48 49
  }

  /**
   * @covers ::getFileExtension
   */
  public function testGetFileExtension() {
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
    $this->mockParser
      ->expects($this->never())
      ->method('getFileExtension');
    $this->assertEquals('yml', YamlStub::getFileExtension());
  }

  /**
   * Tests all YAML files are decoded in the same way with Symfony and PECL.
   *
   * This test is a little bit slow but it tests that we do not have any bugs in
   * our YAML that might not be decoded correctly in any of our implementations.
   *
   * @todo This should exist as an integration test not part of our unit tests.
   *   https://www.drupal.org/node/2597730
   *
   * @requires extension yaml
   * @dataProvider providerYamlFilesInCore
   */
  public function testYamlFiles($file) {
    $data = file_get_contents($file);
    try {
      $this->assertEquals(YamlSymfony::decode($data), YamlPecl::decode($data), $file);
    }
    catch (InvalidDataTypeException $e) {
      // Provide file context to the failure so the exception message is useful.
      $this->fail("Exception thrown parsing $file:\n" . $e->getMessage());
    }
  }

79
  /**
80
   * Ensures that decoding php objects does not work in PECL.
81 82
   *
   * @requires extension yaml
83 84
   *
   * @see \Drupal\Tests\Component\Serialization\YamlTest::testObjectSupportDisabledSymfony()
85
   */
86
  public function testObjectSupportDisabledPecl() {
87 88 89
    $object = new \stdClass();
    $object->foo = 'bar';
    // In core all Yaml encoding is done via Symfony and it does not support
90
    // objects so in order to encode an object we have to use the PECL
91 92 93 94
    // extension.
    // @see \Drupal\Component\Serialization\Yaml::encode()
    $yaml = YamlPecl::encode([$object]);
    $this->assertEquals(['O:8:"stdClass":1:{s:3:"foo";s:3:"bar";}'], YamlPecl::decode($yaml));
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
  }

  /**
   * Ensures that decoding php objects does not work in Symfony.
   *
   * @requires extension yaml
   *
   * @see \Drupal\Tests\Component\Serialization\YamlTest::testObjectSupportDisabledPecl()
   */
  public function testObjectSupportDisabledSymfony() {
    if (method_exists($this, 'setExpectedExceptionRegExp')) {
      $this->setExpectedExceptionRegExp(InvalidDataTypeException::class, '/^Object support when parsing a YAML file has been disabled/');
    }
    else {
      $this->expectException(InvalidDataTypeException::class);
      $this->expectExceptionMessageRegExp('/^Object support when parsing a YAML file has been disabled/');
    }
    $object = new \stdClass();
    $object->foo = 'bar';
    // In core all Yaml encoding is done via Symfony and it does not support
    // objects so in order to encode an object we have to use the PECL
    // extension.
    // @see \Drupal\Component\Serialization\Yaml::encode()
    $yaml = YamlPecl::encode([$object]);
    YamlSymfony::decode($yaml);
120 121
  }

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
  /**
   * Data provider that lists all YAML files in core.
   */
  public function providerYamlFilesInCore() {
    $files = [];
    $dirs = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__ . '/../../../../../', \RecursiveDirectoryIterator::FOLLOW_SYMLINKS));
    foreach ($dirs as $dir) {
      $pathname = $dir->getPathname();
      // Exclude vendor.
      if ($dir->getExtension() == 'yml' && strpos($pathname, '/../../../../../vendor') === FALSE) {
        if (strpos($dir->getRealPath(), 'invalid_file') !== FALSE) {
          // There are some intentionally invalid files provided for testing
          // library API behaviours, ignore them.
          continue;
        }
        $files[] = [$dir->getRealPath()];
      }
    }
    return $files;
  }

}

class YamlStub extends Yaml {

  public static function getSerializer() {
    return '\Drupal\Tests\Component\Serialization\YamlParserProxy';
  }

}

class YamlParserProxy implements SerializationInterface {

  /**
   * @var \Drupal\Component\Serialization\SerializationInterface
   */
  protected static $mock;

  public static function setMock($mock) {
    static::$mock = $mock;
  }

  public static function encode($data) {
    return static::$mock->encode($data);
  }

  public static function decode($raw) {
    return static::$mock->decode($raw);
  }

  public static function getFileExtension() {
    return static::$mock->getFileExtension();
174 175 176
  }

}