xref: /freebsd/contrib/lyaml/spec/ext_yaml_parser_spec.yaml (revision 2bc180ef045e5911cce0cea1c2a139cffd2b577a)
1# LYAML binding for Lua 5.1, 5.2, 5.3 & 5.4
2# Copyright (C) 2013-2022 Gary V. Vaughan
3
4specify parsing:
5- it parses empty streams:
6    e = yaml.parser ""
7    expect (e ().type).to_be "STREAM_START"
8    expect (e ().type).to_be "STREAM_END"
9    expect (e ()).to_be (nil)
10    expect (e ()).to_be (nil)
11- it ignores comments: '
12    e = yaml.parser "# A comment\nnon-comment # trailing comment\n"
13    expect (e ().type).to_be "STREAM_START"
14    expect (e ().type).to_be "DOCUMENT_START"
15    expect (e ().value).to_be "non-comment"
16    expect (e ().type).to_be "DOCUMENT_END"'
17
18- describe STREAM_START:
19  - before:
20      e = yaml.parser "# no BOM"
21  - it is the first event:
22      expect (e ().type).to_be "STREAM_START"
23  - it reports event start marker:
24      expect (e ().start_mark).to_equal {line = 0, column = 0, index = 0}
25  - it reports event end marker:
26      expect (e ().end_mark).to_equal {line = 0, column = 0, index = 0}
27  - it uses UTF-8 by default:
28      expect (e ().encoding).to_be "UTF8"
29  - it recognizes UTF-16 BOM:
30      e = yaml.parser (BOM .. " BOM")
31      expect (e ().encoding).to_match "UTF16[BL]E"
32
33- describe STREAM_END:
34  - before:
35      for t in yaml.parser "nothing to see" do ev = t end
36  - it is the last event:
37      expect (ev.type).to_be "STREAM_END"
38  - it reports event start marker:
39      expect (ev.start_mark).to_equal {line = 1, column = 0, index = 14}
40  - it reports event end marker:
41      expect (ev.end_mark).to_equal {line = 1, column = 0, index = 14}
42
43- describe DOCUMENT_START:
44  - before:
45      e = consume (1, "---")
46  - it recognizes document start marker:
47      expect (filter (e (), "type", "implicit")).
48        to_equal {type = "DOCUMENT_START", implicit = false}
49  - it reports implicit document start:
50      e = consume (1, "foo")
51      expect (e ().implicit).to_be (true)
52  - it reports event start marker:
53      expect (e ().start_mark).to_equal {line = 0, column = 0, index = 0}
54  - it reports event end marker:
55      expect (e ().end_mark).to_equal {line = 0, column = 3, index = 3}
56
57  - context parser directives:
58    - it can recognize document versions:
59        e = consume (1, "%YAML 1.1\n---")
60        expect (e ().version_directive).to_equal {major = 1, minor = 1}
61    - it can diagnose missing document start:
62        e = consume (1, "%YAML 1.1\n")
63        expect (e ()).to_error "expected <document start>"
64    - it can diagnose multiple versions:
65        e = consume (1, "%YAML 1.1\n%YAML 1.1\n---")
66        expect (e ()).to_error "duplicate %YAML directive"
67    - it can diagnose too-new versions:
68        e = consume (1, "%YAML 2.0\n---")
69        expect (e ()).to_error "incompatible YAML document"
70    - it warns of newer minor versions:
71        pending (github_issue "1")
72        e = consume (1, "%YAML 1.9\n---")
73        expect (e ()).
74           to_error "attempting parsing of newer minor document version"
75
76    - it can recognize primary tag handles:
77        e = consume (1, "%TAG ! tag:ben-kiki.org,2000:app/\n---")
78        expect (e ().tag_directives).
79           to_equal {{handle = "!", prefix = "tag:ben-kiki.org,2000:app/"}}
80    - it can recognize secondary tag handles:
81        e = consume (1, "%TAG !! tag:yaml.org,2002:\n---")
82        expect (e ().tag_directives).
83           to_equal {{handle = "!!", prefix = "tag:yaml.org,2002:"}}
84    - it can recognize named tag handles:
85        e = consume (1, "%TAG !o! tag:ben-kiki.org,2000:\n---")
86        expect (e ().tag_directives).
87           to_equal {{handle = "!o!", prefix = "tag:ben-kiki.org,2000:"}}
88    - it can concatenate multiple tag handles:
89        e = consume (1, "%TAG ! !\n" ..
90                        "%TAG !! tag:yaml.org,2002:\n" ..
91                        "%TAG !o! tag:ben-kiki.org,2000:\n" ..
92                        "---")
93        expect (e ().tag_directives).to_contain.
94           all_of {{handle = "!", prefix = "!"},
95                   {handle = "!!", prefix = "tag:yaml.org,2002:"},
96                   {handle = "!o!", prefix = "tag:ben-kiki.org,2000:"}}
97    - it can diagnose missing document start:
98        e = consume (1, "%TAG ! !\n")
99        expect (e ()).to_error "expected <document start>"
100
101- describe DOCUMENT_END:
102  - before:
103      e = consume (3, "foo\n...")
104  - it recognizes the document end marker:
105      expect (filter (e (), "type", "implicit")).
106         to_equal {type = "DOCUMENT_END", implicit = false}
107  - it reports an implicit document end marker:
108      e = consume (3, "foo\n")
109      expect (filter (e (), "type", "implicit")).
110         to_equal {type = "DOCUMENT_END", implicit = true}
111  - it reports event start marker:
112      expect (e ().start_mark).to_equal {line = 1, column = 0, index = 4}
113  - it reports event end marker:
114      expect (e ().end_mark).to_equal {line = 1, column = 3, index = 7}
115
116- describe ALIAS:
117  - before:
118      e = consume (10, "---\n" ..
119                      "hr:\n" ..
120                      "- Mark McGwire\n" ..
121                      "- &SS Sammy Sosa\n" ..
122                      "rbi:\n" ..
123                      "- *SS\n" ..
124                      "- Ken Griffey")
125  - it recognizes an alias event:
126      expect (filter (e (), "type", "anchor")).
127         to_equal {type = "ALIAS", anchor = "SS"}
128  - it reports event start marker:
129      expect (e ().start_mark).to_equal {line = 5, column = 2, index = 47}
130  - it reports event end marker:
131      expect (e ().end_mark).to_equal {line = 5, column = 5, index = 50}
132
133- describe SCALAR:
134  - before:
135      e = consume (6, "---\n" ..
136                      "hr:\n" ..
137                      "- Mark McGwire\n" ..
138                      "- &SS Sammy Sosa\n" ..
139                      "rbi:\n" ..
140                      "- *SS\n" ..
141                      "- Ken Griffey")
142  - it recognizes a scalar event:
143      expect (filter (e (), "type", "value")).
144         to_equal {type = "SCALAR",  value = "Sammy Sosa"}
145  - it records anchors:
146      expect (e ().anchor).to_be "SS"
147  - it reports event start marker:
148      expect (e ().start_mark).to_equal {line = 3, column = 2, index = 25}
149  - it reports event end marker:
150      expect (e ().end_mark).to_equal {line = 3, column = 16, index = 39}
151
152  - context with quoting style:
153    - context plain style:
154      - before:
155          e = consume (2, "---\n" ..
156                          "  Mark McGwire's\n" ..
157                          "  year was crippled\n" ..
158                          "  by a knee injury.\n")
159      - it ignores line-breaks and indentation:
160          expect (e ().value).
161             to_be "Mark McGwire's year was crippled by a knee injury."
162      - it recognizes implicit plain style:
163          e = consume (2, "---\n" ..
164                          "  Mark McGwire's\n" ..
165                          "  year was crippled\n" ..
166                          "  by a knee injury.\n")
167          expect (e ().plain_implicit).to_be (true)
168      - it recognizes explicit plain style:
169          e = consume (2, "|\n" ..
170                          "  Mark McGwire's\n" ..
171                          "  year was crippled\n" ..
172                          "  by a knee injury.\n")
173          expect (e ().plain_implicit).to_be (false)
174      - it recognizes implicit quoted style:
175          e = consume (2, "|\n" ..
176                          "  Mark McGwire's\n" ..
177                          "  year was crippled\n" ..
178                          "  by a knee injury.\n")
179          expect (e ().quoted_implicit).to_be (true)
180      - it recognizes explicit quoted style:
181          e = consume (2, "'\n" ..
182                          "  Mark McGwire's\n" ..
183                          "  year was crippled\n" ..
184                          "  by a knee injury.'\n")
185          expect (e ().plain_implicit).to_be (false)
186    - context folded style:
187      - it preserves blank lines and deeper indentation:
188          e = consume (2, ">\n" ..
189                          "  Sammy Sosa completed another\n" ..
190                          "  fine season with great stats.\n" ..
191                          "\n" ..
192                          "    63 Home Runs\n" ..
193                          "    0.288 Batting Average\n" ..
194                          "\n" ..
195                          "  What a year!\n")
196          expect (e ().value).
197             to_be ("Sammy Sosa completed another fine season with great stats.\n" ..
198                       "\n" ..
199                       "  63 Home Runs\n" ..
200                       "  0.288 Batting Average\n" ..
201                       "\n" ..
202                       "What a year!\n")
203    - context literal style:
204      - it removes indentation but preserves all line-breaks:
205          e = consume (2, [[# ASCII Art]] .. "\n" ..
206                          [[--- |]] .. "\n" ..
207                          [[  \//||\/||]] .. "\n" ..
208                          [[  // ||  ||__]] .. "\n")
209          expect (e ().value).
210             to_be ([[\//||\/||]] .. "\n" ..
211                        [[// ||  ||__]] .. "\n")
212
213    - context single quoted style:
214      - it folds line breaks:
215          e = consume (2, [['This quoted scalar]] .. "\n" ..
216                          [[  spans two lines.']])
217          expect (e ().value).
218             to_be "This quoted scalar spans two lines."
219      - it does not process escape sequences:
220          # Lua [[ quoting makes sure libyaml sees all the quotes.
221          e = consume (2, [['"Howdy!"\t\u263A']])
222          expect (e ().value).to_be [["Howdy!"\t\u263A]]
223
224    # Note that we have to single quote the Lua snippets to prevent
225    # libyaml from interpreting the bytes as the spec file is read, so
226    # that the raw strings get correctly passed to the Lua compiler.
227    - context double quoted style:
228      - it folds line breaks: '
229          e = consume (4, [[quoted: "This quoted scalar]] .. "\n" ..
230                          [[  spans two lines\n"]])
231          expect (e ().value).
232             to_be "This quoted scalar spans two lines\n"'
233      - it recognizes unicode escape sequences: '
234          e = consume (4, [[unicode: "Sosa did fine.\u263A"]])
235          expect (e ().value).to_be "Sosa did fine.\226\152\186"'
236      - it recognizes control escape sequences: '
237          e = consume (4, [[control: "\b1998\t1999\t2000\n"]])
238          expect (e ().value).to_be "\b1998\t1999\t2000\n"'
239      - it recognizes hexadecimal escape sequences: '
240          e = consume (4, [[hexesc: "\x41\x42\x43 is ABC"]])
241          expect (e ().value).to_be "ABC is ABC"'
242
243    - context indentation determines scope: '
244        e = consume (4, "name: Mark McGwire\n" ..
245                        "accomplishment: >\n" ..
246                        "  Mark set a major league\n" ..
247                        "  home run record in 1998.\n" ..
248                        "stats: |\n" ..
249                        "  65 Home Runs\n" ..
250                        "  0.278 Batting Average\n")
251        expect (e ().value).to_be "Mark McGwire"
252        expect (e ().value).to_be "accomplishment"
253        expect (e ().value).
254           to_be "Mark set a major league home run record in 1998.\n"
255        expect (e ().value).to_be "stats"
256        expect (e ().value).to_be "65 Home Runs\n0.278 Batting Average\n"'
257
258  - context with tag:
259    - it recognizes local tags: '
260        e = consume (4, "application specific tag: !something |\n" ..
261                        " The semantics of the tag\n" ..
262                        " above may be different for\n" ..
263                        " different documents.")
264        expect (e ().tag).to_be "!something"'
265    - it recognizes global tags: '
266        e = consume (4, "picture: !!binary |\n" ..
267                        " R0lGODlhDAAMAIQAAP//9/X\n" ..
268                        " 17unp5WZmZgAAAOfn515eXv\n" ..
269                        " Pz7Y6OjuDg4J+fn5OTk6enp\n" ..
270                        " 56enmleECcgggoBADs=")
271        expect (e ().tag).to_be "tag:yaml.org,2002:binary"'
272    - it resolves %TAG declarations: '
273        e = consume (5, "%TAG ! tag:clarkevans.com,2002:\n" ..
274                        "---\n" ..
275                        "shape:\n" ..
276                        "- !circle\n" ..
277                        "  center: &ORIGIN {x: 73, y: 129}\n" ..
278                        "  radius: 7")
279        expect (e ().tag).to_be "tag:clarkevans.com,2002:circle"'
280
281- describe SEQUENCE_START:
282  - before: '
283      e = consume (4, "fubar: &FOO\n" ..
284                      "  - foo\n" ..
285                      "  - bar\n")'
286  - it recognizes a sequence start event:
287      expect (e ().type).to_be "SEQUENCE_START"
288  - it records anchors:
289      expect (e ().anchor).to_be "FOO"
290  - it reports event start marker:
291      expect (e ().start_mark).to_equal {line = 0, column = 7, index = 7}
292  - it reports event end marker:
293      expect (e ().end_mark).to_equal {line = 1, column = 2, index = 14}
294
295  - context with tag:
296    - it recognizes local tags: '
297        e = consume (2, "--- !something\n" ..
298                        "- foo\n")
299        expect (filter (e (), "type", "tag")).
300           to_equal {type = "SEQUENCE_START", tag = "!something"}'
301    - it recognizes global tags: '
302        e = consume (2, "--- !!omap\n" ..
303                        "- Mark McGwire: 65\n" ..
304                        "- Sammy Sosa: 63\n" ..
305                        "- Ken Griffy: 58\n")
306        expect (filter (e (), "type", "tag")).
307           to_equal {type = "SEQUENCE_START",
308                        tag  = "tag:yaml.org,2002:omap"}'
309    - it resolves %TAG declarations: '
310        e = consume (2, "%TAG ! tag:clarkevans.com,2002:\n" ..
311                        "--- !shape\n" ..
312                        "- !circle\n" ..
313                        "  center: &ORIGIN {x: 73, y: 129}\n" ..
314                        "  radius: 7\n")
315        expect (filter (e (), "type", "tag")).
316           to_equal {type = "SEQUENCE_START",
317                        tag  = "tag:clarkevans.com,2002:shape"}'
318
319  - context with style:
320    - it recognizes block style:
321        e = consume (2, "- first\n- second")
322        expect (filter (e (), "type", "style")).
323           to_equal {type = "SEQUENCE_START", style = "BLOCK"}
324    - it recognizes flow style:
325        e = consume (2, "[first, second]")
326        expect (filter (e (), "type", "style")).
327           to_equal {type = "SEQUENCE_START", style = "FLOW"}
328
329- describe SEQUENCE_END:
330  - before:
331      e = consume (5, "- foo\n- bar\n")
332  - it recognizes a sequence end event:
333      expect (e ().type).to_equal "SEQUENCE_END"
334  - it reports event start marker:
335      expect (e ().start_mark).to_equal {line = 2, column = 0, index = 12}
336  - it reports event end marker:
337      expect (e ().end_mark).to_equal {line = 2, column = 0, index = 12}
338
339- describe MAPPING_START:
340  - before: 'e = consume (3, "- &FUBAR\n  foo: bar\n")'
341  - it recognizes a mapping start event:
342        expect (e ().type).to_be "MAPPING_START"
343  - it records anchors:
344      expect (e ().anchor).to_be "FUBAR"
345  - it reports event start marker:
346      expect (e ().start_mark).to_equal {line = 0, column = 2, index = 2}
347  - it reports event end marker:
348      expect (e ().end_mark).to_equal {line = 1, column = 2, index = 11}
349
350  - context with tag:
351    - it recognizes local tags: '
352    e = consume (2, "--- !something\nfoo: bar\n")
353        expect (filter (e (), "type", "tag")).
354           to_equal {type = "MAPPING_START", tag = "!something"}'
355    - it recognizes global tags: '
356        e = consume (2, "--- !!set\n" ..
357                        "? Mark McGwire\n" ..
358                        "? Sammy Sosa\n" ..
359                        "? Ken Griffy\n")
360        expect (filter (e (), "type", "tag")).
361           to_equal {type = "MAPPING_START",
362                        tag  = "tag:yaml.org,2002:set"}'
363    - it resolves %TAG declarations: '
364        e = consume (3, "%TAG ! tag:clarkevans.com,2002:\n" ..
365                        "--- !shape\n" ..
366                        "- !circle\n" ..
367                        "  center: &ORIGIN {x: 73, y: 129}\n" ..
368                        "  radius: 7\n")
369        expect (filter (e (), "type", "tag")).
370           to_equal {type = "MAPPING_START",
371                        tag  = "tag:clarkevans.com,2002:circle"}'
372
373  - context with style:
374    - it recognizes block style: '
375        e = consume (2, "foo: bar\nbaz:\n  quux")
376        expect (filter (e (), "type", "style")).
377           to_equal {type = "MAPPING_START", style = "BLOCK"}'
378    - it recognizes flow style: '
379        e = consume (2, "{foo: bar, baz: quux}")
380        expect (filter (e (), "type", "style")).
381           to_equal {type = "MAPPING_START", style = "FLOW"}'
382
383
384- describe MAPPING_END:
385  - before: 'e = consume (5, "foo: bar\n")'
386  - it recognizes the mapping end event:
387      expect (e ().type).to_equal "MAPPING_END"
388  - it reports event start marker:
389      expect (e ().start_mark).to_equal {line = 1, column = 0, index = 9}
390  - it reports event end marker:
391      expect (e ().end_mark).to_equal {line = 1, column = 0, index = 9}
392