зеркало из https://github.com/github/vitess-gh.git
250 строки
11 KiB
Go
250 строки
11 KiB
Go
// Copyright 2012, Google Inc. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package bson
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/youtube/vitess/go/bytes2"
|
|
)
|
|
|
|
const (
|
|
bsonValNil = "\nVal\x00"
|
|
bsonValBytes = "\x05Val\x00\x04\x00\x00\x00\x00test"
|
|
bsonValInt64 = "\x12Val\x00\x01\x00\x00\x00\x00\x00\x00\x00"
|
|
bsonValInt32 = "\x10Val\x00\x01\x00\x00\x00"
|
|
bsonValUint64 = "\x12Val\x00\x01\x00\x00\x00\x00\x00\x00\x00"
|
|
bsonValFloat64 = "\x01Val\x00\x00\x00\x00\x00\x00\x00\xf0?"
|
|
bsonValBool = "\bVal\x00\x01"
|
|
bsonValMap = "\x03Val\x00\x13\x00\x00\x00\x12Val1\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
bsonValSlice = "\x04Val\x00\x10\x00\x00\x00\x120\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
bsonValTime = "\tVal\x00\x88\xf2\\\x8d\b\x01\x00\x00"
|
|
)
|
|
|
|
var interfaceMarshalCases = []struct {
|
|
desc string
|
|
in interface{}
|
|
out string
|
|
}{
|
|
{"nil", nil, bsonValNil},
|
|
{"string", "test", bsonValBytes},
|
|
{"[]byte", []byte("test"), bsonValBytes},
|
|
{"int64", int64(1), bsonValInt64},
|
|
{"int32", int32(1), bsonValInt32},
|
|
{"int", int(1), bsonValInt64},
|
|
{"uint64", uint64(1), bsonValUint64},
|
|
{"uint32", uint32(1), bsonValUint64},
|
|
{"uint", uint(1), bsonValUint64},
|
|
{"float64", float64(1.0), bsonValFloat64},
|
|
{"bool", true, bsonValBool},
|
|
{"nil map", map[string]interface{}(nil), bsonValNil},
|
|
{"map", map[string]interface{}{"Val1": 1}, bsonValMap},
|
|
{"nil slice", []interface{}(nil), bsonValNil},
|
|
{"slice", []interface{}{1}, bsonValSlice},
|
|
{"time", time.Unix(1136243045, 0).UTC(), bsonValTime},
|
|
}
|
|
|
|
func TestInterfaceMarshal(t *testing.T) {
|
|
for _, tcase := range interfaceMarshalCases {
|
|
buf := bytes2.NewChunkedWriter(DefaultBufferSize)
|
|
EncodeInterface(buf, "Val", tcase.in)
|
|
got := string(buf.Bytes())
|
|
if got != tcase.out {
|
|
t.Errorf("%s: got \n%q, want \n%q", tcase.desc, got, tcase.out)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInterfaceMarshalFailure(t *testing.T) {
|
|
want := "don't know how to marshal chan int"
|
|
func() {
|
|
defer func() {
|
|
if x := recover(); x != nil {
|
|
got := x.(BsonError).Error()
|
|
if got != want {
|
|
t.Errorf("got %s, want %s", got, want)
|
|
}
|
|
return
|
|
}
|
|
}()
|
|
buf := bytes2.NewChunkedWriter(DefaultBufferSize)
|
|
EncodeInterface(buf, "Val", make(chan int))
|
|
t.Errorf("got no error, want %s", want)
|
|
}()
|
|
}
|
|
|
|
const (
|
|
bsonString = "\x05\x00\x00\x00test\x00"
|
|
bsonBinary = "\x04\x00\x00\x00\x00test"
|
|
bsonInt = "\x01\x00\x00\x00"
|
|
bsonLong = "\x01\x00\x00\x00\x00\x00\x00\x00"
|
|
bsonNumber = "\x00\x00\x00\x00\x00\x00\xf0?"
|
|
bsonDatetime = "\x88\xf2\\\x8d\b\x01\x00\x00"
|
|
bsonBoolean = "\x01"
|
|
bsonObject = "\x14\x00\x00\x00\x05Val2\x00\x04\x00\x00\x00\x00test\x00"
|
|
bsonObjectNull = "\v\x00\x00\x00\nVal2\x00\x00"
|
|
bsonArray = "\x11\x00\x00\x00\x050\x00\x04\x00\x00\x00\x00test\x00"
|
|
bsonArrayNull = "\x13\x00\x00\x00\n0\x00\x121\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
bsonStringArray = "\x1f\x00\x00\x00\x050\x00\x05\x00\x00\x00\x00test1\x051\x00\x05\x00\x00\x00\x00test2\x00"
|
|
)
|
|
|
|
func stringDecoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeString(buf, kind) }
|
|
func binaryDecoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeBinary(buf, kind) }
|
|
func int64Decoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeInt64(buf, kind) }
|
|
func int32Decoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeInt32(buf, kind) }
|
|
func intDecoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeInt(buf, kind) }
|
|
func uint64Decoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeUint64(buf, kind) }
|
|
func uint32Decoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeUint32(buf, kind) }
|
|
func uintDecoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeUint(buf, kind) }
|
|
func float64Decoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeFloat64(buf, kind) }
|
|
func boolDecoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeBool(buf, kind) }
|
|
func timeDecoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeTime(buf, kind) }
|
|
func interfaceDecoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeInterface(buf, kind) }
|
|
func mapDecoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeMap(buf, kind) }
|
|
func arrayDecoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeArray(buf, kind) }
|
|
func skipDecoder(buf *bytes.Buffer, kind byte) interface{} { Skip(buf, kind); return nil }
|
|
func stringArrayDecoder(buf *bytes.Buffer, kind byte) interface{} { return DecodeStringArray(buf, kind) }
|
|
|
|
var customUnmarshalCases = []struct {
|
|
desc string
|
|
in string
|
|
kind byte
|
|
decoder func(buf *bytes.Buffer, kind byte) interface{}
|
|
out interface{}
|
|
}{
|
|
{"String->string", bsonString, String, stringDecoder, "test"},
|
|
{"Binary->string", bsonBinary, Binary, stringDecoder, "test"},
|
|
{"Null->string", "", Null, stringDecoder, ""},
|
|
{"String->bytes", bsonString, String, binaryDecoder, []byte("test")},
|
|
{"Binary->bytes", bsonBinary, Binary, binaryDecoder, []byte("test")},
|
|
{"Null->bytes", "", Null, binaryDecoder, []byte(nil)},
|
|
{"Int->int64", bsonInt, Int, int64Decoder, int64(1)},
|
|
{"Long->int64", bsonLong, Long, int64Decoder, int64(1)},
|
|
{"Ulong->int64", bsonLong, Ulong, int64Decoder, int64(1)},
|
|
{"Null->int64", "", Null, int64Decoder, int64(0)},
|
|
{"Int->int32", bsonInt, Int, int32Decoder, int32(1)},
|
|
{"Null->int32", "", Null, int32Decoder, int32(0)},
|
|
{"Int->int", bsonInt, Int, intDecoder, int(1)},
|
|
{"Long->int", bsonLong, Long, intDecoder, int(1)},
|
|
{"Ulong->int", bsonLong, Ulong, intDecoder, int(1)},
|
|
{"Null->int", "", Null, intDecoder, int(0)},
|
|
{"Int->uint64", bsonInt, Int, uint64Decoder, uint64(1)},
|
|
{"Long->uint64", bsonLong, Long, uint64Decoder, uint64(1)},
|
|
{"Ulong->uint64", bsonLong, Ulong, uint64Decoder, uint64(1)},
|
|
{"Null->uint64", "", Null, uint64Decoder, uint64(0)},
|
|
{"Int->uint32", bsonInt, Int, uint32Decoder, uint32(1)},
|
|
{"Ulong->uint32", bsonLong, Ulong, uint32Decoder, uint32(1)},
|
|
{"Null->uint32", "", Null, uint32Decoder, uint32(0)},
|
|
{"Int->uint", bsonInt, Int, uintDecoder, uint(1)},
|
|
{"Long->uint", bsonLong, Long, uintDecoder, uint(1)},
|
|
{"Ulong->uint", bsonLong, Ulong, uintDecoder, uint(1)},
|
|
{"Null->uint", "", Null, uintDecoder, uint(0)},
|
|
{"Number->float64", bsonNumber, Number, float64Decoder, float64(1.0)},
|
|
{"Null->float64", "", Null, float64Decoder, float64(0.0)},
|
|
{"Boolean->bool", bsonBoolean, Boolean, boolDecoder, true},
|
|
{"Null->bool", "", Null, boolDecoder, false},
|
|
{"Datetime->time.Time", bsonDatetime, Datetime, timeDecoder, time.Unix(1136243045, 0).UTC()},
|
|
{"Null->time.Time", "", Null, timeDecoder, time.Time{}},
|
|
{"Number->interface{}", bsonNumber, Number, interfaceDecoder, float64(1.0)},
|
|
{"String->interface{}", bsonString, String, interfaceDecoder, "test"},
|
|
{"Object->interface{}", bsonObject, Object, interfaceDecoder, map[string]interface{}{"Val2": []byte("test")}},
|
|
{"Object->interface{} with null element", bsonObjectNull, Object, interfaceDecoder, map[string]interface{}{"Val2": nil}},
|
|
{"Array->interface{}", bsonArray, Array, interfaceDecoder, []interface{}{[]byte("test")}},
|
|
{"Array->interface{} with null element", bsonArrayNull, Array, interfaceDecoder, []interface{}{nil, int64(1)}},
|
|
{"Binary->interface{}", bsonBinary, Binary, interfaceDecoder, []byte("test")},
|
|
{"Boolean->interface{}", bsonBoolean, Boolean, interfaceDecoder, true},
|
|
{"Datetime->interface{}", bsonDatetime, Datetime, interfaceDecoder, time.Unix(1136243045, 0).UTC()},
|
|
{"Int->interface{}", bsonInt, Int, interfaceDecoder, int32(1)},
|
|
{"Long->interface{}", bsonLong, Long, interfaceDecoder, int64(1)},
|
|
{"Ulong->interface{}", bsonLong, Ulong, interfaceDecoder, uint64(1)},
|
|
{"Null->interface{}", "", Null, interfaceDecoder, nil},
|
|
{"Null->map[string]interface{}", "", Null, mapDecoder, map[string]interface{}(nil)},
|
|
{"Null->[]interface{}", "", Null, arrayDecoder, []interface{}(nil)},
|
|
{"Number->Skip", bsonNumber, Number, skipDecoder, nil},
|
|
{"String->Skip", bsonString, String, skipDecoder, nil},
|
|
{"Object->Skip", bsonObject, Object, skipDecoder, nil},
|
|
{"Object->Skip with null element", bsonObjectNull, Object, skipDecoder, nil},
|
|
{"Array->Skip", bsonArray, Array, skipDecoder, nil},
|
|
{"Array->Skip with null element", bsonArrayNull, Array, skipDecoder, nil},
|
|
{"Binary->Skip", bsonBinary, Binary, skipDecoder, nil},
|
|
{"Boolean->Skip", bsonBoolean, Boolean, skipDecoder, nil},
|
|
{"Datetime->Skip", bsonDatetime, Datetime, skipDecoder, nil},
|
|
{"Int->Skip", bsonInt, Int, skipDecoder, nil},
|
|
{"Long->Skip", bsonLong, Long, skipDecoder, nil},
|
|
{"Ulong->Skip", bsonLong, Ulong, skipDecoder, nil},
|
|
{"Null->Skip", "", Null, skipDecoder, nil},
|
|
{"Null->map[string]interface{}", "", Null, mapDecoder, map[string]interface{}(nil)},
|
|
{"Null->[]interface{}", "", Null, arrayDecoder, []interface{}(nil)},
|
|
{"Array->[]string", bsonStringArray, Array, stringArrayDecoder, []string{"test1", "test2"}},
|
|
{"Null->[]string", "", Null, stringArrayDecoder, []string(nil)},
|
|
}
|
|
|
|
func TestCustomUnmarshal(t *testing.T) {
|
|
for _, tcase := range customUnmarshalCases {
|
|
buf := bytes.NewBuffer([]byte(tcase.in))
|
|
got := tcase.decoder(buf, tcase.kind)
|
|
if !reflect.DeepEqual(got, tcase.out) {
|
|
t.Errorf("%s: received: %v, want %v", tcase.desc, got, tcase.out)
|
|
}
|
|
if buf.Len() != 0 {
|
|
t.Errorf("%s: %d unread bytes from %q, want 0", tcase.desc, buf.Len(), tcase.in)
|
|
}
|
|
}
|
|
}
|
|
|
|
var customUnmarshalFailureCases = []struct {
|
|
typ string
|
|
decoder func(buf *bytes.Buffer, kind byte) interface{}
|
|
valid []byte
|
|
}{
|
|
{"string", stringDecoder, []byte{String, Binary, Null}},
|
|
{"[]byte", binaryDecoder, []byte{String, Binary, Null}},
|
|
{"int64", int64Decoder, []byte{Int, Long, Ulong, Null}},
|
|
{"int32", int32Decoder, []byte{Int, Long, Null}},
|
|
{"int", intDecoder, []byte{Int, Long, Ulong, Null}},
|
|
{"uint64", uint64Decoder, []byte{Int, Long, Ulong, Null}},
|
|
{"uint32", uint32Decoder, []byte{Int, Long, Ulong, Null}},
|
|
{"uint", uintDecoder, []byte{Int, Long, Ulong, Null}},
|
|
{"float64", float64Decoder, []byte{Number, Null}},
|
|
{"bool", boolDecoder, []byte{Boolean, Int, Long, Ulong, Null}},
|
|
{"time.Time", timeDecoder, []byte{Datetime, Null}},
|
|
{"interface{}", interfaceDecoder, []byte{Number, String, Object, Array, Binary, Boolean, Datetime, Null, Int, Long, Ulong}},
|
|
{"map", mapDecoder, []byte{Object, Null}},
|
|
{"slice", arrayDecoder, []byte{Array, Null}},
|
|
{"[]string", stringArrayDecoder, []byte{Array, Null}},
|
|
{"skip", skipDecoder, []byte{Number, String, Object, Array, Binary, Boolean, Datetime, Null, Int, Long, Ulong}},
|
|
}
|
|
|
|
func TestCustomUnmarshalFailures(t *testing.T) {
|
|
allKinds := []byte{EOO, Number, String, Object, Array, Binary, Boolean, Datetime, Null, Int, Long, Ulong}
|
|
for _, tcase := range customUnmarshalFailureCases {
|
|
for _, kind := range allKinds {
|
|
want := fmt.Sprintf("unexpected kind %v for %s", kind, tcase.typ)
|
|
func() {
|
|
defer func() {
|
|
if x := recover(); x != nil {
|
|
got := x.(BsonError).Error()
|
|
if got != want {
|
|
t.Errorf("got %s, want %s", got, want)
|
|
}
|
|
return
|
|
}
|
|
}()
|
|
for _, valid := range tcase.valid {
|
|
if kind == valid {
|
|
return
|
|
}
|
|
}
|
|
tcase.decoder(nil, kind)
|
|
t.Errorf("got no error, want %s", want)
|
|
}()
|
|
}
|
|
}
|
|
}
|