Skip to content

Commit 663e319

Browse files
Rename encode_datetime_as to parse_datetime_as, add some unit tests, fix seconds missing in datetime tables (#16)
## Changes - renamed `encode_datetime_as` to `parse_datetime_as`. I feel like it makes more sense in the parser - Added some unit tests around datetime parsing and max_nesting_depth - fix bug with seconds not showing up in datetimes when parsed as tables
1 parent e72f5c4 commit 663e319

5 files changed

Lines changed: 125 additions & 24 deletions

File tree

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ There are a few parsing options available that are passed in the the `options` p
7272
tinytoml.parse("a=2024-10-31T12:49:00Z", {load_from_string=true, type_conversion=type_conversion})
7373
```
7474

75-
- `encode_datetime_as` (default `string`)
75+
- `parse_datetime_as` (default `string`)
7676

7777
Allows encoding datetime either as a `string` or a `table`. The `table` will take all the individual fields and place them in a table.
7878
This can be used in conjunction with `type_conversion` - either the string or table representation would be passed into whatever function is
@@ -88,14 +88,15 @@ There are a few parsing options available that are passed in the the `options` p
8888
```
8989

9090
```lua
91-
-- with the option: { encode_datetime_as = "string" }
91+
-- with the option: { parse_datetime_as = "string" }
9292
{
9393
offset_datetime = "1979-05-27T07:32:00Z",
9494
local_datetime = "1979-05-27T07:32:00",
9595
local_time = "07:32:00",
9696
local_date = "1979-05-27"
9797
}
98-
-- with the option: { encode_datetime_as = "table" }
98+
99+
-- with the option: { parse_datetime_as = "table" }
99100
{
100101
offset_datetime = {year = 1979, month = 05, day = 27, hour = 7, min = 32, sec = 0, msec = 0, time_offset = "00:00"},
101102
local_datetime = {year = 1979, month = 05, day = 27, hour = 7, min = 32, sec = 0, msec = 0},

tests/date_testing.tl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
local tested = require("tested")
2+
local tinytoml = require("tinytoml")
3+
4+
tested.test("encode date as string", function()
5+
6+
local date_toml = [[offset_datetime = 1979-05-27T07:32:00Z
7+
local_datetime = 1979-05-27T07:32:00
8+
local_time = 07:32:00
9+
local_date = 1979-05-27]]
10+
11+
local expected = {
12+
offset_datetime = "1979-05-27T07:32:00Z",
13+
local_datetime = "1979-05-27T07:32:00",
14+
local_time = "07:32:00",
15+
local_date = "1979-05-27"
16+
}
17+
18+
local parsed_dates = tinytoml.parse(date_toml, {load_from_string=true, parse_datetime_as="string"})
19+
20+
tested.assert({given="toml with dates", should="parse dates as strings", expected=expected, actual=parsed_dates})
21+
22+
end)
23+
24+
tested.test("encode date as table", function()
25+
26+
local date_toml = [[offset_datetime = 1979-05-27T07:32:00Z
27+
local_datetime = 1979-05-27T07:32:00
28+
local_time = 07:32:00
29+
local_date = 1979-05-27]]
30+
31+
local expected = {
32+
offset_datetime = {year = 1979, month = 05, day = 27, hour = 7, min = 32, sec = 0, msec = 0, time_offset = "00:00"},
33+
local_datetime = {year = 1979, month = 05, day = 27, hour = 7, min = 32, sec = 0, msec = 0},
34+
local_time = {hour = 7, min = 32, sec = 0, msec = 0},
35+
local_date = {year = 1979, month = 05, day = 27}
36+
}
37+
38+
local parsed_dates = tinytoml.parse(date_toml, {load_from_string=true, parse_datetime_as="table"})
39+
40+
tested.assert({given="toml with dates", should="parse dates as tables", expected=expected, actual=parsed_dates})
41+
42+
end)
43+
44+
return tested

tests/max_nesting_depth.tl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
local tinytoml = require("tinytoml")
2+
local tested = require("tested")
3+
4+
tested.test("max nesting depth", function()
5+
local crazy_toml = {"e="}
6+
for i = 1, 2000 do
7+
table.insert(crazy_toml, "{e=")
8+
end
9+
10+
table.insert(crazy_toml, "{}")
11+
for i = 1, 2000 do
12+
table.insert(crazy_toml, "}")
13+
end
14+
15+
local ok, err = pcall(tinytoml.parse, table.concat(crazy_toml), {load_from_string=true})
16+
17+
tested.assert({given="too much nesting", should="raies an error", expected=false, actual=ok})
18+
tested.assert({given="too much nesting", should="error includes max_nesting_depth", expected=true, actual=err:find("'max_nesting_depth'") ~= nil})
19+
20+
end)
21+
22+
tested.test("at max nesting depth", function()
23+
local crazy_toml = {"e="}
24+
for i = 1, 998 do
25+
table.insert(crazy_toml, "{e=")
26+
end
27+
28+
table.insert(crazy_toml, "{}")
29+
for i = 1, 998 do
30+
table.insert(crazy_toml, "}")
31+
end
32+
33+
local ok, err = pcall(tinytoml.parse, table.concat(crazy_toml), {load_from_string=true})
34+
35+
tested.assert({given="edge of nesting", should="does not raise an error", expected=true, actual=ok})
36+
end)
37+
38+
tested.test("slightly above max nesting depth", function()
39+
local crazy_toml = {"e="}
40+
for i = 1, 1500 do
41+
table.insert(crazy_toml, "{e=")
42+
end
43+
44+
table.insert(crazy_toml, "{}")
45+
for i = 1, 1500 do
46+
table.insert(crazy_toml, "}")
47+
end
48+
49+
local ok, err = pcall(tinytoml.parse, table.concat(crazy_toml), {load_from_string=true, max_nesting_depth=2000})
50+
51+
tested.assert({given="edge of nesting", should="does not raise an error", expected=true, actual=ok})
52+
end)
53+
54+
return tested

tinytoml.lua

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ end
633633

634634
local function assign_time_local(sm, match, hour, min, sec, msec)
635635
sm.value_type = "time-local"
636-
if sm.options.encode_datetime_as == "string" then
636+
if sm.options.parse_datetime_as == "string" then
637637
sm.value = sm.options.type_conversion[sm.value_type](match)
638638
else
639639
sm.value = sm.options.type_conversion[sm.value_type]({ hour = hour, min = min, sec = sec, msec = msec })
@@ -642,7 +642,7 @@ end
642642

643643
local function assign_date_local(sm, match, year, month, day)
644644
sm.value_type = "date-local"
645-
if sm.options.encode_datetime_as == "string" then
645+
if sm.options.parse_datetime_as == "string" then
646646
sm.value = sm.options.type_conversion[sm.value_type](match)
647647
else
648648
sm.value = sm.options.type_conversion[sm.value_type]({ year = year, month = month, day = day })
@@ -651,7 +651,7 @@ end
651651

652652
local function assign_datetime_local(sm, match, year, month, day, hour, min, sec, msec)
653653
sm.value_type = "datetime-local"
654-
if sm.options.encode_datetime_as == "string" then
654+
if sm.options.parse_datetime_as == "string" then
655655
sm.value = sm.options.type_conversion[sm.value_type](match)
656656
else
657657
sm.value = sm.options.type_conversion[sm.value_type]({ year = year, month = month, day = day, hour = hour, min = min, sec = sec, msec = msec or 0 })
@@ -665,7 +665,7 @@ local function assign_datetime(sm, match, year, month, day, hour, min, sec, msec
665665
validate_hours_minutes(sm, _tointeger(hour_s), _tointeger(min_s), "offset-date-time")
666666
end
667667
sm.value_type = "datetime"
668-
if sm.options.encode_datetime_as == "string" then
668+
if sm.options.parse_datetime_as == "string" then
669669
sm.value = sm.options.type_conversion[sm.value_type](match)
670670
else
671671
sm.value = sm.options.type_conversion[sm.value_type]({ year = year, month = month, day = day, hour = hour, min = min, sec = sec, msec = msec or 0, time_offset = tz or "00:00" })
@@ -739,7 +739,8 @@ local function validate_datetime(sm, value)
739739
local temp_ext
740740
sm._, sm._, sec_s, temp_ext = sm.ext:find("^:(%d%d)(.*)$")
741741
if sec_s then
742-
validate_seconds(sm, _tointeger(sec_s), "local-time")
742+
sec = _tointeger(sec_s)
743+
validate_seconds(sm, sec, "local-time")
743744
sm.match = sm.match .. ":" .. sec_s
744745
sm.ext = temp_ext
745746
else
@@ -1162,7 +1163,7 @@ function tinytoml.parse(filename, options)
11621163
max_nesting_depth = 1000,
11631164
max_filesize = 100000000,
11641165
load_from_string = false,
1165-
encode_datetime_as = "string",
1166+
parse_datetime_as = "string",
11661167
type_conversion = {
11671168
["datetime"] = generic_type_conversion,
11681169
["datetime-local"] = generic_type_conversion,
@@ -1185,8 +1186,8 @@ function tinytoml.parse(filename, options)
11851186
assert(type(options.load_from_string) == "boolean", "the tinytoml option 'load_from_string' takes in a 'function'. You passed in the value '" .. tostring(options.load_from_string) .. "' of type '" .. type(options.load_from_string) .. "'")
11861187
end
11871188

1188-
if options.encode_datetime_as ~= nil then
1189-
assert(type(options.encode_datetime_as) == "string", "the tinytoml option 'encode_datetime_as' takes in either the 'string' or 'table' (as type 'string'). You passed in the value '" .. tostring(options.encode_datetime_as) .. "' of type '" .. type(options.encode_datetime_as) .. "'")
1189+
if options.parse_datetime_as ~= nil then
1190+
assert(type(options.parse_datetime_as) == "string", "the tinytoml option 'parse_datetime_as' takes in either the 'string' or 'table' (as type 'string'). You passed in the value '" .. tostring(options.parse_datetime_as) .. "' of type '" .. type(options.parse_datetime_as) .. "'")
11901191
end
11911192

11921193
if options.type_conversion ~= nil then
@@ -1204,7 +1205,7 @@ function tinytoml.parse(filename, options)
12041205
options.max_nesting_depth = options.max_nesting_depth or default_options.max_nesting_depth
12051206
options.max_filesize = options.max_filesize or default_options.max_filesize
12061207
options.load_from_string = options.load_from_string or default_options.load_from_string
1207-
options.encode_datetime_as = options.encode_datetime_as or default_options.encode_datetime_as
1208+
options.parse_datetime_as = options.parse_datetime_as or default_options.parse_datetime_as
12081209
options.type_conversion = options.type_conversion or default_options.type_conversion
12091210

12101211

@@ -1351,7 +1352,7 @@ local function escape_string(str, multiline, is_key)
13511352
["date-local"] = generic_type_conversion,
13521353
["time-local"] = generic_type_conversion,
13531354
}
1354-
sm.options.encode_datetime_as = "string"
1355+
sm.options.parse_datetime_as = "string"
13551356

13561357

13571358
sm._, sm.end_seq, sm.match = sm.input:find("^([^ #\r\n,%[{%]}]+)", sm.i)

tinytoml.tl

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ end
1313
local record TinyTomlOptions
1414
load_from_string: boolean
1515
type_conversion: {TomlConversionType:function<T>(raw_value: string | table):T}
16-
encode_datetime_as: DateTimeEncode
16+
parse_datetime_as: DateTimeEncode
1717
max_filesize: integer
1818
max_nesting_depth: integer
1919
end
@@ -633,7 +633,7 @@ end
633633

634634
local function assign_time_local(sm: StateMachine, match: string, hour: integer, min: integer, sec: integer, msec: integer)
635635
sm.value_type = "time-local"
636-
if sm.options.encode_datetime_as == "string" then
636+
if sm.options.parse_datetime_as == "string" then
637637
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType](match)
638638
else
639639
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType]({hour=hour, min=min, sec=sec, msec=msec})
@@ -642,7 +642,7 @@ end
642642

643643
local function assign_date_local(sm: StateMachine, match: string, year: integer, month: integer, day: integer)
644644
sm.value_type = "date-local"
645-
if sm.options.encode_datetime_as == "string" then
645+
if sm.options.parse_datetime_as == "string" then
646646
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType](match)
647647
else
648648
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType]({year=year, month=month, day=day})
@@ -651,7 +651,7 @@ end
651651

652652
local function assign_datetime_local(sm: StateMachine, match: string, year: integer, month: integer, day: integer, hour: integer, min: integer, sec: integer, msec?: integer)
653653
sm.value_type = "datetime-local"
654-
if sm.options.encode_datetime_as == "string" then
654+
if sm.options.parse_datetime_as == "string" then
655655
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType](match)
656656
else
657657
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType]({year=year, month=month, day=day, hour=hour, min=min, sec=sec, msec=msec or 0})
@@ -665,7 +665,7 @@ local function assign_datetime(sm: StateMachine, match: string, year: integer, m
665665
validate_hours_minutes(sm, _tointeger(hour_s), _tointeger(min_s), "offset-date-time")
666666
end
667667
sm.value_type = "datetime"
668-
if sm.options.encode_datetime_as == "string" then
668+
if sm.options.parse_datetime_as == "string" then
669669
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType](match)
670670
else
671671
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType]({year=year, month=month, day=day, hour=hour, min=min, sec=sec, msec=msec or 0, time_offset=tz or "00:00"})
@@ -739,7 +739,8 @@ local function validate_datetime(sm: StateMachine, value: string): boolean
739739
local temp_ext: string
740740
sm._, sm._, sec_s, temp_ext = sm.ext:find("^:(%d%d)(.*)$") as (integer, integer, string, string)
741741
if sec_s then
742-
validate_seconds(sm, _tointeger(sec_s), "local-time")
742+
sec = _tointeger(sec_s)
743+
validate_seconds(sm, sec, "local-time")
743744
sm.match = sm.match .. ":" .. sec_s
744745
sm.ext = temp_ext
745746
else
@@ -1162,7 +1163,7 @@ function tinytoml.parse(filename: string, options?: TinyTomlOptions): {string:an
11621163
max_nesting_depth = 1000,
11631164
max_filesize = 100000000,
11641165
load_from_string = false,
1165-
encode_datetime_as = "string",
1166+
parse_datetime_as = "string",
11661167
type_conversion = {
11671168
["datetime"] = generic_type_conversion,
11681169
["datetime-local"] = generic_type_conversion,
@@ -1185,8 +1186,8 @@ function tinytoml.parse(filename: string, options?: TinyTomlOptions): {string:an
11851186
assert(type(options.load_from_string) == "boolean", "the tinytoml option 'load_from_string' takes in a 'function'. You passed in the value '" .. tostring(options.load_from_string) .. "' of type '" .. type(options.load_from_string) .. "'")
11861187
end
11871188

1188-
if options.encode_datetime_as ~= nil then
1189-
assert(type(options.encode_datetime_as) == "string", "the tinytoml option 'encode_datetime_as' takes in either the 'string' or 'table' (as type 'string'). You passed in the value '" .. tostring(options.encode_datetime_as) .. "' of type '" .. type(options.encode_datetime_as) .. "'")
1189+
if options.parse_datetime_as ~= nil then
1190+
assert(type(options.parse_datetime_as) == "string", "the tinytoml option 'parse_datetime_as' takes in either the 'string' or 'table' (as type 'string'). You passed in the value '" .. tostring(options.parse_datetime_as) .. "' of type '" .. type(options.parse_datetime_as) .. "'")
11901191
end
11911192

11921193
if options.type_conversion ~= nil then
@@ -1204,7 +1205,7 @@ function tinytoml.parse(filename: string, options?: TinyTomlOptions): {string:an
12041205
options.max_nesting_depth = options.max_nesting_depth or default_options.max_nesting_depth
12051206
options.max_filesize = options.max_filesize or default_options.max_filesize
12061207
options.load_from_string = options.load_from_string or default_options.load_from_string
1207-
options.encode_datetime_as = options.encode_datetime_as or default_options.encode_datetime_as
1208+
options.parse_datetime_as = options.parse_datetime_as or default_options.parse_datetime_as
12081209
options.type_conversion = options.type_conversion or default_options.type_conversion
12091210

12101211
-- verify/setup the last couple of things
@@ -1351,7 +1352,7 @@ local function escape_string(str: string, multiline: boolean, is_key: boolean):
13511352
["date-local"] = generic_type_conversion,
13521353
["time-local"] = generic_type_conversion
13531354
}
1354-
sm.options.encode_datetime_as = "string"
1355+
sm.options.parse_datetime_as = "string"
13551356

13561357
-- performing the same setup as in close_other_value, should set values correctly to run validate_datetime
13571358
sm._, sm.end_seq, sm.match = sm.input:find("^([^ #\r\n,%[{%]}]+)", sm.i)

0 commit comments

Comments
 (0)