Changed error handling in Marshal and Unmarshal

Instead of returning errors, these now use d.Exp to raise catchable
errors.

Also, added commit hash at which code was pulled from encoding/json

Marshal io.Reader into a Blob, unmarshal Blob into io.Writer
This commit is contained in:
Chris Masone
2015-08-25 10:24:46 -07:00
parent 5de698b8f1
commit ccd70d7c65
10 changed files with 326 additions and 352 deletions

View File

@@ -1,4 +1,4 @@
// Extracted and modified from golang's encoding/json/encode.go
// Extracted and modified from golang's encoding/json/encode.go at 80e6d638bf309181eadcb3fecbe99d2d8518e364.
package marshal

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Copied from the encoding/json package.
// Copied from the encoding/json package at 80e6d638bf309181eadcb3fecbe99d2d8518e364.
package marshal

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Copied from the encoding/json package.
// Copied from the encoding/json package at 80e6d638bf309181eadcb3fecbe99d2d8518e364.
package marshal

View File

@@ -1,4 +1,4 @@
// Modified from golang's encoding/json/encode.go
// Modified from golang's encoding/json/encode.go at 80e6d638bf309181eadcb3fecbe99d2d8518e364.
// Package marshal implements encoding and decoding of Noms values into native Go types.
// The mapping between Noms objects and Go values is described
@@ -7,13 +7,13 @@ package marshal
import (
"bytes"
"fmt"
"io"
"math"
"reflect"
"runtime"
"strconv"
"sync"
"github.com/attic-labs/noms/d"
"github.com/attic-labs/noms/ref"
"github.com/attic-labs/noms/types"
)
@@ -37,9 +37,8 @@ import (
// becomes a member of the object unless
// - the field's tag is "-", or
// - the field is empty and its tag specifies the "omitempty" option.
// The empty values are false, 0, any
// nil pointer or interface value, and any array, slice, map, or string of
// length zero. The Map's default key string is the struct field name
// The empty values are the standard zero values.
// The Map's default keys are the struct field name as a string,
// but can be specified in the struct field's tag value. The "noms" key in
// the struct field's tag value is the key name, followed by an optional comma
// and options. Examples:
@@ -64,13 +63,13 @@ import (
// only Unicode letters, digits, dollar signs, percent signs, hyphens,
// underscores and slashes.
//
// Anonymous struct fields are usually marshaled as if their inner exported fields
// were fields in the outer struct, subject to the usual Go visibility rules amended
// as described in the next paragraph.
// An anonymous struct field with a name given in its 'noms' tag is treated as
// having that name, rather than being anonymous.
// An anonymous struct field of interface type is treated the same as having
// that type as its name, rather than being anonymous.
// Anonymous struct fields (i.e. embedded structs) are marshaled as if their inner exported fields
// were fields in the outer struct, mostly subject to the usual Go visibility rules.
// These are amended slightly, as follows:
// 1) An anonymous struct field with a name given in its 'noms' tag is treated as
// having that name, rather than being anonymous.
// 2) An anonymous struct field of interface type is treated the same as having
// that type as its name, rather than being anonymous.
//
// The Go visibility rules for struct fields are amended for us when
// deciding which field to marshal or unmarshal. If there are
@@ -79,7 +78,7 @@ import (
// usual Go rules), the following extra rules apply:
//
// 1) Of those fields, if any are Noms-tagged, only tagged fields are considered,
// even if there are multiple untagged fields that would otherwise conflict.
// even if there are multiple untagged fields that would otherwise conflict.
// 2) If there is exactly one field (tagged or not according to the first rule), that is selected.
// 3) Otherwise there are multiple fields, and all are ignored; no error occurs.
//
@@ -99,44 +98,16 @@ import (
// handle them. Passing cyclic structures to Marshal will result in
// an infinite recursion.
//
func Marshal(v interface{}) (types.Value, error) {
return marshal(v)
func Marshal(v interface{}) types.Value {
return reflectValue(reflect.ValueOf(v))
}
// An UnsupportedTypeError is returned by Marshal when attempting
// to encode an unsupported value type.
type UnsupportedTypeError struct {
Type reflect.Type
func unsupportedTypeMsg(t reflect.Type) string {
return "noms: unsupported type: " + t.String()
}
func (e *UnsupportedTypeError) Error() string {
return "noms: unsupported type: " + e.Type.String()
}
// An UnsupportedValueError is returned by Marshal when attempting
// to encode an unsupported value -- such as a nil pointer.
type UnsupportedValueError struct {
Value reflect.Value
Str string
}
func (e *UnsupportedValueError) Error() string {
return "noms: unsupported value: " + e.Str
}
func marshal(v interface{}) (nom types.Value, err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
if s, ok := r.(string); ok {
panic(s)
}
err = r.(error)
}
}()
return reflectValue(reflect.ValueOf(v)), nil
func unsupportedValueMsg(s string) string {
return "noms: unsupported value: " + s
}
func isEmptyValue(v reflect.Value) bool {
@@ -209,8 +180,17 @@ func typeEncoder(t reflect.Type) encoderFunc {
return f
}
var (
bytesBufferType = reflect.TypeOf(&bytes.Buffer{})
readerType = reflect.TypeOf((*io.Reader)(nil)).Elem()
)
// newTypeEncoder constructs an encoderFunc for a type.
func newTypeEncoder(t reflect.Type) encoderFunc {
if t.Implements(readerType) {
return readerEncoder
}
switch t.Kind() {
case reflect.Bool:
return boolEncoder
@@ -259,14 +239,13 @@ func intEncoder(v reflect.Value) types.Value {
return types.Int32(v.Int())
case reflect.Int:
n := v.Int()
if reflect.ValueOf(types.Int32(0)).OverflowInt(n) {
panic(&UnsupportedValueError{v, fmt.Sprintf("Unsized integers must be 32 bit values; %d is too large.", n)})
}
d.Exp.False(reflect.ValueOf(types.Int32(0)).OverflowInt(n), " Unsized integers must be 32 bit values; %d is too large.")
return types.Int32(n)
case reflect.Int64:
return types.Int64(v.Int())
default:
panic(&UnsupportedValueError{v, "Not an integer"})
d.Exp.Fail("Not an integer")
panic("unreachable")
}
}
@@ -281,14 +260,13 @@ func uintEncoder(v reflect.Value) types.Value {
return types.UInt32(n)
case reflect.Uint:
n := v.Uint()
if reflect.ValueOf(types.UInt32(0)).OverflowUint(n) {
panic(&UnsupportedValueError{v, fmt.Sprintf("Unsized integers must be 32 bit values; %d is too large.", n)})
}
d.Exp.False(reflect.ValueOf(types.UInt32(0)).OverflowUint(n), "Unsized integers must be 32 bit values; %d is too large.", n)
return types.UInt32(n)
case reflect.Uint64:
return types.UInt64(n)
default:
panic(&UnsupportedValueError{v, fmt.Sprintf("%d not an unsigned integer", n)})
d.Exp.Fail("Not an unsigned integer", "%d", n)
panic("unreachable")
}
}
@@ -296,9 +274,8 @@ type floatEncoder int // number of bits
func (bits floatEncoder) encode(v reflect.Value) types.Value {
f := v.Float()
if math.IsInf(f, 0) || math.IsNaN(f) {
panic(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))})
}
d.Exp.False(math.IsInf(f, 0), "Noms can't encode infinity", strconv.FormatFloat(f, 'g', -1, int(bits)))
d.Exp.False(math.IsNaN(f), "Noms can't encode NaN", strconv.FormatFloat(f, 'g', -1, int(bits)))
if bits == 64 {
return types.Float64(f)
}
@@ -315,14 +292,13 @@ func stringEncoder(v reflect.Value) types.Value {
}
func interfaceEncoder(v reflect.Value) types.Value {
if v.IsNil() {
panic(&UnsupportedValueError{v, "Noms can't encode nil interface."})
}
d.Exp.False(v.IsNil(), "Noms can't encode nil interface.")
return reflectValue(v.Elem())
}
func unsupportedTypeEncoder(v reflect.Value) types.Value {
panic(&UnsupportedTypeError{v.Type()})
d.Exp.Fail(unsupportedTypeMsg(v.Type()))
panic("unreachable")
}
type structEncoder struct {
@@ -339,6 +315,13 @@ func isNilPtrOrNilInterface(v reflect.Value) bool {
}
}
func readerEncoder(v reflect.Value) types.Value {
d.Chk.True(v.Type().Implements(readerType))
blob, err := types.NewBlob(v.Interface().(io.Reader))
d.Exp.NoError(err, "Failed to marshal reader into blob")
return blob
}
// Noms has no notion of a general-purpose nil value. Thus, if struct encoding encounters a field that holds a nil pointer or interface, it skips it even if that field doesn't have the omitempty option set. Nil maps and slices are encoded as an empty Noms map, set, list or blob as appropriate.
func (se *structEncoder) encode(v reflect.Value) types.Value {
if v.Type() == refRefType {
@@ -426,10 +409,6 @@ func encodeByteSlice(v reflect.Value) types.Value {
}
func newSliceEncoder(t reflect.Type) encoderFunc {
// Byte slices get special treatment; arrays don't.
if t.Elem().Kind() == reflect.Uint8 {
return encodeByteSlice
}
return newArrayEncoder(t)
}
@@ -460,9 +439,7 @@ type ptrEncoder struct {
}
func (pe *ptrEncoder) encode(v reflect.Value) types.Value {
if v.IsNil() {
panic(&UnsupportedValueError{v, "Noms can't encode nil ptr."})
}
d.Exp.False(v.IsNil(), "Noms can't encode nil ptr.")
return pe.elemEnc(v.Elem())
}

View File

@@ -1,10 +1,11 @@
// Modified from golang's encoding/json/encode_test.go
// Modified from golang's encoding/json/encode_test.go at 80e6d638bf309181eadcb3fecbe99d2d8518e364.
package marshal
import (
"bytes"
"image"
"io"
"io/ioutil"
"testing"
@@ -58,8 +59,7 @@ func TestOmitEmpty(t *testing.T) {
o.Mr = map[string]interface{}{}
o.Mo = map[string]interface{}{}
nom, err := Marshal(&o)
assert.NoError(err)
nom := Marshal(&o)
if nom, ok := nom.(types.Map); !ok {
assert.Fail("%+v should be a Map", nom)
} else {
@@ -67,36 +67,6 @@ func TestOmitEmpty(t *testing.T) {
}
}
// byte slices are special even if they're renamed types.
type renamedByte byte
type renamedByteSlice []byte
type renamedRenamedByteSlice []renamedByte
func TestEncodeRenamedByteSlice(t *testing.T) {
assert := assert.New(t)
blobData := func(blob types.Value) []byte {
if blob, ok := blob.(types.Blob); !ok {
assert.Fail("blob should be a Blob, not %T", blob)
} else {
b, err := ioutil.ReadAll(blob.Reader())
assert.NoError(err)
return b
}
return nil
}
expected := "abc"
s := renamedByteSlice(expected)
result, err := Marshal(s)
assert.NoError(err)
assert.EqualValues(expected, blobData(result))
r := renamedRenamedByteSlice(expected)
result, err = Marshal(r)
assert.NoError(err)
assert.Equal(expected, string(blobData(result)))
}
type IntType int
type MyStruct struct {
@@ -107,8 +77,7 @@ func TestAnonymousNonstruct(t *testing.T) {
var i IntType = 11
a := MyStruct{i}
nom, err := Marshal(a)
assert.NoError(t, err)
nom := Marshal(a)
if nom, ok := nom.(types.Map); !ok {
assert.Fail(t, "nom should be a Map, not %T", nom)
} else {
@@ -163,8 +132,7 @@ func TestMarshalEmbeds(t *testing.T) {
Point: Point{Z: 17},
},
}
b, err := Marshal(top)
assert.NoError(t, err)
b := Marshal(top)
assert.EqualValues(t, marshaledEmbeds, b)
}
@@ -195,8 +163,7 @@ func TestEmbeddedBug(t *testing.T) {
BugA{"A"},
"B",
}
nom, err := Marshal(v)
assert.NoError(err)
nom := Marshal(v)
nom = nom.(types.Map)
expected := types.NewMap(types.NewString("S"), types.NewString("B"))
@@ -206,8 +173,7 @@ func TestEmbeddedBug(t *testing.T) {
x := BugX{
A: 23,
}
nom, err = Marshal(x)
assert.NoError(err)
nom = Marshal(x)
nom = nom.(types.Map)
expected = types.NewMap(types.NewString("A"), types.Int32(23))
assert.EqualValues(expected, nom)
@@ -230,8 +196,7 @@ func TestTaggedFieldDominates(t *testing.T) {
BugA{"BugA"},
BugD{"BugD"},
}
nom, err := Marshal(v)
assert.NoError(err)
nom := Marshal(v)
nom = nom.(types.Map)
expected := types.NewMap(types.NewString("S"), types.NewString("BugD"))
@@ -255,8 +220,7 @@ func TestDuplicatedFieldDisappears(t *testing.T) {
BugD{"nested BugD"},
},
}
nom, err := Marshal(v)
assert.NoError(err)
nom := Marshal(v)
nom = nom.(types.Map)
expected := types.NewMap()
@@ -271,24 +235,51 @@ func TestMarshalSetP(t *testing.T) {
nil: true,
}
expected := types.NewSet(types.NewMap(types.NewString("Tag"), types.NewString("tag")))
nom, err := Marshal(setP)
assert.NoError(err)
nom := Marshal(setP)
// Check against canned marshalled representation.
if nom, ok := nom.(types.Set); !ok {
assert.Fail("Marshal should return set.", "nom is %v", nom)
return
} else if assert.NotNil(nom) {
assert.True(expected.Equals(nom), "%v != %v", expected, nom)
}
nomSet := nom.(types.Set)
if assert.NotNil(nomSet) {
assert.True(expected.Equals(nomSet), "%v != %v", expected, nomSet)
}
func TestMarshalBuffer(t *testing.T) {
assert := assert.New(t)
expected := []byte("abc")
nom := Marshal(bytes.NewBufferString("abc"))
validateBlob(assert, expected, nom)
}
func TestMarshalReader(t *testing.T) {
assert := assert.New(t)
expected := []byte("abc")
var in io.Reader = bytes.NewBuffer(expected)
nom := Marshal(in)
validateBlob(assert, expected, nom)
in = bytes.NewBuffer(expected)
nom = Marshal(&in)
validateBlob(assert, expected, nom)
}
func validateBlob(assert *assert.Assertions, expected []byte, nom types.Value) {
if nom, ok := nom.(types.Blob); !ok || nom == nil {
assert.Fail("Marshal should return blob.", "nom is %v", nom)
} else {
nomBytes, err := ioutil.ReadAll(nom.Reader())
assert.NoError(err)
assert.EqualValues(expected, nomBytes)
}
}
func TestMarshal(t *testing.T) {
assert := assert.New(t)
nom, err := Marshal(allValue)
assert.NoError(err)
nom := Marshal(allValue)
// Check against canned marshalled representation.
if nom, ok := nom.(types.Map); !ok {
@@ -304,8 +295,7 @@ func TestMarshal(t *testing.T) {
return
})
nom, err = Marshal(pallValue)
assert.NoError(err)
nom = Marshal(pallValue)
if nom, ok := nom.(types.Map); !ok {
assert.Fail("Marshal should return map.", "nom is %v", nom)
return
@@ -522,7 +512,8 @@ var allNomsValue = types.NewMap(
types.NewString("NilSlice"), types.NewList(),
types.NewString("StringSlice"), types.NewList(
types.NewString("str24"), types.NewString("str25"), types.NewString("str26")),
types.NewString("ByteSlice"), makeNewBlob([]byte{27, 28, 29}),
types.NewString("ByteSlice"), types.NewList(
types.UInt8(27), types.UInt8(28), types.UInt8(29)),
types.NewString("Small"), types.NewMap(types.NewString("Tag"), types.NewString("tag30")),
types.NewString("PSmall"), types.NewMap(types.NewString("Tag"), types.NewString("tag31")),
@@ -597,7 +588,7 @@ var pallNomsValue = types.NewMap(
types.NewString("EmptySlice"), types.NewList(),
types.NewString("NilSlice"), types.NewList(),
types.NewString("StringSlice"), types.NewList(),
types.NewString("ByteSlice"), makeNewBlob([]byte{}),
types.NewString("ByteSlice"), types.NewList(),
types.NewString("Small"), types.NewMap(types.NewString("Tag"), types.NewString("")),
// PSmall and Interface are not marhsaled, as they're a nil ptr and nil interface, respectively.

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Copied from the encoding/json package.
// Copied from the encoding/json package at 80e6d638bf309181eadcb3fecbe99d2d8518e364.
package marshal

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Copied from the encoding/json package.
// Copied from the encoding/json package at 80e6d638bf309181eadcb3fecbe99d2d8518e364.
package marshal

View File

@@ -1,4 +1,4 @@
// Modified from golang's encoding/json/decode.go
// Modified from golang's encoding/json/decode.go at 80e6d638bf309181eadcb3fecbe99d2d8518e364.
package marshal
@@ -8,7 +8,6 @@ import (
"io"
"math"
"reflect"
"runtime"
"github.com/attic-labs/noms/d"
"github.com/attic-labs/noms/ref"
@@ -25,120 +24,80 @@ import (
// nom that don't have an analog in v. The primary difference is that
// there's no analog to the json.Unmarshaler interface.
//
// Like json.Unmarshal, this code also treats overflows and field type
// mismatches as non-fatal; the fields will just be skipped and a the
// first such occurence will be reported in the return value. For example,
// a types.Int32 will be unmarshalled into an int64, because that's safe,
// but a types.Float64 won't be allowed to overflow a float32 in the
// target. Similarly, Unmarshal will skip a piece of data in nom that maps
// to a target of the wrong type in v -- e.g. both nom and v have a field
// named Foo, but it's a types.String in the former and an int in the
// latter.
func Unmarshal(nom types.Value, v interface{}) error {
u := unmarshalState{}
return u.unmarshal(nom, v)
// Any value can be "unmarshaled" into a ref.Ref, though the target will be populated only with the value's ref.
// Primitive values can be unmarshaled into Go primitives.
// Lists can be unmarshaled into slices, with space being allocated dynamically.
// Lists can be unmarshaled into arrays if there is room for all the data.
// Maps can be unmarshaled into Go maps.
// Sets can be unmarshaled into Go maps of the form map[ElementType]bool
// Blobs can be unmarshaled into anything that implements io.Writer by using io.Copy.
// Note that your Writer will not be cleared or destroyed before data is written to it.
// Blobs can be unmarshaled into slices, with space being allocated dynamically.
// Blobs can be unmarshaled into arrays if there is room for all the data.
//
// Unline json.Unmarshal, this code treats overflows and significant field
// type mismatches as fatal. For example, a types.Int32 will be unmarshalled
// into an int64, because that's safe, but a types.Float64 won't be allowed
// to overflow a float32 in the target. Similarly, Unmarshal will error on a
// piece of data in nom that maps to a target of the wrong type in v -- e.g.
// both nom and v have a field named Foo, but it's a types.String in the
// former and an int in the latter.
func Unmarshal(nom types.Value, v interface{}) {
rv := reflect.ValueOf(v)
d.Exp.False(rv.Kind() != reflect.Ptr || rv.IsNil(), invalidUnmarshalMsg(reflect.TypeOf(v)))
unmarshalValue(nom, rv)
}
var (
refRefType = reflect.TypeOf(ref.Ref{})
writerType = reflect.TypeOf((*io.Writer)(nil)).Elem()
)
// An UnmarshalTypeError describes a Noms value that was
// not appropriate for a value of a specific Go type.
type UnmarshalTypeError struct {
Value string // type name of Noms value
Type reflect.Type // type of Go value it could not be assigned to
func invalidTypeMsg(v string, t reflect.Type) string {
return "noms: cannot unmarshal noms " + v + " into Go value of type " + t.String()
}
func (e *UnmarshalTypeError) Error() string {
return "noms: cannot unmarshal noms " + e.Value + " into Go value of type " + e.Type.String()
}
// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
// (The argument to Unmarshal must be a non-nil pointer.)
type InvalidUnmarshalError struct {
Type reflect.Type
}
func (e *InvalidUnmarshalError) Error() string {
if e.Type == nil {
// The argument to Unmarshal must be a non-nil pointer
func invalidUnmarshalMsg(t reflect.Type) string {
if t == nil {
return "noms: Unmarshal(nil)"
}
if e.Type.Kind() != reflect.Ptr {
return "noms: Unmarshal(non-pointer " + e.Type.String() + ")"
}
return "noms: Unmarshal(nil " + e.Type.String() + ")"
}
func (u *unmarshalState) unmarshal(nom types.Value, v interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
} else if s, ok := r.(string); ok {
r = fmt.Errorf(s)
}
err = r.(error)
}
}()
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
return &InvalidUnmarshalError{reflect.TypeOf(v)}
}
u.unmarshalValue(nom, rv)
return u.savedError
}
// unmarshalState represents the state while decoding a Noms value.
type unmarshalState struct {
savedError error
}
// error aborts the decoding by panicking with err.
func (u *unmarshalState) error(err error) {
panic(err)
}
// saveError saves the first err it is called with,
// for reporting at the end of the unmarshal.
func (u *unmarshalState) saveError(err error) {
if u.savedError == nil {
u.savedError = err
if t.Kind() != reflect.Ptr {
return "noms: Unmarshal(non-pointer " + t.String() + ")"
}
return "noms: Unmarshal(nil " + t.String() + ")"
}
// unmarshalValue unpacks an arbitrary types.Value into v.
func (u *unmarshalState) unmarshalValue(nom types.Value, v reflect.Value) {
func unmarshalValue(nom types.Value, v reflect.Value) {
if !v.IsValid() {
return
}
switch nom := nom.(type) {
case types.Blob:
u.unmarshalBlob(nom, v)
unmarshalBlob(nom, v)
case types.List:
u.unmarshalList(nom, v)
unmarshalList(nom, v)
case types.Map:
u.unmarshalMap(nom, v)
unmarshalMap(nom, v)
case primitive:
u.unmarshalPrimitive(nom, v)
unmarshalPrimitive(nom, v)
case types.Ref:
u.unmarshalRef(nom, v)
unmarshalRef(nom, v)
case types.Set:
u.unmarshalSet(nom, v)
unmarshalSet(nom, v)
case types.String:
u.unmarshalString(nom, v)
unmarshalString(nom, v)
default:
u.error(&UnmarshalTypeError{reflect.TypeOf(nom).Name(), v.Type()})
d.Exp.Fail(invalidTypeMsg(reflect.TypeOf(nom).Name(), v.Type()))
}
}
// indirect walks down v, allocating pointers as needed,
// until it gets to a non-pointer.
func (u *unmarshalState) indirect(v reflect.Value) reflect.Value {
func indirect(v reflect.Value) reflect.Value {
// If v is a named type and is addressable,
// start with its address, so that if the type has pointer methods,
// we find them.
@@ -146,14 +105,9 @@ func (u *unmarshalState) indirect(v reflect.Value) reflect.Value {
v = v.Addr()
}
for {
// Load value from interface, but only if the result will be
// usefully addressable.
if v.Kind() == reflect.Interface && !v.IsNil() {
e := v.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() {
v = e
continue
}
if nv, ok := loadValueFromInterfaceIfAddressable(v); ok {
v = nv
continue
}
if v.Kind() != reflect.Ptr {
@@ -168,9 +122,57 @@ func (u *unmarshalState) indirect(v reflect.Value) reflect.Value {
return v
}
func (u *unmarshalState) unmarshalBlob(nom types.Blob, v reflect.Value) {
origType := v.Type()
v = u.indirect(v)
// indirect walks down v, allocating pointers as needed,
// until it gets to a non-pointer.
func findImplementor(v reflect.Value, i reflect.Type) (reflect.Value, bool) {
d.Chk.Equal(reflect.Interface, i.Kind())
// If v is a named type and is addressable,
// start with its address, so that if the type has pointer methods,
// we find them.
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
v = v.Addr()
}
for {
if v.Type().Implements(writerType) {
return v, true
}
if nv, ok := loadValueFromInterfaceIfAddressable(v); ok {
v = nv
continue
}
if v.Kind() != reflect.Ptr {
break
}
d.Chk.False(v.IsNil())
v = v.Elem()
}
return v, false
}
// Load value from interface, but only if the result will be usefully addressable.
func loadValueFromInterfaceIfAddressable(v reflect.Value) (reflect.Value, bool) {
if v.Kind() == reflect.Interface && !v.IsNil() {
e := v.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() {
return e, true
}
}
return v, false
}
// TODO: unmarshal into *io.Reader? BUG 160
func unmarshalBlob(nom types.Blob, v reflect.Value) {
origType := v.Type() // For error reporting.
finalV := indirect(v) // To populate any nil pointers.
if v, ok := findImplementor(v, writerType); ok {
n, err := io.Copy(v.Interface().(io.Writer), nom.Reader())
d.Exp.NoError(err)
d.Exp.EqualValues(nom.Len(), n, "Blob too large")
return
}
v = finalV
// Decoding into nil interface? Stuff a reader in there.
if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
@@ -187,7 +189,7 @@ func (u *unmarshalState) unmarshalBlob(nom types.Blob, v reflect.Value) {
// Check type of target.
switch v.Kind() {
default:
u.saveError(&UnmarshalTypeError{reflect.TypeOf(nom).Name(), origType})
d.Exp.Fail(invalidTypeMsg(reflect.TypeOf(nom).Name(), origType))
return
case reflect.Array:
break
@@ -201,22 +203,18 @@ func (u *unmarshalState) unmarshalBlob(nom types.Blob, v reflect.Value) {
}
read, err := io.ReadFull(nom.Reader(), v.Bytes())
if err != nil {
u.saveError(err)
}
if read < nomLen {
u.saveError(fmt.Errorf("blob too large"))
}
d.Exp.NoError(err)
d.Exp.Equal(nomLen, read, "blob too large")
return
}
func (u *unmarshalState) unmarshalList(nom types.List, v reflect.Value) {
func unmarshalList(nom types.List, v reflect.Value) {
origType := v.Type()
v = u.indirect(v)
v = indirect(v)
// Decoding into nil interface? Switch to non-reflect code.
if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
v.Set(reflect.ValueOf(u.listInterface(nom)))
v.Set(reflect.ValueOf(listInterface(nom)))
return
} else if v.Kind() == reflect.Struct && v.Type() == refRefType {
v.Set(reflect.ValueOf(nom.Ref()))
@@ -226,7 +224,7 @@ func (u *unmarshalState) unmarshalList(nom types.List, v reflect.Value) {
// Check type of target.
switch v.Kind() {
default:
u.saveError(&UnmarshalTypeError{reflect.TypeOf(nom).Name(), origType})
d.Exp.Fail(invalidTypeMsg(reflect.TypeOf(nom).Name(), origType))
return
case reflect.Slice:
// The reflection stuff all uses int, so if nom is too big, just make v as big as possible.
@@ -242,11 +240,9 @@ func (u *unmarshalState) unmarshalList(nom types.List, v reflect.Value) {
i := 0
for ; uint64(i) < nom.Len(); i++ {
// If v is a fixed array and we've exhausted it, we just skip content from nom.
if i < v.Len() {
// Decode into element.
u.unmarshalValue(nom.Get(uint64(i)), v.Index(i))
}
d.Exp.True(i < v.Len(), "list is too large for target array of size %d", v.Len())
// Decode into element.
unmarshalValue(nom.Get(uint64(i)), v.Index(i))
}
if i < v.Len() {
@@ -262,13 +258,13 @@ func (u *unmarshalState) unmarshalList(nom types.List, v reflect.Value) {
}
}
func (u *unmarshalState) unmarshalMap(nom types.Map, v reflect.Value) {
func unmarshalMap(nom types.Map, v reflect.Value) {
origType := v.Type()
v = u.indirect(v)
v = indirect(v)
// Decoding into nil interface? Switch to non-reflect code.
if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
v.Set(reflect.ValueOf(u.mapInterface(nom)))
v.Set(reflect.ValueOf(mapInterface(nom)))
return
} else if v.Kind() == reflect.Struct && v.Type() == refRefType {
v.Set(reflect.ValueOf(nom.Ref()))
@@ -277,10 +273,10 @@ func (u *unmarshalState) unmarshalMap(nom types.Map, v reflect.Value) {
switch v.Kind() {
default:
u.saveError(&UnmarshalTypeError{reflect.TypeOf(nom).Name(), origType})
d.Exp.Fail(invalidTypeMsg(reflect.TypeOf(nom).Name(), origType))
return
case reflect.Struct:
u.unmarshalStruct(nom, v)
unmarshalStruct(nom, v)
return
case reflect.Map:
if v.IsNil() {
@@ -295,10 +291,10 @@ func (u *unmarshalState) unmarshalMap(nom types.Map, v reflect.Value) {
nom.Iter(func(key, value types.Value) (stop bool) {
mapKey.Set(reflect.Zero(keyType))
u.unmarshalValue(key, mapKey)
unmarshalValue(key, mapKey)
mapElem.Set(reflect.Zero(elemType))
u.unmarshalValue(value, mapElem)
unmarshalValue(value, mapElem)
v.SetMapIndex(mapKey, mapElem)
return
})
@@ -310,9 +306,9 @@ type primitive interface {
ToPrimitive() interface{}
}
func (u *unmarshalState) unmarshalPrimitive(nom primitive, v reflect.Value) {
func unmarshalPrimitive(nom primitive, v reflect.Value) {
origType := v.Type()
v = u.indirect(v)
v = indirect(v)
nomValue := reflect.ValueOf(nom.ToPrimitive())
if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
@@ -326,36 +322,27 @@ func (u *unmarshalState) unmarshalPrimitive(nom primitive, v reflect.Value) {
switch v.Kind() {
default:
u.saveError(&UnmarshalTypeError{reflect.TypeOf(nom).Name(), origType})
d.Exp.Fail(invalidTypeMsg(reflect.TypeOf(nom).Name(), origType))
case reflect.Bool:
v.SetBool(nomValue.Bool())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n := nomValue.Int()
if v.OverflowInt(n) {
u.saveError(&UnmarshalTypeError{fmt.Sprintf("number %d", n), origType})
break
}
d.Exp.False(v.OverflowInt(n), invalidTypeMsg(fmt.Sprintf("number %d", n), origType))
v.SetInt(n)
case reflect.Float32, reflect.Float64:
n := nomValue.Float()
if v.OverflowFloat(n) {
u.saveError(&UnmarshalTypeError{fmt.Sprintf("number %f", n), origType})
break
}
d.Exp.False(v.OverflowFloat(n), invalidTypeMsg(fmt.Sprintf("number %f", n), origType))
v.SetFloat(n)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
n := nomValue.Uint()
if v.OverflowUint(n) {
u.saveError(&UnmarshalTypeError{fmt.Sprintf("number %d", n), origType})
break
}
d.Exp.False(v.OverflowUint(n), invalidTypeMsg(fmt.Sprintf("number %d", n), origType))
v.SetUint(n)
}
}
func (u *unmarshalState) unmarshalRef(nom types.Ref, v reflect.Value) {
func unmarshalRef(nom types.Ref, v reflect.Value) {
origType := v.Type()
v = u.indirect(v)
v = indirect(v)
// Decoding into nil interface? Stuff a string in there.
if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
@@ -369,7 +356,7 @@ func (u *unmarshalState) unmarshalRef(nom types.Ref, v reflect.Value) {
// Check type of target.
switch v.Kind() {
default:
u.saveError(&UnmarshalTypeError{reflect.TypeOf(nom).Name(), origType})
d.Exp.Fail(invalidTypeMsg(reflect.TypeOf(nom).Name(), origType))
return
case reflect.String:
v.SetString(nom.Ref().String())
@@ -382,18 +369,18 @@ func (u *unmarshalState) unmarshalRef(nom types.Ref, v reflect.Value) {
reflect.Copy(v, reflect.ValueOf(nom.Ref().Digest()))
return
}
u.saveError(&UnmarshalTypeError{reflect.TypeOf(nom).Name(), origType})
d.Exp.Fail(invalidTypeMsg(reflect.TypeOf(nom).Name(), origType))
return
}
}
func (u *unmarshalState) unmarshalSet(nom types.Set, v reflect.Value) {
func unmarshalSet(nom types.Set, v reflect.Value) {
origType := v.Type()
v = u.indirect(v)
v = indirect(v)
// Decoding into nil interface? Switch to non-reflect code.
if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
v.Set(reflect.ValueOf(u.setInterface(nom)))
v.Set(reflect.ValueOf(setInterface(nom)))
return
} else if v.Kind() == reflect.Struct && v.Type() == refRefType {
v.Set(reflect.ValueOf(nom.Ref()))
@@ -403,13 +390,13 @@ func (u *unmarshalState) unmarshalSet(nom types.Set, v reflect.Value) {
// Check type of target.
switch v.Kind() {
default:
u.saveError(&UnmarshalTypeError{reflect.TypeOf(nom).Name(), origType})
d.Exp.Fail(invalidTypeMsg(reflect.TypeOf(nom).Name(), origType))
return
case reflect.Map:
// map must have bool values.
t := v.Type()
if t.Elem().Kind() != reflect.Bool {
u.saveError(&UnmarshalTypeError{reflect.TypeOf(nom).Name(), origType})
d.Exp.Fail(invalidTypeMsg(reflect.TypeOf(nom).Name(), origType))
return
}
if v.IsNil() {
@@ -422,16 +409,16 @@ func (u *unmarshalState) unmarshalSet(nom types.Set, v reflect.Value) {
newElem := reflect.New(v.Type().Key()).Elem() // New returns a pointer, hence the Elem().
trueValue := reflect.ValueOf(true)
nom.Iter(func(elem types.Value) (stop bool) {
u.unmarshalValue(elem, newElem)
unmarshalValue(elem, newElem)
v.SetMapIndex(newElem, trueValue)
return
})
return
}
func (u *unmarshalState) unmarshalString(nom types.String, v reflect.Value) {
func unmarshalString(nom types.String, v reflect.Value) {
origType := v.Type()
v = u.indirect(v)
v = indirect(v)
if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
// You can set the nil interface to a value of any type.
v.Set(reflect.ValueOf(nom.String()))
@@ -443,15 +430,15 @@ func (u *unmarshalState) unmarshalString(nom types.String, v reflect.Value) {
switch v.Kind() {
default:
u.saveError(&UnmarshalTypeError{reflect.TypeOf(nom).Name(), origType})
d.Exp.Fail(invalidTypeMsg(reflect.TypeOf(nom).Name(), origType))
case reflect.String:
v.SetString(nom.String())
}
return
}
func (u *unmarshalState) unmarshalStruct(nom types.Map, v reflect.Value) {
v = u.indirect(v)
func unmarshalStruct(nom types.Map, v reflect.Value) {
v = indirect(v)
d.Chk.Equal(reflect.Struct, v.Kind())
if v.Type() == refRefType {
@@ -489,7 +476,7 @@ func (u *unmarshalState) unmarshalStruct(nom types.Map, v reflect.Value) {
subv = subv.Field(i)
}
// subv is left pointing to the field we want to unmarshal into.
u.unmarshalValue(value, subv)
unmarshalValue(value, subv)
}
}
return
@@ -511,48 +498,50 @@ func truncateUint64(u uint64) (out int) {
// but they avoid the weight of reflection in this common case.
// valueInterface is like value but returns interface{}
func (u *unmarshalState) valueInterface(nom types.Value) interface{} {
func valueInterface(nom types.Value) interface{} {
switch nom := nom.(type) {
case types.Blob:
d.Chk.Fail("Blobs should be handled by returing blob.Reader() directly.")
panic("unreachable")
case types.List:
return u.listInterface(nom)
return listInterface(nom)
case types.Map:
return u.mapInterface(nom)
return mapInterface(nom)
case types.Set:
return u.setInterface(nom)
return setInterface(nom)
case types.String:
return nom.String()
case primitive:
return nom.ToPrimitive()
default:
u.error(fmt.Errorf("Blobs not yet supported"))
panic("unreachable")
}
}
// listInterface is like unmarshalList but returns []interface{}.
func (u *unmarshalState) listInterface(nom types.List) (v []interface{}) {
func listInterface(nom types.List) (v []interface{}) {
v = make([]interface{}, 0)
for i := uint64(0); i < nom.Len(); i++ {
v = append(v, u.valueInterface(nom.Get(i)))
v = append(v, valueInterface(nom.Get(i)))
}
return
}
// setInterface is like unmarshalSet but returns map[interface{}]bool.
func (u *unmarshalState) setInterface(nom types.Set) (v map[interface{}]bool) {
func setInterface(nom types.Set) (v map[interface{}]bool) {
v = make(map[interface{}]bool)
nom.Iter(func(elem types.Value) (stop bool) {
v[u.valueInterface(elem)] = true
v[valueInterface(elem)] = true
return
})
return
}
// mapInterface is like unmarshalMap but returns map[string]interface{}.
func (u *unmarshalState) mapInterface(nom types.Map) (m map[interface{}]interface{}) {
func mapInterface(nom types.Map) (m map[interface{}]interface{}) {
m = make(map[interface{}]interface{})
nom.Iter(func(key, value types.Value) (stop bool) {
m[u.valueInterface(key)] = u.valueInterface(value)
m[valueInterface(key)] = valueInterface(value)
return
})
return

View File

@@ -1,4 +1,4 @@
// Modified from golang's encoding/json/decode_test.go
// Modified from golang's encoding/json/decode_test.go at 80e6d638bf309181eadcb3fecbe99d2d8518e364.
package marshal
@@ -13,6 +13,7 @@ import (
"strings"
"testing"
"github.com/attic-labs/noms/d"
"github.com/attic-labs/noms/ref"
"github.com/attic-labs/noms/types"
"github.com/stretchr/testify/assert"
@@ -130,7 +131,7 @@ type unmarshalTest struct {
in types.Value
ptr interface{}
out interface{}
err error
err string
}
type Ambig struct {
@@ -158,7 +159,7 @@ var unmarshalTests = []unmarshalTest{
{in: types.NewMap(
types.NewString("X"), types.NewList(types.Int16(1)),
types.NewString("Y"), types.Int32(4)),
ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"List", reflect.TypeOf("")}},
ptr: new(T), out: T{Y: 4}, err: invalidTypeMsg("List", reflect.TypeOf(""))},
{in: strIntMap(si{"x", 1}), ptr: new(tx), out: tx{}},
// Z has a "-" tag.
@@ -171,7 +172,7 @@ var unmarshalTests = []unmarshalTest{
// array tests
{in: list(1, 2, 3), ptr: new([3]int), out: [3]int{1, 2, 3}},
{in: list(1, 2, 3), ptr: new([1]int), out: [1]int{1}},
{in: list(1, 2, 3), ptr: new([1]int), out: [1]int{1}, err: "list is too large"},
{in: list(1, 2, 3), ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}},
// blob tests
@@ -179,12 +180,12 @@ var unmarshalTests = []unmarshalTest{
// ref tests
{
in: types.Ref{R: ref.MustParse("sha1-ffffffffffffffffffffffffffffffffffffffff")},
in: types.Ref{R: ref.Parse("sha1-ffffffffffffffffffffffffffffffffffffffff")},
ptr: new(string),
out: "sha1-" + strings.Repeat("f", 40),
},
{
in: types.Ref{R: ref.MustParse("sha1-ffffffffffffffffffffffffffffffffffffffff")},
in: types.Ref{R: ref.Parse("sha1-ffffffffffffffffffffffffffffffffffffffff")},
ptr: &[]byte{},
out: byteSlice(0xff, len(ref.Sha1Digest{})),
},
@@ -284,23 +285,21 @@ func TestUnmarshal(t *testing.T) {
// v = new(right-type)
v := reflect.New(reflect.TypeOf(tt.ptr).Elem())
err := Unmarshal(tt.in, v.Interface())
if tt.err != nil {
err := d.Try(func() { Unmarshal(tt.in, v.Interface()) })
if tt.err != "" {
if assert.NotNil(err) {
assert.EqualValues(err, tt.err, "#%d: %v, want %v", i, err, tt.err)
assert.Contains(err.Error(), tt.err, "#%d: %v not in %s", i, err, tt.err)
}
continue
}
assert.NoError(err)
assert.NoError(err, "error in test #%d", i)
assert.EqualValues(tt.out, v.Elem().Interface())
// Check round trip.
nom, err := Marshal(v.Interface())
if assert.NoError(err, "#%d: error remarshaling", i) {
vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())
assert.NoError(Unmarshal(nom, vv.Interface()), "#%d: error un-remarshaling", i)
assert.EqualValues(v.Elem().Interface(), vv.Elem().Interface())
}
nom := Marshal(v.Interface())
vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())
Unmarshal(nom, vv.Interface())
assert.EqualValues(v.Elem().Interface(), vv.Elem().Interface())
}
}
@@ -319,19 +318,15 @@ func TestUnmarshalAsRef(t *testing.T) {
for _, input := range unmarshalAsRefTests {
expected := input.Ref()
target := ref.Ref{}
if !assert.NoError(Unmarshal(input, &target)) {
return
}
Unmarshal(input, &target)
assert.EqualValues(expected, target)
// Check round trip.
nom, err := Marshal(target)
if assert.NoError(err, "error remarshaling") {
newTarget := ref.Ref{}
assert.NoError(Unmarshal(nom, &newTarget), "error un-remarshaling")
assert.EqualValues(target, newTarget)
}
nom := Marshal(target)
newTarget := ref.Ref{}
Unmarshal(nom, &newTarget)
assert.EqualValues(target, newTarget)
}
}
@@ -351,8 +346,8 @@ func TestUnmarshalSetP(t *testing.T) {
return
}
err := Unmarshal(set, &target)
if !assert.NoError(err) || !assert.Len(target, len(expected)) {
Unmarshal(set, &target)
if !assert.Len(target, len(expected)) {
return
}
@@ -361,17 +356,45 @@ func TestUnmarshalSetP(t *testing.T) {
}
// Check round trip.
nom, err := Marshal(target)
if assert.NoError(err, "error remarshaling") {
newTarget := map[*Small]bool{}
if assert.NoError(Unmarshal(nom, &newTarget), "error un-remarshaling") {
for ntk := range newTarget {
assert.True(findValueInMapKeys(ntk, target))
}
}
nom := Marshal(target)
newTarget := map[*Small]bool{}
Unmarshal(nom, &newTarget)
for ntk := range newTarget {
assert.True(findValueInMapKeys(ntk, target))
}
}
func TestUnmarshalBlobIntoWriter(t *testing.T) {
assert := assert.New(t)
expected := []byte("abc")
blob := blob(expected...)
target := &bytes.Buffer{}
Unmarshal(blob, &target)
targetBytes := target.Bytes()
assert.EqualValues(expected, targetBytes)
// Check round trip.
nom := Marshal(target)
newTarget := &bytes.Buffer{}
Unmarshal(nom, &newTarget)
assert.EqualValues(targetBytes, newTarget.Bytes())
}
func TestUnmarshalBlobIntoWriterPtr(t *testing.T) {
assert := assert.New(t)
expected := []byte("abc")
blob := blob(expected...)
target := &bytes.Buffer{}
targetP := &target
Unmarshal(blob, &targetP)
targetBytes := target.Bytes()
assert.EqualValues(expected, targetBytes)
}
// Helpers for building up unmarshalTests
func sliceAddr(x []int32) *[]int32 { return &x }
func mapAddr(x map[string]int32) *map[string]int32 { return &x }
@@ -430,7 +453,7 @@ func TestUnmarshalMarshal(t *testing.T) {
if err := Unmarshal(jsonBig, &v); err != nil {
t.Fatalf("Unmarshal: %v", err)
}
b, err := Marshal(v)
b:=Marshal(v)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
@@ -447,12 +470,10 @@ func TestLargeByteSlice(t *testing.T) {
for i := range s0 {
s0[i] = byte(i)
}
b, err := Marshal(s0)
assert.NoError(t, err, "Failed to Marshal")
b := Marshal(s0)
var s1 []byte
err = Unmarshal(b, &s1)
assert.NoError(t, err, "Failed to Unmarshal")
Unmarshal(b, &s1)
if !assert.Equal(t, s0, s1, "Marshal large byte slice") {
printDiff(t, s0, s1)
}
@@ -485,7 +506,7 @@ type Xint struct {
func TestUnmarshalInterface(t *testing.T) {
var xint Xint
var i interface{} = &xint
assert.NoError(t, Unmarshal(strIntMap(si{"X", 1}), &i))
Unmarshal(strIntMap(si{"X", 1}), &i)
if xint.X != 1 {
t.Fatalf("Did not write to xint")
}
@@ -494,7 +515,7 @@ func TestUnmarshalInterface(t *testing.T) {
func TestUnmarshalPtrPtr(t *testing.T) {
var xint Xint
pxint := &xint
assert.NoError(t, Unmarshal(strIntMap(si{"X", 1}), &pxint))
Unmarshal(strIntMap(si{"X", 1}), &pxint)
if xint.X != 1 {
t.Fatalf("Did not write to xint")
}
@@ -533,25 +554,26 @@ func TestInterfaceSet(t *testing.T) {
for _, tt := range interfaceSetTests {
native := struct{ X interface{} }{tt.pre}
nom := types.NewMap(types.NewString("X"), tt.nom)
assert.NoError(t, Unmarshal(nom, &native))
Unmarshal(nom, &native)
assert.EqualValues(t, tt.post, native.X, "Unmarshal %v over %#v: X=%#v, want %#v", nom, tt.pre, native.X, tt.post)
}
}
// TODO: enable blobs to be unmarshaled to readers and writers, then add test cases here (BUG 160)
// TODO: enable blobs to be unmarshaled to *io.Reader, then add test cases here (BUG 160)
var blobInterfaceSetTests = []struct {
pre interface{}
nom types.Blob
post []byte
}{
{"foo", blob(1, 2, 3), []byte{1, 2, 3}},
{bytes.NewBuffer([]byte{7}), blob(4, 5, 6), []byte{7, 4, 5, 6}},
}
func TestBlobInterfaceSet(t *testing.T) {
for _, tt := range blobInterfaceSetTests {
native := struct{ X interface{} }{tt.pre}
nom := types.NewMap(types.NewString("X"), tt.nom)
assert.NoError(t, Unmarshal(nom, &native))
Unmarshal(nom, &native)
bytes, err := ioutil.ReadAll(native.X.(io.Reader))
if assert.NoError(t, err) {
assert.Equal(t, tt.post, bytes)
@@ -568,10 +590,8 @@ func TestStringKind(t *testing.T) {
"foo": 42,
}
data, err := Marshal(m1)
assert.NoError(err)
err = Unmarshal(data, &m2)
assert.NoError(err)
data := Marshal(m1)
Unmarshal(data, &m2)
assert.EqualValues(m1, m2)
}
@@ -585,12 +605,10 @@ func TestByteKind(t *testing.T) {
a := byteKind("hello")
data, err := Marshal(a)
assert.NoError(err)
data := Marshal(a)
var b byteKind
err = Unmarshal(data, &b)
assert.NoError(err)
Unmarshal(data, &b)
assert.EqualValues(a, b)
}
@@ -609,8 +627,8 @@ var decodeTypeErrorTests = []struct {
func TestUnmarshalTypeError(t *testing.T) {
for _, item := range decodeTypeErrorTests {
err := Unmarshal(item.src, item.dest)
assert.IsType(t, &UnmarshalTypeError{}, err, "expected type error for Unmarshal(%v, type %T): got %T (%v)",
err := d.Try(func() { Unmarshal(item.src, item.dest) })
assert.IsType(t, d.UsageError{}, err, "expected type error for Unmarshal(%v, type %T): got %T (%v)",
item.src, item.dest, err, err)
}
}
@@ -630,7 +648,7 @@ func TestUnmarshalUnexported(t *testing.T) {
expected := &unexportedFields{Name: "Bob"}
out := &unexportedFields{}
assert.NoError(t, Unmarshal(input, out))
Unmarshal(input, out)
assert.EqualValues(t, expected, out)
}
@@ -659,8 +677,7 @@ func TestPrefilled(t *testing.T) {
for _, tt := range prefillTests {
ptrstr := fmt.Sprintf("%v", tt.ptr)
err := Unmarshal(tt.in, tt.ptr) // tt.ptr edited here
assert.NoError(t, err)
Unmarshal(tt.in, tt.ptr) // tt.ptr edited here
assert.EqualValues(t, tt.ptr, tt.out, "Target should have been overwritten, was originally %s", ptrstr)
}
}
@@ -678,8 +695,8 @@ var invalidUnmarshalTests = []struct {
func TestInvalidUnmarshal(t *testing.T) {
nom := types.NewString("hello")
for _, tt := range invalidUnmarshalTests {
if err := Unmarshal(nom, tt.v); assert.Error(t, err) {
assert.Equal(t, tt.want, err.Error())
if err := d.Try(func() { Unmarshal(nom, tt.v) }); assert.Error(t, err) {
assert.Contains(t, err.Error(), tt.want)
} else {
assert.Fail(t, "Expecting error!")
}

View File

@@ -31,8 +31,8 @@ func NewBlob(r io.Reader) (Blob, error) {
blobs := []Future{}
var blob blobLeaf
for {
buf := bytes.Buffer{}
n, err := copyChunk(&buf, r)
buf := &bytes.Buffer{}
n, err := copyChunk(buf, r)
if err != nil {
return nil, err
}