1# LYAML binding for Lua 5.1, 5.2, 5.3 & 5.4 2# Copyright (C) 2013-2022 Gary V. Vaughan 3 4before: | 5 lyaml = require "lyaml" 6 7 -- Always use the new multi-doc capable API. 8 lyaml.legacy = lyaml.load 9 lyaml.load = function (stream) return lyaml.legacy (stream, true) end 10 11specify lyaml: 12- describe dumping: 13 - context streams: 14 - it writes an empty stream: 15 expect (lyaml.dump {}).to_equal "" 16 17 - context documents: 18 - it writes an empty document: 19 expect (lyaml.dump {""}).to_match "^%-%-%-%s*''\n%.%.%.%s*$" 20 - it writes consecutive documents: 21 expect (lyaml.dump {"one", "two"}). 22 to_match "^%-%-%-%s+one%s*\n%.%.%.%s*\n%-%-%-%s+two%s*\n%.%.%.%s*$" 23 24 - context scalars: 25 - it writes null: 26 expect (lyaml.dump {lyaml.null}).to_be "--- ~\n...\n" 27 expect (lyaml.dump {"~"}).to_be "--- '~'\n...\n" 28 - it writes booleans: 29 expect (lyaml.dump {"true"}).to_be "--- 'true'\n...\n" 30 expect (lyaml.dump {"yes"}).to_be "--- 'yes'\n...\n" 31 expect (lyaml.dump {"false"}).to_be "--- 'false'\n...\n" 32 expect (lyaml.dump {"no"}).to_be "--- 'no'\n...\n" 33 expect (lyaml.dump {true}).to_be "--- true\n...\n" 34 expect (lyaml.dump {false}).to_be "--- false\n...\n" 35 - it writes numbers: 36 expect (lyaml.dump {"123"}).to_be "--- '123'\n...\n" 37 expect (lyaml.dump {"12.3"}).to_be "--- '12.3'\n...\n" 38 expect (lyaml.dump {"0/0"}).to_be "--- 0/0\n...\n" 39 expect (lyaml.dump {123}).to_be "--- 123\n...\n" 40 expect (lyaml.dump {12.3}).to_be "--- 12.3\n...\n" 41 expect (lyaml.dump {0/0}).to_be "--- .nan\n...\n" 42 expect (lyaml.dump {math.huge}).to_be "--- .inf\n...\n" 43 expect (lyaml.dump {-math.huge}).to_be "--- -.inf\n...\n" 44 - it writes strings: 45 expect (lyaml.dump {"a string"}).to_be "--- a string\n...\n" 46 expect (lyaml.dump {"'a string'"}).to_be "--- '''a string'''\n...\n" 47 expect (lyaml.dump {"a\nmultiline\nstring"}).to_be "--- |-\n a\n multiline\n string\n...\n" 48 expect (lyaml.dump {""}).to_be "--- ''\n...\n" 49 50 - context sequences: 51 - it writes a sequence: 52 expect (lyaml.dump {{1, 2, 3}}).to_contain "- 1\n- 2\n- 3" 53 54 - context mappings: 55 - it writes a mapping: | 56 expect (lyaml.dump {{a=1, b=2, c=3, d=""}}). 57 to_contain.all_of {"a: 1", "b: 2", "c: 3", "d: ''"} 58 - it writes a mapping of mixed keys: | 59 expect (lyaml.dump {{[1]=1, [2]=2, three="three", four="4", [5]="five"}}). 60 to_contain.all_of {"1: 1", "2: 2", "three: three", "four: '4'", "5: five"} 61 - it writes a mapping of integer keys starting at two: | 62 expect (lyaml.dump {{[2]=2, [3]=3, [4]=4}}). 63 to_contain.all_of {"2: 2", "3: 3", "4: 4"} 64 - it writes a mapping of mixed keys starting at one: | 65 expect (lyaml.dump {{[1]=1, [2]=2, [3]=3, foo="bar"}}). 66 to_contain.all_of {"1: 1", "2: 2", "3: 3", "foo: bar"} 67 - it writes a mapping of mixed keys starting at two: | 68 expect (lyaml.dump {{[2]=2, [3]=3, [4]=4, foo="bar"}}). 69 to_contain.all_of {"2: 2", "3: 3", "4: 4", "foo: bar"} 70 - it writes a table containing nils (jumps in index) as mapping: | 71 expect (lyaml.dump {{1, 2, nil, 3, 4}}). 72 to_contain.all_of {"1: 1", "2: 2", "4: 3", "5: 4"} 73 74 - context anchors and aliases: 75 - before: 76 anchors = { 77 MAP = {["Mark McGwire"] = 65, ["Sammy Sosa"] = 63}, 78 SEQ = {"Mark McGwire", "Sammy Sosa"}, 79 } 80 - it writes scalar anchors: ' 81 anchors = { SS = "Sammy Sosa" } 82 expect (lyaml.dump ({{{anchor = anchors.SS}, {alias = anchors.SS}}}, anchors)). 83 to_contain "- anchor: &SS Sammy Sosa\n- alias: *SS\n"' 84 - it writes sequence anchors: ' 85 expect (lyaml.dump ({{{anchor = anchors.SEQ}, {alias = anchors.SEQ}}}, anchors)). 86 to_contain "\n- anchor: &SEQ\n - Mark McGwire\n - Sammy Sosa\n- alias: *SEQ\n"' 87 - it writes mapping anchors: ' 88 expect (lyaml.dump ({{{anchor = anchors.MAP}, {alias = anchors.MAP}}}, anchors)). 89 to_match "\n%- anchor: &MAP\n %w+ %w+: %d+\n %w+ %w+: %d+\n%- alias: %*MAP\n"' 90 91 92- describe loading: 93 - before: 94 fn = lyaml.load 95 96 - it loads an empty stream: 97 expect (fn "").to_equal {} 98 - it ignores comments: ' 99 expect (fn "# A comment\nnon-comment # trailing comment\n"). 100 to_equal { "non-comment" }' 101 - it diagnoses unexpected events: ' 102 expect (fn "...").to_error "1:1: did not find expected node content" 103 expect (fn "---\n...\ngarbage\n"). 104 to_error "2:1: did not find expected <document start>" 105 expect (fn " *ALIAS"). 106 to_error "1:2: invalid reference: ALIAS"' 107 108 - context documents: 109 - it lyaml.loads an empty document: 110 expect (fn "---").to_equal {lyaml.null} 111 expect (fn "---\n").to_equal {lyaml.null} 112 expect (fn "---\n...").to_equal {lyaml.null} 113 expect (fn "---\n...\n").to_equal {lyaml.null} 114 - it lyaml.loads multiple documents: 115 expect (fn "one\n---\ntwo").to_equal {"one", "two"} 116 expect (fn "---\none\n---\ntwo").to_equal {"one", "two"} 117 expect (fn "one\n...\n---\ntwo\n...").to_equal {"one", "two"} 118 expect (fn "---\none\n...\n---\ntwo\n...").to_equal {"one", "two"} 119 - it reports an empty document: 120 expect (fn "---\n---\ntwo\n---"). 121 to_equal {lyaml.null, "two", lyaml.null} 122 expect (fn "---\n...\n---\ntwo\n---"). 123 to_equal {lyaml.null, "two", lyaml.null} 124 expect (fn "---\n...\n---\ntwo\n...\n---"). 125 to_equal {lyaml.null, "two", lyaml.null} 126 expect (fn "---\n...\n---\ntwo\n...\n---\n..."). 127 to_equal {lyaml.null, "two", lyaml.null} 128 129 - context version directive: 130 - it recognizes version number: 131 expect (fn "%YAML 1.1\n---").to_equal {lyaml.null} 132 - it diagneses missing document start: 133 expect (fn "%YAML 1.1"). 134 to_error "expected <document start>" 135 - it diagnoses unsupported version: 136 expect (fn "%YAML 2.0\n---"). 137 to_error "incompatible YAML document" 138 139 - context tag directive: 140 - it recognizes primary tag directive: ' 141 expect (fn ("%TAG ! tag:yaml.org,2002:\n" .. 142 "---\n" .. 143 "!bool N")).to_equal {false}' 144 - it recognizes secondary tag directive: ' 145 expect (fn ("%TAG !! tag:ben-kiki.org,2000:\n" .. 146 "---\n" .. 147 "!!bool untrue")).to_equal {"untrue"}' 148 - it recognizes named tag directive: ' 149 expect (fn ("%TAG !bkk! tag:ben-kiki.org,2000:\n" .. 150 "---\n" .. 151 "!bkk!bool untrue")).to_equal {"untrue"}' 152 - it diagnoses undefined tag handles: ' 153 expect (fn ("!bkk!bool untrue")). 154 to_error "undefined tag handle"' 155 156 - context scalars: 157 - it recognizes null: ' 158 expect (fn "~").to_equal {lyaml.null} 159 expect (fn "foo: ").to_equal {{foo = lyaml.null}} 160 expect (fn "foo: ~").to_equal {{foo = lyaml.null}} 161 expect (fn "foo: !!null").to_equal {{foo = lyaml.null}} 162 expect (fn "foo: null").to_equal {{foo = lyaml.null}} 163 expect (fn "foo: Null").to_equal {{foo = lyaml.null}} 164 expect (fn "foo: NULL").to_equal {{foo = lyaml.null}}' 165 - it recognizes booleans: ' 166 expect (fn "true").to_equal {true} 167 expect (fn "false").to_equal {false} 168 expect (fn "yes").to_equal {true} 169 expect (fn "no").to_equal {false}' 170 - it loads bare y and n as strings: 171 expect (fn "y").to_equal {"y"} 172 expect (fn "n").to_equal {"n"} 173 - it recognizes integers: 174 expect (fn "0b001010011010").to_equal {666} 175 expect (fn "0b0010_1001_1010").to_equal {666} 176 expect (fn "+0b001_010_011_010").to_equal {666} 177 expect (fn "-0b0010_1001_1010").to_equal {-666} 178 expect (fn "0_1232").to_equal {666} 179 expect (fn "-01232").to_equal {-666} 180 expect (fn "666").to_equal {666} 181 expect (fn "0x29a").to_equal {666} 182 expect (fn "-0x29a").to_equal {-666} 183 expect (fn "12_345_678").to_equal {12345678} 184 expect (fn "11:6").to_equal {666} 185 - it recognizes floats: 186 expect (fn "12.3").to_equal {12.3} 187 expect (fn "685.230_15e+03").to_equal {685230.15} 188 expect (fn "685_230.15e+03").to_equal {685230150.0} 189 expect (fn "12_345_678.9").to_equal {12345678.9} 190 expect (fn "11:6.777").to_equal {666.777} 191 expect (fn ".Inf").to_equal {math.huge} 192 expect (fn "-.inf").to_equal {-math.huge} 193 nant = fn ".NaN" 194 expect (nant[1]).not_to_equal (nant[1]) 195 - it recognizes strings: 196 expect (fn "a string").to_equal {"a string"} 197 expect (fn "'''a string'''").to_equal {"'a string'"} 198 expect (fn "|-\n a\n multiline\n string").to_equal {"a\nmultiline\nstring"} 199 expect (fn "'yes'").to_equal {"yes"} 200 expect (fn "''").to_equal {""} 201 expect (fn '""').to_equal {""} 202 203 - context global tags: 204 - it recognizes !!null: 205 expect (fn "!!null").to_equal {lyaml.null} 206 - it recognizes !!bool: | 207 expect (fn '!!bool "true"').to_equal {true} 208 expect (fn '!!bool true').to_equal {true} 209 expect (fn '!!bool True').to_equal {true} 210 expect (fn '!!bool TRUE').to_equal {true} 211 expect (fn "!!bool 'false'").to_equal {false} 212 expect (fn '!!bool false').to_equal {false} 213 expect (fn '!!bool False').to_equal {false} 214 expect (fn '!!bool FALSE').to_equal {false} 215 expect (fn '!!bool "yes"').to_equal {true} 216 expect (fn "!!bool 'Yes'").to_equal {true} 217 expect (fn '!!bool YES').to_equal {true} 218 expect (fn '!!bool no').to_equal {false} 219 expect (fn "!!bool 'No'").to_equal {false} 220 expect (fn '!!bool "NO"').to_equal {false} 221 expect (fn '!!bool garbage'). 222 to_raise "invalid 'tag:yaml.org,2002:bool' value: 'garbage'" 223 - it loads explicit y and n as booleans: 224 expect (fn '!!bool Y').to_equal {true} 225 expect (fn '!!bool y').to_equal {true} 226 expect (fn '!!bool N').to_equal {false} 227 expect (fn '!!bool n').to_equal {false} 228 - it recognizes !!float: | 229 expect (fn '!!float 42').to_equal {42.0} 230 expect (fn '!!float "42"').to_equal {42.0} 231 expect (fn '!!float +42').to_equal {42.0} 232 expect (fn '!!float 12.3').to_equal {12.3} 233 expect (fn '!!float -3.141592').to_equal {-3.141592} 234 expect (fn '!!float 685_230.15e+03').to_equal {685230150.0} 235 expect (fn '!!float +685.230_15e+03').to_equal {685230.15} 236 expect (fn '!!float 12_345_678.9').to_equal {12345678.9} 237 expect (fn '!!float -0:3:11:6.777').to_equal {-11466.777} 238 expect (fn '!!float .Inf').to_equal {math.huge} 239 expect (fn '!!float -.inf').to_equal {-math.huge} 240 nant = fn '!!float .NaN' 241 expect (nant[1]).not_to_equal (nant[1]) 242 expect (fn '!!float garbage'). 243 to_raise "invalid 'tag:yaml.org,2002:float' value: 'garbage'" 244 - it recognizes !!int: | 245 expect (fn '!!int 0b0010_1001_1010').to_equal {666} 246 expect (fn '!!int "+0b001_010_011_010"').to_equal {666} 247 expect (fn '!!int -0b0010_1001_1010').to_equal {-666} 248 expect (fn '!!int 0_1232').to_equal {666} 249 expect (fn '!!int "-01232"').to_equal {-666} 250 expect (fn '!!int 666').to_equal {666} 251 expect (fn '!!int 0668').to_equal {668} 252 expect (fn '!!int "0x29a"').to_equal {666} 253 expect (fn '!!int -0x29a').to_equal {-666} 254 expect (fn '!!int 12_345_678').to_equal {12345678} 255 expect (fn '!!int 11:6').to_equal {666} 256 expect (fn '!!int 12.3'). 257 to_raise "invalid 'tag:yaml.org,2002:int' value: '12.3'" 258 expect (fn '!!int garbage'). 259 to_raise "invalid 'tag:yaml.org,2002:int' value: 'garbage'" 260 261 - context sequences: 262 - it recognizes block sequences: 263 expect (fn "- ~\n- \n- true\n- 42"). 264 to_equal {{lyaml.null, lyaml.null, true, 42}} 265 - it recognizes flow sequences: 266 expect (fn "[~, true, 42]"). 267 to_equal {{lyaml.null, true, 42}} 268 269 - context anchors and aliases: 270 - it resolves scalar anchors: ' 271 expect (fn "anchor: &SS Sammy Sosa\nalias: *SS"). 272 to_equal {{anchor = "Sammy Sosa", alias = "Sammy Sosa"}}' 273 - it resolves sequence anchors: ' 274 expect (fn "anchor: &SEQ [Mark McGwire, Sammy Sosa]\nalias: *SEQ"). 275 to_equal {{anchor = {"Mark McGwire", "Sammy Sosa"}, 276 alias = {"Mark McGwire", "Sammy Sosa"}}}' 277 - it resolves mapping anchors: ' 278 expect (fn "anchor: &MAP {Mark McGwire: 65, Sammy Sosa: 63}\nalias: *MAP"). 279 to_equal {{anchor = {["Mark McGwire"] = 65, ["Sammy Sosa"] = 63}, 280 alias = {["Mark McGwire"] = 65, ["Sammy Sosa"] = 63}}}' 281 282 - context a map: 283 - it recognizes block mapping: | 284 expect (fn "'null': ~\nboolean: yes\nnumber: 3.14"). 285 to_equal {{null = lyaml.null, boolean = true, number = 3.14}} 286 - it recognizes flow mapping: | 287 expect (fn "{null: null, boolean: yes, number: 3.14}"). 288 to_equal {{[lyaml.null] = lyaml.null, boolean = true, number = 3.14}} 289 - context with merge keys: 290 - before: | 291 merge = {x=1, y=2} 292 override = {x=0, z=2} 293 bogus = true 294 YAML = "- &MERGE {x: 1, y: 2}\n" .. 295 "- &OVERRIDE {x: 0, z: 2}\n" .. 296 "- &BOGUS true\n" 297 - it diagnoses invalid merge events: | 298 expect (fn "-\n !!merge : x\n z: 3"). 299 to_raise "invalid 'tag:yaml.org,2002:merge' merge event: x" 300 expect (fn "-\n << : x\n z: 3"). 301 to_raise "invalid '<<' merge event: x" 302 - it diagnoses invalid merge alias types: | 303 expect (fn (YAML .. "-\n !!merge : *BOGUS")). 304 to_raise "invalid 'tag:yaml.org,2002:merge' merge event: true" 305 expect (fn (YAML .. "-\n << : *BOGUS")). 306 to_raise "invalid '<<' merge event: true" 307 - it diagnoses invalid merge sequence elements: | 308 expect (fn (YAML .. '-\n !!merge : [*MERGE, OVERRIDE]')). 309 to_raise "invalid 'tag:yaml.org,2002:merge' sequence element 2: OVERRIDE" 310 expect (fn (YAML .. '-\n <<: [*MERGE, OVERRIDE]')). 311 to_raise "invalid '<<' sequence element 2: OVERRIDE" 312 - it diagnoses invalid merge sequence alias tyes: | 313 expect (fn (YAML .. '-\n !!merge : [*MERGE, *BOGUS]')). 314 to_raise "invalid 'tag:yaml.org,2002:merge' sequence element 2: true" 315 expect (fn (YAML .. '-\n <<: [*MERGE, *BOGUS]')). 316 to_raise "invalid '<<' sequence element 2: true" 317 - it supports merging bare maps: | 318 expect (fn ("-\n !!merge : {x: 1, y: 2}\n z: 3")). 319 to_equal {{{x=1, y=2, z=3}}} 320 expect (fn "-\n <<: {x: 1, y: 2}\n z: 3"). 321 to_equal {{{x=1, y=2, z=3}}} 322 - it supports merging map aliases: | 323 expect (fn (YAML .. "-\n !!merge : *MERGE\n z: 3")). 324 to_equal {{merge, override, bogus, {x=1, y=2, z=3}}} 325 expect (fn (YAML .. "-\n <<: *MERGE\n z: 3")). 326 to_equal {{merge, override, bogus, {x=1, y=2, z=3}}} 327 - it merges sequence of bare maps with decreasing precedence: | 328 expect (fn "-\n !!merge : [{x: 1, y: 2}, {x: 0, z: 2}]\n z: 3"). 329 to_equal {{{x=1, y=2, z=3}}} 330 expect (fn "-\n <<: [{x: 1, y: 2}, {x: 0, z: 2}]\n z: 3"). 331 to_equal {{{x=1, y=2, z=3}}} 332 - it merges sequence of aliases with decreasing precedence: | 333 expect (fn (YAML .. "-\n !!merge : [*MERGE, *OVERRIDE]\n z: 3")). 334 to_equal {{merge, override, bogus, {x=1, y=2, z=3}}} 335 expect (fn (YAML .. "-\n <<: [*MERGE, *OVERRIDE]\n z: 3")). 336 to_equal {{merge, override, bogus, {x=1, y=2, z=3}}} 337 - it merges a sequence alias with decreasing precedence: | 338 seq = {merge, override} 339 r = {{merge, override, bogus, seq, {x=1, y=2, z=3}}} 340 expect (fn (YAML .. "- &SEQ [*MERGE, *OVERRIDE]\n" .. 341 "-\n !!merge : *SEQ\n z: 3")).to_equal (r) 342 expect (fn (YAML .. "- &SEQ [*MERGE, *OVERRIDE]\n" .. 343 "-\n <<: *SEQ\n z: 3")).to_equal (r) 344