- Add VariableSpec class with magnitude field validation - Add Formula class supporting multiple input/output variables - Support d4rt_code as string or object with code field - Add comprehensive tests for parsing and serialization - Fix broken test import in pruebas_d4rt_test.dart Follows README.md format requirements exactly
1921 lines
47 KiB
Dart
1921 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];
|
||
}
|
||
}
|
||
}
|