diff --git a/README.md b/README.md index c404a03..d87b016 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,10 @@ In the above, `TTYPE` may be one of: * string * integer * float -* datetime +* datetime (for offset date-time) +* datetime-local +* date +* time * bool * array @@ -101,7 +104,9 @@ and `TVALUE` is always a JSON string, except when `TTYPE` is `array` in which Empty hashes correspond to empty JSON objects (i.e., `{}`) and empty arrays correspond to empty JSON arrays (i.e., `[]`). -Datetime should be encoded following RFC 3339. +Offset datetimes should be encoded following RFC 3339. Local datetimes should be +encoded following RFC 3339, without the offset part. Local dates should be +encoded as the date part of RFC 3339 and Local times as the time part. ### Example JSON encoding diff --git a/json.go b/json.go index 7cf4a5e..dada813 100644 --- a/json.go +++ b/json.go @@ -3,6 +3,7 @@ package main import ( "strconv" "time" + "strings" ) // compareJson consumes the recursive structure of both `expected` and `test` @@ -137,6 +138,8 @@ func (r result) cmpJsonValues(e, t map[string]interface{}) result { return r.cmpFloats(evalue, tvalue); case "datetime": return r.cmpAsDatetimes(evalue, tvalue); + case "datetime-local": + return r.cmpAsLocalDateTimes(evalue, tvalue); default: return r.cmpAsStrings(evalue, tvalue); } @@ -151,7 +154,48 @@ func (r result) cmpAsStrings(e, t string) result { return r } +func (r result) cmpAsLocalDateTimes(e, t string) result { + ce := strings.Replace(strings.Replace(e, "t", "T", 1), " ", "T", 1) + ct := strings.Replace(strings.Replace(t, "t", "T", 1), " ", "T", 1) + + if ce != ct { + return r.failedf("Values for key '%s' don't match. Expected a "+ + "value of '%s' but got '%s'.", r.key, e, t) + } + return r +} + + func (r result) cmpFloats(e, t string) result { + // Handle Infinity and NaN + tc := strings.ToLower(t) + ec := strings.ToLower(e) + + if ec == "nan" || ec == "-nan" || ec == "+nan" { + if tc == "nan" || tc == "-nan" || tc == "+nan" { + return r + } else { + return r.failedf("Value for key '%s' don't match. Expected either nan, -nan or +nan but got '%v'.", r.key, tc) + } + } + + if ec == "inf" || ec == "+inf" { + if tc == "inf" || tc == "+inf" { + return r + } else { + return r.failedf("Value for key '%s' don't match. Expected inf or +inf but got '%v'.", r.key, tc) + } + } + + if ec == "-inf" { + if tc == "-inf" { + return r + } else { + return r.failedf("Value for key '%s' don't match. Expected -inf but got '%v'.", r.key, tc) + } + } + + // Else, compare as regular floats ef, err := strconv.ParseFloat(e, 64) if err != nil { return r.failedf("BUG in test case. Could not read '%s' as a "+ @@ -173,13 +217,13 @@ func (r result) cmpFloats(e, t string) result { func (r result) cmpAsDatetimes(e, t string) result { var err error - ef, err := time.Parse(time.RFC3339Nano, e) + ef, err := time.Parse(time.RFC3339Nano, strings.Replace(e, " ", "T", 1)) if err != nil { return r.failedf("BUG in test case. Could not read '%s' as a "+ "datetime value for key '%s'.", e, r.key) } - tf, err := time.Parse(time.RFC3339Nano, t) + tf, err := time.Parse(time.RFC3339Nano, strings.Replace(t, " ", "T", 1)) if err != nil { return r.failedf("Malformed parser output. Could not read '%s' "+ "as datetime value for key '%s'.", t, r.key) diff --git a/tests/invalid/array-7.toml b/tests/invalid/array-7.toml new file mode 100644 index 0000000..0991019 --- /dev/null +++ b/tests/invalid/array-7.toml @@ -0,0 +1 @@ +arr6 = [ 1, 2.0 ] # INVALID diff --git a/tests/invalid/array-of-tables-1.toml b/tests/invalid/array-of-tables-1.toml new file mode 100644 index 0000000..01d4d13 --- /dev/null +++ b/tests/invalid/array-of-tables-1.toml @@ -0,0 +1,4 @@ +# INVALID TOML DOC +fruit = [] + +[[fruit]] # Not allowed diff --git a/tests/invalid/array-of-tables-2.toml b/tests/invalid/array-of-tables-2.toml new file mode 100644 index 0000000..a77b0e4 --- /dev/null +++ b/tests/invalid/array-of-tables-2.toml @@ -0,0 +1,10 @@ +# INVALID TOML DOC +[[fruit]] + name = "apple" + + [[fruit.variety]] + name = "red delicious" + + # This table conflicts with the previous table + [fruit.variety] + name = "granny smith" diff --git a/tests/invalid/bare-key-1.toml b/tests/invalid/bare-key-1.toml new file mode 100644 index 0000000..e50dbe3 --- /dev/null +++ b/tests/invalid/bare-key-1.toml @@ -0,0 +1 @@ +bare!key = 123 diff --git a/tests/invalid/bare-key-2.toml b/tests/invalid/bare-key-2.toml new file mode 100644 index 0000000..24acaa1 --- /dev/null +++ b/tests/invalid/bare-key-2.toml @@ -0,0 +1,2 @@ +barekey + = 123 diff --git a/tests/invalid/bare-key-3.toml b/tests/invalid/bare-key-3.toml new file mode 100644 index 0000000..6aeca14 --- /dev/null +++ b/tests/invalid/bare-key-3.toml @@ -0,0 +1 @@ +barekey = \ No newline at end of file diff --git a/tests/invalid/int-0-padded.toml b/tests/invalid/int-0-padded.toml new file mode 100644 index 0000000..74b4032 --- /dev/null +++ b/tests/invalid/int-0-padded.toml @@ -0,0 +1 @@ +int = 0123 diff --git a/tests/invalid/key-value-pair-1.toml b/tests/invalid/key-value-pair-1.toml new file mode 100644 index 0000000..56f085a --- /dev/null +++ b/tests/invalid/key-value-pair-1.toml @@ -0,0 +1 @@ +key = # INVALID diff --git a/tests/invalid/multiple-dot-key.toml b/tests/invalid/multiple-dot-key.toml new file mode 100644 index 0000000..38d928b --- /dev/null +++ b/tests/invalid/multiple-dot-key.toml @@ -0,0 +1,3 @@ +# THIS IS INVALID +a.b = 1 +a.b.c = 2 diff --git a/tests/invalid/multiple-key.toml b/tests/invalid/multiple-key.toml new file mode 100644 index 0000000..7847bd4 --- /dev/null +++ b/tests/invalid/multiple-key.toml @@ -0,0 +1,3 @@ +# DO NOT DO THIS +name = "Tom" +name = "Pradyun" diff --git a/tests/invalid/no-key-name.toml b/tests/invalid/no-key-name.toml new file mode 100644 index 0000000..cd9fa90 --- /dev/null +++ b/tests/invalid/no-key-name.toml @@ -0,0 +1 @@ += "no key name" # INVALID diff --git a/tests/invalid/non-dec-integers.toml b/tests/invalid/non-dec-integers.toml new file mode 100644 index 0000000..63c1370 --- /dev/null +++ b/tests/invalid/non-dec-integers.toml @@ -0,0 +1,3 @@ +bin1 = -0b11010110 # non decimal integers are only for non negative +oct1 = 0o_1 +hex3 = 0xdeadbeeg \ No newline at end of file diff --git a/tests/invalid/string-basic-control-1.toml b/tests/invalid/string-basic-control-1.toml new file mode 100644 index 0000000..351f8c7 Binary files /dev/null and b/tests/invalid/string-basic-control-1.toml differ diff --git a/tests/invalid/string-basic-control-2.toml b/tests/invalid/string-basic-control-2.toml new file mode 100644 index 0000000..e8c87ef --- /dev/null +++ b/tests/invalid/string-basic-control-2.toml @@ -0,0 +1 @@ +a = "null" diff --git a/tests/invalid/string-basic-control-3.toml b/tests/invalid/string-basic-control-3.toml new file mode 100644 index 0000000..0937f8d --- /dev/null +++ b/tests/invalid/string-basic-control-3.toml @@ -0,0 +1 @@ +a = "null" diff --git a/tests/invalid/string-basic-control-4.toml b/tests/invalid/string-basic-control-4.toml new file mode 100644 index 0000000..21b4ec1 --- /dev/null +++ b/tests/invalid/string-basic-control-4.toml @@ -0,0 +1 @@ +a = "null" diff --git a/tests/invalid/string-basic-multiline-control-1.toml b/tests/invalid/string-basic-multiline-control-1.toml new file mode 100644 index 0000000..5b45dcd Binary files /dev/null and b/tests/invalid/string-basic-multiline-control-1.toml differ diff --git a/tests/invalid/string-basic-multiline-control-2.toml b/tests/invalid/string-basic-multiline-control-2.toml new file mode 100644 index 0000000..bb7eeb6 --- /dev/null +++ b/tests/invalid/string-basic-multiline-control-2.toml @@ -0,0 +1 @@ +a = """null""" diff --git a/tests/invalid/string-basic-multiline-control-3.toml b/tests/invalid/string-basic-multiline-control-3.toml new file mode 100644 index 0000000..45e378f --- /dev/null +++ b/tests/invalid/string-basic-multiline-control-3.toml @@ -0,0 +1 @@ +a = """null""" diff --git a/tests/invalid/string-basic-multiline-control-4.toml b/tests/invalid/string-basic-multiline-control-4.toml new file mode 100644 index 0000000..7d788a8 --- /dev/null +++ b/tests/invalid/string-basic-multiline-control-4.toml @@ -0,0 +1 @@ +a = """null""" diff --git a/tests/invalid/string-basic-multiline-out-of-range-unicode-escape-1.toml b/tests/invalid/string-basic-multiline-out-of-range-unicode-escape-1.toml new file mode 100644 index 0000000..b27e203 --- /dev/null +++ b/tests/invalid/string-basic-multiline-out-of-range-unicode-escape-1.toml @@ -0,0 +1 @@ +a = """\UFFFFFFFF""" diff --git a/tests/invalid/string-basic-multiline-out-of-range-unicode-escape-2.toml b/tests/invalid/string-basic-multiline-out-of-range-unicode-escape-2.toml new file mode 100644 index 0000000..17a9361 --- /dev/null +++ b/tests/invalid/string-basic-multiline-out-of-range-unicode-escape-2.toml @@ -0,0 +1 @@ +a = """\U00D80000""" diff --git a/tests/invalid/string-basic-multiline-unknown-escape.toml b/tests/invalid/string-basic-multiline-unknown-escape.toml new file mode 100644 index 0000000..35c5cc5 --- /dev/null +++ b/tests/invalid/string-basic-multiline-unknown-escape.toml @@ -0,0 +1 @@ +a = """\@""" diff --git a/tests/invalid/string-basic-out-of-range-unicode-escape-1.toml b/tests/invalid/string-basic-out-of-range-unicode-escape-1.toml new file mode 100644 index 0000000..ada1f55 --- /dev/null +++ b/tests/invalid/string-basic-out-of-range-unicode-escape-1.toml @@ -0,0 +1 @@ +a = "\UFFFFFFFF" diff --git a/tests/invalid/string-basic-out-of-range-unicode-escape-2.toml b/tests/invalid/string-basic-out-of-range-unicode-escape-2.toml new file mode 100644 index 0000000..d4833b3 --- /dev/null +++ b/tests/invalid/string-basic-out-of-range-unicode-escape-2.toml @@ -0,0 +1 @@ +a = "\U00D80000" diff --git a/tests/invalid/string-basic-unknown-escape.toml b/tests/invalid/string-basic-unknown-escape.toml new file mode 100644 index 0000000..381dd85 --- /dev/null +++ b/tests/invalid/string-basic-unknown-escape.toml @@ -0,0 +1 @@ +a = "\@" diff --git a/tests/invalid/string-literal-control-1.toml b/tests/invalid/string-literal-control-1.toml new file mode 100644 index 0000000..337fdc4 Binary files /dev/null and b/tests/invalid/string-literal-control-1.toml differ diff --git a/tests/invalid/string-literal-control-2.toml b/tests/invalid/string-literal-control-2.toml new file mode 100644 index 0000000..a09c908 --- /dev/null +++ b/tests/invalid/string-literal-control-2.toml @@ -0,0 +1 @@ +a = 'null' diff --git a/tests/invalid/string-literal-control-3.toml b/tests/invalid/string-literal-control-3.toml new file mode 100644 index 0000000..74697de --- /dev/null +++ b/tests/invalid/string-literal-control-3.toml @@ -0,0 +1 @@ +a = 'null' diff --git a/tests/invalid/string-literal-control-4.toml b/tests/invalid/string-literal-control-4.toml new file mode 100644 index 0000000..6c11637 --- /dev/null +++ b/tests/invalid/string-literal-control-4.toml @@ -0,0 +1 @@ +a = 'null' diff --git a/tests/invalid/string-literal-multiline-control-1.toml b/tests/invalid/string-literal-multiline-control-1.toml new file mode 100644 index 0000000..8510285 Binary files /dev/null and b/tests/invalid/string-literal-multiline-control-1.toml differ diff --git a/tests/invalid/string-literal-multiline-control-2.toml b/tests/invalid/string-literal-multiline-control-2.toml new file mode 100644 index 0000000..9c02f11 --- /dev/null +++ b/tests/invalid/string-literal-multiline-control-2.toml @@ -0,0 +1 @@ +a = '''null''' diff --git a/tests/invalid/string-literal-multiline-control-3.toml b/tests/invalid/string-literal-multiline-control-3.toml new file mode 100644 index 0000000..0a96cc5 --- /dev/null +++ b/tests/invalid/string-literal-multiline-control-3.toml @@ -0,0 +1 @@ +a = '''null''' diff --git a/tests/invalid/string-literal-multiline-control-4.toml b/tests/invalid/string-literal-multiline-control-4.toml new file mode 100644 index 0000000..da40ffc --- /dev/null +++ b/tests/invalid/string-literal-multiline-control-4.toml @@ -0,0 +1 @@ +a = '''null''' diff --git a/tests/invalid/table-1.toml b/tests/invalid/table-1.toml new file mode 100644 index 0000000..560cbc8 --- /dev/null +++ b/tests/invalid/table-1.toml @@ -0,0 +1,7 @@ +# DO NOT DO THIS + +[a] +b = 1 + +[a] +c = 2 diff --git a/tests/invalid/table-2.toml b/tests/invalid/table-2.toml new file mode 100644 index 0000000..3699f7d --- /dev/null +++ b/tests/invalid/table-2.toml @@ -0,0 +1,7 @@ +# DO NOT DO THIS EITHER + +[a] +b = 1 + +[a.b] +c = 2 diff --git a/tests/valid/datetime.json b/tests/valid/datetime.json index 4cdc000..57387b6 100644 --- a/tests/valid/datetime.json +++ b/tests/valid/datetime.json @@ -1,5 +1,6 @@ { "bestdayever": {"type": "datetime", "value": "1987-07-05T17:45:00Z"}, "numoffset": {"type": "datetime", "value": "1977-06-28T12:32:00Z"}, - "milliseconds": {"type": "datetime", "value": "1977-12-21T03:32:00.555+00:00"} + "milliseconds": {"type": "datetime", "value": "1977-12-21T03:32:00.555+00:00"}, + "bestdayever_with_space": {"type": "datetime", "value": "1987-07-05T17:45:00Z"} } diff --git a/tests/valid/datetime.toml b/tests/valid/datetime.toml index ee787b7..5fa9888 100644 --- a/tests/valid/datetime.toml +++ b/tests/valid/datetime.toml @@ -1,3 +1,4 @@ bestdayever = 1987-07-05T17:45:00Z numoffset = 1977-06-28T07:32:00-05:00 milliseconds = 1977-12-21T10:32:00.555+07:00 +bestdayever_with_space = 1987-07-05 17:45:00Z diff --git a/tests/valid/dotted-keys.json b/tests/valid/dotted-keys.json new file mode 100644 index 0000000..b702537 --- /dev/null +++ b/tests/valid/dotted-keys.json @@ -0,0 +1,21 @@ +{ + "name": { + "first": {"type": "string", "value": "Tom"}, + "last": {"type": "string", "value": "Preston-Werner"} + }, + "point": { + "x": {"type": "integer", "value": "1"}, + "y": {"type": "integer", "value": "2"} + }, + "l1": { + "l2": { + "l3": { + "l4": { + "l5": { + "l6": {"type": "integer", "value": "42"} + } + } + } + } + } +} diff --git a/tests/valid/dotted-keys.toml b/tests/valid/dotted-keys.toml new file mode 100644 index 0000000..f969273 --- /dev/null +++ b/tests/valid/dotted-keys.toml @@ -0,0 +1,5 @@ +name.first = "Tom" +name.last = "Preston-Werner" +point.x = 1 +point.y = 2 +l1.l2.l3 = {l4.l5.l6 = 42} diff --git a/tests/valid/infinity-and-nan.json b/tests/valid/infinity-and-nan.json new file mode 100644 index 0000000..c79e4f8 --- /dev/null +++ b/tests/valid/infinity-and-nan.json @@ -0,0 +1,8 @@ +{ + "nan": {"type": "float", "value": "nan"}, + "nan_neg": {"type": "float", "value": "nan"}, + "nan_plus": {"type": "float", "value": "+nan"}, + "infinity": {"type": "float", "value": "inf"}, + "infinity_neg": {"type": "float", "value": "-inf"}, + "infinity_plus": {"type": "float", "value": "+inf"} +} diff --git a/tests/valid/infinity-and-nan.toml b/tests/valid/infinity-and-nan.toml new file mode 100644 index 0000000..f8386a9 --- /dev/null +++ b/tests/valid/infinity-and-nan.toml @@ -0,0 +1,7 @@ +nan = nan +nan_neg = -nan +nan_plus = +nan +infinity = inf +infinity_neg = -inf +infinity_plus = +inf + diff --git a/tests/valid/local-date.json b/tests/valid/local-date.json new file mode 100644 index 0000000..655607c --- /dev/null +++ b/tests/valid/local-date.json @@ -0,0 +1,3 @@ +{ + "bestdayever": {"type": "date", "value": "1987-07-05"} +} diff --git a/tests/valid/local-date.toml b/tests/valid/local-date.toml new file mode 100644 index 0000000..1be4a5f --- /dev/null +++ b/tests/valid/local-date.toml @@ -0,0 +1 @@ +bestdayever = 1987-07-05 diff --git a/tests/valid/local-datetime.json b/tests/valid/local-datetime.json new file mode 100644 index 0000000..4636a9d --- /dev/null +++ b/tests/valid/local-datetime.json @@ -0,0 +1,5 @@ +{ + "bestdayever": {"type": "datetime-local", "value": "1987-07-05T17:45:00"}, + "milliseconds": {"type": "datetime-local", "value": "1977-12-21T10:32:00.555"}, + "bestdayever_with_space": {"type": "datetime-local", "value": "1987-07-05T17:45:00"} +} diff --git a/tests/valid/local-datetime.toml b/tests/valid/local-datetime.toml new file mode 100644 index 0000000..cb62ef3 --- /dev/null +++ b/tests/valid/local-datetime.toml @@ -0,0 +1,3 @@ +bestdayever = 1987-07-05T17:45:00 +milliseconds = 1977-12-21T10:32:00.555 +bestdayever_with_space = 1987-07-05 17:45:00 diff --git a/tests/valid/local-time.json b/tests/valid/local-time.json new file mode 100644 index 0000000..8a7cc85 --- /dev/null +++ b/tests/valid/local-time.json @@ -0,0 +1,4 @@ +{ + "besttimeever": {"type": "time", "value": "17:45:00"}, + "milliseconds": {"type": "time", "value": "10:32:00.555"} +} diff --git a/tests/valid/local-time.toml b/tests/valid/local-time.toml new file mode 100644 index 0000000..01a56a5 --- /dev/null +++ b/tests/valid/local-time.toml @@ -0,0 +1,3 @@ +besttimeever = 17:45:00 +milliseconds = 10:32:00.555 + diff --git a/tests/valid/multiline-string-accidental-whitespace.json b/tests/valid/multiline-string-accidental-whitespace.json new file mode 100644 index 0000000..3bc5199 --- /dev/null +++ b/tests/valid/multiline-string-accidental-whitespace.json @@ -0,0 +1,6 @@ +{ + "three_lines": { + "type": "string", + "value": "The quick brown fox jumps over the lazy dog." + } +} diff --git a/tests/valid/multiline-string-accidental-whitespace.toml b/tests/valid/multiline-string-accidental-whitespace.toml new file mode 100644 index 0000000..88c0452 --- /dev/null +++ b/tests/valid/multiline-string-accidental-whitespace.toml @@ -0,0 +1,5 @@ +three_lines = """\ + The quick brown \ + fox jumps over \ + the lazy dog.\ + """ diff --git a/tests/valid/non-dec-integers.json b/tests/valid/non-dec-integers.json new file mode 100644 index 0000000..5b38001 --- /dev/null +++ b/tests/valid/non-dec-integers.json @@ -0,0 +1,8 @@ +{ + "bin1": {"type": "integer", "value": "214"}, + "oct1": {"type": "integer", "value": "342391"}, + "oct2": {"type": "integer", "value": "493"}, + "hex1": {"type": "integer", "value": "3735928559"}, + "hex2": {"type": "integer", "value": "3735928559" }, + "hex3": {"type": "integer", "value": "3735928559"} +} diff --git a/tests/valid/non-dec-integers.toml b/tests/valid/non-dec-integers.toml new file mode 100644 index 0000000..6929c43 --- /dev/null +++ b/tests/valid/non-dec-integers.toml @@ -0,0 +1,6 @@ +bin1 = 0b11010110 +oct1 = 0o01234567 +oct2 = 0o755 +hex1 = 0xDEADBEEF +hex2 = 0xdeadbeef +hex3 = 0xdead_beef