1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Symfony package. |
5
|
|
|
* |
6
|
|
|
* (c) Fabien Potencier <[email protected]> |
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 PHPUnit\Framework\TestCase; |
15
|
|
|
use Symfony\Component\Yaml\Parser; |
16
|
|
|
use Symfony\Component\Yaml\Tag\TaggedValue; |
17
|
|
|
use Symfony\Component\Yaml\Yaml; |
18
|
|
|
|
19
|
|
|
class ParserTest extends TestCase |
20
|
|
|
{ |
21
|
|
|
/** @var Parser */ |
22
|
|
|
protected $parser; |
23
|
|
|
|
24
|
|
|
protected function setUp() |
25
|
|
|
{ |
26
|
|
|
$this->parser = new Parser(); |
27
|
|
|
} |
28
|
|
|
|
29
|
|
|
protected function tearDown() |
30
|
|
|
{ |
31
|
|
|
$this->parser = null; |
32
|
|
|
|
33
|
|
|
chmod(__DIR__.'/Fixtures/not_readable.yml', 0644); |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @dataProvider getDataFormSpecifications |
38
|
|
|
*/ |
39
|
|
|
public function testSpecifications($expected, $yaml, $comment, $deprecated) |
40
|
|
|
{ |
41
|
|
|
$deprecations = []; |
42
|
|
|
|
43
|
|
|
if ($deprecated) { |
44
|
|
|
set_error_handler(function ($type, $msg) use (&$deprecations) { |
45
|
|
|
if (\E_USER_DEPRECATED !== $type) { |
46
|
|
|
restore_error_handler(); |
47
|
|
|
|
48
|
|
|
return \call_user_func_array('PHPUnit\Util\ErrorHandler::handleError', \func_get_args()); |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
$deprecations[] = $msg; |
52
|
|
|
|
53
|
|
|
return null; |
54
|
|
|
}); |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
$this->assertEquals($expected, var_export($this->parser->parse($yaml), true), $comment); |
58
|
|
|
|
59
|
|
|
if ($deprecated) { |
60
|
|
|
restore_error_handler(); |
61
|
|
|
|
62
|
|
|
$this->assertCount(1, $deprecations); |
63
|
|
|
$this->assertStringContainsString(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]); |
64
|
|
|
} |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
public function getDataFormSpecifications() |
68
|
|
|
{ |
69
|
|
|
return $this->loadTestsFromFixtureFiles('index.yml'); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @group legacy |
74
|
|
|
* @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 |
75
|
|
|
* @dataProvider getNonStringMappingKeysData |
76
|
|
|
*/ |
77
|
|
|
public function testNonStringMappingKeys($expected, $yaml, $comment) |
78
|
|
|
{ |
79
|
|
|
$this->assertSame($expected, var_export($this->parser->parse($yaml, Yaml::PARSE_KEYS_AS_STRINGS), true), $comment); |
|
|
|
|
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
public function getNonStringMappingKeysData() |
83
|
|
|
{ |
84
|
|
|
return $this->loadTestsFromFixtureFiles('nonStringKeys.yml'); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* @group legacy |
89
|
|
|
* @dataProvider getLegacyNonStringMappingKeysData |
90
|
|
|
*/ |
91
|
|
|
public function testLegacyNonStringMappingKeys($expected, $yaml, $comment) |
92
|
|
|
{ |
93
|
|
|
$this->assertSame($expected, var_export($this->parser->parse($yaml), true), $comment); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
public function getLegacyNonStringMappingKeysData() |
97
|
|
|
{ |
98
|
|
|
return $this->loadTestsFromFixtureFiles('legacyNonStringKeys.yml'); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
public function testTabsInYaml() |
102
|
|
|
{ |
103
|
|
|
// test tabs in YAML |
104
|
|
|
$yamls = [ |
105
|
|
|
"foo:\n bar", |
106
|
|
|
"foo:\n bar", |
107
|
|
|
"foo:\n bar", |
108
|
|
|
"foo:\n bar", |
109
|
|
|
]; |
110
|
|
|
|
111
|
|
|
foreach ($yamls as $yaml) { |
112
|
|
|
try { |
113
|
|
|
$this->parser->parse($yaml); |
114
|
|
|
|
115
|
|
|
$this->fail('YAML files must not contain tabs'); |
116
|
|
|
} catch (\Exception $e) { |
117
|
|
|
$this->assertInstanceOf('\Exception', $e, 'YAML files must not contain tabs'); |
118
|
|
|
$this->assertEquals('A YAML file cannot contain tabs as indentation at line 2 (near "'.strpbrk($yaml, "\t").'").', $e->getMessage(), 'YAML files must not contain tabs'); |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
public function testEndOfTheDocumentMarker() |
124
|
|
|
{ |
125
|
|
|
$yaml = <<<'EOF' |
126
|
|
|
--- %YAML:1.0 |
127
|
|
|
foo |
128
|
|
|
... |
129
|
|
|
EOF; |
130
|
|
|
|
131
|
|
|
$this->assertEquals('foo', $this->parser->parse($yaml)); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
public function getBlockChompingTests() |
135
|
|
|
{ |
136
|
|
|
$tests = []; |
137
|
|
|
|
138
|
|
|
$yaml = <<<'EOF' |
139
|
|
|
foo: |- |
140
|
|
|
one |
141
|
|
|
two |
142
|
|
|
bar: |- |
143
|
|
|
one |
144
|
|
|
two |
145
|
|
|
|
146
|
|
|
EOF; |
147
|
|
|
$expected = [ |
148
|
|
|
'foo' => "one\ntwo", |
149
|
|
|
'bar' => "one\ntwo", |
150
|
|
|
]; |
151
|
|
|
$tests['Literal block chomping strip with single trailing newline'] = [$expected, $yaml]; |
152
|
|
|
|
153
|
|
|
$yaml = <<<'EOF' |
154
|
|
|
foo: |- |
155
|
|
|
one |
156
|
|
|
two |
157
|
|
|
|
158
|
|
|
bar: |- |
159
|
|
|
one |
160
|
|
|
two |
161
|
|
|
|
162
|
|
|
|
163
|
|
|
EOF; |
164
|
|
|
$expected = [ |
165
|
|
|
'foo' => "one\ntwo", |
166
|
|
|
'bar' => "one\ntwo", |
167
|
|
|
]; |
168
|
|
|
$tests['Literal block chomping strip with multiple trailing newlines'] = [$expected, $yaml]; |
169
|
|
|
|
170
|
|
|
$yaml = <<<'EOF' |
171
|
|
|
{} |
172
|
|
|
|
173
|
|
|
|
174
|
|
|
EOF; |
175
|
|
|
$expected = []; |
176
|
|
|
$tests['Literal block chomping strip with multiple trailing newlines after a 1-liner'] = [$expected, $yaml]; |
177
|
|
|
|
178
|
|
|
$yaml = <<<'EOF' |
179
|
|
|
foo: |- |
180
|
|
|
one |
181
|
|
|
two |
182
|
|
|
bar: |- |
183
|
|
|
one |
184
|
|
|
two |
185
|
|
|
EOF; |
186
|
|
|
$expected = [ |
187
|
|
|
'foo' => "one\ntwo", |
188
|
|
|
'bar' => "one\ntwo", |
189
|
|
|
]; |
190
|
|
|
$tests['Literal block chomping strip without trailing newline'] = [$expected, $yaml]; |
191
|
|
|
|
192
|
|
|
$yaml = <<<'EOF' |
193
|
|
|
foo: | |
194
|
|
|
one |
195
|
|
|
two |
196
|
|
|
bar: | |
197
|
|
|
one |
198
|
|
|
two |
199
|
|
|
|
200
|
|
|
EOF; |
201
|
|
|
$expected = [ |
202
|
|
|
'foo' => "one\ntwo\n", |
203
|
|
|
'bar' => "one\ntwo\n", |
204
|
|
|
]; |
205
|
|
|
$tests['Literal block chomping clip with single trailing newline'] = [$expected, $yaml]; |
206
|
|
|
|
207
|
|
|
$yaml = <<<'EOF' |
208
|
|
|
foo: | |
209
|
|
|
one |
210
|
|
|
two |
211
|
|
|
|
212
|
|
|
bar: | |
213
|
|
|
one |
214
|
|
|
two |
215
|
|
|
|
216
|
|
|
|
217
|
|
|
EOF; |
218
|
|
|
$expected = [ |
219
|
|
|
'foo' => "one\ntwo\n", |
220
|
|
|
'bar' => "one\ntwo\n", |
221
|
|
|
]; |
222
|
|
|
$tests['Literal block chomping clip with multiple trailing newlines'] = [$expected, $yaml]; |
223
|
|
|
|
224
|
|
|
$yaml = <<<'EOF' |
225
|
|
|
foo: |
226
|
|
|
- bar: | |
227
|
|
|
one |
228
|
|
|
|
229
|
|
|
two |
230
|
|
|
EOF; |
231
|
|
|
$expected = [ |
232
|
|
|
'foo' => [ |
233
|
|
|
[ |
234
|
|
|
'bar' => "one\n\ntwo", |
235
|
|
|
], |
236
|
|
|
], |
237
|
|
|
]; |
238
|
|
|
$tests['Literal block chomping clip with embedded blank line inside unindented collection'] = [$expected, $yaml]; |
239
|
|
|
|
240
|
|
|
$yaml = <<<'EOF' |
241
|
|
|
foo: | |
242
|
|
|
one |
243
|
|
|
two |
244
|
|
|
bar: | |
245
|
|
|
one |
246
|
|
|
two |
247
|
|
|
EOF; |
248
|
|
|
$expected = [ |
249
|
|
|
'foo' => "one\ntwo\n", |
250
|
|
|
'bar' => "one\ntwo", |
251
|
|
|
]; |
252
|
|
|
$tests['Literal block chomping clip without trailing newline'] = [$expected, $yaml]; |
253
|
|
|
|
254
|
|
|
$yaml = <<<'EOF' |
255
|
|
|
foo: |+ |
256
|
|
|
one |
257
|
|
|
two |
258
|
|
|
bar: |+ |
259
|
|
|
one |
260
|
|
|
two |
261
|
|
|
|
262
|
|
|
EOF; |
263
|
|
|
$expected = [ |
264
|
|
|
'foo' => "one\ntwo\n", |
265
|
|
|
'bar' => "one\ntwo\n", |
266
|
|
|
]; |
267
|
|
|
$tests['Literal block chomping keep with single trailing newline'] = [$expected, $yaml]; |
268
|
|
|
|
269
|
|
|
$yaml = <<<'EOF' |
270
|
|
|
foo: |+ |
271
|
|
|
one |
272
|
|
|
two |
273
|
|
|
|
274
|
|
|
bar: |+ |
275
|
|
|
one |
276
|
|
|
two |
277
|
|
|
|
278
|
|
|
|
279
|
|
|
EOF; |
280
|
|
|
$expected = [ |
281
|
|
|
'foo' => "one\ntwo\n\n", |
282
|
|
|
'bar' => "one\ntwo\n\n", |
283
|
|
|
]; |
284
|
|
|
$tests['Literal block chomping keep with multiple trailing newlines'] = [$expected, $yaml]; |
285
|
|
|
|
286
|
|
|
$yaml = <<<'EOF' |
287
|
|
|
foo: |+ |
288
|
|
|
one |
289
|
|
|
two |
290
|
|
|
bar: |+ |
291
|
|
|
one |
292
|
|
|
two |
293
|
|
|
EOF; |
294
|
|
|
$expected = [ |
295
|
|
|
'foo' => "one\ntwo\n", |
296
|
|
|
'bar' => "one\ntwo", |
297
|
|
|
]; |
298
|
|
|
$tests['Literal block chomping keep without trailing newline'] = [$expected, $yaml]; |
299
|
|
|
|
300
|
|
|
$yaml = <<<'EOF' |
301
|
|
|
foo: >- |
302
|
|
|
one |
303
|
|
|
two |
304
|
|
|
bar: >- |
305
|
|
|
one |
306
|
|
|
two |
307
|
|
|
|
308
|
|
|
EOF; |
309
|
|
|
$expected = [ |
310
|
|
|
'foo' => 'one two', |
311
|
|
|
'bar' => 'one two', |
312
|
|
|
]; |
313
|
|
|
$tests['Folded block chomping strip with single trailing newline'] = [$expected, $yaml]; |
314
|
|
|
|
315
|
|
|
$yaml = <<<'EOF' |
316
|
|
|
foo: >- |
317
|
|
|
one |
318
|
|
|
two |
319
|
|
|
|
320
|
|
|
bar: >- |
321
|
|
|
one |
322
|
|
|
two |
323
|
|
|
|
324
|
|
|
|
325
|
|
|
EOF; |
326
|
|
|
$expected = [ |
327
|
|
|
'foo' => 'one two', |
328
|
|
|
'bar' => 'one two', |
329
|
|
|
]; |
330
|
|
|
$tests['Folded block chomping strip with multiple trailing newlines'] = [$expected, $yaml]; |
331
|
|
|
|
332
|
|
|
$yaml = <<<'EOF' |
333
|
|
|
foo: >- |
334
|
|
|
one |
335
|
|
|
two |
336
|
|
|
bar: >- |
337
|
|
|
one |
338
|
|
|
two |
339
|
|
|
EOF; |
340
|
|
|
$expected = [ |
341
|
|
|
'foo' => 'one two', |
342
|
|
|
'bar' => 'one two', |
343
|
|
|
]; |
344
|
|
|
$tests['Folded block chomping strip without trailing newline'] = [$expected, $yaml]; |
345
|
|
|
|
346
|
|
|
$yaml = <<<'EOF' |
347
|
|
|
foo: > |
348
|
|
|
one |
349
|
|
|
two |
350
|
|
|
bar: > |
351
|
|
|
one |
352
|
|
|
two |
353
|
|
|
|
354
|
|
|
EOF; |
355
|
|
|
$expected = [ |
356
|
|
|
'foo' => "one two\n", |
357
|
|
|
'bar' => "one two\n", |
358
|
|
|
]; |
359
|
|
|
$tests['Folded block chomping clip with single trailing newline'] = [$expected, $yaml]; |
360
|
|
|
|
361
|
|
|
$yaml = <<<'EOF' |
362
|
|
|
foo: > |
363
|
|
|
one |
364
|
|
|
two |
365
|
|
|
|
366
|
|
|
bar: > |
367
|
|
|
one |
368
|
|
|
two |
369
|
|
|
|
370
|
|
|
|
371
|
|
|
EOF; |
372
|
|
|
$expected = [ |
373
|
|
|
'foo' => "one two\n", |
374
|
|
|
'bar' => "one two\n", |
375
|
|
|
]; |
376
|
|
|
$tests['Folded block chomping clip with multiple trailing newlines'] = [$expected, $yaml]; |
377
|
|
|
|
378
|
|
|
$yaml = <<<'EOF' |
379
|
|
|
foo: > |
380
|
|
|
one |
381
|
|
|
two |
382
|
|
|
bar: > |
383
|
|
|
one |
384
|
|
|
two |
385
|
|
|
EOF; |
386
|
|
|
$expected = [ |
387
|
|
|
'foo' => "one two\n", |
388
|
|
|
'bar' => 'one two', |
389
|
|
|
]; |
390
|
|
|
$tests['Folded block chomping clip without trailing newline'] = [$expected, $yaml]; |
391
|
|
|
|
392
|
|
|
$yaml = <<<'EOF' |
393
|
|
|
foo: >+ |
394
|
|
|
one |
395
|
|
|
two |
396
|
|
|
bar: >+ |
397
|
|
|
one |
398
|
|
|
two |
399
|
|
|
|
400
|
|
|
EOF; |
401
|
|
|
$expected = [ |
402
|
|
|
'foo' => "one two\n", |
403
|
|
|
'bar' => "one two\n", |
404
|
|
|
]; |
405
|
|
|
$tests['Folded block chomping keep with single trailing newline'] = [$expected, $yaml]; |
406
|
|
|
|
407
|
|
|
$yaml = <<<'EOF' |
408
|
|
|
foo: >+ |
409
|
|
|
one |
410
|
|
|
two |
411
|
|
|
|
412
|
|
|
bar: >+ |
413
|
|
|
one |
414
|
|
|
two |
415
|
|
|
|
416
|
|
|
|
417
|
|
|
EOF; |
418
|
|
|
$expected = [ |
419
|
|
|
'foo' => "one two\n\n", |
420
|
|
|
'bar' => "one two\n\n", |
421
|
|
|
]; |
422
|
|
|
$tests['Folded block chomping keep with multiple trailing newlines'] = [$expected, $yaml]; |
423
|
|
|
|
424
|
|
|
$yaml = <<<'EOF' |
425
|
|
|
foo: >+ |
426
|
|
|
one |
427
|
|
|
two |
428
|
|
|
bar: >+ |
429
|
|
|
one |
430
|
|
|
two |
431
|
|
|
EOF; |
432
|
|
|
$expected = [ |
433
|
|
|
'foo' => "one two\n", |
434
|
|
|
'bar' => 'one two', |
435
|
|
|
]; |
436
|
|
|
$tests['Folded block chomping keep without trailing newline'] = [$expected, $yaml]; |
437
|
|
|
|
438
|
|
|
return $tests; |
439
|
|
|
} |
440
|
|
|
|
441
|
|
|
/** |
442
|
|
|
* @dataProvider getBlockChompingTests |
443
|
|
|
*/ |
444
|
|
|
public function testBlockChomping($expected, $yaml) |
445
|
|
|
{ |
446
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
447
|
|
|
} |
448
|
|
|
|
449
|
|
|
/** |
450
|
|
|
* Regression test for issue #7989. |
451
|
|
|
* |
452
|
|
|
* @see https://github.com/symfony/symfony/issues/7989 |
453
|
|
|
*/ |
454
|
|
|
public function testBlockLiteralWithLeadingNewlines() |
455
|
|
|
{ |
456
|
|
|
$yaml = <<<'EOF' |
457
|
|
|
foo: |- |
458
|
|
|
|
459
|
|
|
|
460
|
|
|
bar |
461
|
|
|
|
462
|
|
|
EOF; |
463
|
|
|
$expected = [ |
464
|
|
|
'foo' => "\n\nbar", |
465
|
|
|
]; |
466
|
|
|
|
467
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
468
|
|
|
} |
469
|
|
|
|
470
|
|
|
public function testObjectSupportEnabled() |
471
|
|
|
{ |
472
|
|
|
$input = <<<'EOF' |
473
|
|
|
foo: !php/object O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";} |
474
|
|
|
bar: 1 |
475
|
|
|
EOF; |
476
|
|
|
$this->assertEquals(['foo' => new B(), 'bar' => 1], $this->parser->parse($input, Yaml::PARSE_OBJECT), '->parse() is able to parse objects'); |
477
|
|
|
} |
478
|
|
|
|
479
|
|
|
/** |
480
|
|
|
* @group legacy |
481
|
|
|
*/ |
482
|
|
|
public function testObjectSupportEnabledPassingTrue() |
483
|
|
|
{ |
484
|
|
|
$input = <<<'EOF' |
485
|
|
|
foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";} |
486
|
|
|
bar: 1 |
487
|
|
|
EOF; |
488
|
|
|
$this->assertEquals(['foo' => new B(), 'bar' => 1], $this->parser->parse($input, false, true), '->parse() is able to parse objects'); |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
/** |
492
|
|
|
* @group legacy |
493
|
|
|
* @dataProvider deprecatedObjectValueProvider |
494
|
|
|
*/ |
495
|
|
|
public function testObjectSupportEnabledWithDeprecatedTag($yaml) |
496
|
|
|
{ |
497
|
|
|
$this->assertEquals(['foo' => new B(), 'bar' => 1], $this->parser->parse($yaml, Yaml::PARSE_OBJECT), '->parse() is able to parse objects'); |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
public function deprecatedObjectValueProvider() |
501
|
|
|
{ |
502
|
|
|
return [ |
503
|
|
|
[ |
504
|
|
|
<<<YAML |
505
|
|
|
foo: !!php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";} |
506
|
|
|
bar: 1 |
507
|
|
|
YAML |
508
|
|
|
], |
509
|
|
|
[ |
510
|
|
|
<<<YAML |
511
|
|
|
foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";} |
512
|
|
|
bar: 1 |
513
|
|
|
YAML |
514
|
|
|
], |
515
|
|
|
]; |
516
|
|
|
} |
517
|
|
|
|
518
|
|
|
/** |
519
|
|
|
* @dataProvider invalidDumpedObjectProvider |
520
|
|
|
*/ |
521
|
|
|
public function testObjectSupportDisabledButNoExceptions($input) |
522
|
|
|
{ |
523
|
|
|
$this->assertEquals(['foo' => null, 'bar' => 1], $this->parser->parse($input), '->parse() does not parse objects'); |
524
|
|
|
} |
525
|
|
|
|
526
|
|
|
/** |
527
|
|
|
* @dataProvider getObjectForMapTests |
528
|
|
|
*/ |
529
|
|
|
public function testObjectForMap($yaml, $expected) |
530
|
|
|
{ |
531
|
|
|
$flags = Yaml::PARSE_OBJECT_FOR_MAP; |
532
|
|
|
|
533
|
|
|
$this->assertEquals($expected, $this->parser->parse($yaml, $flags)); |
534
|
|
|
} |
535
|
|
|
|
536
|
|
|
/** |
537
|
|
|
* @group legacy |
538
|
|
|
* @dataProvider getObjectForMapTests |
539
|
|
|
*/ |
540
|
|
|
public function testObjectForMapEnabledWithMappingUsingBooleanToggles($yaml, $expected) |
541
|
|
|
{ |
542
|
|
|
$this->assertEquals($expected, $this->parser->parse($yaml, false, false, true)); |
543
|
|
|
} |
544
|
|
|
|
545
|
|
|
public function getObjectForMapTests() |
546
|
|
|
{ |
547
|
|
|
$tests = []; |
548
|
|
|
|
549
|
|
|
$yaml = <<<'EOF' |
550
|
|
|
foo: |
551
|
|
|
fiz: [cat] |
552
|
|
|
EOF; |
553
|
|
|
$expected = new \stdClass(); |
554
|
|
|
$expected->foo = new \stdClass(); |
555
|
|
|
$expected->foo->fiz = ['cat']; |
556
|
|
|
$tests['mapping'] = [$yaml, $expected]; |
557
|
|
|
|
558
|
|
|
$yaml = '{ "foo": "bar", "fiz": "cat" }'; |
559
|
|
|
$expected = new \stdClass(); |
560
|
|
|
$expected->foo = 'bar'; |
561
|
|
|
$expected->fiz = 'cat'; |
562
|
|
|
$tests['inline-mapping'] = [$yaml, $expected]; |
563
|
|
|
|
564
|
|
|
$yaml = "foo: bar\nbaz: foobar"; |
565
|
|
|
$expected = new \stdClass(); |
566
|
|
|
$expected->foo = 'bar'; |
567
|
|
|
$expected->baz = 'foobar'; |
568
|
|
|
$tests['object-for-map-is-applied-after-parsing'] = [$yaml, $expected]; |
569
|
|
|
|
570
|
|
|
$yaml = <<<'EOT' |
571
|
|
|
array: |
572
|
|
|
- key: one |
573
|
|
|
- key: two |
574
|
|
|
EOT; |
575
|
|
|
$expected = new \stdClass(); |
576
|
|
|
$expected->array = []; |
577
|
|
|
$expected->array[0] = new \stdClass(); |
578
|
|
|
$expected->array[0]->key = 'one'; |
579
|
|
|
$expected->array[1] = new \stdClass(); |
580
|
|
|
$expected->array[1]->key = 'two'; |
581
|
|
|
$tests['nest-map-and-sequence'] = [$yaml, $expected]; |
582
|
|
|
|
583
|
|
|
$yaml = <<<'YAML' |
584
|
|
|
map: |
585
|
|
|
1: one |
586
|
|
|
2: two |
587
|
|
|
YAML; |
588
|
|
|
$expected = new \stdClass(); |
589
|
|
|
$expected->map = new \stdClass(); |
590
|
|
|
$expected->map->{1} = 'one'; |
591
|
|
|
$expected->map->{2} = 'two'; |
592
|
|
|
$tests['numeric-keys'] = [$yaml, $expected]; |
593
|
|
|
|
594
|
|
|
$yaml = <<<'YAML' |
595
|
|
|
map: |
596
|
|
|
'0': one |
597
|
|
|
'1': two |
598
|
|
|
YAML; |
599
|
|
|
$expected = new \stdClass(); |
600
|
|
|
$expected->map = new \stdClass(); |
601
|
|
|
$expected->map->{0} = 'one'; |
602
|
|
|
$expected->map->{1} = 'two'; |
603
|
|
|
$tests['zero-indexed-numeric-keys'] = [$yaml, $expected]; |
604
|
|
|
|
605
|
|
|
return $tests; |
606
|
|
|
} |
607
|
|
|
|
608
|
|
|
/** |
609
|
|
|
* @dataProvider invalidDumpedObjectProvider |
610
|
|
|
*/ |
611
|
|
|
public function testObjectsSupportDisabledWithExceptions($yaml) |
612
|
|
|
{ |
613
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
614
|
|
|
$this->parser->parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE); |
615
|
|
|
} |
616
|
|
|
|
617
|
|
|
public function testCanParseContentWithTrailingSpaces() |
618
|
|
|
{ |
619
|
|
|
$yaml = "items: \n foo: bar"; |
620
|
|
|
|
621
|
|
|
$expected = [ |
622
|
|
|
'items' => ['foo' => 'bar'], |
623
|
|
|
]; |
624
|
|
|
|
625
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
626
|
|
|
} |
627
|
|
|
|
628
|
|
|
/** |
629
|
|
|
* @group legacy |
630
|
|
|
* @dataProvider invalidDumpedObjectProvider |
631
|
|
|
*/ |
632
|
|
|
public function testObjectsSupportDisabledWithExceptionsUsingBooleanToggles($yaml) |
633
|
|
|
{ |
634
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
635
|
|
|
$this->parser->parse($yaml, true); |
636
|
|
|
} |
637
|
|
|
|
638
|
|
|
public function invalidDumpedObjectProvider() |
639
|
|
|
{ |
640
|
|
|
$yamlTag = <<<'EOF' |
641
|
|
|
foo: !!php/object:O:30:"Symfony\Tests\Component\Yaml\B":1:{s:1:"b";s:3:"foo";} |
642
|
|
|
bar: 1 |
643
|
|
|
EOF; |
644
|
|
|
$localTag = <<<'EOF' |
645
|
|
|
foo: !php/object:O:30:"Symfony\Tests\Component\Yaml\B":1:{s:1:"b";s:3:"foo";} |
646
|
|
|
bar: 1 |
647
|
|
|
EOF; |
648
|
|
|
|
649
|
|
|
return [ |
650
|
|
|
'yaml-tag' => [$yamlTag], |
651
|
|
|
'local-tag' => [$localTag], |
652
|
|
|
]; |
653
|
|
|
} |
654
|
|
|
|
655
|
|
|
/** |
656
|
|
|
* @requires extension iconv |
657
|
|
|
*/ |
658
|
|
|
public function testNonUtf8Exception() |
659
|
|
|
{ |
660
|
|
|
$yamls = [ |
661
|
|
|
iconv('UTF-8', 'ISO-8859-1', "foo: 'äöüß'"), |
662
|
|
|
iconv('UTF-8', 'ISO-8859-15', "euro: '€'"), |
663
|
|
|
iconv('UTF-8', 'CP1252', "cp1252: '©ÉÇáñ'"), |
664
|
|
|
]; |
665
|
|
|
|
666
|
|
|
foreach ($yamls as $yaml) { |
667
|
|
|
try { |
668
|
|
|
$this->parser->parse($yaml); |
669
|
|
|
|
670
|
|
|
$this->fail('charsets other than UTF-8 are rejected.'); |
671
|
|
|
} catch (\Exception $e) { |
672
|
|
|
$this->assertInstanceOf('Symfony\Component\Yaml\Exception\ParseException', $e, 'charsets other than UTF-8 are rejected.'); |
673
|
|
|
} |
674
|
|
|
} |
675
|
|
|
} |
676
|
|
|
|
677
|
|
|
public function testUnindentedCollectionException() |
678
|
|
|
{ |
679
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
680
|
|
|
$yaml = <<<'EOF' |
681
|
|
|
|
682
|
|
|
collection: |
683
|
|
|
-item1 |
684
|
|
|
-item2 |
685
|
|
|
-item3 |
686
|
|
|
|
687
|
|
|
EOF; |
688
|
|
|
|
689
|
|
|
$this->parser->parse($yaml); |
690
|
|
|
} |
691
|
|
|
|
692
|
|
|
public function testShortcutKeyUnindentedCollectionException() |
693
|
|
|
{ |
694
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
695
|
|
|
$yaml = <<<'EOF' |
696
|
|
|
|
697
|
|
|
collection: |
698
|
|
|
- key: foo |
699
|
|
|
foo: bar |
700
|
|
|
|
701
|
|
|
EOF; |
702
|
|
|
|
703
|
|
|
$this->parser->parse($yaml); |
704
|
|
|
} |
705
|
|
|
|
706
|
|
|
public function testMultipleDocumentsNotSupportedException() |
707
|
|
|
{ |
708
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
709
|
|
|
$this->expectExceptionMessageMatches('/^Multiple documents are not supported.+/'); |
|
|
|
|
710
|
|
|
Yaml::parse(<<<'EOL' |
711
|
|
|
# Ranking of 1998 home runs |
712
|
|
|
--- |
713
|
|
|
- Mark McGwire |
714
|
|
|
- Sammy Sosa |
715
|
|
|
- Ken Griffey |
716
|
|
|
|
717
|
|
|
# Team ranking |
718
|
|
|
--- |
719
|
|
|
- Chicago Cubs |
720
|
|
|
- St Louis Cardinals |
721
|
|
|
EOL |
722
|
|
|
); |
723
|
|
|
} |
724
|
|
|
|
725
|
|
|
public function testSequenceInAMapping() |
726
|
|
|
{ |
727
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
728
|
|
|
Yaml::parse(<<<'EOF' |
729
|
|
|
yaml: |
730
|
|
|
hash: me |
731
|
|
|
- array stuff |
732
|
|
|
EOF |
733
|
|
|
); |
734
|
|
|
} |
735
|
|
|
|
736
|
|
|
public function testSequenceInMappingStartedBySingleDashLine() |
737
|
|
|
{ |
738
|
|
|
$yaml = <<<'EOT' |
739
|
|
|
a: |
740
|
|
|
- |
741
|
|
|
b: |
742
|
|
|
- |
743
|
|
|
bar: baz |
744
|
|
|
- foo |
745
|
|
|
d: e |
746
|
|
|
EOT; |
747
|
|
|
$expected = [ |
748
|
|
|
'a' => [ |
749
|
|
|
[ |
750
|
|
|
'b' => [ |
751
|
|
|
[ |
752
|
|
|
'bar' => 'baz', |
753
|
|
|
], |
754
|
|
|
], |
755
|
|
|
], |
756
|
|
|
'foo', |
757
|
|
|
], |
758
|
|
|
'd' => 'e', |
759
|
|
|
]; |
760
|
|
|
|
761
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
762
|
|
|
} |
763
|
|
|
|
764
|
|
|
public function testSequenceFollowedByCommentEmbeddedInMapping() |
765
|
|
|
{ |
766
|
|
|
$yaml = <<<'EOT' |
767
|
|
|
a: |
768
|
|
|
b: |
769
|
|
|
- c |
770
|
|
|
# comment |
771
|
|
|
d: e |
772
|
|
|
EOT; |
773
|
|
|
$expected = [ |
774
|
|
|
'a' => [ |
775
|
|
|
'b' => ['c'], |
776
|
|
|
'd' => 'e', |
777
|
|
|
], |
778
|
|
|
]; |
779
|
|
|
|
780
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
781
|
|
|
} |
782
|
|
|
|
783
|
|
|
public function testNonStringFollowedByCommentEmbeddedInMapping() |
784
|
|
|
{ |
785
|
|
|
$yaml = <<<'EOT' |
786
|
|
|
a: |
787
|
|
|
b: |
788
|
|
|
{} |
789
|
|
|
# comment |
790
|
|
|
d: |
791
|
|
|
1.1 |
792
|
|
|
# another comment |
793
|
|
|
EOT; |
794
|
|
|
$expected = [ |
795
|
|
|
'a' => [ |
796
|
|
|
'b' => [], |
797
|
|
|
'd' => 1.1, |
798
|
|
|
], |
799
|
|
|
]; |
800
|
|
|
|
801
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
802
|
|
|
} |
803
|
|
|
|
804
|
|
|
public function getParseExceptionNotAffectedMultiLineStringLastResortParsing() |
805
|
|
|
{ |
806
|
|
|
$tests = []; |
807
|
|
|
|
808
|
|
|
$yaml = <<<'EOT' |
809
|
|
|
a |
810
|
|
|
b: |
811
|
|
|
EOT; |
812
|
|
|
$tests['parse error on first line'] = [$yaml]; |
813
|
|
|
|
814
|
|
|
$yaml = <<<'EOT' |
815
|
|
|
a |
816
|
|
|
|
817
|
|
|
b |
818
|
|
|
c: |
819
|
|
|
EOT; |
820
|
|
|
$tests['parse error due to inconsistent indentation'] = [$yaml]; |
821
|
|
|
|
822
|
|
|
$yaml = <<<'EOT' |
823
|
|
|
& * ! | > ' " % @ ` #, { asd a;sdasd }-@^qw3 |
824
|
|
|
EOT; |
825
|
|
|
$tests['symfony/symfony/issues/22967#issuecomment-322067742'] = [$yaml]; |
826
|
|
|
|
827
|
|
|
return $tests; |
828
|
|
|
} |
829
|
|
|
|
830
|
|
|
/** |
831
|
|
|
* @dataProvider getParseExceptionNotAffectedMultiLineStringLastResortParsing |
832
|
|
|
*/ |
833
|
|
|
public function testParseExceptionNotAffectedByMultiLineStringLastResortParsing($yaml) |
834
|
|
|
{ |
835
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
836
|
|
|
$this->parser->parse($yaml); |
837
|
|
|
} |
838
|
|
|
|
839
|
|
|
public function testMultiLineStringLastResortParsing() |
840
|
|
|
{ |
841
|
|
|
$yaml = <<<'EOT' |
842
|
|
|
test: |
843
|
|
|
You can have things that don't look like strings here |
844
|
|
|
true |
845
|
|
|
yes you can |
846
|
|
|
EOT; |
847
|
|
|
$expected = [ |
848
|
|
|
'test' => 'You can have things that don\'t look like strings here true yes you can', |
849
|
|
|
]; |
850
|
|
|
|
851
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
852
|
|
|
|
853
|
|
|
$yaml = <<<'EOT' |
854
|
|
|
a: |
855
|
|
|
b |
856
|
|
|
c |
857
|
|
|
EOT; |
858
|
|
|
$expected = [ |
859
|
|
|
'a' => 'b c', |
860
|
|
|
]; |
861
|
|
|
|
862
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
|
|
|
|
863
|
|
|
} |
864
|
|
|
|
865
|
|
|
public function testMappingInASequence() |
866
|
|
|
{ |
867
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
868
|
|
|
Yaml::parse(<<<'EOF' |
869
|
|
|
yaml: |
870
|
|
|
- array stuff |
871
|
|
|
hash: me |
872
|
|
|
EOF |
873
|
|
|
); |
874
|
|
|
} |
875
|
|
|
|
876
|
|
|
public function testScalarInSequence() |
877
|
|
|
{ |
878
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
879
|
|
|
$this->expectExceptionMessage('missing colon'); |
880
|
|
|
Yaml::parse(<<<'EOF' |
881
|
|
|
foo: |
882
|
|
|
- bar |
883
|
|
|
"missing colon" |
884
|
|
|
foo: bar |
885
|
|
|
EOF |
886
|
|
|
); |
887
|
|
|
} |
888
|
|
|
|
889
|
|
|
/** |
890
|
|
|
* > It is an error for two equal keys to appear in the same mapping node. |
891
|
|
|
* > In such a case the YAML processor may continue, ignoring the second |
892
|
|
|
* > `key: value` pair and issuing an appropriate warning. This strategy |
893
|
|
|
* > preserves a consistent information model for one-pass and random access |
894
|
|
|
* > applications. |
895
|
|
|
* |
896
|
|
|
* @see http://yaml.org/spec/1.2/spec.html#id2759572 |
897
|
|
|
* @see http://yaml.org/spec/1.1/#id932806 |
898
|
|
|
* @group legacy |
899
|
|
|
*/ |
900
|
|
|
public function testMappingDuplicateKeyBlock() |
901
|
|
|
{ |
902
|
|
|
$input = <<<'EOD' |
903
|
|
|
parent: |
904
|
|
|
child: first |
905
|
|
|
child: duplicate |
906
|
|
|
parent: |
907
|
|
|
child: duplicate |
908
|
|
|
child: duplicate |
909
|
|
|
EOD; |
910
|
|
|
$expected = [ |
911
|
|
|
'parent' => [ |
912
|
|
|
'child' => 'first', |
913
|
|
|
], |
914
|
|
|
]; |
915
|
|
|
$this->assertSame($expected, Yaml::parse($input)); |
916
|
|
|
} |
917
|
|
|
|
918
|
|
|
/** |
919
|
|
|
* @group legacy |
920
|
|
|
*/ |
921
|
|
|
public function testMappingDuplicateKeyFlow() |
922
|
|
|
{ |
923
|
|
|
$input = <<<'EOD' |
924
|
|
|
parent: { child: first, child: duplicate } |
925
|
|
|
parent: { child: duplicate, child: duplicate } |
926
|
|
|
EOD; |
927
|
|
|
$expected = [ |
928
|
|
|
'parent' => [ |
929
|
|
|
'child' => 'first', |
930
|
|
|
], |
931
|
|
|
]; |
932
|
|
|
$this->assertSame($expected, Yaml::parse($input)); |
933
|
|
|
} |
934
|
|
|
|
935
|
|
|
/** |
936
|
|
|
* @group legacy |
937
|
|
|
* @dataProvider getParseExceptionOnDuplicateData |
938
|
|
|
* @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. |
939
|
|
|
* throws \Symfony\Component\Yaml\Exception\ParseException in 4.0 |
940
|
|
|
*/ |
941
|
|
|
public function testParseExceptionOnDuplicate($input, $duplicateKey, $lineNumber) |
|
|
|
|
942
|
|
|
{ |
943
|
|
|
Yaml::parse($input); |
944
|
|
|
} |
945
|
|
|
|
946
|
|
|
public function getParseExceptionOnDuplicateData() |
947
|
|
|
{ |
948
|
|
|
$tests = []; |
949
|
|
|
|
950
|
|
|
$yaml = <<<EOD |
951
|
|
|
parent: { child: first, child: duplicate } |
952
|
|
|
EOD; |
953
|
|
|
$tests[] = [$yaml, 'child', 1]; |
954
|
|
|
|
955
|
|
|
$yaml = <<<EOD |
956
|
|
|
parent: |
957
|
|
|
child: first, |
958
|
|
|
child: duplicate |
959
|
|
|
EOD; |
960
|
|
|
$tests[] = [$yaml, 'child', 3]; |
961
|
|
|
|
962
|
|
|
$yaml = <<<EOD |
963
|
|
|
parent: { child: foo } |
964
|
|
|
parent: { child: bar } |
965
|
|
|
EOD; |
966
|
|
|
$tests[] = [$yaml, 'parent', 2]; |
967
|
|
|
|
968
|
|
|
$yaml = <<<EOD |
969
|
|
|
parent: { child_mapping: { value: bar}, child_mapping: { value: bar} } |
970
|
|
|
EOD; |
971
|
|
|
$tests[] = [$yaml, 'child_mapping', 1]; |
972
|
|
|
|
973
|
|
|
$yaml = <<<EOD |
974
|
|
|
parent: |
975
|
|
|
child_mapping: |
976
|
|
|
value: bar |
977
|
|
|
child_mapping: |
978
|
|
|
value: bar |
979
|
|
|
EOD; |
980
|
|
|
$tests[] = [$yaml, 'child_mapping', 4]; |
981
|
|
|
|
982
|
|
|
$yaml = <<<EOD |
983
|
|
|
parent: { child_sequence: ['key1', 'key2', 'key3'], child_sequence: ['key1', 'key2', 'key3'] } |
984
|
|
|
EOD; |
985
|
|
|
$tests[] = [$yaml, 'child_sequence', 1]; |
986
|
|
|
|
987
|
|
|
$yaml = <<<EOD |
988
|
|
|
parent: |
989
|
|
|
child_sequence: |
990
|
|
|
- key1 |
991
|
|
|
- key2 |
992
|
|
|
- key3 |
993
|
|
|
child_sequence: |
994
|
|
|
- key1 |
995
|
|
|
- key2 |
996
|
|
|
- key3 |
997
|
|
|
EOD; |
998
|
|
|
$tests[] = [$yaml, 'child_sequence', 6]; |
999
|
|
|
|
1000
|
|
|
return $tests; |
1001
|
|
|
} |
1002
|
|
|
|
1003
|
|
|
public function testEmptyValue() |
1004
|
|
|
{ |
1005
|
|
|
$input = <<<'EOF' |
1006
|
|
|
hash: |
1007
|
|
|
EOF; |
1008
|
|
|
|
1009
|
|
|
$this->assertEquals(['hash' => null], Yaml::parse($input)); |
1010
|
|
|
} |
1011
|
|
|
|
1012
|
|
|
public function testCommentAtTheRootIndent() |
1013
|
|
|
{ |
1014
|
|
|
$this->assertEquals([ |
1015
|
|
|
'services' => [ |
1016
|
|
|
'app.foo_service' => [ |
1017
|
|
|
'class' => 'Foo', |
1018
|
|
|
], |
1019
|
|
|
'app/bar_service' => [ |
1020
|
|
|
'class' => 'Bar', |
1021
|
|
|
], |
1022
|
|
|
], |
1023
|
|
|
], Yaml::parse(<<<'EOF' |
1024
|
|
|
# comment 1 |
1025
|
|
|
services: |
1026
|
|
|
# comment 2 |
1027
|
|
|
# comment 3 |
1028
|
|
|
app.foo_service: |
1029
|
|
|
class: Foo |
1030
|
|
|
# comment 4 |
1031
|
|
|
# comment 5 |
1032
|
|
|
app/bar_service: |
1033
|
|
|
class: Bar |
1034
|
|
|
EOF |
1035
|
|
|
)); |
1036
|
|
|
} |
1037
|
|
|
|
1038
|
|
|
public function testStringBlockWithComments() |
1039
|
|
|
{ |
1040
|
|
|
$this->assertEquals(['content' => <<<'EOT' |
1041
|
|
|
# comment 1 |
1042
|
|
|
header |
1043
|
|
|
|
1044
|
|
|
# comment 2 |
1045
|
|
|
<body> |
1046
|
|
|
<h1>title</h1> |
1047
|
|
|
</body> |
1048
|
|
|
|
1049
|
|
|
footer # comment3 |
1050
|
|
|
EOT |
1051
|
|
|
], Yaml::parse(<<<'EOF' |
1052
|
|
|
content: | |
1053
|
|
|
# comment 1 |
1054
|
|
|
header |
1055
|
|
|
|
1056
|
|
|
# comment 2 |
1057
|
|
|
<body> |
1058
|
|
|
<h1>title</h1> |
1059
|
|
|
</body> |
1060
|
|
|
|
1061
|
|
|
footer # comment3 |
1062
|
|
|
EOF |
1063
|
|
|
)); |
1064
|
|
|
} |
1065
|
|
|
|
1066
|
|
|
public function testFoldedStringBlockWithComments() |
1067
|
|
|
{ |
1068
|
|
|
$this->assertEquals([['content' => <<<'EOT' |
1069
|
|
|
# comment 1 |
1070
|
|
|
header |
1071
|
|
|
|
1072
|
|
|
# comment 2 |
1073
|
|
|
<body> |
1074
|
|
|
<h1>title</h1> |
1075
|
|
|
</body> |
1076
|
|
|
|
1077
|
|
|
footer # comment3 |
1078
|
|
|
EOT |
1079
|
|
|
]], Yaml::parse(<<<'EOF' |
1080
|
|
|
- |
1081
|
|
|
content: | |
1082
|
|
|
# comment 1 |
1083
|
|
|
header |
1084
|
|
|
|
1085
|
|
|
# comment 2 |
1086
|
|
|
<body> |
1087
|
|
|
<h1>title</h1> |
1088
|
|
|
</body> |
1089
|
|
|
|
1090
|
|
|
footer # comment3 |
1091
|
|
|
EOF |
1092
|
|
|
)); |
1093
|
|
|
} |
1094
|
|
|
|
1095
|
|
|
public function testNestedFoldedStringBlockWithComments() |
1096
|
|
|
{ |
1097
|
|
|
$this->assertEquals([[ |
1098
|
|
|
'title' => 'some title', |
1099
|
|
|
'content' => <<<'EOT' |
1100
|
|
|
# comment 1 |
1101
|
|
|
header |
1102
|
|
|
|
1103
|
|
|
# comment 2 |
1104
|
|
|
<body> |
1105
|
|
|
<h1>title</h1> |
1106
|
|
|
</body> |
1107
|
|
|
|
1108
|
|
|
footer # comment3 |
1109
|
|
|
EOT |
1110
|
|
|
]], Yaml::parse(<<<'EOF' |
1111
|
|
|
- |
1112
|
|
|
title: some title |
1113
|
|
|
content: | |
1114
|
|
|
# comment 1 |
1115
|
|
|
header |
1116
|
|
|
|
1117
|
|
|
# comment 2 |
1118
|
|
|
<body> |
1119
|
|
|
<h1>title</h1> |
1120
|
|
|
</body> |
1121
|
|
|
|
1122
|
|
|
footer # comment3 |
1123
|
|
|
EOF |
1124
|
|
|
)); |
1125
|
|
|
} |
1126
|
|
|
|
1127
|
|
|
public function testReferenceResolvingInInlineStrings() |
1128
|
|
|
{ |
1129
|
|
|
$this->assertEquals([ |
1130
|
|
|
'var' => 'var-value', |
1131
|
|
|
'scalar' => 'var-value', |
1132
|
|
|
'list' => ['var-value'], |
1133
|
|
|
'list_in_list' => [['var-value']], |
1134
|
|
|
'map_in_list' => [['key' => 'var-value']], |
1135
|
|
|
'embedded_mapping' => [['key' => 'var-value']], |
1136
|
|
|
'map' => ['key' => 'var-value'], |
1137
|
|
|
'list_in_map' => ['key' => ['var-value']], |
1138
|
|
|
'map_in_map' => ['foo' => ['bar' => 'var-value']], |
1139
|
|
|
], Yaml::parse(<<<'EOF' |
1140
|
|
|
var: &var var-value |
1141
|
|
|
scalar: *var |
1142
|
|
|
list: [ *var ] |
1143
|
|
|
list_in_list: [[ *var ]] |
1144
|
|
|
map_in_list: [ { key: *var } ] |
1145
|
|
|
embedded_mapping: [ key: *var ] |
1146
|
|
|
map: { key: *var } |
1147
|
|
|
list_in_map: { key: [*var] } |
1148
|
|
|
map_in_map: { foo: { bar: *var } } |
1149
|
|
|
EOF |
1150
|
|
|
)); |
1151
|
|
|
} |
1152
|
|
|
|
1153
|
|
|
public function testYamlDirective() |
1154
|
|
|
{ |
1155
|
|
|
$yaml = <<<'EOF' |
1156
|
|
|
%YAML 1.2 |
1157
|
|
|
--- |
1158
|
|
|
foo: 1 |
1159
|
|
|
bar: 2 |
1160
|
|
|
EOF; |
1161
|
|
|
$this->assertEquals(['foo' => 1, 'bar' => 2], $this->parser->parse($yaml)); |
1162
|
|
|
} |
1163
|
|
|
|
1164
|
|
|
/** |
1165
|
|
|
* @group legacy |
1166
|
|
|
* @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. |
1167
|
|
|
*/ |
1168
|
|
|
public function testFloatKeys() |
1169
|
|
|
{ |
1170
|
|
|
$yaml = <<<'EOF' |
1171
|
|
|
foo: |
1172
|
|
|
1.2: "bar" |
1173
|
|
|
1.3: "baz" |
1174
|
|
|
EOF; |
1175
|
|
|
|
1176
|
|
|
$expected = [ |
1177
|
|
|
'foo' => [ |
1178
|
|
|
'1.2' => 'bar', |
1179
|
|
|
'1.3' => 'baz', |
1180
|
|
|
], |
1181
|
|
|
]; |
1182
|
|
|
|
1183
|
|
|
$this->assertEquals($expected, $this->parser->parse($yaml)); |
1184
|
|
|
} |
1185
|
|
|
|
1186
|
|
|
/** |
1187
|
|
|
* @group legacy |
1188
|
|
|
* @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. |
1189
|
|
|
*/ |
1190
|
|
|
public function testBooleanKeys() |
1191
|
|
|
{ |
1192
|
|
|
$yaml = <<<'EOF' |
1193
|
|
|
true: foo |
1194
|
|
|
false: bar |
1195
|
|
|
EOF; |
1196
|
|
|
|
1197
|
|
|
$expected = [ |
1198
|
|
|
1 => 'foo', |
1199
|
|
|
0 => 'bar', |
1200
|
|
|
]; |
1201
|
|
|
|
1202
|
|
|
$this->assertEquals($expected, $this->parser->parse($yaml)); |
1203
|
|
|
} |
1204
|
|
|
|
1205
|
|
|
public function testExplicitStringCasting() |
1206
|
|
|
{ |
1207
|
|
|
$yaml = <<<'EOF' |
1208
|
|
|
'1.2': "bar" |
1209
|
|
|
!!str 1.3: "baz" |
1210
|
|
|
|
1211
|
|
|
'true': foo |
1212
|
|
|
!!str false: bar |
1213
|
|
|
|
1214
|
|
|
!!str null: 'null' |
1215
|
|
|
'~': 'null' |
1216
|
|
|
EOF; |
1217
|
|
|
|
1218
|
|
|
$expected = [ |
1219
|
|
|
'1.2' => 'bar', |
1220
|
|
|
'1.3' => 'baz', |
1221
|
|
|
'true' => 'foo', |
1222
|
|
|
'false' => 'bar', |
1223
|
|
|
'null' => 'null', |
1224
|
|
|
'~' => 'null', |
1225
|
|
|
]; |
1226
|
|
|
|
1227
|
|
|
$this->assertEquals($expected, $this->parser->parse($yaml)); |
1228
|
|
|
} |
1229
|
|
|
|
1230
|
|
|
public function testColonInMappingValueException() |
1231
|
|
|
{ |
1232
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
1233
|
|
|
$this->expectExceptionMessage('A colon cannot be used in an unquoted mapping value'); |
1234
|
|
|
$yaml = <<<'EOF' |
1235
|
|
|
foo: bar: baz |
1236
|
|
|
EOF; |
1237
|
|
|
|
1238
|
|
|
$this->parser->parse($yaml); |
1239
|
|
|
} |
1240
|
|
|
|
1241
|
|
|
public function testColonInMappingValueExceptionNotTriggeredByColonInComment() |
1242
|
|
|
{ |
1243
|
|
|
$yaml = <<<'EOT' |
1244
|
|
|
foo: |
1245
|
|
|
bar: foobar # Note: a comment after a colon |
1246
|
|
|
EOT; |
1247
|
|
|
|
1248
|
|
|
$this->assertSame(['foo' => ['bar' => 'foobar']], $this->parser->parse($yaml)); |
1249
|
|
|
} |
1250
|
|
|
|
1251
|
|
|
/** |
1252
|
|
|
* @dataProvider getCommentLikeStringInScalarBlockData |
1253
|
|
|
*/ |
1254
|
|
|
public function testCommentLikeStringsAreNotStrippedInBlockScalars($yaml, $expectedParserResult) |
1255
|
|
|
{ |
1256
|
|
|
$this->assertSame($expectedParserResult, $this->parser->parse($yaml)); |
1257
|
|
|
} |
1258
|
|
|
|
1259
|
|
|
public function getCommentLikeStringInScalarBlockData() |
1260
|
|
|
{ |
1261
|
|
|
$tests = []; |
1262
|
|
|
|
1263
|
|
|
$yaml = <<<'EOT' |
1264
|
|
|
pages: |
1265
|
|
|
- |
1266
|
|
|
title: some title |
1267
|
|
|
content: | |
1268
|
|
|
# comment 1 |
1269
|
|
|
header |
1270
|
|
|
|
1271
|
|
|
# comment 2 |
1272
|
|
|
<body> |
1273
|
|
|
<h1>title</h1> |
1274
|
|
|
</body> |
1275
|
|
|
|
1276
|
|
|
footer # comment3 |
1277
|
|
|
EOT; |
1278
|
|
|
$expected = [ |
1279
|
|
|
'pages' => [ |
1280
|
|
|
[ |
1281
|
|
|
'title' => 'some title', |
1282
|
|
|
'content' => <<<'EOT' |
1283
|
|
|
# comment 1 |
1284
|
|
|
header |
1285
|
|
|
|
1286
|
|
|
# comment 2 |
1287
|
|
|
<body> |
1288
|
|
|
<h1>title</h1> |
1289
|
|
|
</body> |
1290
|
|
|
|
1291
|
|
|
footer # comment3 |
1292
|
|
|
EOT |
1293
|
|
|
, |
1294
|
|
|
], |
1295
|
|
|
], |
1296
|
|
|
]; |
1297
|
|
|
$tests[] = [$yaml, $expected]; |
1298
|
|
|
|
1299
|
|
|
$yaml = <<<'EOT' |
1300
|
|
|
test: | |
1301
|
|
|
foo |
1302
|
|
|
# bar |
1303
|
|
|
baz |
1304
|
|
|
collection: |
1305
|
|
|
- one: | |
1306
|
|
|
foo |
1307
|
|
|
# bar |
1308
|
|
|
baz |
1309
|
|
|
- two: | |
1310
|
|
|
foo |
1311
|
|
|
# bar |
1312
|
|
|
baz |
1313
|
|
|
EOT; |
1314
|
|
|
$expected = [ |
1315
|
|
|
'test' => <<<'EOT' |
1316
|
|
|
foo |
1317
|
|
|
# bar |
1318
|
|
|
baz |
1319
|
|
|
|
1320
|
|
|
EOT |
1321
|
|
|
, |
1322
|
|
|
'collection' => [ |
1323
|
|
|
[ |
1324
|
|
|
'one' => <<<'EOT' |
1325
|
|
|
foo |
1326
|
|
|
# bar |
1327
|
|
|
baz |
1328
|
|
|
|
1329
|
|
|
EOT |
1330
|
|
|
, |
1331
|
|
|
], |
1332
|
|
|
[ |
1333
|
|
|
'two' => <<<'EOT' |
1334
|
|
|
foo |
1335
|
|
|
# bar |
1336
|
|
|
baz |
1337
|
|
|
EOT |
1338
|
|
|
, |
1339
|
|
|
], |
1340
|
|
|
], |
1341
|
|
|
]; |
1342
|
|
|
$tests[] = [$yaml, $expected]; |
1343
|
|
|
|
1344
|
|
|
$yaml = <<<'EOT' |
1345
|
|
|
foo: |
1346
|
|
|
bar: |
1347
|
|
|
scalar-block: > |
1348
|
|
|
line1 |
1349
|
|
|
line2> |
1350
|
|
|
baz: |
1351
|
|
|
# comment |
1352
|
|
|
foobar: ~ |
1353
|
|
|
EOT; |
1354
|
|
|
$expected = [ |
1355
|
|
|
'foo' => [ |
1356
|
|
|
'bar' => [ |
1357
|
|
|
'scalar-block' => "line1 line2>\n", |
1358
|
|
|
], |
1359
|
|
|
'baz' => [ |
1360
|
|
|
'foobar' => null, |
1361
|
|
|
], |
1362
|
|
|
], |
1363
|
|
|
]; |
1364
|
|
|
$tests[] = [$yaml, $expected]; |
1365
|
|
|
|
1366
|
|
|
$yaml = <<<'EOT' |
1367
|
|
|
a: |
1368
|
|
|
b: hello |
1369
|
|
|
# c: | |
1370
|
|
|
# first row |
1371
|
|
|
# second row |
1372
|
|
|
d: hello |
1373
|
|
|
EOT; |
1374
|
|
|
$expected = [ |
1375
|
|
|
'a' => [ |
1376
|
|
|
'b' => 'hello', |
1377
|
|
|
'd' => 'hello', |
1378
|
|
|
], |
1379
|
|
|
]; |
1380
|
|
|
$tests[] = [$yaml, $expected]; |
1381
|
|
|
|
1382
|
|
|
return $tests; |
1383
|
|
|
} |
1384
|
|
|
|
1385
|
|
|
public function testBlankLinesAreParsedAsNewLinesInFoldedBlocks() |
1386
|
|
|
{ |
1387
|
|
|
$yaml = <<<'EOT' |
1388
|
|
|
test: > |
1389
|
|
|
<h2>A heading</h2> |
1390
|
|
|
|
1391
|
|
|
<ul> |
1392
|
|
|
<li>a list</li> |
1393
|
|
|
<li>may be a good example</li> |
1394
|
|
|
</ul> |
1395
|
|
|
EOT; |
1396
|
|
|
|
1397
|
|
|
$this->assertSame( |
1398
|
|
|
[ |
1399
|
|
|
'test' => <<<'EOT' |
1400
|
|
|
<h2>A heading</h2> |
1401
|
|
|
<ul> <li>a list</li> <li>may be a good example</li> </ul> |
1402
|
|
|
EOT |
1403
|
|
|
, |
1404
|
|
|
], |
1405
|
|
|
$this->parser->parse($yaml) |
1406
|
|
|
); |
1407
|
|
|
} |
1408
|
|
|
|
1409
|
|
|
public function testAdditionallyIndentedLinesAreParsedAsNewLinesInFoldedBlocks() |
1410
|
|
|
{ |
1411
|
|
|
$yaml = <<<'EOT' |
1412
|
|
|
test: > |
1413
|
|
|
<h2>A heading</h2> |
1414
|
|
|
|
1415
|
|
|
<ul> |
1416
|
|
|
<li>a list</li> |
1417
|
|
|
<li>may be a good example</li> |
1418
|
|
|
</ul> |
1419
|
|
|
EOT; |
1420
|
|
|
|
1421
|
|
|
$this->assertSame( |
1422
|
|
|
[ |
1423
|
|
|
'test' => <<<'EOT' |
1424
|
|
|
<h2>A heading</h2> |
1425
|
|
|
<ul> |
1426
|
|
|
<li>a list</li> |
1427
|
|
|
<li>may be a good example</li> |
1428
|
|
|
</ul> |
1429
|
|
|
EOT |
1430
|
|
|
, |
1431
|
|
|
], |
1432
|
|
|
$this->parser->parse($yaml) |
1433
|
|
|
); |
1434
|
|
|
} |
1435
|
|
|
|
1436
|
|
|
/** |
1437
|
|
|
* @dataProvider getBinaryData |
1438
|
|
|
*/ |
1439
|
|
|
public function testParseBinaryData($data) |
1440
|
|
|
{ |
1441
|
|
|
$this->assertSame(['data' => 'Hello world'], $this->parser->parse($data)); |
1442
|
|
|
} |
1443
|
|
|
|
1444
|
|
|
public function getBinaryData() |
1445
|
|
|
{ |
1446
|
|
|
return [ |
1447
|
|
|
'enclosed with double quotes' => ['data: !!binary "SGVsbG8gd29ybGQ="'], |
1448
|
|
|
'enclosed with single quotes' => ["data: !!binary 'SGVsbG8gd29ybGQ='"], |
1449
|
|
|
'containing spaces' => ['data: !!binary "SGVs bG8gd 29ybGQ="'], |
1450
|
|
|
'in block scalar' => [ |
1451
|
|
|
<<<'EOT' |
1452
|
|
|
data: !!binary | |
1453
|
|
|
SGVsbG8gd29ybGQ= |
1454
|
|
|
EOT |
1455
|
|
|
], |
1456
|
|
|
'containing spaces in block scalar' => [ |
1457
|
|
|
<<<'EOT' |
1458
|
|
|
data: !!binary | |
1459
|
|
|
SGVs bG8gd 29ybGQ= |
1460
|
|
|
EOT |
1461
|
|
|
], |
1462
|
|
|
]; |
1463
|
|
|
} |
1464
|
|
|
|
1465
|
|
|
/** |
1466
|
|
|
* @dataProvider getInvalidBinaryData |
1467
|
|
|
*/ |
1468
|
|
|
public function testParseInvalidBinaryData($data, $expectedMessage) |
1469
|
|
|
{ |
1470
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
1471
|
|
|
$this->expectExceptionMessageMatches($expectedMessage); |
1472
|
|
|
|
1473
|
|
|
$this->parser->parse($data); |
1474
|
|
|
} |
1475
|
|
|
|
1476
|
|
|
public function getInvalidBinaryData() |
1477
|
|
|
{ |
1478
|
|
|
return [ |
1479
|
|
|
'length not a multiple of four' => ['data: !!binary "SGVsbG8d29ybGQ="', '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/'], |
1480
|
|
|
'invalid characters' => ['!!binary "SGVsbG8#d29ybGQ="', '/The base64 encoded data \(.*\) contains invalid characters/'], |
1481
|
|
|
'too many equals characters' => ['data: !!binary "SGVsbG8gd29yb==="', '/The base64 encoded data \(.*\) contains invalid characters/'], |
1482
|
|
|
'misplaced equals character' => ['data: !!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'], |
1483
|
|
|
'length not a multiple of four in block scalar' => [ |
1484
|
|
|
<<<'EOT' |
1485
|
|
|
data: !!binary | |
1486
|
|
|
SGVsbG8d29ybGQ= |
1487
|
|
|
EOT |
1488
|
|
|
, |
1489
|
|
|
'/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/', |
1490
|
|
|
], |
1491
|
|
|
'invalid characters in block scalar' => [ |
1492
|
|
|
<<<'EOT' |
1493
|
|
|
data: !!binary | |
1494
|
|
|
SGVsbG8#d29ybGQ= |
1495
|
|
|
EOT |
1496
|
|
|
, |
1497
|
|
|
'/The base64 encoded data \(.*\) contains invalid characters/', |
1498
|
|
|
], |
1499
|
|
|
'too many equals characters in block scalar' => [ |
1500
|
|
|
<<<'EOT' |
1501
|
|
|
data: !!binary | |
1502
|
|
|
SGVsbG8gd29yb=== |
1503
|
|
|
EOT |
1504
|
|
|
, |
1505
|
|
|
'/The base64 encoded data \(.*\) contains invalid characters/', |
1506
|
|
|
], |
1507
|
|
|
'misplaced equals character in block scalar' => [ |
1508
|
|
|
<<<'EOT' |
1509
|
|
|
data: !!binary | |
1510
|
|
|
SGVsbG8gd29ybG=Q |
1511
|
|
|
EOT |
1512
|
|
|
, |
1513
|
|
|
'/The base64 encoded data \(.*\) contains invalid characters/', |
1514
|
|
|
], |
1515
|
|
|
]; |
1516
|
|
|
} |
1517
|
|
|
|
1518
|
|
|
public function testParseDateAsMappingValue() |
1519
|
|
|
{ |
1520
|
|
|
$yaml = <<<'EOT' |
1521
|
|
|
date: 2002-12-14 |
1522
|
|
|
EOT; |
1523
|
|
|
$expectedDate = new \DateTime(); |
1524
|
|
|
$expectedDate->setTimeZone(new \DateTimeZone('UTC')); |
1525
|
|
|
$expectedDate->setDate(2002, 12, 14); |
1526
|
|
|
$expectedDate->setTime(0, 0, 0); |
1527
|
|
|
|
1528
|
|
|
$this->assertEquals(['date' => $expectedDate], $this->parser->parse($yaml, Yaml::PARSE_DATETIME)); |
1529
|
|
|
} |
1530
|
|
|
|
1531
|
|
|
/** |
1532
|
|
|
* @param $lineNumber |
1533
|
|
|
* @param $yaml |
1534
|
|
|
* @dataProvider parserThrowsExceptionWithCorrectLineNumberProvider |
1535
|
|
|
*/ |
1536
|
|
|
public function testParserThrowsExceptionWithCorrectLineNumber($lineNumber, $yaml) |
1537
|
|
|
{ |
1538
|
|
|
$this->expectException('\Symfony\Component\Yaml\Exception\ParseException'); |
1539
|
|
|
$this->expectExceptionMessage(sprintf('Unexpected characters near "," at line %d (near "bar: "123",").', $lineNumber)); |
1540
|
|
|
|
1541
|
|
|
$this->parser->parse($yaml); |
1542
|
|
|
} |
1543
|
|
|
|
1544
|
|
|
public function parserThrowsExceptionWithCorrectLineNumberProvider() |
1545
|
|
|
{ |
1546
|
|
|
return [ |
1547
|
|
|
[ |
1548
|
|
|
4, |
1549
|
|
|
<<<'YAML' |
1550
|
|
|
foo: |
1551
|
|
|
- |
1552
|
|
|
# bar |
1553
|
|
|
bar: "123", |
1554
|
|
|
YAML |
1555
|
|
|
], |
1556
|
|
|
[ |
1557
|
|
|
5, |
1558
|
|
|
<<<'YAML' |
1559
|
|
|
foo: |
1560
|
|
|
- |
1561
|
|
|
# bar |
1562
|
|
|
# bar |
1563
|
|
|
bar: "123", |
1564
|
|
|
YAML |
1565
|
|
|
], |
1566
|
|
|
[ |
1567
|
|
|
8, |
1568
|
|
|
<<<'YAML' |
1569
|
|
|
foo: |
1570
|
|
|
- |
1571
|
|
|
# foobar |
1572
|
|
|
baz: 123 |
1573
|
|
|
bar: |
1574
|
|
|
- |
1575
|
|
|
# bar |
1576
|
|
|
bar: "123", |
1577
|
|
|
YAML |
1578
|
|
|
], |
1579
|
|
|
[ |
1580
|
|
|
10, |
1581
|
|
|
<<<'YAML' |
1582
|
|
|
foo: |
1583
|
|
|
- |
1584
|
|
|
# foobar |
1585
|
|
|
# foobar |
1586
|
|
|
baz: 123 |
1587
|
|
|
bar: |
1588
|
|
|
- |
1589
|
|
|
# bar |
1590
|
|
|
# bar |
1591
|
|
|
bar: "123", |
1592
|
|
|
YAML |
1593
|
|
|
], |
1594
|
|
|
]; |
1595
|
|
|
} |
1596
|
|
|
|
1597
|
|
|
public function testParseMultiLineQuotedString() |
1598
|
|
|
{ |
1599
|
|
|
$yaml = <<<EOT |
1600
|
|
|
foo: "bar |
1601
|
|
|
baz |
1602
|
|
|
foobar |
1603
|
|
|
foo" |
1604
|
|
|
bar: baz |
1605
|
|
|
EOT; |
1606
|
|
|
|
1607
|
|
|
$this->assertSame(['foo' => 'bar baz foobar foo', 'bar' => 'baz'], $this->parser->parse($yaml)); |
1608
|
|
|
} |
1609
|
|
|
|
1610
|
|
|
public function testMultiLineQuotedStringWithTrailingBackslash() |
1611
|
|
|
{ |
1612
|
|
|
$yaml = <<<YAML |
1613
|
|
|
foobar: |
1614
|
|
|
"foo\ |
1615
|
|
|
bar" |
1616
|
|
|
YAML; |
1617
|
|
|
|
1618
|
|
|
$this->assertSame(['foobar' => 'foobar'], $this->parser->parse($yaml)); |
1619
|
|
|
} |
1620
|
|
|
|
1621
|
|
|
public function testCommentCharactersInMultiLineQuotedStrings() |
1622
|
|
|
{ |
1623
|
|
|
$yaml = <<<YAML |
1624
|
|
|
foo: |
1625
|
|
|
foobar: 'foo |
1626
|
|
|
#bar' |
1627
|
|
|
bar: baz |
1628
|
|
|
YAML; |
1629
|
|
|
$expected = [ |
1630
|
|
|
'foo' => [ |
1631
|
|
|
'foobar' => 'foo #bar', |
1632
|
|
|
'bar' => 'baz', |
1633
|
|
|
], |
1634
|
|
|
]; |
1635
|
|
|
|
1636
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
1637
|
|
|
} |
1638
|
|
|
|
1639
|
|
|
public function testBlankLinesInQuotedMultiLineString() |
1640
|
|
|
{ |
1641
|
|
|
$yaml = <<<YAML |
1642
|
|
|
foobar: 'foo |
1643
|
|
|
|
1644
|
|
|
bar' |
1645
|
|
|
YAML; |
1646
|
|
|
$expected = [ |
1647
|
|
|
'foobar' => "foo\nbar", |
1648
|
|
|
]; |
1649
|
|
|
|
1650
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
1651
|
|
|
} |
1652
|
|
|
|
1653
|
|
|
public function testEscapedQuoteInQuotedMultiLineString() |
1654
|
|
|
{ |
1655
|
|
|
$yaml = <<<YAML |
1656
|
|
|
foobar: "foo |
1657
|
|
|
\\"bar\\" |
1658
|
|
|
baz" |
1659
|
|
|
YAML; |
1660
|
|
|
$expected = [ |
1661
|
|
|
'foobar' => 'foo "bar" baz', |
1662
|
|
|
]; |
1663
|
|
|
|
1664
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
1665
|
|
|
} |
1666
|
|
|
|
1667
|
|
|
public function testBackslashInQuotedMultiLineString() |
1668
|
|
|
{ |
1669
|
|
|
$yaml = <<<YAML |
1670
|
|
|
foobar: "foo |
1671
|
|
|
bar\\\\" |
1672
|
|
|
YAML; |
1673
|
|
|
$expected = [ |
1674
|
|
|
'foobar' => 'foo bar\\', |
1675
|
|
|
]; |
1676
|
|
|
|
1677
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
1678
|
|
|
} |
1679
|
|
|
|
1680
|
|
|
public function testParseMultiLineUnquotedString() |
1681
|
|
|
{ |
1682
|
|
|
$yaml = <<<EOT |
1683
|
|
|
foo: bar |
1684
|
|
|
baz |
1685
|
|
|
foobar |
1686
|
|
|
foo |
1687
|
|
|
bar: baz |
1688
|
|
|
EOT; |
1689
|
|
|
|
1690
|
|
|
$this->assertSame(['foo' => 'bar baz foobar foo', 'bar' => 'baz'], $this->parser->parse($yaml)); |
1691
|
|
|
} |
1692
|
|
|
|
1693
|
|
|
public function testParseMultiLineString() |
1694
|
|
|
{ |
1695
|
|
|
$this->assertEquals("foo bar\nbaz", $this->parser->parse("foo\nbar\n\nbaz")); |
1696
|
|
|
} |
1697
|
|
|
|
1698
|
|
|
/** |
1699
|
|
|
* @dataProvider multiLineDataProvider |
1700
|
|
|
*/ |
1701
|
|
|
public function testParseMultiLineMappingValue($yaml, $expected, $parseError) |
|
|
|
|
1702
|
|
|
{ |
1703
|
|
|
$this->assertEquals($expected, $this->parser->parse($yaml)); |
1704
|
|
|
} |
1705
|
|
|
|
1706
|
|
|
public function multiLineDataProvider() |
1707
|
|
|
{ |
1708
|
|
|
$tests = []; |
1709
|
|
|
|
1710
|
|
|
$yaml = <<<'EOF' |
1711
|
|
|
foo: |
1712
|
|
|
- bar: |
1713
|
|
|
one |
1714
|
|
|
|
1715
|
|
|
two |
1716
|
|
|
three |
1717
|
|
|
EOF; |
1718
|
|
|
$expected = [ |
1719
|
|
|
'foo' => [ |
1720
|
|
|
[ |
1721
|
|
|
'bar' => "one\ntwo three", |
1722
|
|
|
], |
1723
|
|
|
], |
1724
|
|
|
]; |
1725
|
|
|
|
1726
|
|
|
$tests[] = [$yaml, $expected, false]; |
1727
|
|
|
|
1728
|
|
|
$yaml = <<<'EOF' |
1729
|
|
|
bar |
1730
|
|
|
"foo" |
1731
|
|
|
EOF; |
1732
|
|
|
$expected = 'bar "foo"'; |
1733
|
|
|
|
1734
|
|
|
$tests[] = [$yaml, $expected, false]; |
1735
|
|
|
|
1736
|
|
|
$yaml = <<<'EOF' |
1737
|
|
|
bar |
1738
|
|
|
"foo |
1739
|
|
|
EOF; |
1740
|
|
|
$expected = 'bar "foo'; |
1741
|
|
|
|
1742
|
|
|
$tests[] = [$yaml, $expected, false]; |
1743
|
|
|
|
1744
|
|
|
$yaml = <<<'EOF' |
1745
|
|
|
bar |
1746
|
|
|
|
1747
|
|
|
'foo' |
1748
|
|
|
EOF; |
1749
|
|
|
$expected = "bar\n'foo'"; |
1750
|
|
|
|
1751
|
|
|
$tests[] = [$yaml, $expected, false]; |
1752
|
|
|
|
1753
|
|
|
$yaml = <<<'EOF' |
1754
|
|
|
bar |
1755
|
|
|
|
1756
|
|
|
foo' |
1757
|
|
|
EOF; |
1758
|
|
|
$expected = "bar\nfoo'"; |
1759
|
|
|
|
1760
|
|
|
$tests[] = [$yaml, $expected, false]; |
1761
|
|
|
|
1762
|
|
|
return $tests; |
1763
|
|
|
} |
1764
|
|
|
|
1765
|
|
|
public function testTaggedInlineMapping() |
1766
|
|
|
{ |
1767
|
|
|
$this->assertEquals(new TaggedValue('foo', ['foo' => 'bar']), $this->parser->parse('!foo {foo: bar}', Yaml::PARSE_CUSTOM_TAGS)); |
1768
|
|
|
} |
1769
|
|
|
|
1770
|
|
|
/** |
1771
|
|
|
* @dataProvider taggedValuesProvider |
1772
|
|
|
*/ |
1773
|
|
|
public function testCustomTagSupport($expected, $yaml) |
1774
|
|
|
{ |
1775
|
|
|
$this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_CUSTOM_TAGS)); |
1776
|
|
|
} |
1777
|
|
|
|
1778
|
|
|
public function taggedValuesProvider() |
1779
|
|
|
{ |
1780
|
|
|
return [ |
1781
|
|
|
'sequences' => [ |
1782
|
|
|
[new TaggedValue('foo', ['yaml']), new TaggedValue('quz', ['bar'])], |
1783
|
|
|
<<<YAML |
1784
|
|
|
- !foo |
1785
|
|
|
- yaml |
1786
|
|
|
- !quz [bar] |
1787
|
|
|
YAML |
1788
|
|
|
], |
1789
|
|
|
'mappings' => [ |
1790
|
|
|
new TaggedValue('foo', ['foo' => new TaggedValue('quz', ['bar']), 'quz' => new TaggedValue('foo', ['quz' => 'bar'])]), |
1791
|
|
|
<<<YAML |
1792
|
|
|
!foo |
1793
|
|
|
foo: !quz [bar] |
1794
|
|
|
quz: !foo |
1795
|
|
|
quz: bar |
1796
|
|
|
YAML |
1797
|
|
|
], |
1798
|
|
|
'inline' => [ |
1799
|
|
|
[new TaggedValue('foo', ['foo', 'bar']), new TaggedValue('quz', ['foo' => 'bar', 'quz' => new TaggedValue('bar', ['one' => 'bar'])])], |
1800
|
|
|
<<<YAML |
1801
|
|
|
- !foo [foo, bar] |
1802
|
|
|
- !quz {foo: bar, quz: !bar {one: bar}} |
1803
|
|
|
YAML |
1804
|
|
|
], |
1805
|
|
|
]; |
1806
|
|
|
} |
1807
|
|
|
|
1808
|
|
|
public function testCustomTagsDisabled() |
1809
|
|
|
{ |
1810
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
1811
|
|
|
$this->expectExceptionMessage('Tags support is not enabled. Enable the `Yaml::PARSE_CUSTOM_TAGS` flag to use "!iterator" at line 1 (near "!iterator [foo]").'); |
1812
|
|
|
$this->parser->parse('!iterator [foo]'); |
1813
|
|
|
} |
1814
|
|
|
|
1815
|
|
|
/** |
1816
|
|
|
* @group legacy |
1817
|
|
|
* @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. |
1818
|
|
|
*/ |
1819
|
|
|
public function testUnsupportedTagWithScalar() |
1820
|
|
|
{ |
1821
|
|
|
$this->assertEquals('!iterator foo', $this->parser->parse('!iterator foo')); |
1822
|
|
|
} |
1823
|
|
|
|
1824
|
|
|
public function testExceptionWhenUsingUnsupportedBuiltInTags() |
1825
|
|
|
{ |
1826
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
1827
|
|
|
$this->expectExceptionMessage('The built-in tag "!!foo" is not implemented at line 1 (near "!!foo").'); |
1828
|
|
|
$this->parser->parse('!!foo'); |
1829
|
|
|
} |
1830
|
|
|
|
1831
|
|
|
/** |
1832
|
|
|
* @group legacy |
1833
|
|
|
* @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. |
1834
|
|
|
*/ |
1835
|
|
|
public function testComplexMappingThrowsParseException() |
1836
|
|
|
{ |
1837
|
|
|
$yaml = <<<YAML |
1838
|
|
|
? "1" |
1839
|
|
|
: |
1840
|
|
|
name: végétalien |
1841
|
|
|
YAML; |
1842
|
|
|
|
1843
|
|
|
$this->parser->parse($yaml); |
1844
|
|
|
} |
1845
|
|
|
|
1846
|
|
|
/** |
1847
|
|
|
* @group legacy |
1848
|
|
|
* @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. |
1849
|
|
|
*/ |
1850
|
|
|
public function testComplexMappingNestedInMappingThrowsParseException() |
1851
|
|
|
{ |
1852
|
|
|
$yaml = <<<YAML |
1853
|
|
|
diet: |
1854
|
|
|
? "1" |
1855
|
|
|
: |
1856
|
|
|
name: végétalien |
1857
|
|
|
YAML; |
1858
|
|
|
|
1859
|
|
|
$this->parser->parse($yaml); |
1860
|
|
|
} |
1861
|
|
|
|
1862
|
|
|
/** |
1863
|
|
|
* @group legacy |
1864
|
|
|
* @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. |
1865
|
|
|
*/ |
1866
|
|
|
public function testComplexMappingNestedInSequenceThrowsParseException() |
1867
|
|
|
{ |
1868
|
|
|
$yaml = <<<YAML |
1869
|
|
|
- ? "1" |
1870
|
|
|
: |
1871
|
|
|
name: végétalien |
1872
|
|
|
YAML; |
1873
|
|
|
|
1874
|
|
|
$this->parser->parse($yaml); |
1875
|
|
|
} |
1876
|
|
|
|
1877
|
|
|
public function testParsingIniThrowsException() |
1878
|
|
|
{ |
1879
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
1880
|
|
|
$this->expectExceptionMessage('Unable to parse at line 1 (near "[parameters]").'); |
1881
|
|
|
$ini = <<<INI |
1882
|
|
|
[parameters] |
1883
|
|
|
foo = bar |
1884
|
|
|
bar = %foo% |
1885
|
|
|
INI; |
1886
|
|
|
|
1887
|
|
|
$this->parser->parse($ini); |
1888
|
|
|
} |
1889
|
|
|
|
1890
|
|
|
private function loadTestsFromFixtureFiles($testsFile) |
1891
|
|
|
{ |
1892
|
|
|
$parser = new Parser(); |
1893
|
|
|
|
1894
|
|
|
$tests = []; |
1895
|
|
|
$files = $parser->parseFile(__DIR__.'/Fixtures/'.$testsFile); |
1896
|
|
|
foreach ($files as $file) { |
1897
|
|
|
$yamls = file_get_contents(__DIR__.'/Fixtures/'.$file.'.yml'); |
1898
|
|
|
|
1899
|
|
|
// split YAMLs documents |
1900
|
|
|
foreach (preg_split('/^---( %YAML\:1\.0)?/m', $yamls) as $yaml) { |
1901
|
|
|
if (!$yaml) { |
1902
|
|
|
continue; |
1903
|
|
|
} |
1904
|
|
|
|
1905
|
|
|
$test = $parser->parse($yaml); |
1906
|
|
|
if (isset($test['todo']) && $test['todo']) { |
1907
|
|
|
// TODO |
1908
|
|
|
} else { |
1909
|
|
|
eval('$expected = '.trim($test['php']).';'); |
|
|
|
|
1910
|
|
|
|
1911
|
|
|
$tests[] = [var_export($expected, true), $test['yaml'], $test['test'], isset($test['deprecated']) ? $test['deprecated'] : false]; |
|
|
|
|
1912
|
|
|
} |
1913
|
|
|
} |
1914
|
|
|
} |
1915
|
|
|
|
1916
|
|
|
return $tests; |
1917
|
|
|
} |
1918
|
|
|
|
1919
|
|
|
public function testCanParseVeryLongValue() |
1920
|
|
|
{ |
1921
|
|
|
$longStringWithSpaces = str_repeat('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ', 20000); |
1922
|
|
|
$trickyVal = ['x' => $longStringWithSpaces]; |
1923
|
|
|
|
1924
|
|
|
$yamlString = Yaml::dump($trickyVal); |
1925
|
|
|
$arrayFromYaml = $this->parser->parse($yamlString); |
1926
|
|
|
|
1927
|
|
|
$this->assertEquals($trickyVal, $arrayFromYaml); |
1928
|
|
|
} |
1929
|
|
|
|
1930
|
|
|
public function testParserCleansUpReferencesBetweenRuns() |
1931
|
|
|
{ |
1932
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
1933
|
|
|
$this->expectExceptionMessage('Reference "foo" does not exist at line 2'); |
1934
|
|
|
$yaml = <<<YAML |
1935
|
|
|
foo: &foo |
1936
|
|
|
baz: foobar |
1937
|
|
|
bar: |
1938
|
|
|
<<: *foo |
1939
|
|
|
YAML; |
1940
|
|
|
$this->parser->parse($yaml); |
1941
|
|
|
|
1942
|
|
|
$yaml = <<<YAML |
1943
|
|
|
bar: |
1944
|
|
|
<<: *foo |
1945
|
|
|
YAML; |
1946
|
|
|
$this->parser->parse($yaml); |
1947
|
|
|
} |
1948
|
|
|
|
1949
|
|
|
public function testPhpConstantTagMappingKey() |
1950
|
|
|
{ |
1951
|
|
|
$yaml = <<<YAML |
1952
|
|
|
transitions: |
1953
|
|
|
!php/const 'Symfony\Component\Yaml\Tests\B::FOO': |
1954
|
|
|
from: |
1955
|
|
|
- !php/const 'Symfony\Component\Yaml\Tests\B::BAR' |
1956
|
|
|
to: !php/const 'Symfony\Component\Yaml\Tests\B::BAZ' |
1957
|
|
|
YAML; |
1958
|
|
|
$expected = [ |
1959
|
|
|
'transitions' => [ |
1960
|
|
|
'foo' => [ |
1961
|
|
|
'from' => [ |
1962
|
|
|
'bar', |
1963
|
|
|
], |
1964
|
|
|
'to' => 'baz', |
1965
|
|
|
], |
1966
|
|
|
], |
1967
|
|
|
]; |
1968
|
|
|
|
1969
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml, Yaml::PARSE_CONSTANT)); |
1970
|
|
|
} |
1971
|
|
|
|
1972
|
|
|
/** |
1973
|
|
|
* @group legacy |
1974
|
|
|
* @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. |
1975
|
|
|
* @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. |
1976
|
|
|
* @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. |
1977
|
|
|
*/ |
1978
|
|
|
public function testDeprecatedPhpConstantTagMappingKey() |
1979
|
|
|
{ |
1980
|
|
|
$yaml = <<<YAML |
1981
|
|
|
transitions: |
1982
|
|
|
!php/const:Symfony\Component\Yaml\Tests\B::FOO: |
1983
|
|
|
from: |
1984
|
|
|
- !php/const:Symfony\Component\Yaml\Tests\B::BAR |
1985
|
|
|
to: !php/const:Symfony\Component\Yaml\Tests\B::BAZ |
1986
|
|
|
YAML; |
1987
|
|
|
$expected = [ |
1988
|
|
|
'transitions' => [ |
1989
|
|
|
'foo' => [ |
1990
|
|
|
'from' => [ |
1991
|
|
|
'bar', |
1992
|
|
|
], |
1993
|
|
|
'to' => 'baz', |
1994
|
|
|
], |
1995
|
|
|
], |
1996
|
|
|
]; |
1997
|
|
|
|
1998
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml, Yaml::PARSE_CONSTANT)); |
1999
|
|
|
} |
2000
|
|
|
|
2001
|
|
|
/** |
2002
|
|
|
* @group legacy |
2003
|
|
|
* @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. |
2004
|
|
|
*/ |
2005
|
|
|
public function testPhpConstantTagMappingKeyWithKeysCastToStrings() |
2006
|
|
|
{ |
2007
|
|
|
$yaml = <<<YAML |
2008
|
|
|
transitions: |
2009
|
|
|
!php/const 'Symfony\Component\Yaml\Tests\B::FOO': |
2010
|
|
|
from: |
2011
|
|
|
- !php/const 'Symfony\Component\Yaml\Tests\B::BAR' |
2012
|
|
|
to: !php/const 'Symfony\Component\Yaml\Tests\B::BAZ' |
2013
|
|
|
YAML; |
2014
|
|
|
$expected = [ |
2015
|
|
|
'transitions' => [ |
2016
|
|
|
'foo' => [ |
2017
|
|
|
'from' => [ |
2018
|
|
|
'bar', |
2019
|
|
|
], |
2020
|
|
|
'to' => 'baz', |
2021
|
|
|
], |
2022
|
|
|
], |
2023
|
|
|
]; |
2024
|
|
|
|
2025
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml, Yaml::PARSE_CONSTANT | Yaml::PARSE_KEYS_AS_STRINGS)); |
|
|
|
|
2026
|
|
|
} |
2027
|
|
|
|
2028
|
|
|
public function testPhpConstantTagMappingAsScalarKey() |
2029
|
|
|
{ |
2030
|
|
|
$yaml = <<<YAML |
2031
|
|
|
map1: |
2032
|
|
|
- foo: 'value_0' |
2033
|
|
|
!php/const 'Symfony\Component\Yaml\Tests\B::BAR': 'value_1' |
2034
|
|
|
map2: |
2035
|
|
|
- !php/const 'Symfony\Component\Yaml\Tests\B::FOO': 'value_0' |
2036
|
|
|
bar: 'value_1' |
2037
|
|
|
YAML; |
2038
|
|
|
$this->assertSame([ |
2039
|
|
|
'map1' => [['foo' => 'value_0', 'bar' => 'value_1']], |
2040
|
|
|
'map2' => [['foo' => 'value_0', 'bar' => 'value_1']], |
2041
|
|
|
], $this->parser->parse($yaml, Yaml::PARSE_CONSTANT)); |
2042
|
|
|
} |
2043
|
|
|
|
2044
|
|
|
public function testTagMappingAsScalarKey() |
2045
|
|
|
{ |
2046
|
|
|
$yaml = <<<YAML |
2047
|
|
|
map1: |
2048
|
|
|
- !!str 0: 'value_0' |
2049
|
|
|
!!str 1: 'value_1' |
2050
|
|
|
YAML; |
2051
|
|
|
$this->assertSame([ |
2052
|
|
|
'map1' => [['0' => 'value_0', '1' => 'value_1']], |
2053
|
|
|
], $this->parser->parse($yaml)); |
2054
|
|
|
} |
2055
|
|
|
|
2056
|
|
|
public function testMergeKeysWhenMappingsAreParsedAsObjects() |
2057
|
|
|
{ |
2058
|
|
|
$yaml = <<<YAML |
2059
|
|
|
foo: &FOO |
2060
|
|
|
bar: 1 |
2061
|
|
|
bar: &BAR |
2062
|
|
|
baz: 2 |
2063
|
|
|
<<: *FOO |
2064
|
|
|
baz: |
2065
|
|
|
baz_foo: 3 |
2066
|
|
|
<<: |
2067
|
|
|
baz_bar: 4 |
2068
|
|
|
foobar: |
2069
|
|
|
bar: ~ |
2070
|
|
|
<<: [*FOO, *BAR] |
2071
|
|
|
YAML; |
2072
|
|
|
$expected = (object) [ |
2073
|
|
|
'foo' => (object) [ |
2074
|
|
|
'bar' => 1, |
2075
|
|
|
], |
2076
|
|
|
'bar' => (object) [ |
2077
|
|
|
'baz' => 2, |
2078
|
|
|
'bar' => 1, |
2079
|
|
|
], |
2080
|
|
|
'baz' => (object) [ |
2081
|
|
|
'baz_foo' => 3, |
2082
|
|
|
'baz_bar' => 4, |
2083
|
|
|
], |
2084
|
|
|
'foobar' => (object) [ |
2085
|
|
|
'bar' => null, |
2086
|
|
|
'baz' => 2, |
2087
|
|
|
], |
2088
|
|
|
]; |
2089
|
|
|
|
2090
|
|
|
$this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP)); |
2091
|
|
|
} |
2092
|
|
|
|
2093
|
|
|
public function testFilenamesAreParsedAsStringsWithoutFlag() |
2094
|
|
|
{ |
2095
|
|
|
$file = __DIR__.'/Fixtures/index.yml'; |
2096
|
|
|
|
2097
|
|
|
$this->assertSame($file, $this->parser->parse($file)); |
2098
|
|
|
} |
2099
|
|
|
|
2100
|
|
|
public function testParseFile() |
2101
|
|
|
{ |
2102
|
|
|
$this->assertIsArray($this->parser->parseFile(__DIR__.'/Fixtures/index.yml')); |
2103
|
|
|
} |
2104
|
|
|
|
2105
|
|
|
public function testParsingNonExistentFilesThrowsException() |
2106
|
|
|
{ |
2107
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
2108
|
|
|
$this->expectExceptionMessageMatches('#^File ".+/Fixtures/nonexistent.yml" does not exist\.$#'); |
2109
|
|
|
$this->parser->parseFile(__DIR__.'/Fixtures/nonexistent.yml'); |
2110
|
|
|
} |
2111
|
|
|
|
2112
|
|
|
public function testParsingNotReadableFilesThrowsException() |
2113
|
|
|
{ |
2114
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
2115
|
|
|
$this->expectExceptionMessageMatches('#^File ".+/Fixtures/not_readable.yml" cannot be read\.$#'); |
2116
|
|
|
if ('\\' === \DIRECTORY_SEPARATOR) { |
2117
|
|
|
$this->markTestSkipped('chmod is not supported on Windows'); |
2118
|
|
|
} |
2119
|
|
|
|
2120
|
|
|
if (!getenv('USER') || 'root' === getenv('USER')) { |
2121
|
|
|
$this->markTestSkipped('This test will fail if run under superuser'); |
2122
|
|
|
} |
2123
|
|
|
|
2124
|
|
|
$file = __DIR__.'/Fixtures/not_readable.yml'; |
2125
|
|
|
chmod($file, 0200); |
2126
|
|
|
|
2127
|
|
|
$this->parser->parseFile($file); |
2128
|
|
|
} |
2129
|
|
|
|
2130
|
|
|
public function testParseReferencesOnMergeKeys() |
2131
|
|
|
{ |
2132
|
|
|
$yaml = <<<YAML |
2133
|
|
|
mergekeyrefdef: |
2134
|
|
|
a: foo |
2135
|
|
|
<<: &quux |
2136
|
|
|
b: bar |
2137
|
|
|
c: baz |
2138
|
|
|
mergekeyderef: |
2139
|
|
|
d: quux |
2140
|
|
|
<<: *quux |
2141
|
|
|
YAML; |
2142
|
|
|
$expected = [ |
2143
|
|
|
'mergekeyrefdef' => [ |
2144
|
|
|
'a' => 'foo', |
2145
|
|
|
'b' => 'bar', |
2146
|
|
|
'c' => 'baz', |
2147
|
|
|
], |
2148
|
|
|
'mergekeyderef' => [ |
2149
|
|
|
'd' => 'quux', |
2150
|
|
|
'b' => 'bar', |
2151
|
|
|
'c' => 'baz', |
2152
|
|
|
], |
2153
|
|
|
]; |
2154
|
|
|
|
2155
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
2156
|
|
|
} |
2157
|
|
|
|
2158
|
|
|
public function testParseReferencesOnMergeKeysWithMappingsParsedAsObjects() |
2159
|
|
|
{ |
2160
|
|
|
$yaml = <<<YAML |
2161
|
|
|
mergekeyrefdef: |
2162
|
|
|
a: foo |
2163
|
|
|
<<: &quux |
2164
|
|
|
b: bar |
2165
|
|
|
c: baz |
2166
|
|
|
mergekeyderef: |
2167
|
|
|
d: quux |
2168
|
|
|
<<: *quux |
2169
|
|
|
YAML; |
2170
|
|
|
$expected = (object) [ |
2171
|
|
|
'mergekeyrefdef' => (object) [ |
2172
|
|
|
'a' => 'foo', |
2173
|
|
|
'b' => 'bar', |
2174
|
|
|
'c' => 'baz', |
2175
|
|
|
], |
2176
|
|
|
'mergekeyderef' => (object) [ |
2177
|
|
|
'd' => 'quux', |
2178
|
|
|
'b' => 'bar', |
2179
|
|
|
'c' => 'baz', |
2180
|
|
|
], |
2181
|
|
|
]; |
2182
|
|
|
|
2183
|
|
|
$this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP)); |
2184
|
|
|
} |
2185
|
|
|
|
2186
|
|
|
public function testEvalRefException() |
2187
|
|
|
{ |
2188
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
2189
|
|
|
$this->expectExceptionMessage('Reference "foo" does not exist'); |
2190
|
|
|
$yaml = <<<EOE |
2191
|
|
|
foo: { &foo { a: Steve, <<: *foo} } |
2192
|
|
|
EOE; |
2193
|
|
|
$this->parser->parse($yaml); |
2194
|
|
|
} |
2195
|
|
|
|
2196
|
|
|
/** |
2197
|
|
|
* @dataProvider circularReferenceProvider |
2198
|
|
|
*/ |
2199
|
|
|
public function testDetectCircularReferences($yaml) |
2200
|
|
|
{ |
2201
|
|
|
$this->expectException('Symfony\Component\Yaml\Exception\ParseException'); |
2202
|
|
|
$this->expectExceptionMessage('Circular reference [foo, bar, foo] detected'); |
2203
|
|
|
$this->parser->parse($yaml, Yaml::PARSE_CUSTOM_TAGS); |
2204
|
|
|
} |
2205
|
|
|
|
2206
|
|
|
public function circularReferenceProvider() |
2207
|
|
|
{ |
2208
|
|
|
$tests = []; |
2209
|
|
|
|
2210
|
|
|
$yaml = <<<YAML |
2211
|
|
|
foo: |
2212
|
|
|
- &foo |
2213
|
|
|
- &bar |
2214
|
|
|
bar: foobar |
2215
|
|
|
baz: *foo |
2216
|
|
|
YAML; |
2217
|
|
|
$tests['sequence'] = [$yaml]; |
2218
|
|
|
|
2219
|
|
|
$yaml = <<<YAML |
2220
|
|
|
foo: &foo |
2221
|
|
|
bar: &bar |
2222
|
|
|
foobar: baz |
2223
|
|
|
baz: *foo |
2224
|
|
|
YAML; |
2225
|
|
|
$tests['mapping'] = [$yaml]; |
2226
|
|
|
|
2227
|
|
|
$yaml = <<<YAML |
2228
|
|
|
foo: &foo |
2229
|
|
|
bar: &bar |
2230
|
|
|
foobar: baz |
2231
|
|
|
<<: *foo |
2232
|
|
|
YAML; |
2233
|
|
|
$tests['mapping with merge key'] = [$yaml]; |
2234
|
|
|
|
2235
|
|
|
return $tests; |
2236
|
|
|
} |
2237
|
|
|
|
2238
|
|
|
/** |
2239
|
|
|
* @dataProvider indentedMappingData |
2240
|
|
|
*/ |
2241
|
|
|
public function testParseIndentedMappings($yaml, $expected) |
2242
|
|
|
{ |
2243
|
|
|
$this->assertSame($expected, $this->parser->parse($yaml)); |
2244
|
|
|
} |
2245
|
|
|
|
2246
|
|
|
public function indentedMappingData() |
2247
|
|
|
{ |
2248
|
|
|
$tests = []; |
2249
|
|
|
|
2250
|
|
|
$yaml = <<<YAML |
2251
|
|
|
foo: |
2252
|
|
|
- bar: "foobar" |
2253
|
|
|
# A comment |
2254
|
|
|
baz: "foobaz" |
2255
|
|
|
YAML; |
2256
|
|
|
$expected = [ |
2257
|
|
|
'foo' => [ |
2258
|
|
|
[ |
2259
|
|
|
'bar' => 'foobar', |
2260
|
|
|
'baz' => 'foobaz', |
2261
|
|
|
], |
2262
|
|
|
], |
2263
|
|
|
]; |
2264
|
|
|
$tests['comment line is first line in indented block'] = [$yaml, $expected]; |
2265
|
|
|
|
2266
|
|
|
$yaml = <<<YAML |
2267
|
|
|
foo: |
2268
|
|
|
- bar: |
2269
|
|
|
# comment |
2270
|
|
|
baz: [1, 2, 3] |
2271
|
|
|
YAML; |
2272
|
|
|
$expected = [ |
2273
|
|
|
'foo' => [ |
2274
|
|
|
[ |
2275
|
|
|
'bar' => [ |
2276
|
|
|
'baz' => [1, 2, 3], |
2277
|
|
|
], |
2278
|
|
|
], |
2279
|
|
|
], |
2280
|
|
|
]; |
2281
|
|
|
$tests['mapping value on new line starting with a comment line'] = [$yaml, $expected]; |
2282
|
|
|
|
2283
|
|
|
$yaml = <<<YAML |
2284
|
|
|
foo: |
2285
|
|
|
- |
2286
|
|
|
bar: foobar |
2287
|
|
|
YAML; |
2288
|
|
|
$expected = [ |
2289
|
|
|
'foo' => [ |
2290
|
|
|
[ |
2291
|
|
|
'bar' => 'foobar', |
2292
|
|
|
], |
2293
|
|
|
], |
2294
|
|
|
]; |
2295
|
|
|
$tests['mapping in sequence starting on a new line'] = [$yaml, $expected]; |
2296
|
|
|
|
2297
|
|
|
$yaml = <<<YAML |
2298
|
|
|
foo: |
2299
|
|
|
|
2300
|
|
|
bar: baz |
2301
|
|
|
YAML; |
2302
|
|
|
$expected = [ |
2303
|
|
|
'foo' => [ |
2304
|
|
|
'bar' => 'baz', |
2305
|
|
|
], |
2306
|
|
|
]; |
2307
|
|
|
$tests['blank line at the beginning of an indented mapping value'] = [$yaml, $expected]; |
2308
|
|
|
|
2309
|
|
|
return $tests; |
2310
|
|
|
} |
2311
|
|
|
|
2312
|
|
|
public function testMultiLineComment() |
2313
|
|
|
{ |
2314
|
|
|
$yaml = <<<YAML |
2315
|
|
|
parameters: |
2316
|
|
|
abc |
2317
|
|
|
|
2318
|
|
|
# Comment |
2319
|
|
|
YAML; |
2320
|
|
|
|
2321
|
|
|
$this->assertSame(['parameters' => 'abc'], $this->parser->parse($yaml)); |
2322
|
|
|
} |
2323
|
|
|
|
2324
|
|
|
public function testParseValueWithModifiers() |
2325
|
|
|
{ |
2326
|
|
|
$yaml = <<<YAML |
2327
|
|
|
parameters: |
2328
|
|
|
abc: |+5 # plus five spaces indent |
2329
|
|
|
one |
2330
|
|
|
two |
2331
|
|
|
three |
2332
|
|
|
four |
2333
|
|
|
five |
2334
|
|
|
YAML; |
2335
|
|
|
$this->assertSame( |
2336
|
|
|
[ |
2337
|
|
|
'parameters' => [ |
2338
|
|
|
'abc' => implode("\n", ['one', 'two', 'three', 'four', 'five']), |
2339
|
|
|
], |
2340
|
|
|
], |
2341
|
|
|
$this->parser->parse($yaml) |
2342
|
|
|
); |
2343
|
|
|
} |
2344
|
|
|
|
2345
|
|
|
public function testParseValueWithNegativeModifiers() |
2346
|
|
|
{ |
2347
|
|
|
$yaml = <<<YAML |
2348
|
|
|
parameters: |
2349
|
|
|
abc: |-3 # minus |
2350
|
|
|
one |
2351
|
|
|
two |
2352
|
|
|
three |
2353
|
|
|
four |
2354
|
|
|
five |
2355
|
|
|
YAML; |
2356
|
|
|
$this->assertSame( |
2357
|
|
|
[ |
2358
|
|
|
'parameters' => [ |
2359
|
|
|
'abc' => implode("\n", ['one', 'two', 'three', 'four', 'five']), |
2360
|
|
|
], |
2361
|
|
|
], |
2362
|
|
|
$this->parser->parse($yaml) |
2363
|
|
|
); |
2364
|
|
|
} |
2365
|
|
|
|
2366
|
|
|
/** |
2367
|
|
|
* This is a regression test for a bug where a YAML block with a nested multiline string using | was parsed without |
2368
|
|
|
* a trailing \n when a shorter YAML document was parsed before. |
2369
|
|
|
* |
2370
|
|
|
* When a shorter document was parsed before, the nested string did not have a \n at the end of the string, because |
2371
|
|
|
* the Parser thought it was the end of the file, even though it is not. |
2372
|
|
|
*/ |
2373
|
|
|
public function testParsingMultipleDocuments() |
2374
|
|
|
{ |
2375
|
|
|
$shortDocument = 'foo: bar'; |
2376
|
|
|
$longDocument = <<<YAML |
2377
|
|
|
a: |
2378
|
|
|
b: | |
2379
|
|
|
row |
2380
|
|
|
row2 |
2381
|
|
|
c: d |
2382
|
|
|
YAML; |
2383
|
|
|
|
2384
|
|
|
// The first parsing set and fixed the totalNumberOfLines in the Parser before, so parsing the short document here |
2385
|
|
|
// to reproduce the issue. If the issue would not have been fixed, the next assertion will fail |
2386
|
|
|
$this->parser->parse($shortDocument); |
2387
|
|
|
|
2388
|
|
|
// After the total number of lines has been reset the result will be the same as if a new parser was used |
2389
|
|
|
// (before, there was no \n after row2) |
2390
|
|
|
$this->assertSame(['a' => ['b' => "row\nrow2\n"], 'c' => 'd'], $this->parser->parse($longDocument)); |
|
|
|
|
2391
|
|
|
} |
2392
|
|
|
} |
2393
|
|
|
|
2394
|
|
|
class B |
2395
|
|
|
{ |
2396
|
|
|
public $b = 'foo'; |
2397
|
|
|
|
2398
|
|
|
const FOO = 'foo'; |
2399
|
|
|
const BAR = 'bar'; |
2400
|
|
|
const BAZ = 'baz'; |
2401
|
|
|
} |
2402
|
|
|
|
This class constant has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.