mirror of
https://git.savannah.gnu.org/git/guix.git
synced 2025-01-18 13:36:36 +01:00
63cb43d56c
Change-Id: Id14d4008391a01820ade754fa9c2ca8e88b8c7f9
469 lines
13 KiB
Scheme
469 lines
13 KiB
Scheme
;;; GNU Guix --- Functional package management for GNU
|
|
;;; Copyright © 2023 Lars-Dominik Braun <lars@6xq.net>
|
|
;;;
|
|
;;; This file is part of GNU Guix.
|
|
;;;
|
|
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
|
;;; under the terms of the GNU General Public License as published by
|
|
;;; the Free Software Foundation; either version 3 of the License, or (at
|
|
;;; your option) any later version.
|
|
;;;
|
|
;;; GNU Guix is distributed in the hope that it will be useful, but
|
|
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;;; GNU General Public License for more details.
|
|
;;;
|
|
;;; You should have received a copy of the GNU General Public License
|
|
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
(define-module (test-toml)
|
|
#:use-module (guix build toml)
|
|
#:use-module (guix tests)
|
|
#:use-module (srfi srfi-19) ; For datetime.
|
|
#:use-module (srfi srfi-64)
|
|
#:use-module (ice-9 match))
|
|
|
|
(test-begin "toml")
|
|
|
|
;; Tests taken from https://toml.io/en/v1.0.0
|
|
|
|
(test-error "parse-toml: Unspecified key"
|
|
&file-not-consumed
|
|
(parse-toml "key = # INVALID"))
|
|
|
|
(test-error "parse-toml: Missing EOL"
|
|
&file-not-consumed
|
|
(parse-toml "first = \"Tom\" last = \"Preston-Werner\" # INVALID"))
|
|
|
|
(test-equal "parse-toml: Bare keys"
|
|
'(("key" . "value") ("bare_key" . "value") ("bare-key" . "value") ("1234" . "value"))
|
|
(parse-toml "key = \"value\"
|
|
bare_key = \"value\"
|
|
bare-key = \"value\"
|
|
1234 = \"value\""))
|
|
|
|
(test-equal "parse-toml: Quoted keys"
|
|
'(("127.0.0.1" . "value")
|
|
("character encoding" . "value")
|
|
("ʎǝʞ" . "value")
|
|
("key2" . "value")
|
|
("quoted \"value\"" . "value"))
|
|
(parse-toml "\"127.0.0.1\" = \"value\"
|
|
\"character encoding\" = \"value\"
|
|
\"ʎǝʞ\" = \"value\"
|
|
'key2' = \"value\"
|
|
'quoted \"value\"' = \"value\""))
|
|
|
|
(test-equal "parse-toml: No key"
|
|
#f
|
|
(parse-toml "= \"no key name\""))
|
|
|
|
(test-equal "parse-toml: Empty key"
|
|
'(("" . "blank"))
|
|
(parse-toml "\"\" = \"blank\""))
|
|
|
|
(test-equal "parse-toml: Dotted keys"
|
|
'(("name" . "Orange")
|
|
("physical" ("color" . "orange")
|
|
("shape" . "round"))
|
|
("site" ("google.com" . #t)))
|
|
(parse-toml "name = \"Orange\"
|
|
physical.color = \"orange\"
|
|
physical.shape = \"round\"
|
|
site.\"google.com\" = true"))
|
|
|
|
(test-equal "parse-toml: Dotted keys with whitespace"
|
|
'(("fruit" ("name" . "banana") ("color" . "yellow") ("flavor" . "banana")))
|
|
(parse-toml "fruit.name = \"banana\" # this is best practice
|
|
fruit. color = \"yellow\" # same as fruit.color
|
|
fruit . flavor = \"banana\" # same as fruit.flavor"))
|
|
|
|
(test-error "parse-toml: Multiple keys"
|
|
&already-defined
|
|
(parse-toml "name = \"Tom\"
|
|
name = \"Pradyun\""))
|
|
|
|
(test-equal "parse-toml: Implicit tables"
|
|
'(("fruit" ("apple" ("smooth" . #t)) ("orange" . 2)))
|
|
(parse-toml "fruit.apple.smooth = true
|
|
fruit.orange = 2"))
|
|
|
|
(test-error "parse-toml: Write to value"
|
|
&already-defined
|
|
(parse-toml "fruit.apple = 1
|
|
fruit.apple.smooth = true"))
|
|
|
|
(test-equal "parse-toml: String"
|
|
'(("str" . "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."))
|
|
(parse-toml "str = \"I'm a string. \\\"You can quote me\\\". Name\\tJos\\u00E9\\nLocation\\tSF.\""))
|
|
|
|
(test-equal "parse-toml: Empty string"
|
|
'(("str1" . "")
|
|
("str2" . "")
|
|
("str3" . "")
|
|
("str4" . ""))
|
|
(parse-toml "str1 = \"\"
|
|
str2 = ''
|
|
str3 = \"\"\"\"\"\"
|
|
str4 = ''''''"))
|
|
|
|
(test-equal "parse-toml: Multi-line basic strings"
|
|
'(("str1" . "Roses are red\nViolets are blue")
|
|
("str2" . "The quick brown fox jumps over the lazy dog.")
|
|
("str3" . "The quick brown fox jumps over the lazy dog.")
|
|
("str4" . "Here are two quotation marks: \"\". Simple enough.")
|
|
("str5" . "Here are three quotation marks: \"\"\".")
|
|
("str6" . "Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\".")
|
|
("str7" . "\"This,\" she said, \"is just a pointless statement.\""))
|
|
(parse-toml "str1 = \"\"\"
|
|
Roses are red
|
|
Violets are blue\"\"\"
|
|
|
|
str2 = \"\"\"
|
|
The quick brown \\
|
|
|
|
|
|
fox jumps over \\
|
|
the lazy dog.\"\"\"
|
|
|
|
str3 = \"\"\"\\
|
|
The quick brown \\
|
|
fox jumps over \\
|
|
the lazy dog.\\
|
|
\"\"\"
|
|
|
|
str4 = \"\"\"Here are two quotation marks: \"\". Simple enough.\"\"\"
|
|
# str5 = \"\"\"Here are three quotation marks: \"\"\".\"\"\" # INVALID
|
|
str5 = \"\"\"Here are three quotation marks: \"\"\\\".\"\"\"
|
|
str6 = \"\"\"Here are fifteen quotation marks: \"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\"\"\"\\\".\"\"\"
|
|
|
|
# \"This,\" she said, \"is just a pointless statement.\"
|
|
str7 = \"\"\"\"This,\" she said, \"is just a pointless statement.\"\"\"\""))
|
|
|
|
(test-equal "parse-toml: Literal string"
|
|
'(("winpath" . "C:\\Users\\nodejs\\templates")
|
|
("winpath2" . "\\\\ServerX\\admin$\\system32\\")
|
|
("quoted" . "Tom \"Dubs\" Preston-Werner")
|
|
("regex" . "<\\i\\c*\\s*>"))
|
|
(parse-toml "winpath = 'C:\\Users\\nodejs\\templates'
|
|
winpath2 = '\\\\ServerX\\admin$\\system32\\'
|
|
quoted = 'Tom \"Dubs\" Preston-Werner'
|
|
regex = '<\\i\\c*\\s*>'"))
|
|
|
|
(test-equal "parse-toml: Multi-line literal strings"
|
|
'(("regex2" . "I [dw]on't need \\d{2} apples")
|
|
("lines" . "The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n")
|
|
("quot15" . "Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"")
|
|
("apos15" . "Here are fifteen apostrophes: '''''''''''''''")
|
|
("str" . "'That,' she said, 'is still pointless.'"))
|
|
(parse-toml "regex2 = '''I [dw]on't need \\d{2} apples'''
|
|
lines = '''
|
|
The first newline is
|
|
trimmed in raw strings.
|
|
All other whitespace
|
|
is preserved.
|
|
'''
|
|
quot15 = '''Here are fifteen quotation marks: \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"'''
|
|
|
|
# apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID
|
|
apos15 = \"Here are fifteen apostrophes: '''''''''''''''\"
|
|
|
|
# 'That,' she said, 'is still pointless.'
|
|
str = ''''That,' she said, 'is still pointless.''''"))
|
|
|
|
(test-equal "parse-toml: Decimal integer"
|
|
'(("int1" . 99) ("int2" . 42) ("int3" . 0) ("int4" . -17))
|
|
(parse-toml "int1 = +99
|
|
int2 = 42
|
|
int3 = 0
|
|
int4 = -17"))
|
|
|
|
(test-equal "parse-toml: Decimal integer underscores"
|
|
'(("int5" . 1000) ("int6" . 5349221) ("int7" . 5349221) ("int8" . 12345))
|
|
(parse-toml "int5 = 1_000
|
|
int6 = 5_349_221
|
|
int7 = 53_49_221 # Indian number system grouping
|
|
int8 = 1_2_3_4_5 # VALID but discouraged"))
|
|
|
|
(test-equal "parse-toml: Hexadecimal"
|
|
`(("hex1" . ,#xdeadbeef) ("hex2" . ,#xdeadbeef) ("hex3" . ,#xdeadbeef))
|
|
(parse-toml "hex1 = 0xDEADBEEF
|
|
hex2 = 0xdeadbeef
|
|
hex3 = 0xdead_beef"))
|
|
|
|
(test-equal "parse-toml: Octal"
|
|
`(("oct1" . ,#o01234567) ("oct2" . #o755))
|
|
(parse-toml "oct1 = 0o01234567
|
|
oct2 = 0o755"))
|
|
|
|
(test-equal "parse-toml: Binary"
|
|
`(("bin1" . ,#b11010110))
|
|
(parse-toml "bin1 = 0b11010110"))
|
|
|
|
(test-equal "parse-toml: Float"
|
|
'(("flt1" . 1.0)
|
|
("flt2" . 3.1415)
|
|
("flt3" . -0.01)
|
|
("flt4" . 5e+22)
|
|
("flt5" . 1e06)
|
|
("flt6" . -2e-2)
|
|
("flt7" . 6.626e-34)
|
|
("flt8" . 224617.445991228))
|
|
(parse-toml "# fractional
|
|
flt1 = +1.0
|
|
flt2 = 3.1415
|
|
flt3 = -0.01
|
|
|
|
# exponent
|
|
flt4 = 5e+22
|
|
flt5 = 1e06
|
|
flt6 = -2E-2
|
|
|
|
# both
|
|
flt7 = 6.626e-34
|
|
|
|
flt8 = 224_617.445_991_228"))
|
|
|
|
(test-equal "parse-toml: Float"
|
|
'(("sf1" . +inf.0)
|
|
("sf2" . +inf.0)
|
|
("sf3" . -inf.0)
|
|
("sf4" . +nan.0)
|
|
("sf5" . +nan.0)
|
|
("sf6" . -nan.0))
|
|
(parse-toml "# infinity
|
|
sf1 = inf # positive infinity
|
|
sf2 = +inf # positive infinity
|
|
sf3 = -inf # negative infinity
|
|
|
|
# not a number
|
|
sf4 = nan # actual sNaN/qNaN encoding is implementation-specific
|
|
sf5 = +nan # same as `nan`
|
|
sf6 = -nan # valid, actual encoding is implementation-specific"))
|
|
|
|
(test-equal "parse-toml: Boolean"
|
|
'(("bool1" . #t)
|
|
("bool2" . #f))
|
|
(parse-toml "bool1 = true
|
|
bool2 = false"))
|
|
|
|
(test-equal "parse-toml: Offset date-time"
|
|
`(("odt1" . ,(make-date #f 0 32 7 27 5 1979 0))
|
|
("odt2" . ,(make-date #f 0 32 0 27 5 1979 (* -7 60 60)))
|
|
("odt3" . ,(make-date 999999 0 32 0 27 5 1979 (* 7 60 60)))
|
|
("odt4" . ,(make-date #f 0 32 7 27 5 1979 0)))
|
|
(parse-toml "odt1 = 1979-05-27T07:32:00Z
|
|
odt2 = 1979-05-27T00:32:00-07:00
|
|
odt3 = 1979-05-27T00:32:00.999999+07:00
|
|
odt4 = 1979-05-27 07:32:00Z"))
|
|
|
|
(test-equal "parse-toml: Local date-time"
|
|
`(("ldt1" . ,(make-date #f 0 32 7 27 5 1979 #f))
|
|
("ldt2" . ,(make-date 999999 0 32 0 27 5 1979 #f)))
|
|
(parse-toml "ldt1 = 1979-05-27T07:32:00
|
|
ldt2 = 1979-05-27T00:32:00.999999"))
|
|
|
|
(test-equal "parse-toml: Local date"
|
|
`(("ld1" . ,(make-date #f #f #f #f 27 5 1979 #f)))
|
|
(parse-toml "ld1 = 1979-05-27"))
|
|
|
|
(test-equal "parse-toml: Local time"
|
|
`(("lt1" . ,(make-date #f 0 32 7 #f #f #f #f))
|
|
("lt2" . ,(make-date 999999 0 32 0 #f #f #f #f)))
|
|
(parse-toml "lt1 = 07:32:00
|
|
lt2 = 00:32:00.999999"))
|
|
|
|
(test-equal "parse-toml: Arrays"
|
|
'(("integers" 1 2 3)
|
|
("colors" "red" "yellow" "green")
|
|
("nested_arrays_of_ints" (1 2) (3 4 5))
|
|
("nested_mixed_array" (1 2) ("a" "b" "c"))
|
|
("string_array" "all" "strings")
|
|
("numbers" 0.1 0.2 0.5 1 2 5)
|
|
("contributors" "Foo Bar <foo@example.com>" (("name" . "Baz Qux") ("email" . "bazqux@example.com") ("url" . "https://example.com/bazqux")))
|
|
("integers2" 1 2 3)
|
|
("integers3" 1 2))
|
|
(parse-toml "integers = [ 1, 2, 3 ]
|
|
colors = [ \"red\", \"yellow\", \"green\" ]
|
|
nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ]
|
|
nested_mixed_array = [ [ 1, 2 ], [\"a\", \"b\", \"c\"] ]
|
|
string_array = [ \"all\", 'strings' ]
|
|
|
|
# Mixed-type arrays are allowed
|
|
numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ]
|
|
contributors = [
|
|
\"Foo Bar <foo@example.com>\",
|
|
{ name = \"Baz Qux\", email = \"bazqux@example.com\", url = \"https://example.com/bazqux\" }
|
|
]
|
|
|
|
integers2 = [
|
|
1, 2, 3
|
|
]
|
|
|
|
integers3 = [
|
|
1,
|
|
2, # this is ok
|
|
]"))
|
|
|
|
(test-equal "parse-toml: Arrays of empty strings"
|
|
'(("empty1" "")
|
|
("empty2" "" "")
|
|
("empty3" "" "" "")
|
|
("emptyraw1" "")
|
|
("emptyraw2" "" "")
|
|
("emptyraw3" "" "" "")
|
|
("emptyml1" "")
|
|
("emptyml2" "" "")
|
|
("emptyml3" "" "" "")
|
|
("emptyrawml1" "")
|
|
("emptyrawml2" "" "")
|
|
("emptyrawml3" "" "" ""))
|
|
(parse-toml "empty1 = [ \"\" ]
|
|
empty2 = [ \"\", \"\" ]
|
|
empty3 = [ \"\", \"\", \"\" ]
|
|
emptyraw1 = [ '' ]
|
|
emptyraw2 = [ '', '' ]
|
|
emptyraw3 = [ '', '', '' ]
|
|
emptyml1 = [ \"\"\"\"\"\" ]
|
|
emptyml2 = [ \"\"\"\"\"\", \"\"\"\"\"\" ]
|
|
emptyml3 = [ \"\"\"\"\"\", \"\"\"\"\"\", \"\"\"\"\"\" ]
|
|
emptyrawml1 = [ '''''' ]
|
|
emptyrawml2 = [ '''''', '''''' ]
|
|
emptyrawml3 = [ '''''', '''''', '''''' ]
|
|
"))
|
|
|
|
(test-equal "parse-toml: Tables"
|
|
'(("table-1" ("key1" . "some string")
|
|
("key2" . 123))
|
|
("table-2" ("key1" . "another string")
|
|
("key2" . 456)))
|
|
(parse-toml "[table-1]
|
|
key1 = \"some string\"
|
|
key2 = 123
|
|
|
|
[table-2]
|
|
key1 = \"another string\"
|
|
key2 = 456"))
|
|
|
|
|
|
(test-equal "parse-toml: Dotted table"
|
|
'(("dog" ("tater.man" ("type" ("name" . "pug")))))
|
|
(parse-toml "[dog.\"tater.man\"]
|
|
type.name = \"pug\""))
|
|
|
|
|
|
(test-equal "parse-toml: Dotted table with whitespace"
|
|
'(("a" ("b" ("c" ("x" . 1))))
|
|
("d" ("e" ("f" ("x" . 1))))
|
|
("g" ("h" ("i" ("x" . 1))))
|
|
("j" ("ʞ" ("l" ("x" . 1)))))
|
|
(parse-toml "[a.b.c] # this is best practice
|
|
x=1
|
|
[ d.e.f ] # same as [d.e.f]
|
|
x=1
|
|
[ g . h . i ] # same as [g.h.i]
|
|
x=1
|
|
[ j . \"ʞ\" . 'l' ] # same as [j.\"ʞ\".'l']
|
|
x=1"))
|
|
|
|
;; XXX: technically this is not allowed, but we permit it.
|
|
(test-equal "parse-toml: Multiple tables"
|
|
'(("fruit" ("apple" . "red") ("orange" . "orange")))
|
|
(parse-toml "[fruit]
|
|
apple = \"red\"
|
|
|
|
[fruit]
|
|
orange = \"orange\""))
|
|
|
|
(test-equal "parse-toml: Assignment to non-table"
|
|
#f
|
|
(parse-toml "[fruit]
|
|
apple = \"red\"
|
|
|
|
[fruit.apple]
|
|
texture = \"smooth\""))
|
|
|
|
(test-equal "parse-toml: Dotted keys create tables"
|
|
'(("fruit" ("apple" ("color" . "red") ("taste" ("sweet" . #t)))))
|
|
(parse-toml "fruit.apple.color = \"red\"
|
|
fruit.apple.taste.sweet = true"))
|
|
|
|
(test-equal "parse-toml: Inline tables"
|
|
'(("name" ("first" . "Tom") ("last" . "Preston-Werner"))
|
|
("point" ("x" . 1) ("y" . 2))
|
|
("animal" ("type" ("name" . "pug"))))
|
|
(parse-toml "name = { first = \"Tom\", last = \"Preston-Werner\" }
|
|
point = { x = 1, y = 2 }
|
|
animal = { type.name = \"pug\" }"))
|
|
|
|
(test-error "parse-toml: Invalid assignment to inline table"
|
|
#t
|
|
(parse-toml "[product]
|
|
type = { name = \"Nail\" }
|
|
type.edible = false # INVALID"))
|
|
|
|
;; We do not catch this semantic error yet.
|
|
(test-expect-fail 1)
|
|
(test-error "parse-toml: Invalid assignment to implicit table"
|
|
#f
|
|
(parse-toml "[product]
|
|
type.name = \"Nail\"
|
|
type = { edible = false } # INVALID"))
|
|
|
|
;; Not implemented.
|
|
(test-expect-fail 1)
|
|
(test-equal "parse-toml: Array of tables"
|
|
'(("products" (("name" . "Hammer") ("sku" . 738594937))
|
|
()
|
|
(("name" . "Nail") ("sku" . 284758393) ("color" . "gray"))))
|
|
(parse-toml "[[products]]
|
|
name = \"Hammer\"
|
|
sku = 738594937
|
|
|
|
[[products]] # empty table within the array
|
|
|
|
[[products]]
|
|
name = \"Nail\"
|
|
sku = 284758393
|
|
|
|
color = \"gray\""))
|
|
|
|
;; Not implemented.
|
|
(test-expect-fail 1)
|
|
(test-equal "parse-toml: Array of tables"
|
|
'(("fruits" ((("name" . "apple")
|
|
("physical" (("color" . "red") ("shape" . "round")))
|
|
("varieties" ((("name" . "red delicious")) (("name" . "granny smith")))))
|
|
(("name" . "banana")
|
|
("varieties" (((("name" . "plantain")))))))))
|
|
(parse-toml "[[fruits]]
|
|
name = \"apple\"
|
|
|
|
[fruits.physical] # subtable
|
|
color = \"red\"
|
|
shape = \"round\"
|
|
|
|
[[fruits.varieties]] # nested array of tables
|
|
name = \"red delicious\"
|
|
|
|
[[fruits.varieties]]
|
|
name = \"granny smith\"
|
|
|
|
|
|
[[fruits]]
|
|
name = \"banana\"
|
|
|
|
[[fruits.varieties]]
|
|
name = \"plantain\""))
|
|
|
|
;; Not implemented.
|
|
(test-expect-fail 1)
|
|
(test-error "parse-toml: Assignment to statically defined array"
|
|
#f
|
|
(parse-toml "fruits = []
|
|
|
|
[[fruits]]
|
|
x=1"))
|
|
|
|
(test-end "toml")
|
|
|