Compare commits

...

12 Commits

Author SHA1 Message Date
Thomas Pelletier ee07c9203b Update to go 1.24 (#982) 2025-04-07 07:11:38 -04:00
Alex Mikitik 014204cfb7 Replace stretchr/testify with an internal test suite (#981)
As recommended, an `internal/assert` package was added with a reduced set of assertions. All tests were then refactored to use the internal assertions. When more complex assertions were used, they have been rewritten using logic and the simplified assertions.

Fancy formatting for failures was omitted. The `internal/assert/assertions.diff` function could be overwritten for better formatting. That is where diff libraries are used in other test suites.

Refs: #872

Co-authored-by: Alex Mikitik <alex.mikitik@oracle.com>
2025-04-07 06:36:37 -04:00
Oleksandr Redko 923b2ab478 Fix typos in comments and tests (#972) 2024-11-16 11:30:13 -05:00
Thomas Pelletier af236b689f Fix goreleaser deprecated attribute name (#964)
https://goreleaser.com/deprecations/#snapshotname_template
2024-08-23 13:56:48 -04:00
Thomas Pelletier b730b2be5d Bump testing to go 1.23 (#961) 2024-08-17 16:26:05 -04:00
vito a437caafe5 Fix reflect.Pointer backward compatibility (#956) 2024-08-17 16:07:56 -04:00
guoguangwu be6c57be30 Fix readme typo(#951) 2024-08-17 15:56:40 -04:00
Daniel Weiße d55304782e Allow int, uint, and floats as map keys (#958)
Signed-off-by: Daniel Weiße <dw@edgeless.systems>
2024-08-17 15:44:21 -04:00
Daniel Weiße 0977c05dd5 Update goreleaser action to v6 and set goreleaser binary to v2 (#959)
Signed-off-by: Daniel Weiße <dw@edgeless.systems>
2024-08-17 15:40:55 -04:00
Daniel Martí bccd6e48f4 allocate unstable.Parser as part of decoder (#953)
This way, calls to Unmarshal or Decoder.Decode allocate once
at the start rather than twice.

                                │    old     │               new                │
                                │ allocs/op  │ allocs/op   vs base              │
    Unmarshal/HugoFrontMatter-8   141.0 ± 0%   140.0 ± 0%  -0.71% (p=0.002 n=6)
2024-05-24 14:49:06 -04:00
Daniel Martí 9b890cf9c5 go.mod: bump minimum and language to 1.21 (#949)
* go.mod: bump minimum and language to 1.21

CI only tests Go 1.21 and 1.22, and older versions of Go are no longer
getting any bug or security fixes, so advertise that we only support
Go 1.21 or later via go.mod.

While here, ensure the module is tidy and resolve deprecation warnings,
and remove now-unnecessary Go version build tags.

* replace sort.Slice with slices.SortFunc

The latter is more efficient, and allocates less, since sort.Slice
needs to go through sort.Interface which causes allocations.

    goos: linux
    goarch: amd64
    pkg: github.com/pelletier/go-toml/v2/benchmark
    cpu: AMD Ryzen 7 PRO 5850U with Radeon Graphics
                              │     old     │                new                 │
                              │   sec/op    │   sec/op     vs base               │
    Marshal/HugoFrontMatter-8   7.612µ ± 1%   6.730µ ± 1%  -11.59% (p=0.002 n=6)

                              │     old      │                 new                 │
                              │     B/s      │     B/s       vs base               │
    Marshal/HugoFrontMatter-8   65.52Mi ± 1%   74.11Mi ± 1%  +13.11% (p=0.002 n=6)

                              │     old      │                new                 │
                              │     B/op     │     B/op      vs base              │
    Marshal/HugoFrontMatter-8   5.672Ki ± 0%   5.266Ki ± 0%  -7.16% (p=0.002 n=6)

                              │    old     │                new                │
                              │ allocs/op  │ allocs/op   vs base               │
    Marshal/HugoFrontMatter-8   85.00 ± 0%   73.00 ± 0%  -14.12% (p=0.002 n=6)
2024-05-24 10:58:39 -04:00
大可 a3d5a0bb53 fix: sync pool race condition (#947) 2024-04-29 06:02:54 -04:00
33 changed files with 970 additions and 427 deletions
+1 -1
View File
@@ -15,6 +15,6 @@ jobs:
- name: Setup go
uses: actions/setup-go@v5
with:
go-version: "1.22"
go-version: "1.24"
- name: Run tests with coverage
run: ./ci.sh coverage -d "${GITHUB_BASE_REF-HEAD}"
+4 -4
View File
@@ -22,7 +22,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.22"
go-version: "1.24"
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
@@ -30,10 +30,10 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: latest
args: release ${{ inputs.args }} --rm-dist
version: '~> v2'
args: release ${{ inputs.args }} --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+2 -2
View File
@@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
os: [ 'ubuntu-latest', 'windows-latest', 'macos-latest', 'macos-14' ]
go: [ '1.21', '1.22' ]
go: [ '1.23', '1.24' ]
runs-on: ${{ matrix.os }}
name: ${{ matrix.go }}/${{ matrix.os }}
steps:
@@ -27,6 +27,6 @@ jobs:
run: go test -race ./...
release-check:
if: ${{ github.ref != 'refs/heads/v2' }}
uses: pelletier/go-toml/.github/workflows/release.yml@v2
uses: ./.github/workflows/release.yml
with:
args: --snapshot
+2 -1
View File
@@ -1,3 +1,4 @@
version: 2
before:
hooks:
- go mod tidy
@@ -112,7 +113,7 @@ dockers:
checksum:
name_template: 'sha256sums.txt'
snapshot:
name_template: "{{ incpatch .Version }}-next"
version_template: "{{ incpatch .Version }}-next"
release:
github:
owner: pelletier
+1 -1
View File
@@ -565,7 +565,7 @@ complete solutions exist out there.
## Versioning
Expect for parts explicitely marked otherwise, go-toml follows [Semantic
Expect for parts explicitly marked otherwise, go-toml follows [Semantic
Versioning](https://semver.org). The supported version of
[TOML](https://github.com/toml-lang/toml) is indicated at the beginning of this
document. The last two major versions of Go are supported (see [Go Release
+8 -8
View File
@@ -9,7 +9,7 @@ import (
"testing"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
var bench_inputs = []struct {
@@ -35,11 +35,11 @@ func TestUnmarshalDatasetCode(t *testing.T) {
buf := fixture(t, tc.name)
var v interface{}
require.NoError(t, toml.Unmarshal(buf, &v))
assert.NoError(t, toml.Unmarshal(buf, &v))
b, err := json.Marshal(v)
require.NoError(t, err)
require.Equal(t, len(b), tc.jsonLen)
assert.NoError(t, err)
assert.Equal(t, len(b), tc.jsonLen)
})
}
}
@@ -53,7 +53,7 @@ func BenchmarkUnmarshalDataset(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var v interface{}
require.NoError(b, toml.Unmarshal(buf, &v))
assert.NoError(b, toml.Unmarshal(buf, &v))
}
})
}
@@ -68,13 +68,13 @@ func fixture(tb testing.TB, path string) []byte {
if os.IsNotExist(err) {
tb.Skip("benchmark fixture not found:", file)
}
require.NoError(tb, err)
assert.NoError(tb, err)
defer f.Close()
gz, err := gzip.NewReader(f)
require.NoError(tb, err)
assert.NoError(tb, err)
buf, err := ioutil.ReadAll(gz)
require.NoError(tb, err)
assert.NoError(tb, err)
return buf
}
+4 -4
View File
@@ -7,7 +7,7 @@ import (
"time"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
func TestUnmarshalSimple(t *testing.T) {
@@ -345,10 +345,10 @@ type benchmarkDoc struct {
func TestUnmarshalReferenceFile(t *testing.T) {
bytes, err := ioutil.ReadFile("benchmark.toml")
require.NoError(t, err)
assert.NoError(t, err)
d := benchmarkDoc{}
err = toml.Unmarshal(bytes, &d)
require.NoError(t, err)
assert.NoError(t, err)
expected := benchmarkDoc{
Table: struct {
@@ -627,7 +627,7 @@ trimmed in raw strings.
},
}
require.Equal(t, expected, d)
assert.Equal(t, expected, d)
}
var hugoFrontMatterbytes = []byte(`
+2 -3
View File
@@ -5,8 +5,7 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
func TestConvert(t *testing.T) {
@@ -54,7 +53,7 @@ a = 42
useJsonNumber = e.useJsonNumber
err := convert(strings.NewReader(e.input), b)
if e.errors {
require.Error(t, err)
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, e.expected, b.String())
+2 -3
View File
@@ -7,8 +7,7 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
func TestConvert(t *testing.T) {
@@ -46,7 +45,7 @@ a = 42`),
b := new(bytes.Buffer)
err := convert(e.input, b)
if e.errors {
require.Error(t, err)
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, e.expected, b.String())
+2 -3
View File
@@ -5,8 +5,7 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
func TestConvert(t *testing.T) {
@@ -36,7 +35,7 @@ a = 42.0
b := new(bytes.Buffer)
err := convert(strings.NewReader(e.input), b)
if e.errors {
require.Error(t, err)
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, e.expected, b.String())
+1 -1
View File
@@ -7,8 +7,8 @@ import (
"strings"
"testing"
"github.com/pelletier/go-toml/v2/internal/assert"
"github.com/pelletier/go-toml/v2/unstable"
"github.com/stretchr/testify/assert"
)
//nolint:funlen
+15 -15
View File
@@ -4,28 +4,28 @@ import (
"testing"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
func TestFastSimpleInt(t *testing.T) {
m := map[string]int64{}
err := toml.Unmarshal([]byte(`a = 42`), &m)
require.NoError(t, err)
require.Equal(t, map[string]int64{"a": 42}, m)
assert.NoError(t, err)
assert.Equal(t, map[string]int64{"a": 42}, m)
}
func TestFastSimpleFloat(t *testing.T) {
m := map[string]float64{}
err := toml.Unmarshal([]byte("a = 42\nb = 1.1\nc = 12341234123412341234123412341234"), &m)
require.NoError(t, err)
require.Equal(t, map[string]float64{"a": 42, "b": 1.1, "c": 1.2341234123412342e+31}, m)
assert.NoError(t, err)
assert.Equal(t, map[string]float64{"a": 42, "b": 1.1, "c": 1.2341234123412342e+31}, m)
}
func TestFastSimpleString(t *testing.T) {
m := map[string]string{}
err := toml.Unmarshal([]byte(`a = "hello"`), &m)
require.NoError(t, err)
require.Equal(t, map[string]string{"a": "hello"}, m)
assert.NoError(t, err)
assert.Equal(t, map[string]string{"a": "hello"}, m)
}
func TestFastSimpleInterface(t *testing.T) {
@@ -33,8 +33,8 @@ func TestFastSimpleInterface(t *testing.T) {
err := toml.Unmarshal([]byte(`
a = "hello"
b = 42`), &m)
require.NoError(t, err)
require.Equal(t, map[string]interface{}{
assert.NoError(t, err)
assert.Equal(t, map[string]interface{}{
"a": "hello",
"b": int64(42),
}, m)
@@ -46,8 +46,8 @@ func TestFastMultipartKeyInterface(t *testing.T) {
a.interim = "test"
a.b.c = "hello"
b = 42`), &m)
require.NoError(t, err)
require.Equal(t, map[string]interface{}{
assert.NoError(t, err)
assert.Equal(t, map[string]interface{}{
"a": map[string]interface{}{
"interim": "test",
"b": map[string]interface{}{
@@ -66,8 +66,8 @@ func TestFastExistingMap(t *testing.T) {
ints.one = 1
ints.two = 2
strings.yo = "hello"`), &m)
require.NoError(t, err)
require.Equal(t, map[string]interface{}{
assert.NoError(t, err)
assert.Equal(t, map[string]interface{}{
"ints": map[string]interface{}{
"one": int64(1),
"two": int64(2),
@@ -90,9 +90,9 @@ func TestFastArrayTable(t *testing.T) {
m := map[string]interface{}{}
err := toml.Unmarshal(b, &m)
require.NoError(t, err)
assert.NoError(t, err)
require.Equal(t, map[string]interface{}{
assert.Equal(t, map[string]interface{}{
"root": map[string]interface{}{
"nested": []interface{}{
map[string]interface{}{
+2 -5
View File
@@ -1,6 +1,3 @@
//go:build go1.18 || go1.19 || go1.20 || go1.21 || go1.22
// +build go1.18 go1.19 go1.20 go1.21 go1.22
package toml_test
import (
@@ -9,7 +6,7 @@ import (
"testing"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
func FuzzUnmarshal(f *testing.F) {
@@ -51,6 +48,6 @@ func FuzzUnmarshal(f *testing.F) {
if err != nil {
t.Fatalf("failed round trip: %s", err)
}
require.Equal(t, v, v2)
assert.Equal(t, v, v2)
})
}
+1 -3
View File
@@ -1,5 +1,3 @@
module github.com/pelletier/go-toml/v2
go 1.16
require github.com/stretchr/testify v1.9.0
go 1.21.0
-19
View File
@@ -1,19 +0,0 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+135
View File
@@ -0,0 +1,135 @@
package assert
import (
"bytes"
"fmt"
"reflect"
"strings"
"testing"
)
// True asserts that an expression is true.
func True(t testing.TB, ok bool, msgAndArgs ...any) {
if ok {
return
}
t.Helper()
t.Fatal(formatMsgAndArgs("Expected expression to be true", msgAndArgs...))
}
// False asserts that an expression is false.
func False(t testing.TB, ok bool, msgAndArgs ...any) {
if !ok {
return
}
t.Helper()
t.Fatal(formatMsgAndArgs("Expected expression to be false", msgAndArgs...))
}
// Equal asserts that "expected" and "actual" are equal.
func Equal[T any](t testing.TB, expected, actual T, msgAndArgs ...any) {
if objectsAreEqual(expected, actual) {
return
}
t.Helper()
msg := formatMsgAndArgs("Expected values to be equal:", msgAndArgs...)
t.Fatalf("%s\n%s", msg, diff(expected, actual))
}
// Error asserts that an error is not nil.
func Error(t testing.TB, err error, msgAndArgs ...any) {
if err != nil {
return
}
t.Helper()
t.Fatal(formatMsgAndArgs("Expected an error", msgAndArgs...))
}
// NoError asserts that an error is nil.
func NoError(t testing.TB, err error, msgAndArgs ...any) {
if err == nil {
return
}
t.Helper()
msg := formatMsgAndArgs("Unexpected error:", msgAndArgs...)
t.Fatalf("%s\n%+v", msg, err)
}
// Panics asserts that the given function panics.
func Panics(t testing.TB, fn func(), msgAndArgs ...any) {
t.Helper()
defer func() {
if recover() == nil {
msg := formatMsgAndArgs("Expected function to panic", msgAndArgs...)
t.Fatal(msg)
}
}()
fn()
}
// Zero asserts that a value is its zero value.
func Zero[T any](t testing.TB, value T, msgAndArgs ...any) {
var zero T
if objectsAreEqual(value, zero) {
return
}
val := reflect.ValueOf(value)
if (val.Kind() == reflect.Slice || val.Kind() == reflect.Map || val.Kind() == reflect.Array) && val.Len() == 0 {
return
}
t.Helper()
msg := formatMsgAndArgs("Expected zero value but got:", msgAndArgs...)
t.Fatalf("%s\n%s", msg, fmt.Sprintf("%v", value))
}
func NotZero[T any](t testing.TB, value T, msgAndArgs ...any) {
var zero T
if !objectsAreEqual(value, zero) {
val := reflect.ValueOf(value)
if !((val.Kind() == reflect.Slice || val.Kind() == reflect.Map || val.Kind() == reflect.Array) && val.Len() == 0) {
return
}
}
t.Helper()
msg := formatMsgAndArgs("Unexpected zero value:", msgAndArgs...)
t.Fatalf("%s\n%s", msg, fmt.Sprintf("%v", value))
}
func formatMsgAndArgs(msg string, args ...any) string {
if len(args) == 0 {
return msg
}
format, ok := args[0].(string)
if !ok {
panic("message argument must be a fmt string")
}
return fmt.Sprintf(format, args[1:]...)
}
func diff(expected, actual any) string {
lines := []string{
"expected:",
fmt.Sprintf("%v", expected),
"actual:",
fmt.Sprintf("%v", actual),
}
return strings.Join(lines, "\n")
}
func objectsAreEqual(expected, actual any) bool {
if expected == nil || actual == nil {
return expected == actual
}
if exp, eok := expected.([]byte); eok {
if act, aok := actual.([]byte); aok {
return bytes.Equal(exp, act)
}
}
if exp, eok := expected.(string); eok {
if act, aok := actual.(string); aok {
return exp == act
}
}
return reflect.DeepEqual(expected, actual)
}
+184
View File
@@ -0,0 +1,184 @@
package assert
import (
"fmt"
"testing"
)
type Data struct {
Label string
Value int64
}
func TestBadMessage(t *testing.T) {
invalidMessage := func() { True(t, false, 1234) }
assertOk(t, "Non-fmt message value", func(t testing.TB) {
Panics(t, invalidMessage)
})
assertFail(t, "Non-fmt message value", func(t testing.TB) {
True(t, false, "example %s", "message")
})
}
func TestTrue(t *testing.T) {
assertOk(t, "Succeed", func(t testing.TB) {
True(t, 1 > 0)
})
assertFail(t, "Fail", func(t testing.TB) {
True(t, 1 < 0)
})
}
func TestFalse(t *testing.T) {
assertOk(t, "Succeed", func(t testing.TB) {
False(t, 1 < 0)
})
assertFail(t, "Fail", func(t testing.TB) {
False(t, 1 > 0)
})
}
func TestEqual(t *testing.T) {
assertOk(t, "Nil", func(t testing.TB) {
Equal(t, interface{}(nil), interface{}(nil))
})
assertOk(t, "Identical structs", func(t testing.TB) {
Equal(t, Data{"expected", 1234}, Data{"expected", 1234})
})
assertFail(t, "Different structs", func(t testing.TB) {
Equal(t, Data{"expected", 1234}, Data{"actual", 1234})
})
assertOk(t, "Identical numbers", func(t testing.TB) {
Equal(t, 1234, 1234)
})
assertFail(t, "Identical numbers", func(t testing.TB) {
Equal(t, 1234, 1324)
})
assertOk(t, "Zero-length byte arrays", func(t testing.TB) {
Equal(t, []byte(nil), []byte(""))
})
assertOk(t, "Identical byte arrays", func(t testing.TB) {
Equal(t, []byte{1, 2, 3, 4}, []byte{1, 2, 3, 4})
})
assertFail(t, "Different byte arrays", func(t testing.TB) {
Equal(t, []byte{1, 2, 3, 4}, []byte{1, 3, 2, 4})
})
assertOk(t, "Identical strings", func(t testing.TB) {
Equal(t, "example", "example")
})
assertFail(t, "Identical strings", func(t testing.TB) {
Equal(t, "example", "elpmaxe")
})
}
func TestError(t *testing.T) {
assertOk(t, "Error", func(t testing.TB) {
Error(t, fmt.Errorf("example"))
})
assertFail(t, "Nil", func(t testing.TB) {
Error(t, nil)
})
}
func TestNoError(t *testing.T) {
assertFail(t, "Error", func(t testing.TB) {
NoError(t, fmt.Errorf("example"))
})
assertOk(t, "Nil", func(t testing.TB) {
NoError(t, nil)
})
}
func TestPanics(t *testing.T) {
willPanic := func() { panic("example") }
wontPanic := func() {}
assertOk(t, "Will panic", func(t testing.TB) {
Panics(t, willPanic)
})
assertFail(t, "Won't panic", func(t testing.TB) {
Panics(t, wontPanic)
})
}
func TestZero(t *testing.T) {
assertOk(t, "Empty struct", func(t testing.TB) {
Zero(t, Data{})
})
assertFail(t, "Non-empty struct", func(t testing.TB) {
Zero(t, Data{Label: "example"})
})
assertOk(t, "Nil slice", func(t testing.TB) {
var slice []int
Zero(t, slice)
})
assertFail(t, "Non-empty slice", func(t testing.TB) {
slice := []int{1, 2, 3, 4}
Zero(t, slice)
})
assertOk(t, "Zero-length slice", func(t testing.TB) {
slice := []int{}
Zero(t, slice)
})
}
func TestNotZero(t *testing.T) {
assertFail(t, "Empty struct", func(t testing.TB) {
zero := Data{}
NotZero(t, zero)
})
assertOk(t, "Non-empty struct", func(t testing.TB) {
notZero := Data{Label: "example"}
NotZero(t, notZero)
})
assertFail(t, "Nil slice", func(t testing.TB) {
var slice []int
NotZero(t, slice)
})
assertFail(t, "Zero-length slice", func(t testing.TB) {
slice := []int{}
NotZero(t, slice)
})
assertOk(t, "Non-empty slice", func(t testing.TB) {
slice := []int{1, 2, 3, 4}
NotZero(t, slice)
})
}
type testCase struct {
*testing.T
failed string
}
func (t *testCase) Fatal(args ...interface{}) {
t.failed = fmt.Sprint(args...)
}
func (t *testCase) Fatalf(message string, args ...interface{}) {
t.failed = fmt.Sprintf(message, args...)
}
func assertFail(t *testing.T, name string, fn func(t testing.TB)) {
t.Helper()
t.Run(name, func(t *testing.T) {
t.Helper()
test := &testCase{T: t}
fn(test)
if test.failed == "" {
t.Fatal("Test expected to fail but did not")
} else {
t.Log(test.failed)
}
})
}
func assertOk(t *testing.T, name string, fn func(t testing.TB)) {
t.Helper()
t.Run(name, func(t *testing.T) {
t.Helper()
test := &testCase{T: t}
fn(test)
if test.failed != "" {
t.Fatal("Test expected to succeed but did not:\n", test.failed)
}
})
}
+27 -28
View File
@@ -11,8 +11,7 @@ import (
"testing"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
func processMain(args []string, input io.Reader, stdout, stderr io.Writer, f ConvertFn) int {
@@ -30,8 +29,8 @@ func TestProcessMainStdin(t *testing.T) {
})
assert.Equal(t, 0, exit)
assert.Empty(t, stdout.String())
assert.Empty(t, stderr.String())
assert.Zero(t, stdout.String())
assert.Zero(t, stderr.String())
}
func TestProcessMainStdinErr(t *testing.T) {
@@ -44,8 +43,8 @@ func TestProcessMainStdinErr(t *testing.T) {
})
assert.Equal(t, -1, exit)
assert.Empty(t, stdout.String())
assert.NotEmpty(t, stderr.String())
assert.Zero(t, stdout.String())
assert.NotZero(t, stderr.String())
}
func TestProcessMainStdinDecodeErr(t *testing.T) {
@@ -59,16 +58,16 @@ func TestProcessMainStdinDecodeErr(t *testing.T) {
})
assert.Equal(t, -1, exit)
assert.Empty(t, stdout.String())
assert.Contains(t, stderr.String(), "error occurred at")
assert.Zero(t, stdout.String())
assert.True(t, strings.Contains(stderr.String(), "error occurred at"))
}
func TestProcessMainFileExists(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "example")
require.NoError(t, err)
assert.NoError(t, err)
defer os.Remove(tmpfile.Name())
_, err = tmpfile.Write([]byte(`some data`))
require.NoError(t, err)
assert.NoError(t, err)
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
@@ -78,8 +77,8 @@ func TestProcessMainFileExists(t *testing.T) {
})
assert.Equal(t, 0, exit)
assert.Empty(t, stdout.String())
assert.Empty(t, stderr.String())
assert.Zero(t, stdout.String())
assert.Zero(t, stderr.String())
}
func TestProcessMainFileDoesNotExist(t *testing.T) {
@@ -91,22 +90,22 @@ func TestProcessMainFileDoesNotExist(t *testing.T) {
})
assert.Equal(t, -1, exit)
assert.Empty(t, stdout.String())
assert.NotEmpty(t, stderr.String())
assert.Zero(t, stdout.String())
assert.NotZero(t, stderr.String())
}
func TestProcessMainFilesInPlace(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
assert.NoError(t, err)
defer os.RemoveAll(dir)
path1 := path.Join(dir, "file1")
path2 := path.Join(dir, "file2")
err = ioutil.WriteFile(path1, []byte("content 1"), 0600)
require.NoError(t, err)
assert.NoError(t, err)
err = ioutil.WriteFile(path2, []byte("content 2"), 0600)
require.NoError(t, err)
assert.NoError(t, err)
p := Program{
Fn: dummyFileFn,
@@ -115,15 +114,15 @@ func TestProcessMainFilesInPlace(t *testing.T) {
exit := p.main([]string{path1, path2}, os.Stdin, os.Stdout, os.Stderr)
require.Equal(t, 0, exit)
assert.Equal(t, 0, exit)
v1, err := ioutil.ReadFile(path1)
require.NoError(t, err)
require.Equal(t, "1", string(v1))
assert.NoError(t, err)
assert.Equal(t, "1", string(v1))
v2, err := ioutil.ReadFile(path2)
require.NoError(t, err)
require.Equal(t, "2", string(v2))
assert.NoError(t, err)
assert.Equal(t, "2", string(v2))
}
func TestProcessMainFilesInPlaceErrRead(t *testing.T) {
@@ -134,18 +133,18 @@ func TestProcessMainFilesInPlaceErrRead(t *testing.T) {
exit := p.main([]string{"/this/path/is/invalid"}, os.Stdin, os.Stdout, os.Stderr)
require.Equal(t, -1, exit)
assert.Equal(t, -1, exit)
}
func TestProcessMainFilesInPlaceFailFn(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
assert.NoError(t, err)
defer os.RemoveAll(dir)
path1 := path.Join(dir, "file1")
err = ioutil.WriteFile(path1, []byte("content 1"), 0600)
require.NoError(t, err)
assert.NoError(t, err)
p := Program{
Fn: func(io.Reader, io.Writer) error { return fmt.Errorf("oh no") },
@@ -154,11 +153,11 @@ func TestProcessMainFilesInPlaceFailFn(t *testing.T) {
exit := p.main([]string{path1}, os.Stdin, os.Stdout, os.Stderr)
require.Equal(t, -1, exit)
assert.Equal(t, -1, exit)
v1, err := ioutil.ReadFile(path1)
require.NoError(t, err)
require.Equal(t, "content 1", string(v1))
assert.NoError(t, err)
assert.Equal(t, "content 1", string(v1))
}
func dummyFileFn(r io.Reader, w io.Writer) error {
+6 -8
View File
@@ -4,9 +4,7 @@ import (
"testing"
"unsafe"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
"github.com/pelletier/go-toml/v2/internal/danger"
)
@@ -72,7 +70,7 @@ func TestSubsliceOffsetInvalid(t *testing.T) {
for _, e := range examples {
t.Run(e.desc, func(t *testing.T) {
d, s := e.test()
require.Panics(t, func() {
assert.Panics(t, func() {
danger.SubsliceOffset(d, s)
})
})
@@ -83,9 +81,9 @@ func TestStride(t *testing.T) {
a := []byte{1, 2, 3, 4}
x := &a[1]
n := (*byte)(danger.Stride(unsafe.Pointer(x), unsafe.Sizeof(byte(0)), 1))
require.Equal(t, &a[2], n)
assert.Equal(t, &a[2], n)
n = (*byte)(danger.Stride(unsafe.Pointer(x), unsafe.Sizeof(byte(0)), -1))
require.Equal(t, &a[0], n)
assert.Equal(t, &a[0], n)
}
func TestBytesRange(t *testing.T) {
@@ -166,12 +164,12 @@ func TestBytesRange(t *testing.T) {
t.Run(e.desc, func(t *testing.T) {
start, end := e.test()
if e.expected == nil {
require.Panics(t, func() {
assert.Panics(t, func() {
danger.BytesRange(start, end)
})
} else {
res := danger.BytesRange(start, end)
require.Equal(t, e.expected, res)
assert.Equal(t, e.expected, res)
}
})
}
@@ -9,7 +9,7 @@ import (
"time"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
func TestDocMarshal(t *testing.T) {
@@ -107,13 +107,13 @@ name = 'List.Second'
`
result, err := toml.Marshal(docData)
require.NoError(t, err)
require.Equal(t, marshalTestToml, string(result))
assert.NoError(t, err)
assert.Equal(t, marshalTestToml, string(result))
}
func TestBasicMarshalQuotedKey(t *testing.T) {
result, err := toml.Marshal(quotedKeyMarshalTestData)
require.NoError(t, err)
assert.NoError(t, err)
expected := `'Z.string-àéù' = 'Hello'
'Yfloat-𝟘' = 3.5
@@ -128,7 +128,7 @@ String2 = 'Two'
String2 = 'Three'
`
require.Equal(t, string(expected), string(result))
assert.Equal(t, string(expected), string(result))
}
@@ -153,7 +153,7 @@ func TestEmptyMarshal(t *testing.T) {
Map: map[string]string{},
}
result, err := toml.Marshal(doc)
require.NoError(t, err)
assert.NoError(t, err)
expected := `title = 'Placeholder'
bool = false
@@ -164,7 +164,7 @@ stringlist = []
[map]
`
require.Equal(t, string(expected), string(result))
assert.Equal(t, string(expected), string(result))
}
type textMarshaler struct {
@@ -187,13 +187,13 @@ func TestTextMarshaler(t *testing.T) {
t.Run("at root", func(t *testing.T) {
_, err := toml.Marshal(m)
// in v2 we do not allow TextMarshaler at root
require.Error(t, err)
assert.Error(t, err)
})
t.Run("leaf", func(t *testing.T) {
res, err := toml.Marshal(wrap{m})
require.NoError(t, err)
assert.NoError(t, err)
require.Equal(t, "TM = 'Sally Fields'\n", string(res))
assert.Equal(t, "TM = 'Sally Fields'\n", string(res))
})
}
@@ -16,8 +16,7 @@ import (
"time"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
type basicMarshalTestStruct struct {
@@ -123,7 +122,7 @@ func TestInterface(t *testing.T) {
var config Conf
config.Inter = &NestedStruct{}
err := toml.Unmarshal(doc, &config)
require.NoError(t, err)
assert.NoError(t, err)
expected := Conf{
Name: "rui",
Age: 18,
@@ -139,8 +138,8 @@ func TestInterface(t *testing.T) {
func TestBasicUnmarshal(t *testing.T) {
result := basicMarshalTestStruct{}
err := toml.Unmarshal(basicTestToml, &result)
require.NoError(t, err)
require.Equal(t, basicTestData, result)
assert.NoError(t, err)
assert.Equal(t, basicTestData, result)
}
type quotedKeyMarshalTestStruct struct {
@@ -300,7 +299,7 @@ func TestDocUnmarshal(t *testing.T) {
result := testDoc{}
err := toml.Unmarshal(marshalTestToml, &result)
expected := docData
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, expected, result)
}
@@ -340,7 +339,7 @@ shouldntBeHere = 2
func TestUnexportedUnmarshal(t *testing.T) {
result := unexportedMarshalTestStruct{}
err := toml.Unmarshal(unexportedTestToml, &result)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, unexportedTestData, result)
}
@@ -456,7 +455,7 @@ func TestEmptytomlUnmarshal(t *testing.T) {
result := emptyMarshalTestStruct{}
err := toml.Unmarshal(emptyTestToml, &result)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, emptyTestData, result)
}
@@ -504,7 +503,7 @@ Str = "Hello"
func TestPointerUnmarshal(t *testing.T) {
result := pointerMarshalTestStruct{}
err := toml.Unmarshal(pointerTestToml, &result)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, pointerTestData, result)
}
@@ -540,7 +539,7 @@ StringPtr = [["Three", "Four"]]
func TestNestedUnmarshal(t *testing.T) {
result := nestedMarshalTestStruct{}
err := toml.Unmarshal(nestedTestToml, &result)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, nestedTestData, result)
}
@@ -834,7 +833,7 @@ func TestUnmarshalTabInStringAndQuotedKey(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
result := Test{}
err := toml.Unmarshal(test.input, &result)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, test.expected, result)
})
}
@@ -963,7 +962,7 @@ func TestUnmarshalTypeTableHeader(t *testing.T) {
}
expected := map[header]map[string]int{
"test": map[string]int{"a": 1},
"test": {"a": 1},
}
if !reflect.DeepEqual(result, expected) {
@@ -1090,7 +1089,7 @@ func TestUnmarshalCheckConversionFloatInt(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
err := toml.Unmarshal([]byte(test.input), &conversionCheck{})
require.Error(t, err)
assert.Error(t, err)
})
}
}
@@ -1125,7 +1124,7 @@ func TestUnmarshalOverflow(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
err := toml.Unmarshal([]byte(test.input), &overflow{})
require.Error(t, err)
assert.Error(t, err)
})
}
}
@@ -1745,7 +1744,7 @@ Age = 23
}
actual := OuterStruct{}
err := toml.Unmarshal(doc, &actual)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, expected, actual)
}
@@ -1830,7 +1829,7 @@ InnerField = "After4"
}
err := toml.Unmarshal(doc, &actual)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, expected, actual)
}
@@ -1879,7 +1878,7 @@ type arrayTooSmallStruct struct {
func TestUnmarshalSlice(t *testing.T) {
var actual sliceStruct
err := toml.Unmarshal(sliceTomlDemo, &actual)
require.NoError(t, err)
assert.NoError(t, err)
expected := sliceStruct{
Slice: []string{"Howdy", "Hey There"},
SlicePtr: &[]string{"Howdy", "Hey There"},
@@ -1930,7 +1929,7 @@ func TestUnmarshalMixedTypeSlice(t *testing.T) {
},
}
err := toml.Unmarshal(doc, &actual)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, expected, actual)
}
@@ -1939,7 +1938,7 @@ func TestUnmarshalArray(t *testing.T) {
var actual arrayStruct
err = toml.Unmarshal(sliceTomlDemo, &actual)
require.NoError(t, err)
assert.NoError(t, err)
expected := arrayStruct{
Slice: [4]string{"Howdy", "Hey There"},
@@ -1998,8 +1997,13 @@ func TestDecoderStrict(t *testing.T) {
}
err := strictDecoder(input).Decode(&doc)
require.Error(t, err)
require.IsType(t, &toml.StrictMissingError{}, err)
assert.Error(t, err)
assert.Equal(t,
reflect.TypeOf(err), reflect.TypeOf(&toml.StrictMissingError{}),
"Expected a *toml.StrictMissingError, got: %v", reflect.TypeOf(err),
)
se := err.(*toml.StrictMissingError)
keys := []toml.Key{}
@@ -2015,10 +2019,10 @@ func TestDecoderStrict(t *testing.T) {
{"undecoded", "array"},
}
require.Equal(t, expectedKeys, keys)
assert.Equal(t, expectedKeys, keys)
err = decoder(input).Decode(&doc)
require.NoError(t, err)
assert.NoError(t, err)
var m map[string]interface{}
err = decoder(input).Decode(&m)
@@ -2036,7 +2040,7 @@ func TestDecoderStrictValid(t *testing.T) {
}
err := strictDecoder(input).Decode(&doc)
require.NoError(t, err)
assert.NoError(t, err)
}
type docUnmarshalTOML struct {
@@ -2087,7 +2091,7 @@ func TestCustomUnmarshal(t *testing.T) {
var d parent
err := toml.Unmarshal([]byte(input), &d)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, "ok1", d.Doc.Decoded.Key)
assert.Equal(t, "ok2", d.DocPointer.Decoded.Key)
}
@@ -2153,7 +2157,7 @@ Int = 21
Float = 2.0
`
err := toml.Unmarshal([]byte(input), &doc)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, 12, doc.UnixTime.Value)
assert.Equal(t, 42, doc.Version.Value)
assert.Equal(t, 1, doc.Bool.Value)
@@ -2223,7 +2227,10 @@ func TestUnmarshalEmptyInterface(t *testing.T) {
if err != nil {
t.Fatal(err)
}
require.IsType(t, map[string]interface{}{}, v)
assert.Equal(t,
reflect.TypeOf(map[string]interface{}{}), reflect.TypeOf(v),
"Expected map[string]interface{}{} type, got: %v", reflect.TypeOf(v),
)
x := v.(map[string]interface{})
assert.Equal(t, "pelletier", x["User"])
+1 -1
View File
@@ -42,7 +42,7 @@ func rmTag(typedJson interface{}) (interface{}, error) {
}
return m, nil
// Array: remove tags from all itenm.
// Array: remove tags from all items.
case []interface{}:
a := make([]interface{}, len(v))
for i := range v {
+5 -7
View File
@@ -57,7 +57,11 @@ type SeenTracker struct {
currentIdx int
}
var pool sync.Pool
var pool = sync.Pool{
New: func() interface{} {
return &SeenTracker{}
},
}
func (s *SeenTracker) reset() {
// Always contains a root element at index 0.
@@ -331,12 +335,6 @@ func (s *SeenTracker) checkArray(node *unstable.Node) (first bool, err error) {
}
func (s *SeenTracker) checkInlineTable(node *unstable.Node) (first bool, err error) {
if pool.New == nil {
pool.New = func() interface{} {
return &SeenTracker{}
}
}
s = pool.Get().(*SeenTracker)
s.reset()
+6 -2
View File
@@ -4,7 +4,7 @@ import (
"testing"
"unsafe"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
func TestEntrySize(t *testing.T) {
@@ -12,5 +12,9 @@ func TestEntrySize(t *testing.T) {
// performance of unmarshaling documents. Should only be increased with care
// and a very good reason.
maxExpectedEntrySize := 48
require.LessOrEqual(t, int(unsafe.Sizeof(entry{})), maxExpectedEntrySize)
assert.True(t,
int(unsafe.Sizeof(entry{})) <= maxExpectedEntrySize,
"Expected entry to be less than or equal to %d, got: %d",
maxExpectedEntrySize, int(unsafe.Sizeof(entry{})),
)
}
+28 -28
View File
@@ -5,73 +5,73 @@ import (
"time"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
func TestLocalDate_AsTime(t *testing.T) {
d := toml.LocalDate{2021, 6, 8}
cast := d.AsTime(time.UTC)
require.Equal(t, time.Date(2021, time.June, 8, 0, 0, 0, 0, time.UTC), cast)
assert.Equal(t, time.Date(2021, time.June, 8, 0, 0, 0, 0, time.UTC), cast)
}
func TestLocalDate_String(t *testing.T) {
d := toml.LocalDate{2021, 6, 8}
require.Equal(t, "2021-06-08", d.String())
assert.Equal(t, "2021-06-08", d.String())
}
func TestLocalDate_MarshalText(t *testing.T) {
d := toml.LocalDate{2021, 6, 8}
b, err := d.MarshalText()
require.NoError(t, err)
require.Equal(t, []byte("2021-06-08"), b)
assert.NoError(t, err)
assert.Equal(t, []byte("2021-06-08"), b)
}
func TestLocalDate_UnmarshalMarshalText(t *testing.T) {
d := toml.LocalDate{}
err := d.UnmarshalText([]byte("2021-06-08"))
require.NoError(t, err)
require.Equal(t, toml.LocalDate{2021, 6, 8}, d)
assert.NoError(t, err)
assert.Equal(t, toml.LocalDate{2021, 6, 8}, d)
err = d.UnmarshalText([]byte("what"))
require.Error(t, err)
assert.Error(t, err)
}
func TestLocalTime_String(t *testing.T) {
d := toml.LocalTime{20, 12, 1, 2, 9}
require.Equal(t, "20:12:01.000000002", d.String())
assert.Equal(t, "20:12:01.000000002", d.String())
d = toml.LocalTime{20, 12, 1, 0, 0}
require.Equal(t, "20:12:01", d.String())
assert.Equal(t, "20:12:01", d.String())
d = toml.LocalTime{20, 12, 1, 0, 9}
require.Equal(t, "20:12:01.000000000", d.String())
assert.Equal(t, "20:12:01.000000000", d.String())
d = toml.LocalTime{20, 12, 1, 100, 0}
require.Equal(t, "20:12:01.0000001", d.String())
assert.Equal(t, "20:12:01.0000001", d.String())
}
func TestLocalTime_MarshalText(t *testing.T) {
d := toml.LocalTime{20, 12, 1, 2, 9}
b, err := d.MarshalText()
require.NoError(t, err)
require.Equal(t, []byte("20:12:01.000000002"), b)
assert.NoError(t, err)
assert.Equal(t, []byte("20:12:01.000000002"), b)
}
func TestLocalTime_UnmarshalMarshalText(t *testing.T) {
d := toml.LocalTime{}
err := d.UnmarshalText([]byte("20:12:01.000000002"))
require.NoError(t, err)
require.Equal(t, toml.LocalTime{20, 12, 1, 2, 9}, d)
assert.NoError(t, err)
assert.Equal(t, toml.LocalTime{20, 12, 1, 2, 9}, d)
err = d.UnmarshalText([]byte("what"))
require.Error(t, err)
assert.Error(t, err)
err = d.UnmarshalText([]byte("20:12:01.000000002 bad"))
require.Error(t, err)
assert.Error(t, err)
}
func TestLocalTime_RoundTrip(t *testing.T) {
var d struct{ A toml.LocalTime }
err := toml.Unmarshal([]byte("a=20:12:01.500"), &d)
require.NoError(t, err)
require.Equal(t, "20:12:01.500", d.A.String())
assert.NoError(t, err)
assert.Equal(t, "20:12:01.500", d.A.String())
}
func TestLocalDateTime_AsTime(t *testing.T) {
@@ -80,7 +80,7 @@ func TestLocalDateTime_AsTime(t *testing.T) {
toml.LocalTime{20, 12, 1, 2, 9},
}
cast := d.AsTime(time.UTC)
require.Equal(t, time.Date(2021, time.June, 8, 20, 12, 1, 2, time.UTC), cast)
assert.Equal(t, time.Date(2021, time.June, 8, 20, 12, 1, 2, time.UTC), cast)
}
func TestLocalDateTime_String(t *testing.T) {
@@ -88,7 +88,7 @@ func TestLocalDateTime_String(t *testing.T) {
toml.LocalDate{2021, 6, 8},
toml.LocalTime{20, 12, 1, 2, 9},
}
require.Equal(t, "2021-06-08T20:12:01.000000002", d.String())
assert.Equal(t, "2021-06-08T20:12:01.000000002", d.String())
}
func TestLocalDateTime_MarshalText(t *testing.T) {
@@ -97,22 +97,22 @@ func TestLocalDateTime_MarshalText(t *testing.T) {
toml.LocalTime{20, 12, 1, 2, 9},
}
b, err := d.MarshalText()
require.NoError(t, err)
require.Equal(t, []byte("2021-06-08T20:12:01.000000002"), b)
assert.NoError(t, err)
assert.Equal(t, []byte("2021-06-08T20:12:01.000000002"), b)
}
func TestLocalDateTime_UnmarshalMarshalText(t *testing.T) {
d := toml.LocalDateTime{}
err := d.UnmarshalText([]byte("2021-06-08 20:12:01.000000002"))
require.NoError(t, err)
require.Equal(t, toml.LocalDateTime{
assert.NoError(t, err)
assert.Equal(t, toml.LocalDateTime{
toml.LocalDate{2021, 6, 8},
toml.LocalTime{20, 12, 1, 2, 9},
}, d)
err = d.UnmarshalText([]byte("what"))
require.Error(t, err)
assert.Error(t, err)
err = d.UnmarshalText([]byte("2021-06-08 20:12:01.000000002 bad"))
require.Error(t, err)
assert.Error(t, err)
}
+18 -6
View File
@@ -8,7 +8,7 @@ import (
"io"
"math"
"reflect"
"sort"
"slices"
"strconv"
"strings"
"time"
@@ -280,7 +280,7 @@ func (enc *Encoder) encode(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, e
}
hasTextMarshaler := v.Type().Implements(textMarshalerType)
if hasTextMarshaler || (v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) {
if hasTextMarshaler || (v.CanAddr() && reflect.PointerTo(v.Type()).Implements(textMarshalerType)) {
if !hasTextMarshaler {
v = v.Addr()
}
@@ -631,6 +631,18 @@ func (enc *Encoder) keyToString(k reflect.Value) (string, error) {
return "", fmt.Errorf("toml: error marshalling key %v from text: %w", k, err)
}
return string(keyB), nil
case keyType.Kind() == reflect.Int || keyType.Kind() == reflect.Int8 || keyType.Kind() == reflect.Int16 || keyType.Kind() == reflect.Int32 || keyType.Kind() == reflect.Int64:
return strconv.FormatInt(k.Int(), 10), nil
case keyType.Kind() == reflect.Uint || keyType.Kind() == reflect.Uint8 || keyType.Kind() == reflect.Uint16 || keyType.Kind() == reflect.Uint32 || keyType.Kind() == reflect.Uint64:
return strconv.FormatUint(k.Uint(), 10), nil
case keyType.Kind() == reflect.Float32:
return strconv.FormatFloat(k.Float(), 'f', -1, 32), nil
case keyType.Kind() == reflect.Float64:
return strconv.FormatFloat(k.Float(), 'f', -1, 64), nil
}
return "", fmt.Errorf("toml: type %s is not supported as a map key", keyType.Kind())
}
@@ -668,8 +680,8 @@ func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte
}
func sortEntriesByKey(e []entry) {
sort.Slice(e, func(i, j int) bool {
return e[i].Key < e[j].Key
slices.SortFunc(e, func(a, b entry) int {
return strings.Compare(a.Key, b.Key)
})
}
@@ -732,7 +744,7 @@ func walkStruct(ctx encoderCtx, t *table, v reflect.Value) {
if fieldType.Anonymous {
if fieldType.Type.Kind() == reflect.Struct {
walkStruct(ctx, t, f)
} else if fieldType.Type.Kind() == reflect.Pointer && !f.IsNil() && f.Elem().Kind() == reflect.Struct {
} else if fieldType.Type.Kind() == reflect.Ptr && !f.IsNil() && f.Elem().Kind() == reflect.Struct {
walkStruct(ctx, t, f.Elem())
}
continue
@@ -951,7 +963,7 @@ func willConvertToTable(ctx encoderCtx, v reflect.Value) bool {
if !v.IsValid() {
return false
}
if v.Type() == timeType || v.Type().Implements(textMarshalerType) || (v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) {
if v.Type() == timeType || v.Type().Implements(textMarshalerType) || (v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PointerTo(v.Type()).Implements(textMarshalerType)) {
return false
}
+155 -76
View File
@@ -6,13 +6,13 @@ import (
"fmt"
"math"
"math/big"
"reflect"
"strings"
"testing"
"time"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
type marshalTextKey struct {
@@ -30,6 +30,27 @@ func (k marshalBadTextKey) MarshalText() ([]byte, error) {
return nil, fmt.Errorf("error")
}
func toFloat(x interface{}) float64 {
// Shortened version of testify/toFloat
var xf float64
switch xn := x.(type) {
case float32:
xf = float64(xn)
case float64:
xf = xn
}
return xf
}
func inDelta(t *testing.T, expected, actual interface{}, delta float64) {
dt := toFloat(expected) - toFloat(actual)
assert.True(t,
dt < -delta && dt < delta,
"Difference between %v and %v is %v, but difference was %v",
expected, actual, delta, dt,
)
}
func TestMarshal(t *testing.T) {
someInt := 42
@@ -587,13 +608,69 @@ foo = 42
`,
},
{
desc: "invalid map key",
desc: "int map key",
v: map[int]interface{}{1: "a"},
expected: `1 = 'a'
`,
},
{
desc: "int8 map key",
v: map[int8]interface{}{1: "a"},
expected: `1 = 'a'
`,
},
{
desc: "int64 map key",
v: map[int64]interface{}{1: "a"},
expected: `1 = 'a'
`,
},
{
desc: "uint map key",
v: map[uint]interface{}{1: "a"},
expected: `1 = 'a'
`,
},
{
desc: "uint8 map key",
v: map[uint8]interface{}{1: "a"},
expected: `1 = 'a'
`,
},
{
desc: "uint64 map key",
v: map[uint64]interface{}{1: "a"},
expected: `1 = 'a'
`,
},
{
desc: "float32 map key",
v: map[float32]interface{}{
1.1: "a",
1.0020: "b",
},
expected: `'1.002' = 'b'
'1.1' = 'a'
`,
},
{
desc: "float64 map key",
v: map[float64]interface{}{
1.1: "a",
1.0020: "b",
},
expected: `'1.002' = 'b'
'1.1' = 'a'
`,
},
{
desc: "invalid map key",
v: map[struct{ int }]interface{}{{1}: "a"},
err: true,
},
{
desc: "invalid map key but empty",
v: map[int]interface{}{},
v: map[struct{ int }]interface{}{},
expected: "",
},
{
@@ -708,18 +785,18 @@ Three = [1, 2, 3]
t.Run(e.desc, func(t *testing.T) {
b, err := toml.Marshal(e.v)
if e.err {
require.Error(t, err)
assert.Error(t, err)
return
}
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, e.expected, string(b))
// make sure the output is always valid TOML
defaultMap := map[string]interface{}{}
err = toml.Unmarshal(b, &defaultMap)
require.NoError(t, err)
assert.NoError(t, err)
testWithAllFlags(t, func(t *testing.T, flags int) {
t.Helper()
@@ -729,13 +806,13 @@ Three = [1, 2, 3]
setFlags(enc, flags)
err := enc.Encode(e.v)
require.NoError(t, err)
assert.NoError(t, err)
inlineMap := map[string]interface{}{}
err = toml.Unmarshal(buf.Bytes(), &inlineMap)
require.NoError(t, err)
assert.NoError(t, err)
require.Equal(t, defaultMap, inlineMap)
assert.Equal(t, defaultMap, inlineMap)
})
})
}
@@ -802,8 +879,8 @@ nan = nan
`
actual, err := toml.Marshal(v)
require.NoError(t, err)
require.Equal(t, expected, string(actual))
assert.NoError(t, err)
assert.Equal(t, expected, string(actual))
v64 := map[string]float64{
"nan": math.NaN(),
@@ -812,8 +889,8 @@ nan = nan
}
actual, err = toml.Marshal(v64)
require.NoError(t, err)
require.Equal(t, expected, string(actual))
assert.NoError(t, err)
assert.Equal(t, expected, string(actual))
}
//nolint:funlen
@@ -873,7 +950,7 @@ func TestMarshalIndentTables(t *testing.T) {
enc := toml.NewEncoder(&buf)
enc.SetIndentTables(true)
err := enc.Encode(e.v)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, e.expected, buf.String())
})
}
@@ -893,13 +970,13 @@ func (c *customTextMarshaler) MarshalText() ([]byte, error) {
func TestMarshalTextMarshaler_NoRoot(t *testing.T) {
c := customTextMarshaler{}
_, err := toml.Marshal(&c)
require.Error(t, err)
assert.Error(t, err)
}
func TestMarshalTextMarshaler_Error(t *testing.T) {
m := map[string]interface{}{"a": &customTextMarshaler{value: 1}}
_, err := toml.Marshal(m)
require.Error(t, err)
assert.Error(t, err)
}
func TestMarshalTextMarshaler_ErrorInline(t *testing.T) {
@@ -912,13 +989,13 @@ func TestMarshalTextMarshaler_ErrorInline(t *testing.T) {
}
_, err := toml.Marshal(d)
require.Error(t, err)
assert.Error(t, err)
}
func TestMarshalTextMarshaler(t *testing.T) {
m := map[string]interface{}{"a": &customTextMarshaler{value: 2}}
r, err := toml.Marshal(m)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, "a = '::2'\n", string(r))
}
@@ -932,7 +1009,7 @@ func TestEncodeToBrokenWriter(t *testing.T) {
w := brokenWriter{}
enc := toml.NewEncoder(&w)
err := enc.Encode(map[string]string{"hello": "world"})
require.Error(t, err)
assert.Error(t, err)
}
func TestEncoderSetIndentSymbol(t *testing.T) {
@@ -941,7 +1018,7 @@ func TestEncoderSetIndentSymbol(t *testing.T) {
enc.SetIndentTables(true)
enc.SetIndentSymbol(">>>")
err := enc.Encode(map[string]map[string]string{"parent": {"hello": "world"}})
require.NoError(t, err)
assert.NoError(t, err)
expected := `[parent]
>>>hello = 'world'
`
@@ -960,7 +1037,7 @@ func TestEncoderSetMarshalJsonNumbers(t *testing.T) {
"E": json.Number("0.0"),
"F": json.Number(""),
})
require.NoError(t, err)
assert.NoError(t, err)
expected := `A = 1.1
B = 0.042
C = 42
@@ -997,7 +1074,7 @@ func TestEncoderOmitempty(t *testing.T) {
d := doc{}
b, err := toml.Marshal(d)
require.NoError(t, err)
assert.NoError(t, err)
expected := ``
@@ -1014,7 +1091,7 @@ func TestEncoderTagFieldName(t *testing.T) {
d := doc{String: "world"}
b, err := toml.Marshal(d)
require.NoError(t, err)
assert.NoError(t, err)
expected := `hello = 'world'
'#' = ''
@@ -1029,11 +1106,11 @@ func TestIssue436(t *testing.T) {
var v interface{}
err := json.Unmarshal(data, &v)
require.NoError(t, err)
assert.NoError(t, err)
var buf bytes.Buffer
err = toml.NewEncoder(&buf).Encode(v)
require.NoError(t, err)
assert.NoError(t, err)
expected := `[[a]]
[a.b]
@@ -1055,27 +1132,30 @@ func TestIssue424(t *testing.T) {
msg2 := Message2{"Hello\\World"}
toml1, err := toml.Marshal(msg1)
require.NoError(t, err)
assert.NoError(t, err)
toml2, err := toml.Marshal(msg2)
require.NoError(t, err)
assert.NoError(t, err)
msg1parsed := Message1{}
err = toml.Unmarshal(toml1, &msg1parsed)
require.NoError(t, err)
require.Equal(t, msg1, msg1parsed)
assert.NoError(t, err)
assert.Equal(t, msg1, msg1parsed)
msg2parsed := Message2{}
err = toml.Unmarshal(toml2, &msg2parsed)
require.NoError(t, err)
require.Equal(t, msg2, msg2parsed)
assert.NoError(t, err)
assert.Equal(t, msg2, msg2parsed)
}
func TestIssue567(t *testing.T) {
var m map[string]interface{}
err := toml.Unmarshal([]byte("A = 12:08:05"), &m)
require.NoError(t, err)
require.IsType(t, m["A"], toml.LocalTime{})
assert.NoError(t, err)
assert.Equal(t,
reflect.TypeOf(m["A"]), reflect.TypeOf(toml.LocalTime{}),
"Expected type '%v', got: %v", reflect.TypeOf(m["A"]), reflect.TypeOf(toml.LocalTime{}),
)
}
func TestIssue590(t *testing.T) {
@@ -1084,7 +1164,7 @@ func TestIssue590(t *testing.T) {
Option CustomType `toml:"option"`
}
err := toml.Unmarshal([]byte("option = 42"), &cfg)
require.NoError(t, err)
assert.NoError(t, err)
}
func TestIssue571(t *testing.T) {
@@ -1100,14 +1180,14 @@ func TestIssue571(t *testing.T) {
Float64: 43,
}
b, err := toml.Marshal(foo)
require.NoError(t, err)
assert.NoError(t, err)
var foo2 Foo
err = toml.Unmarshal(b, &foo2)
require.NoError(t, err)
assert.NoError(t, err)
assert.InDelta(t, 42, foo2.Float32, closeEnough)
assert.InDelta(t, 43, foo2.Float64, closeEnough)
inDelta(t, 42, foo2.Float32, closeEnough)
inDelta(t, 43, foo2.Float64, closeEnough)
}
func TestIssue678(t *testing.T) {
@@ -1120,13 +1200,13 @@ func TestIssue678(t *testing.T) {
}
out, err := toml.Marshal(cfg)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, "BigInt = '123'\n", string(out))
cfg2 := &Config{}
err = toml.Unmarshal(out, cfg2)
require.NoError(t, err)
require.Equal(t, cfg, cfg2)
assert.NoError(t, err)
assert.Equal(t, cfg, cfg2)
}
func TestIssue752(t *testing.T) {
@@ -1141,8 +1221,8 @@ func TestIssue752(t *testing.T) {
c := Container{}
out, err := toml.Marshal(c)
require.NoError(t, err)
require.Equal(t, "", string(out))
assert.NoError(t, err)
assert.Equal(t, "", string(out))
}
func TestIssue768(t *testing.T) {
@@ -1151,14 +1231,14 @@ func TestIssue768(t *testing.T) {
}
out, err := toml.Marshal(&cfg{})
require.NoError(t, err)
assert.NoError(t, err)
expected := `# This is a multiline comment.
# This is line 2.
Name = ''
`
require.Equal(t, expected, string(out))
assert.Equal(t, expected, string(out))
}
func TestIssue786(t *testing.T) {
@@ -1174,9 +1254,9 @@ func TestIssue786(t *testing.T) {
x := Test{}
b, err := toml.Marshal(x)
require.NoError(t, err)
assert.NoError(t, err)
require.Equal(t, "", string(b))
assert.Equal(t, "", string(b))
type General struct {
From string `toml:"from,omitempty" json:"from,omitempty" comment:"from in graphite-web format, the local TZ is used"`
@@ -1221,10 +1301,10 @@ from = '-2d'
randomize = true
`
require.Equal(t, expected, buf.String())
assert.Equal(t, expected, buf.String())
}
func TestMarhsalIssue888(t *testing.T) {
func TestMarshalIssue888(t *testing.T) {
type Thing struct {
FieldA string `comment:"my field A"`
FieldB string `comment:"my field B"`
@@ -1260,7 +1340,7 @@ func TestMarhsalIssue888(t *testing.T) {
FieldB = 'field b 2'
`
require.Equal(t, expected, buf.String())
assert.Equal(t, expected, buf.String())
}
func TestMarshalNestedAnonymousStructs(t *testing.T) {
@@ -1296,8 +1376,8 @@ value = ''
`
result, err := toml.Marshal(doc)
require.NoError(t, err)
require.Equal(t, expected, string(result))
assert.NoError(t, err)
assert.Equal(t, expected, string(result))
}
func TestMarshalNestedAnonymousStructs_DuplicateField(t *testing.T) {
@@ -1322,9 +1402,9 @@ value = ''
`
result, err := toml.Marshal(doc)
require.NoError(t, err)
require.NoError(t, err)
require.Equal(t, expected, string(result))
assert.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, expected, string(result))
}
func TestMarshalNestedAnonymousStructs_PointerEmbedded(t *testing.T) {
@@ -1355,8 +1435,8 @@ func TestMarshalNestedAnonymousStructs_PointerEmbedded(t *testing.T) {
`
result, err := toml.Marshal(doc)
require.NoError(t, err)
require.Equal(t, expected, string(result))
assert.NoError(t, err)
assert.Equal(t, expected, string(result))
}
func TestLocalTime(t *testing.T) {
@@ -1373,12 +1453,12 @@ func TestLocalTime(t *testing.T) {
`
out, err := toml.Marshal(v)
require.NoError(t, err)
require.Equal(t, expected, string(out))
assert.NoError(t, err)
assert.Equal(t, expected, string(out))
}
func TestMarshalUint64Overflow(t *testing.T) {
// The TOML spec only requires implementation to provide support for the
// The TOML spec only asserts implementation to provide support for the
// int64 range. To avoid generating TOML documents that would not be
// supported by standard-compliant parsers, uint64 > max int64 cannot be
// marshaled.
@@ -1387,7 +1467,7 @@ func TestMarshalUint64Overflow(t *testing.T) {
}
_, err := toml.Marshal(x)
require.Error(t, err)
assert.Error(t, err)
}
func TestIndentWithInlineTable(t *testing.T) {
@@ -1407,7 +1487,7 @@ func TestIndentWithInlineTable(t *testing.T) {
enc.SetIndentTables(true)
enc.SetTablesInline(true)
enc.SetArraysMultiline(true)
require.NoError(t, enc.Encode(x))
assert.NoError(t, enc.Encode(x))
assert.Equal(t, expected, buf.String())
}
@@ -1464,7 +1544,7 @@ func TestMarshalCommented(t *testing.T) {
}
out, err := toml.Marshal(c)
require.NoError(t, err)
assert.NoError(t, err)
expected := `# Int = 42
# String = 'root'
@@ -1496,7 +1576,7 @@ func TestMarshalCommented(t *testing.T) {
# Values = [4, 5, 6]
`
require.Equal(t, expected, string(out))
assert.Equal(t, expected, string(out))
}
func TestMarshalIndentedCustomTypeArray(t *testing.T) {
@@ -1532,8 +1612,8 @@ func TestMarshalIndentedCustomTypeArray(t *testing.T) {
var buf bytes.Buffer
enc := toml.NewEncoder(&buf)
enc.SetIndentTables(true)
require.NoError(t, enc.Encode(c))
require.Equal(t, expected, buf.String())
assert.NoError(t, enc.Encode(c))
assert.Equal(t, expected, buf.String())
}
func ExampleMarshal() {
@@ -1565,7 +1645,6 @@ func ExampleMarshal() {
// configuration file that has commented out sections (example from
// go-graphite/graphite-clickhouse).
func ExampleMarshal_commented() {
type Common struct {
Listen string `toml:"listen" comment:"general listener"`
PprofListen string `toml:"pprof-listen" comment:"listener to serve /debug/pprof requests. '-pprof' argument overrides it"`
@@ -1574,15 +1653,15 @@ func ExampleMarshal_commented() {
}
type Costs struct {
Cost *int `toml:"cost" comment:"default cost (for wildcarded equalence or matched with regex, or if no value cost set)"`
ValuesCost map[string]int `toml:"values-cost" comment:"cost with some value (for equalence without wildcards) (additional tuning, usually not needed)"`
Cost *int `toml:"cost" comment:"default cost (for wildcarded equivalence or matched with regex, or if no value cost set)"`
ValuesCost map[string]int `toml:"values-cost" comment:"cost with some value (for equivalence without wildcards) (additional tuning, usually not needed)"`
}
type ClickHouse struct {
URL string `toml:"url" comment:"default url, see https://clickhouse.tech/docs/en/interfaces/http. Can be overwritten with query-params"`
RenderMaxQueries int `toml:"render-max-queries" comment:"Max queries to render queiries"`
RenderConcurrentQueries int `toml:"render-concurrent-queries" comment:"Concurrent queries to render queiries"`
RenderMaxQueries int `toml:"render-max-queries" comment:"Max queries to render queries"`
RenderConcurrentQueries int `toml:"render-concurrent-queries" comment:"Concurrent queries to render queries"`
TaggedCosts map[string]*Costs `toml:"tagged-costs,commented"`
TreeTable string `toml:"tree-table,commented"`
ReverseTreeTable string `toml:"reverse-tree-table,commented"`
@@ -1656,9 +1735,9 @@ func ExampleMarshal_commented() {
// [clickhouse]
// # default url, see https://clickhouse.tech/docs/en/interfaces/http. Can be overwritten with query-params
// url = 'http://localhost:8123?cancel_http_readonly_queries_on_client_close=1'
// # Max queries to render queiries
// # Max queries to render queries
// render-max-queries = 0
// # Concurrent queries to render queiries
// # Concurrent queries to render queries
// render-concurrent-queries = 0
// # tree-table = ''
// # reverse-tree-table = ''
@@ -1704,7 +1783,7 @@ func TestReadmeComments(t *testing.T) {
},
}
out, err := toml.Marshal(example)
require.NoError(t, err)
assert.NoError(t, err)
expected := `# Host IP to connect to.
host = '127.0.0.1'
@@ -1716,5 +1795,5 @@ port = 4242
# cipher = 'AEAD-AES128-GCM-SHA256'
# version = 'TLS 1.3'
`
require.Equal(t, expected, string(out))
assert.Equal(t, expected, string(out))
}
-3
View File
@@ -1,6 +1,3 @@
//go:build go1.18 || go1.19 || go1.20 || go1.21 || go1.22
// +build go1.18 go1.19 go1.20 go1.21 go1.22
package ossfuzz
import (
+4 -4
View File
@@ -9,8 +9,8 @@ import (
"testing"
"github.com/pelletier/go-toml/v2"
"github.com/pelletier/go-toml/v2/internal/assert"
"github.com/pelletier/go-toml/v2/internal/testsuite"
"github.com/stretchr/testify/require"
)
func testgenInvalid(t *testing.T, input string) {
@@ -45,15 +45,15 @@ func testgenValid(t *testing.T, input string, jsonRef string) {
t.Fatalf("failed parsing toml: %s", err)
}
j, err := testsuite.ValueToTaggedJSON(doc)
require.NoError(t, err)
assert.NoError(t, err)
var ref interface{}
err = json.Unmarshal([]byte(jsonRef), &ref)
require.NoError(t, err)
assert.NoError(t, err)
var actual interface{}
err = json.Unmarshal([]byte(j), &actual)
require.NoError(t, err)
assert.NoError(t, err)
testsuite.CmpJSON(t, "", ref, actual)
}
+1 -1
View File
@@ -1804,7 +1804,7 @@ func TestTOMLTest_Valid_Array_Empty(t *testing.T) {
testgenValid(t, input, jsonRef)
}
func TestTOMLTest_Valid_Array_Hetergeneous(t *testing.T) {
func TestTOMLTest_Valid_Array_Heterogeneous(t *testing.T) {
input := "mixed = [[1, 2], [\"a\", \"b\"], [1.1, 2.1]]\n"
jsonRef := "{\n \"mixed\": [\n [\n {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n ],\n [\n {\n \"type\": \"string\",\n \"value\": \"a\"\n },\n {\n \"type\": \"string\",\n \"value\": \"b\"\n }\n ],\n [\n {\n \"type\": \"float\",\n \"value\": \"1.1\"\n },\n {\n \"type\": \"float\",\n \"value\": \"2.1\"\n }\n ]\n ]\n}\n"
testgenValid(t, input, jsonRef)
+35 -12
View File
@@ -5,9 +5,9 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"math"
"reflect"
"strconv"
"strings"
"sync/atomic"
"time"
@@ -21,10 +21,8 @@ import (
//
// It is a shortcut for Decoder.Decode() with the default options.
func Unmarshal(data []byte, v interface{}) error {
p := unstable.Parser{}
p.Reset(data)
d := decoder{p: &p}
d := decoder{}
d.p.Reset(data)
return d.FromParser(v)
}
@@ -61,7 +59,7 @@ func (d *Decoder) DisallowUnknownFields() *Decoder {
//
// With this feature enabled, types implementing the unstable/Unmarshaler
// interface can be decoded from any structure of the document. It allows types
// that don't have a straightfoward TOML representation to provide their own
// that don't have a straightforward TOML representation to provide their own
// decoding logic.
//
// Currently, types can only decode from a single value. Tables and array tables
@@ -117,27 +115,25 @@ func (d *Decoder) EnableUnmarshalerInterface() *Decoder {
// Inline Table -> same as Table
// Array of Tables -> same as Array and Table
func (d *Decoder) Decode(v interface{}) error {
b, err := ioutil.ReadAll(d.r)
b, err := io.ReadAll(d.r)
if err != nil {
return fmt.Errorf("toml: %w", err)
}
p := unstable.Parser{}
p.Reset(b)
dec := decoder{
p: &p,
strict: strict{
Enabled: d.strict,
},
unmarshalerInterface: d.unmarshalerInterface,
}
dec.p.Reset(b)
return dec.FromParser(v)
}
type decoder struct {
// Which parser instance in use for this decoding session.
p *unstable.Parser
p unstable.Parser
// Flag indicating that the current expression is stashed.
// If set to true, calling nextExpr will not actually pull a new expression
@@ -1078,12 +1074,39 @@ func (d *decoder) keyFromData(keyType reflect.Type, data []byte) (reflect.Value,
}
return mk, nil
case reflect.PtrTo(keyType).Implements(textUnmarshalerType):
case reflect.PointerTo(keyType).Implements(textUnmarshalerType):
mk := reflect.New(keyType)
if err := mk.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
return reflect.Value{}, fmt.Errorf("toml: error unmarshalling key type %s from text: %w", stringType, err)
}
return mk.Elem(), nil
case keyType.Kind() == reflect.Int || keyType.Kind() == reflect.Int8 || keyType.Kind() == reflect.Int16 || keyType.Kind() == reflect.Int32 || keyType.Kind() == reflect.Int64:
key, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from integer: %w", stringType, err)
}
return reflect.ValueOf(key).Convert(keyType), nil
case keyType.Kind() == reflect.Uint || keyType.Kind() == reflect.Uint8 || keyType.Kind() == reflect.Uint16 || keyType.Kind() == reflect.Uint32 || keyType.Kind() == reflect.Uint64:
key, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from unsigned integer: %w", stringType, err)
}
return reflect.ValueOf(key).Convert(keyType), nil
case keyType.Kind() == reflect.Float32:
key, err := strconv.ParseFloat(string(data), 32)
if err != nil {
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from float: %w", stringType, err)
}
return reflect.ValueOf(float32(key)), nil
case keyType.Kind() == reflect.Float64:
key, err := strconv.ParseFloat(string(data), 64)
if err != nil {
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from float: %w", stringType, err)
}
return reflect.ValueOf(float64(key)), nil
}
return reflect.Value{}, fmt.Errorf("toml: cannot convert map key of type %s to expected type %s", stringType, keyType)
}
+265 -132
View File
@@ -12,9 +12,8 @@ import (
"time"
"github.com/pelletier/go-toml/v2"
"github.com/pelletier/go-toml/v2/internal/assert"
"github.com/pelletier/go-toml/v2/unstable"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type unmarshalTextKey struct {
@@ -109,7 +108,7 @@ func TestDecodeReaderError(t *testing.T) {
dec := toml.NewDecoder(r)
m := map[string]interface{}{}
err := dec.Decode(&m)
require.Error(t, err)
assert.Error(t, err)
}
// nolint:funlen
@@ -187,9 +186,9 @@ func TestUnmarshal_Integers(t *testing.T) {
doc := doc{}
err := toml.Unmarshal([]byte(`A = `+e.input), &doc)
if e.err {
require.Error(t, err)
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, e.expected, doc.A)
}
})
@@ -205,7 +204,6 @@ func TestUnmarshal_Floats(t *testing.T) {
testFn func(t *testing.T, v float64)
err bool
}{
{
desc: "float pi",
input: `3.1415`,
@@ -322,9 +320,9 @@ func TestUnmarshal_Floats(t *testing.T) {
doc := doc{}
err := toml.Unmarshal([]byte(`A = `+e.input), &doc)
if e.err {
require.Error(t, err)
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NoError(t, err)
if e.testFn != nil {
e.testFn(t, doc.A)
} else {
@@ -840,8 +838,10 @@ huey = 'dewey'
return test{
target: &doc{},
expected: &doc{A: []interface{}{"0", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17"}},
expected: &doc{A: []interface{}{
"0", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17",
}},
}
},
},
@@ -1696,16 +1696,6 @@ B = "data"`,
}
},
},
{
desc: "empty map into map with invalid key type",
input: ``,
gen: func() test {
return test{
target: &map[int]string{},
expected: &map[int]string{},
}
},
},
{
desc: "into map with convertible key type",
input: `A = "hello"`,
@@ -1942,6 +1932,150 @@ B = "data"`,
}
},
},
{
desc: "into map of int to string",
input: `1 = "a"`,
gen: func() test {
return test{
target: &map[int]string{},
expected: &map[int]string{1: "a"},
assert: func(t *testing.T, test test) {
assert.Equal(t, test.expected, test.target)
},
}
},
},
{
desc: "into map of int8 to string",
input: `1 = "a"`,
gen: func() test {
return test{
target: &map[int8]string{},
expected: &map[int8]string{1: "a"},
assert: func(t *testing.T, test test) {
assert.Equal(t, test.expected, test.target)
},
}
},
},
{
desc: "into map of int64 to string",
input: `1 = "a"`,
gen: func() test {
return test{
target: &map[int64]string{},
expected: &map[int64]string{1: "a"},
assert: func(t *testing.T, test test) {
assert.Equal(t, test.expected, test.target)
},
}
},
},
{
desc: "into map of uint to string",
input: `1 = "a"`,
gen: func() test {
return test{
target: &map[uint]string{},
expected: &map[uint]string{1: "a"},
assert: func(t *testing.T, test test) {
assert.Equal(t, test.expected, test.target)
},
}
},
},
{
desc: "into map of uint8 to string",
input: `1 = "a"`,
gen: func() test {
return test{
target: &map[uint8]string{},
expected: &map[uint8]string{1: "a"},
assert: func(t *testing.T, test test) {
assert.Equal(t, test.expected, test.target)
},
}
},
},
{
desc: "into map of uint64 to string",
input: `1 = "a"`,
gen: func() test {
return test{
target: &map[uint64]string{},
expected: &map[uint64]string{1: "a"},
assert: func(t *testing.T, test test) {
assert.Equal(t, test.expected, test.target)
},
}
},
},
{
desc: "into map of uint with invalid key",
input: `-1 = "a"`,
gen: func() test {
return test{
target: &map[uint]string{},
err: true,
}
},
},
{
desc: "into map of float64 to string",
input: `'1.01' = "a"`,
gen: func() test {
return test{
target: &map[float64]string{},
expected: &map[float64]string{1.01: "a"},
assert: func(t *testing.T, test test) {
assert.Equal(t, test.expected, test.target)
},
}
},
},
{
desc: "into map of float64 with invalid key",
input: `key = "a"`,
gen: func() test {
return test{
target: &map[float64]string{},
err: true,
}
},
},
{
desc: "into map of float32 to string",
input: `'1.01' = "a"`,
gen: func() test {
return test{
target: &map[float32]string{},
expected: &map[float32]string{1.01: "a"},
assert: func(t *testing.T, test test) {
assert.Equal(t, test.expected, test.target)
},
}
},
},
{
desc: "into map of float32 with invalid key",
input: `key = "a"`,
gen: func() test {
return test{
target: &map[float32]string{},
err: true,
}
},
},
{
desc: "invalid map key type",
input: `1 = "a"`,
gen: func() test {
return test{
target: &map[struct{ int }]string{},
err: true,
}
},
},
}
for _, e := range examples {
@@ -1959,9 +2093,9 @@ B = "data"`,
if err == nil {
t.Log("=>", test.target)
}
require.Error(t, err)
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NoError(t, err)
if test.assert != nil {
test.assert(t, test)
} else {
@@ -2023,14 +2157,14 @@ func TestUnmarshalOverflows(t *testing.T) {
doc := "A = " + v
err := toml.Unmarshal([]byte(doc), e.t)
t.Log("input:", doc)
require.Error(t, err)
assert.Error(t, err)
})
}
t.Run(fmt.Sprintf("%T ok", e.t), func(t *testing.T) {
doc := "A = 1"
err := toml.Unmarshal([]byte(doc), e.t)
t.Log("input:", doc)
require.NoError(t, err)
assert.NoError(t, err)
})
}
}
@@ -2044,9 +2178,9 @@ func TestUnmarshalErrors(t *testing.T) {
s := mystruct{}
err := toml.Unmarshal([]byte(data), &s)
require.Error(t, err)
assert.Error(t, err)
require.Equal(t, "toml: cannot decode TOML integer into struct field toml_test.mystruct.Bar of type string", err.Error())
assert.Equal(t, "toml: cannot decode TOML integer into struct field toml_test.mystruct.Bar of type string", err.Error())
}
func TestUnmarshalStringInvalidStructField(t *testing.T) {
@@ -2068,16 +2202,16 @@ port = "bad"
file := strings.NewReader(data)
err := toml.NewDecoder(file).Decode(&cfg)
require.Error(t, err)
assert.Error(t, err)
x := err.(*toml.DecodeError)
require.Equal(t, "toml: cannot decode TOML string into struct field toml_test.Server.Port of type int", x.Error())
assert.Equal(t, "toml: cannot decode TOML string into struct field toml_test.Server.Port of type int", x.Error())
expected := `1| [server]
2| path = "/my/path"
3| port = "bad"
| ~~~~~ cannot decode TOML string into struct field toml_test.Server.Port of type int`
require.Equal(t, expected, x.String())
assert.Equal(t, expected, x.String())
}
func TestUnmarshalIntegerInvalidStructField(t *testing.T) {
@@ -2099,38 +2233,38 @@ port = 50
file := strings.NewReader(data)
err := toml.NewDecoder(file).Decode(&cfg)
require.Error(t, err)
assert.Error(t, err)
x := err.(*toml.DecodeError)
require.Equal(t, "toml: cannot decode TOML integer into struct field toml_test.Server.Path of type string", x.Error())
assert.Equal(t, "toml: cannot decode TOML integer into struct field toml_test.Server.Path of type string", x.Error())
expected := `1| [server]
2| path = 100
| ~~~ cannot decode TOML integer into struct field toml_test.Server.Path of type string
3| port = 50`
require.Equal(t, expected, x.String())
assert.Equal(t, expected, x.String())
}
func TestUnmarshalInvalidTarget(t *testing.T) {
x := "foo"
err := toml.Unmarshal([]byte{}, x)
require.Error(t, err)
assert.Error(t, err)
var m *map[string]interface{}
err = toml.Unmarshal([]byte{}, m)
require.Error(t, err)
assert.Error(t, err)
}
func TestUnmarshalFloat32(t *testing.T) {
t.Run("fits", func(t *testing.T) {
doc := "A = 1.2"
err := toml.Unmarshal([]byte(doc), &map[string]float32{})
require.NoError(t, err)
assert.NoError(t, err)
})
t.Run("overflows", func(t *testing.T) {
doc := "A = 4.40282346638528859811704183484516925440e+38"
err := toml.Unmarshal([]byte(doc), &map[string]float32{})
require.Error(t, err)
assert.Error(t, err)
})
}
@@ -2222,7 +2356,7 @@ bar = 42`,
x = &struct{}{}
}
err := d.Decode(x)
require.NoError(t, err)
assert.NoError(t, err)
})
})
}
@@ -2244,15 +2378,15 @@ val1 = "test1"
}
err := toml.Unmarshal(configFile, cfg)
require.NoError(t, err)
require.Equal(t, "test2", cfg.Val2)
assert.NoError(t, err)
assert.Equal(t, "test2", cfg.Val2)
}
func TestIssue287(t *testing.T) {
b := `y=[[{}]]`
v := map[string]interface{}{}
err := toml.Unmarshal([]byte(b), &v)
require.NoError(t, err)
assert.NoError(t, err)
expected := map[string]interface{}{
"y": []interface{}{
@@ -2261,7 +2395,7 @@ func TestIssue287(t *testing.T) {
},
},
}
require.Equal(t, expected, v)
assert.Equal(t, expected, v)
}
type (
@@ -2280,7 +2414,7 @@ name = "decode"
version = "0.1.0"`)
m := Map458{}
err := toml.Unmarshal(s, &m)
require.NoError(t, err)
assert.NoError(t, err)
a := m.A("package")
expected := Slice458{
map[string]interface{}{
@@ -2319,7 +2453,7 @@ func TestIssue484(t *testing.T) {
var cfg Config484
err := toml.Unmarshal(raw, &cfg)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, Config484{
Integers: []Integer484{{1}, {2}, {3}, {100}},
}, cfg)
@@ -2337,7 +2471,7 @@ bar = 2021-04-08
}
ss := new(s)
err := toml.Unmarshal([]byte(data), ss)
require.NoError(t, err)
assert.NoError(t, err)
}
func TestIssue508(t *testing.T) {
@@ -2353,15 +2487,15 @@ func TestIssue508(t *testing.T) {
t1 := text{}
err := toml.Unmarshal(b, &t1)
require.NoError(t, err)
require.Equal(t, "This is a title", t1.head.Title)
assert.NoError(t, err)
assert.Equal(t, "This is a title", t1.head.Title)
}
func TestIssue507(t *testing.T) {
data := []byte{'0', '=', '\n', '0', 'a', 'm', 'e'}
m := map[string]interface{}{}
err := toml.Unmarshal(data, &m)
require.Error(t, err)
assert.Error(t, err)
}
type uuid [16]byte
@@ -2384,8 +2518,8 @@ func TestIssue564(t *testing.T) {
var config Config
err := toml.Unmarshal([]byte(`id = "0818a52b97b94768941ba1172c76cf6c"`), &config)
require.NoError(t, err)
require.Equal(t, uuid{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}, config.ID)
assert.NoError(t, err)
assert.Equal(t, uuid{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}, config.ID)
}
func TestIssue575(t *testing.T) {
@@ -2422,7 +2556,7 @@ xz_hash = "1a48f723fea1f17d786ce6eadd9d00914d38062d28fd9c455ed3c3801905b388"
var dist doc
err := toml.Unmarshal(b, &dist)
require.NoError(t, err)
assert.NoError(t, err)
expected := doc{
Pkg: map[string]pkg{
@@ -2439,60 +2573,60 @@ xz_hash = "1a48f723fea1f17d786ce6eadd9d00914d38062d28fd9c455ed3c3801905b388"
},
}
require.Equal(t, expected, dist)
assert.Equal(t, expected, dist)
}
func TestIssue579(t *testing.T) {
var v interface{}
err := toml.Unmarshal([]byte(`[foo`), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue581(t *testing.T) {
var v interface{}
err := toml.Unmarshal([]byte(`P=[#`), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue585(t *testing.T) {
var v interface{}
err := toml.Unmarshal([]byte(`a=1979-05127T 0`), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue586(t *testing.T) {
var v interface{}
err := toml.Unmarshal([]byte(`a={ `), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue588(t *testing.T) {
var v interface{}
err := toml.Unmarshal([]byte(`a=[1#`), &v)
require.Error(t, err)
assert.Error(t, err)
}
// Support lowercase 'T' and 'Z'
func TestIssue600(t *testing.T) {
var v interface{}
err := toml.Unmarshal([]byte(`a=1979-05-27t00:32:00z`), &v)
require.NoError(t, err)
assert.NoError(t, err)
}
func TestIssue596(t *testing.T) {
var v interface{}
err := toml.Unmarshal([]byte(`a=1979-05-27T90:+2:99`), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue602(t *testing.T) {
var v interface{}
err := toml.Unmarshal([]byte(""), &v)
require.NoError(t, err)
assert.NoError(t, err)
var expected interface{} = map[string]interface{}{}
require.Equal(t, expected, v)
assert.Equal(t, expected, v)
}
func TestIssue623(t *testing.T) {
@@ -2504,31 +2638,31 @@ func TestIssue623(t *testing.T) {
foo = "bar"`
err := toml.Unmarshal([]byte(values), &definition)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue631(t *testing.T) {
v := map[string]interface{}{}
err := toml.Unmarshal([]byte("\"\\b\u007f\"= 2"), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue658(t *testing.T) {
var v map[string]interface{}
err := toml.Unmarshal([]byte("e={b=1,b=4}"), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue662(t *testing.T) {
var v map[string]interface{}
err := toml.Unmarshal([]byte("a=[{b=1,b=2}]"), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue666(t *testing.T) {
var v map[string]interface{}
err := toml.Unmarshal([]byte("a={}\na={}"), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue677(t *testing.T) {
@@ -2552,7 +2686,7 @@ Program = "hugo"
p := tomlParser{}
err := toml.Unmarshal([]byte(doc), &p)
require.NoError(t, err)
assert.NoError(t, err)
expected := tomlParser{
Build: &_tomlJob{
@@ -2564,7 +2698,7 @@ Program = "hugo"
},
},
}
require.Equal(t, expected, p)
assert.Equal(t, expected, p)
}
func TestIssue701(t *testing.T) {
@@ -2598,50 +2732,50 @@ z=0
func TestIssue703(t *testing.T) {
var v interface{}
err := toml.Unmarshal([]byte("[a]\nx.y=0\n[a.x]"), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue708(t *testing.T) {
v := map[string]string{}
err := toml.Unmarshal([]byte("0=\"\"\"\\\r\n\"\"\""), &v)
require.NoError(t, err)
require.Equal(t, map[string]string{"0": ""}, v)
assert.NoError(t, err)
assert.Equal(t, map[string]string{"0": ""}, v)
}
func TestIssue710(t *testing.T) {
v := map[string]toml.LocalTime{}
err := toml.Unmarshal([]byte(`0=00:00:00.0000000000`), &v)
require.NoError(t, err)
require.Equal(t, map[string]toml.LocalTime{"0": {Precision: 9}}, v)
assert.NoError(t, err)
assert.Equal(t, map[string]toml.LocalTime{"0": {Precision: 9}}, v)
v1 := map[string]toml.LocalTime{}
err = toml.Unmarshal([]byte(`0=00:00:00.0000000001`), &v1)
require.NoError(t, err)
require.Equal(t, map[string]toml.LocalTime{"0": {Precision: 9}}, v1)
assert.NoError(t, err)
assert.Equal(t, map[string]toml.LocalTime{"0": {Precision: 9}}, v1)
v2 := map[string]toml.LocalTime{}
err = toml.Unmarshal([]byte(`0=00:00:00.1111111119`), &v2)
require.NoError(t, err)
require.Equal(t, map[string]toml.LocalTime{"0": {Nanosecond: 111111111, Precision: 9}}, v2)
assert.NoError(t, err)
assert.Equal(t, map[string]toml.LocalTime{"0": {Nanosecond: 111111111, Precision: 9}}, v2)
}
func TestIssue715(t *testing.T) {
var v interface{}
err := toml.Unmarshal([]byte("0=+"), &v)
require.Error(t, err)
assert.Error(t, err)
err = toml.Unmarshal([]byte("0=-"), &v)
require.Error(t, err)
assert.Error(t, err)
err = toml.Unmarshal([]byte("0=+A"), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue714(t *testing.T) {
var v interface{}
err := toml.Unmarshal([]byte("0."), &v)
require.Error(t, err)
assert.Error(t, err)
err = toml.Unmarshal([]byte("0={0=0,"), &v)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue772(t *testing.T) {
@@ -2653,14 +2787,14 @@ func TestIssue772(t *testing.T) {
FileHandling `toml:"filehandling"`
}
var defaultConfigFile = []byte(`
defaultConfigFile := []byte(`
[filehandling]
pattern = "reach-masterdev-"`)
config := Config{}
err := toml.Unmarshal(defaultConfigFile, &config)
require.NoError(t, err)
require.Equal(t, "reach-masterdev-", config.FileHandling.FilePattern)
assert.NoError(t, err)
assert.Equal(t, "reach-masterdev-", config.FileHandling.FilePattern)
}
func TestIssue774(t *testing.T) {
@@ -2676,14 +2810,14 @@ func TestIssue774(t *testing.T) {
c.SCP = []ScpData{{Host: "main.domain.com"}}
b, err := toml.Marshal(c)
require.NoError(t, err)
assert.NoError(t, err)
expected := `# Array of Secure Copy Configurations
[[scp]]
Host = 'main.domain.com'
`
require.Equal(t, expected, string(b))
assert.Equal(t, expected, string(b))
}
func TestIssue799(t *testing.T) {
@@ -2699,7 +2833,7 @@ answer = 42
}
err := toml.Unmarshal([]byte(testTOML), &s)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue807(t *testing.T) {
@@ -2713,14 +2847,14 @@ func TestIssue807(t *testing.T) {
var m M
err := toml.Unmarshal([]byte(`name = 'foo'`), &m)
require.NoError(t, err)
require.Equal(t, "foo", m.Name)
assert.NoError(t, err)
assert.Equal(t, "foo", m.Name)
}
func TestIssue850(t *testing.T) {
data := make(map[string]string)
err := toml.Unmarshal([]byte("foo = {}"), &data)
require.Error(t, err)
assert.Error(t, err)
}
func TestIssue851(t *testing.T) {
@@ -2731,11 +2865,11 @@ func TestIssue851(t *testing.T) {
content := "params = {a=\"1\",b=\"2\"}"
var target Target
err := toml.Unmarshal([]byte(content), &target)
require.NoError(t, err)
require.Equal(t, map[string]string{"a": "1", "b": "2"}, target.Params)
assert.NoError(t, err)
assert.Equal(t, map[string]string{"a": "1", "b": "2"}, target.Params)
err = toml.Unmarshal([]byte(content), &target)
require.NoError(t, err)
require.Equal(t, map[string]string{"a": "1", "b": "2"}, target.Params)
assert.NoError(t, err)
assert.Equal(t, map[string]string{"a": "1", "b": "2"}, target.Params)
}
func TestIssue866(t *testing.T) {
@@ -2750,7 +2884,7 @@ func TestIssue866(t *testing.T) {
PipelineMapping map[string]*Pipeline `toml:"pipelines"`
}
var badToml = `
badToml := `
[pipelines.register]
mapping.inst.req = [
["param1", "value1"],
@@ -2768,7 +2902,7 @@ mapping.inst.res = [
t.Fatal("unmarshal failed with mismatch value")
}
var goodTooToml = `
goodTooToml := `
[pipelines.register]
mapping.inst.req = [
["param1", "value1"],
@@ -2783,7 +2917,7 @@ mapping.inst.req = [
t.Fatal("unmarshal failed with mismatch value")
}
var goodToml = `
goodToml := `
[pipelines.register.mapping.inst]
req = [
["param1", "value1"],
@@ -2817,11 +2951,11 @@ fizz = "abc"
blah.a = "def"`)
var cfg config
err := toml.Unmarshal(b, &cfg)
require.NoError(t, err)
assert.NoError(t, err)
require.Equal(t, "abc", cfg.Fizz)
require.Equal(t, "def", cfg.blah.A)
require.Equal(t, "def", cfg.A)
assert.Equal(t, "abc", cfg.Fizz)
assert.Equal(t, "def", cfg.blah.A)
assert.Equal(t, "def", cfg.A)
}
func TestIssue931(t *testing.T) {
@@ -2844,7 +2978,7 @@ func TestIssue931(t *testing.T) {
`)
toml.Unmarshal(b, &its)
require.Equal(t, items{[]item{{"c"}, {"d"}}}, its)
assert.Equal(t, items{[]item{{"c"}, {"d"}}}, its)
}
func TestIssue931Interface(t *testing.T) {
@@ -2865,7 +2999,7 @@ func TestIssue931Interface(t *testing.T) {
`)
toml.Unmarshal(b, &its)
require.Equal(t, items{[]interface{}{item{"Name": "c"}, item{"Name": "d"}}}, its)
assert.Equal(t, items{[]interface{}{item{"Name": "c"}, item{"Name": "d"}}}, its)
}
func TestIssue931SliceInterface(t *testing.T) {
@@ -2891,7 +3025,7 @@ func TestIssue931SliceInterface(t *testing.T) {
`)
toml.Unmarshal(b, &its)
require.Equal(t, items{[]interface{}{item{"Name": "c"}, item{"Name": "d"}}}, its)
assert.Equal(t, items{[]interface{}{item{"Name": "c"}, item{"Name": "d"}}}, its)
}
func TestUnmarshalDecodeErrors(t *testing.T) {
@@ -3330,7 +3464,7 @@ world'`,
t.Run(e.desc, func(t *testing.T) {
m := map[string]interface{}{}
err := toml.Unmarshal([]byte(e.data), &m)
require.Error(t, err)
assert.Error(t, err)
var de *toml.DecodeError
if !errors.As(err, &de) {
@@ -3339,7 +3473,7 @@ world'`,
if e.msg != "" {
t.Log("\n" + de.String())
require.Equal(t, "toml: "+e.msg, de.Error())
assert.Equal(t, "toml: "+e.msg, de.Error())
}
})
}
@@ -3362,7 +3496,7 @@ func TestOmitEmpty(t *testing.T) {
X []elem `toml:",inline"`
}
d := doc{X: []elem{elem{
d := doc{X: []elem{{
Foo: "test",
Inner: inner{
V: "alue",
@@ -3370,9 +3504,9 @@ func TestOmitEmpty(t *testing.T) {
}}}
b, err := toml.Marshal(d)
require.NoError(t, err)
assert.NoError(t, err)
require.Equal(t, "X = [{Foo = 'test', Inner = {V = 'alue'}}]\n", string(b))
assert.Equal(t, "X = [{Foo = 'test', Inner = {V = 'alue'}}]\n", string(b))
}
func TestUnmarshalTags(t *testing.T) {
@@ -3399,8 +3533,8 @@ comma = 'ok'
}
err := toml.Unmarshal([]byte(data), &d)
require.NoError(t, err)
require.Equal(t, expected, d)
assert.NoError(t, err)
assert.Equal(t, expected, d)
}
func TestASCIIControlCharacters(t *testing.T) {
@@ -3431,7 +3565,7 @@ func TestASCIIControlCharacters(t *testing.T) {
t.Helper()
m := map[string]interface{}{}
err := toml.Unmarshal(input, &m)
require.Error(t, err)
assert.Error(t, err)
var de *toml.DecodeError
if !errors.As(err, &de) {
@@ -3533,15 +3667,15 @@ func TestLocalDateTime(t *testing.T) {
doc := `a = ` + e.input
m := map[string]toml.LocalDateTime{}
err := toml.Unmarshal([]byte(doc), &m)
require.NoError(t, err)
assert.NoError(t, err)
actual := m["a"]
golang, err := time.Parse("2006-01-02T15:04:05.999999999", e.input)
require.NoError(t, err)
assert.NoError(t, err)
expected := toml.LocalDateTime{
toml.LocalDate{golang.Year(), int(golang.Month()), golang.Day()},
toml.LocalTime{golang.Hour(), golang.Minute(), golang.Second(), golang.Nanosecond(), e.prec},
}
require.Equal(t, expected, actual)
assert.Equal(t, expected, actual)
})
}
}
@@ -3615,11 +3749,11 @@ func TestUnmarshal_RecursiveTable(t *testing.T) {
foo := Foo{}
err := toml.Unmarshal([]byte(e.input), &foo)
if e.err {
require.Error(t, err)
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NoError(t, err)
j, err := json.Marshal(foo)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, e.expected, string(j))
}
})
@@ -3706,11 +3840,11 @@ func TestUnmarshal_RecursiveTableArray(t *testing.T) {
foo := Foo{}
err := toml.Unmarshal([]byte(e.input), &foo)
if e.err {
require.Error(t, err)
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NoError(t, err)
j, err := json.Marshal(foo)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, e.expected, string(j))
}
})
@@ -3726,8 +3860,8 @@ func TestUnmarshalEmbedNonString(t *testing.T) {
d := doc{}
err := toml.Unmarshal([]byte(`foo = 'bar'`), &d)
require.NoError(t, err)
require.Nil(t, d.Foo)
assert.NoError(t, err)
assert.Equal(t, d.Foo, nil)
}
func TestUnmarshal_Nil(t *testing.T) {
@@ -3763,11 +3897,11 @@ func TestUnmarshal_Nil(t *testing.T) {
foo := Foo{}
err := toml.Unmarshal([]byte(e.input), &foo)
if e.err {
require.Error(t, err)
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NoError(t, err)
j, err := toml.Marshal(foo)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, e.expected, string(j))
}
})
@@ -3785,7 +3919,6 @@ func (k *CustomUnmarshalerKey) UnmarshalTOML(value *unstable.Node) error {
}
k.A = item
return nil
}
func TestUnmarshal_CustomUnmarshaler(t *testing.T) {
@@ -3853,14 +3986,14 @@ foo = "bar"`,
err := decoder.Decode(&foo)
if e.err {
require.Error(t, err)
assert.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, len(foo.Unmarshalers), len(e.expected.Unmarshalers))
assert.NoError(t, err)
assert.Equal(t, len(foo.Unmarshalers), len(e.expected.Unmarshalers))
for i := 0; i < len(foo.Unmarshalers); i++ {
require.Equal(t, foo.Unmarshalers[i], e.expected.Unmarshalers[i])
assert.Equal(t, foo.Unmarshalers[i], e.expected.Unmarshalers[i])
}
require.Equal(t, foo.Foo, e.expected.Foo)
assert.Equal(t, foo.Foo, e.expected.Foo)
}
})
}
+9 -9
View File
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/pelletier/go-toml/v2/internal/assert"
)
func TestParser_AST_Numbers(t *testing.T) {
@@ -141,9 +141,9 @@ func TestParser_AST_Numbers(t *testing.T) {
p.NextExpression()
err := p.Error()
if e.err {
require.Error(t, err)
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NoError(t, err)
expected := astNode{
Kind: KeyValue,
@@ -168,8 +168,8 @@ type (
func compareNode(t *testing.T, e astNode, n *Node) {
t.Helper()
require.Equal(t, e.Kind, n.Kind)
require.Equal(t, e.Data, n.Data)
assert.Equal(t, e.Kind, n.Kind)
assert.Equal(t, e.Data, n.Data)
compareIterator(t, e.Children, n.Children())
}
@@ -341,9 +341,9 @@ func TestParser_AST(t *testing.T) {
p.NextExpression()
err := p.Error()
if e.err {
require.Error(t, err)
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NoError(t, err)
compareNode(t, e.ast, p.Expression())
}
})
@@ -431,9 +431,9 @@ func TestParser_AST_DateTimes(t *testing.T) {
p.NextExpression()
err := p.Error()
if e.err {
require.Error(t, err)
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.NoError(t, err)
expected := astNode{
Kind: KeyValue,