Commit 8be3fcab authored by Kirill Smelkov's avatar Kirill Smelkov

*: Switch reflect.DeepEqual to own deepEqual that supports Dict

reflect.DeepEqual does not work with Dicts because each Dict uses own
distinct random seed. But in the tests we will need to be able to
compare arbitrary objects, including Dicts.

-> Fix this via implementing our own deepEqual that extends
   reflect.DeepEqual to also support Dicts.

Handle only top-level Dicts for now as that level of support will be
enough for our tests.
parent 4178bf4a
......@@ -5,7 +5,6 @@ package ogórek
import (
"bytes"
"fmt"
"reflect"
)
func Fuzz(data []byte) int {
......@@ -75,7 +74,7 @@ func fuzz(data []byte, strictUnicode bool) int {
panic(fmt.Sprintf("%s: decode back error: %s\npickle: %q", subj, err, encoded))
}
if !reflect.DeepEqual(obj, obj2) {
if !deepEqual(obj, obj2) {
panic(fmt.Sprintf("%s: decode·encode != identity:\nhave: %#v\nwant: %#v", subj, obj2, obj))
}
}
......
......@@ -7,7 +7,6 @@ import (
"fmt"
"io"
"math/big"
"reflect"
"strconv"
"strings"
"testing"
......@@ -619,7 +618,7 @@ func testDecode(t *testing.T, strictUnicode bool, object interface{}, input stri
t.Error(err)
}
if !reflect.DeepEqual(v, object) {
if !deepEqual(v, object) {
t.Errorf("decode:\nhave: %#v\nwant: %#v", v, object)
}
......@@ -716,9 +715,9 @@ func testEncode(t *testing.T, proto int, strictUnicode bool, object, objectDecod
if err != nil {
t.Errorf("encode -> decode -> error: %s", err)
} else {
if !reflect.DeepEqual(v, objectDecodedBack) {
if !deepEqual(v, objectDecodedBack) {
what := "identity"
if !reflect.DeepEqual(object, objectDecodedBack) {
if !deepEqual(object, objectDecodedBack) {
what = "expected object"
}
t.Errorf("encode -> decode != %s\nhave: %#v\nwant: %#v", what, v, objectDecodedBack)
......@@ -742,7 +741,7 @@ func TestDecodeMultiple(t *testing.T) {
t.Errorf("step #%v: %v", i, err)
}
if !reflect.DeepEqual(obj, objOk) {
if !deepEqual(obj, objOk) {
t.Errorf("step #%v: %q ; want %q", i, obj, objOk)
}
}
......@@ -929,7 +928,7 @@ func TestPersistentRefs(t *testing.T) {
errExpect = "pickle: handleRef: " + e.Error()
}
if !(reflect.DeepEqual(v, expected) &&
if !(deepEqual(v, expected) &&
((err == nil && errExpect == "") || err.Error() == errExpect)) {
t.Errorf("%q: decode -> %#v, %q; want %#v, %q",
tt.input, v, err, expected, errExpect)
......@@ -955,7 +954,7 @@ func TestPersistentRefs(t *testing.T) {
continue
}
if !reflect.DeepEqual(v, tt.expected) {
if !deepEqual(v, tt.expected) {
t.Errorf("%q: expected -> encode -> decode != identity\nhave: %#v\nwant: %#v",
tt.input, v, tt.expected)
}
......
......@@ -45,7 +45,7 @@ func TestAsInt64(t *testing.T) {
}
}
if !reflect.DeepEqual(out, tt.outOK) {
if !deepEqual(out, tt.outOK) {
t.Errorf("%T %#v -> %T %#v ; want %T %#v",
tt.in, tt.in, out, out, tt.outOK, tt.outOK)
}
......@@ -100,12 +100,12 @@ func TestAsBytesString(t *testing.T) {
serrOK = Estring(tt.in)
}
if !(bout == boutOK && reflect.DeepEqual(berr, berrOK)) {
if !(bout == boutOK && deepEqual(berr, berrOK)) {
t.Errorf("%#v: AsBytes:\nhave %#v %#v\nwant %#v %#v",
tt.in, bout, berr, boutOK, berrOK)
}
if !(sout == soutOK && reflect.DeepEqual(serr, serrOK)) {
if !(sout == soutOK && deepEqual(serr, serrOK)) {
t.Errorf("%#v: AsString:\nhave %#v %#v\nwant %#v %#v",
tt.in, sout, serr, soutOK, serrOK)
}
......
package ogórek
// Utilities that complement std reflect package.
import (
"reflect"
)
// deepEqual is like reflect.DeepEqual but also supports Dict.
//
// It is needed because reflect.DeepEqual considers two Dicts not-equal because
// each Dict is made with its own seed.
//
// XXX only top-level Dict is supported currently.
// For example comparing Dict inside list with the same won't work.
func deepEqual(a, b any) bool {
da, ok := a.(Dict)
if !ok {
return reflect.DeepEqual(a, b)
}
db, ok := b.(Dict)
if !ok {
return false // Dict != non-dict
}
if da.Len() != db.Len() {
return false
}
// XXX O(n^2) because we want to compare keys exactly and so cannot use
// db.Get(ka) because Dict.Get uses general equality that would match e.g. int == int64
eq := true
da.Iter()(func(ka, va any) bool {
keq := false
db.Iter()(func(kb, vb any) bool {
// NOTE don't use reflect.Equal(ka,kb) because it does not handle e.g. big.Int
if reflect.TypeOf(ka) == reflect.TypeOf(kb) && equal(ka,kb) {
if reflect.DeepEqual(va, vb) {
keq = true
}
return false
}
return true
})
if !keq {
eq = false
return false
}
return true
})
return eq
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment