diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 19e92390..6d7b2cb6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -10,7 +10,7 @@ jobs:
test:
strategy:
matrix:
- go-version: [1.9.x, 1.10.x, 1.11.x, 1.12.x, 1.13.x, 1.14.x, 1.15.x, 1.16.x, 1.17.x, 1.18.x, tip]
+ go-version: [1.16.x, 1.17.x, 1.18.x, tip]
full-tests: [false]
include:
- go-version: 1.19.x
@@ -41,7 +41,7 @@ jobs:
if: matrix.full-tests
run: |
curl -sL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh |
- sh -s -- -b $HOME/go/bin v1.49.0
+ sh -s -- -b $HOME/go/bin v1.50.0
echo $PATH
$HOME/go/bin/golangci-lint run --max-issues-per-linter 0 \
--max-same-issues 0 \
@@ -71,16 +71,6 @@ jobs:
GO_TEST_RACE_SAFE_FLAGS="$cover_flags-race-safe.out"
fi
- case ${{ matrix.go-version }} in
- 1.9.x | 1.10.x) # Before go 1.11, go modules are not available
- mkdir -p ../src/github.com/maxatome
- ln -s $(pwd) ../src/github.com/$GITHUB_REPOSITORY
- export GOPATH=$(dirname $(pwd))
- cd $GOPATH/src/github.com/$GITHUB_REPOSITORY
- go get -t ./...
- ;;
- esac
-
export GORACE="halt_on_error=1"
echo "CLASSIC ==========================================="
go test $GO_TEST_FLAGS ./...
diff --git a/.golangci.yml b/.golangci.yml
index bea7c93f..26b4bd73 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,2 +1,2 @@
run:
- go: '1.9'
+ go: '1.16'
diff --git a/README.md b/README.md
index 6206697d..442459a4 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ go-testdeep
**Extremely flexible golang deep comparison, extends the go testing package.**
-Currently supports go 1.9 → 1.19.
+Currently supports go 1.16 → 1.19.
- [Latest news](#latest-news)
- [Synopsis](#synopsis)
@@ -203,7 +203,7 @@ details.**
## Installation
```sh
-$ go get -u github.com/maxatome/go-testdeep
+$ go get github.com/maxatome/go-testdeep
```
diff --git a/helpers/tdhttp/example_test.go b/helpers/tdhttp/example_test.go
index 16ba3d11..7f19a3e4 100644
--- a/helpers/tdhttp/example_test.go
+++ b/helpers/tdhttp/example_test.go
@@ -10,7 +10,7 @@ import (
"encoding/json"
"encoding/xml"
"fmt"
- "io/ioutil"
+ "io"
"net/http"
"net/url"
"strconv"
@@ -103,7 +103,7 @@ func Example() {
return
}
case "application/x-www-form-urlencoded":
- b, err := ioutil.ReadAll(req.Body)
+ b, err := io.ReadAll(req.Body)
if err != nil {
http.Error(w, "Bad request", http.StatusBadRequest)
return
diff --git a/helpers/tdhttp/internal/response_test.go b/helpers/tdhttp/internal/response_test.go
index 2340aa74..cf4b85b3 100644
--- a/helpers/tdhttp/internal/response_test.go
+++ b/helpers/tdhttp/internal/response_test.go
@@ -8,7 +8,7 @@ package internal_test
import (
"bytes"
- "io/ioutil"
+ "io"
"net/http"
"testing"
@@ -28,7 +28,7 @@ func newResponse(body string) *http.Response {
"A": []string{"foo"},
"B": []string{"bar"},
},
- Body: ioutil.NopCloser(bytes.NewBufferString(body)),
+ Body: io.NopCloser(bytes.NewBufferString(body)),
}
}
diff --git a/helpers/tdhttp/multipart_test.go b/helpers/tdhttp/multipart_test.go
index a89229dc..728bb58a 100644
--- a/helpers/tdhttp/multipart_test.go
+++ b/helpers/tdhttp/multipart_test.go
@@ -9,7 +9,6 @@ package tdhttp_test
import (
"bytes"
"io"
- "io/ioutil"
"mime/multipart"
"net/http"
"os"
@@ -38,7 +37,7 @@ func TestMultipartPart(t *testing.T) {
}
// Full empty
- b, err := ioutil.ReadAll(&tdhttp.MultipartPart{})
+ b, err := io.ReadAll(&tdhttp.MultipartPart{})
assert.CmpNoError(err)
assert.Len(b, 0)
@@ -143,11 +142,11 @@ hey!
yo!`)
// With file name
- dir, err := ioutil.TempDir("", "multipart")
+ dir, err := os.MkdirTemp("", "multipart")
require.CmpNoError(err)
defer os.RemoveAll(dir)
filePath := filepath.Join(dir, "body.txt")
- require.CmpNoError(ioutil.WriteFile(filePath, []byte("hey!\nyo!"), 0666))
+ require.CmpNoError(os.WriteFile(filePath, []byte("hey!\nyo!"), 0666))
check(tdhttp.NewMultipartPartFile("pipo", filePath),
`Content-Disposition: form-data; name="pipo"; filename="body.txt"%CR
@@ -165,7 +164,7 @@ hey!
yo!`)
// Error during os.Open
- _, err = ioutil.ReadAll(
+ _, err = io.ReadAll(
tdhttp.NewMultipartPartFile("pipo", filepath.Join(dir, "unknown.xxx")),
)
assert.CmpError(err)
@@ -174,11 +173,11 @@ yo!`)
func TestMultipartBody(t *testing.T) {
assert, require := td.AssertRequire(t)
- dir, err := ioutil.TempDir("", "multipart")
+ dir, err := os.MkdirTemp("", "multipart")
require.CmpNoError(err)
defer os.RemoveAll(dir)
filePath := filepath.Join(dir, "body.txt")
- require.CmpNoError(ioutil.WriteFile(filePath, []byte("hey!\nyo!"), 0666))
+ require.CmpNoError(os.WriteFile(filePath, []byte("hey!\nyo!"), 0666))
for _, boundary := range []struct{ in, out string }{
{in: "", out: "go-testdeep-42"},
@@ -251,7 +250,7 @@ Content-Disposition: form-data; name="io"%CR
if assert.CmpNoError(err) {
assert.Cmp(part.FormName(), "pipo")
assert.Cmp(part.FileName(), "")
- assert.Smuggle(part, ioutil.ReadAll, td.String("pipo!\nbingo!"))
+ assert.Smuggle(part, io.ReadAll, td.String("pipo!\nbingo!"))
}
// 1
@@ -259,7 +258,7 @@ Content-Disposition: form-data; name="io"%CR
if assert.CmpNoError(err) {
assert.Cmp(part.FormName(), "file")
assert.Cmp(part.FileName(), "body.txt")
- assert.Smuggle(part, ioutil.ReadAll, td.String("hey!\nyo!"))
+ assert.Smuggle(part, io.ReadAll, td.String("hey!\nyo!"))
}
// 2
@@ -267,7 +266,7 @@ Content-Disposition: form-data; name="io"%CR
if assert.CmpNoError(err) {
assert.Cmp(part.FormName(), "string")
assert.Cmp(part.FileName(), "")
- assert.Smuggle(part, ioutil.ReadAll, td.String("zip!\nzap!"))
+ assert.Smuggle(part, io.ReadAll, td.String("zip!\nzap!"))
}
// 3
@@ -275,7 +274,7 @@ Content-Disposition: form-data; name="io"%CR
if assert.CmpNoError(err) {
assert.Cmp(part.FormName(), "bytes")
assert.Cmp(part.FileName(), "")
- assert.Smuggle(part, ioutil.ReadAll, td.String(`{"ola":"hello"}`))
+ assert.Smuggle(part, io.ReadAll, td.String(`{"ola":"hello"}`))
}
// 4
@@ -283,7 +282,7 @@ Content-Disposition: form-data; name="io"%CR
if assert.CmpNoError(err) {
assert.Cmp(part.FormName(), "io")
assert.Cmp(part.FileName(), "")
- assert.Smuggle(part, ioutil.ReadAll, td.String(""))
+ assert.Smuggle(part, io.ReadAll, td.String(""))
}
// 5
@@ -291,7 +290,7 @@ Content-Disposition: form-data; name="io"%CR
if assert.CmpNoError(err) {
assert.Cmp(part.FormName(), "")
assert.Cmp(part.FileName(), "")
- assert.Smuggle(part, ioutil.ReadAll, td.String(""))
+ assert.Smuggle(part, io.ReadAll, td.String(""))
}
// EOF
diff --git a/helpers/tdhttp/request_test.go b/helpers/tdhttp/request_test.go
index e0242cab..cc49c43e 100644
--- a/helpers/tdhttp/request_test.go
+++ b/helpers/tdhttp/request_test.go
@@ -7,7 +7,7 @@
package tdhttp_test
import (
- "io/ioutil"
+ "io"
"net/http"
"net/url"
"testing"
@@ -251,7 +251,7 @@ func TestNewRequest(tt *testing.T) {
td.StructFields{
"URL": td.String("/path"),
"Body": td.Smuggle(
- ioutil.ReadAll,
+ io.ReadAll,
[]byte("param1=val1¶m1=val2¶m2=zip"),
),
}))
@@ -336,7 +336,7 @@ func TestNewJSONRequest(tt *testing.T) {
t.String(req.Header.Get("Foo"), "Bar")
t.String(req.Header.Get("Zip"), "Test")
- body, err := ioutil.ReadAll(req.Body)
+ body, err := io.ReadAll(req.Body)
if t.CmpNoError(err, "read request body") {
t.String(string(body), `{"name":"Bob"}`)
}
@@ -445,7 +445,7 @@ func TestNewXMLRequest(tt *testing.T) {
t.String(req.Header.Get("Foo"), "Bar")
t.String(req.Header.Get("Zip"), "Test")
- body, err := ioutil.ReadAll(req.Body)
+ body, err := io.ReadAll(req.Body)
if t.CmpNoError(err, "read request body") {
t.String(string(body), `Bob`)
}
diff --git a/helpers/tdsuite/suite.go b/helpers/tdsuite/suite.go
index d777f79c..da6f219a 100644
--- a/helpers/tdsuite/suite.go
+++ b/helpers/tdsuite/suite.go
@@ -24,10 +24,9 @@ var tType = reflect.TypeOf((*td.T)(nil))
// tests suite, Setup method is called once before any test runs. If
// Setup returns an error, the tests suite aborts: no tests are run.
//
-// Starting go1.14, t.Cleanup() can be called in Setup method. It can
-// replace the definition of a [Destroy] method. It can also be used
-// together, in this case cleanup registered functions are called
-// after [Destroy].
+// t.Cleanup() can be called in Setup method. It can replace the
+// definition of a [Destroy] method. It can also be used together, in
+// this case cleanup registered functions are called after [Destroy].
type Setup interface {
Setup(t *td.T) error
}
@@ -37,10 +36,9 @@ type Setup interface {
// itself. If PreTest returns an error, the subtest aborts: the test
// is not run.
//
-// Starting go1.14, t.Cleanup() can be called in PreTest method. It can
-// replace the definition of a [PostTest] method. It can also be used
-// together, in this case cleanup registered functions are called
-// after [PostTest].
+// t.Cleanup() can be called in PreTest method. It can replace the
+// definition of a [PostTest] method. It can also be used together, in
+// this case cleanup registered functions are called after [PostTest].
type PreTest interface {
PreTest(t *td.T, testName string) error
}
diff --git a/helpers/tdsuite/suite_go114_test.go b/helpers/tdsuite/suite_go114_test.go
deleted file mode 100644
index a04fc715..00000000
--- a/helpers/tdsuite/suite_go114_test.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2021, Maxime Soulé
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-//go:build go1.14
-// +build go1.14
-
-package tdsuite_test
-
-import (
- "testing"
-
- "github.com/maxatome/go-testdeep/helpers/tdsuite"
- "github.com/maxatome/go-testdeep/td"
-)
-
-// FullCleanup has tests and all possible hooks.
-type FullCleanup struct{ base }
-
-func (f *FullCleanup) Setup(t *td.T) error { f.rec(); return nil }
-func (f *FullCleanup) PreTest(t *td.T, tn string) error {
- f.rec(tn)
- t.Cleanup(func() { f.rec(tn) })
- return nil
-}
-
-func (f *FullCleanup) PostTest(t *td.T, tn string) error {
- f.rec(tn)
- t.Cleanup(func() { f.rec(tn) })
- return nil
-}
-
-func (f *FullCleanup) BetweenTests(t *td.T, prev, next string) error {
- f.rec(prev, next)
- return nil
-}
-func (f *FullCleanup) Destroy(t *td.T) error { f.rec(); return nil }
-
-func (f *FullCleanup) Test1(t *td.T) {
- f.rec()
- t.Cleanup(func() { f.rec() })
-}
-
-func (f *FullCleanup) Test2(assert *td.T, require *td.T) {
- f.rec()
- assert.Cleanup(func() { f.rec() })
-}
-
-func (f *FullCleanup) Test3(t *td.T) {
- f.rec()
- t.Cleanup(func() { f.rec() })
-}
-func (f *FullCleanup) Testimony(t *td.T) {} // not a test method
-
-var (
- _ tdsuite.Setup = (*FullCleanup)(nil)
- _ tdsuite.PreTest = (*FullCleanup)(nil)
- _ tdsuite.PostTest = (*FullCleanup)(nil)
- _ tdsuite.BetweenTests = (*FullCleanup)(nil)
- _ tdsuite.Destroy = (*FullCleanup)(nil)
-)
-
-func TestRunCleanup(t *testing.T) {
- t.Run("Full", func(t *testing.T) {
- suite := FullCleanup{}
- td.CmpTrue(t, tdsuite.Run(t, &suite))
- ok := td.Cmp(t, suite.calls, []string{
- "Setup",
- /**/ "PreTest+Test1",
- /**/ "Test1",
- /**/ "PostTest+Test1",
- /**/ "PostTest.Cleanup+Test1",
- /**/ "Test1.Cleanup",
- /**/ "PreTest.Cleanup+Test1",
- "BetweenTests+Test1+Test2",
- /**/ "PreTest+Test2",
- /**/ "Test2",
- /**/ "PostTest+Test2",
- /**/ "PostTest.Cleanup+Test2",
- /**/ "Test2.Cleanup",
- /**/ "PreTest.Cleanup+Test2",
- "BetweenTests+Test2+Test3",
- /**/ "PreTest+Test3",
- /**/ "Test3",
- /**/ "PostTest+Test3",
- /**/ "PostTest.Cleanup+Test3",
- /**/ "Test3.Cleanup",
- /**/ "PreTest.Cleanup+Test3",
- "Destroy",
- })
- if !ok {
- for _, c := range suite.calls {
- switch c[0] {
- case 'S', 'B', 'D':
- t.Log(c)
- default:
- t.Log(" ", c)
- }
- }
- }
- })
-}
diff --git a/helpers/tdsuite/suite_test.go b/helpers/tdsuite/suite_test.go
index 93f37c86..df35c885 100644
--- a/helpers/tdsuite/suite_test.go
+++ b/helpers/tdsuite/suite_test.go
@@ -737,3 +737,90 @@ func TestRunErrors(t *testing.T) {
})
})
}
+
+// FullCleanup has tests and all possible hooks.
+type FullCleanup struct{ base }
+
+func (f *FullCleanup) Setup(t *td.T) error { f.rec(); return nil }
+func (f *FullCleanup) PreTest(t *td.T, tn string) error {
+ f.rec(tn)
+ t.Cleanup(func() { f.rec(tn) })
+ return nil
+}
+
+func (f *FullCleanup) PostTest(t *td.T, tn string) error {
+ f.rec(tn)
+ t.Cleanup(func() { f.rec(tn) })
+ return nil
+}
+
+func (f *FullCleanup) BetweenTests(t *td.T, prev, next string) error {
+ f.rec(prev, next)
+ return nil
+}
+func (f *FullCleanup) Destroy(t *td.T) error { f.rec(); return nil }
+
+func (f *FullCleanup) Test1(t *td.T) {
+ f.rec()
+ t.Cleanup(func() { f.rec() })
+}
+
+func (f *FullCleanup) Test2(assert *td.T, require *td.T) {
+ f.rec()
+ assert.Cleanup(func() { f.rec() })
+}
+
+func (f *FullCleanup) Test3(t *td.T) {
+ f.rec()
+ t.Cleanup(func() { f.rec() })
+}
+func (f *FullCleanup) Testimony(t *td.T) {} // not a test method
+
+var (
+ _ tdsuite.Setup = (*FullCleanup)(nil)
+ _ tdsuite.PreTest = (*FullCleanup)(nil)
+ _ tdsuite.PostTest = (*FullCleanup)(nil)
+ _ tdsuite.BetweenTests = (*FullCleanup)(nil)
+ _ tdsuite.Destroy = (*FullCleanup)(nil)
+)
+
+func TestRunCleanup(t *testing.T) {
+ t.Run("Full", func(t *testing.T) {
+ suite := FullCleanup{}
+ td.CmpTrue(t, tdsuite.Run(t, &suite))
+ ok := td.Cmp(t, suite.calls, []string{
+ "Setup",
+ /**/ "PreTest+Test1",
+ /**/ "Test1",
+ /**/ "PostTest+Test1",
+ /**/ "PostTest.Cleanup+Test1",
+ /**/ "Test1.Cleanup",
+ /**/ "PreTest.Cleanup+Test1",
+ "BetweenTests+Test1+Test2",
+ /**/ "PreTest+Test2",
+ /**/ "Test2",
+ /**/ "PostTest+Test2",
+ /**/ "PostTest.Cleanup+Test2",
+ /**/ "Test2.Cleanup",
+ /**/ "PreTest.Cleanup+Test2",
+ "BetweenTests+Test2+Test3",
+ /**/ "PreTest+Test3",
+ /**/ "Test3",
+ /**/ "PostTest+Test3",
+ /**/ "PostTest.Cleanup+Test3",
+ /**/ "Test3.Cleanup",
+ /**/ "PreTest.Cleanup+Test3",
+ "Destroy",
+ })
+ if !ok {
+ for _, c := range suite.calls {
+ switch c[0] {
+ case 'S', 'B', 'D':
+ t.Log(c)
+ default:
+ t.Log(" ", c)
+ }
+ }
+ }
+ })
+}
diff --git a/helpers/tdutil/map.go b/helpers/tdutil/map.go
index fda51dfa..4c7778f5 100644
--- a/helpers/tdutil/map.go
+++ b/helpers/tdutil/map.go
@@ -9,6 +9,8 @@ package tdutil
import (
"reflect"
"sort"
+
+ "github.com/maxatome/go-testdeep/internal/visited"
)
// MapSortedKeys returns a slice of all sorted keys of map m. It
@@ -18,3 +20,72 @@ func MapSortedKeys(m reflect.Value) []reflect.Value {
sort.Sort(SortableValues(ks))
return ks
}
+
+type kv struct {
+ key reflect.Value
+ value reflect.Value
+}
+
+type kvSlice struct {
+ v visited.Visited
+ s []kv
+}
+
+func newKvSlice(l int) *kvSlice {
+ s := kvSlice{}
+ if l > 0 {
+ s.s = make([]kv, 0, l)
+ if l > 1 {
+ s.v = visited.NewVisited()
+ }
+ }
+ return &s
+}
+
+func (s *kvSlice) Len() int { return len(s.s) }
+func (s *kvSlice) Less(i, j int) bool {
+ return cmp(s.v, s.s[i].key, s.s[j].key) < 0
+}
+func (s *kvSlice) Swap(i, j int) { s.s[i], s.s[j] = s.s[j], s.s[i] }
+
+// MapEach calls fn for each key/value pair of map m. If fn
+// returns false, it will not be called again.
+func MapEach(m reflect.Value, fn func(k, v reflect.Value) bool) bool {
+ kvs := newKvSlice(m.Len())
+ iter := m.MapRange()
+ for iter.Next() {
+ kvs.s = append(kvs.s, kv{key: iter.Key(), value: iter.Value()})
+ }
+ sort.Sort(kvs)
+
+ for _, kv := range kvs.s {
+ if !fn(kv.key, kv.value) {
+ return false
+ }
+ }
+ return true
+}
+
+// MapEachValue calls fn for each value of map m. If fn returns
+// false, it will not be called again.
+func MapEachValue(m reflect.Value, fn func(k reflect.Value) bool) bool {
+ iter := m.MapRange()
+ for iter.Next() {
+ if !fn(iter.Value()) {
+ return false
+ }
+ }
+ return true
+}
+
+// MapSortedValues returns a slice of all sorted values of map m. It
+// panics if m's [reflect.Kind] is not [reflect.Map].
+func MapSortedValues(m reflect.Value) []reflect.Value {
+ vs := make([]reflect.Value, 0, m.Len())
+ iter := m.MapRange()
+ for iter.Next() {
+ vs = append(vs, iter.Value())
+ }
+ sort.Sort(SortableValues(vs))
+ return vs
+}
diff --git a/helpers/tdutil/map_go112.go b/helpers/tdutil/map_go112.go
deleted file mode 100644
index e89101d8..00000000
--- a/helpers/tdutil/map_go112.go
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2018, Maxime Soulé
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-//go:build go1.12
-// +build go1.12
-
-package tdutil
-
-import (
- "reflect"
- "sort"
-
- "github.com/maxatome/go-testdeep/internal/visited"
-)
-
-type kv struct {
- key reflect.Value
- value reflect.Value
-}
-
-type kvSlice struct {
- v visited.Visited
- s []kv
-}
-
-func newKvSlice(l int) *kvSlice {
- s := kvSlice{}
- if l > 0 {
- s.s = make([]kv, 0, l)
- if l > 1 {
- s.v = visited.NewVisited()
- }
- }
- return &s
-}
-
-func (s *kvSlice) Len() int { return len(s.s) }
-func (s *kvSlice) Less(i, j int) bool {
- return cmp(s.v, s.s[i].key, s.s[j].key) < 0
-}
-func (s *kvSlice) Swap(i, j int) { s.s[i], s.s[j] = s.s[j], s.s[i] }
-
-// MapEach calls fn for each key/value pair of map m. If fn
-// returns false, it will not be called again.
-func MapEach(m reflect.Value, fn func(k, v reflect.Value) bool) bool {
- kvs := newKvSlice(m.Len())
- iter := m.MapRange()
- for iter.Next() {
- kvs.s = append(kvs.s, kv{key: iter.Key(), value: iter.Value()})
- }
- sort.Sort(kvs)
-
- for _, kv := range kvs.s {
- if !fn(kv.key, kv.value) {
- return false
- }
- }
- return true
-}
-
-// MapEachValue calls fn for each value of map m. If fn returns
-// false, it will not be called again.
-func MapEachValue(m reflect.Value, fn func(k reflect.Value) bool) bool {
- iter := m.MapRange()
- for iter.Next() {
- if !fn(iter.Value()) {
- return false
- }
- }
- return true
-}
-
-// MapSortedValues returns a slice of all sorted values of map m. It
-// panics if m's [reflect.Kind] is not [reflect.Map].
-func MapSortedValues(m reflect.Value) []reflect.Value {
- vs := make([]reflect.Value, 0, m.Len())
- iter := m.MapRange()
- for iter.Next() {
- vs = append(vs, iter.Value())
- }
- sort.Sort(SortableValues(vs))
- return vs
-}
diff --git a/helpers/tdutil/map_other.go b/helpers/tdutil/map_other.go
deleted file mode 100644
index a8459424..00000000
--- a/helpers/tdutil/map_other.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2018, Maxime Soulé
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-//go:build !go1.12
-// +build !go1.12
-
-package tdutil
-
-import (
- "reflect"
- "sort"
-)
-
-// MapEach calls fn for each key/value pair of map m. If fn
-// returns false, it will not be called again.
-func MapEach(m reflect.Value, fn func(k, v reflect.Value) bool) bool {
- ks := MapSortedKeys(m)
- for _, vkey := range ks {
- if !fn(vkey, m.MapIndex(vkey)) {
- return false
- }
- }
- return true
-}
-
-// MapEachValue calls fn for each value of map m. If fn returns
-// false, it will not be called again.
-func MapEachValue(m reflect.Value, fn func(k reflect.Value) bool) bool {
- for _, vkey := range m.MapKeys() {
- if !fn(m.MapIndex(vkey)) {
- return false
- }
- }
- return true
-}
-
-// MapSortedValues returns a slice of all sorted values of map m. It
-// panics if m's [reflect.Kind] is not [reflect.Map].
-func MapSortedValues(m reflect.Value) []reflect.Value {
- vs := make([]reflect.Value, 0, m.Len())
- for _, vkey := range m.MapKeys() {
- vs = append(vs, m.MapIndex(vkey))
- }
- sort.Sort(SortableValues(vs))
- return vs
-}
diff --git a/helpers/tdutil/map_go112_test.go b/helpers/tdutil/map_private_test.go
similarity index 97%
rename from helpers/tdutil/map_go112_test.go
rename to helpers/tdutil/map_private_test.go
index c131fbf0..983a4b69 100644
--- a/helpers/tdutil/map_go112_test.go
+++ b/helpers/tdutil/map_private_test.go
@@ -4,9 +4,6 @@
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.
-//go:build go1.12
-// +build go1.12
-
package tdutil
import (
diff --git a/helpers/tdutil/name.go b/helpers/tdutil/name.go
index 210eaa8c..7e6fc777 100644
--- a/helpers/tdutil/name.go
+++ b/helpers/tdutil/name.go
@@ -7,7 +7,6 @@
package tdutil
import (
- "bytes"
"fmt"
"io"
"strings"
@@ -22,7 +21,7 @@ func BuildTestName(args ...any) string {
return ""
}
- var b bytes.Buffer
+ var b strings.Builder
FbuildTestName(&b, args...)
return b.String()
}
diff --git a/internal/ctxerr/op_error.go b/internal/ctxerr/op_error.go
index 31e92884..ea674d64 100644
--- a/internal/ctxerr/op_error.go
+++ b/internal/ctxerr/op_error.go
@@ -7,9 +7,9 @@
package ctxerr
import (
- "bytes"
"fmt"
"reflect"
+ "strings"
"github.com/maxatome/go-testdeep/internal/types"
)
@@ -17,7 +17,7 @@ import (
// OpBadUsage returns a string to notice the user he passed a bad
// parameter to an operator constructor.
func OpBadUsage(op, usage string, param any, pos int, kind bool) *Error {
- var b bytes.Buffer
+ var b strings.Builder
fmt.Fprintf(&b, "usage: %s%s, but received ", op, usage)
if param == nil {
diff --git a/internal/json/parser_go113_test.go b/internal/json/parser_go113_test.go
deleted file mode 100644
index e7000d16..00000000
--- a/internal/json/parser_go113_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2022, Maxime Soulé
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-//go:build go1.13
-// +build go1.13
-
-package json_test
-
-import (
- "testing"
-)
-
-func TestJSON_go113(t *testing.T) {
- // Extend to golang 1.13 accepted numbers
-
- // as int64
- checkJSON(t, `4_2`, `42`)
- checkJSON(t, `+4_2`, `42`)
- checkJSON(t, `-4_2`, `-42`)
-
- checkJSON(t, `0b101010`, `42`)
- checkJSON(t, `-0b101010`, `-42`)
- checkJSON(t, `+0b101010`, `42`)
-
- checkJSON(t, `0b10_1010`, `42`)
- checkJSON(t, `-0b_10_1010`, `-42`)
- checkJSON(t, `+0b10_10_10`, `42`)
-
- checkJSON(t, `0B101010`, `42`)
- checkJSON(t, `-0B101010`, `-42`)
- checkJSON(t, `+0B101010`, `42`)
-
- checkJSON(t, `0B10_1010`, `42`)
- checkJSON(t, `-0B_10_1010`, `-42`)
- checkJSON(t, `+0B10_10_10`, `42`)
-
- checkJSON(t, `0_600`, `384`)
- checkJSON(t, `-0_600`, `-384`)
- checkJSON(t, `+0_600`, `384`)
-
- checkJSON(t, `0o600`, `384`)
- checkJSON(t, `0o_600`, `384`)
- checkJSON(t, `-0o600`, `-384`)
- checkJSON(t, `-0o6_00`, `-384`)
- checkJSON(t, `+0o600`, `384`)
- checkJSON(t, `+0o60_0`, `384`)
-
- checkJSON(t, `0O600`, `384`)
- checkJSON(t, `0O_600`, `384`)
- checkJSON(t, `-0O600`, `-384`)
- checkJSON(t, `-0O6_00`, `-384`)
- checkJSON(t, `+0O600`, `384`)
- checkJSON(t, `+0O60_0`, `384`)
-
- checkJSON(t, `0xBad_Face`, `195951310`)
- checkJSON(t, `-0x_Bad_Face`, `-195951310`)
- checkJSON(t, `+0xBad_Face`, `195951310`)
-
- checkJSON(t, `0XBad_Face`, `195951310`)
- checkJSON(t, `-0X_Bad_Face`, `-195951310`)
- checkJSON(t, `+0XBad_Face`, `195951310`)
-
- // as float64
- checkJSON(t, `0_600.123`, `600.123`) // float64 can not be an octal number
- checkJSON(t, `1_5.`, `15`)
- checkJSON(t, `0.15e+0_2`, `15`)
- checkJSON(t, `0x1p-2`, `0.25`)
- checkJSON(t, `0x2.p10`, `2048`)
- checkJSON(t, `0x1.Fp+0`, `1.9375`)
- checkJSON(t, `0X.8p-0`, `0.5`)
- checkJSON(t, `0X_1FFFP-16`, `0.1249847412109375`)
-}
diff --git a/internal/json/parser_test.go b/internal/json/parser_test.go
index 88901e7c..0f85bd82 100644
--- a/internal/json/parser_test.go
+++ b/internal/json/parser_test.go
@@ -128,6 +128,64 @@ func TestJSON(t *testing.T) {
checkJSON(t, `0600.`, `600`) // float64 can not be an octal number
checkJSON(t, `.25`, `0.25`)
checkJSON(t, `+123.`, `123`)
+
+ // Extend to golang 1.13 accepted numbers
+ // as int64
+ checkJSON(t, `4_2`, `42`)
+ checkJSON(t, `+4_2`, `42`)
+ checkJSON(t, `-4_2`, `-42`)
+
+ checkJSON(t, `0b101010`, `42`)
+ checkJSON(t, `-0b101010`, `-42`)
+ checkJSON(t, `+0b101010`, `42`)
+
+ checkJSON(t, `0b10_1010`, `42`)
+ checkJSON(t, `-0b_10_1010`, `-42`)
+ checkJSON(t, `+0b10_10_10`, `42`)
+
+ checkJSON(t, `0B101010`, `42`)
+ checkJSON(t, `-0B101010`, `-42`)
+ checkJSON(t, `+0B101010`, `42`)
+
+ checkJSON(t, `0B10_1010`, `42`)
+ checkJSON(t, `-0B_10_1010`, `-42`)
+ checkJSON(t, `+0B10_10_10`, `42`)
+
+ checkJSON(t, `0_600`, `384`)
+ checkJSON(t, `-0_600`, `-384`)
+ checkJSON(t, `+0_600`, `384`)
+
+ checkJSON(t, `0o600`, `384`)
+ checkJSON(t, `0o_600`, `384`)
+ checkJSON(t, `-0o600`, `-384`)
+ checkJSON(t, `-0o6_00`, `-384`)
+ checkJSON(t, `+0o600`, `384`)
+ checkJSON(t, `+0o60_0`, `384`)
+
+ checkJSON(t, `0O600`, `384`)
+ checkJSON(t, `0O_600`, `384`)
+ checkJSON(t, `-0O600`, `-384`)
+ checkJSON(t, `-0O6_00`, `-384`)
+ checkJSON(t, `+0O600`, `384`)
+ checkJSON(t, `+0O60_0`, `384`)
+
+ checkJSON(t, `0xBad_Face`, `195951310`)
+ checkJSON(t, `-0x_Bad_Face`, `-195951310`)
+ checkJSON(t, `+0xBad_Face`, `195951310`)
+
+ checkJSON(t, `0XBad_Face`, `195951310`)
+ checkJSON(t, `-0X_Bad_Face`, `-195951310`)
+ checkJSON(t, `+0XBad_Face`, `195951310`)
+
+ // as float64
+ checkJSON(t, `0_600.123`, `600.123`) // float64 can not be an octal number
+ checkJSON(t, `1_5.`, `15`)
+ checkJSON(t, `0.15e+0_2`, `15`)
+ checkJSON(t, `0x1p-2`, `0.25`)
+ checkJSON(t, `0x2.p10`, `2048`)
+ checkJSON(t, `0x1.Fp+0`, `1.9375`)
+ checkJSON(t, `0X.8p-0`, `0.5`)
+ checkJSON(t, `0X_1FFFP-16`, `0.1249847412109375`)
})
t.Run("Special string cases", func(t *testing.T) {
diff --git a/internal/trace/trace_test.go b/internal/trace/trace_test.go
index 13c59667..7f2e8803 100644
--- a/internal/trace/trace_test.go
+++ b/internal/trace/trace_test.go
@@ -8,7 +8,6 @@ package trace_test
import (
"go/build"
- "io/ioutil"
"os"
"path/filepath"
"runtime"
@@ -38,7 +37,7 @@ func TestIgnorePackage(t *testing.T) {
}
func TestFindGoModDir(t *testing.T) {
- tmp, err := ioutil.TempDir("", "go-testdeep")
+ tmp, err := os.MkdirTemp("", "go-testdeep")
if err != nil {
t.Fatalf("TempDir() failed: %s", err)
}
@@ -55,7 +54,7 @@ func TestFindGoModDir(t *testing.T) {
t.Run("/tmp/.../a/b/c/go.mod", func(t *testing.T) {
goMod := filepath.Join(tmp, "a", "b", "c", "go.mod")
- err := ioutil.WriteFile(goMod, nil, 0644)
+ err := os.WriteFile(goMod, nil, 0644)
if err != nil {
t.Fatalf("WriteFile(%s) failed: %s", goMod, err)
}
@@ -74,7 +73,7 @@ func TestFindGoModDir(t *testing.T) {
if !os.IsNotExist(err) {
t.Fatalf("Stat(%s) failed: %s", goMod, err)
}
- err := ioutil.WriteFile(goMod, nil, 0644)
+ err := os.WriteFile(goMod, nil, 0644)
if err != nil {
t.Fatalf("WriteFile(%s) failed: %s", goMod, err)
}
@@ -86,7 +85,7 @@ func TestFindGoModDir(t *testing.T) {
}
func TestFindGoModDirLinks(t *testing.T) {
- tmp, err := ioutil.TempDir("", "go-testdeep")
+ tmp, err := os.MkdirTemp("", "go-testdeep")
if err != nil {
t.Fatalf("TempDir() failed: %s", err)
}
@@ -108,7 +107,7 @@ func TestFindGoModDirLinks(t *testing.T) {
goMod := filepath.Join(goModDir, "go.mod")
- err = ioutil.WriteFile(goMod, nil, 0644)
+ err = os.WriteFile(goMod, nil, 0644)
if err != nil {
t.Fatalf("WriteFile(%s) failed: %s", goMod, err)
}
diff --git a/td/cmp_deeply.go b/td/cmp_deeply.go
index b8b35884..9c53bcaf 100644
--- a/td/cmp_deeply.go
+++ b/td/cmp_deeply.go
@@ -147,7 +147,8 @@ func formatError(t TestingT, isFatal bool, err *ctxerr.Error, args ...any) {
}
func cmpDeeply(ctx ctxerr.Context, t TestingT, got, expected any,
- args ...any) bool {
+ args ...any,
+) bool {
err := deepValueEqualFinal(ctx,
reflect.ValueOf(got), reflect.ValueOf(expected))
if err == nil {
diff --git a/td/example_cmp_test.go b/td/example_cmp_test.go
index 0fe33029..9de99d3a 100644
--- a/td/example_cmp_test.go
+++ b/td/example_cmp_test.go
@@ -13,7 +13,6 @@ import (
"encoding/json"
"errors"
"fmt"
- "io/ioutil"
"math"
"os"
"regexp"
@@ -1277,14 +1276,14 @@ func ExampleCmpJSON_file() {
Gender: "male",
}
- tmpDir, err := ioutil.TempDir("", "")
+ tmpDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir) // clean up
filename := tmpDir + "/test.json"
- if err = ioutil.WriteFile(filename, []byte(`
+ if err = os.WriteFile(filename, []byte(`
{
"fullname": "$name",
"age": "$age",
@@ -3461,14 +3460,14 @@ func ExampleCmpSubJSONOf_file() {
Gender: "male",
}
- tmpDir, err := ioutil.TempDir("", "")
+ tmpDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir) // clean up
filename := tmpDir + "/test.json"
- if err = ioutil.WriteFile(filename, []byte(`
+ if err = os.WriteFile(filename, []byte(`
{
"fullname": "$name",
"age": "$age",
@@ -3690,14 +3689,14 @@ func ExampleCmpSuperJSONOf_file() {
Zip: 666,
}
- tmpDir, err := ioutil.TempDir("", "")
+ tmpDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir) // clean up
filename := tmpDir + "/test.json"
- if err = ioutil.WriteFile(filename, []byte(`
+ if err = os.WriteFile(filename, []byte(`
{
"fullname": "$name",
"age": "$age",
diff --git a/td/example_t_test.go b/td/example_t_test.go
index 8289490d..144e41a8 100644
--- a/td/example_t_test.go
+++ b/td/example_t_test.go
@@ -13,7 +13,6 @@ import (
"encoding/json"
"errors"
"fmt"
- "io/ioutil"
"math"
"os"
"regexp"
@@ -1277,14 +1276,14 @@ func ExampleT_JSON_file() {
Gender: "male",
}
- tmpDir, err := ioutil.TempDir("", "")
+ tmpDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir) // clean up
filename := tmpDir + "/test.json"
- if err = ioutil.WriteFile(filename, []byte(`
+ if err = os.WriteFile(filename, []byte(`
{
"fullname": "$name",
"age": "$age",
@@ -3461,14 +3460,14 @@ func ExampleT_SubJSONOf_file() {
Gender: "male",
}
- tmpDir, err := ioutil.TempDir("", "")
+ tmpDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir) // clean up
filename := tmpDir + "/test.json"
- if err = ioutil.WriteFile(filename, []byte(`
+ if err = os.WriteFile(filename, []byte(`
{
"fullname": "$name",
"age": "$age",
@@ -3690,14 +3689,14 @@ func ExampleT_SuperJSONOf_file() {
Zip: 666,
}
- tmpDir, err := ioutil.TempDir("", "")
+ tmpDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir) // clean up
filename := tmpDir + "/test.json"
- if err = ioutil.WriteFile(filename, []byte(`
+ if err = os.WriteFile(filename, []byte(`
{
"fullname": "$name",
"age": "$age",
diff --git a/td/example_test.go b/td/example_test.go
index 3bd07ba8..cbb1ca9f 100644
--- a/td/example_test.go
+++ b/td/example_test.go
@@ -11,7 +11,6 @@ import (
"encoding/json"
"errors"
"fmt"
- "io/ioutil"
"math"
"os"
"regexp"
@@ -1478,14 +1477,14 @@ func ExampleJSON_file() {
Gender: "male",
}
- tmpDir, err := ioutil.TempDir("", "")
+ tmpDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir) // clean up
filename := tmpDir + "/test.json"
- if err = ioutil.WriteFile(filename, []byte(`
+ if err = os.WriteFile(filename, []byte(`
{
"fullname": "$name",
"age": "$age",
@@ -4108,14 +4107,14 @@ func ExampleSubJSONOf_file() {
Gender: "male",
}
- tmpDir, err := ioutil.TempDir("", "")
+ tmpDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir) // clean up
filename := tmpDir + "/test.json"
- if err = ioutil.WriteFile(filename, []byte(`
+ if err = os.WriteFile(filename, []byte(`
{
"fullname": "$name",
"age": "$age",
@@ -4364,14 +4363,14 @@ func ExampleSuperJSONOf_file() {
Zip: 666,
}
- tmpDir, err := ioutil.TempDir("", "")
+ tmpDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir) // clean up
filename := tmpDir + "/test.json"
- if err = ioutil.WriteFile(filename, []byte(`
+ if err = os.WriteFile(filename, []byte(`
{
"fullname": "$name",
"age": "$age",
diff --git a/td/t_anchor.go b/td/t_anchor.go
index 562b7f4c..d2462bba 100644
--- a/td/t_anchor.go
+++ b/td/t_anchor.go
@@ -289,7 +289,7 @@ func (t *T) initAnchors() {
// Do not record a finalizer if no name (should not happen
// except perhaps in tests)
if name != "" {
- cleanupTB(t.TB, func() {
+ t.Cleanup(func() {
allAnchorsMu.Lock()
defer allAnchorsMu.Unlock()
delete(allAnchors, name)
diff --git a/td/t_anchor_go114.go b/td/t_anchor_go114.go
deleted file mode 100644
index 3eb4db91..00000000
--- a/td/t_anchor_go114.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2020, Maxime Soulé
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-//go:build go1.14
-// +build go1.14
-
-package td
-
-import "testing"
-
-func cleanupTB(tb testing.TB, finalize func()) {
- tb.Cleanup(finalize)
-}
diff --git a/td/t_anchor_other.go b/td/t_anchor_other.go
deleted file mode 100644
index ef83d43f..00000000
--- a/td/t_anchor_other.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2020, Maxime Soulé
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-//go:build !go1.14
-// +build !go1.14
-
-package td
-
-import (
- "runtime"
- "testing"
-)
-
-func cleanupTB(tb testing.TB, finalize func()) {
- runtime.SetFinalizer(tb, func(_ testing.TB) { finalize() })
-}
diff --git a/td/t_struct.go b/td/t_struct.go
index b051cffc..bd9271ca 100644
--- a/td/t_struct.go
+++ b/td/t_struct.go
@@ -7,8 +7,8 @@
package td
import (
- "bytes"
"reflect"
+ "strings"
"sync"
"testing"
@@ -783,12 +783,12 @@ func (t *T) RunT(name string, f func(t *T)) bool {
}
func getTrace(args ...any) string {
- var b bytes.Buffer
+ var b strings.Builder
tdutil.FbuildTestName(&b, args...)
if b.Len() == 0 {
b.WriteString("Stack trace:\n")
- } else if !bytes.HasSuffix(b.Bytes(), []byte{'\n'}) {
+ } else if !strings.HasSuffix(b.String(), "\n") {
b.WriteByte('\n')
}
diff --git a/td/td_json.go b/td/td_json.go
index 9c4eb8df..d90cdd80 100644
--- a/td/td_json.go
+++ b/td/td_json.go
@@ -12,7 +12,7 @@ import (
"errors"
"fmt"
"io"
- "io/ioutil"
+ "os"
"reflect"
"strings"
@@ -110,7 +110,7 @@ func (u tdJSONUnmarshaler) unmarshal(expectedJSON any, params []any) (any, *ctxe
// a JSON content)
if strings.HasSuffix(data, ".json") {
// It could be a file name, try to read from it
- b, err = ioutil.ReadFile(data)
+ b, err = os.ReadFile(data)
if err != nil {
return nil, ctxerr.OpBad(u.Func, "JSON file %s cannot be read: %s", data, err)
}
@@ -122,7 +122,7 @@ func (u tdJSONUnmarshaler) unmarshal(expectedJSON any, params []any) (any, *ctxe
b = data
case io.Reader:
- b, err = ioutil.ReadAll(data)
+ b, err = io.ReadAll(data)
if err != nil {
return nil, ctxerr.OpBad(u.Func, "JSON read error: %s", err)
}
@@ -489,9 +489,9 @@ func jsonify(ctx ctxerr.Context, got reflect.Value) (any, *ctxerr.Error) {
//
// - string containing JSON data like `{"fullname":"Bob","age":42}`
// - string containing a JSON filename, ending with ".json" (its
-// content is [ioutil.ReadFile] before unmarshaling)
+// content is [os.ReadFile] before unmarshaling)
// - []byte containing JSON data
-// - [io.Reader] stream containing JSON data (is [ioutil.ReadAll]
+// - [io.Reader] stream containing JSON data (is [io.ReadAll]
// before unmarshaling)
//
// expectedJSON JSON value can contain placeholders. The params
@@ -740,9 +740,9 @@ var _ TestDeep = &tdMapJSON{}
//
// - string containing JSON data like `{"fullname":"Bob","age":42}`
// - string containing a JSON filename, ending with ".json" (its
-// content is [ioutil.ReadFile] before unmarshaling)
+// content is [os.ReadFile] before unmarshaling)
// - []byte containing JSON data
-// - [io.Reader] stream containing JSON data (is [ioutil.ReadAll] before
+// - [io.Reader] stream containing JSON data (is [io.ReadAll] before
// unmarshaling)
//
// JSON data contained in expectedJSON must be a JSON object/map
@@ -962,9 +962,9 @@ func SubJSONOf(expectedJSON any, params ...any) TestDeep {
//
// - string containing JSON data like `{"fullname":"Bob","age":42}`
// - string containing a JSON filename, ending with ".json" (its
-// content is [ioutil.ReadFile] before unmarshaling)
+// content is [os.ReadFile] before unmarshaling)
// - []byte containing JSON data
-// - [io.Reader] stream containing JSON data (is [ioutil.ReadAll] before
+// - [io.Reader] stream containing JSON data (is [io.ReadAll] before
// unmarshaling)
//
// JSON data contained in expectedJSON must be a JSON object/map
diff --git a/td/td_json_test.go b/td/td_json_test.go
index 3ad4ff39..430b3535 100644
--- a/td/td_json_test.go
+++ b/td/td_json_test.go
@@ -9,7 +9,6 @@ package td_test
import (
"encoding/json"
"errors"
- "io/ioutil"
"os"
"reflect"
"testing"
@@ -190,14 +189,10 @@ func TestJSON(t *testing.T) {
//
// Loading a file
- tmpDir, err := ioutil.TempDir("", "")
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(tmpDir) // clean up
+ tmpDir := t.TempDir()
filename := tmpDir + "/test.json"
- err = ioutil.WriteFile(
+ err := os.WriteFile(
filename, []byte(`{"name":$name,"age":$1,"gender":$^NotEmpty}`), 0644)
if err != nil {
t.Fatal(err)
diff --git a/td/td_map.go b/td/td_map.go
index b590d9ac..0d20d165 100644
--- a/td/td_map.go
+++ b/td/td_map.go
@@ -7,9 +7,9 @@
package td
import (
- "bytes"
"fmt"
"reflect"
+ "strings"
"github.com/maxatome/go-testdeep/helpers/tdutil"
"github.com/maxatome/go-testdeep/internal/ctxerr"
@@ -403,7 +403,7 @@ func (m *tdMap) String() string {
return m.stringError()
}
- buf := &bytes.Buffer{}
+ var buf strings.Builder
if m.kind != allMap {
buf.WriteString(m.GetLocation().Func)
@@ -418,7 +418,7 @@ func (m *tdMap) String() string {
buf.WriteString("{\n")
for _, entryInfo := range m.expectedEntries {
- fmt.Fprintf(buf, " %s: %s,\n", //nolint: errcheck
+ fmt.Fprintf(&buf, " %s: %s,\n", //nolint: errcheck
util.ToString(entryInfo.key),
util.ToString(entryInfo.expected))
}
diff --git a/td/td_smuggle.go b/td/td_smuggle.go
index 54b03908..9cbd3c18 100644
--- a/td/td_smuggle.go
+++ b/td/td_smuggle.go
@@ -31,9 +31,6 @@ type SmuggledGot struct {
const smuggled = ""
var (
- // strconv.ParseComplex only exists from go1.15.
- parseComplex func(string, int) (complex128, error)
-
smuggleFnsMu sync.Mutex
smuggleFns = map[any]reflect.Value{}
@@ -76,7 +73,7 @@ type smuggleField struct {
}
func joinFieldsPath(path []smuggleField) string {
- var buf bytes.Buffer
+ var buf strings.Builder
for i, part := range path {
if part.Indexed {
fmt.Fprintf(&buf, "[%s]", part.Name)
@@ -220,17 +217,13 @@ func buildFieldsPathFn(path string) (func(any) (smuggleValue, error), error) {
}
vkey = reflect.ValueOf(f).Convert(tkey)
case reflect.Complex64, reflect.Complex128:
- if parseComplex != nil {
- c, err := parseComplex(field.Name, 128)
- if err != nil {
- return smuggleValue{}, fmt.Errorf(
- "field %q, %q is not a complex number and so cannot match %s map key type",
- joinFieldsPath(parts[:idxPart+1]), field.Name, tkey)
- }
- vkey = reflect.ValueOf(c).Convert(tkey)
- break
+ c, err := strconv.ParseComplex(field.Name, 128)
+ if err != nil {
+ return smuggleValue{}, fmt.Errorf(
+ "field %q, %q is not a complex number and so cannot match %s map key type",
+ joinFieldsPath(parts[:idxPart+1]), field.Name, tkey)
}
- fallthrough
+ vkey = reflect.ValueOf(c).Convert(tkey)
default:
return smuggleValue{}, fmt.Errorf(
"field %q, %q cannot match unsupported %s map key type",
@@ -332,12 +325,6 @@ func getCaster(outType reflect.Type) reflect.Value {
return fn
}
-// Needed for go≤1.12
-// From go1.13, reflect.ValueOf(&ctxerr.Error{…}) works as expected.
-func errorInterface(err error) reflect.Value {
- return reflect.ValueOf(&err).Elem()
-}
-
// buildCaster returns a function:
//
// func(in any) (out outType, err error)
@@ -362,7 +349,7 @@ func buildCaster(outType reflect.Type, useString bool) reflect.Value {
if args[0].IsNil() {
return []reflect.Value{
zeroRet,
- errorInterface(&ctxerr.Error{
+ reflect.ValueOf(&ctxerr.Error{
Message: "incompatible parameter type",
Got: types.RawString("nil"),
Expected: types.RawString(outType.String() + " or convertible or io.Reader"),
@@ -383,11 +370,11 @@ func buildCaster(outType reflect.Type, useString bool) reflect.Value {
// Our caller encures Interface() can be called safely
switch ta := args[0].Interface().(type) {
case io.Reader:
- var b bytes.Buffer // as we still support go1.9
+ var b bytes.Buffer
if _, err := b.ReadFrom(ta); err != nil {
return []reflect.Value{
zeroRet,
- errorInterface(&ctxerr.Error{
+ reflect.ValueOf(&ctxerr.Error{
Message: "an error occurred while reading from io.Reader",
Summary: ctxerr.NewSummary(err.Error()),
}),
@@ -407,7 +394,7 @@ func buildCaster(outType reflect.Type, useString bool) reflect.Value {
default:
return []reflect.Value{
zeroRet,
- errorInterface(&ctxerr.Error{
+ reflect.ValueOf(&ctxerr.Error{
Message: "incompatible parameter type",
Got: types.RawString(args[0].Type().String()),
Expected: types.RawString(outType.String() + " or convertible or io.Reader"),
diff --git a/td/td_smuggle_go115.go b/td/td_smuggle_go115.go
deleted file mode 100644
index 1432ffb9..00000000
--- a/td/td_smuggle_go115.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2021, Maxime Soulé
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-//go:build go1.15
-// +build go1.15
-
-package td
-
-import "strconv"
-
-// strconv.ParseComplex is only available from go 1.15.
-func init() {
- parseComplex = strconv.ParseComplex
-}
diff --git a/td/td_smuggle_go115_test.go b/td/td_smuggle_go115_test.go
deleted file mode 100644
index 20dc28ea..00000000
--- a/td/td_smuggle_go115_test.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2021, Maxime Soulé
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree.
-
-//go:build go1.15
-// +build go1.15
-
-package td_test
-
-import (
- "fmt"
- "testing"
-
- "github.com/maxatome/go-testdeep/td"
-)
-
-func TestSmuggleFieldsPath_go115(t *testing.T) {
- type C struct {
- Iface any
- }
-
- got := C{
- Iface: []any{
- map[complex64]any{complex(42, 0): []string{"pipo"}},
- map[complex128]any{complex(42, 0): []string{"pipo"}},
- },
- }
-
- for i := 0; i < 2; i++ {
- checkOK(t, got, td.Smuggle(fmt.Sprintf("Iface[%d][42][0]", i), "pipo"))
- checkOK(t, got, td.Smuggle(fmt.Sprintf("Iface[%d][42][0]", i-2), "pipo"))
- }
-}
diff --git a/td/td_smuggle_private_test.go b/td/td_smuggle_private_test.go
index 4353c62d..d63ea5ce 100644
--- a/td/td_smuggle_private_test.go
+++ b/td/td_smuggle_private_test.go
@@ -128,13 +128,10 @@ func TestBuildFieldsPathFn(t *testing.T) {
`field "Iface[str]", "str" is not a float and so cannot match float32 map key type`)
}
- // go1.15 min
- if parseComplex != nil {
- _, err = fn(Build{Iface: map[complex128]Build{}})
- if test.Error(t, err) {
- test.EqualStr(t, err.Error(),
- `field "Iface[str]", "str" is not a complex number and so cannot match complex128 map key type`)
- }
+ _, err = fn(Build{Iface: map[complex128]Build{}})
+ if test.Error(t, err) {
+ test.EqualStr(t, err.Error(),
+ `field "Iface[str]", "str" is not a complex number and so cannot match complex128 map key type`)
}
_, err = fn(Build{Iface: map[struct{ A int }]Build{}})
@@ -181,24 +178,4 @@ func TestBuildFieldsPathFn(t *testing.T) {
test.EqualStr(t, err.Error(),
`it is a int, but a map, array or slice is expected`)
}
-
- // Complex map keys are not supported for go<1.15
- saveParseComplex := parseComplex
- defer func() { parseComplex = saveParseComplex }()
- parseComplex = nil
-
- fn, err = buildFieldsPathFn("Iface[18].Field")
- if test.NoError(t, err) {
- _, err = fn(Build{Iface: map[complex64]Build{}})
- if test.Error(t, err) {
- test.EqualStr(t, err.Error(),
- `field "Iface[18]", "18" cannot match unsupported complex64 map key type`)
- }
-
- _, err = fn(Build{Iface: map[complex128]Build{}})
- if test.Error(t, err) {
- test.EqualStr(t, err.Error(),
- `field "Iface[18]", "18" cannot match unsupported complex128 map key type`)
- }
- }
}
diff --git a/td/td_smuggle_test.go b/td/td_smuggle_test.go
index 21843ca0..587ba515 100644
--- a/td/td_smuggle_test.go
+++ b/td/td_smuggle_test.go
@@ -727,6 +727,23 @@ func TestSmuggleFieldsPath(t *testing.T) {
checkOK(t, x, td.Lax(td.Smuggle("PppA", nil)))
checkOK(t, x, td.Smuggle("PppA", td.Nil()))
+
+ //
+ type D struct {
+ Iface any
+ }
+
+ got := D{
+ Iface: []any{
+ map[complex64]any{complex(42, 0): []string{"pipo"}},
+ map[complex128]any{complex(42, 0): []string{"pipo"}},
+ },
+ }
+
+ for i := 0; i < 2; i++ {
+ checkOK(t, got, td.Smuggle(fmt.Sprintf("Iface[%d][42][0]", i), "pipo"))
+ checkOK(t, got, td.Smuggle(fmt.Sprintf("Iface[%d][42][0]", i-2), "pipo"))
+ }
}
func TestSmuggleTypeBehind(t *testing.T) {
diff --git a/td/types_test.go b/td/types_test.go
index 0a3e5e6f..bb682555 100644
--- a/td/types_test.go
+++ b/td/types_test.go
@@ -4,11 +4,6 @@
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.
-// Work around https://github.com/golang/go/issues/26995 issue
-// (corrected in go 1.12).
-//go:build go1.12
-// +build go1.12
-
package td_test
import (