1922 lines
47 KiB
Dart
1922 lines
47 KiB
Dart
|
|
// Copyright (c) 2012, the Dart project authors.
|
|||
|
|
// Copyright (c) 2006, Kirill Simonov.
|
|||
|
|
//
|
|||
|
|
// Use of this source code is governed by an MIT-style
|
|||
|
|
// license that can be found in the LICENSE file or at
|
|||
|
|
// https://opensource.org/licenses/MIT.
|
|||
|
|
|
|||
|
|
// ignore_for_file: avoid_dynamic_calls
|
|||
|
|
|
|||
|
|
import 'package:test/test.dart';
|
|||
|
|
import 'package:yaml/src/error_listener.dart';
|
|||
|
|
import 'package:yaml/yaml.dart';
|
|||
|
|
|
|||
|
|
import 'utils.dart';
|
|||
|
|
|
|||
|
|
void main() {
|
|||
|
|
var infinity = double.parse('Infinity');
|
|||
|
|
var nan = double.parse('NaN');
|
|||
|
|
|
|||
|
|
group('has a friendly error message for', () {
|
|||
|
|
var tabError = predicate((e) =>
|
|||
|
|
e.toString().contains('Tab characters are not allowed as indentation'));
|
|||
|
|
|
|||
|
|
test('using a tab as indentation', () {
|
|||
|
|
expect(() => loadYaml('foo:\n\tbar'), throwsA(tabError));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('using a tab not as indentation', () {
|
|||
|
|
expect(() => loadYaml('''
|
|||
|
|
"foo
|
|||
|
|
\tbar"
|
|||
|
|
error'''), throwsA(isNot(tabError)));
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('refuses', () {
|
|||
|
|
// Regression test for #19.
|
|||
|
|
test('invalid contents', () {
|
|||
|
|
expectYamlFails('{');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('duplicate mapping keys', () {
|
|||
|
|
expectYamlFails('{a: 1, a: 2}');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('documents that declare version', () {
|
|||
|
|
test('1.0', () {
|
|||
|
|
expectYamlFails('''
|
|||
|
|
%YAML 1.0
|
|||
|
|
--- text
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('1.3', () {
|
|||
|
|
expectYamlFails('''
|
|||
|
|
%YAML 1.3
|
|||
|
|
--- text
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('2.0', () {
|
|||
|
|
expectYamlFails('''
|
|||
|
|
%YAML 2.0
|
|||
|
|
--- text
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('recovers', () {
|
|||
|
|
var collector = ErrorCollector();
|
|||
|
|
setUp(() {
|
|||
|
|
collector = ErrorCollector();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('from incomplete leading keys', () {
|
|||
|
|
final yaml = cleanUpLiteral(r'''
|
|||
|
|
dependencies:
|
|||
|
|
zero
|
|||
|
|
one: any
|
|||
|
|
''');
|
|||
|
|
var result = loadYaml(yaml, recover: true, errorListener: collector);
|
|||
|
|
expect(
|
|||
|
|
result,
|
|||
|
|
deepEquals({
|
|||
|
|
'dependencies': {
|
|||
|
|
'zero': null,
|
|||
|
|
'one': 'any',
|
|||
|
|
}
|
|||
|
|
}));
|
|||
|
|
expect(collector.errors.length, equals(1));
|
|||
|
|
// These errors are reported at the start of the next token (after the
|
|||
|
|
// whitespace/newlines).
|
|||
|
|
expectErrorAtLineCol(collector.errors[0], "Expected ':'.", 2, 2);
|
|||
|
|
// Skipped because this case is not currently handled. If it's the first
|
|||
|
|
// package without the colon, because the value is indented from the line
|
|||
|
|
// above, the whole `zero\n one` is treated as a scalar value.
|
|||
|
|
}, skip: true);
|
|||
|
|
test('from incomplete keys', () {
|
|||
|
|
final yaml = cleanUpLiteral(r'''
|
|||
|
|
dependencies:
|
|||
|
|
one: any
|
|||
|
|
two
|
|||
|
|
three:
|
|||
|
|
four
|
|||
|
|
five:
|
|||
|
|
1.2.3
|
|||
|
|
six: 5.4.3
|
|||
|
|
''');
|
|||
|
|
var result = loadYaml(yaml, recover: true, errorListener: collector);
|
|||
|
|
expect(
|
|||
|
|
result,
|
|||
|
|
deepEquals({
|
|||
|
|
'dependencies': {
|
|||
|
|
'one': 'any',
|
|||
|
|
'two': null,
|
|||
|
|
'three': null,
|
|||
|
|
'four': null,
|
|||
|
|
'five': '1.2.3',
|
|||
|
|
'six': '5.4.3',
|
|||
|
|
}
|
|||
|
|
}));
|
|||
|
|
|
|||
|
|
expect(collector.errors.length, equals(2));
|
|||
|
|
// These errors are reported at the start of the next token (after the
|
|||
|
|
// whitespace/newlines).
|
|||
|
|
expectErrorAtLineCol(collector.errors[0], "Expected ':'.", 3, 2);
|
|||
|
|
expectErrorAtLineCol(collector.errors[1], "Expected ':'.", 5, 2);
|
|||
|
|
});
|
|||
|
|
test('from incomplete trailing keys', () {
|
|||
|
|
final yaml = cleanUpLiteral(r'''
|
|||
|
|
dependencies:
|
|||
|
|
six: 5.4.3
|
|||
|
|
seven
|
|||
|
|
''');
|
|||
|
|
var result = loadYaml(yaml, recover: true);
|
|||
|
|
expect(
|
|||
|
|
result,
|
|||
|
|
deepEquals({
|
|||
|
|
'dependencies': {
|
|||
|
|
'six': '5.4.3',
|
|||
|
|
'seven': null,
|
|||
|
|
}
|
|||
|
|
}));
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('includes source span information', () {
|
|||
|
|
var yaml = loadYamlNode(r'''
|
|||
|
|
- foo:
|
|||
|
|
bar
|
|||
|
|
- 123
|
|||
|
|
''') as YamlList;
|
|||
|
|
|
|||
|
|
expect(yaml.span.start.line, equals(0));
|
|||
|
|
expect(yaml.span.start.column, equals(0));
|
|||
|
|
expect(yaml.span.end.line, equals(3));
|
|||
|
|
expect(yaml.span.end.column, equals(0));
|
|||
|
|
|
|||
|
|
var map = yaml.nodes.first as YamlMap;
|
|||
|
|
expect(map.span.start.line, equals(0));
|
|||
|
|
expect(map.span.start.column, equals(2));
|
|||
|
|
expect(map.span.end.line, equals(2));
|
|||
|
|
expect(map.span.end.column, equals(0));
|
|||
|
|
|
|||
|
|
var key = map.nodes.keys.first;
|
|||
|
|
expect(key.span.start.line, equals(0));
|
|||
|
|
expect(key.span.start.column, equals(2));
|
|||
|
|
expect(key.span.end.line, equals(0));
|
|||
|
|
expect(key.span.end.column, equals(5));
|
|||
|
|
|
|||
|
|
var value = map.nodes.values.first;
|
|||
|
|
expect(value.span.start.line, equals(1));
|
|||
|
|
expect(value.span.start.column, equals(4));
|
|||
|
|
expect(value.span.end.line, equals(1));
|
|||
|
|
expect(value.span.end.column, equals(7));
|
|||
|
|
|
|||
|
|
var scalar = yaml.nodes.last;
|
|||
|
|
expect(scalar.span.start.line, equals(2));
|
|||
|
|
expect(scalar.span.start.column, equals(2));
|
|||
|
|
expect(scalar.span.end.line, equals(2));
|
|||
|
|
expect(scalar.span.end.column, equals(5));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// The following tests are all taken directly from the YAML spec
|
|||
|
|
// (http://www.yaml.org/spec/1.2/spec.html). Most of them are code examples
|
|||
|
|
// that are directly included in the spec, but additional tests are derived
|
|||
|
|
// from the prose.
|
|||
|
|
|
|||
|
|
// A few examples from the spec are deliberately excluded, because they test
|
|||
|
|
// features that this implementation doesn't intend to support (character
|
|||
|
|
// encoding detection and user-defined tags). More tests are commented out,
|
|||
|
|
// because they're intended to be supported but not yet implemented.
|
|||
|
|
|
|||
|
|
// Chapter 2 is just a preview of various Yaml documents. It's probably not
|
|||
|
|
// necessary to test its examples, but it would be nice to test everything in
|
|||
|
|
// the spec.
|
|||
|
|
group('2.1: Collections', () {
|
|||
|
|
test('[Example 2.1]', () {
|
|||
|
|
expectYamlLoads(['Mark McGwire', 'Sammy Sosa', 'Ken Griffey'], '''
|
|||
|
|
- Mark McGwire
|
|||
|
|
- Sammy Sosa
|
|||
|
|
- Ken Griffey''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.2]', () {
|
|||
|
|
expectYamlLoads({'hr': 65, 'avg': 0.278, 'rbi': 147}, '''
|
|||
|
|
hr: 65 # Home runs
|
|||
|
|
avg: 0.278 # Batting average
|
|||
|
|
rbi: 147 # Runs Batted In''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.3]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'american': ['Boston Red Sox', 'Detroit Tigers', 'New York Yankees'],
|
|||
|
|
'national': ['New York Mets', 'Chicago Cubs', 'Atlanta Braves'],
|
|||
|
|
}, '''
|
|||
|
|
american:
|
|||
|
|
- Boston Red Sox
|
|||
|
|
- Detroit Tigers
|
|||
|
|
- New York Yankees
|
|||
|
|
national:
|
|||
|
|
- New York Mets
|
|||
|
|
- Chicago Cubs
|
|||
|
|
- Atlanta Braves''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.4]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
{'name': 'Mark McGwire', 'hr': 65, 'avg': 0.278},
|
|||
|
|
{'name': 'Sammy Sosa', 'hr': 63, 'avg': 0.288},
|
|||
|
|
], '''
|
|||
|
|
-
|
|||
|
|
name: Mark McGwire
|
|||
|
|
hr: 65
|
|||
|
|
avg: 0.278
|
|||
|
|
-
|
|||
|
|
name: Sammy Sosa
|
|||
|
|
hr: 63
|
|||
|
|
avg: 0.288''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.5]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
['name', 'hr', 'avg'],
|
|||
|
|
['Mark McGwire', 65, 0.278],
|
|||
|
|
['Sammy Sosa', 63, 0.288]
|
|||
|
|
], '''
|
|||
|
|
- [name , hr, avg ]
|
|||
|
|
- [Mark McGwire, 65, 0.278]
|
|||
|
|
- [Sammy Sosa , 63, 0.288]''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.6]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'Mark McGwire': {'hr': 65, 'avg': 0.278},
|
|||
|
|
'Sammy Sosa': {'hr': 63, 'avg': 0.288}
|
|||
|
|
}, '''
|
|||
|
|
Mark McGwire: {hr: 65, avg: 0.278}
|
|||
|
|
Sammy Sosa: {
|
|||
|
|
hr: 63,
|
|||
|
|
avg: 0.288
|
|||
|
|
}''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('2.2: Structures', () {
|
|||
|
|
test('[Example 2.7]', () {
|
|||
|
|
expectYamlStreamLoads([
|
|||
|
|
['Mark McGwire', 'Sammy Sosa', 'Ken Griffey'],
|
|||
|
|
['Chicago Cubs', 'St Louis Cardinals']
|
|||
|
|
], '''
|
|||
|
|
# Ranking of 1998 home runs
|
|||
|
|
---
|
|||
|
|
- Mark McGwire
|
|||
|
|
- Sammy Sosa
|
|||
|
|
- Ken Griffey
|
|||
|
|
|
|||
|
|
# Team ranking
|
|||
|
|
---
|
|||
|
|
- Chicago Cubs
|
|||
|
|
- St Louis Cardinals''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.8]', () {
|
|||
|
|
expectYamlStreamLoads([
|
|||
|
|
{'time': '20:03:20', 'player': 'Sammy Sosa', 'action': 'strike (miss)'},
|
|||
|
|
{'time': '20:03:47', 'player': 'Sammy Sosa', 'action': 'grand slam'},
|
|||
|
|
], '''
|
|||
|
|
---
|
|||
|
|
time: 20:03:20
|
|||
|
|
player: Sammy Sosa
|
|||
|
|
action: strike (miss)
|
|||
|
|
...
|
|||
|
|
---
|
|||
|
|
time: 20:03:47
|
|||
|
|
player: Sammy Sosa
|
|||
|
|
action: grand slam
|
|||
|
|
...''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.9]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'hr': ['Mark McGwire', 'Sammy Sosa'],
|
|||
|
|
'rbi': ['Sammy Sosa', 'Ken Griffey']
|
|||
|
|
}, '''
|
|||
|
|
---
|
|||
|
|
hr: # 1998 hr ranking
|
|||
|
|
- Mark McGwire
|
|||
|
|
- Sammy Sosa
|
|||
|
|
rbi:
|
|||
|
|
# 1998 rbi ranking
|
|||
|
|
- Sammy Sosa
|
|||
|
|
- Ken Griffey''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.10]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'hr': ['Mark McGwire', 'Sammy Sosa'],
|
|||
|
|
'rbi': ['Sammy Sosa', 'Ken Griffey']
|
|||
|
|
}, '''
|
|||
|
|
---
|
|||
|
|
hr:
|
|||
|
|
- Mark McGwire
|
|||
|
|
# Following node labeled SS
|
|||
|
|
- &SS Sammy Sosa
|
|||
|
|
rbi:
|
|||
|
|
- *SS # Subsequent occurrence
|
|||
|
|
- Ken Griffey''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.11]', () {
|
|||
|
|
var doc = deepEqualsMap();
|
|||
|
|
doc[['Detroit Tigers', 'Chicago cubs']] = ['2001-07-23'];
|
|||
|
|
doc[['New York Yankees', 'Atlanta Braves']] = [
|
|||
|
|
'2001-07-02',
|
|||
|
|
'2001-08-12',
|
|||
|
|
'2001-08-14'
|
|||
|
|
];
|
|||
|
|
expectYamlLoads(doc, '''
|
|||
|
|
? - Detroit Tigers
|
|||
|
|
- Chicago cubs
|
|||
|
|
:
|
|||
|
|
- 2001-07-23
|
|||
|
|
|
|||
|
|
? [ New York Yankees,
|
|||
|
|
Atlanta Braves ]
|
|||
|
|
: [ 2001-07-02, 2001-08-12,
|
|||
|
|
2001-08-14 ]''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.12]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
{'item': 'Super Hoop', 'quantity': 1},
|
|||
|
|
{'item': 'Basketball', 'quantity': 4},
|
|||
|
|
{'item': 'Big Shoes', 'quantity': 1},
|
|||
|
|
], '''
|
|||
|
|
---
|
|||
|
|
# Products purchased
|
|||
|
|
- item : Super Hoop
|
|||
|
|
quantity: 1
|
|||
|
|
- item : Basketball
|
|||
|
|
quantity: 4
|
|||
|
|
- item : Big Shoes
|
|||
|
|
quantity: 1''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('2.3: Scalars', () {
|
|||
|
|
test('[Example 2.13]', () {
|
|||
|
|
expectYamlLoads(cleanUpLiteral('''
|
|||
|
|
\\//||\\/||
|
|||
|
|
// || ||__'''), '''
|
|||
|
|
# ASCII Art
|
|||
|
|
--- |
|
|||
|
|
\\//||\\/||
|
|||
|
|
// || ||__''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.14]', () {
|
|||
|
|
expectYamlLoads("Mark McGwire's year was crippled by a knee injury.", '''
|
|||
|
|
--- >
|
|||
|
|
Mark McGwire's
|
|||
|
|
year was crippled
|
|||
|
|
by a knee injury.''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.15]', () {
|
|||
|
|
expectYamlLoads(cleanUpLiteral('''
|
|||
|
|
Sammy Sosa completed another fine season with great stats.
|
|||
|
|
|
|||
|
|
63 Home Runs
|
|||
|
|
0.288 Batting Average
|
|||
|
|
|
|||
|
|
What a year!'''), '''
|
|||
|
|
>
|
|||
|
|
Sammy Sosa completed another
|
|||
|
|
fine season with great stats.
|
|||
|
|
|
|||
|
|
63 Home Runs
|
|||
|
|
0.288 Batting Average
|
|||
|
|
|
|||
|
|
What a year!''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.16]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'name': 'Mark McGwire',
|
|||
|
|
'accomplishment': 'Mark set a major league home run record in 1998.\n',
|
|||
|
|
'stats': '65 Home Runs\n0.278 Batting Average'
|
|||
|
|
}, '''
|
|||
|
|
name: Mark McGwire
|
|||
|
|
accomplishment: >
|
|||
|
|
Mark set a major league
|
|||
|
|
home run record in 1998.
|
|||
|
|
stats: |
|
|||
|
|
65 Home Runs
|
|||
|
|
0.278 Batting Average''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.17]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'unicode': 'Sosa did fine.\u263A \u{1F680}',
|
|||
|
|
'control': '\b1998\t1999\t2000\n',
|
|||
|
|
'hex esc': '\r\n is \r\n',
|
|||
|
|
'single': '"Howdy!" he cried.',
|
|||
|
|
'quoted': " # Not a 'comment'.",
|
|||
|
|
'tie-fighter': '|\\-*-/|',
|
|||
|
|
'surrogate-pair': 'I \u{D83D}\u{DE03} ️Dart!',
|
|||
|
|
'key-\u{D83D}\u{DD11}': 'Look\u{D83D}\u{DE03}\u{D83C}\u{DF89}surprise!',
|
|||
|
|
}, """
|
|||
|
|
unicode: "Sosa did fine.\\u263A \\U0001F680"
|
|||
|
|
control: "\\b1998\\t1999\\t2000\\n"
|
|||
|
|
hex esc: "\\x0d\\x0a is \\r\\n"
|
|||
|
|
|
|||
|
|
single: '"Howdy!" he cried.'
|
|||
|
|
quoted: ' # Not a ''comment''.'
|
|||
|
|
tie-fighter: '|\\-*-/|'
|
|||
|
|
|
|||
|
|
surrogate-pair: I \u{D83D}\u{DE03} ️Dart!
|
|||
|
|
key-\u{D83D}\u{DD11}: Look\u{D83D}\u{DE03}\u{D83C}\u{DF89}surprise!""");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.18]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'plain': 'This unquoted scalar spans many lines.',
|
|||
|
|
'quoted': 'So does this quoted scalar.\n'
|
|||
|
|
}, '''
|
|||
|
|
plain:
|
|||
|
|
This unquoted scalar
|
|||
|
|
spans many lines.
|
|||
|
|
|
|||
|
|
quoted: "So does this
|
|||
|
|
quoted scalar.\\n"''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('2.4: Tags', () {
|
|||
|
|
test('[Example 2.19]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'canonical': 12345,
|
|||
|
|
'decimal': 12345,
|
|||
|
|
'octal': 12,
|
|||
|
|
'hexadecimal': 12
|
|||
|
|
}, '''
|
|||
|
|
canonical: 12345
|
|||
|
|
decimal: +12345
|
|||
|
|
octal: 0o14
|
|||
|
|
hexadecimal: 0xC''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.20]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'canonical': 1230.15,
|
|||
|
|
'exponential': 1230.15,
|
|||
|
|
'fixed': 1230.15,
|
|||
|
|
'negative infinity': -infinity,
|
|||
|
|
'not a number': nan
|
|||
|
|
}, '''
|
|||
|
|
canonical: 1.23015e+3
|
|||
|
|
exponential: 12.3015e+02
|
|||
|
|
fixed: 1230.15
|
|||
|
|
negative infinity: -.inf
|
|||
|
|
not a number: .NaN''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 2.21]', () {
|
|||
|
|
var doc = deepEqualsMap({
|
|||
|
|
'booleans': [true, false],
|
|||
|
|
'string': '012345'
|
|||
|
|
});
|
|||
|
|
doc[null] = null;
|
|||
|
|
expectYamlLoads(doc, """
|
|||
|
|
null:
|
|||
|
|
booleans: [ true, false ]
|
|||
|
|
string: '012345'""");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Examples 2.22 through 2.26 test custom tag URIs, which this
|
|||
|
|
// implementation currently doesn't plan to support.
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('2.5 Full Length Example', () {
|
|||
|
|
// Example 2.27 tests custom tag URIs, which this implementation currently
|
|||
|
|
// doesn't plan to support.
|
|||
|
|
|
|||
|
|
test('[Example 2.28]', () {
|
|||
|
|
expectYamlStreamLoads([
|
|||
|
|
{
|
|||
|
|
'Time': '2001-11-23 15:01:42 -5',
|
|||
|
|
'User': 'ed',
|
|||
|
|
'Warning': 'This is an error message for the log file'
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
'Time': '2001-11-23 15:02:31 -5',
|
|||
|
|
'User': 'ed',
|
|||
|
|
'Warning': 'A slightly different error message.'
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
'DateTime': '2001-11-23 15:03:17 -5',
|
|||
|
|
'User': 'ed',
|
|||
|
|
'Fatal': 'Unknown variable "bar"',
|
|||
|
|
'Stack': [
|
|||
|
|
{
|
|||
|
|
'file': 'TopClass.py',
|
|||
|
|
'line': 23,
|
|||
|
|
'code': 'x = MoreObject("345\\n")\n'
|
|||
|
|
},
|
|||
|
|
{'file': 'MoreClass.py', 'line': 58, 'code': 'foo = bar'}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
], '''
|
|||
|
|
---
|
|||
|
|
Time: 2001-11-23 15:01:42 -5
|
|||
|
|
User: ed
|
|||
|
|
Warning:
|
|||
|
|
This is an error message
|
|||
|
|
for the log file
|
|||
|
|
---
|
|||
|
|
Time: 2001-11-23 15:02:31 -5
|
|||
|
|
User: ed
|
|||
|
|
Warning:
|
|||
|
|
A slightly different error
|
|||
|
|
message.
|
|||
|
|
---
|
|||
|
|
DateTime: 2001-11-23 15:03:17 -5
|
|||
|
|
User: ed
|
|||
|
|
Fatal:
|
|||
|
|
Unknown variable "bar"
|
|||
|
|
Stack:
|
|||
|
|
- file: TopClass.py
|
|||
|
|
line: 23
|
|||
|
|
code: |
|
|||
|
|
x = MoreObject("345\\n")
|
|||
|
|
- file: MoreClass.py
|
|||
|
|
line: 58
|
|||
|
|
code: |-
|
|||
|
|
foo = bar''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Chapter 3 just talks about the structure of loading and dumping Yaml.
|
|||
|
|
// Chapter 4 explains conventions used in the spec.
|
|||
|
|
|
|||
|
|
// Chapter 5: Characters
|
|||
|
|
group('5.1: Character Set', () {
|
|||
|
|
void expectAllowsCharacter(int charCode) {
|
|||
|
|
var char = String.fromCharCodes([charCode]);
|
|||
|
|
expectYamlLoads('The character "$char" is allowed',
|
|||
|
|
'The character "$char" is allowed');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void expectAllowsQuotedCharacter(int charCode) {
|
|||
|
|
var char = String.fromCharCodes([charCode]);
|
|||
|
|
expectYamlLoads("The character '$char' is allowed",
|
|||
|
|
'"The character \'$char\' is allowed"');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void expectDisallowsCharacter(int charCode) {
|
|||
|
|
var char = String.fromCharCodes([charCode]);
|
|||
|
|
expectYamlFails('The character "$char" is disallowed');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
test("doesn't include C0 control characters", () {
|
|||
|
|
expectDisallowsCharacter(0x0);
|
|||
|
|
expectDisallowsCharacter(0x8);
|
|||
|
|
expectDisallowsCharacter(0x1F);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('includes TAB', () => expectAllowsCharacter(0x9));
|
|||
|
|
test("doesn't include DEL", () => expectDisallowsCharacter(0x7F));
|
|||
|
|
|
|||
|
|
test("doesn't include C1 control characters", () {
|
|||
|
|
expectDisallowsCharacter(0x80);
|
|||
|
|
expectDisallowsCharacter(0x8A);
|
|||
|
|
expectDisallowsCharacter(0x9F);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('includes NEL', () => expectAllowsCharacter(0x85));
|
|||
|
|
|
|||
|
|
group('within quoted strings', () {
|
|||
|
|
test('includes DEL', () => expectAllowsQuotedCharacter(0x7F));
|
|||
|
|
test('includes C1 control characters', () {
|
|||
|
|
expectAllowsQuotedCharacter(0x80);
|
|||
|
|
expectAllowsQuotedCharacter(0x8A);
|
|||
|
|
expectAllowsQuotedCharacter(0x9F);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Skipping section 5.2 (Character Encodings), since at the moment the module
|
|||
|
|
// assumes that the client code is providing it with a string of the proper
|
|||
|
|
// encoding.
|
|||
|
|
|
|||
|
|
group('5.3: Indicator Characters', () {
|
|||
|
|
test('[Example 5.3]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'sequence': ['one', 'two'],
|
|||
|
|
'mapping': {'sky': 'blue', 'sea': 'green'}
|
|||
|
|
}, '''
|
|||
|
|
sequence:
|
|||
|
|
- one
|
|||
|
|
- two
|
|||
|
|
mapping:
|
|||
|
|
? sky
|
|||
|
|
: blue
|
|||
|
|
sea : green''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 5.4]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'sequence': ['one', 'two'],
|
|||
|
|
'mapping': {'sky': 'blue', 'sea': 'green'}
|
|||
|
|
}, '''
|
|||
|
|
sequence: [ one, two, ]
|
|||
|
|
mapping: { sky: blue, sea: green }''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 5.5]', () => expectYamlLoads(null, '# Comment only.'));
|
|||
|
|
|
|||
|
|
// Skipping 5.6 because it uses an undefined tag.
|
|||
|
|
|
|||
|
|
test('[Example 5.7]', () {
|
|||
|
|
expectYamlLoads({'literal': 'some\ntext\n', 'folded': 'some text\n'}, '''
|
|||
|
|
literal: |
|
|||
|
|
some
|
|||
|
|
text
|
|||
|
|
folded: >
|
|||
|
|
some
|
|||
|
|
text
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 5.8]', () {
|
|||
|
|
expectYamlLoads({'single': 'text', 'double': 'text'}, '''
|
|||
|
|
single: 'text'
|
|||
|
|
double: "text"
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 5.9]', () {
|
|||
|
|
expectYamlLoads('text', '''
|
|||
|
|
%YAML 1.2
|
|||
|
|
--- text''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 5.10]', () {
|
|||
|
|
expectYamlFails('commercial-at: @text');
|
|||
|
|
expectYamlFails('commercial-at: `text');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('5.4: Line Break Characters', () {
|
|||
|
|
group('include', () {
|
|||
|
|
test('\\n', () => expectYamlLoads([1, 2], indentLiteral('- 1\n- 2')));
|
|||
|
|
test('\\r', () => expectYamlLoads([1, 2], '- 1\r- 2'));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('do not include', () {
|
|||
|
|
test('form feed', () => expectYamlFails('- 1\x0C- 2'));
|
|||
|
|
test('NEL', () => expectYamlLoads(['1\x85- 2'], '- 1\x85- 2'));
|
|||
|
|
test('0x2028', () => expectYamlLoads(['1\u2028- 2'], '- 1\u2028- 2'));
|
|||
|
|
test('0x2029', () => expectYamlLoads(['1\u2029- 2'], '- 1\u2029- 2'));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('in a scalar context must be normalized', () {
|
|||
|
|
test(
|
|||
|
|
'from \\r to \\n',
|
|||
|
|
() => expectYamlLoads(
|
|||
|
|
['foo\nbar'], indentLiteral('- |\n foo\r bar')));
|
|||
|
|
test(
|
|||
|
|
'from \\r\\n to \\n',
|
|||
|
|
() => expectYamlLoads(
|
|||
|
|
['foo\nbar'], indentLiteral('- |\n foo\r\n bar')));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 5.11]', () {
|
|||
|
|
expectYamlLoads(cleanUpLiteral('''
|
|||
|
|
Line break (no glyph)
|
|||
|
|
Line break (glyphed)'''), '''
|
|||
|
|
|
|
|||
|
|
Line break (no glyph)
|
|||
|
|
Line break (glyphed)''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('5.5: White Space Characters', () {
|
|||
|
|
test('[Example 5.12]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'quoted': 'Quoted \t',
|
|||
|
|
'block': 'void main() {\n\tprintf("Hello, world!\\n");\n}\n'
|
|||
|
|
}, '''
|
|||
|
|
# Tabs and spaces
|
|||
|
|
quoted: "Quoted \t"
|
|||
|
|
block:\t|
|
|||
|
|
void main() {
|
|||
|
|
\tprintf("Hello, world!\\n");
|
|||
|
|
}
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('5.7: Escaped Characters', () {
|
|||
|
|
test('[Example 5.13]', () {
|
|||
|
|
expectYamlLoads(
|
|||
|
|
'Fun with \x5C '
|
|||
|
|
'\x22 \x07 \x08 \x1B \x0C '
|
|||
|
|
'\x0A \x0D \x09 \x0B \x00 '
|
|||
|
|
'\x20 \xA0 \x85 \u2028 \u2029 '
|
|||
|
|
'A A A',
|
|||
|
|
'''
|
|||
|
|
"Fun with \\\\
|
|||
|
|
\\" \\a \\b \\e \\f \\
|
|||
|
|
\\n \\r \\t \\v \\0 \\
|
|||
|
|
\\ \\_ \\N \\L \\P \\
|
|||
|
|
\\x41 \\u0041 \\U00000041"''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 5.14]', () {
|
|||
|
|
expectYamlFails('Bad escape: "\\c"');
|
|||
|
|
expectYamlFails('Bad escape: "\\xq-"');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Chapter 6: Basic Structures
|
|||
|
|
group('6.1: Indentation Spaces', () {
|
|||
|
|
test('may not include TAB characters', () {
|
|||
|
|
expectYamlFails('''
|
|||
|
|
-
|
|||
|
|
\t- foo
|
|||
|
|
\t- bar''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('must be the same for all sibling nodes', () {
|
|||
|
|
expectYamlFails('''
|
|||
|
|
-
|
|||
|
|
- foo
|
|||
|
|
- bar''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('may be different for the children of sibling nodes', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
['foo'],
|
|||
|
|
['bar']
|
|||
|
|
], '''
|
|||
|
|
-
|
|||
|
|
- foo
|
|||
|
|
-
|
|||
|
|
- bar''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.1]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'Not indented': {
|
|||
|
|
'By one space': 'By four\n spaces\n',
|
|||
|
|
'Flow style': ['By two', 'Also by two', 'Still by two']
|
|||
|
|
}
|
|||
|
|
}, '''
|
|||
|
|
# Leading comment line spaces are
|
|||
|
|
# neither content nor indentation.
|
|||
|
|
|
|||
|
|
Not indented:
|
|||
|
|
By one space: |
|
|||
|
|
By four
|
|||
|
|
spaces
|
|||
|
|
Flow style: [ # Leading spaces
|
|||
|
|
By two, # in flow style
|
|||
|
|
Also by two, # are neither
|
|||
|
|
\tStill by two # content nor
|
|||
|
|
] # indentation.''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.2]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'a': [
|
|||
|
|
'b',
|
|||
|
|
['c', 'd']
|
|||
|
|
]
|
|||
|
|
}, '''
|
|||
|
|
? a
|
|||
|
|
: -\tb
|
|||
|
|
- -\tc
|
|||
|
|
- d''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('6.2: Separation Spaces', () {
|
|||
|
|
test('[Example 6.3]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
{'foo': 'bar'},
|
|||
|
|
['baz', 'baz']
|
|||
|
|
], '''
|
|||
|
|
- foo:\t bar
|
|||
|
|
- - baz
|
|||
|
|
-\tbaz''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('6.3: Line Prefixes', () {
|
|||
|
|
test('[Example 6.4]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'plain': 'text lines',
|
|||
|
|
'quoted': 'text lines',
|
|||
|
|
'block': 'text\n \tlines\n'
|
|||
|
|
}, '''
|
|||
|
|
plain: text
|
|||
|
|
lines
|
|||
|
|
quoted: "text
|
|||
|
|
\tlines"
|
|||
|
|
block: |
|
|||
|
|
text
|
|||
|
|
\tlines
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('6.4: Empty Lines', () {
|
|||
|
|
test('[Example 6.5]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'Folding': 'Empty line\nas a line feed',
|
|||
|
|
'Chomping': 'Clipped empty lines\n',
|
|||
|
|
}, '''
|
|||
|
|
Folding:
|
|||
|
|
"Empty line
|
|||
|
|
\t
|
|||
|
|
as a line feed"
|
|||
|
|
Chomping: |
|
|||
|
|
Clipped empty lines
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('6.5: Line Folding', () {
|
|||
|
|
test('[Example 6.6]', () {
|
|||
|
|
expectYamlLoads('trimmed\n\n\nas space', '''
|
|||
|
|
>-
|
|||
|
|
trimmed
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
as
|
|||
|
|
space
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.7]', () {
|
|||
|
|
expectYamlLoads('foo \n\n\t bar\n\nbaz\n', '''
|
|||
|
|
>
|
|||
|
|
foo
|
|||
|
|
|
|||
|
|
\t bar
|
|||
|
|
|
|||
|
|
baz
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.8]', () {
|
|||
|
|
expectYamlLoads(' foo\nbar\nbaz ', '''
|
|||
|
|
"
|
|||
|
|
foo
|
|||
|
|
|
|||
|
|
\t bar
|
|||
|
|
|
|||
|
|
baz
|
|||
|
|
"''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('6.6: Comments', () {
|
|||
|
|
test('must be separated from other tokens by white space characters', () {
|
|||
|
|
expectYamlLoads('foo#bar', 'foo#bar');
|
|||
|
|
expectYamlLoads('foo:#bar', 'foo:#bar');
|
|||
|
|
expectYamlLoads('-#bar', '-#bar');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.9]', () {
|
|||
|
|
expectYamlLoads({'key': 'value'}, '''
|
|||
|
|
key: # Comment
|
|||
|
|
value''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('outside of scalar content', () {
|
|||
|
|
test('may appear on a line of their own', () {
|
|||
|
|
expectYamlLoads([1, 2], '''
|
|||
|
|
- 1
|
|||
|
|
# Comment
|
|||
|
|
- 2''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('are independent of indentation level', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
[1, 2]
|
|||
|
|
], '''
|
|||
|
|
-
|
|||
|
|
- 1
|
|||
|
|
# Comment
|
|||
|
|
- 2''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('include lines containing only white space characters', () {
|
|||
|
|
expectYamlLoads([1, 2], '''
|
|||
|
|
- 1
|
|||
|
|
\t
|
|||
|
|
- 2''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('within scalar content', () {
|
|||
|
|
test('may not appear on a line of their own', () {
|
|||
|
|
expectYamlLoads(['foo\n# not comment\nbar\n'], '''
|
|||
|
|
- |
|
|||
|
|
foo
|
|||
|
|
# not comment
|
|||
|
|
bar
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test("don't include lines containing only white space characters", () {
|
|||
|
|
expectYamlLoads(['foo\n \t \nbar\n'], '''
|
|||
|
|
- |
|
|||
|
|
foo
|
|||
|
|
\t
|
|||
|
|
bar
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.10]', () {
|
|||
|
|
expectYamlLoads(null, '''
|
|||
|
|
# Comment
|
|||
|
|
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.11]', () {
|
|||
|
|
expectYamlLoads({'key': 'value'}, '''
|
|||
|
|
key: # Comment
|
|||
|
|
# lines
|
|||
|
|
value
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('ending a block scalar header', () {
|
|||
|
|
test('may not be followed by additional comment lines', () {
|
|||
|
|
expectYamlLoads(['# not comment\nfoo\n'], '''
|
|||
|
|
- | # comment
|
|||
|
|
# not comment
|
|||
|
|
foo
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('6.7: Separation Lines', () {
|
|||
|
|
test('may not be used within implicit keys', () {
|
|||
|
|
expectYamlFails('''
|
|||
|
|
[1,
|
|||
|
|
2]: 3''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.12]', () {
|
|||
|
|
var doc = deepEqualsMap();
|
|||
|
|
doc[{'first': 'Sammy', 'last': 'Sosa'}] = {'hr': 65, 'avg': 0.278};
|
|||
|
|
expectYamlLoads(doc, '''
|
|||
|
|
{ first: Sammy, last: Sosa }:
|
|||
|
|
# Statistics:
|
|||
|
|
hr: # Home runs
|
|||
|
|
65
|
|||
|
|
avg: # Average
|
|||
|
|
0.278''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('6.8: Directives', () {
|
|||
|
|
// TODO(nweiz): assert that this produces a warning
|
|||
|
|
test('[Example 6.13]', () {
|
|||
|
|
expectYamlLoads('foo', '''
|
|||
|
|
%FOO bar baz # Should be ignored
|
|||
|
|
# with a warning.
|
|||
|
|
--- "foo"''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// TODO(nweiz): assert that this produces a warning.
|
|||
|
|
test('[Example 6.14]', () {
|
|||
|
|
expectYamlLoads('foo', '''
|
|||
|
|
%YAML 1.3 # Attempt parsing
|
|||
|
|
# with a warning
|
|||
|
|
---
|
|||
|
|
"foo"''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.15]', () {
|
|||
|
|
expectYamlFails('''
|
|||
|
|
%YAML 1.2
|
|||
|
|
%YAML 1.1
|
|||
|
|
foo''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.16]', () {
|
|||
|
|
expectYamlLoads('foo', '''
|
|||
|
|
%TAG !yaml! tag:yaml.org,2002:
|
|||
|
|
---
|
|||
|
|
!yaml!str "foo"''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.17]', () {
|
|||
|
|
expectYamlFails('''
|
|||
|
|
%TAG ! !foo
|
|||
|
|
%TAG ! !foo
|
|||
|
|
bar''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Examples 6.18 through 6.22 test custom tag URIs, which this
|
|||
|
|
// implementation currently doesn't plan to support.
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('6.9: Node Properties', () {
|
|||
|
|
test('may be specified in any order', () {
|
|||
|
|
expectYamlLoads(['foo', 'bar'], '''
|
|||
|
|
- !!str &a1 foo
|
|||
|
|
- &a2 !!str bar''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.23]', () {
|
|||
|
|
expectYamlLoads({'foo': 'bar', 'baz': 'foo'}, '''
|
|||
|
|
!!str &a1 "foo":
|
|||
|
|
!!str bar
|
|||
|
|
&a2 baz : *a1''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Example 6.24 tests custom tag URIs, which this implementation currently
|
|||
|
|
// doesn't plan to support.
|
|||
|
|
|
|||
|
|
test('[Example 6.25]', () {
|
|||
|
|
expectYamlFails('- !<!> foo');
|
|||
|
|
expectYamlFails('- !<\$:?> foo');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Examples 6.26 and 6.27 test custom tag URIs, which this implementation
|
|||
|
|
// currently doesn't plan to support.
|
|||
|
|
|
|||
|
|
test('[Example 6.28]', () {
|
|||
|
|
expectYamlLoads(['12', 12, '12'], '''
|
|||
|
|
# Assuming conventional resolution:
|
|||
|
|
- "12"
|
|||
|
|
- 12
|
|||
|
|
- ! 12''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 6.29]', () {
|
|||
|
|
expectYamlLoads(
|
|||
|
|
{'First occurrence': 'Value', 'Second occurrence': 'Value'}, '''
|
|||
|
|
First occurrence: &anchor Value
|
|||
|
|
Second occurrence: *anchor''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Chapter 7: Flow Styles
|
|||
|
|
group('7.1: Alias Nodes', () {
|
|||
|
|
test("must not use an anchor that doesn't previously occur", () {
|
|||
|
|
expectYamlFails('''
|
|||
|
|
- *anchor
|
|||
|
|
- &anchor foo''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test("don't have to exist for a given anchor node", () {
|
|||
|
|
expectYamlLoads(['foo'], '- &anchor foo');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('must not specify', () {
|
|||
|
|
test('tag properties', () => expectYamlFails('''
|
|||
|
|
- &anchor foo
|
|||
|
|
- !str *anchor'''));
|
|||
|
|
|
|||
|
|
test('anchor properties', () => expectYamlFails('''
|
|||
|
|
- &anchor foo
|
|||
|
|
- &anchor2 *anchor'''));
|
|||
|
|
|
|||
|
|
test('content', () => expectYamlFails('''
|
|||
|
|
- &anchor foo
|
|||
|
|
- *anchor bar'''));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('must preserve structural equality', () {
|
|||
|
|
var doc = loadYaml(cleanUpLiteral('''
|
|||
|
|
anchor: &anchor [a, b, c]
|
|||
|
|
alias: *anchor'''));
|
|||
|
|
var anchorList = doc['anchor'];
|
|||
|
|
var aliasList = doc['alias'];
|
|||
|
|
expect(anchorList, same(aliasList));
|
|||
|
|
|
|||
|
|
doc = loadYaml(cleanUpLiteral('''
|
|||
|
|
? &anchor [a, b, c]
|
|||
|
|
: ? *anchor
|
|||
|
|
: bar'''));
|
|||
|
|
anchorList = doc.keys.first;
|
|||
|
|
aliasList = doc[['a', 'b', 'c']].keys.first;
|
|||
|
|
expect(anchorList, same(aliasList));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.1]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'First occurrence': 'Foo',
|
|||
|
|
'Second occurrence': 'Foo',
|
|||
|
|
'Override anchor': 'Bar',
|
|||
|
|
'Reuse anchor': 'Bar',
|
|||
|
|
}, '''
|
|||
|
|
First occurrence: &anchor Foo
|
|||
|
|
Second occurrence: *anchor
|
|||
|
|
Override anchor: &anchor Bar
|
|||
|
|
Reuse anchor: *anchor''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('7.2: Empty Nodes', () {
|
|||
|
|
test('[Example 7.2]', () {
|
|||
|
|
expectYamlLoads({'foo': '', '': 'bar'}, '''
|
|||
|
|
{
|
|||
|
|
foo : !!str,
|
|||
|
|
!!str : bar,
|
|||
|
|
}''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.3]', () {
|
|||
|
|
var doc = deepEqualsMap({'foo': null});
|
|||
|
|
doc[null] = 'bar';
|
|||
|
|
expectYamlLoads(doc, '''
|
|||
|
|
{
|
|||
|
|
? foo :,
|
|||
|
|
: bar,
|
|||
|
|
}''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('7.3: Flow Scalar Styles', () {
|
|||
|
|
test('[Example 7.4]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'implicit block key': [
|
|||
|
|
{'implicit flow key': 'value'}
|
|||
|
|
]
|
|||
|
|
}, '''
|
|||
|
|
"implicit block key" : [
|
|||
|
|
"implicit flow key" : value,
|
|||
|
|
]''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.5]', () {
|
|||
|
|
expectYamlLoads(
|
|||
|
|
'folded to a space,\nto a line feed, or \t \tnon-content', '''
|
|||
|
|
"folded
|
|||
|
|
to a space,\t
|
|||
|
|
|
|||
|
|
to a line feed, or \t\\
|
|||
|
|
\\ \tnon-content"''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.6]', () {
|
|||
|
|
expectYamlLoads(' 1st non-empty\n2nd non-empty 3rd non-empty ', '''
|
|||
|
|
" 1st non-empty
|
|||
|
|
|
|||
|
|
2nd non-empty
|
|||
|
|
\t3rd non-empty "''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.7]', () {
|
|||
|
|
expectYamlLoads("here's to \"quotes\"", "'here''s to \"quotes\"'");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.8]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'implicit block key': [
|
|||
|
|
{'implicit flow key': 'value'}
|
|||
|
|
]
|
|||
|
|
}, """
|
|||
|
|
'implicit block key' : [
|
|||
|
|
'implicit flow key' : value,
|
|||
|
|
]""");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.9]', () {
|
|||
|
|
expectYamlLoads(' 1st non-empty\n2nd non-empty 3rd non-empty ', """
|
|||
|
|
' 1st non-empty
|
|||
|
|
|
|||
|
|
2nd non-empty
|
|||
|
|
\t3rd non-empty '""");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.10]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
'::vector',
|
|||
|
|
': - ()',
|
|||
|
|
'Up, up, and away!',
|
|||
|
|
-123,
|
|||
|
|
'http://example.com/foo#bar',
|
|||
|
|
[
|
|||
|
|
'::vector',
|
|||
|
|
': - ()',
|
|||
|
|
'Up, up, and away!',
|
|||
|
|
-123,
|
|||
|
|
'http://example.com/foo#bar'
|
|||
|
|
]
|
|||
|
|
], '''
|
|||
|
|
# Outside flow collection:
|
|||
|
|
- ::vector
|
|||
|
|
- ": - ()"
|
|||
|
|
- Up, up, and away!
|
|||
|
|
- -123
|
|||
|
|
- http://example.com/foo#bar
|
|||
|
|
# Inside flow collection:
|
|||
|
|
- [ ::vector,
|
|||
|
|
": - ()",
|
|||
|
|
"Up, up, and away!",
|
|||
|
|
-123,
|
|||
|
|
http://example.com/foo#bar ]''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.11]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'implicit block key': [
|
|||
|
|
{'implicit flow key': 'value'}
|
|||
|
|
]
|
|||
|
|
}, '''
|
|||
|
|
implicit block key : [
|
|||
|
|
implicit flow key : value,
|
|||
|
|
]''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.12]', () {
|
|||
|
|
expectYamlLoads('1st non-empty\n2nd non-empty 3rd non-empty', '''
|
|||
|
|
1st non-empty
|
|||
|
|
|
|||
|
|
2nd non-empty
|
|||
|
|
\t3rd non-empty''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('7.4: Flow Collection Styles', () {
|
|||
|
|
test('[Example 7.13]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
['one', 'two'],
|
|||
|
|
['three', 'four']
|
|||
|
|
], '''
|
|||
|
|
- [ one, two, ]
|
|||
|
|
- [three ,four]''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.14]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
'double quoted',
|
|||
|
|
'single quoted',
|
|||
|
|
'plain text',
|
|||
|
|
['nested'],
|
|||
|
|
{'single': 'pair'}
|
|||
|
|
], """
|
|||
|
|
[
|
|||
|
|
"double
|
|||
|
|
quoted", 'single
|
|||
|
|
quoted',
|
|||
|
|
plain
|
|||
|
|
text, [ nested ],
|
|||
|
|
single: pair,
|
|||
|
|
]""");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.15]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
{'one': 'two', 'three': 'four'},
|
|||
|
|
{'five': 'six', 'seven': 'eight'},
|
|||
|
|
], '''
|
|||
|
|
- { one : two , three: four , }
|
|||
|
|
- {five: six,seven : eight}''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.16]', () {
|
|||
|
|
var doc = deepEqualsMap({'explicit': 'entry', 'implicit': 'entry'});
|
|||
|
|
doc[null] = null;
|
|||
|
|
expectYamlLoads(doc, '''
|
|||
|
|
{
|
|||
|
|
? explicit: entry,
|
|||
|
|
implicit: entry,
|
|||
|
|
?
|
|||
|
|
}''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.17]', () {
|
|||
|
|
var doc = deepEqualsMap({
|
|||
|
|
'unquoted': 'separate',
|
|||
|
|
'http://foo.com': null,
|
|||
|
|
'omitted value': null
|
|||
|
|
});
|
|||
|
|
doc[null] = 'omitted key';
|
|||
|
|
expectYamlLoads(doc, '''
|
|||
|
|
{
|
|||
|
|
unquoted : "separate",
|
|||
|
|
http://foo.com,
|
|||
|
|
omitted value:,
|
|||
|
|
: omitted key,
|
|||
|
|
}''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.18]', () {
|
|||
|
|
expectYamlLoads(
|
|||
|
|
{'adjacent': 'value', 'readable': 'value', 'empty': null}, '''
|
|||
|
|
{
|
|||
|
|
"adjacent":value,
|
|||
|
|
"readable": value,
|
|||
|
|
"empty":
|
|||
|
|
}''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.19]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
{'foo': 'bar'}
|
|||
|
|
], '''
|
|||
|
|
[
|
|||
|
|
foo: bar
|
|||
|
|
]''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.20]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
{'foo bar': 'baz'}
|
|||
|
|
], '''
|
|||
|
|
[
|
|||
|
|
? foo
|
|||
|
|
bar : baz
|
|||
|
|
]''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.21]', () {
|
|||
|
|
var el1 = deepEqualsMap();
|
|||
|
|
el1[null] = 'empty key entry';
|
|||
|
|
|
|||
|
|
var el2 = deepEqualsMap();
|
|||
|
|
el2[{'JSON': 'like'}] = 'adjacent';
|
|||
|
|
|
|||
|
|
expectYamlLoads([
|
|||
|
|
[
|
|||
|
|
{'YAML': 'separate'}
|
|||
|
|
],
|
|||
|
|
[el1],
|
|||
|
|
[el2]
|
|||
|
|
], '''
|
|||
|
|
- [ YAML : separate ]
|
|||
|
|
- [ : empty key entry ]
|
|||
|
|
- [ {JSON: like}:adjacent ]''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// TODO(nweiz): enable this when we throw an error for long or multiline
|
|||
|
|
// keys.
|
|||
|
|
// test('[Example 7.22]', () {
|
|||
|
|
// expectYamlFails(
|
|||
|
|
// """
|
|||
|
|
// [ foo
|
|||
|
|
// bar: invalid ]""");
|
|||
|
|
//
|
|||
|
|
// var dotList = new List.filled(1024, ' ');
|
|||
|
|
// var dots = dotList.join();
|
|||
|
|
// expectYamlFails('[ "foo...$dots...bar": invalid ]');
|
|||
|
|
// });
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('7.5: Flow Nodes', () {
|
|||
|
|
test('[Example 7.23]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
['a', 'b'],
|
|||
|
|
{'a': 'b'},
|
|||
|
|
'a',
|
|||
|
|
'b',
|
|||
|
|
'c'
|
|||
|
|
], '''
|
|||
|
|
- [ a, b ]
|
|||
|
|
- { a: b }
|
|||
|
|
- 'a'
|
|||
|
|
- 'b'
|
|||
|
|
- c''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 7.24]', () {
|
|||
|
|
expectYamlLoads(['a', 'b', 'c', 'c', ''], '''
|
|||
|
|
- !!str "a"
|
|||
|
|
- 'b'
|
|||
|
|
- &anchor "c"
|
|||
|
|
- *anchor
|
|||
|
|
- !!str''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Chapter 8: Block Styles
|
|||
|
|
group('8.1: Block Scalar Styles', () {
|
|||
|
|
test('[Example 8.1]', () {
|
|||
|
|
expectYamlLoads(['literal\n', ' folded\n', 'keep\n\n', ' strip'], '''
|
|||
|
|
- | # Empty header
|
|||
|
|
literal
|
|||
|
|
- >1 # Indentation indicator
|
|||
|
|
folded
|
|||
|
|
- |+ # Chomping indicator
|
|||
|
|
keep
|
|||
|
|
|
|||
|
|
- >1- # Both indicators
|
|||
|
|
strip''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.2]', () {
|
|||
|
|
// Note: in the spec, the fourth element in this array is listed as
|
|||
|
|
// "\t detected\n", not "\t\ndetected\n". However, I'm reasonably
|
|||
|
|
// confident that "\t\ndetected\n" is correct when parsed according to the
|
|||
|
|
// rest of the spec.
|
|||
|
|
expectYamlLoads(
|
|||
|
|
['detected\n', '\n\n# detected\n', ' explicit\n', '\t\ndetected\n'],
|
|||
|
|
'''
|
|||
|
|
- |
|
|||
|
|
detected
|
|||
|
|
- >
|
|||
|
|
|
|||
|
|
|
|||
|
|
# detected
|
|||
|
|
- |1
|
|||
|
|
explicit
|
|||
|
|
- >
|
|||
|
|
\t
|
|||
|
|
detected
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.3]', () {
|
|||
|
|
expectYamlFails('''
|
|||
|
|
- |
|
|||
|
|
|
|||
|
|
text''');
|
|||
|
|
|
|||
|
|
expectYamlFails('''
|
|||
|
|
- >
|
|||
|
|
text
|
|||
|
|
text''');
|
|||
|
|
|
|||
|
|
expectYamlFails('''
|
|||
|
|
- |2
|
|||
|
|
text''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.4]', () {
|
|||
|
|
expectYamlLoads({'strip': 'text', 'clip': 'text\n', 'keep': 'text\n'}, '''
|
|||
|
|
strip: |-
|
|||
|
|
text
|
|||
|
|
clip: |
|
|||
|
|
text
|
|||
|
|
keep: |+
|
|||
|
|
text
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.5]', () {
|
|||
|
|
// This example in the spec only includes a single newline in the "keep"
|
|||
|
|
// value, but as far as I can tell that's not how it's supposed to be
|
|||
|
|
// parsed according to the rest of the spec.
|
|||
|
|
expectYamlLoads(
|
|||
|
|
{'strip': '# text', 'clip': '# text\n', 'keep': '# text\n\n'}, '''
|
|||
|
|
# Strip
|
|||
|
|
# Comments:
|
|||
|
|
strip: |-
|
|||
|
|
# text
|
|||
|
|
|
|||
|
|
# Clip
|
|||
|
|
# comments:
|
|||
|
|
|
|||
|
|
clip: |
|
|||
|
|
# text
|
|||
|
|
|
|||
|
|
# Keep
|
|||
|
|
# comments:
|
|||
|
|
|
|||
|
|
keep: |+
|
|||
|
|
# text
|
|||
|
|
|
|||
|
|
# Trail
|
|||
|
|
# comments.
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.6]', () {
|
|||
|
|
expectYamlLoads({'strip': '', 'clip': '', 'keep': '\n'}, '''
|
|||
|
|
strip: >-
|
|||
|
|
|
|||
|
|
clip: >
|
|||
|
|
|
|||
|
|
keep: |+
|
|||
|
|
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.7]', () {
|
|||
|
|
expectYamlLoads('literal\n\ttext\n', '''
|
|||
|
|
|
|
|||
|
|
literal
|
|||
|
|
\ttext
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.8]', () {
|
|||
|
|
expectYamlLoads('\n\nliteral\n \n\ntext\n', '''
|
|||
|
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
literal
|
|||
|
|
|
|||
|
|
|
|||
|
|
text
|
|||
|
|
|
|||
|
|
# Comment''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.9]', () {
|
|||
|
|
expectYamlLoads('folded text\n', '''
|
|||
|
|
>
|
|||
|
|
folded
|
|||
|
|
text
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.10]', () {
|
|||
|
|
expectYamlLoads(cleanUpLiteral('''
|
|||
|
|
|
|||
|
|
folded line
|
|||
|
|
next line
|
|||
|
|
* bullet
|
|||
|
|
|
|||
|
|
* list
|
|||
|
|
* lines
|
|||
|
|
|
|||
|
|
last line
|
|||
|
|
'''), '''
|
|||
|
|
>
|
|||
|
|
|
|||
|
|
folded
|
|||
|
|
line
|
|||
|
|
|
|||
|
|
next
|
|||
|
|
line
|
|||
|
|
* bullet
|
|||
|
|
|
|||
|
|
* list
|
|||
|
|
* lines
|
|||
|
|
|
|||
|
|
last
|
|||
|
|
line
|
|||
|
|
|
|||
|
|
# Comment''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Examples 8.11 through 8.13 are duplicates of 8.10.
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('8.2: Block Collection Styles', () {
|
|||
|
|
test('[Example 8.14]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'block sequence': [
|
|||
|
|
'one',
|
|||
|
|
{'two': 'three'}
|
|||
|
|
]
|
|||
|
|
}, '''
|
|||
|
|
block sequence:
|
|||
|
|
- one
|
|||
|
|
- two : three''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.15]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
null,
|
|||
|
|
'block node\n',
|
|||
|
|
['one', 'two'],
|
|||
|
|
{'one': 'two'}
|
|||
|
|
], '''
|
|||
|
|
- # Empty
|
|||
|
|
- |
|
|||
|
|
block node
|
|||
|
|
- - one # Compact
|
|||
|
|
- two # sequence
|
|||
|
|
- one: two # Compact mapping''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.16]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'block mapping': {'key': 'value'}
|
|||
|
|
}, '''
|
|||
|
|
block mapping:
|
|||
|
|
key: value''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.17]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'explicit key': null,
|
|||
|
|
'block key\n': ['one', 'two']
|
|||
|
|
}, '''
|
|||
|
|
? explicit key # Empty value
|
|||
|
|
? |
|
|||
|
|
block key
|
|||
|
|
: - one # Explicit compact
|
|||
|
|
- two # block value''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.18]', () {
|
|||
|
|
var doc = deepEqualsMap({
|
|||
|
|
'plain key': 'in-line value',
|
|||
|
|
'quoted key': ['entry']
|
|||
|
|
});
|
|||
|
|
doc[null] = null;
|
|||
|
|
expectYamlLoads(doc, '''
|
|||
|
|
plain key: in-line value
|
|||
|
|
: # Both empty
|
|||
|
|
"quoted key":
|
|||
|
|
- entry''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.19]', () {
|
|||
|
|
var el = deepEqualsMap();
|
|||
|
|
el[{'earth': 'blue'}] = {'moon': 'white'};
|
|||
|
|
expectYamlLoads([
|
|||
|
|
{'sun': 'yellow'},
|
|||
|
|
el
|
|||
|
|
], '''
|
|||
|
|
- sun: yellow
|
|||
|
|
- ? earth: blue
|
|||
|
|
: moon: white''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.20]', () {
|
|||
|
|
expectYamlLoads([
|
|||
|
|
'flow in block',
|
|||
|
|
'Block scalar\n',
|
|||
|
|
{'foo': 'bar'}
|
|||
|
|
], '''
|
|||
|
|
-
|
|||
|
|
"flow in block"
|
|||
|
|
- >
|
|||
|
|
Block scalar
|
|||
|
|
- !!map # Block collection
|
|||
|
|
foo : bar''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.21]', () {
|
|||
|
|
// The spec doesn't include a newline after "value" in the parsed map, but
|
|||
|
|
// the block scalar is clipped so it should be retained.
|
|||
|
|
expectYamlLoads({'literal': 'value\n', 'folded': 'value'}, '''
|
|||
|
|
literal: |2
|
|||
|
|
value
|
|||
|
|
folded:
|
|||
|
|
!!str
|
|||
|
|
>1
|
|||
|
|
value''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 8.22]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'sequence': [
|
|||
|
|
'entry',
|
|||
|
|
['nested']
|
|||
|
|
],
|
|||
|
|
'mapping': {'foo': 'bar'}
|
|||
|
|
}, '''
|
|||
|
|
sequence: !!seq
|
|||
|
|
- entry
|
|||
|
|
- !!seq
|
|||
|
|
- nested
|
|||
|
|
mapping: !!map
|
|||
|
|
foo: bar''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Chapter 9: YAML Character Stream
|
|||
|
|
group('9.1: Documents', () {
|
|||
|
|
// Example 9.1 tests the use of a BOM, which this implementation currently
|
|||
|
|
// doesn't plan to support.
|
|||
|
|
|
|||
|
|
test('[Example 9.2]', () {
|
|||
|
|
expectYamlLoads('Document', '''
|
|||
|
|
%YAML 1.2
|
|||
|
|
---
|
|||
|
|
Document
|
|||
|
|
... # Suffix''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 9.3]', () {
|
|||
|
|
// The spec example indicates that the comment after "%!PS-Adobe-2.0"
|
|||
|
|
// should be stripped, which would imply that that line is not part of the
|
|||
|
|
// literal defined by the "|". The rest of the spec is ambiguous on this
|
|||
|
|
// point; the allowable indentation for non-indented literal content is
|
|||
|
|
// not clearly explained. However, if both the "|" and the text were
|
|||
|
|
// indented the same amount, the text would be part of the literal, which
|
|||
|
|
// implies that the spec's parse of this document is incorrect.
|
|||
|
|
expectYamlStreamLoads(
|
|||
|
|
['Bare document', '%!PS-Adobe-2.0 # Not the first line\n'], '''
|
|||
|
|
Bare
|
|||
|
|
document
|
|||
|
|
...
|
|||
|
|
# No document
|
|||
|
|
...
|
|||
|
|
|
|
|||
|
|
%!PS-Adobe-2.0 # Not the first line
|
|||
|
|
''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 9.4]', () {
|
|||
|
|
expectYamlStreamLoads([
|
|||
|
|
{'matches %': 20},
|
|||
|
|
null
|
|||
|
|
], '''
|
|||
|
|
---
|
|||
|
|
{ matches
|
|||
|
|
% : 20 }
|
|||
|
|
...
|
|||
|
|
---
|
|||
|
|
# Empty
|
|||
|
|
...''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 9.5]', () {
|
|||
|
|
// The spec doesn't have a space between the second
|
|||
|
|
// "YAML" and "1.2", but this seems to be a typo.
|
|||
|
|
expectYamlStreamLoads(['%!PS-Adobe-2.0\n', null], '''
|
|||
|
|
%YAML 1.2
|
|||
|
|
--- |
|
|||
|
|
%!PS-Adobe-2.0
|
|||
|
|
...
|
|||
|
|
%YAML 1.2
|
|||
|
|
---
|
|||
|
|
# Empty
|
|||
|
|
...''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 9.6]', () {
|
|||
|
|
expectYamlStreamLoads([
|
|||
|
|
'Document',
|
|||
|
|
null,
|
|||
|
|
{'matches %': 20}
|
|||
|
|
], '''
|
|||
|
|
Document
|
|||
|
|
---
|
|||
|
|
# Empty
|
|||
|
|
...
|
|||
|
|
%YAML 1.2
|
|||
|
|
---
|
|||
|
|
matches %: 20''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Chapter 10: Recommended Schemas
|
|||
|
|
group('10.1: Failsafe Schema', () {
|
|||
|
|
test('[Example 10.1]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'Block style': {
|
|||
|
|
'Clark': 'Evans',
|
|||
|
|
'Ingy': 'döt Net',
|
|||
|
|
'Oren': 'Ben-Kiki'
|
|||
|
|
},
|
|||
|
|
'Flow style': {'Clark': 'Evans', 'Ingy': 'döt Net', 'Oren': 'Ben-Kiki'}
|
|||
|
|
}, '''
|
|||
|
|
Block style: !!map
|
|||
|
|
Clark : Evans
|
|||
|
|
Ingy : döt Net
|
|||
|
|
Oren : Ben-Kiki
|
|||
|
|
|
|||
|
|
Flow style: !!map { Clark: Evans, Ingy: döt Net, Oren: Ben-Kiki }''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 10.2]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'Block style': ['Clark Evans', 'Ingy döt Net', 'Oren Ben-Kiki'],
|
|||
|
|
'Flow style': ['Clark Evans', 'Ingy döt Net', 'Oren Ben-Kiki']
|
|||
|
|
}, '''
|
|||
|
|
Block style: !!seq
|
|||
|
|
- Clark Evans
|
|||
|
|
- Ingy döt Net
|
|||
|
|
- Oren Ben-Kiki
|
|||
|
|
|
|||
|
|
Flow style: !!seq [ Clark Evans, Ingy döt Net, Oren Ben-Kiki ]''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 10.3]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'Block style': 'String: just a theory.',
|
|||
|
|
'Flow style': 'String: just a theory.'
|
|||
|
|
}, '''
|
|||
|
|
Block style: !!str |-
|
|||
|
|
String: just a theory.
|
|||
|
|
|
|||
|
|
Flow style: !!str "String: just a theory."''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('10.2: JSON Schema', () {
|
|||
|
|
test('[Example 10.4]', () {
|
|||
|
|
var doc = deepEqualsMap({'key with null value': null});
|
|||
|
|
doc[null] = 'value for null key';
|
|||
|
|
expectYamlStreamLoads([doc], '''
|
|||
|
|
!!null null: value for null key
|
|||
|
|
key with null value: !!null null''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 10.5]', () {
|
|||
|
|
expectYamlStreamLoads([
|
|||
|
|
{'YAML is a superset of JSON': true, 'Pluto is a planet': false}
|
|||
|
|
], '''
|
|||
|
|
YAML is a superset of JSON: !!bool true
|
|||
|
|
Pluto is a planet: !!bool false''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 10.6]', () {
|
|||
|
|
expectYamlStreamLoads([
|
|||
|
|
{'negative': -12, 'zero': 0, 'positive': 34}
|
|||
|
|
], '''
|
|||
|
|
negative: !!int -12
|
|||
|
|
zero: !!int 0
|
|||
|
|
positive: !!int 34''');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('[Example 10.7]', () {
|
|||
|
|
expectYamlStreamLoads([
|
|||
|
|
{
|
|||
|
|
'negative': -1,
|
|||
|
|
'zero': 0,
|
|||
|
|
'positive': 23000,
|
|||
|
|
'infinity': infinity,
|
|||
|
|
'not a number': nan
|
|||
|
|
}
|
|||
|
|
], '''
|
|||
|
|
negative: !!float -1
|
|||
|
|
zero: !!float 0
|
|||
|
|
positive: !!float 2.3e4
|
|||
|
|
infinity: !!float .inf
|
|||
|
|
not a number: !!float .nan''');
|
|||
|
|
}, skip: 'Fails for single digit float');
|
|||
|
|
|
|||
|
|
test('[Example 10.8]', () {
|
|||
|
|
expectYamlStreamLoads([
|
|||
|
|
{
|
|||
|
|
'A null': null,
|
|||
|
|
'Booleans': [true, false],
|
|||
|
|
'Integers': [0, -0, 3, -19],
|
|||
|
|
'Floats': [0, 0, 12000, -200000],
|
|||
|
|
// Despite being invalid in the JSON schema, these values are valid in
|
|||
|
|
// the core schema which this implementation supports.
|
|||
|
|
'Invalid': [true, null, 7, 0x3A, 12.3]
|
|||
|
|
}
|
|||
|
|
], '''
|
|||
|
|
A null: null
|
|||
|
|
Booleans: [ true, false ]
|
|||
|
|
Integers: [ 0, -0, 3, -19 ]
|
|||
|
|
Floats: [ 0., -0.0, 12e03, -2E+05 ]
|
|||
|
|
Invalid: [ True, Null, 0o7, 0x3A, +12.3 ]''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
group('10.3: Core Schema', () {
|
|||
|
|
test('[Example 10.9]', () {
|
|||
|
|
expectYamlLoads({
|
|||
|
|
'A null': null,
|
|||
|
|
'Also a null': null,
|
|||
|
|
'Not a null': '',
|
|||
|
|
'Booleans': [true, true, false, false],
|
|||
|
|
'Integers': [0, 7, 0x3A, -19],
|
|||
|
|
'Floats': [0, 0, 0.5, 12000, -200000],
|
|||
|
|
'Also floats': [infinity, -infinity, infinity, nan]
|
|||
|
|
}, '''
|
|||
|
|
A null: null
|
|||
|
|
Also a null: # Empty
|
|||
|
|
Not a null: ""
|
|||
|
|
Booleans: [ true, True, false, FALSE ]
|
|||
|
|
Integers: [ 0, 0o7, 0x3A, -19 ]
|
|||
|
|
Floats: [ 0., -0.0, .5, +12e03, -2E+05 ]
|
|||
|
|
Also floats: [ .inf, -.Inf, +.INF, .NAN ]''');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('preserves key order', () {
|
|||
|
|
const keys = ['a', 'b', 'c', 'd', 'e', 'f'];
|
|||
|
|
var sanityCheckCount = 0;
|
|||
|
|
for (var permutation in _generatePermutations(keys)) {
|
|||
|
|
final yaml = permutation.map((key) => '$key: value').join('\n');
|
|||
|
|
expect(loadYaml(yaml).keys.toList(), permutation);
|
|||
|
|
sanityCheckCount++;
|
|||
|
|
}
|
|||
|
|
final expectedPermutationCount =
|
|||
|
|
List.generate(keys.length, (i) => i + 1).reduce((n, i) => n * i);
|
|||
|
|
expect(sanityCheckCount, expectedPermutationCount);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Iterable<List<String>> _generatePermutations(List<String> keys) sync* {
|
|||
|
|
if (keys.length <= 1) {
|
|||
|
|
yield keys;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
for (var i = 0; i < keys.length; i++) {
|
|||
|
|
final first = keys[i];
|
|||
|
|
final rest = <String>[...keys.sublist(0, i), ...keys.sublist(i + 1)];
|
|||
|
|
for (var subPermutation in _generatePermutations(rest)) {
|
|||
|
|
yield <String>[first, ...subPermutation];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|