namespace Symfony\Component\Yaml\Tests;
use PHPUnit\Framework\TestCase;
-use Symfony\Component\Yaml\Yaml;
+use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser;
+use Symfony\Component\Yaml\Tag\TaggedValue;
+use Symfony\Component\Yaml\Yaml;
class ParserTest extends TestCase
{
protected function tearDown()
{
$this->parser = null;
+
+ chmod(__DIR__.'/Fixtures/not_readable.yml', 0644);
}
/**
* @dataProvider getDataFormSpecifications
*/
- public function testSpecifications($file, $expected, $yaml, $comment)
+ public function testSpecifications($expected, $yaml, $comment, $deprecated)
{
+ $deprecations = array();
+
+ if ($deprecated) {
+ set_error_handler(function ($type, $msg) use (&$deprecations) {
+ if (E_USER_DEPRECATED !== $type) {
+ restore_error_handler();
+
+ if (class_exists('PHPUnit_Util_ErrorHandler')) {
+ return \call_user_func_array('PHPUnit_Util_ErrorHandler::handleError', \func_get_args());
+ }
+
+ return \call_user_func_array('PHPUnit\Util\ErrorHandler::handleError', \func_get_args());
+ }
+
+ $deprecations[] = $msg;
+ });
+ }
+
$this->assertEquals($expected, var_export($this->parser->parse($yaml), true), $comment);
+
+ if ($deprecated) {
+ restore_error_handler();
+
+ $this->assertCount(1, $deprecations);
+ $this->assertContains(true !== $deprecated ? $deprecated : 'Using the comma as a group separator for floats is deprecated since Symfony 3.2 and will be removed in 4.0 on line 1.', $deprecations[0]);
+ }
}
public function getDataFormSpecifications()
{
- $parser = new Parser();
- $path = __DIR__.'/Fixtures';
-
- $tests = array();
- $files = $parser->parse(file_get_contents($path.'/index.yml'));
- foreach ($files as $file) {
- $yamls = file_get_contents($path.'/'.$file.'.yml');
+ return $this->loadTestsFromFixtureFiles('index.yml');
+ }
- // split YAMLs documents
- foreach (preg_split('/^---( %YAML\:1\.0)?/m', $yamls) as $yaml) {
- if (!$yaml) {
- continue;
- }
+ /**
+ * @group legacy
+ * @expectedDeprecationMessage Using the Yaml::PARSE_KEYS_AS_STRINGS flag is deprecated since Symfony 3.4 as it will be removed in 4.0. Quote your keys when they are evaluable
+ * @dataProvider getNonStringMappingKeysData
+ */
+ public function testNonStringMappingKeys($expected, $yaml, $comment)
+ {
+ $this->assertSame($expected, var_export($this->parser->parse($yaml, Yaml::PARSE_KEYS_AS_STRINGS), true), $comment);
+ }
- $test = $parser->parse($yaml);
- if (isset($test['todo']) && $test['todo']) {
- // TODO
- } else {
- eval('$expected = '.trim($test['php']).';');
+ public function getNonStringMappingKeysData()
+ {
+ return $this->loadTestsFromFixtureFiles('nonStringKeys.yml');
+ }
- $tests[] = array($file, var_export($expected, true), $test['yaml'], $test['test']);
- }
- }
- }
+ /**
+ * @group legacy
+ * @dataProvider getLegacyNonStringMappingKeysData
+ */
+ public function testLegacyNonStringMappingKeys($expected, $yaml, $comment)
+ {
+ $this->assertSame($expected, var_export($this->parser->parse($yaml), true), $comment);
+ }
- return $tests;
+ public function getLegacyNonStringMappingKeysData()
+ {
+ return $this->loadTestsFromFixtureFiles('legacyNonStringKeys.yml');
}
public function testTabsInYaml()
public function testObjectSupportEnabled()
{
$input = <<<'EOF'
-foo: !!php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";}
+foo: !php/object O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";}
bar: 1
EOF;
- $this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, false, true), '->parse() is able to parse objects');
+ $this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, Yaml::PARSE_OBJECT), '->parse() is able to parse objects');
+ }
+ /**
+ * @group legacy
+ */
+ public function testObjectSupportEnabledPassingTrue()
+ {
$input = <<<'EOF'
foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";}
bar: 1
$this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, false, true), '->parse() is able to parse objects');
}
+ /**
+ * @group legacy
+ * @dataProvider deprecatedObjectValueProvider
+ */
+ public function testObjectSupportEnabledWithDeprecatedTag($yaml)
+ {
+ $this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($yaml, Yaml::PARSE_OBJECT), '->parse() is able to parse objects');
+ }
+
+ public function deprecatedObjectValueProvider()
+ {
+ return array(
+ array(
+ <<<YAML
+foo: !!php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";}
+bar: 1
+YAML
+ ),
+ array(
+ <<<YAML
+foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";}
+bar: 1
+YAML
+ ),
+ );
+ }
+
/**
* @dataProvider invalidDumpedObjectProvider
*/
* @dataProvider getObjectForMapTests
*/
public function testObjectForMap($yaml, $expected)
+ {
+ $flags = Yaml::PARSE_OBJECT_FOR_MAP;
+
+ $this->assertEquals($expected, $this->parser->parse($yaml, $flags));
+ }
+
+ /**
+ * @group legacy
+ * @dataProvider getObjectForMapTests
+ */
+ public function testObjectForMapEnabledWithMappingUsingBooleanToggles($yaml, $expected)
{
$this->assertEquals($expected, $this->parser->parse($yaml, false, false, true));
}
$yaml = <<<'YAML'
map:
- 0: one
- 1: two
+ '0': one
+ '1': two
YAML;
$expected = new \stdClass();
$expected->map = new \stdClass();
*/
public function testObjectsSupportDisabledWithExceptions($yaml)
{
- $this->parser->parse($yaml, true, false);
+ $this->parser->parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE);
+ }
+
+ public function testCanParseContentWithTrailingSpaces()
+ {
+ $yaml = "items: \n foo: bar";
+
+ $expected = array(
+ 'items' => array('foo' => 'bar'),
+ );
+
+ $this->assertSame($expected, $this->parser->parse($yaml));
+ }
+
+ /**
+ * @group legacy
+ * @dataProvider invalidDumpedObjectProvider
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
+ */
+ public function testObjectsSupportDisabledWithExceptionsUsingBooleanToggles($yaml)
+ {
+ $this->parser->parse($yaml, true);
}
public function invalidDumpedObjectProvider()
$this->assertSame($expected, $this->parser->parse($yaml));
}
+ public function testNonStringFollowedByCommentEmbeddedInMapping()
+ {
+ $yaml = <<<'EOT'
+a:
+ b:
+ {}
+# comment
+ d:
+ 1.1
+# another comment
+EOT;
+ $expected = array(
+ 'a' => array(
+ 'b' => array(),
+ 'd' => 1.1,
+ ),
+ );
+
+ $this->assertSame($expected, $this->parser->parse($yaml));
+ }
+
+ public function getParseExceptionNotAffectedMultiLineStringLastResortParsing()
+ {
+ $tests = array();
+
+ $yaml = <<<'EOT'
+a
+ b:
+EOT;
+ $tests['parse error on first line'] = array($yaml);
+
+ $yaml = <<<'EOT'
+a
+
+b
+ c:
+EOT;
+ $tests['parse error due to inconsistent indentation'] = array($yaml);
+
+ $yaml = <<<'EOT'
+ & * ! | > ' " % @ ` #, { asd a;sdasd }-@^qw3
+EOT;
+ $tests['symfony/symfony/issues/22967#issuecomment-322067742'] = array($yaml);
+
+ return $tests;
+ }
+
+ /**
+ * @dataProvider getParseExceptionNotAffectedMultiLineStringLastResortParsing
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
+ */
+ public function testParseExceptionNotAffectedByMultiLineStringLastResortParsing($yaml)
+ {
+ $this->parser->parse($yaml);
+ }
+
+ public function testMultiLineStringLastResortParsing()
+ {
+ $yaml = <<<'EOT'
+test:
+ You can have things that don't look like strings here
+ true
+ yes you can
+EOT;
+ $expected = array(
+ 'test' => 'You can have things that don\'t look like strings here true yes you can',
+ );
+
+ $this->assertSame($expected, $this->parser->parse($yaml));
+
+ $yaml = <<<'EOT'
+a:
+ b
+ c
+EOT;
+ $expected = array(
+ 'a' => 'b c',
+ );
+
+ $this->assertSame($expected, $this->parser->parse($yaml));
+ }
+
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
*/
*
* @see http://yaml.org/spec/1.2/spec.html#id2759572
* @see http://yaml.org/spec/1.1/#id932806
+ * @group legacy
*/
public function testMappingDuplicateKeyBlock()
{
$this->assertSame($expected, Yaml::parse($input));
}
+ /**
+ * @group legacy
+ */
public function testMappingDuplicateKeyFlow()
{
$input = <<<'EOD'
$this->assertSame($expected, Yaml::parse($input));
}
+ /**
+ * @group legacy
+ * @dataProvider getParseExceptionOnDuplicateData
+ * @expectedDeprecation Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated %s and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0 on line %d.
+ * throws \Symfony\Component\Yaml\Exception\ParseException in 4.0
+ */
+ public function testParseExceptionOnDuplicate($input, $duplicateKey, $lineNumber)
+ {
+ Yaml::parse($input);
+ }
+
+ public function getParseExceptionOnDuplicateData()
+ {
+ $tests = array();
+
+ $yaml = <<<EOD
+parent: { child: first, child: duplicate }
+EOD;
+ $tests[] = array($yaml, 'child', 1);
+
+ $yaml = <<<EOD
+parent:
+ child: first,
+ child: duplicate
+EOD;
+ $tests[] = array($yaml, 'child', 3);
+
+ $yaml = <<<EOD
+parent: { child: foo }
+parent: { child: bar }
+EOD;
+ $tests[] = array($yaml, 'parent', 2);
+
+ $yaml = <<<EOD
+parent: { child_mapping: { value: bar}, child_mapping: { value: bar} }
+EOD;
+ $tests[] = array($yaml, 'child_mapping', 1);
+
+ $yaml = <<<EOD
+parent:
+ child_mapping:
+ value: bar
+ child_mapping:
+ value: bar
+EOD;
+ $tests[] = array($yaml, 'child_mapping', 4);
+
+ $yaml = <<<EOD
+parent: { child_sequence: ['key1', 'key2', 'key3'], child_sequence: ['key1', 'key2', 'key3'] }
+EOD;
+ $tests[] = array($yaml, 'child_sequence', 1);
+
+ $yaml = <<<EOD
+parent:
+ child_sequence:
+ - key1
+ - key2
+ - key3
+ child_sequence:
+ - key1
+ - key2
+ - key3
+EOD;
+ $tests[] = array($yaml, 'child_sequence', 6);
+
+ return $tests;
+ }
+
public function testEmptyValue()
{
$input = <<<'EOF'
$this->assertEquals(array('foo' => 1, 'bar' => 2), $this->parser->parse($yaml));
}
+ /**
+ * @group legacy
+ * @expectedDeprecation Implicit casting of numeric key to string is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead on line 2.
+ */
public function testFloatKeys()
{
$yaml = <<<'EOF'
/**
* @group legacy
- * @expectedDeprecation Using a colon in the unquoted mapping value "bar: baz" in line 1 is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.
- * throw ParseException in Symfony 3.0
+ * @expectedDeprecation Implicit casting of non-string key to string is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead on line 1.
+ */
+ public function testBooleanKeys()
+ {
+ $yaml = <<<'EOF'
+true: foo
+false: bar
+EOF;
+
+ $expected = array(
+ 1 => 'foo',
+ 0 => 'bar',
+ );
+
+ $this->assertEquals($expected, $this->parser->parse($yaml));
+ }
+
+ public function testExplicitStringCasting()
+ {
+ $yaml = <<<'EOF'
+'1.2': "bar"
+!!str 1.3: "baz"
+
+'true': foo
+!!str false: bar
+
+!!str null: 'null'
+'~': 'null'
+EOF;
+
+ $expected = array(
+ '1.2' => 'bar',
+ '1.3' => 'baz',
+ 'true' => 'foo',
+ 'false' => 'bar',
+ 'null' => 'null',
+ '~' => 'null',
+ );
+
+ $this->assertEquals($expected, $this->parser->parse($yaml));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
+ * @expectedExceptionMessage A colon cannot be used in an unquoted mapping value
*/
public function testColonInMappingValueException()
{
}
/**
- * @param $lineNumber
- * @param $yaml
- * @dataProvider parserThrowsExceptionWithCorrectLineNumberProvider
+ * @dataProvider getBinaryData
*/
- public function testParserThrowsExceptionWithCorrectLineNumber($lineNumber, $yaml)
+ public function testParseBinaryData($data)
+ {
+ $this->assertSame(array('data' => 'Hello world'), $this->parser->parse($data));
+ }
+
+ public function getBinaryData()
+ {
+ return array(
+ 'enclosed with double quotes' => array('data: !!binary "SGVsbG8gd29ybGQ="'),
+ 'enclosed with single quotes' => array("data: !!binary 'SGVsbG8gd29ybGQ='"),
+ 'containing spaces' => array('data: !!binary "SGVs bG8gd 29ybGQ="'),
+ 'in block scalar' => array(
+ <<<'EOT'
+data: !!binary |
+ SGVsbG8gd29ybGQ=
+EOT
+ ),
+ 'containing spaces in block scalar' => array(
+ <<<'EOT'
+data: !!binary |
+ SGVs bG8gd 29ybGQ=
+EOT
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider getInvalidBinaryData
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
+ */
+ public function testParseInvalidBinaryData($data, $expectedMessage)
{
if (method_exists($this, 'expectException')) {
- $this->expectException('\Symfony\Component\Yaml\Exception\ParseException');
- $this->expectExceptionMessage(sprintf('Unexpected characters near "," at line %d (near "bar: "123",").', $lineNumber));
+ $this->expectExceptionMessageRegExp($expectedMessage);
} else {
- $this->setExpectedException('\Symfony\Component\Yaml\Exception\ParseException', sprintf('Unexpected characters near "," at line %d (near "bar: "123",").', $lineNumber));
+ $this->setExpectedExceptionRegExp(ParseException::class, $expectedMessage);
}
- $this->parser->parse($yaml);
+ $this->parser->parse($data);
}
- public function parserThrowsExceptionWithCorrectLineNumberProvider()
+ public function getInvalidBinaryData()
{
return array(
- array(
- 4,
- <<<'YAML'
-foo:
- -
- # bar
- bar: "123",
-YAML
- ),
- array(
- 5,
- <<<'YAML'
-foo:
- -
- # bar
- # bar
- bar: "123",
-YAML
+ 'length not a multiple of four' => array('data: !!binary "SGVsbG8d29ybGQ="', '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/'),
+ 'invalid characters' => array('!!binary "SGVsbG8#d29ybGQ="', '/The base64 encoded data \(.*\) contains invalid characters/'),
+ 'too many equals characters' => array('data: !!binary "SGVsbG8gd29yb==="', '/The base64 encoded data \(.*\) contains invalid characters/'),
+ 'misplaced equals character' => array('data: !!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'),
+ 'length not a multiple of four in block scalar' => array(
+ <<<'EOT'
+data: !!binary |
+ SGVsbG8d29ybGQ=
+EOT
+ ,
+ '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/',
+ ),
+ 'invalid characters in block scalar' => array(
+ <<<'EOT'
+data: !!binary |
+ SGVsbG8#d29ybGQ=
+EOT
+ ,
+ '/The base64 encoded data \(.*\) contains invalid characters/',
+ ),
+ 'too many equals characters in block scalar' => array(
+ <<<'EOT'
+data: !!binary |
+ SGVsbG8gd29yb===
+EOT
+ ,
+ '/The base64 encoded data \(.*\) contains invalid characters/',
+ ),
+ 'misplaced equals character in block scalar' => array(
+ <<<'EOT'
+data: !!binary |
+ SGVsbG8gd29ybG=Q
+EOT
+ ,
+ '/The base64 encoded data \(.*\) contains invalid characters/',
+ ),
+ );
+ }
+
+ public function testParseDateAsMappingValue()
+ {
+ $yaml = <<<'EOT'
+date: 2002-12-14
+EOT;
+ $expectedDate = new \DateTime();
+ $expectedDate->setTimeZone(new \DateTimeZone('UTC'));
+ $expectedDate->setDate(2002, 12, 14);
+ $expectedDate->setTime(0, 0, 0);
+
+ $this->assertEquals(array('date' => $expectedDate), $this->parser->parse($yaml, Yaml::PARSE_DATETIME));
+ }
+
+ /**
+ * @param $lineNumber
+ * @param $yaml
+ * @dataProvider parserThrowsExceptionWithCorrectLineNumberProvider
+ */
+ public function testParserThrowsExceptionWithCorrectLineNumber($lineNumber, $yaml)
+ {
+ if (method_exists($this, 'expectException')) {
+ $this->expectException('\Symfony\Component\Yaml\Exception\ParseException');
+ $this->expectExceptionMessage(sprintf('Unexpected characters near "," at line %d (near "bar: "123",").', $lineNumber));
+ } else {
+ $this->setExpectedException('\Symfony\Component\Yaml\Exception\ParseException', sprintf('Unexpected characters near "," at line %d (near "bar: "123",").', $lineNumber));
+ }
+
+ $this->parser->parse($yaml);
+ }
+
+ public function parserThrowsExceptionWithCorrectLineNumberProvider()
+ {
+ return array(
+ array(
+ 4,
+ <<<'YAML'
+foo:
+ -
+ # bar
+ bar: "123",
+YAML
+ ),
+ array(
+ 5,
+ <<<'YAML'
+foo:
+ -
+ # bar
+ # bar
+ bar: "123",
+YAML
),
array(
8,
);
}
+ public function testParseMultiLineQuotedString()
+ {
+ $yaml = <<<EOT
+foo: "bar
+ baz
+ foobar
+foo"
+bar: baz
+EOT;
+
+ $this->assertSame(array('foo' => 'bar baz foobar foo', 'bar' => 'baz'), $this->parser->parse($yaml));
+ }
+
+ public function testMultiLineQuotedStringWithTrailingBackslash()
+ {
+ $yaml = <<<YAML
+foobar:
+ "foo\
+ bar"
+YAML;
+
+ $this->assertSame(array('foobar' => 'foobar'), $this->parser->parse($yaml));
+ }
+
+ public function testCommentCharactersInMultiLineQuotedStrings()
+ {
+ $yaml = <<<YAML
+foo:
+ foobar: 'foo
+ #bar'
+ bar: baz
+YAML;
+ $expected = array(
+ 'foo' => array(
+ 'foobar' => 'foo #bar',
+ 'bar' => 'baz',
+ ),
+ );
+
+ $this->assertSame($expected, $this->parser->parse($yaml));
+ }
+
+ public function testBlankLinesInQuotedMultiLineString()
+ {
+ $yaml = <<<YAML
+foobar: 'foo
+
+ bar'
+YAML;
+ $expected = array(
+ 'foobar' => "foo\nbar",
+ );
+
+ $this->assertSame($expected, $this->parser->parse($yaml));
+ }
+
+ public function testParseMultiLineUnquotedString()
+ {
+ $yaml = <<<EOT
+foo: bar
+ baz
+ foobar
+ foo
+bar: baz
+EOT;
+
+ $this->assertSame(array('foo' => 'bar baz foobar foo', 'bar' => 'baz'), $this->parser->parse($yaml));
+ }
+
+ public function testParseMultiLineString()
+ {
+ $this->assertEquals("foo bar\nbaz", $this->parser->parse("foo\nbar\n\nbaz"));
+ }
+
+ /**
+ * @dataProvider multiLineDataProvider
+ */
+ public function testParseMultiLineMappingValue($yaml, $expected, $parseError)
+ {
+ $this->assertEquals($expected, $this->parser->parse($yaml));
+ }
+
+ public function multiLineDataProvider()
+ {
+ $tests = array();
+
+ $yaml = <<<'EOF'
+foo:
+- bar:
+ one
+
+ two
+ three
+EOF;
+ $expected = array(
+ 'foo' => array(
+ array(
+ 'bar' => "one\ntwo three",
+ ),
+ ),
+ );
+
+ $tests[] = array($yaml, $expected, false);
+
+ $yaml = <<<'EOF'
+bar
+"foo"
+EOF;
+ $expected = 'bar "foo"';
+
+ $tests[] = array($yaml, $expected, false);
+
+ $yaml = <<<'EOF'
+bar
+"foo
+EOF;
+ $expected = 'bar "foo';
+
+ $tests[] = array($yaml, $expected, false);
+
+ $yaml = <<<'EOF'
+bar
+
+'foo'
+EOF;
+ $expected = "bar\n'foo'";
+
+ $tests[] = array($yaml, $expected, false);
+
+ $yaml = <<<'EOF'
+bar
+
+foo'
+EOF;
+ $expected = "bar\nfoo'";
+
+ $tests[] = array($yaml, $expected, false);
+
+ return $tests;
+ }
+
+ public function testTaggedInlineMapping()
+ {
+ $this->assertEquals(new TaggedValue('foo', array('foo' => 'bar')), $this->parser->parse('!foo {foo: bar}', Yaml::PARSE_CUSTOM_TAGS));
+ }
+
+ /**
+ * @dataProvider taggedValuesProvider
+ */
+ public function testCustomTagSupport($expected, $yaml)
+ {
+ $this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_CUSTOM_TAGS));
+ }
+
+ public function taggedValuesProvider()
+ {
+ return array(
+ 'sequences' => array(
+ array(new TaggedValue('foo', array('yaml')), new TaggedValue('quz', array('bar'))),
+ <<<YAML
+- !foo
+ - yaml
+- !quz [bar]
+YAML
+ ),
+ 'mappings' => array(
+ new TaggedValue('foo', array('foo' => new TaggedValue('quz', array('bar')), 'quz' => new TaggedValue('foo', array('quz' => 'bar')))),
+ <<<YAML
+!foo
+foo: !quz [bar]
+quz: !foo
+ quz: bar
+YAML
+ ),
+ 'inline' => array(
+ array(new TaggedValue('foo', array('foo', 'bar')), new TaggedValue('quz', array('foo' => 'bar', 'quz' => new TaggedValue('bar', array('one' => 'bar'))))),
+ <<<YAML
+- !foo [foo, bar]
+- !quz {foo: bar, quz: !bar {one: bar}}
+YAML
+ ),
+ );
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
+ * @expectedExceptionMessage Tags support is not enabled. Enable the `Yaml::PARSE_CUSTOM_TAGS` flag to use "!iterator" at line 1 (near "!iterator [foo]").
+ */
+ public function testCustomTagsDisabled()
+ {
+ $this->parser->parse('!iterator [foo]');
+ }
+
+ /**
+ * @group legacy
+ * @expectedDeprecation Using the unquoted scalar value "!iterator foo" is deprecated since Symfony 3.3 and will be considered as a tagged value in 4.0. You must quote it on line 1.
+ */
+ public function testUnsupportedTagWithScalar()
+ {
+ $this->assertEquals('!iterator foo', $this->parser->parse('!iterator foo'));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
+ * @expectedExceptionMessage The built-in tag "!!foo" is not implemented at line 1 (near "!!foo").
+ */
+ public function testExceptionWhenUsingUnsuportedBuiltInTags()
+ {
+ $this->parser->parse('!!foo');
+ }
+
+ /**
+ * @group legacy
+ * @expectedDeprecation Starting an unquoted string with a question mark followed by a space is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0 on line 1.
+ */
+ public function testComplexMappingThrowsParseException()
+ {
+ $yaml = <<<YAML
+? "1"
+:
+ name: végétalien
+YAML;
+
+ $this->parser->parse($yaml);
+ }
+
+ /**
+ * @group legacy
+ * @expectedDeprecation Starting an unquoted string with a question mark followed by a space is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0 on line 2.
+ */
+ public function testComplexMappingNestedInMappingThrowsParseException()
+ {
+ $yaml = <<<YAML
+diet:
+ ? "1"
+ :
+ name: végétalien
+YAML;
+
+ $this->parser->parse($yaml);
+ }
+
+ /**
+ * @group legacy
+ * @expectedDeprecation Starting an unquoted string with a question mark followed by a space is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0 on line 1.
+ */
+ public function testComplexMappingNestedInSequenceThrowsParseException()
+ {
+ $yaml = <<<YAML
+- ? "1"
+ :
+ name: végétalien
+YAML;
+
+ $this->parser->parse($yaml);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
+ * @expectedExceptionMessage Unable to parse at line 1 (near "[parameters]").
+ */
+ public function testParsingIniThrowsException()
+ {
+ $ini = <<<INI
+[parameters]
+ foo = bar
+ bar = %foo%
+INI;
+
+ $this->parser->parse($ini);
+ }
+
+ private function loadTestsFromFixtureFiles($testsFile)
+ {
+ $parser = new Parser();
+
+ $tests = array();
+ $files = $parser->parseFile(__DIR__.'/Fixtures/'.$testsFile);
+ foreach ($files as $file) {
+ $yamls = file_get_contents(__DIR__.'/Fixtures/'.$file.'.yml');
+
+ // split YAMLs documents
+ foreach (preg_split('/^---( %YAML\:1\.0)?/m', $yamls) as $yaml) {
+ if (!$yaml) {
+ continue;
+ }
+
+ $test = $parser->parse($yaml);
+ if (isset($test['todo']) && $test['todo']) {
+ // TODO
+ } else {
+ eval('$expected = '.trim($test['php']).';');
+
+ $tests[] = array(var_export($expected, true), $test['yaml'], $test['test'], isset($test['deprecated']) ? $test['deprecated'] : false);
+ }
+ }
+ }
+
+ return $tests;
+ }
+
public function testCanParseVeryLongValue()
{
$longStringWithSpaces = str_repeat('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ', 20000);
YAML;
$this->parser->parse($yaml);
}
+
+ public function testPhpConstantTagMappingKey()
+ {
+ $yaml = <<<YAML
+transitions:
+ !php/const 'Symfony\Component\Yaml\Tests\B::FOO':
+ from:
+ - !php/const 'Symfony\Component\Yaml\Tests\B::BAR'
+ to: !php/const 'Symfony\Component\Yaml\Tests\B::BAZ'
+YAML;
+ $expected = array(
+ 'transitions' => array(
+ 'foo' => array(
+ 'from' => array(
+ 'bar',
+ ),
+ 'to' => 'baz',
+ ),
+ ),
+ );
+
+ $this->assertSame($expected, $this->parser->parse($yaml, Yaml::PARSE_CONSTANT));
+ }
+
+ /**
+ * @group legacy
+ * @expectedDeprecation The !php/const: tag to indicate dumped PHP constants is deprecated since Symfony 3.4 and will be removed in 4.0. Use the !php/const (without the colon) tag instead on line 2.
+ * @expectedDeprecation The !php/const: tag to indicate dumped PHP constants is deprecated since Symfony 3.4 and will be removed in 4.0. Use the !php/const (without the colon) tag instead on line 4.
+ * @expectedDeprecation The !php/const: tag to indicate dumped PHP constants is deprecated since Symfony 3.4 and will be removed in 4.0. Use the !php/const (without the colon) tag instead on line 5.
+ */
+ public function testDeprecatedPhpConstantTagMappingKey()
+ {
+ $yaml = <<<YAML
+transitions:
+ !php/const:Symfony\Component\Yaml\Tests\B::FOO:
+ from:
+ - !php/const:Symfony\Component\Yaml\Tests\B::BAR
+ to: !php/const:Symfony\Component\Yaml\Tests\B::BAZ
+YAML;
+ $expected = array(
+ 'transitions' => array(
+ 'foo' => array(
+ 'from' => array(
+ 'bar',
+ ),
+ 'to' => 'baz',
+ ),
+ ),
+ );
+
+ $this->assertSame($expected, $this->parser->parse($yaml, Yaml::PARSE_CONSTANT));
+ }
+
+ /**
+ * @group legacy
+ * @expectedDeprecation Using the Yaml::PARSE_KEYS_AS_STRINGS flag is deprecated since Symfony 3.4 as it will be removed in 4.0. Quote your keys when they are evaluable instead.
+ */
+ public function testPhpConstantTagMappingKeyWithKeysCastToStrings()
+ {
+ $yaml = <<<YAML
+transitions:
+ !php/const 'Symfony\Component\Yaml\Tests\B::FOO':
+ from:
+ - !php/const 'Symfony\Component\Yaml\Tests\B::BAR'
+ to: !php/const 'Symfony\Component\Yaml\Tests\B::BAZ'
+YAML;
+ $expected = array(
+ 'transitions' => array(
+ 'foo' => array(
+ 'from' => array(
+ 'bar',
+ ),
+ 'to' => 'baz',
+ ),
+ ),
+ );
+
+ $this->assertSame($expected, $this->parser->parse($yaml, Yaml::PARSE_CONSTANT | Yaml::PARSE_KEYS_AS_STRINGS));
+ }
+
+ public function testMergeKeysWhenMappingsAreParsedAsObjects()
+ {
+ $yaml = <<<YAML
+foo: &FOO
+ bar: 1
+bar: &BAR
+ baz: 2
+ <<: *FOO
+baz:
+ baz_foo: 3
+ <<:
+ baz_bar: 4
+foobar:
+ bar: ~
+ <<: [*FOO, *BAR]
+YAML;
+ $expected = (object) array(
+ 'foo' => (object) array(
+ 'bar' => 1,
+ ),
+ 'bar' => (object) array(
+ 'baz' => 2,
+ 'bar' => 1,
+ ),
+ 'baz' => (object) array(
+ 'baz_foo' => 3,
+ 'baz_bar' => 4,
+ ),
+ 'foobar' => (object) array(
+ 'bar' => null,
+ 'baz' => 2,
+ ),
+ );
+
+ $this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP));
+ }
+
+ public function testFilenamesAreParsedAsStringsWithoutFlag()
+ {
+ $file = __DIR__.'/Fixtures/index.yml';
+
+ $this->assertSame($file, $this->parser->parse($file));
+ }
+
+ public function testParseFile()
+ {
+ $this->assertInternalType('array', $this->parser->parseFile(__DIR__.'/Fixtures/index.yml'));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
+ * @expectedExceptionMessageRegExp #^File ".+/Fixtures/nonexistent.yml" does not exist\.$#
+ */
+ public function testParsingNonExistentFilesThrowsException()
+ {
+ $this->parser->parseFile(__DIR__.'/Fixtures/nonexistent.yml');
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
+ * @expectedExceptionMessageRegExp #^File ".+/Fixtures/not_readable.yml" cannot be read\.$#
+ */
+ public function testParsingNotReadableFilesThrowsException()
+ {
+ if ('\\' === \DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('chmod is not supported on Windows');
+ }
+
+ if (!getenv('USER') || 'root' === getenv('USER')) {
+ $this->markTestSkipped('This test will fail if run under superuser');
+ }
+
+ $file = __DIR__.'/Fixtures/not_readable.yml';
+ chmod($file, 0200);
+
+ $this->parser->parseFile($file);
+ }
+
+ public function testParseReferencesOnMergeKeys()
+ {
+ $yaml = <<<YAML
+mergekeyrefdef:
+ a: foo
+ <<: &quux
+ b: bar
+ c: baz
+mergekeyderef:
+ d: quux
+ <<: *quux
+YAML;
+ $expected = array(
+ 'mergekeyrefdef' => array(
+ 'a' => 'foo',
+ 'b' => 'bar',
+ 'c' => 'baz',
+ ),
+ 'mergekeyderef' => array(
+ 'd' => 'quux',
+ 'b' => 'bar',
+ 'c' => 'baz',
+ ),
+ );
+
+ $this->assertSame($expected, $this->parser->parse($yaml));
+ }
+
+ public function testParseReferencesOnMergeKeysWithMappingsParsedAsObjects()
+ {
+ $yaml = <<<YAML
+mergekeyrefdef:
+ a: foo
+ <<: &quux
+ b: bar
+ c: baz
+mergekeyderef:
+ d: quux
+ <<: *quux
+YAML;
+ $expected = (object) array(
+ 'mergekeyrefdef' => (object) array(
+ 'a' => 'foo',
+ 'b' => 'bar',
+ 'c' => 'baz',
+ ),
+ 'mergekeyderef' => (object) array(
+ 'd' => 'quux',
+ 'b' => 'bar',
+ 'c' => 'baz',
+ ),
+ );
+
+ $this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
+ * @expectedExceptionMessage Reference "foo" does not exist
+ */
+ public function testEvalRefException()
+ {
+ $yaml = <<<EOE
+foo: { &foo { a: Steve, <<: *foo} }
+EOE;
+ $this->parser->parse($yaml);
+ }
+
+ /**
+ * @dataProvider indentedMappingData
+ */
+ public function testParseIndentedMappings($yaml, $expected)
+ {
+ $this->assertSame($expected, $this->parser->parse($yaml));
+ }
+
+ public function indentedMappingData()
+ {
+ $tests = array();
+
+ $yaml = <<<YAML
+foo:
+ - bar: "foobar"
+ # A comment
+ baz: "foobaz"
+YAML;
+ $expected = array(
+ 'foo' => array(
+ array(
+ 'bar' => 'foobar',
+ 'baz' => 'foobaz',
+ ),
+ ),
+ );
+ $tests['comment line is first line in indented block'] = array($yaml, $expected);
+
+ $yaml = <<<YAML
+foo:
+ - bar:
+ # comment
+ baz: [1, 2, 3]
+YAML;
+ $expected = array(
+ 'foo' => array(
+ array(
+ 'bar' => array(
+ 'baz' => array(1, 2, 3),
+ ),
+ ),
+ ),
+ );
+ $tests['mapping value on new line starting with a comment line'] = array($yaml, $expected);
+
+ $yaml = <<<YAML
+foo:
+ -
+ bar: foobar
+YAML;
+ $expected = array(
+ 'foo' => array(
+ array(
+ 'bar' => 'foobar',
+ ),
+ ),
+ );
+ $tests['mapping in sequence starting on a new line'] = array($yaml, $expected);
+
+ $yaml = <<<YAML
+foo:
+
+ bar: baz
+YAML;
+ $expected = array(
+ 'foo' => array(
+ 'bar' => 'baz',
+ ),
+ );
+ $tests['blank line at the beginning of an indented mapping value'] = array($yaml, $expected);
+
+ return $tests;
+ }
}
class B
{
public $b = 'foo';
+
+ const FOO = 'foo';
+ const BAR = 'bar';
+ const BAZ = 'baz';
}