InlineTest.php (17633B)
1 <?php 2 3 /* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12 namespace Symfony\Component\Yaml\Tests; 13 14 use Symfony\Component\Yaml\Inline; 15 16 class InlineTest extends \PHPUnit_Framework_TestCase 17 { 18 /** 19 * @dataProvider getTestsForParse 20 */ 21 public function testParse($yaml, $value) 22 { 23 $this->assertSame($value, Inline::parse($yaml), sprintf('::parse() converts an inline YAML to a PHP structure (%s)', $yaml)); 24 } 25 26 /** 27 * @dataProvider getTestsForParseWithMapObjects 28 */ 29 public function testParseWithMapObjects($yaml, $value) 30 { 31 $actual = Inline::parse($yaml, false, false, true); 32 33 $this->assertSame(serialize($value), serialize($actual)); 34 } 35 36 /** 37 * @dataProvider getTestsForDump 38 */ 39 public function testDump($yaml, $value) 40 { 41 $this->assertEquals($yaml, Inline::dump($value), sprintf('::dump() converts a PHP structure to an inline YAML (%s)', $yaml)); 42 43 $this->assertSame($value, Inline::parse(Inline::dump($value)), 'check consistency'); 44 } 45 46 public function testDumpNumericValueWithLocale() 47 { 48 $locale = setlocale(LC_NUMERIC, 0); 49 if (false === $locale) { 50 $this->markTestSkipped('Your platform does not support locales.'); 51 } 52 53 try { 54 $requiredLocales = array('fr_FR.UTF-8', 'fr_FR.UTF8', 'fr_FR.utf-8', 'fr_FR.utf8', 'French_France.1252'); 55 if (false === setlocale(LC_NUMERIC, $requiredLocales)) { 56 $this->markTestSkipped('Could not set any of required locales: '.implode(', ', $requiredLocales)); 57 } 58 59 $this->assertEquals('1.2', Inline::dump(1.2)); 60 $this->assertContains('fr', strtolower(setlocale(LC_NUMERIC, 0))); 61 setlocale(LC_NUMERIC, $locale); 62 } catch (\Exception $e) { 63 setlocale(LC_NUMERIC, $locale); 64 throw $e; 65 } 66 } 67 68 public function testHashStringsResemblingExponentialNumericsShouldNotBeChangedToINF() 69 { 70 $value = '686e444'; 71 72 $this->assertSame($value, Inline::parse(Inline::dump($value))); 73 } 74 75 /** 76 * @expectedException \Symfony\Component\Yaml\Exception\ParseException 77 */ 78 public function testParseScalarWithIncorrectlyQuotedStringShouldThrowException() 79 { 80 $value = "'don't do somthin' like that'"; 81 Inline::parse($value); 82 } 83 84 /** 85 * @expectedException \Symfony\Component\Yaml\Exception\ParseException 86 */ 87 public function testParseScalarWithIncorrectlyDoubleQuotedStringShouldThrowException() 88 { 89 $value = '"don"t do somthin" like that"'; 90 Inline::parse($value); 91 } 92 93 /** 94 * @expectedException \Symfony\Component\Yaml\Exception\ParseException 95 */ 96 public function testParseInvalidMappingKeyShouldThrowException() 97 { 98 $value = '{ "foo " bar": "bar" }'; 99 Inline::parse($value); 100 } 101 102 /** 103 * @expectedException \Symfony\Component\Yaml\Exception\ParseException 104 */ 105 public function testParseInvalidMappingShouldThrowException() 106 { 107 Inline::parse('[foo] bar'); 108 } 109 110 /** 111 * @expectedException \Symfony\Component\Yaml\Exception\ParseException 112 */ 113 public function testParseInvalidSequenceShouldThrowException() 114 { 115 Inline::parse('{ foo: bar } bar'); 116 } 117 118 public function testParseScalarWithCorrectlyQuotedStringShouldReturnString() 119 { 120 $value = "'don''t do somthin'' like that'"; 121 $expect = "don't do somthin' like that"; 122 123 $this->assertSame($expect, Inline::parseScalar($value)); 124 } 125 126 /** 127 * @dataProvider getDataForParseReferences 128 */ 129 public function testParseReferences($yaml, $expected) 130 { 131 $this->assertSame($expected, Inline::parse($yaml, false, false, false, array('var' => 'var-value'))); 132 } 133 134 public function getDataForParseReferences() 135 { 136 return array( 137 'scalar' => array('*var', 'var-value'), 138 'list' => array('[ *var ]', array('var-value')), 139 'list-in-list' => array('[[ *var ]]', array(array('var-value'))), 140 'map-in-list' => array('[ { key: *var } ]', array(array('key' => 'var-value'))), 141 'embedded-mapping-in-list' => array('[ key: *var ]', array(array('key' => 'var-value'))), 142 'map' => array('{ key: *var }', array('key' => 'var-value')), 143 'list-in-map' => array('{ key: [*var] }', array('key' => array('var-value'))), 144 'map-in-map' => array('{ foo: { bar: *var } }', array('foo' => array('bar' => 'var-value'))), 145 ); 146 } 147 148 public function testParseMapReferenceInSequence() 149 { 150 $foo = array( 151 'a' => 'Steve', 152 'b' => 'Clark', 153 'c' => 'Brian', 154 ); 155 $this->assertSame(array($foo), Inline::parse('[*foo]', false, false, false, array('foo' => $foo))); 156 } 157 158 /** 159 * @expectedException \Symfony\Component\Yaml\Exception\ParseException 160 * @expectedExceptionMessage A reference must contain at least one character. 161 */ 162 public function testParseUnquotedAsterisk() 163 { 164 Inline::parse('{ foo: * }'); 165 } 166 167 /** 168 * @expectedException \Symfony\Component\Yaml\Exception\ParseException 169 * @expectedExceptionMessage A reference must contain at least one character. 170 */ 171 public function testParseUnquotedAsteriskFollowedByAComment() 172 { 173 Inline::parse('{ foo: * #foo }'); 174 } 175 176 public function getTestsForParse() 177 { 178 return array( 179 array('', ''), 180 array('null', null), 181 array('false', false), 182 array('true', true), 183 array('12', 12), 184 array('-12', -12), 185 array('"quoted string"', 'quoted string'), 186 array("'quoted string'", 'quoted string'), 187 array('12.30e+02', 12.30e+02), 188 array('0x4D2', 0x4D2), 189 array('02333', 02333), 190 array('.Inf', -log(0)), 191 array('-.Inf', log(0)), 192 array("'686e444'", '686e444'), 193 array('686e444', 646e444), 194 array('123456789123456789123456789123456789', '123456789123456789123456789123456789'), 195 array('"foo\r\nbar"', "foo\r\nbar"), 196 array("'foo#bar'", 'foo#bar'), 197 array("'foo # bar'", 'foo # bar'), 198 array("'#cfcfcf'", '#cfcfcf'), 199 array('::form_base.html.twig', '::form_base.html.twig'), 200 201 // Pre-YAML-1.2 booleans 202 array("'y'", 'y'), 203 array("'n'", 'n'), 204 array("'yes'", 'yes'), 205 array("'no'", 'no'), 206 array("'on'", 'on'), 207 array("'off'", 'off'), 208 209 array('2007-10-30', mktime(0, 0, 0, 10, 30, 2007)), 210 array('2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)), 211 array('2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)), 212 array('1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)), 213 array('1730-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 1730)), 214 215 array('"a \\"string\\" with \'quoted strings inside\'"', 'a "string" with \'quoted strings inside\''), 216 array("'a \"string\" with ''quoted strings inside'''", 'a "string" with \'quoted strings inside\''), 217 218 // sequences 219 // urls are no key value mapping. see #3609. Valid yaml "key: value" mappings require a space after the colon 220 array('[foo, http://urls.are/no/mappings, false, null, 12]', array('foo', 'http://urls.are/no/mappings', false, null, 12)), 221 array('[ foo , bar , false , null , 12 ]', array('foo', 'bar', false, null, 12)), 222 array('[\'foo,bar\', \'foo bar\']', array('foo,bar', 'foo bar')), 223 224 // mappings 225 array('{foo:bar,bar:foo,false:false,null:null,integer:12}', array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)), 226 array('{ foo : bar, bar : foo, false : false, null : null, integer : 12 }', array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)), 227 array('{foo: \'bar\', bar: \'foo: bar\'}', array('foo' => 'bar', 'bar' => 'foo: bar')), 228 array('{\'foo\': \'bar\', "bar": \'foo: bar\'}', array('foo' => 'bar', 'bar' => 'foo: bar')), 229 array('{\'foo\'\'\': \'bar\', "bar\"": \'foo: bar\'}', array('foo\'' => 'bar', 'bar"' => 'foo: bar')), 230 array('{\'foo: \': \'bar\', "bar: ": \'foo: bar\'}', array('foo: ' => 'bar', 'bar: ' => 'foo: bar')), 231 232 // nested sequences and mappings 233 array('[foo, [bar, foo]]', array('foo', array('bar', 'foo'))), 234 array('[foo, {bar: foo}]', array('foo', array('bar' => 'foo'))), 235 array('{ foo: {bar: foo} }', array('foo' => array('bar' => 'foo'))), 236 array('{ foo: [bar, foo] }', array('foo' => array('bar', 'foo'))), 237 238 array('[ foo, [ bar, foo ] ]', array('foo', array('bar', 'foo'))), 239 240 array('[{ foo: {bar: foo} }]', array(array('foo' => array('bar' => 'foo')))), 241 242 array('[foo, [bar, [foo, [bar, foo]], foo]]', array('foo', array('bar', array('foo', array('bar', 'foo')), 'foo'))), 243 244 array('[foo, {bar: foo, foo: [foo, {bar: foo}]}, [foo, {bar: foo}]]', array('foo', array('bar' => 'foo', 'foo' => array('foo', array('bar' => 'foo'))), array('foo', array('bar' => 'foo')))), 245 246 array('[foo, bar: { foo: bar }]', array('foo', '1' => array('bar' => array('foo' => 'bar')))), 247 array('[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']', array('foo', '@foo.baz', array('%foo%' => 'foo is %foo%', 'bar' => '%foo%'), true, '@service_container')), 248 ); 249 } 250 251 public function getTestsForParseWithMapObjects() 252 { 253 return array( 254 array('', ''), 255 array('null', null), 256 array('false', false), 257 array('true', true), 258 array('12', 12), 259 array('-12', -12), 260 array('"quoted string"', 'quoted string'), 261 array("'quoted string'", 'quoted string'), 262 array('12.30e+02', 12.30e+02), 263 array('0x4D2', 0x4D2), 264 array('02333', 02333), 265 array('.Inf', -log(0)), 266 array('-.Inf', log(0)), 267 array("'686e444'", '686e444'), 268 array('686e444', 646e444), 269 array('123456789123456789123456789123456789', '123456789123456789123456789123456789'), 270 array('"foo\r\nbar"', "foo\r\nbar"), 271 array("'foo#bar'", 'foo#bar'), 272 array("'foo # bar'", 'foo # bar'), 273 array("'#cfcfcf'", '#cfcfcf'), 274 array('::form_base.html.twig', '::form_base.html.twig'), 275 276 array('2007-10-30', mktime(0, 0, 0, 10, 30, 2007)), 277 array('2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)), 278 array('2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)), 279 array('1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)), 280 array('1730-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 1730)), 281 282 array('"a \\"string\\" with \'quoted strings inside\'"', 'a "string" with \'quoted strings inside\''), 283 array("'a \"string\" with ''quoted strings inside'''", 'a "string" with \'quoted strings inside\''), 284 285 // sequences 286 // urls are no key value mapping. see #3609. Valid yaml "key: value" mappings require a space after the colon 287 array('[foo, http://urls.are/no/mappings, false, null, 12]', array('foo', 'http://urls.are/no/mappings', false, null, 12)), 288 array('[ foo , bar , false , null , 12 ]', array('foo', 'bar', false, null, 12)), 289 array('[\'foo,bar\', \'foo bar\']', array('foo,bar', 'foo bar')), 290 291 // mappings 292 array('{foo:bar,bar:foo,false:false,null:null,integer:12}', (object) array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)), 293 array('{ foo : bar, bar : foo, false : false, null : null, integer : 12 }', (object) array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)), 294 array('{foo: \'bar\', bar: \'foo: bar\'}', (object) array('foo' => 'bar', 'bar' => 'foo: bar')), 295 array('{\'foo\': \'bar\', "bar": \'foo: bar\'}', (object) array('foo' => 'bar', 'bar' => 'foo: bar')), 296 array('{\'foo\'\'\': \'bar\', "bar\"": \'foo: bar\'}', (object) array('foo\'' => 'bar', 'bar"' => 'foo: bar')), 297 array('{\'foo: \': \'bar\', "bar: ": \'foo: bar\'}', (object) array('foo: ' => 'bar', 'bar: ' => 'foo: bar')), 298 299 // nested sequences and mappings 300 array('[foo, [bar, foo]]', array('foo', array('bar', 'foo'))), 301 array('[foo, {bar: foo}]', array('foo', (object) array('bar' => 'foo'))), 302 array('{ foo: {bar: foo} }', (object) array('foo' => (object) array('bar' => 'foo'))), 303 array('{ foo: [bar, foo] }', (object) array('foo' => array('bar', 'foo'))), 304 305 array('[ foo, [ bar, foo ] ]', array('foo', array('bar', 'foo'))), 306 307 array('[{ foo: {bar: foo} }]', array((object) array('foo' => (object) array('bar' => 'foo')))), 308 309 array('[foo, [bar, [foo, [bar, foo]], foo]]', array('foo', array('bar', array('foo', array('bar', 'foo')), 'foo'))), 310 311 array('[foo, {bar: foo, foo: [foo, {bar: foo}]}, [foo, {bar: foo}]]', array('foo', (object) array('bar' => 'foo', 'foo' => array('foo', (object) array('bar' => 'foo'))), array('foo', (object) array('bar' => 'foo')))), 312 313 array('[foo, bar: { foo: bar }]', array('foo', '1' => (object) array('bar' => (object) array('foo' => 'bar')))), 314 array('[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']', array('foo', '@foo.baz', (object) array('%foo%' => 'foo is %foo%', 'bar' => '%foo%'), true, '@service_container')), 315 316 array('{}', new \stdClass()), 317 array('{ foo : bar, bar : {} }', (object) array('foo' => 'bar', 'bar' => new \stdClass())), 318 array('{ foo : [], bar : {} }', (object) array('foo' => array(), 'bar' => new \stdClass())), 319 array('{foo: \'bar\', bar: {} }', (object) array('foo' => 'bar', 'bar' => new \stdClass())), 320 array('{\'foo\': \'bar\', "bar": {}}', (object) array('foo' => 'bar', 'bar' => new \stdClass())), 321 array('{\'foo\': \'bar\', "bar": \'{}\'}', (object) array('foo' => 'bar', 'bar' => '{}')), 322 323 array('[foo, [{}, {}]]', array('foo', array(new \stdClass(), new \stdClass()))), 324 array('[foo, [[], {}]]', array('foo', array(array(), new \stdClass()))), 325 array('[foo, [[{}, {}], {}]]', array('foo', array(array(new \stdClass(), new \stdClass()), new \stdClass()))), 326 array('[foo, {bar: {}}]', array('foo', '1' => (object) array('bar' => new \stdClass()))), 327 ); 328 } 329 330 public function getTestsForDump() 331 { 332 return array( 333 array('null', null), 334 array('false', false), 335 array('true', true), 336 array('12', 12), 337 array("'quoted string'", 'quoted string'), 338 array('!!float 1230', 12.30e+02), 339 array('1234', 0x4D2), 340 array('1243', 02333), 341 array('.Inf', -log(0)), 342 array('-.Inf', log(0)), 343 array("'686e444'", '686e444'), 344 array('"foo\r\nbar"', "foo\r\nbar"), 345 array("'foo#bar'", 'foo#bar'), 346 array("'foo # bar'", 'foo # bar'), 347 array("'#cfcfcf'", '#cfcfcf'), 348 349 array("'a \"string\" with ''quoted strings inside'''", 'a "string" with \'quoted strings inside\''), 350 351 array("'-dash'", '-dash'), 352 array("'-'", '-'), 353 354 // Pre-YAML-1.2 booleans 355 array("'y'", 'y'), 356 array("'n'", 'n'), 357 array("'yes'", 'yes'), 358 array("'no'", 'no'), 359 array("'on'", 'on'), 360 array("'off'", 'off'), 361 362 // sequences 363 array('[foo, bar, false, null, 12]', array('foo', 'bar', false, null, 12)), 364 array('[\'foo,bar\', \'foo bar\']', array('foo,bar', 'foo bar')), 365 366 // mappings 367 array('{ foo: bar, bar: foo, \'false\': false, \'null\': null, integer: 12 }', array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)), 368 array('{ foo: bar, bar: \'foo: bar\' }', array('foo' => 'bar', 'bar' => 'foo: bar')), 369 370 // nested sequences and mappings 371 array('[foo, [bar, foo]]', array('foo', array('bar', 'foo'))), 372 373 array('[foo, [bar, [foo, [bar, foo]], foo]]', array('foo', array('bar', array('foo', array('bar', 'foo')), 'foo'))), 374 375 array('{ foo: { bar: foo } }', array('foo' => array('bar' => 'foo'))), 376 377 array('[foo, { bar: foo }]', array('foo', array('bar' => 'foo'))), 378 379 array('[foo, { bar: foo, foo: [foo, { bar: foo }] }, [foo, { bar: foo }]]', array('foo', array('bar' => 'foo', 'foo' => array('foo', array('bar' => 'foo'))), array('foo', array('bar' => 'foo')))), 380 381 array('[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']', array('foo', '@foo.baz', array('%foo%' => 'foo is %foo%', 'bar' => '%foo%'), true, '@service_container')), 382 ); 383 } 384 }