3795 lines
112 KiB
Go
3795 lines
112 KiB
Go
|
// Copyright (C) MongoDB, Inc. 2017-present.
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||
|
// not use this file except in compliance with the License. You may obtain
|
||
|
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
package bsoncodec
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"math"
|
||
|
"net/url"
|
||
|
"reflect"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/google/go-cmp/cmp"
|
||
|
"go.mongodb.org/mongo-driver/bson/bsonrw"
|
||
|
"go.mongodb.org/mongo-driver/bson/bsonrw/bsonrwtest"
|
||
|
"go.mongodb.org/mongo-driver/bson/bsontype"
|
||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||
|
"go.mongodb.org/mongo-driver/internal/testutil/assert"
|
||
|
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
defaultTestStructCodec = newDefaultStructCodec()
|
||
|
)
|
||
|
|
||
|
func TestDefaultValueDecoders(t *testing.T) {
|
||
|
var dvd DefaultValueDecoders
|
||
|
var wrong = func(string, string) string { return "wrong" }
|
||
|
|
||
|
type mybool bool
|
||
|
type myint8 int8
|
||
|
type myint16 int16
|
||
|
type myint32 int32
|
||
|
type myint64 int64
|
||
|
type myint int
|
||
|
type myuint8 uint8
|
||
|
type myuint16 uint16
|
||
|
type myuint32 uint32
|
||
|
type myuint64 uint64
|
||
|
type myuint uint
|
||
|
type myfloat32 float32
|
||
|
type myfloat64 float64
|
||
|
type mystring string
|
||
|
type mystruct struct{}
|
||
|
|
||
|
const cansetreflectiontest = "cansetreflectiontest"
|
||
|
const cansettest = "cansettest"
|
||
|
|
||
|
now := time.Now().Truncate(time.Millisecond)
|
||
|
d128 := primitive.NewDecimal128(12345, 67890)
|
||
|
var pbool = func(b bool) *bool { return &b }
|
||
|
var pi32 = func(i32 int32) *int32 { return &i32 }
|
||
|
var pi64 = func(i64 int64) *int64 { return &i64 }
|
||
|
|
||
|
type subtest struct {
|
||
|
name string
|
||
|
val interface{}
|
||
|
dctx *DecodeContext
|
||
|
llvrw *bsonrwtest.ValueReaderWriter
|
||
|
invoke bsonrwtest.Invoked
|
||
|
err error
|
||
|
}
|
||
|
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
vd ValueDecoder
|
||
|
subtests []subtest
|
||
|
}{
|
||
|
{
|
||
|
"BooleanDecodeValue",
|
||
|
ValueDecoderFunc(dvd.BooleanDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Boolean},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "BooleanDecodeValue", Kinds: []reflect.Kind{reflect.Bool}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not boolean",
|
||
|
bool(false),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a boolean", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"fast path",
|
||
|
bool(true),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Boolean, Return: bool(true)},
|
||
|
bsonrwtest.ReadBoolean,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"reflection path",
|
||
|
mybool(true),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Boolean, Return: bool(true)},
|
||
|
bsonrwtest.ReadBoolean,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"reflection path error",
|
||
|
mybool(true),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Boolean, Return: bool(true), Err: errors.New("ReadBoolean Error"), ErrAfter: bsonrwtest.ReadBoolean},
|
||
|
bsonrwtest.ReadBoolean, errors.New("ReadBoolean Error"),
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Boolean},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "BooleanDecodeValue", Kinds: []reflect.Kind{reflect.Bool}},
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
mybool(false),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
mybool(false),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"IntDecodeValue",
|
||
|
ValueDecoderFunc(dvd.IntDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)},
|
||
|
bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "IntDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int},
|
||
|
Received: reflect.ValueOf(wrong),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"type not int32/int64",
|
||
|
0,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into an integer type", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadInt32 error",
|
||
|
0,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0), Err: errors.New("ReadInt32 error"), ErrAfter: bsonrwtest.ReadInt32},
|
||
|
bsonrwtest.ReadInt32,
|
||
|
errors.New("ReadInt32 error"),
|
||
|
},
|
||
|
{
|
||
|
"ReadInt64 error",
|
||
|
0,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(0), Err: errors.New("ReadInt64 error"), ErrAfter: bsonrwtest.ReadInt64},
|
||
|
bsonrwtest.ReadInt64,
|
||
|
errors.New("ReadInt64 error"),
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble error",
|
||
|
0,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(0), Err: errors.New("ReadDouble error"), ErrAfter: bsonrwtest.ReadDouble},
|
||
|
bsonrwtest.ReadDouble,
|
||
|
errors.New("ReadDouble error"),
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble", int64(3), &DecodeContext{},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.00)}, bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble (truncate)", int64(3), &DecodeContext{Truncate: true},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14)}, bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble (no truncate)", int64(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14)}, bsonrwtest.ReadDouble,
|
||
|
errCannotTruncate,
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble overflows int64", int64(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: math.MaxFloat64}, bsonrwtest.ReadDouble,
|
||
|
fmt.Errorf("%g overflows int64", math.MaxFloat64),
|
||
|
},
|
||
|
{"int8/fast path", int8(127), nil, &bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(127)}, bsonrwtest.ReadInt32, nil},
|
||
|
{"int16/fast path", int16(32676), nil, &bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(32676)}, bsonrwtest.ReadInt32, nil},
|
||
|
{"int32/fast path", int32(1234), nil, &bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(1234)}, bsonrwtest.ReadInt32, nil},
|
||
|
{"int64/fast path", int64(1234), nil, &bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(1234)}, bsonrwtest.ReadInt64, nil},
|
||
|
{"int/fast path", int(1234), nil, &bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(1234)}, bsonrwtest.ReadInt64, nil},
|
||
|
{
|
||
|
"int8/fast path - nil", (*int8)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)}, bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "IntDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int},
|
||
|
Received: reflect.ValueOf((*int8)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"int16/fast path - nil", (*int16)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)}, bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "IntDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int},
|
||
|
Received: reflect.ValueOf((*int16)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"int32/fast path - nil", (*int32)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)}, bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "IntDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int},
|
||
|
Received: reflect.ValueOf((*int32)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"int64/fast path - nil", (*int64)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)}, bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "IntDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int},
|
||
|
Received: reflect.ValueOf((*int64)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"int/fast path - nil", (*int)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)}, bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "IntDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int},
|
||
|
Received: reflect.ValueOf((*int)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"int8/fast path - overflow", int8(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(129)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows int8", 129),
|
||
|
},
|
||
|
{
|
||
|
"int16/fast path - overflow", int16(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(32768)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows int16", 32768),
|
||
|
},
|
||
|
{
|
||
|
"int32/fast path - overflow", int32(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(2147483648)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows int32", int64(2147483648)),
|
||
|
},
|
||
|
{
|
||
|
"int8/fast path - overflow (negative)", int8(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(-129)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows int8", -129),
|
||
|
},
|
||
|
{
|
||
|
"int16/fast path - overflow (negative)", int16(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(-32769)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows int16", -32769),
|
||
|
},
|
||
|
{
|
||
|
"int32/fast path - overflow (negative)", int32(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(-2147483649)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows int32", int64(-2147483649)),
|
||
|
},
|
||
|
{
|
||
|
"int8/reflection path", myint8(127), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(127)}, bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"int16/reflection path", myint16(255), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(255)}, bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"int32/reflection path", myint32(511), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(511)}, bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"int64/reflection path", myint64(1023), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(1023)}, bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"int/reflection path", myint(2047), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(2047)}, bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"int8/reflection path - overflow", myint8(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(129)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows int8", 129),
|
||
|
},
|
||
|
{
|
||
|
"int16/reflection path - overflow", myint16(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(32768)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows int16", 32768),
|
||
|
},
|
||
|
{
|
||
|
"int32/reflection path - overflow", myint32(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(2147483648)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows int32", int64(2147483648)),
|
||
|
},
|
||
|
{
|
||
|
"int8/reflection path - overflow (negative)", myint8(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(-129)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows int8", -129),
|
||
|
},
|
||
|
{
|
||
|
"int16/reflection path - overflow (negative)", myint16(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(-32769)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows int16", -32769),
|
||
|
},
|
||
|
{
|
||
|
"int32/reflection path - overflow (negative)", myint32(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(-2147483649)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows int32", int64(-2147483649)),
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{
|
||
|
Name: "IntDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
myint(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
myint(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"defaultUIntCodec.DecodeValue",
|
||
|
defaultUIntCodec,
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)},
|
||
|
bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "UintDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
|
||
|
Received: reflect.ValueOf(wrong),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"type not int32/int64",
|
||
|
0,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into an integer type", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadInt32 error",
|
||
|
uint(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0), Err: errors.New("ReadInt32 error"), ErrAfter: bsonrwtest.ReadInt32},
|
||
|
bsonrwtest.ReadInt32,
|
||
|
errors.New("ReadInt32 error"),
|
||
|
},
|
||
|
{
|
||
|
"ReadInt64 error",
|
||
|
uint(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(0), Err: errors.New("ReadInt64 error"), ErrAfter: bsonrwtest.ReadInt64},
|
||
|
bsonrwtest.ReadInt64,
|
||
|
errors.New("ReadInt64 error"),
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble error",
|
||
|
0,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(0), Err: errors.New("ReadDouble error"), ErrAfter: bsonrwtest.ReadDouble},
|
||
|
bsonrwtest.ReadDouble,
|
||
|
errors.New("ReadDouble error"),
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble", uint64(3), &DecodeContext{},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.00)}, bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble (truncate)", uint64(3), &DecodeContext{Truncate: true},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14)}, bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble (no truncate)", uint64(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14)}, bsonrwtest.ReadDouble,
|
||
|
errCannotTruncate,
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble overflows int64", uint64(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: math.MaxFloat64}, bsonrwtest.ReadDouble,
|
||
|
fmt.Errorf("%g overflows int64", math.MaxFloat64),
|
||
|
},
|
||
|
{"uint8/fast path", uint8(127), nil, &bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(127)}, bsonrwtest.ReadInt32, nil},
|
||
|
{"uint16/fast path", uint16(255), nil, &bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(255)}, bsonrwtest.ReadInt32, nil},
|
||
|
{"uint32/fast path", uint32(1234), nil, &bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(1234)}, bsonrwtest.ReadInt32, nil},
|
||
|
{"uint64/fast path", uint64(1234), nil, &bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(1234)}, bsonrwtest.ReadInt64, nil},
|
||
|
{"uint/fast path", uint(1234), nil, &bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(1234)}, bsonrwtest.ReadInt64, nil},
|
||
|
{
|
||
|
"uint8/fast path - nil", (*uint8)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)}, bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "UintDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
|
||
|
Received: reflect.ValueOf((*uint8)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"uint16/fast path - nil", (*uint16)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)}, bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "UintDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
|
||
|
Received: reflect.ValueOf((*uint16)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"uint32/fast path - nil", (*uint32)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)}, bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "UintDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
|
||
|
Received: reflect.ValueOf((*uint32)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"uint64/fast path - nil", (*uint64)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)}, bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "UintDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
|
||
|
Received: reflect.ValueOf((*uint64)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"uint/fast path - nil", (*uint)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)}, bsonrwtest.ReadInt32,
|
||
|
ValueDecoderError{
|
||
|
Name: "UintDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
|
||
|
Received: reflect.ValueOf((*uint)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"uint8/fast path - overflow", uint8(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(1 << 8)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows uint8", 1<<8),
|
||
|
},
|
||
|
{
|
||
|
"uint16/fast path - overflow", uint16(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(1 << 16)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows uint16", 1<<16),
|
||
|
},
|
||
|
{
|
||
|
"uint32/fast path - overflow", uint32(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(1 << 32)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows uint32", int64(1<<32)),
|
||
|
},
|
||
|
{
|
||
|
"uint8/fast path - overflow (negative)", uint8(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(-1)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows uint8", -1),
|
||
|
},
|
||
|
{
|
||
|
"uint16/fast path - overflow (negative)", uint16(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(-1)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows uint16", -1),
|
||
|
},
|
||
|
{
|
||
|
"uint32/fast path - overflow (negative)", uint32(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(-1)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows uint32", -1),
|
||
|
},
|
||
|
{
|
||
|
"uint64/fast path - overflow (negative)", uint64(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(-1)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows uint64", -1),
|
||
|
},
|
||
|
{
|
||
|
"uint/fast path - overflow (negative)", uint(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(-1)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows uint", -1),
|
||
|
},
|
||
|
{
|
||
|
"uint8/reflection path", myuint8(127), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(127)}, bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"uint16/reflection path", myuint16(255), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(255)}, bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"uint32/reflection path", myuint32(511), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(511)}, bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"uint64/reflection path", myuint64(1023), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(1023)}, bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"uint/reflection path", myuint(2047), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(2047)}, bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"uint8/reflection path - overflow", myuint8(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(1 << 8)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows uint8", 1<<8),
|
||
|
},
|
||
|
{
|
||
|
"uint16/reflection path - overflow", myuint16(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(1 << 16)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows uint16", 1<<16),
|
||
|
},
|
||
|
{
|
||
|
"uint32/reflection path - overflow", myuint32(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(1 << 32)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows uint32", int64(1<<32)),
|
||
|
},
|
||
|
{
|
||
|
"uint8/reflection path - overflow (negative)", myuint8(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(-1)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows uint8", -1),
|
||
|
},
|
||
|
{
|
||
|
"uint16/reflection path - overflow (negative)", myuint16(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(-1)}, bsonrwtest.ReadInt32,
|
||
|
fmt.Errorf("%d overflows uint16", -1),
|
||
|
},
|
||
|
{
|
||
|
"uint32/reflection path - overflow (negative)", myuint32(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(-1)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows uint32", -1),
|
||
|
},
|
||
|
{
|
||
|
"uint64/reflection path - overflow (negative)", myuint64(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(-1)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows uint64", -1),
|
||
|
},
|
||
|
{
|
||
|
"uint/reflection path - overflow (negative)", myuint(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(-1)}, bsonrwtest.ReadInt64,
|
||
|
fmt.Errorf("%d overflows uint", -1),
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0)},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{
|
||
|
Name: "UintDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"FloatDecodeValue",
|
||
|
ValueDecoderFunc(dvd.FloatDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(0)},
|
||
|
bsonrwtest.ReadDouble,
|
||
|
ValueDecoderError{
|
||
|
Name: "FloatDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Float32, reflect.Float64},
|
||
|
Received: reflect.ValueOf(wrong),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"type not double",
|
||
|
0,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a float32 or float64 type", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble error",
|
||
|
float64(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(0), Err: errors.New("ReadDouble error"), ErrAfter: bsonrwtest.ReadDouble},
|
||
|
bsonrwtest.ReadDouble,
|
||
|
errors.New("ReadDouble error"),
|
||
|
},
|
||
|
{
|
||
|
"ReadInt32 error",
|
||
|
float64(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(0), Err: errors.New("ReadInt32 error"), ErrAfter: bsonrwtest.ReadInt32},
|
||
|
bsonrwtest.ReadInt32,
|
||
|
errors.New("ReadInt32 error"),
|
||
|
},
|
||
|
{
|
||
|
"ReadInt64 error",
|
||
|
float64(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(0), Err: errors.New("ReadInt64 error"), ErrAfter: bsonrwtest.ReadInt64},
|
||
|
bsonrwtest.ReadInt64,
|
||
|
errors.New("ReadInt64 error"),
|
||
|
},
|
||
|
{
|
||
|
"float64/int32", float32(32.0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(32)}, bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"float64/int64", float32(64.0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(64)}, bsonrwtest.ReadInt64,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"float32/fast path (equal)", float32(3.0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.0)}, bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"float64/fast path", float64(3.14159), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14159)}, bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"float32/fast path (truncate)", float32(3.14), &DecodeContext{Truncate: true},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14)}, bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"float32/fast path (no truncate)", float32(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14)}, bsonrwtest.ReadDouble,
|
||
|
errCannotTruncate,
|
||
|
},
|
||
|
{
|
||
|
"float32/fast path - nil", (*float32)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(0)}, bsonrwtest.ReadDouble,
|
||
|
ValueDecoderError{
|
||
|
Name: "FloatDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Float32, reflect.Float64},
|
||
|
Received: reflect.ValueOf((*float32)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"float64/fast path - nil", (*float64)(nil), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(0)}, bsonrwtest.ReadDouble,
|
||
|
ValueDecoderError{
|
||
|
Name: "FloatDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Float32, reflect.Float64},
|
||
|
Received: reflect.ValueOf((*float64)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"float32/reflection path (equal)", myfloat32(3.0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.0)}, bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"float64/reflection path", myfloat64(3.14159), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14159)}, bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"float32/reflection path (truncate)", myfloat32(3.14), &DecodeContext{Truncate: true},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14)}, bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"float32/reflection path (no truncate)", myfloat32(0), nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14)}, bsonrwtest.ReadDouble,
|
||
|
errCannotTruncate,
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(0)},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{
|
||
|
Name: "FloatDecodeValue",
|
||
|
Kinds: []reflect.Kind{reflect.Float32, reflect.Float64},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"defaultTimeCodec.DecodeValue",
|
||
|
defaultTimeCodec,
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.DateTime, Return: int64(0)},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "TimeDecodeValue", Types: []reflect.Type{tTime}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"ReadDateTime error",
|
||
|
time.Time{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.DateTime, Return: int64(0), Err: errors.New("ReadDateTime error"), ErrAfter: bsonrwtest.ReadDateTime},
|
||
|
bsonrwtest.ReadDateTime,
|
||
|
errors.New("ReadDateTime error"),
|
||
|
},
|
||
|
{
|
||
|
"time.Time",
|
||
|
now,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.DateTime, Return: now.UnixNano() / int64(time.Millisecond)},
|
||
|
bsonrwtest.ReadDateTime,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.DateTime, Return: int64(0)},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "TimeDecodeValue", Types: []reflect.Type{tTime}},
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
time.Time{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
time.Time{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"defaultMapCodec.DecodeValue",
|
||
|
defaultMapCodec,
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong kind",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "MapDecodeValue", Kinds: []reflect.Kind{reflect.Map}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"wrong kind (non-string key)",
|
||
|
map[bool]interface{}{},
|
||
|
&DecodeContext{Registry: buildDefaultRegistry()},
|
||
|
&bsonrwtest.ValueReaderWriter{},
|
||
|
bsonrwtest.ReadElement,
|
||
|
fmt.Errorf("unsupported key type: %T", false),
|
||
|
},
|
||
|
{
|
||
|
"ReadDocument Error",
|
||
|
make(map[string]interface{}),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{Err: errors.New("rd error"), ErrAfter: bsonrwtest.ReadDocument},
|
||
|
bsonrwtest.ReadDocument,
|
||
|
errors.New("rd error"),
|
||
|
},
|
||
|
{
|
||
|
"Lookup Error",
|
||
|
map[string]string{},
|
||
|
&DecodeContext{Registry: NewRegistryBuilder().Build()},
|
||
|
&bsonrwtest.ValueReaderWriter{},
|
||
|
bsonrwtest.ReadDocument,
|
||
|
ErrNoDecoder{Type: reflect.TypeOf("")},
|
||
|
},
|
||
|
{
|
||
|
"ReadElement Error",
|
||
|
make(map[string]interface{}),
|
||
|
&DecodeContext{Registry: buildDefaultRegistry()},
|
||
|
&bsonrwtest.ValueReaderWriter{Err: errors.New("re error"), ErrAfter: bsonrwtest.ReadElement},
|
||
|
bsonrwtest.ReadElement,
|
||
|
errors.New("re error"),
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "MapDecodeValue", Kinds: []reflect.Kind{reflect.Map}},
|
||
|
},
|
||
|
{
|
||
|
"wrong BSON type",
|
||
|
map[string]interface{}{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
errors.New("cannot decode string into a map[string]interface {}"),
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
(map[string]interface{})(nil),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
(map[string]interface{})(nil),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"ArrayDecodeValue",
|
||
|
ValueDecoderFunc(dvd.ArrayDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong kind",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "ArrayDecodeValue", Kinds: []reflect.Kind{reflect.Array}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "ArrayDecodeValue", Kinds: []reflect.Kind{reflect.Array}},
|
||
|
},
|
||
|
{
|
||
|
"Not Type Array",
|
||
|
[1]interface{}{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
errors.New("cannot decode string into an array"),
|
||
|
},
|
||
|
{
|
||
|
"ReadArray Error",
|
||
|
[1]interface{}{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{Err: errors.New("ra error"), ErrAfter: bsonrwtest.ReadArray, BSONType: bsontype.Array},
|
||
|
bsonrwtest.ReadArray,
|
||
|
errors.New("ra error"),
|
||
|
},
|
||
|
{
|
||
|
"Lookup Error",
|
||
|
[1]string{},
|
||
|
&DecodeContext{Registry: NewRegistryBuilder().Build()},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Array},
|
||
|
bsonrwtest.ReadArray,
|
||
|
ErrNoDecoder{Type: reflect.TypeOf("")},
|
||
|
},
|
||
|
{
|
||
|
"ReadValue Error",
|
||
|
[1]string{},
|
||
|
&DecodeContext{Registry: buildDefaultRegistry()},
|
||
|
&bsonrwtest.ValueReaderWriter{Err: errors.New("rv error"), ErrAfter: bsonrwtest.ReadValue, BSONType: bsontype.Array},
|
||
|
bsonrwtest.ReadValue,
|
||
|
errors.New("rv error"),
|
||
|
},
|
||
|
{
|
||
|
"DecodeValue Error",
|
||
|
[1]string{},
|
||
|
&DecodeContext{Registry: buildDefaultRegistry()},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Array},
|
||
|
bsonrwtest.ReadValue,
|
||
|
&DecodeError{keys: []string{"0"}, wrapped: errors.New("cannot decode array into a string type")},
|
||
|
},
|
||
|
{
|
||
|
"Document but not D",
|
||
|
[1]string{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Type(0)},
|
||
|
bsonrwtest.Nothing,
|
||
|
errors.New("cannot decode document into [1]string"),
|
||
|
},
|
||
|
{
|
||
|
"EmbeddedDocument but not D",
|
||
|
[1]string{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.EmbeddedDocument},
|
||
|
bsonrwtest.Nothing,
|
||
|
errors.New("cannot decode document into [1]string"),
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
[1]string{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
[1]string{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"defaultSliceCodec.DecodeValue",
|
||
|
defaultSliceCodec,
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong kind",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "SliceDecodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "SliceDecodeValue", Kinds: []reflect.Kind{reflect.Slice}},
|
||
|
},
|
||
|
{
|
||
|
"Not Type Array",
|
||
|
[]interface{}{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32},
|
||
|
bsonrwtest.Nothing,
|
||
|
errors.New("cannot decode 32-bit integer into a slice"),
|
||
|
},
|
||
|
{
|
||
|
"ReadArray Error",
|
||
|
[]interface{}{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{Err: errors.New("ra error"), ErrAfter: bsonrwtest.ReadArray, BSONType: bsontype.Array},
|
||
|
bsonrwtest.ReadArray,
|
||
|
errors.New("ra error"),
|
||
|
},
|
||
|
{
|
||
|
"Lookup Error",
|
||
|
[]string{},
|
||
|
&DecodeContext{Registry: NewRegistryBuilder().Build()},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Array},
|
||
|
bsonrwtest.ReadArray,
|
||
|
ErrNoDecoder{Type: reflect.TypeOf("")},
|
||
|
},
|
||
|
{
|
||
|
"ReadValue Error",
|
||
|
[]string{},
|
||
|
&DecodeContext{Registry: buildDefaultRegistry()},
|
||
|
&bsonrwtest.ValueReaderWriter{Err: errors.New("rv error"), ErrAfter: bsonrwtest.ReadValue, BSONType: bsontype.Array},
|
||
|
bsonrwtest.ReadValue,
|
||
|
errors.New("rv error"),
|
||
|
},
|
||
|
{
|
||
|
"DecodeValue Error",
|
||
|
[]string{},
|
||
|
&DecodeContext{Registry: buildDefaultRegistry()},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Array},
|
||
|
bsonrwtest.ReadValue,
|
||
|
&DecodeError{keys: []string{"0"}, wrapped: errors.New("cannot decode array into a string type")},
|
||
|
},
|
||
|
{
|
||
|
"Document but not D",
|
||
|
[]string{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Type(0)},
|
||
|
bsonrwtest.Nothing,
|
||
|
errors.New("cannot decode document into []string"),
|
||
|
},
|
||
|
{
|
||
|
"EmbeddedDocument but not D",
|
||
|
[]string{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.EmbeddedDocument},
|
||
|
bsonrwtest.Nothing,
|
||
|
errors.New("cannot decode document into []string"),
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
([]string)(nil),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
([]string)(nil),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"ObjectIDDecodeValue",
|
||
|
ValueDecoderFunc(dvd.ObjectIDDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.ObjectID},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "ObjectIDDecodeValue", Types: []reflect.Type{tOID}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not objectID",
|
||
|
primitive.ObjectID{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into an ObjectID", bsontype.Int32),
|
||
|
},
|
||
|
{
|
||
|
"ReadObjectID Error",
|
||
|
primitive.ObjectID{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.ObjectID, Err: errors.New("roid error"), ErrAfter: bsonrwtest.ReadObjectID},
|
||
|
bsonrwtest.ReadObjectID,
|
||
|
errors.New("roid error"),
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.ObjectID, Return: primitive.ObjectID{}},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "ObjectIDDecodeValue", Types: []reflect.Type{tOID}},
|
||
|
},
|
||
|
{
|
||
|
"success",
|
||
|
primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{
|
||
|
BSONType: bsontype.ObjectID,
|
||
|
Return: primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
|
||
|
},
|
||
|
bsonrwtest.ReadObjectID,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"success/string",
|
||
|
primitive.ObjectID{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{
|
||
|
BSONType: bsontype.String,
|
||
|
Return: "0123456789ab",
|
||
|
},
|
||
|
bsonrwtest.ReadString,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"success/string-hex",
|
||
|
primitive.ObjectID{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{
|
||
|
BSONType: bsontype.String,
|
||
|
Return: "303132333435363738396162",
|
||
|
},
|
||
|
bsonrwtest.ReadString,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.ObjectID{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.ObjectID{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"Decimal128DecodeValue",
|
||
|
ValueDecoderFunc(dvd.Decimal128DecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Decimal128},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "Decimal128DecodeValue", Types: []reflect.Type{tDecimal}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not decimal128",
|
||
|
primitive.Decimal128{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a primitive.Decimal128", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadDecimal128 Error",
|
||
|
primitive.Decimal128{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Decimal128, Err: errors.New("rd128 error"), ErrAfter: bsonrwtest.ReadDecimal128},
|
||
|
bsonrwtest.ReadDecimal128,
|
||
|
errors.New("rd128 error"),
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Decimal128, Return: d128},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "Decimal128DecodeValue", Types: []reflect.Type{tDecimal}},
|
||
|
},
|
||
|
{
|
||
|
"success",
|
||
|
d128,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Decimal128, Return: d128},
|
||
|
bsonrwtest.ReadDecimal128,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.Decimal128{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.Decimal128{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"JSONNumberDecodeValue",
|
||
|
ValueDecoderFunc(dvd.JSONNumberDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.ObjectID},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "JSONNumberDecodeValue", Types: []reflect.Type{tJSONNumber}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not double/int32/int64",
|
||
|
json.Number(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a json.Number", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadDouble Error",
|
||
|
json.Number(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Err: errors.New("rd error"), ErrAfter: bsonrwtest.ReadDouble},
|
||
|
bsonrwtest.ReadDouble,
|
||
|
errors.New("rd error"),
|
||
|
},
|
||
|
{
|
||
|
"ReadInt32 Error",
|
||
|
json.Number(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Err: errors.New("ri32 error"), ErrAfter: bsonrwtest.ReadInt32},
|
||
|
bsonrwtest.ReadInt32,
|
||
|
errors.New("ri32 error"),
|
||
|
},
|
||
|
{
|
||
|
"ReadInt64 Error",
|
||
|
json.Number(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Err: errors.New("ri64 error"), ErrAfter: bsonrwtest.ReadInt64},
|
||
|
bsonrwtest.ReadInt64,
|
||
|
errors.New("ri64 error"),
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.ObjectID, Return: primitive.ObjectID{}},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "JSONNumberDecodeValue", Types: []reflect.Type{tJSONNumber}},
|
||
|
},
|
||
|
{
|
||
|
"success/double",
|
||
|
json.Number("3.14159"),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14159)},
|
||
|
bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"success/int32",
|
||
|
json.Number("12345"),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32, Return: int32(12345)},
|
||
|
bsonrwtest.ReadInt32,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"success/int64",
|
||
|
json.Number("1234567890"),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int64, Return: int64(1234567890)},
|
||
|
bsonrwtest.ReadInt64,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
json.Number(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
json.Number(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"URLDecodeValue",
|
||
|
ValueDecoderFunc(dvd.URLDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
url.URL{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a *url.URL", bsontype.Int32),
|
||
|
},
|
||
|
{
|
||
|
"type not *url.URL",
|
||
|
int64(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String, Return: "http://example.com"},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "URLDecodeValue", Types: []reflect.Type{tURL}, Received: reflect.ValueOf(int64(0))},
|
||
|
},
|
||
|
{
|
||
|
"ReadString error",
|
||
|
url.URL{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String, Err: errors.New("rs error"), ErrAfter: bsonrwtest.ReadString},
|
||
|
bsonrwtest.ReadString,
|
||
|
errors.New("rs error"),
|
||
|
},
|
||
|
{
|
||
|
"url.Parse error",
|
||
|
url.URL{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String, Return: "not-valid-%%%%://"},
|
||
|
bsonrwtest.ReadString,
|
||
|
&url.Error{
|
||
|
Op: "parse",
|
||
|
URL: "not-valid-%%%%://",
|
||
|
Err: errors.New("first path segment in URL cannot contain colon"),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String, Return: "http://example.com"},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "URLDecodeValue", Types: []reflect.Type{tURL}},
|
||
|
},
|
||
|
{
|
||
|
"url.URL",
|
||
|
url.URL{Scheme: "http", Host: "example.com"},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String, Return: "http://example.com"},
|
||
|
bsonrwtest.ReadString,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
url.URL{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
url.URL{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"defaultByteSliceCodec.DecodeValue",
|
||
|
defaultByteSliceCodec,
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
[]byte{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a []byte", bsontype.Int32),
|
||
|
},
|
||
|
{
|
||
|
"type not []byte",
|
||
|
int64(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Binary, Return: bsoncore.Value{Type: bsontype.Binary}},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "ByteSliceDecodeValue", Types: []reflect.Type{tByteSlice}, Received: reflect.ValueOf(int64(0))},
|
||
|
},
|
||
|
{
|
||
|
"ReadBinary error",
|
||
|
[]byte{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Binary, Err: errors.New("rb error"), ErrAfter: bsonrwtest.ReadBinary},
|
||
|
bsonrwtest.ReadBinary,
|
||
|
errors.New("rb error"),
|
||
|
},
|
||
|
{
|
||
|
"incorrect subtype",
|
||
|
[]byte{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{
|
||
|
BSONType: bsontype.Binary,
|
||
|
Return: bsoncore.Value{
|
||
|
Type: bsontype.Binary,
|
||
|
Data: bsoncore.AppendBinary(nil, 0xFF, []byte{0x01, 0x02, 0x03}),
|
||
|
},
|
||
|
},
|
||
|
bsonrwtest.ReadBinary,
|
||
|
decodeBinaryError{subtype: byte(0xFF), typeName: "[]byte"},
|
||
|
},
|
||
|
{
|
||
|
"can set false",
|
||
|
cansettest,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Binary, Return: bsoncore.AppendBinary(nil, 0x00, []byte{0x01, 0x02, 0x03})},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "ByteSliceDecodeValue", Types: []reflect.Type{tByteSlice}},
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
([]byte)(nil),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
([]byte)(nil),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"defaultStringCodec.DecodeValue",
|
||
|
defaultStringCodec,
|
||
|
[]subtest{
|
||
|
{
|
||
|
"symbol",
|
||
|
"var hello = 'world';",
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Symbol, Return: "var hello = 'world';"},
|
||
|
bsonrwtest.ReadSymbol,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
"",
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
"",
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"ValueUnmarshalerDecodeValue",
|
||
|
ValueDecoderFunc(dvd.ValueUnmarshalerDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
nil,
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{
|
||
|
Name: "ValueUnmarshalerDecodeValue",
|
||
|
Types: []reflect.Type{tValueUnmarshaler},
|
||
|
Received: reflect.ValueOf(wrong),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"copy error",
|
||
|
&testValueUnmarshaler{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String, Err: errors.New("copy error"), ErrAfter: bsonrwtest.ReadString},
|
||
|
bsonrwtest.ReadString,
|
||
|
errors.New("copy error"),
|
||
|
},
|
||
|
{
|
||
|
"ValueUnmarshaler",
|
||
|
&testValueUnmarshaler{t: bsontype.String, val: bsoncore.AppendString(nil, "hello, world")},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String, Return: "hello, world"},
|
||
|
bsonrwtest.ReadString,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"UnmarshalerDecodeValue",
|
||
|
ValueDecoderFunc(dvd.UnmarshalerDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
nil,
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "UnmarshalerDecodeValue", Types: []reflect.Type{tUnmarshaler}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"copy error",
|
||
|
&testUnmarshaler{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String, Err: errors.New("copy error"), ErrAfter: bsonrwtest.ReadString},
|
||
|
bsonrwtest.ReadString,
|
||
|
errors.New("copy error"),
|
||
|
},
|
||
|
{
|
||
|
"Unmarshaler",
|
||
|
testUnmarshaler{Val: bsoncore.AppendDouble(nil, 3.14159)},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double, Return: float64(3.14159)},
|
||
|
bsonrwtest.ReadDouble,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"PointerCodec.DecodeValue",
|
||
|
NewPointerCodec(),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"not valid", nil, nil, nil, bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "PointerCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: reflect.Value{}},
|
||
|
},
|
||
|
{
|
||
|
"can set", cansettest, nil, nil, bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "PointerCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Ptr}},
|
||
|
},
|
||
|
{
|
||
|
"No Decoder", &wrong, &DecodeContext{Registry: buildDefaultRegistry()}, nil, bsonrwtest.Nothing,
|
||
|
ErrNoDecoder{Type: reflect.TypeOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
(*mystruct)(nil),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
(*mystruct)(nil),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"BinaryDecodeValue",
|
||
|
ValueDecoderFunc(dvd.BinaryDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "BinaryDecodeValue", Types: []reflect.Type{tBinary}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not binary",
|
||
|
primitive.Binary{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a Binary", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadBinary Error",
|
||
|
primitive.Binary{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Binary, Err: errors.New("rb error"), ErrAfter: bsonrwtest.ReadBinary},
|
||
|
bsonrwtest.ReadBinary,
|
||
|
errors.New("rb error"),
|
||
|
},
|
||
|
{
|
||
|
"Binary/success",
|
||
|
primitive.Binary{Data: []byte{0x01, 0x02, 0x03}, Subtype: 0xFF},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{
|
||
|
BSONType: bsontype.Binary,
|
||
|
Return: bsoncore.Value{
|
||
|
Type: bsontype.Binary,
|
||
|
Data: bsoncore.AppendBinary(nil, 0xFF, []byte{0x01, 0x02, 0x03}),
|
||
|
},
|
||
|
},
|
||
|
bsonrwtest.ReadBinary,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.Binary{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.Binary{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"UndefinedDecodeValue",
|
||
|
ValueDecoderFunc(dvd.UndefinedDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "UndefinedDecodeValue", Types: []reflect.Type{tUndefined}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not undefined",
|
||
|
primitive.Undefined{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into an Undefined", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadUndefined Error",
|
||
|
primitive.Undefined{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined, Err: errors.New("ru error"), ErrAfter: bsonrwtest.ReadUndefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
errors.New("ru error"),
|
||
|
},
|
||
|
{
|
||
|
"ReadUndefined/success",
|
||
|
primitive.Undefined{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.Undefined{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"DateTimeDecodeValue",
|
||
|
ValueDecoderFunc(dvd.DateTimeDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.DateTime},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "DateTimeDecodeValue", Types: []reflect.Type{tDateTime}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not datetime",
|
||
|
primitive.DateTime(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a DateTime", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadDateTime Error",
|
||
|
primitive.DateTime(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.DateTime, Err: errors.New("rdt error"), ErrAfter: bsonrwtest.ReadDateTime},
|
||
|
bsonrwtest.ReadDateTime,
|
||
|
errors.New("rdt error"),
|
||
|
},
|
||
|
{
|
||
|
"success",
|
||
|
primitive.DateTime(1234567890),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.DateTime, Return: int64(1234567890)},
|
||
|
bsonrwtest.ReadDateTime,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.DateTime(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.DateTime(0),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"NullDecodeValue",
|
||
|
ValueDecoderFunc(dvd.NullDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "NullDecodeValue", Types: []reflect.Type{tNull}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not null",
|
||
|
primitive.Null{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a Null", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadNull Error",
|
||
|
primitive.Null{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null, Err: errors.New("rn error"), ErrAfter: bsonrwtest.ReadNull},
|
||
|
bsonrwtest.ReadNull,
|
||
|
errors.New("rn error"),
|
||
|
},
|
||
|
{
|
||
|
"success",
|
||
|
primitive.Null{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"RegexDecodeValue",
|
||
|
ValueDecoderFunc(dvd.RegexDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Regex},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "RegexDecodeValue", Types: []reflect.Type{tRegex}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not regex",
|
||
|
primitive.Regex{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a Regex", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadRegex Error",
|
||
|
primitive.Regex{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Regex, Err: errors.New("rr error"), ErrAfter: bsonrwtest.ReadRegex},
|
||
|
bsonrwtest.ReadRegex,
|
||
|
errors.New("rr error"),
|
||
|
},
|
||
|
{
|
||
|
"success",
|
||
|
primitive.Regex{Pattern: "foo", Options: "bar"},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{
|
||
|
BSONType: bsontype.Regex,
|
||
|
Return: bsoncore.Value{
|
||
|
Type: bsontype.Regex,
|
||
|
Data: bsoncore.AppendRegex(nil, "foo", "bar"),
|
||
|
},
|
||
|
},
|
||
|
bsonrwtest.ReadRegex,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.Regex{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.Regex{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"DBPointerDecodeValue",
|
||
|
ValueDecoderFunc(dvd.DBPointerDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.DBPointer},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "DBPointerDecodeValue", Types: []reflect.Type{tDBPointer}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not dbpointer",
|
||
|
primitive.DBPointer{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a DBPointer", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadDBPointer Error",
|
||
|
primitive.DBPointer{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.DBPointer, Err: errors.New("rdbp error"), ErrAfter: bsonrwtest.ReadDBPointer},
|
||
|
bsonrwtest.ReadDBPointer,
|
||
|
errors.New("rdbp error"),
|
||
|
},
|
||
|
{
|
||
|
"success",
|
||
|
primitive.DBPointer{
|
||
|
DB: "foobar",
|
||
|
Pointer: primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
|
||
|
},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{
|
||
|
BSONType: bsontype.DBPointer,
|
||
|
Return: bsoncore.Value{
|
||
|
Type: bsontype.DBPointer,
|
||
|
Data: bsoncore.AppendDBPointer(
|
||
|
nil, "foobar", primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
|
||
|
),
|
||
|
},
|
||
|
},
|
||
|
bsonrwtest.ReadDBPointer,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.DBPointer{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.DBPointer{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"TimestampDecodeValue",
|
||
|
ValueDecoderFunc(dvd.TimestampDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Timestamp},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "TimestampDecodeValue", Types: []reflect.Type{tTimestamp}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not timestamp",
|
||
|
primitive.Timestamp{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a Timestamp", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadTimestamp Error",
|
||
|
primitive.Timestamp{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Timestamp, Err: errors.New("rt error"), ErrAfter: bsonrwtest.ReadTimestamp},
|
||
|
bsonrwtest.ReadTimestamp,
|
||
|
errors.New("rt error"),
|
||
|
},
|
||
|
{
|
||
|
"success",
|
||
|
primitive.Timestamp{T: 12345, I: 67890},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{
|
||
|
BSONType: bsontype.Timestamp,
|
||
|
Return: bsoncore.Value{
|
||
|
Type: bsontype.Timestamp,
|
||
|
Data: bsoncore.AppendTimestamp(nil, 12345, 67890),
|
||
|
},
|
||
|
},
|
||
|
bsonrwtest.ReadTimestamp,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.Timestamp{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.Timestamp{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"MinKeyDecodeValue",
|
||
|
ValueDecoderFunc(dvd.MinKeyDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.MinKey},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "MinKeyDecodeValue", Types: []reflect.Type{tMinKey}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not null",
|
||
|
primitive.MinKey{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a MinKey", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadMinKey Error",
|
||
|
primitive.MinKey{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.MinKey, Err: errors.New("rn error"), ErrAfter: bsonrwtest.ReadMinKey},
|
||
|
bsonrwtest.ReadMinKey,
|
||
|
errors.New("rn error"),
|
||
|
},
|
||
|
{
|
||
|
"success",
|
||
|
primitive.MinKey{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.MinKey},
|
||
|
bsonrwtest.ReadMinKey,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.MinKey{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.MinKey{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"MaxKeyDecodeValue",
|
||
|
ValueDecoderFunc(dvd.MaxKeyDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.MaxKey},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "MaxKeyDecodeValue", Types: []reflect.Type{tMaxKey}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not null",
|
||
|
primitive.MaxKey{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a MaxKey", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadMaxKey Error",
|
||
|
primitive.MaxKey{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.MaxKey, Err: errors.New("rn error"), ErrAfter: bsonrwtest.ReadMaxKey},
|
||
|
bsonrwtest.ReadMaxKey,
|
||
|
errors.New("rn error"),
|
||
|
},
|
||
|
{
|
||
|
"success",
|
||
|
primitive.MaxKey{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.MaxKey},
|
||
|
bsonrwtest.ReadMaxKey,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.MaxKey{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.MaxKey{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"JavaScriptDecodeValue",
|
||
|
ValueDecoderFunc(dvd.JavaScriptDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.JavaScript, Return: ""},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "JavaScriptDecodeValue", Types: []reflect.Type{tJavaScript}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not Javascript",
|
||
|
primitive.JavaScript(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a primitive.JavaScript", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadJavascript Error",
|
||
|
primitive.JavaScript(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.JavaScript, Err: errors.New("rjs error"), ErrAfter: bsonrwtest.ReadJavascript},
|
||
|
bsonrwtest.ReadJavascript,
|
||
|
errors.New("rjs error"),
|
||
|
},
|
||
|
{
|
||
|
"JavaScript/success",
|
||
|
primitive.JavaScript("var hello = 'world';"),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.JavaScript, Return: "var hello = 'world';"},
|
||
|
bsonrwtest.ReadJavascript,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.JavaScript(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.JavaScript(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"SymbolDecodeValue",
|
||
|
ValueDecoderFunc(dvd.SymbolDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Symbol, Return: ""},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{Name: "SymbolDecodeValue", Types: []reflect.Type{tSymbol}, Received: reflect.ValueOf(wrong)},
|
||
|
},
|
||
|
{
|
||
|
"type not Symbol",
|
||
|
primitive.Symbol(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Int32},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a primitive.Symbol", bsontype.Int32),
|
||
|
},
|
||
|
{
|
||
|
"ReadSymbol Error",
|
||
|
primitive.Symbol(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Symbol, Err: errors.New("rjs error"), ErrAfter: bsonrwtest.ReadSymbol},
|
||
|
bsonrwtest.ReadSymbol,
|
||
|
errors.New("rjs error"),
|
||
|
},
|
||
|
{
|
||
|
"Symbol/success",
|
||
|
primitive.Symbol("var hello = 'world';"),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Symbol, Return: "var hello = 'world';"},
|
||
|
bsonrwtest.ReadSymbol,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.Symbol(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.Symbol(""),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"CoreDocumentDecodeValue",
|
||
|
ValueDecoderFunc(dvd.CoreDocumentDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{
|
||
|
Name: "CoreDocumentDecodeValue",
|
||
|
Types: []reflect.Type{tCoreDocument},
|
||
|
Received: reflect.ValueOf(wrong),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"*bsoncore.Document is nil",
|
||
|
(*bsoncore.Document)(nil),
|
||
|
nil,
|
||
|
nil,
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{
|
||
|
Name: "CoreDocumentDecodeValue",
|
||
|
Types: []reflect.Type{tCoreDocument},
|
||
|
Received: reflect.ValueOf((*bsoncore.Document)(nil)),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"Copy error",
|
||
|
bsoncore.Document{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{Err: errors.New("copy error"), ErrAfter: bsonrwtest.ReadDocument},
|
||
|
bsonrwtest.ReadDocument,
|
||
|
errors.New("copy error"),
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"StructCodec.DecodeValue",
|
||
|
defaultTestStructCodec,
|
||
|
[]subtest{
|
||
|
{
|
||
|
"Not struct",
|
||
|
reflect.New(reflect.TypeOf(struct{ Foo string }{})).Elem().Interface(),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
errors.New("cannot decode string into a struct { Foo string }"),
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
reflect.New(reflect.TypeOf(struct{ Foo string }{})).Elem().Interface(),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
reflect.New(reflect.TypeOf(struct{ Foo string }{})).Elem().Interface(),
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"CodeWithScopeDecodeValue",
|
||
|
ValueDecoderFunc(dvd.CodeWithScopeDecodeValue),
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.CodeWithScope},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{
|
||
|
Name: "CodeWithScopeDecodeValue",
|
||
|
Types: []reflect.Type{tCodeWithScope},
|
||
|
Received: reflect.ValueOf(wrong),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"type not codewithscope",
|
||
|
primitive.CodeWithScope{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.String},
|
||
|
bsonrwtest.Nothing,
|
||
|
fmt.Errorf("cannot decode %v into a primitive.CodeWithScope", bsontype.String),
|
||
|
},
|
||
|
{
|
||
|
"ReadCodeWithScope Error",
|
||
|
primitive.CodeWithScope{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.CodeWithScope, Err: errors.New("rcws error"), ErrAfter: bsonrwtest.ReadCodeWithScope},
|
||
|
bsonrwtest.ReadCodeWithScope,
|
||
|
errors.New("rcws error"),
|
||
|
},
|
||
|
{
|
||
|
"decodeDocument Error",
|
||
|
primitive.CodeWithScope{
|
||
|
Code: "var hello = 'world';",
|
||
|
Scope: primitive.D{{"foo", nil}},
|
||
|
},
|
||
|
&DecodeContext{Registry: buildDefaultRegistry()},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.CodeWithScope, Err: errors.New("dd error"), ErrAfter: bsonrwtest.ReadElement},
|
||
|
bsonrwtest.ReadElement,
|
||
|
errors.New("dd error"),
|
||
|
},
|
||
|
{
|
||
|
"decode null",
|
||
|
primitive.CodeWithScope{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Null},
|
||
|
bsonrwtest.ReadNull,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"decode undefined",
|
||
|
primitive.CodeWithScope{},
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Undefined},
|
||
|
bsonrwtest.ReadUndefined,
|
||
|
nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"CoreArrayDecodeValue",
|
||
|
defaultArrayCodec,
|
||
|
[]subtest{
|
||
|
{
|
||
|
"wrong type",
|
||
|
wrong,
|
||
|
nil,
|
||
|
&bsonrwtest.ValueReaderWriter{},
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{
|
||
|
Name: "CoreArrayDecodeValue",
|
||
|
Types: []reflect.Type{tCoreArray},
|
||
|
Received: reflect.ValueOf(wrong),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
"*bsoncore.Array is nil",
|
||
|
(*bsoncore.Array)(nil),
|
||
|
nil,
|
||
|
nil,
|
||
|
bsonrwtest.Nothing,
|
||
|
ValueDecoderError{
|
||
|
Name: "CoreArrayDecodeValue",
|
||
|
Types: []reflect.Type{tCoreArray},
|
||
|
Received: reflect.ValueOf((*bsoncore.Array)(nil)),
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tc := range testCases {
|
||
|
t.Run(tc.name, func(t *testing.T) {
|
||
|
for _, rc := range tc.subtests {
|
||
|
t.Run(rc.name, func(t *testing.T) {
|
||
|
var dc DecodeContext
|
||
|
if rc.dctx != nil {
|
||
|
dc = *rc.dctx
|
||
|
}
|
||
|
llvrw := new(bsonrwtest.ValueReaderWriter)
|
||
|
if rc.llvrw != nil {
|
||
|
llvrw = rc.llvrw
|
||
|
}
|
||
|
llvrw.T = t
|
||
|
// var got interface{}
|
||
|
if rc.val == cansetreflectiontest { // We're doing a CanSet reflection test
|
||
|
err := tc.vd.DecodeValue(dc, llvrw, reflect.Value{})
|
||
|
if !compareErrors(err, rc.err) {
|
||
|
t.Errorf("Errors do not match. got %v; want %v", err, rc.err)
|
||
|
}
|
||
|
|
||
|
val := reflect.New(reflect.TypeOf(rc.val)).Elem()
|
||
|
err = tc.vd.DecodeValue(dc, llvrw, val)
|
||
|
if !compareErrors(err, rc.err) {
|
||
|
t.Errorf("Errors do not match. got %v; want %v", err, rc.err)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
if rc.val == cansettest { // We're doing an IsValid and CanSet test
|
||
|
wanterr, ok := rc.err.(ValueDecoderError)
|
||
|
if !ok {
|
||
|
t.Fatalf("Error must be a DecodeValueError, but got a %T", rc.err)
|
||
|
}
|
||
|
|
||
|
err := tc.vd.DecodeValue(dc, llvrw, reflect.Value{})
|
||
|
wanterr.Received = reflect.ValueOf(nil)
|
||
|
if !compareErrors(err, wanterr) {
|
||
|
t.Errorf("Errors do not match. got %v; want %v", err, wanterr)
|
||
|
}
|
||
|
|
||
|
err = tc.vd.DecodeValue(dc, llvrw, reflect.ValueOf(int(12345)))
|
||
|
wanterr.Received = reflect.ValueOf(int(12345))
|
||
|
if !compareErrors(err, wanterr) {
|
||
|
t.Errorf("Errors do not match. got %v; want %v", err, wanterr)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
var val reflect.Value
|
||
|
if rtype := reflect.TypeOf(rc.val); rtype != nil {
|
||
|
val = reflect.New(rtype).Elem()
|
||
|
}
|
||
|
want := rc.val
|
||
|
defer func() {
|
||
|
if err := recover(); err != nil {
|
||
|
fmt.Println(t.Name())
|
||
|
panic(err)
|
||
|
}
|
||
|
}()
|
||
|
err := tc.vd.DecodeValue(dc, llvrw, val)
|
||
|
if !compareErrors(err, rc.err) {
|
||
|
t.Errorf("Errors do not match. got %v; want %v", err, rc.err)
|
||
|
}
|
||
|
invoked := llvrw.Invoked
|
||
|
if !cmp.Equal(invoked, rc.invoke) {
|
||
|
t.Errorf("Incorrect method invoked. got %v; want %v", invoked, rc.invoke)
|
||
|
}
|
||
|
var got interface{}
|
||
|
if val.IsValid() && val.CanInterface() {
|
||
|
got = val.Interface()
|
||
|
}
|
||
|
if rc.err == nil && !cmp.Equal(got, want, cmp.Comparer(compareDecimal128)) {
|
||
|
t.Errorf("Values do not match. got (%T)%v; want (%T)%v", got, got, want, want)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
t.Run("CodeWithScopeCodec/DecodeValue/success", func(t *testing.T) {
|
||
|
dc := DecodeContext{Registry: buildDefaultRegistry()}
|
||
|
b := bsoncore.BuildDocument(nil,
|
||
|
bsoncore.AppendCodeWithScopeElement(
|
||
|
nil, "foo", "var hello = 'world';",
|
||
|
buildDocument(bsoncore.AppendNullElement(nil, "bar")),
|
||
|
),
|
||
|
)
|
||
|
dvr := bsonrw.NewBSONDocumentReader(b)
|
||
|
dr, err := dvr.ReadDocument()
|
||
|
noerr(t, err)
|
||
|
_, vr, err := dr.ReadElement()
|
||
|
noerr(t, err)
|
||
|
|
||
|
want := primitive.CodeWithScope{
|
||
|
Code: "var hello = 'world';",
|
||
|
Scope: primitive.D{{"bar", nil}},
|
||
|
}
|
||
|
val := reflect.New(tCodeWithScope).Elem()
|
||
|
err = dvd.CodeWithScopeDecodeValue(dc, vr, val)
|
||
|
noerr(t, err)
|
||
|
|
||
|
got := val.Interface().(primitive.CodeWithScope)
|
||
|
if got.Code != want.Code && !cmp.Equal(got.Scope, want.Scope) {
|
||
|
t.Errorf("CodeWithScopes do not match. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
t.Run("ValueUnmarshalerDecodeValue/UnmarshalBSONValue error", func(t *testing.T) {
|
||
|
var dc DecodeContext
|
||
|
llvrw := &bsonrwtest.ValueReaderWriter{BSONType: bsontype.String, Return: string("hello, world!")}
|
||
|
llvrw.T = t
|
||
|
|
||
|
want := errors.New("ubsonv error")
|
||
|
valUnmarshaler := &testValueUnmarshaler{err: want}
|
||
|
got := dvd.ValueUnmarshalerDecodeValue(dc, llvrw, reflect.ValueOf(valUnmarshaler))
|
||
|
if !compareErrors(got, want) {
|
||
|
t.Errorf("Errors do not match. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
t.Run("ValueUnmarshalerDecodeValue/Unaddressable value", func(t *testing.T) {
|
||
|
var dc DecodeContext
|
||
|
llvrw := &bsonrwtest.ValueReaderWriter{BSONType: bsontype.String, Return: string("hello, world!")}
|
||
|
llvrw.T = t
|
||
|
|
||
|
val := reflect.ValueOf(testValueUnmarshaler{})
|
||
|
want := ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tValueUnmarshaler}, Received: val}
|
||
|
got := dvd.ValueUnmarshalerDecodeValue(dc, llvrw, val)
|
||
|
if !compareErrors(got, want) {
|
||
|
t.Errorf("Errors do not match. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
t.Run("SliceCodec/DecodeValue/can't set slice", func(t *testing.T) {
|
||
|
var val []string
|
||
|
want := ValueDecoderError{Name: "SliceDecodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: reflect.ValueOf(val)}
|
||
|
got := dvd.SliceDecodeValue(DecodeContext{}, nil, reflect.ValueOf(val))
|
||
|
if !compareErrors(got, want) {
|
||
|
t.Errorf("Errors do not match. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
t.Run("SliceCodec/DecodeValue/too many elements", func(t *testing.T) {
|
||
|
idx, doc := bsoncore.AppendDocumentStart(nil)
|
||
|
aidx, doc := bsoncore.AppendArrayElementStart(doc, "foo")
|
||
|
doc = bsoncore.AppendStringElement(doc, "0", "foo")
|
||
|
doc = bsoncore.AppendStringElement(doc, "1", "bar")
|
||
|
doc, err := bsoncore.AppendArrayEnd(doc, aidx)
|
||
|
noerr(t, err)
|
||
|
doc, err = bsoncore.AppendDocumentEnd(doc, idx)
|
||
|
noerr(t, err)
|
||
|
dvr := bsonrw.NewBSONDocumentReader(doc)
|
||
|
noerr(t, err)
|
||
|
dr, err := dvr.ReadDocument()
|
||
|
noerr(t, err)
|
||
|
_, vr, err := dr.ReadElement()
|
||
|
noerr(t, err)
|
||
|
var val [1]string
|
||
|
want := fmt.Errorf("more elements returned in array than can fit inside %T, got 2 elements", val)
|
||
|
|
||
|
dc := DecodeContext{Registry: buildDefaultRegistry()}
|
||
|
got := dvd.ArrayDecodeValue(dc, vr, reflect.ValueOf(val))
|
||
|
if !compareErrors(got, want) {
|
||
|
t.Errorf("Errors do not match. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
t.Run("success path", func(t *testing.T) {
|
||
|
oid := primitive.NewObjectID()
|
||
|
oids := []primitive.ObjectID{primitive.NewObjectID(), primitive.NewObjectID(), primitive.NewObjectID()}
|
||
|
var str = new(string)
|
||
|
*str = "bar"
|
||
|
now := time.Now().Truncate(time.Millisecond).UTC()
|
||
|
murl, err := url.Parse("https://mongodb.com/random-url?hello=world")
|
||
|
if err != nil {
|
||
|
t.Errorf("Error parsing URL: %v", err)
|
||
|
t.FailNow()
|
||
|
}
|
||
|
decimal128, err := primitive.ParseDecimal128("1.5e10")
|
||
|
if err != nil {
|
||
|
t.Errorf("Error parsing decimal128: %v", err)
|
||
|
t.FailNow()
|
||
|
}
|
||
|
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
value interface{}
|
||
|
b []byte
|
||
|
err error
|
||
|
}{
|
||
|
{
|
||
|
"map[string]int",
|
||
|
map[string]int32{"foo": 1},
|
||
|
[]byte{
|
||
|
0x0E, 0x00, 0x00, 0x00,
|
||
|
0x10, 'f', 'o', 'o', 0x00,
|
||
|
0x01, 0x00, 0x00, 0x00,
|
||
|
0x00,
|
||
|
},
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"map[string]primitive.ObjectID",
|
||
|
map[string]primitive.ObjectID{"foo": oid},
|
||
|
func() []byte {
|
||
|
idx, doc := bsoncore.AppendDocumentStart(nil)
|
||
|
doc = bsoncore.AppendObjectIDElement(doc, "foo", oid)
|
||
|
doc, _ = bsoncore.AppendDocumentEnd(doc, idx)
|
||
|
return doc
|
||
|
}(),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"map[string][]int32",
|
||
|
map[string][]int32{"Z": {1, 2, 3}},
|
||
|
buildDocumentArray(func(doc []byte) []byte {
|
||
|
doc = bsoncore.AppendInt32Element(doc, "0", 1)
|
||
|
doc = bsoncore.AppendInt32Element(doc, "1", 2)
|
||
|
return bsoncore.AppendInt32Element(doc, "2", 3)
|
||
|
}),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"map[string][]primitive.ObjectID",
|
||
|
map[string][]primitive.ObjectID{"Z": oids},
|
||
|
buildDocumentArray(func(doc []byte) []byte {
|
||
|
doc = bsoncore.AppendObjectIDElement(doc, "0", oids[0])
|
||
|
doc = bsoncore.AppendObjectIDElement(doc, "1", oids[1])
|
||
|
return bsoncore.AppendObjectIDElement(doc, "2", oids[2])
|
||
|
}),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"map[string][]json.Number(int64)",
|
||
|
map[string][]json.Number{"Z": {json.Number("5"), json.Number("10")}},
|
||
|
buildDocumentArray(func(doc []byte) []byte {
|
||
|
doc = bsoncore.AppendInt64Element(doc, "0", 5)
|
||
|
return bsoncore.AppendInt64Element(doc, "1", 10)
|
||
|
}),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"map[string][]json.Number(float64)",
|
||
|
map[string][]json.Number{"Z": {json.Number("5"), json.Number("10.1")}},
|
||
|
buildDocumentArray(func(doc []byte) []byte {
|
||
|
doc = bsoncore.AppendInt64Element(doc, "0", 5)
|
||
|
return bsoncore.AppendDoubleElement(doc, "1", 10.1)
|
||
|
}),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"map[string][]*url.URL",
|
||
|
map[string][]*url.URL{"Z": {murl}},
|
||
|
buildDocumentArray(func(doc []byte) []byte {
|
||
|
return bsoncore.AppendStringElement(doc, "0", murl.String())
|
||
|
}),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"map[string][]primitive.Decimal128",
|
||
|
map[string][]primitive.Decimal128{"Z": {decimal128}},
|
||
|
buildDocumentArray(func(doc []byte) []byte {
|
||
|
return bsoncore.AppendDecimal128Element(doc, "0", decimal128)
|
||
|
}),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"map[mystring]interface{}",
|
||
|
map[mystring]interface{}{"pi": 3.14159},
|
||
|
buildDocument(bsoncore.AppendDoubleElement(nil, "pi", 3.14159)),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"-",
|
||
|
struct {
|
||
|
A string `bson:"-"`
|
||
|
}{
|
||
|
A: "",
|
||
|
},
|
||
|
[]byte{0x05, 0x00, 0x00, 0x00, 0x00},
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"omitempty",
|
||
|
struct {
|
||
|
A string `bson:",omitempty"`
|
||
|
}{
|
||
|
A: "",
|
||
|
},
|
||
|
[]byte{0x05, 0x00, 0x00, 0x00, 0x00},
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"omitempty, empty time",
|
||
|
struct {
|
||
|
A time.Time `bson:",omitempty"`
|
||
|
}{
|
||
|
A: time.Time{},
|
||
|
},
|
||
|
[]byte{0x05, 0x00, 0x00, 0x00, 0x00},
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"no private fields",
|
||
|
noPrivateFields{a: "should be empty"},
|
||
|
[]byte{0x05, 0x00, 0x00, 0x00, 0x00},
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"minsize",
|
||
|
struct {
|
||
|
A int64 `bson:",minsize"`
|
||
|
}{
|
||
|
A: 12345,
|
||
|
},
|
||
|
buildDocument(bsoncore.AppendInt32Element(nil, "a", 12345)),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"inline",
|
||
|
struct {
|
||
|
Foo struct {
|
||
|
A int64 `bson:",minsize"`
|
||
|
} `bson:",inline"`
|
||
|
}{
|
||
|
Foo: struct {
|
||
|
A int64 `bson:",minsize"`
|
||
|
}{
|
||
|
A: 12345,
|
||
|
},
|
||
|
},
|
||
|
buildDocument(bsoncore.AppendInt32Element(nil, "a", 12345)),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"inline struct pointer",
|
||
|
struct {
|
||
|
Foo *struct {
|
||
|
A int64 `bson:",minsize"`
|
||
|
} `bson:",inline"`
|
||
|
Bar *struct {
|
||
|
B int64
|
||
|
} `bson:",inline"`
|
||
|
}{
|
||
|
Foo: &struct {
|
||
|
A int64 `bson:",minsize"`
|
||
|
}{
|
||
|
A: 12345,
|
||
|
},
|
||
|
Bar: nil,
|
||
|
},
|
||
|
buildDocument(bsoncore.AppendInt32Element(nil, "a", 12345)),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"nested inline struct pointer",
|
||
|
struct {
|
||
|
Foo *struct {
|
||
|
Bar *struct {
|
||
|
A int64 `bson:",minsize"`
|
||
|
} `bson:",inline"`
|
||
|
} `bson:",inline"`
|
||
|
}{
|
||
|
Foo: &struct {
|
||
|
Bar *struct {
|
||
|
A int64 `bson:",minsize"`
|
||
|
} `bson:",inline"`
|
||
|
}{
|
||
|
Bar: &struct {
|
||
|
A int64 `bson:",minsize"`
|
||
|
}{
|
||
|
A: 12345,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
buildDocument(bsoncore.AppendInt32Element(nil, "a", 12345)),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"inline nil struct pointer",
|
||
|
struct {
|
||
|
Foo *struct {
|
||
|
A int64 `bson:",minsize"`
|
||
|
} `bson:",inline"`
|
||
|
}{
|
||
|
Foo: nil,
|
||
|
},
|
||
|
buildDocument([]byte{}),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"inline overwrite",
|
||
|
struct {
|
||
|
Foo struct {
|
||
|
A int32
|
||
|
B string
|
||
|
} `bson:",inline"`
|
||
|
A int64
|
||
|
}{
|
||
|
Foo: struct {
|
||
|
A int32
|
||
|
B string
|
||
|
}{
|
||
|
A: 0,
|
||
|
B: "foo",
|
||
|
},
|
||
|
A: 54321,
|
||
|
},
|
||
|
buildDocument(func(doc []byte) []byte {
|
||
|
doc = bsoncore.AppendStringElement(doc, "b", "foo")
|
||
|
doc = bsoncore.AppendInt64Element(doc, "a", 54321)
|
||
|
return doc
|
||
|
}(nil)),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"inline overwrite with nested structs",
|
||
|
struct {
|
||
|
Foo struct {
|
||
|
A int32
|
||
|
} `bson:",inline"`
|
||
|
Bar struct {
|
||
|
A int32
|
||
|
} `bson:",inline"`
|
||
|
A int64
|
||
|
}{
|
||
|
Foo: struct {
|
||
|
A int32
|
||
|
}{},
|
||
|
Bar: struct {
|
||
|
A int32
|
||
|
}{},
|
||
|
A: 54321,
|
||
|
},
|
||
|
buildDocument(bsoncore.AppendInt64Element(nil, "a", 54321)),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"inline map",
|
||
|
struct {
|
||
|
Foo map[string]string `bson:",inline"`
|
||
|
}{
|
||
|
Foo: map[string]string{"foo": "bar"},
|
||
|
},
|
||
|
buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"alternate name bson:name",
|
||
|
struct {
|
||
|
A string `bson:"foo"`
|
||
|
}{
|
||
|
A: "bar",
|
||
|
},
|
||
|
buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"alternate name",
|
||
|
struct {
|
||
|
A string `bson:"foo"`
|
||
|
}{
|
||
|
A: "bar",
|
||
|
},
|
||
|
buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"inline, omitempty",
|
||
|
struct {
|
||
|
A string
|
||
|
Foo zeroTest `bson:"omitempty,inline"`
|
||
|
}{
|
||
|
A: "bar",
|
||
|
Foo: zeroTest{true},
|
||
|
},
|
||
|
buildDocument(bsoncore.AppendStringElement(nil, "a", "bar")),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"struct{}",
|
||
|
struct {
|
||
|
A bool
|
||
|
B int32
|
||
|
C int64
|
||
|
D uint16
|
||
|
E uint64
|
||
|
F float64
|
||
|
G string
|
||
|
H map[string]string
|
||
|
I []byte
|
||
|
K [2]string
|
||
|
L struct {
|
||
|
M string
|
||
|
}
|
||
|
Q primitive.ObjectID
|
||
|
T []struct{}
|
||
|
Y json.Number
|
||
|
Z time.Time
|
||
|
AA json.Number
|
||
|
AB *url.URL
|
||
|
AC primitive.Decimal128
|
||
|
AD *time.Time
|
||
|
AE *testValueUnmarshaler
|
||
|
AF *bool
|
||
|
AG *bool
|
||
|
AH *int32
|
||
|
AI *int64
|
||
|
AJ *primitive.ObjectID
|
||
|
AK *primitive.ObjectID
|
||
|
AL testValueUnmarshaler
|
||
|
AM interface{}
|
||
|
AN interface{}
|
||
|
AO interface{}
|
||
|
AP primitive.D
|
||
|
AQ primitive.A
|
||
|
AR [2]primitive.E
|
||
|
AS []byte
|
||
|
AT map[string]interface{}
|
||
|
AU primitive.CodeWithScope
|
||
|
AV primitive.M
|
||
|
AW primitive.D
|
||
|
AX map[string]interface{}
|
||
|
AY []primitive.E
|
||
|
AZ interface{}
|
||
|
}{
|
||
|
A: true,
|
||
|
B: 123,
|
||
|
C: 456,
|
||
|
D: 789,
|
||
|
E: 101112,
|
||
|
F: 3.14159,
|
||
|
G: "Hello, world",
|
||
|
H: map[string]string{"foo": "bar"},
|
||
|
I: []byte{0x01, 0x02, 0x03},
|
||
|
K: [2]string{"baz", "qux"},
|
||
|
L: struct {
|
||
|
M string
|
||
|
}{
|
||
|
M: "foobar",
|
||
|
},
|
||
|
Q: oid,
|
||
|
T: nil,
|
||
|
Y: json.Number("5"),
|
||
|
Z: now,
|
||
|
AA: json.Number("10.1"),
|
||
|
AB: murl,
|
||
|
AC: decimal128,
|
||
|
AD: &now,
|
||
|
AE: &testValueUnmarshaler{t: bsontype.String, val: bsoncore.AppendString(nil, "hello, world!")},
|
||
|
AF: func(b bool) *bool { return &b }(true),
|
||
|
AG: nil,
|
||
|
AH: func(i32 int32) *int32 { return &i32 }(12345),
|
||
|
AI: func(i64 int64) *int64 { return &i64 }(1234567890),
|
||
|
AJ: &oid,
|
||
|
AK: nil,
|
||
|
AL: testValueUnmarshaler{t: bsontype.String, val: bsoncore.AppendString(nil, "hello, world!")},
|
||
|
AM: "hello, world",
|
||
|
AN: int32(12345),
|
||
|
AO: oid,
|
||
|
AP: primitive.D{{"foo", "bar"}},
|
||
|
AQ: primitive.A{"foo", "bar"},
|
||
|
AR: [2]primitive.E{{"hello", "world"}, {"pi", 3.14159}},
|
||
|
AS: nil,
|
||
|
AT: nil,
|
||
|
AU: primitive.CodeWithScope{Code: "var hello = 'world';", Scope: primitive.D{{"pi", 3.14159}}},
|
||
|
AV: primitive.M{"foo": primitive.M{"bar": "baz"}},
|
||
|
AW: primitive.D{{"foo", primitive.D{{"bar", "baz"}}}},
|
||
|
AX: map[string]interface{}{"foo": map[string]interface{}{"bar": "baz"}},
|
||
|
AY: []primitive.E{{"foo", []primitive.E{{"bar", "baz"}}}},
|
||
|
AZ: primitive.D{{"foo", primitive.D{{"bar", "baz"}}}},
|
||
|
},
|
||
|
buildDocument(func(doc []byte) []byte {
|
||
|
doc = bsoncore.AppendBooleanElement(doc, "a", true)
|
||
|
doc = bsoncore.AppendInt32Element(doc, "b", 123)
|
||
|
doc = bsoncore.AppendInt64Element(doc, "c", 456)
|
||
|
doc = bsoncore.AppendInt32Element(doc, "d", 789)
|
||
|
doc = bsoncore.AppendInt64Element(doc, "e", 101112)
|
||
|
doc = bsoncore.AppendDoubleElement(doc, "f", 3.14159)
|
||
|
doc = bsoncore.AppendStringElement(doc, "g", "Hello, world")
|
||
|
doc = bsoncore.AppendDocumentElement(doc, "h", buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")))
|
||
|
doc = bsoncore.AppendBinaryElement(doc, "i", 0x00, []byte{0x01, 0x02, 0x03})
|
||
|
doc = bsoncore.AppendArrayElement(doc, "k",
|
||
|
buildArray(bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "baz"), "1", "qux")),
|
||
|
)
|
||
|
doc = bsoncore.AppendDocumentElement(doc, "l", buildDocument(bsoncore.AppendStringElement(nil, "m", "foobar")))
|
||
|
doc = bsoncore.AppendObjectIDElement(doc, "q", oid)
|
||
|
doc = bsoncore.AppendNullElement(doc, "t")
|
||
|
doc = bsoncore.AppendInt64Element(doc, "y", 5)
|
||
|
doc = bsoncore.AppendDateTimeElement(doc, "z", now.UnixNano()/int64(time.Millisecond))
|
||
|
doc = bsoncore.AppendDoubleElement(doc, "aa", 10.1)
|
||
|
doc = bsoncore.AppendStringElement(doc, "ab", murl.String())
|
||
|
doc = bsoncore.AppendDecimal128Element(doc, "ac", decimal128)
|
||
|
doc = bsoncore.AppendDateTimeElement(doc, "ad", now.UnixNano()/int64(time.Millisecond))
|
||
|
doc = bsoncore.AppendStringElement(doc, "ae", "hello, world!")
|
||
|
doc = bsoncore.AppendBooleanElement(doc, "af", true)
|
||
|
doc = bsoncore.AppendNullElement(doc, "ag")
|
||
|
doc = bsoncore.AppendInt32Element(doc, "ah", 12345)
|
||
|
doc = bsoncore.AppendInt32Element(doc, "ai", 1234567890)
|
||
|
doc = bsoncore.AppendObjectIDElement(doc, "aj", oid)
|
||
|
doc = bsoncore.AppendNullElement(doc, "ak")
|
||
|
doc = bsoncore.AppendStringElement(doc, "al", "hello, world!")
|
||
|
doc = bsoncore.AppendStringElement(doc, "am", "hello, world")
|
||
|
doc = bsoncore.AppendInt32Element(doc, "an", 12345)
|
||
|
doc = bsoncore.AppendObjectIDElement(doc, "ao", oid)
|
||
|
doc = bsoncore.AppendDocumentElement(doc, "ap", buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")))
|
||
|
doc = bsoncore.AppendArrayElement(doc, "aq",
|
||
|
buildArray(bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "foo"), "1", "bar")),
|
||
|
)
|
||
|
doc = bsoncore.AppendDocumentElement(doc, "ar",
|
||
|
buildDocument(bsoncore.AppendDoubleElement(bsoncore.AppendStringElement(nil, "hello", "world"), "pi", 3.14159)),
|
||
|
)
|
||
|
doc = bsoncore.AppendNullElement(doc, "as")
|
||
|
doc = bsoncore.AppendNullElement(doc, "at")
|
||
|
doc = bsoncore.AppendCodeWithScopeElement(doc, "au",
|
||
|
"var hello = 'world';", buildDocument(bsoncore.AppendDoubleElement(nil, "pi", 3.14159)),
|
||
|
)
|
||
|
for _, name := range [5]string{"av", "aw", "ax", "ay", "az"} {
|
||
|
doc = bsoncore.AppendDocumentElement(doc, name, buildDocument(
|
||
|
bsoncore.AppendDocumentElement(nil, "foo", buildDocument(
|
||
|
bsoncore.AppendStringElement(nil, "bar", "baz"),
|
||
|
)),
|
||
|
))
|
||
|
}
|
||
|
return doc
|
||
|
}(nil)),
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"struct{[]interface{}}",
|
||
|
struct {
|
||
|
A []bool
|
||
|
B []int32
|
||
|
C []int64
|
||
|
D []uint16
|
||
|
E []uint64
|
||
|
F []float64
|
||
|
G []string
|
||
|
H []map[string]string
|
||
|
I [][]byte
|
||
|
K [1][2]string
|
||
|
L []struct {
|
||
|
M string
|
||
|
}
|
||
|
N [][]string
|
||
|
R []primitive.ObjectID
|
||
|
T []struct{}
|
||
|
W []map[string]struct{}
|
||
|
X []map[string]struct{}
|
||
|
Y []map[string]struct{}
|
||
|
Z []time.Time
|
||
|
AA []json.Number
|
||
|
AB []*url.URL
|
||
|
AC []primitive.Decimal128
|
||
|
AD []*time.Time
|
||
|
AE []*testValueUnmarshaler
|
||
|
AF []*bool
|
||
|
AG []*int32
|
||
|
AH []*int64
|
||
|
AI []*primitive.ObjectID
|
||
|
AJ []primitive.D
|
||
|
AK []primitive.A
|
||
|
AL [][2]primitive.E
|
||
|
}{
|
||
|
A: []bool{true},
|
||
|
B: []int32{123},
|
||
|
C: []int64{456},
|
||
|
D: []uint16{789},
|
||
|
E: []uint64{101112},
|
||
|
F: []float64{3.14159},
|
||
|
G: []string{"Hello, world"},
|
||
|
H: []map[string]string{{"foo": "bar"}},
|
||
|
I: [][]byte{{0x01, 0x02, 0x03}},
|
||
|
K: [1][2]string{{"baz", "qux"}},
|
||
|
L: []struct {
|
||
|
M string
|
||
|
}{
|
||
|
{
|
||
|
M: "foobar",
|
||
|
},
|
||
|
},
|
||
|
N: [][]string{{"foo", "bar"}},
|
||
|
R: oids,
|
||
|
T: nil,
|
||
|
W: nil,
|
||
|
X: []map[string]struct{}{}, // Should be empty BSON Array
|
||
|
Y: []map[string]struct{}{{}}, // Should be BSON array with one element, an empty BSON SubDocument
|
||
|
Z: []time.Time{now, now},
|
||
|
AA: []json.Number{json.Number("5"), json.Number("10.1")},
|
||
|
AB: []*url.URL{murl},
|
||
|
AC: []primitive.Decimal128{decimal128},
|
||
|
AD: []*time.Time{&now, &now},
|
||
|
AE: []*testValueUnmarshaler{
|
||
|
{t: bsontype.String, val: bsoncore.AppendString(nil, "hello")},
|
||
|
{t: bsontype.String, val: bsoncore.AppendString(nil, "world")},
|
||
|
},
|
||
|
AF: []*bool{pbool(true), nil},
|
||
|
AG: []*int32{pi32(12345), nil},
|
||
|
AH: []*int64{pi64(1234567890), nil, pi64(9012345678)},
|
||
|
AI: []*primitive.ObjectID{&oid, nil},
|
||
|
AJ: []primitive.D{{{"foo", "bar"}}, nil},
|
||
|
AK: []primitive.A{{"foo", "bar"}, nil},
|
||
|
AL: [][2]primitive.E{{{"hello", "world"}, {"pi", 3.14159}}},
|
||
|
},
|
||
|
buildDocument(func(doc []byte) []byte {
|
||
|
doc = appendArrayElement(doc, "a", bsoncore.AppendBooleanElement(nil, "0", true))
|
||
|
doc = appendArrayElement(doc, "b", bsoncore.AppendInt32Element(nil, "0", 123))
|
||
|
doc = appendArrayElement(doc, "c", bsoncore.AppendInt64Element(nil, "0", 456))
|
||
|
doc = appendArrayElement(doc, "d", bsoncore.AppendInt32Element(nil, "0", 789))
|
||
|
doc = appendArrayElement(doc, "e", bsoncore.AppendInt64Element(nil, "0", 101112))
|
||
|
doc = appendArrayElement(doc, "f", bsoncore.AppendDoubleElement(nil, "0", 3.14159))
|
||
|
doc = appendArrayElement(doc, "g", bsoncore.AppendStringElement(nil, "0", "Hello, world"))
|
||
|
doc = appendArrayElement(doc, "h", bsoncore.BuildDocumentElement(nil, "0", bsoncore.AppendStringElement(nil, "foo", "bar")))
|
||
|
doc = appendArrayElement(doc, "i", bsoncore.AppendBinaryElement(nil, "0", 0x00, []byte{0x01, 0x02, 0x03}))
|
||
|
doc = appendArrayElement(doc, "k",
|
||
|
appendArrayElement(nil, "0",
|
||
|
bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "baz"), "1", "qux")),
|
||
|
)
|
||
|
doc = appendArrayElement(doc, "l", bsoncore.BuildDocumentElement(nil, "0", bsoncore.AppendStringElement(nil, "m", "foobar")))
|
||
|
doc = appendArrayElement(doc, "n",
|
||
|
appendArrayElement(nil, "0",
|
||
|
bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "foo"), "1", "bar")),
|
||
|
)
|
||
|
doc = appendArrayElement(doc, "r",
|
||
|
bsoncore.AppendObjectIDElement(
|
||
|
bsoncore.AppendObjectIDElement(
|
||
|
bsoncore.AppendObjectIDElement(nil,
|
||
|
"0", oids[0]),
|
||
|
"1", oids[1]),
|
||
|
"2", oids[2]),
|
||
|
)
|
||
|
doc = bsoncore.AppendNullElement(doc, "t")
|
||
|
doc = bsoncore.AppendNullElement(doc, "w")
|
||
|
doc = appendArrayElement(doc, "x", nil)
|
||
|
doc = appendArrayElement(doc, "y", bsoncore.BuildDocumentElement(nil, "0", nil))
|
||
|
doc = appendArrayElement(doc, "z",
|
||
|
bsoncore.AppendDateTimeElement(
|
||
|
bsoncore.AppendDateTimeElement(
|
||
|
nil, "0", now.UnixNano()/int64(time.Millisecond)),
|
||
|
"1", now.UnixNano()/int64(time.Millisecond)),
|
||
|
)
|
||
|
doc = appendArrayElement(doc, "aa", bsoncore.AppendDoubleElement(bsoncore.AppendInt64Element(nil, "0", 5), "1", 10.10))
|
||
|
doc = appendArrayElement(doc, "ab", bsoncore.AppendStringElement(nil, "0", murl.String()))
|
||
|
doc = appendArrayElement(doc, "ac", bsoncore.AppendDecimal128Element(nil, "0", decimal128))
|
||
|
doc = appendArrayElement(doc, "ad",
|
||
|
bsoncore.AppendDateTimeElement(
|
||
|
bsoncore.AppendDateTimeElement(nil, "0", now.UnixNano()/int64(time.Millisecond)),
|
||
|
"1", now.UnixNano()/int64(time.Millisecond)),
|
||
|
)
|
||
|
doc = appendArrayElement(doc, "ae",
|
||
|
bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "hello"), "1", "world"),
|
||
|
)
|
||
|
doc = appendArrayElement(doc, "af",
|
||
|
bsoncore.AppendNullElement(bsoncore.AppendBooleanElement(nil, "0", true), "1"),
|
||
|
)
|
||
|
doc = appendArrayElement(doc, "ag",
|
||
|
bsoncore.AppendNullElement(bsoncore.AppendInt32Element(nil, "0", 12345), "1"),
|
||
|
)
|
||
|
doc = appendArrayElement(doc, "ah",
|
||
|
bsoncore.AppendInt64Element(
|
||
|
bsoncore.AppendNullElement(bsoncore.AppendInt64Element(nil, "0", 1234567890), "1"),
|
||
|
"2", 9012345678,
|
||
|
),
|
||
|
)
|
||
|
doc = appendArrayElement(doc, "ai",
|
||
|
bsoncore.AppendNullElement(bsoncore.AppendObjectIDElement(nil, "0", oid), "1"),
|
||
|
)
|
||
|
doc = appendArrayElement(doc, "aj",
|
||
|
bsoncore.AppendNullElement(
|
||
|
bsoncore.AppendDocumentElement(nil, "0", buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar"))),
|
||
|
"1",
|
||
|
),
|
||
|
)
|
||
|
doc = appendArrayElement(doc, "ak",
|
||
|
bsoncore.AppendNullElement(
|
||
|
appendArrayElement(nil, "0",
|
||
|
bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "foo"), "1", "bar"),
|
||
|
),
|
||
|
"1",
|
||
|
),
|
||
|
)
|
||
|
doc = appendArrayElement(doc, "al",
|
||
|
bsoncore.BuildDocumentElement(nil, "0",
|
||
|
bsoncore.AppendDoubleElement(bsoncore.AppendStringElement(nil, "hello", "world"), "pi", 3.14159),
|
||
|
),
|
||
|
)
|
||
|
return doc
|
||
|
}(nil)),
|
||
|
nil,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
t.Run("Decode", func(t *testing.T) {
|
||
|
for _, tc := range testCases {
|
||
|
t.Run(tc.name, func(t *testing.T) {
|
||
|
vr := bsonrw.NewBSONDocumentReader(tc.b)
|
||
|
reg := buildDefaultRegistry()
|
||
|
vtype := reflect.TypeOf(tc.value)
|
||
|
dec, err := reg.LookupDecoder(vtype)
|
||
|
noerr(t, err)
|
||
|
|
||
|
gotVal := reflect.New(reflect.TypeOf(tc.value)).Elem()
|
||
|
err = dec.DecodeValue(DecodeContext{Registry: reg}, vr, gotVal)
|
||
|
noerr(t, err)
|
||
|
|
||
|
got := gotVal.Interface()
|
||
|
want := tc.value
|
||
|
if diff := cmp.Diff(
|
||
|
got, want,
|
||
|
cmp.Comparer(compareDecimal128),
|
||
|
cmp.Comparer(compareNoPrivateFields),
|
||
|
cmp.Comparer(compareZeroTest),
|
||
|
cmp.Comparer(compareTime),
|
||
|
); diff != "" {
|
||
|
t.Errorf("difference:\n%s", diff)
|
||
|
t.Errorf("Values are not equal.\ngot: %#v\nwant:%#v", got, want)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
})
|
||
|
t.Run("error path", func(t *testing.T) {
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
value interface{}
|
||
|
b []byte
|
||
|
err error
|
||
|
}{
|
||
|
{
|
||
|
"duplicate name struct",
|
||
|
struct {
|
||
|
A int64
|
||
|
B int64 `bson:"a"`
|
||
|
}{
|
||
|
A: 0,
|
||
|
B: 54321,
|
||
|
},
|
||
|
buildDocument(bsoncore.AppendInt32Element(nil, "a", 12345)),
|
||
|
fmt.Errorf("duplicated key a"),
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tc := range testCases {
|
||
|
t.Run(tc.name, func(t *testing.T) {
|
||
|
vr := bsonrw.NewBSONDocumentReader(tc.b)
|
||
|
reg := buildDefaultRegistry()
|
||
|
vtype := reflect.TypeOf(tc.value)
|
||
|
dec, err := reg.LookupDecoder(vtype)
|
||
|
noerr(t, err)
|
||
|
|
||
|
gotVal := reflect.New(reflect.TypeOf(tc.value)).Elem()
|
||
|
err = dec.DecodeValue(DecodeContext{Registry: reg}, vr, gotVal)
|
||
|
if err == nil || !strings.Contains(err.Error(), tc.err.Error()) {
|
||
|
t.Errorf("Did not receive expected error. got %v; want %v", err, tc.err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
|
||
|
t.Run("defaultEmptyInterfaceCodec.DecodeValue", func(t *testing.T) {
|
||
|
t.Run("DecodeValue", func(t *testing.T) {
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
val interface{}
|
||
|
bsontype bsontype.Type
|
||
|
}{
|
||
|
{
|
||
|
"Double - float64",
|
||
|
float64(3.14159),
|
||
|
bsontype.Double,
|
||
|
},
|
||
|
{
|
||
|
"String - string",
|
||
|
"foo bar baz",
|
||
|
bsontype.String,
|
||
|
},
|
||
|
{
|
||
|
"Array - primitive.A",
|
||
|
primitive.A{3.14159},
|
||
|
bsontype.Array,
|
||
|
},
|
||
|
{
|
||
|
"Binary - Binary",
|
||
|
primitive.Binary{Subtype: 0xFF, Data: []byte{0x01, 0x02, 0x03}},
|
||
|
bsontype.Binary,
|
||
|
},
|
||
|
{
|
||
|
"Undefined - Undefined",
|
||
|
primitive.Undefined{},
|
||
|
bsontype.Undefined,
|
||
|
},
|
||
|
{
|
||
|
"ObjectID - primitive.ObjectID",
|
||
|
primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
|
||
|
bsontype.ObjectID,
|
||
|
},
|
||
|
{
|
||
|
"Boolean - bool",
|
||
|
bool(true),
|
||
|
bsontype.Boolean,
|
||
|
},
|
||
|
{
|
||
|
"DateTime - DateTime",
|
||
|
primitive.DateTime(1234567890),
|
||
|
bsontype.DateTime,
|
||
|
},
|
||
|
{
|
||
|
"Null - Null",
|
||
|
nil,
|
||
|
bsontype.Null,
|
||
|
},
|
||
|
{
|
||
|
"Regex - Regex",
|
||
|
primitive.Regex{Pattern: "foo", Options: "bar"},
|
||
|
bsontype.Regex,
|
||
|
},
|
||
|
{
|
||
|
"DBPointer - DBPointer",
|
||
|
primitive.DBPointer{
|
||
|
DB: "foobar",
|
||
|
Pointer: primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
|
||
|
},
|
||
|
bsontype.DBPointer,
|
||
|
},
|
||
|
{
|
||
|
"JavaScript - JavaScript",
|
||
|
primitive.JavaScript("var foo = 'bar';"),
|
||
|
bsontype.JavaScript,
|
||
|
},
|
||
|
{
|
||
|
"Symbol - Symbol",
|
||
|
primitive.Symbol("foobarbazlolz"),
|
||
|
bsontype.Symbol,
|
||
|
},
|
||
|
{
|
||
|
"Int32 - int32",
|
||
|
int32(123456),
|
||
|
bsontype.Int32,
|
||
|
},
|
||
|
{
|
||
|
"Int64 - int64",
|
||
|
int64(1234567890),
|
||
|
bsontype.Int64,
|
||
|
},
|
||
|
{
|
||
|
"Timestamp - Timestamp",
|
||
|
primitive.Timestamp{T: 12345, I: 67890},
|
||
|
bsontype.Timestamp,
|
||
|
},
|
||
|
{
|
||
|
"Decimal128 - decimal.Decimal128",
|
||
|
primitive.NewDecimal128(12345, 67890),
|
||
|
bsontype.Decimal128,
|
||
|
},
|
||
|
{
|
||
|
"MinKey - MinKey",
|
||
|
primitive.MinKey{},
|
||
|
bsontype.MinKey,
|
||
|
},
|
||
|
{
|
||
|
"MaxKey - MaxKey",
|
||
|
primitive.MaxKey{},
|
||
|
bsontype.MaxKey,
|
||
|
},
|
||
|
}
|
||
|
for _, tc := range testCases {
|
||
|
t.Run(tc.name, func(t *testing.T) {
|
||
|
llvr := &bsonrwtest.ValueReaderWriter{BSONType: tc.bsontype}
|
||
|
|
||
|
t.Run("Type Map failure", func(t *testing.T) {
|
||
|
if tc.bsontype == bsontype.Null {
|
||
|
t.Skip()
|
||
|
}
|
||
|
val := reflect.New(tEmpty).Elem()
|
||
|
dc := DecodeContext{Registry: NewRegistryBuilder().Build()}
|
||
|
want := ErrNoTypeMapEntry{Type: tc.bsontype}
|
||
|
got := defaultEmptyInterfaceCodec.DecodeValue(dc, llvr, val)
|
||
|
if !compareErrors(got, want) {
|
||
|
t.Errorf("Errors are not equal. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
t.Run("Lookup failure", func(t *testing.T) {
|
||
|
if tc.bsontype == bsontype.Null {
|
||
|
t.Skip()
|
||
|
}
|
||
|
val := reflect.New(tEmpty).Elem()
|
||
|
dc := DecodeContext{
|
||
|
Registry: NewRegistryBuilder().
|
||
|
RegisterTypeMapEntry(tc.bsontype, reflect.TypeOf(tc.val)).
|
||
|
Build(),
|
||
|
}
|
||
|
want := ErrNoDecoder{Type: reflect.TypeOf(tc.val)}
|
||
|
got := defaultEmptyInterfaceCodec.DecodeValue(dc, llvr, val)
|
||
|
if !compareErrors(got, want) {
|
||
|
t.Errorf("Errors are not equal. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
t.Run("DecodeValue failure", func(t *testing.T) {
|
||
|
if tc.bsontype == bsontype.Null {
|
||
|
t.Skip()
|
||
|
}
|
||
|
want := errors.New("DecodeValue failure error")
|
||
|
llc := &llCodec{t: t, err: want}
|
||
|
dc := DecodeContext{
|
||
|
Registry: NewRegistryBuilder().
|
||
|
RegisterTypeDecoder(reflect.TypeOf(tc.val), llc).
|
||
|
RegisterTypeMapEntry(tc.bsontype, reflect.TypeOf(tc.val)).
|
||
|
Build(),
|
||
|
}
|
||
|
got := defaultEmptyInterfaceCodec.DecodeValue(dc, llvr, reflect.New(tEmpty).Elem())
|
||
|
if !compareErrors(got, want) {
|
||
|
t.Errorf("Errors are not equal. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
t.Run("Success", func(t *testing.T) {
|
||
|
want := tc.val
|
||
|
llc := &llCodec{t: t, decodeval: tc.val}
|
||
|
dc := DecodeContext{
|
||
|
Registry: NewRegistryBuilder().
|
||
|
RegisterTypeDecoder(reflect.TypeOf(tc.val), llc).
|
||
|
RegisterTypeMapEntry(tc.bsontype, reflect.TypeOf(tc.val)).
|
||
|
Build(),
|
||
|
}
|
||
|
got := reflect.New(tEmpty).Elem()
|
||
|
err := defaultEmptyInterfaceCodec.DecodeValue(dc, llvr, got)
|
||
|
noerr(t, err)
|
||
|
if !cmp.Equal(got.Interface(), want, cmp.Comparer(compareDecimal128)) {
|
||
|
t.Errorf("Did not receive expected value. got %v; want %v", got.Interface(), want)
|
||
|
}
|
||
|
})
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
|
||
|
t.Run("non-interface{}", func(t *testing.T) {
|
||
|
val := uint64(1234567890)
|
||
|
want := ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: reflect.ValueOf(val)}
|
||
|
got := defaultEmptyInterfaceCodec.DecodeValue(DecodeContext{}, nil, reflect.ValueOf(val))
|
||
|
if !compareErrors(got, want) {
|
||
|
t.Errorf("Errors are not equal. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
t.Run("nil *interface{}", func(t *testing.T) {
|
||
|
var val interface{}
|
||
|
want := ValueDecoderError{Name: "EmptyInterfaceDecodeValue", Types: []reflect.Type{tEmpty}, Received: reflect.ValueOf(val)}
|
||
|
got := defaultEmptyInterfaceCodec.DecodeValue(DecodeContext{}, nil, reflect.ValueOf(val))
|
||
|
if !compareErrors(got, want) {
|
||
|
t.Errorf("Errors are not equal. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
t.Run("no type registered", func(t *testing.T) {
|
||
|
llvr := &bsonrwtest.ValueReaderWriter{BSONType: bsontype.Double}
|
||
|
want := ErrNoTypeMapEntry{Type: bsontype.Double}
|
||
|
val := reflect.New(tEmpty).Elem()
|
||
|
got := defaultEmptyInterfaceCodec.DecodeValue(DecodeContext{Registry: NewRegistryBuilder().Build()}, llvr, val)
|
||
|
if !compareErrors(got, want) {
|
||
|
t.Errorf("Errors are not equal. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
t.Run("top level document", func(t *testing.T) {
|
||
|
data := bsoncore.BuildDocument(nil, bsoncore.AppendDoubleElement(nil, "pi", 3.14159))
|
||
|
vr := bsonrw.NewBSONDocumentReader(data)
|
||
|
want := primitive.D{{"pi", 3.14159}}
|
||
|
var got interface{}
|
||
|
val := reflect.ValueOf(&got).Elem()
|
||
|
err := defaultEmptyInterfaceCodec.DecodeValue(DecodeContext{Registry: buildDefaultRegistry()}, vr, val)
|
||
|
noerr(t, err)
|
||
|
if !cmp.Equal(got, want) {
|
||
|
t.Errorf("Did not get correct result. got %v; want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
t.Run("custom type map entry", func(t *testing.T) {
|
||
|
// registering a custom type map entry for both bsontype.Type(0) anad bsontype.EmbeddedDocument should cause
|
||
|
// both top-level and embedded documents to decode to registered type when unmarshalling to interface{}
|
||
|
|
||
|
topLevelRb := NewRegistryBuilder()
|
||
|
defaultValueEncoders.RegisterDefaultEncoders(topLevelRb)
|
||
|
defaultValueDecoders.RegisterDefaultDecoders(topLevelRb)
|
||
|
topLevelRb.RegisterTypeMapEntry(bsontype.Type(0), reflect.TypeOf(primitive.M{}))
|
||
|
|
||
|
embeddedRb := NewRegistryBuilder()
|
||
|
defaultValueEncoders.RegisterDefaultEncoders(embeddedRb)
|
||
|
defaultValueDecoders.RegisterDefaultDecoders(embeddedRb)
|
||
|
embeddedRb.RegisterTypeMapEntry(bsontype.Type(0), reflect.TypeOf(primitive.M{}))
|
||
|
|
||
|
// create doc {"nested": {"foo": 1}}
|
||
|
innerDoc := bsoncore.BuildDocument(
|
||
|
nil,
|
||
|
bsoncore.AppendInt32Element(nil, "foo", 1),
|
||
|
)
|
||
|
doc := bsoncore.BuildDocument(
|
||
|
nil,
|
||
|
bsoncore.AppendDocumentElement(nil, "nested", innerDoc),
|
||
|
)
|
||
|
want := primitive.M{
|
||
|
"nested": primitive.M{
|
||
|
"foo": int32(1),
|
||
|
},
|
||
|
}
|
||
|
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
registry *Registry
|
||
|
}{
|
||
|
{"top level", topLevelRb.Build()},
|
||
|
{"embedded", embeddedRb.Build()},
|
||
|
}
|
||
|
for _, tc := range testCases {
|
||
|
var got interface{}
|
||
|
vr := bsonrw.NewBSONDocumentReader(doc)
|
||
|
val := reflect.ValueOf(&got).Elem()
|
||
|
|
||
|
err := defaultEmptyInterfaceCodec.DecodeValue(DecodeContext{Registry: tc.registry}, vr, val)
|
||
|
noerr(t, err)
|
||
|
if !cmp.Equal(got, want) {
|
||
|
t.Fatalf("got %v, want %v", got, want)
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
t.Run("ancestor info is used over custom type map entry", func(t *testing.T) {
|
||
|
// If a type map entry is registered for bsontype.EmbeddedDocument, the decoder should use ancestor
|
||
|
// information if available instead of the registered entry.
|
||
|
|
||
|
rb := NewRegistryBuilder()
|
||
|
defaultValueEncoders.RegisterDefaultEncoders(rb)
|
||
|
defaultValueDecoders.RegisterDefaultDecoders(rb)
|
||
|
rb.RegisterTypeMapEntry(bsontype.EmbeddedDocument, reflect.TypeOf(primitive.M{}))
|
||
|
reg := rb.Build()
|
||
|
|
||
|
// build document {"nested": {"foo": 10}}
|
||
|
inner := bsoncore.BuildDocument(
|
||
|
nil,
|
||
|
bsoncore.AppendInt32Element(nil, "foo", 10),
|
||
|
)
|
||
|
doc := bsoncore.BuildDocument(
|
||
|
nil,
|
||
|
bsoncore.AppendDocumentElement(nil, "nested", inner),
|
||
|
)
|
||
|
want := primitive.D{
|
||
|
{"nested", primitive.D{
|
||
|
{"foo", int32(10)},
|
||
|
}},
|
||
|
}
|
||
|
|
||
|
var got primitive.D
|
||
|
vr := bsonrw.NewBSONDocumentReader(doc)
|
||
|
val := reflect.ValueOf(&got).Elem()
|
||
|
err := defaultSliceCodec.DecodeValue(DecodeContext{Registry: reg}, vr, val)
|
||
|
noerr(t, err)
|
||
|
if !cmp.Equal(got, want) {
|
||
|
t.Fatalf("got %v, want %v", got, want)
|
||
|
}
|
||
|
})
|
||
|
})
|
||
|
|
||
|
t.Run("decode errors contain key information", func(t *testing.T) {
|
||
|
decodeValueError := errors.New("decode value error")
|
||
|
emptyInterfaceErrorDecode := func(DecodeContext, bsonrw.ValueReader, reflect.Value) error {
|
||
|
return decodeValueError
|
||
|
}
|
||
|
emptyInterfaceErrorRegistry := NewRegistryBuilder().
|
||
|
RegisterTypeDecoder(tEmpty, ValueDecoderFunc(emptyInterfaceErrorDecode)).Build()
|
||
|
|
||
|
// Set up a document {foo: 10} and an error that would happen if the value were decoded into interface{}
|
||
|
// using the registry defined above.
|
||
|
docBytes := bsoncore.BuildDocumentFromElements(
|
||
|
nil,
|
||
|
bsoncore.AppendInt32Element(nil, "foo", 10),
|
||
|
)
|
||
|
docEmptyInterfaceErr := &DecodeError{
|
||
|
keys: []string{"foo"},
|
||
|
wrapped: decodeValueError,
|
||
|
}
|
||
|
|
||
|
// Set up struct definitions where Foo maps to interface{} and string. When decoded using the registry defined
|
||
|
// above, the interface{} struct will get an error when calling DecodeValue and the string struct will get an
|
||
|
// error when looking up a decoder.
|
||
|
type emptyInterfaceStruct struct {
|
||
|
Foo interface{}
|
||
|
}
|
||
|
type stringStruct struct {
|
||
|
Foo string
|
||
|
}
|
||
|
emptyInterfaceStructErr := &DecodeError{
|
||
|
keys: []string{"foo"},
|
||
|
wrapped: decodeValueError,
|
||
|
}
|
||
|
stringStructErr := &DecodeError{
|
||
|
keys: []string{"foo"},
|
||
|
wrapped: ErrNoDecoder{reflect.TypeOf("")},
|
||
|
}
|
||
|
|
||
|
// Test a deeply nested struct mixed with maps and slices.
|
||
|
// Build document {"first": {"second": {"randomKey": {"third": [{}, {"fourth": "value"}]}}}}
|
||
|
type inner3 struct{ Fourth interface{} }
|
||
|
type inner2 struct{ Third []inner3 }
|
||
|
type inner1 struct{ Second map[string]inner2 }
|
||
|
type outer struct{ First inner1 }
|
||
|
inner3EmptyDoc := buildDocument(nil)
|
||
|
inner3Doc := buildDocument(bsoncore.AppendStringElement(nil, "fourth", "value"))
|
||
|
inner3Array := buildArray(
|
||
|
// buildArray takes []byte so we first append() all of the values into a single []byte
|
||
|
append(
|
||
|
bsoncore.AppendDocumentElement(nil, "0", inner3EmptyDoc),
|
||
|
bsoncore.AppendDocumentElement(nil, "1", inner3Doc)...,
|
||
|
),
|
||
|
)
|
||
|
inner2Doc := buildDocument(bsoncore.AppendArrayElement(nil, "third", inner3Array))
|
||
|
inner2Map := buildDocument(bsoncore.AppendDocumentElement(nil, "randomKey", inner2Doc))
|
||
|
inner1Doc := buildDocument(bsoncore.AppendDocumentElement(nil, "second", inner2Map))
|
||
|
outerDoc := buildDocument(bsoncore.AppendDocumentElement(nil, "first", inner1Doc))
|
||
|
|
||
|
// Use a registry that has all default decoders with the custom interface{} decoder that always errors.
|
||
|
nestedRegistryBuilder := NewRegistryBuilder()
|
||
|
defaultValueDecoders.RegisterDefaultDecoders(nestedRegistryBuilder)
|
||
|
nestedRegistry := nestedRegistryBuilder.
|
||
|
RegisterTypeDecoder(tEmpty, ValueDecoderFunc(emptyInterfaceErrorDecode)).
|
||
|
Build()
|
||
|
nestedErr := &DecodeError{
|
||
|
keys: []string{"fourth", "1", "third", "randomKey", "second", "first"},
|
||
|
wrapped: decodeValueError,
|
||
|
}
|
||
|
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
val interface{}
|
||
|
vr bsonrw.ValueReader
|
||
|
registry *Registry // buildDefaultRegistry will be used if this is nil
|
||
|
decoder ValueDecoder
|
||
|
err error
|
||
|
}{
|
||
|
{
|
||
|
// DecodeValue error when decoding into a primitive.D.
|
||
|
"primitive.D slice",
|
||
|
primitive.D{},
|
||
|
bsonrw.NewBSONDocumentReader(docBytes),
|
||
|
emptyInterfaceErrorRegistry,
|
||
|
defaultSliceCodec,
|
||
|
docEmptyInterfaceErr,
|
||
|
},
|
||
|
{
|
||
|
// DecodeValue error when decoding into a []string.
|
||
|
"string slice",
|
||
|
[]string{},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Array},
|
||
|
nil,
|
||
|
defaultSliceCodec,
|
||
|
&DecodeError{
|
||
|
keys: []string{"0"},
|
||
|
wrapped: errors.New("cannot decode array into a string type"),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
// DecodeValue error when decoding into a primitive.E array. This should have the same behavior as
|
||
|
// the "primitive.D slice" test above because both the defaultSliceCodec and ArrayDecodeValue use
|
||
|
// the decodeD helper function.
|
||
|
"primitive.D array",
|
||
|
[1]primitive.E{},
|
||
|
bsonrw.NewBSONDocumentReader(docBytes),
|
||
|
emptyInterfaceErrorRegistry,
|
||
|
ValueDecoderFunc(dvd.ArrayDecodeValue),
|
||
|
docEmptyInterfaceErr,
|
||
|
},
|
||
|
{
|
||
|
// DecodeValue error when decoding into a string array. This should have the same behavior as
|
||
|
// the "primitive.D slice" test above because both the defaultSliceCodec and ArrayDecodeValue use
|
||
|
// the decodeDefault helper function.
|
||
|
"string array",
|
||
|
[1]string{},
|
||
|
&bsonrwtest.ValueReaderWriter{BSONType: bsontype.Array},
|
||
|
nil,
|
||
|
ValueDecoderFunc(dvd.ArrayDecodeValue),
|
||
|
&DecodeError{
|
||
|
keys: []string{"0"},
|
||
|
wrapped: errors.New("cannot decode array into a string type"),
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
// DecodeValue error when decoding into a map.
|
||
|
"map",
|
||
|
map[string]interface{}{},
|
||
|
bsonrw.NewBSONDocumentReader(docBytes),
|
||
|
emptyInterfaceErrorRegistry,
|
||
|
defaultMapCodec,
|
||
|
docEmptyInterfaceErr,
|
||
|
},
|
||
|
{
|
||
|
// DecodeValue error when decoding into a struct.
|
||
|
"struct - DecodeValue error",
|
||
|
emptyInterfaceStruct{},
|
||
|
bsonrw.NewBSONDocumentReader(docBytes),
|
||
|
emptyInterfaceErrorRegistry,
|
||
|
defaultTestStructCodec,
|
||
|
emptyInterfaceStructErr,
|
||
|
},
|
||
|
{
|
||
|
// ErrNoDecoder when decoding into a struct.
|
||
|
// This test uses NewRegistryBuilder().Build rather than buildDefaultRegistry to ensure that there is
|
||
|
// no decoder for strings.
|
||
|
"struct - no decoder found",
|
||
|
stringStruct{},
|
||
|
bsonrw.NewBSONDocumentReader(docBytes),
|
||
|
NewRegistryBuilder().Build(),
|
||
|
defaultTestStructCodec,
|
||
|
stringStructErr,
|
||
|
},
|
||
|
{
|
||
|
"deeply nested struct",
|
||
|
outer{},
|
||
|
bsonrw.NewBSONDocumentReader(outerDoc),
|
||
|
nestedRegistry,
|
||
|
defaultTestStructCodec,
|
||
|
nestedErr,
|
||
|
},
|
||
|
}
|
||
|
for _, tc := range testCases {
|
||
|
t.Run(tc.name, func(t *testing.T) {
|
||
|
dc := DecodeContext{Registry: tc.registry}
|
||
|
if dc.Registry == nil {
|
||
|
dc.Registry = buildDefaultRegistry()
|
||
|
}
|
||
|
|
||
|
var val reflect.Value
|
||
|
if rtype := reflect.TypeOf(tc.val); rtype != nil {
|
||
|
val = reflect.New(rtype).Elem()
|
||
|
}
|
||
|
err := tc.decoder.DecodeValue(dc, tc.vr, val)
|
||
|
assert.Equal(t, tc.err, err, "expected error %v, got %v", tc.err, err)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
t.Run("keys are correctly reversed", func(t *testing.T) {
|
||
|
innerBytes := bsoncore.BuildDocumentFromElements(nil, bsoncore.AppendInt32Element(nil, "bar", 10))
|
||
|
outerBytes := bsoncore.BuildDocumentFromElements(nil, bsoncore.AppendDocumentElement(nil, "foo", innerBytes))
|
||
|
|
||
|
type inner struct{ Bar string }
|
||
|
type outer struct{ Foo inner }
|
||
|
|
||
|
dc := DecodeContext{Registry: buildDefaultRegistry()}
|
||
|
vr := bsonrw.NewBSONDocumentReader(outerBytes)
|
||
|
val := reflect.New(reflect.TypeOf(outer{})).Elem()
|
||
|
err := defaultTestStructCodec.DecodeValue(dc, vr, val)
|
||
|
|
||
|
decodeErr, ok := err.(*DecodeError)
|
||
|
assert.True(t, ok, "expected DecodeError, got %v of type %T", err, err)
|
||
|
expectedKeys := []string{"foo", "bar"}
|
||
|
assert.Equal(t, expectedKeys, decodeErr.Keys(), "expected keys slice %v, got %v", expectedKeys,
|
||
|
decodeErr.Keys())
|
||
|
keyPath := strings.Join(expectedKeys, ".")
|
||
|
assert.True(t, strings.Contains(decodeErr.Error(), keyPath),
|
||
|
"expected error %v to contain key pattern %s", decodeErr, keyPath)
|
||
|
})
|
||
|
})
|
||
|
|
||
|
t.Run("values are converted", func(t *testing.T) {
|
||
|
// When decoding into a D or M, values must be converted if they are not being decoded to the default type.
|
||
|
|
||
|
t.Run("D", func(t *testing.T) {
|
||
|
trueValue := bsoncore.Value{
|
||
|
Type: bsontype.Boolean,
|
||
|
Data: bsoncore.AppendBoolean(nil, true),
|
||
|
}
|
||
|
docBytes := bsoncore.BuildDocumentFromElements(nil,
|
||
|
bsoncore.AppendBooleanElement(nil, "bool", true),
|
||
|
bsoncore.BuildArrayElement(nil, "boolArray", trueValue),
|
||
|
)
|
||
|
|
||
|
rb := NewRegistryBuilder()
|
||
|
defaultValueDecoders.RegisterDefaultDecoders(rb)
|
||
|
reg := rb.RegisterTypeMapEntry(bsontype.Boolean, reflect.TypeOf(mybool(true))).Build()
|
||
|
|
||
|
dc := DecodeContext{Registry: reg}
|
||
|
vr := bsonrw.NewBSONDocumentReader(docBytes)
|
||
|
val := reflect.New(tD).Elem()
|
||
|
err := defaultValueDecoders.DDecodeValue(dc, vr, val)
|
||
|
assert.Nil(t, err, "DDecodeValue error: %v", err)
|
||
|
|
||
|
want := primitive.D{
|
||
|
{"bool", mybool(true)},
|
||
|
{"boolArray", primitive.A{mybool(true)}},
|
||
|
}
|
||
|
got := val.Interface().(primitive.D)
|
||
|
assert.Equal(t, want, got, "want document %v, got %v", want, got)
|
||
|
})
|
||
|
t.Run("M", func(t *testing.T) {
|
||
|
docBytes := bsoncore.BuildDocumentFromElements(nil,
|
||
|
bsoncore.AppendBooleanElement(nil, "bool", true),
|
||
|
)
|
||
|
|
||
|
type myMap map[string]mybool
|
||
|
dc := DecodeContext{Registry: buildDefaultRegistry()}
|
||
|
vr := bsonrw.NewBSONDocumentReader(docBytes)
|
||
|
val := reflect.New(reflect.TypeOf(myMap{})).Elem()
|
||
|
err := defaultMapCodec.DecodeValue(dc, vr, val)
|
||
|
assert.Nil(t, err, "DecodeValue error: %v", err)
|
||
|
|
||
|
want := myMap{
|
||
|
"bool": mybool(true),
|
||
|
}
|
||
|
got := val.Interface().(myMap)
|
||
|
assert.Equal(t, want, got, "expected map %v, got %v", want, got)
|
||
|
})
|
||
|
})
|
||
|
}
|
||
|
|
||
|
type testValueUnmarshaler struct {
|
||
|
t bsontype.Type
|
||
|
val []byte
|
||
|
err error
|
||
|
}
|
||
|
|
||
|
func (tvu *testValueUnmarshaler) UnmarshalBSONValue(t bsontype.Type, val []byte) error {
|
||
|
tvu.t, tvu.val = t, val
|
||
|
return tvu.err
|
||
|
}
|
||
|
|
||
|
type testUnmarshaler struct {
|
||
|
Val []byte
|
||
|
Err error
|
||
|
}
|
||
|
|
||
|
func (tvu *testUnmarshaler) UnmarshalBSON(val []byte) error {
|
||
|
tvu.Val = val
|
||
|
return tvu.Err
|
||
|
}
|
||
|
|
||
|
func (tvu testValueUnmarshaler) Equal(tvu2 testValueUnmarshaler) bool {
|
||
|
return tvu.t == tvu2.t && bytes.Equal(tvu.val, tvu2.val)
|
||
|
}
|
||
|
|
||
|
// buildDocumentArray inserts vals inside of an array inside of a document.
|
||
|
func buildDocumentArray(fn func([]byte) []byte) []byte {
|
||
|
aix, doc := bsoncore.AppendArrayElementStart(nil, "Z")
|
||
|
doc = fn(doc)
|
||
|
doc, _ = bsoncore.AppendArrayEnd(doc, aix)
|
||
|
return buildDocument(doc)
|
||
|
}
|
||
|
|
||
|
func buildArray(vals []byte) []byte {
|
||
|
aix, doc := bsoncore.AppendArrayStart(nil)
|
||
|
doc = append(doc, vals...)
|
||
|
doc, _ = bsoncore.AppendArrayEnd(doc, aix)
|
||
|
return doc
|
||
|
}
|
||
|
|
||
|
func appendArrayElement(dst []byte, key string, vals []byte) []byte {
|
||
|
aix, doc := bsoncore.AppendArrayElementStart(dst, key)
|
||
|
doc = append(doc, vals...)
|
||
|
doc, _ = bsoncore.AppendArrayEnd(doc, aix)
|
||
|
return doc
|
||
|
}
|
||
|
|
||
|
// buildDocument inserts elems inside of a document.
|
||
|
func buildDocument(elems []byte) []byte {
|
||
|
idx, doc := bsoncore.AppendDocumentStart(nil)
|
||
|
doc = append(doc, elems...)
|
||
|
doc, _ = bsoncore.AppendDocumentEnd(doc, idx)
|
||
|
return doc
|
||
|
}
|