| // 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. |
| |
| 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', |
| '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 = 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"""); |
| // }); |
| |
| // 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]; |
| } |
| } |
| } |