diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..39d488b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +* text=auto + +benchmark/benchmark.toml text eol=lf diff --git a/benchmark/benchmark.toml b/benchmark/benchmark.toml index dfd77e0..ec11975 100644 --- a/benchmark/benchmark.toml +++ b/benchmark/benchmark.toml @@ -186,7 +186,7 @@ key3 = 1979-05-27T00:32:00.999999-07:00 key1 = [ 1, 2, 3 ] key2 = [ "red", "yellow", "green" ] key3 = [ [ 1, 2 ], [3, 4, 5] ] -#key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok +key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok # Arrays can also be multiline. So in addition to ignoring whitespace, arrays # also ignore newlines between the brackets. Terminating commas are ok before diff --git a/benchmark/benchmark_test.go b/benchmark/benchmark_test.go index 1337895..da56f06 100644 --- a/benchmark/benchmark_test.go +++ b/benchmark/benchmark_test.go @@ -57,7 +57,7 @@ type benchmarkDoc struct { } Point struct { X int64 - U int64 + Y int64 } } } @@ -130,6 +130,7 @@ type benchmarkDoc struct { Key2 []string Key3 [][]int64 // TODO: Key4 not supported by go-toml's Unmarshal + Key4 []interface{} Key5 []int64 Key6 []int64 } @@ -141,11 +142,11 @@ type benchmarkDoc struct { Fruit []struct { Name string Physical struct { - Color string - Shape string - Variety []struct { - Name string - } + Color string + Shape string + } + Variety []struct { + Name string } } } @@ -189,6 +190,285 @@ func TestReferenceFile(t *testing.T) { d := benchmarkDoc{} err = toml.Unmarshal(bytes, &d) require.NoError(t, err) + + expected := benchmarkDoc{ + Table: struct { + Key string + Subtable struct{ Key string } + Inline struct { + Name struct { + First string + Last string + } + Point struct { + X int64 + Y int64 + } + } + }{ + Key: "value", + Subtable: struct{ Key string }{ + Key: "another value", + }, + // note: x.y.z.w is purposefully missing + Inline: struct { + Name struct { + First string + Last string + } + Point struct { + X int64 + Y int64 + } + }{ + Name: struct { + First string + Last string + }{ + First: "Tom", + Last: "Preston-Werner", + }, + Point: struct { + X int64 + Y int64 + }{ + X: 1, + Y: 2, + }, + }, + }, + String: struct { + Basic struct{ Basic string } + Multiline struct { + Key1 string + Key2 string + Key3 string + Continued struct { + Key1 string + Key2 string + Key3 string + } + } + Literal struct { + Winpath string + Winpath2 string + Quoted string + Regex string + Multiline struct { + Regex2 string + Lines string + } + } + }{ + Basic: struct{ Basic string }{ + Basic: "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.", + }, + Multiline: struct { + Key1 string + Key2 string + Key3 string + Continued struct { + Key1 string + Key2 string + Key3 string + } + }{ + Key1: "One\nTwo", + Key2: "One\nTwo", + Key3: "One\nTwo", + + Continued: struct { + Key1 string + Key2 string + Key3 string + }{ + Key1: `The quick brown fox jumps over the lazy dog.`, + Key2: `The quick brown fox jumps over the lazy dog.`, + Key3: `The quick brown fox jumps over the lazy dog.`, + }, + }, + Literal: struct { + Winpath string + Winpath2 string + Quoted string + Regex string + Multiline struct { + Regex2 string + Lines string + } + }{ + Winpath: `C:\Users\nodejs\templates`, + Winpath2: `\\ServerX\admin$\system32\`, + Quoted: `Tom "Dubs" Preston-Werner`, + Regex: `<\i\c*\s*>`, + + Multiline: struct { + Regex2 string + Lines string + }{ + Regex2: `I [dw]on't need \d{2} apples`, + Lines: `The first newline is +trimmed in raw strings. + All other whitespace + is preserved. +`, + }, + }, + }, + Integer: struct { + Key1 int64 + Key2 int64 + Key3 int64 + Key4 int64 + Underscores struct { + Key1 int64 + Key2 int64 + Key3 int64 + } + }{ + Key1: 99, + Key2: 42, + Key3: 0, + Key4: -17, + + Underscores: struct { + Key1 int64 + Key2 int64 + Key3 int64 + }{ + Key1: 1000, + Key2: 5349221, + Key3: 12345, + }, + }, + Float: struct { + Fractional struct { + Key1 float64 + Key2 float64 + Key3 float64 + } + Exponent struct { + Key1 float64 + Key2 float64 + Key3 float64 + } + Both struct{ Key float64 } + Underscores struct { + Key1 float64 + Key2 float64 + } + }{ + Fractional: struct { + Key1 float64 + Key2 float64 + Key3 float64 + }{ + Key1: 1.0, + Key2: 3.1415, + Key3: -0.01, + }, + Exponent: struct { + Key1 float64 + Key2 float64 + Key3 float64 + }{ + Key1: 5e+22, + Key2: 1e6, + Key3: -2e-2, + }, + Both: struct{ Key float64 }{ + Key: 6.626e-34, + }, + Underscores: struct { + Key1 float64 + Key2 float64 + }{ + Key1: 9224617.445991228313, + Key2: 1e100, + }, + }, + Boolean: struct { + True bool + False bool + }{ + True: true, + False: false, + }, + Datetime: struct { + Key1 time.Time + Key2 time.Time + Key3 time.Time + }{ + Key1: time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC), + Key2: time.Date(1979, 5, 27, 0, 32, 0, 0, time.FixedZone("", -7*3600)), + Key3: time.Date(1979, 5, 27, 0, 32, 0, 999999000, time.FixedZone("", -7*3600)), + }, + Array: struct { + Key1 []int64 + Key2 []string + Key3 [][]int64 + Key4 []interface{} + Key5 []int64 + Key6 []int64 + }{ + Key1: []int64{1, 2, 3}, + Key2: []string{"red", "yellow", "green"}, + Key3: [][]int64{{1, 2}, {3, 4, 5}}, + Key4: []interface{}{ + []interface{}{int64(1), int64(2)}, + []interface{}{"a", "b", "c"}, + }, + Key5: []int64{1, 2, 3}, + Key6: []int64{1, 2}, + }, + Products: []struct { + Name string + Sku int64 + Color string + }{ + { + Name: "Hammer", + Sku: 738594937, + }, + {}, + { + Name: "Nail", + Sku: 284758393, + Color: "gray", + }, + }, + Fruit: []struct { + Name string + Physical struct { + Color string + Shape string + } + Variety []struct{ Name string } + }{ + { + Name: "apple", + Physical: struct { + Color string + Shape string + }{ + Color: "red", + Shape: "round", + }, + Variety: []struct{ Name string }{ + {Name: "red delicious"}, + {Name: "granny smith"}, + }, + }, + { + Name: "banana", + Variety: []struct{ Name string }{ + {Name: "plantain"}, + }, + }, + }, + } + + require.Equal(t, expected, d) } func BenchmarkHugoFrontMatter(b *testing.B) { diff --git a/go.mod b/go.mod index 6745f0a..8fed342 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,5 @@ module github.com/pelletier/go-toml/v2 go 1.15 -require github.com/stretchr/testify v1.7.0 +// latest (v1.7.0) doesn't have the fix for time.Time +require github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942 diff --git a/go.sum b/go.sum index acb88a4..6fe6dfa 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942 h1:t0lM6y/M5IiUZyvbBTcngso8SZEZICH7is9B6g/obVU= +github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/unmarshaler.go b/unmarshaler.go index 6a156ae..fda9438 100644 --- a/unmarshaler.go +++ b/unmarshaler.go @@ -198,6 +198,7 @@ func (d *decoder) fromParser(p *parser, v interface{}) error { err = d.unmarshalKeyValue(current, node) found = true case ast.Table: + skipUntilTable = false d.strict.EnterTable(node) current, found, err = d.scopeWithKey(root, node.Key()) @@ -210,6 +211,7 @@ func (d *decoder) fromParser(p *parser, v interface{}) error { ensureMapIfInterface(current) } case ast.ArrayTable: + skipUntilTable = false d.strict.EnterArrayTable(node) current, found, err = d.scopeWithArrayTable(root, node.Key()) default: