blob: 42cb6137d6b7680ad2eb4ccbcd780e2293c554c3 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library yaml_test;
// TODO(rnystrom): rewrite tests so that they don't need "Expect".
import "package:expect/expect.dart";
import 'package:unittest/unittest.dart';
import 'package:yaml/yaml.dart';
import 'package:yaml/src/deep_equals.dart';
// TODO(jmesserly): we should not be reaching outside the YAML package
// The http package has a similar problem.
import '../../../tests/utils/test_utils.dart';
/// Constructs a new yaml.YamlMap, optionally from a normal Map.
Map yamlMap([Map from]) =>
from == null ? new YamlMap() : new YamlMap.from(from);
/// Asserts that a string containing a single YAML document produces a given
/// value when loaded.
expectYamlLoads(expected, String source) {
var actual = loadYaml(cleanUpLiteral(source));
Expect.isTrue(deepEquals(expected, actual),
'expectYamlLoads(expected: <$expected>, actual: <$actual>)');
}
/// Asserts that a string containing a stream of YAML documents produces a given
/// list of values when loaded.
expectYamlStreamLoads(List expected, String source) {
var actual = loadYamlStream(cleanUpLiteral(source));
Expect.isTrue(deepEquals(expected, actual),
'expectYamlStreamLoads(expected: <$expected>, actual: <$actual>)');
}
main() {
var infinity = double.parse("Infinity");
var nan = double.parse("NaN");
group('YamlMap', () {
group('accepts as a key', () {
_expectKeyWorks(keyFn()) {
var map = yamlMap();
map[keyFn()] = 5;
expect(map.containsKey(keyFn()), isTrue);
expect(map[keyFn()], 5);
}
test('null', () => _expectKeyWorks(() => null));
test('true', () => _expectKeyWorks(() => true));
test('false', () => _expectKeyWorks(() => false));
test('a list', () => _expectKeyWorks(() => [1, 2, 3]));
test('a map', () => _expectKeyWorks(() => {'foo': 'bar'}));
test('a YAML map', () => _expectKeyWorks(() => yamlMap({'foo': 'bar'})));
});
test('works as a hash key', () {
var normalMap = new Map();
normalMap[yamlMap({'foo': 'bar'})] = 'baz';
expect(normalMap.containsKey(yamlMap({'foo': 'bar'})), isTrue);
expect(normalMap[yamlMap({'foo': 'bar'})], 'baz');
});
test('treats YamlMap keys the same as normal maps', () {
var map = yamlMap();
map[{'a': 'b'}] = 5;
expect(map[yamlMap({'a': 'b'})], 5);
});
});
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)));
});
});
// 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 = yamlMap();
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",
"control": "\b1998\t1999\t2000\n",
"hex esc": "\r\n is \r\n",
"single": '"Howdy!" he cried.',
"quoted": " # Not a 'comment'.",
"tie-fighter": "|\\-*-/|"
},
"""
unicode: "Sosa did fine.\\u263A"
control: "\\b1998\\t1999\\t2000\\n"
hex esc: "\\x0d\\x0a is \\r\\n"
single: '"Howdy!" he cried.'
quoted: ' # Not a ''comment''.'
tie-fighter: '|\\-*-/|'""");
});
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 = yamlMap({
"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', () {
expectAllowsCharacter(int charCode) {
var char = new String.fromCharCodes([charCode]);
expectYamlLoads('The character "$char" is allowed',
'The character "$char" is allowed');
}
expectAllowsQuotedCharacter(int charCode) {
var char = new String.fromCharCodes([charCode]);
expectYamlLoads("The character '$char' is allowed",
'"The character \'$char\' is allowed"');
}
expectDisallowsCharacter(int charCode) {
var char = new String.fromCharCodes([charCode]);
Expect.throws(() => loadYaml('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]', () {
Expect.throws(() => loadYaml("commercial-at: @text"));
Expect.throws(() => loadYaml("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', () => Expect.throws(() => loadYaml("- 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]', () {
Expect.throws(() => loadYaml('Bad escape: "\\c"'));
Expect.throws(() => loadYaml('Bad escape: "\\xq-"'));
});
});
// Chapter 6: Basic Structures
group('6.1: Indentation Spaces', () {
test('may not include TAB characters', () {
Expect.throws(() => loadYaml(cleanUpLiteral(
"""
-
\t- foo
\t- bar""")));
});
test('must be the same for all sibling nodes', () {
Expect.throws(() => loadYaml(cleanUpLiteral(
"""
-
- 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', () {
Expect.throws(() => loadYaml(cleanUpLiteral(
"""
[1,
2]: 3""")));
});
test('[Example 6.12]', () {
var doc = yamlMap();
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]', () {
// Expect.throws(() => loadYaml(cleanUpLiteral(
// """
// %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]', () {
// Expect.throws(() => loadYaml(cleanUpLiteral(
// """
// %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]', () {
// Expect.throws(() => loadYaml("- !<!> foo"));
// Expect.throws(() => loadYaml("- !<\$:?> 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": "anchor"
// },
// """
// 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", () {
// Expect.throws(() => loadYaml(cleanUpLiteral(
// """
// - *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', () => Expect.throws(() => loadYaml(cleanUpLiteral(
// """
// - &anchor foo
// - !str *anchor""")));
// test('anchor properties', () => Expect.throws(
// () => loadYaml(cleanUpLiteral(
// """
// - &anchor foo
// - &anchor2 *anchor""")));
// test('content', () => Expect.throws(() => loadYaml(cleanUpLiteral(
// """
// - &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.isTrue(anchorList === aliasList);
// anchorList.add('d');
// Expect.listEquals(['a', 'b', 'c', 'd'], aliasList);
// doc = loadYaml(cleanUpLiteral(
// """
// ? &anchor [a, b, c]
// : ? *anchor
// : bar""");
// anchorList = doc.keys[0];
// aliasList = doc[['a', 'b', 'c']].keys[0];
// Expect.isTrue(anchorList === aliasList);
// anchorList.add('d');
// Expect.listEquals(['a', 'b', 'c', 'd'], aliasList);
// });
// test('[Example 7.1]', () {
// expectYamlLoads({
// "First occurence": "Foo",
// "Second occurence": "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 = yamlMap({"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 = yamlMap({
"explicit": "entry",
"implicit": "entry"
});
doc[null] = null;
expectYamlLoads(doc,
"""
{
? explicit: entry,
implicit: entry,
?
}""");
});
test('[Example 7.17]', () {
var doc = yamlMap({
"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 = yamlMap();
el1[null] = "empty key entry";
var el2 = yamlMap();
el2[{"JSON": "like"}] = "adjacent";
expectYamlLoads([[{"YAML": "separate"}], [el1], [el2]],
"""
- [ YAML : separate ]
- [ : empty key entry ]
- [ {JSON: like}:adjacent ]""");
});
test('[Example 7.22]', () {
Expect.throws(() => loadYaml(cleanUpLiteral(
"""
[ foo
bar: invalid ]""")));
// TODO(nweiz): enable this when we throw an error for long keys
// var dotList = new List.filled(1024, ' ');
// var dots = dotList.join();
// Expect.throws(() => loadYaml('[ "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]', () {
Expect.throws(() => loadYaml(cleanUpLiteral(
"""
- |
text""")));
Expect.throws(() => loadYaml(cleanUpLiteral(
"""
- >
text
text""")));
Expect.throws(() => loadYaml(cleanUpLiteral(
"""
- |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 = yamlMap({
'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 = yamlMap();
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]', () {
// expectYamlLoads({"literal": "value", "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]', () {
// expectYamlStreamLoads(["%!PS-Adobe-2.0\n", null],
// """
// %YAML 1.2
// --- |
// %!PS-Adobe-2.0
// ...
// %YAML1.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]', () {
// expectYamlStreamLoads({
// "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]', () {
// expectYamlStreamLoads({
// "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]', () {
// expectYamlStreamLoads({
// "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 = yamlMap({"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""");
// });
// 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 ]''');
});
});
}