mirror of
https://github.com/fluencelabs/tendermint
synced 2025-05-15 08:01:19 +00:00
binary/reflect handles JSON
This commit is contained in:
parent
13ca6fb241
commit
d4e9b747d3
@ -1,6 +1,7 @@
|
|||||||
package binary
|
package binary
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
@ -28,6 +29,30 @@ func WriteBinary(o interface{}, w io.Writer, n *int64, err *error) {
|
|||||||
writeReflect(rv, rt, w, n, err)
|
writeReflect(rv, rt, w, n, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadJSON(o interface{}, bytes []byte, err *error) interface{} {
|
||||||
|
var parsed interface{}
|
||||||
|
*err = json.Unmarshal(bytes, &parsed)
|
||||||
|
if *err != nil {
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
rv, rt := reflect.ValueOf(o), reflect.TypeOf(o)
|
||||||
|
if rv.Kind() == reflect.Ptr {
|
||||||
|
readReflectJSON(rv.Elem(), rt.Elem(), parsed, err)
|
||||||
|
return o
|
||||||
|
} else {
|
||||||
|
ptrRv := reflect.New(rt)
|
||||||
|
readReflectJSON(ptrRv.Elem(), rt, parsed, err)
|
||||||
|
return ptrRv.Elem().Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteJSON(o interface{}, w io.Writer, n *int64, err *error) {
|
||||||
|
rv := reflect.ValueOf(o)
|
||||||
|
rt := reflect.TypeOf(o)
|
||||||
|
writeReflectJSON(rv, rt, w, n, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Write all of bz to w
|
// Write all of bz to w
|
||||||
// Increment n and set err accordingly.
|
// Increment n and set err accordingly.
|
||||||
func WriteTo(bz []byte, w io.Writer, n *int64, err *error) {
|
func WriteTo(bz []byte, w io.Writer, n *int64, err *error) {
|
||||||
|
@ -11,8 +11,8 @@ var log = log15.New("module", "binary")
|
|||||||
func init() {
|
func init() {
|
||||||
log.SetHandler(
|
log.SetHandler(
|
||||||
log15.LvlFilterHandler(
|
log15.LvlFilterHandler(
|
||||||
//log15.LvlWarn,
|
log15.LvlWarn,
|
||||||
log15.LvlDebug,
|
//log15.LvlDebug,
|
||||||
log15.StreamHandler(os.Stderr, log15.LogfmtFormat()),
|
log15.StreamHandler(os.Stderr, log15.LogfmtFormat()),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package binary
|
package binary
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
@ -127,7 +128,7 @@ func RegisterType(info *TypeInfo) *TypeInfo {
|
|||||||
zero := reflect.Zero(rt)
|
zero := reflect.Zero(rt)
|
||||||
typeByte := zero.Interface().(HasTypeByte).TypeByte()
|
typeByte := zero.Interface().(HasTypeByte).TypeByte()
|
||||||
if info.HasTypeByte && info.TypeByte != typeByte {
|
if info.HasTypeByte && info.TypeByte != typeByte {
|
||||||
panic(fmt.Sprintf("Type %v expected TypeByte of %X", rt, typeByte))
|
panic(Fmt("Type %v expected TypeByte of %X", rt, typeByte))
|
||||||
} else {
|
} else {
|
||||||
info.HasTypeByte = true
|
info.HasTypeByte = true
|
||||||
info.TypeByte = typeByte
|
info.TypeByte = typeByte
|
||||||
@ -136,7 +137,7 @@ func RegisterType(info *TypeInfo) *TypeInfo {
|
|||||||
zero := reflect.Zero(ptrRt)
|
zero := reflect.Zero(ptrRt)
|
||||||
typeByte := zero.Interface().(HasTypeByte).TypeByte()
|
typeByte := zero.Interface().(HasTypeByte).TypeByte()
|
||||||
if info.HasTypeByte && info.TypeByte != typeByte {
|
if info.HasTypeByte && info.TypeByte != typeByte {
|
||||||
panic(fmt.Sprintf("Type %v expected TypeByte of %X", ptrRt, typeByte))
|
panic(Fmt("Type %v expected TypeByte of %X", ptrRt, typeByte))
|
||||||
} else {
|
} else {
|
||||||
info.HasTypeByte = true
|
info.HasTypeByte = true
|
||||||
info.TypeByte = typeByte
|
info.TypeByte = typeByte
|
||||||
@ -178,7 +179,7 @@ func readReflect(rv reflect.Value, rt reflect.Type, r Unreader, n *int64, err *e
|
|||||||
typeByte := ReadByte(r, n, err)
|
typeByte := ReadByte(r, n, err)
|
||||||
log.Debug("Read typebyte", "typeByte", typeByte)
|
log.Debug("Read typebyte", "typeByte", typeByte)
|
||||||
if typeByte != typeInfo.TypeByte {
|
if typeByte != typeInfo.TypeByte {
|
||||||
*err = errors.New(fmt.Sprintf("Expected TypeByte of %X but got %X", typeInfo.TypeByte, typeByte))
|
*err = errors.New(Fmt("Expected TypeByte of %X but got %X", typeInfo.TypeByte, typeByte))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,7 +285,7 @@ func readReflect(rv reflect.Value, rt reflect.Type, r Unreader, n *int64, err *e
|
|||||||
rv.SetUint(uint64(num))
|
rv.SetUint(uint64(num))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unknown field type %v", rt.Kind()))
|
panic(Fmt("Unknown field type %v", rt.Kind()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,8 +312,6 @@ func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err
|
|||||||
if rt.Kind() == reflect.Ptr {
|
if rt.Kind() == reflect.Ptr {
|
||||||
rt = rt.Elem()
|
rt = rt.Elem()
|
||||||
rv = rv.Elem()
|
rv = rv.Elem()
|
||||||
// RegisterType registers the ptr type,
|
|
||||||
// so typeInfo is already for the ptr.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write TypeByte prefix
|
// Write TypeByte prefix
|
||||||
@ -383,6 +382,256 @@ func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err
|
|||||||
WriteUvarint(uint(rv.Uint()), w, n, err)
|
WriteUvarint(uint(rv.Uint()), w, n, err)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unknown field type %v", rt.Kind()))
|
panic(Fmt("Unknown field type %v", rt.Kind()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func readTypeByteJSON(o interface{}) (typeByte byte, rest interface{}, err error) {
|
||||||
|
oSlice, ok := o.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
err = errors.New(Fmt("Expected type [TypeByte,?] but got type %v", reflect.TypeOf(o)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(oSlice) != 2 {
|
||||||
|
err = errors.New(Fmt("Expected [TypeByte,?] len 2 but got len %v", len(oSlice)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
typeByte_, ok := oSlice[0].(float64)
|
||||||
|
typeByte = byte(typeByte_)
|
||||||
|
rest = oSlice[1]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *error) {
|
||||||
|
|
||||||
|
log.Debug("Read reflect json", "type", rt)
|
||||||
|
|
||||||
|
// Get typeInfo
|
||||||
|
typeInfo := GetTypeInfo(rt)
|
||||||
|
|
||||||
|
// Create a new struct if rv is nil pointer.
|
||||||
|
if rt.Kind() == reflect.Ptr && rv.IsNil() {
|
||||||
|
newRv := reflect.New(rt.Elem())
|
||||||
|
rv.Set(newRv)
|
||||||
|
rv = newRv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dereference pointer
|
||||||
|
// Still addressable, thus settable!
|
||||||
|
if rv.Kind() == reflect.Ptr {
|
||||||
|
rv, rt = rv.Elem(), rt.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read TypeByte prefix
|
||||||
|
if typeInfo.HasTypeByte {
|
||||||
|
typeByte, rest, err_ := readTypeByteJSON(o)
|
||||||
|
if err_ != nil {
|
||||||
|
*err = err_
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if typeByte != typeInfo.TypeByte {
|
||||||
|
*err = errors.New(Fmt("Expected TypeByte of %X but got %X", typeInfo.TypeByte, byte(typeByte)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
o = rest
|
||||||
|
}
|
||||||
|
|
||||||
|
switch rt.Kind() {
|
||||||
|
case reflect.Interface:
|
||||||
|
typeByte, _, err_ := readTypeByteJSON(o)
|
||||||
|
if err_ != nil {
|
||||||
|
*err = err_
|
||||||
|
return
|
||||||
|
}
|
||||||
|
concreteType, ok := typeInfo.ConcreteTypes[typeByte]
|
||||||
|
if !ok {
|
||||||
|
panic(Fmt("TypeByte %X not registered for interface %v", typeByte, rt))
|
||||||
|
}
|
||||||
|
newRv := reflect.New(concreteType)
|
||||||
|
readReflectJSON(newRv.Elem(), concreteType, o, err)
|
||||||
|
rv.Set(newRv.Elem())
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
elemRt := rt.Elem()
|
||||||
|
if elemRt.Kind() == reflect.Uint8 {
|
||||||
|
// Special case: Byteslices
|
||||||
|
oString, ok := o.(string)
|
||||||
|
if !ok {
|
||||||
|
*err = errors.New(Fmt("Expected string but got type %v", reflect.TypeOf(o)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
byteslice, err_ := hex.DecodeString(oString)
|
||||||
|
if err_ != nil {
|
||||||
|
*err = err_
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("Read byteslice", "bytes", byteslice)
|
||||||
|
rv.Set(reflect.ValueOf(byteslice))
|
||||||
|
} else {
|
||||||
|
// Read length
|
||||||
|
oSlice, ok := o.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
*err = errors.New(Fmt("Expected array but got type %v", reflect.TypeOf(o)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
length := len(oSlice)
|
||||||
|
log.Debug(Fmt("Read length: %v", length))
|
||||||
|
sliceRv := reflect.MakeSlice(rt, length, length)
|
||||||
|
// Read elems
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
elemRv := sliceRv.Index(i)
|
||||||
|
readReflectJSON(elemRv, elemRt, oSlice[i], err)
|
||||||
|
}
|
||||||
|
rv.Set(sliceRv)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
oMap, ok := o.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
*err = errors.New(Fmt("Expected map but got type %v", reflect.TypeOf(o)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: ensure that all fields are set?
|
||||||
|
for name, value := range oMap {
|
||||||
|
field, ok := rt.FieldByName(name)
|
||||||
|
if !ok {
|
||||||
|
*err = errors.New(Fmt("Attempt to set unknown field %v", field.Name))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// JAE: I don't think golang reflect lets us set unexported fields, but just in case:
|
||||||
|
if field.PkgPath != "" {
|
||||||
|
*err = errors.New(Fmt("Attempt to set unexported field %v", field.Name))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fieldRv := rv.FieldByName(name)
|
||||||
|
readReflectJSON(fieldRv, field.Type, value, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.String:
|
||||||
|
str, ok := o.(string)
|
||||||
|
if !ok {
|
||||||
|
*err = errors.New(Fmt("Expected string but got type %v", reflect.TypeOf(o)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug(Fmt("Read string: %v", str))
|
||||||
|
rv.SetString(str)
|
||||||
|
|
||||||
|
case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
|
||||||
|
num, ok := o.(float64)
|
||||||
|
if !ok {
|
||||||
|
*err = errors.New(Fmt("Expected numeric but got type %v", reflect.TypeOf(o)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug(Fmt("Read num: %v", num))
|
||||||
|
rv.SetInt(int64(num))
|
||||||
|
|
||||||
|
case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint:
|
||||||
|
num, ok := o.(float64)
|
||||||
|
if !ok {
|
||||||
|
*err = errors.New(Fmt("Expected numeric but got type %v", reflect.TypeOf(o)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if num < 0 {
|
||||||
|
*err = errors.New(Fmt("Expected unsigned numeric but got %v", num))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug(Fmt("Read num: %v", num))
|
||||||
|
rv.SetUint(uint64(num))
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(Fmt("Unknown field type %v", rt.Kind()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err *error) {
|
||||||
|
|
||||||
|
// Get typeInfo
|
||||||
|
typeInfo := GetTypeInfo(rt)
|
||||||
|
|
||||||
|
// Custom encoder, say for an interface type rt.
|
||||||
|
if typeInfo.Encoder != nil {
|
||||||
|
typeInfo.Encoder(rv.Interface(), w, n, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dereference interface
|
||||||
|
if rt.Kind() == reflect.Interface {
|
||||||
|
rv = rv.Elem()
|
||||||
|
rt = rv.Type()
|
||||||
|
// If interface type, get typeInfo of underlying type.
|
||||||
|
typeInfo = GetTypeInfo(rt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dereference pointer
|
||||||
|
if rt.Kind() == reflect.Ptr {
|
||||||
|
rt = rt.Elem()
|
||||||
|
rv = rv.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write TypeByte prefix
|
||||||
|
if typeInfo.HasTypeByte {
|
||||||
|
WriteTo([]byte(Fmt("[%v,", typeInfo.TypeByte)), w, n, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch rt.Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
elemRt := rt.Elem()
|
||||||
|
if elemRt.Kind() == reflect.Uint8 {
|
||||||
|
// Special case: Byteslices
|
||||||
|
byteslice := rv.Bytes()
|
||||||
|
WriteTo([]byte(Fmt("\"%X\"", byteslice)), w, n, err)
|
||||||
|
//WriteByteSlice(byteslice, w, n, err)
|
||||||
|
} else {
|
||||||
|
WriteTo([]byte("["), w, n, err)
|
||||||
|
// Write elems
|
||||||
|
length := rv.Len()
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
elemRv := rv.Index(i)
|
||||||
|
writeReflectJSON(elemRv, elemRt, w, n, err)
|
||||||
|
if i < length-1 {
|
||||||
|
WriteTo([]byte(","), w, n, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WriteTo([]byte("]"), w, n, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Struct:
|
||||||
|
WriteTo([]byte("{"), w, n, err)
|
||||||
|
numFields := rt.NumField()
|
||||||
|
for i := 0; i < numFields; i++ {
|
||||||
|
field := rt.Field(i)
|
||||||
|
if field.PkgPath != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fieldRv := rv.Field(i)
|
||||||
|
WriteTo([]byte(Fmt("\"%v\":", field.Name)), w, n, err)
|
||||||
|
writeReflectJSON(fieldRv, field.Type, w, n, err)
|
||||||
|
if i < numFields-1 {
|
||||||
|
WriteTo([]byte(","), w, n, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WriteTo([]byte("}"), w, n, err)
|
||||||
|
|
||||||
|
case reflect.String:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
|
||||||
|
jsonBytes, err_ := json.Marshal(rv.Interface())
|
||||||
|
if err_ != nil {
|
||||||
|
*err = err_
|
||||||
|
return
|
||||||
|
}
|
||||||
|
WriteTo(jsonBytes, w, n, err)
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(Fmt("Unknown field type %v", rt.Kind()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write TypeByte close bracket
|
||||||
|
if typeInfo.HasTypeByte {
|
||||||
|
WriteTo([]byte("]"), w, n, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,51 +58,40 @@ var _ = RegisterInterface(
|
|||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
func TestBasic(t *testing.T) {
|
type Constructor func() interface{}
|
||||||
|
type Instantiator func() (o interface{}, ptr interface{})
|
||||||
|
type Validator func(o interface{}, t *testing.T)
|
||||||
|
|
||||||
|
type TestCase struct {
|
||||||
|
Constructor
|
||||||
|
Instantiator
|
||||||
|
Validator
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
func constructBasic() interface{} {
|
||||||
cat := Cat{
|
cat := Cat{
|
||||||
SimpleStruct{
|
SimpleStruct{
|
||||||
String: "String",
|
String: "String",
|
||||||
Bytes: []byte("Bytes"),
|
Bytes: []byte("Bytes"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
return cat
|
||||||
buf, n, err := new(bytes.Buffer), new(int64), new(error)
|
|
||||||
WriteBinary(cat, buf, n, err)
|
|
||||||
if *err != nil {
|
|
||||||
t.Fatalf("Failed to write cat: %v", *err)
|
|
||||||
}
|
|
||||||
t.Logf("Wrote bytes: %X", buf.Bytes())
|
|
||||||
bufBytes := buf.Bytes()
|
|
||||||
|
|
||||||
// Read onto a struct
|
|
||||||
cat2_ := ReadBinary(Cat{}, buf, n, err)
|
|
||||||
if *err != nil {
|
|
||||||
t.Fatalf("Failed to read cat: %v", *err)
|
|
||||||
}
|
|
||||||
cat2 := cat2_.(Cat)
|
|
||||||
|
|
||||||
if cat2.String != "String" {
|
|
||||||
t.Errorf("Expected cat2.String == 'String', got %v", cat2.String)
|
|
||||||
}
|
|
||||||
if string(cat2.Bytes) != "Bytes" {
|
|
||||||
t.Errorf("Expected cat2.Bytes == 'Bytes', got %X", cat2.Bytes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read onto a ptr
|
func instantiateBasic() (interface{}, interface{}) {
|
||||||
r := bytes.NewReader(bufBytes)
|
return Cat{}, &Cat{}
|
||||||
cat3_ := ReadBinary(&Cat{}, r, n, err)
|
|
||||||
if *err != nil {
|
|
||||||
t.Fatalf("Failed to read cat: %v", *err)
|
|
||||||
}
|
|
||||||
cat3 := cat3_.(*Cat)
|
|
||||||
|
|
||||||
if cat3.String != "String" {
|
|
||||||
t.Errorf("Expected cat3.String == 'String', got %v", cat3.String)
|
|
||||||
}
|
|
||||||
if string(cat3.Bytes) != "Bytes" {
|
|
||||||
t.Errorf("Expected cat3.Bytes == 'Bytes', got %X", cat3.Bytes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateBasic(o interface{}, t *testing.T) {
|
||||||
|
cat := o.(Cat)
|
||||||
|
if cat.String != "String" {
|
||||||
|
t.Errorf("Expected cat2.String == 'String', got %v", cat.String)
|
||||||
|
}
|
||||||
|
if string(cat.Bytes) != "Bytes" {
|
||||||
|
t.Errorf("Expected cat2.Bytes == 'Bytes', got %X", cat.Bytes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
@ -112,38 +101,22 @@ type ComplexStruct struct {
|
|||||||
Animal Animal
|
Animal Animal
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestComplexStruct(t *testing.T) {
|
func constructComplex() interface{} {
|
||||||
c := ComplexStruct{
|
c := ComplexStruct{
|
||||||
Name: "Complex",
|
Name: "Complex",
|
||||||
Animal: Cat{
|
Animal: constructBasic(),
|
||||||
SimpleStruct{
|
}
|
||||||
String: "String",
|
return c
|
||||||
Bytes: []byte("Bytes"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf, n, err := new(bytes.Buffer), new(int64), new(error)
|
func instantiateComplex() (interface{}, interface{}) {
|
||||||
WriteBinary(c, buf, n, err)
|
return ComplexStruct{}, &ComplexStruct{}
|
||||||
if *err != nil {
|
|
||||||
t.Fatalf("Failed to write c: %v", *err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Wrote bytes: %X", buf.Bytes())
|
func validateComplex(o interface{}, t *testing.T) {
|
||||||
|
c2 := o.(ComplexStruct)
|
||||||
c2_ := ReadBinary(&ComplexStruct{}, buf, n, err)
|
|
||||||
if *err != nil {
|
|
||||||
t.Fatalf("Failed to read c: %v", *err)
|
|
||||||
}
|
|
||||||
c2 := c2_.(*ComplexStruct)
|
|
||||||
|
|
||||||
if cat, ok := c2.Animal.(Cat); ok {
|
if cat, ok := c2.Animal.(Cat); ok {
|
||||||
if cat.String != "String" {
|
validateBasic(cat, t)
|
||||||
t.Errorf("Expected cat.String == 'String', got %v", cat.String)
|
|
||||||
}
|
|
||||||
if string(cat.Bytes) != "Bytes" {
|
|
||||||
t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
t.Errorf("Expected c2.Animal to be of type cat, got %v", reflect.ValueOf(c2.Animal).Elem().Type())
|
t.Errorf("Expected c2.Animal to be of type cat, got %v", reflect.ValueOf(c2.Animal).Elem().Type())
|
||||||
}
|
}
|
||||||
@ -151,12 +124,91 @@ func TestComplexStruct(t *testing.T) {
|
|||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
type ComplexArrayStruct struct {
|
type ComplexStruct2 struct {
|
||||||
|
Cat Cat
|
||||||
|
Dog *Dog
|
||||||
|
Snake Snake
|
||||||
|
Snake2 *Snake
|
||||||
|
Viper Viper
|
||||||
|
Viper2 *Viper
|
||||||
|
}
|
||||||
|
|
||||||
|
func constructComplex2() interface{} {
|
||||||
|
snake_ := Snake([]byte("hiss"))
|
||||||
|
snakePtr_ := &snake_
|
||||||
|
|
||||||
|
c := ComplexStruct2{
|
||||||
|
Cat: Cat{
|
||||||
|
SimpleStruct{
|
||||||
|
String: "String",
|
||||||
|
Bytes: []byte("Bytes"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Dog: &Dog{
|
||||||
|
SimpleStruct{
|
||||||
|
String: "Woof",
|
||||||
|
Bytes: []byte("Bark"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Snake: Snake([]byte("hiss")),
|
||||||
|
Snake2: snakePtr_,
|
||||||
|
Viper: Viper{Bytes: []byte("hizz")},
|
||||||
|
Viper2: &Viper{Bytes: []byte("hizz")},
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func instantiateComplex2() (interface{}, interface{}) {
|
||||||
|
return ComplexStruct2{}, &ComplexStruct2{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateComplex2(o interface{}, t *testing.T) {
|
||||||
|
c2 := o.(ComplexStruct2)
|
||||||
|
cat := c2.Cat
|
||||||
|
if cat.String != "String" {
|
||||||
|
t.Errorf("Expected cat.String == 'String', got %v", cat.String)
|
||||||
|
}
|
||||||
|
if string(cat.Bytes) != "Bytes" {
|
||||||
|
t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
dog := c2.Dog
|
||||||
|
if dog.String != "Woof" {
|
||||||
|
t.Errorf("Expected dog.String == 'Woof', got %v", dog.String)
|
||||||
|
}
|
||||||
|
if string(dog.Bytes) != "Bark" {
|
||||||
|
t.Errorf("Expected dog.Bytes == 'Bark', got %X", dog.Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
snake := c2.Snake
|
||||||
|
if string(snake) != "hiss" {
|
||||||
|
t.Errorf("Expected string(snake) == 'hiss', got %v", string(snake))
|
||||||
|
}
|
||||||
|
|
||||||
|
snake2 := c2.Snake2
|
||||||
|
if string(*snake2) != "hiss" {
|
||||||
|
t.Errorf("Expected string(snake2) == 'hiss', got %v", string(*snake2))
|
||||||
|
}
|
||||||
|
|
||||||
|
viper := c2.Viper
|
||||||
|
if string(viper.Bytes) != "hizz" {
|
||||||
|
t.Errorf("Expected string(viper.Bytes) == 'hizz', got %v", string(viper.Bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
viper2 := c2.Viper2
|
||||||
|
if string(viper2.Bytes) != "hizz" {
|
||||||
|
t.Errorf("Expected string(viper2.Bytes) == 'hizz', got %v", string(viper2.Bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
type ComplexStructArray struct {
|
||||||
Animals []Animal
|
Animals []Animal
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestComplexArrayStruct(t *testing.T) {
|
func constructComplexArray() interface{} {
|
||||||
c := ComplexArrayStruct{
|
c := ComplexStructArray{
|
||||||
Animals: []Animal{
|
Animals: []Animal{
|
||||||
Cat{
|
Cat{
|
||||||
SimpleStruct{
|
SimpleStruct{
|
||||||
@ -176,21 +228,15 @@ func TestComplexArrayStruct(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
return c
|
||||||
buf, n, err := new(bytes.Buffer), new(int64), new(error)
|
|
||||||
WriteBinary(c, buf, n, err)
|
|
||||||
if *err != nil {
|
|
||||||
t.Fatalf("Failed to write c: %v", *err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Wrote bytes: %X", buf.Bytes())
|
func instantiateComplexArray() (interface{}, interface{}) {
|
||||||
|
return ComplexStructArray{}, &ComplexStructArray{}
|
||||||
c2_ := ReadBinary(&ComplexArrayStruct{}, buf, n, err)
|
|
||||||
if *err != nil {
|
|
||||||
t.Fatalf("Failed to read c: %v", *err)
|
|
||||||
}
|
}
|
||||||
c2 := c2_.(*ComplexArrayStruct)
|
|
||||||
|
|
||||||
|
func validateComplexArray(o interface{}, t *testing.T) {
|
||||||
|
c2 := o.(ComplexStructArray)
|
||||||
if cat, ok := c2.Animals[0].(Cat); ok {
|
if cat, ok := c2.Animals[0].(Cat); ok {
|
||||||
if cat.String != "String" {
|
if cat.String != "String" {
|
||||||
t.Errorf("Expected cat.String == 'String', got %v", cat.String)
|
t.Errorf("Expected cat.String == 'String', got %v", cat.String)
|
||||||
@ -230,88 +276,92 @@ func TestComplexArrayStruct(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
type ComplexStruct2 struct {
|
var testCases = []TestCase{}
|
||||||
Cat Cat
|
|
||||||
Dog *Dog
|
func init() {
|
||||||
Snake Snake
|
testCases = append(testCases, TestCase{constructBasic, instantiateBasic, validateBasic})
|
||||||
Snake2 *Snake
|
testCases = append(testCases, TestCase{constructComplex, instantiateComplex, validateComplex})
|
||||||
Viper Viper
|
testCases = append(testCases, TestCase{constructComplex2, instantiateComplex2, validateComplex2})
|
||||||
Viper2 *Viper
|
testCases = append(testCases, TestCase{constructComplexArray, instantiateComplexArray, validateComplexArray})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestComplexStruct2(t *testing.T) {
|
func TestBinary(t *testing.T) {
|
||||||
|
|
||||||
snake_ := Snake([]byte("hiss"))
|
for _, testCase := range testCases {
|
||||||
snakePtr_ := &snake_
|
|
||||||
|
|
||||||
c := ComplexStruct2{
|
// Construct an object
|
||||||
Cat: Cat{
|
o := testCase.Constructor()
|
||||||
SimpleStruct{
|
|
||||||
String: "String",
|
|
||||||
Bytes: []byte("Bytes"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Dog: &Dog{
|
|
||||||
SimpleStruct{
|
|
||||||
String: "Woof",
|
|
||||||
Bytes: []byte("Bark"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Snake: Snake([]byte("hiss")),
|
|
||||||
Snake2: snakePtr_,
|
|
||||||
Viper: Viper{Bytes: []byte("hizz")},
|
|
||||||
Viper2: &Viper{Bytes: []byte("hizz")},
|
|
||||||
}
|
|
||||||
|
|
||||||
buf, n, err := new(bytes.Buffer), new(int64), new(error)
|
// Write the object
|
||||||
WriteBinary(c, buf, n, err)
|
data := BinaryBytes(o)
|
||||||
|
t.Logf("Binary: %X", data)
|
||||||
|
|
||||||
|
instance, instancePtr := testCase.Instantiator()
|
||||||
|
|
||||||
|
// Read onto a struct
|
||||||
|
n, err := new(int64), new(error)
|
||||||
|
res := ReadBinary(instance, bytes.NewReader(data), n, err)
|
||||||
if *err != nil {
|
if *err != nil {
|
||||||
t.Fatalf("Failed to write c: %v", *err)
|
t.Fatalf("Failed to read cat: %v", *err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Wrote bytes: %X", buf.Bytes())
|
// Validate object
|
||||||
|
testCase.Validator(res, t)
|
||||||
|
|
||||||
c2_ := ReadBinary(&ComplexStruct2{}, buf, n, err)
|
// Read onto a pointer
|
||||||
|
n, err = new(int64), new(error)
|
||||||
|
res = ReadBinary(instancePtr, bytes.NewReader(data), n, err)
|
||||||
if *err != nil {
|
if *err != nil {
|
||||||
t.Fatalf("Failed to read c: %v", *err)
|
t.Fatalf("Failed to read cat: %v", *err)
|
||||||
}
|
|
||||||
c2 := c2_.(*ComplexStruct2)
|
|
||||||
|
|
||||||
cat := c2.Cat
|
|
||||||
if cat.String != "String" {
|
|
||||||
t.Errorf("Expected cat.String == 'String', got %v", cat.String)
|
|
||||||
}
|
|
||||||
if string(cat.Bytes) != "Bytes" {
|
|
||||||
t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dog := c2.Dog
|
if res != instancePtr {
|
||||||
if dog.String != "Woof" {
|
t.Errorf("Expected pointer to pass through")
|
||||||
t.Errorf("Expected dog.String == 'Woof', got %v", dog.String)
|
|
||||||
}
|
|
||||||
if string(dog.Bytes) != "Bark" {
|
|
||||||
t.Errorf("Expected dog.Bytes == 'Bark', got %X", dog.Bytes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
snake := c2.Snake
|
// Validate object
|
||||||
if string(snake) != "hiss" {
|
testCase.Validator(reflect.ValueOf(res).Elem().Interface(), t)
|
||||||
t.Errorf("Expected string(snake) == 'hiss', got %v", string(snake))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
snake2 := c2.Snake2
|
|
||||||
if string(*snake2) != "hiss" {
|
|
||||||
t.Errorf("Expected string(snake2) == 'hiss', got %v", string(*snake2))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
viper := c2.Viper
|
func TestJSON(t *testing.T) {
|
||||||
if string(viper.Bytes) != "hizz" {
|
|
||||||
t.Errorf("Expected string(viper.Bytes) == 'hizz', got %v", string(viper.Bytes))
|
for _, testCase := range testCases {
|
||||||
|
|
||||||
|
// Construct an object
|
||||||
|
o := testCase.Constructor()
|
||||||
|
|
||||||
|
// Write the object
|
||||||
|
data := JSONBytes(o)
|
||||||
|
t.Logf("JSON: %v", string(data))
|
||||||
|
|
||||||
|
instance, instancePtr := testCase.Instantiator()
|
||||||
|
|
||||||
|
// Read onto a struct
|
||||||
|
err := new(error)
|
||||||
|
res := ReadJSON(instance, data, err)
|
||||||
|
if *err != nil {
|
||||||
|
t.Fatalf("Failed to read cat: %v", *err)
|
||||||
}
|
}
|
||||||
|
|
||||||
viper2 := c2.Viper2
|
// Validate object
|
||||||
if string(viper2.Bytes) != "hizz" {
|
testCase.Validator(res, t)
|
||||||
t.Errorf("Expected string(viper2.Bytes) == 'hizz', got %v", string(viper2.Bytes))
|
|
||||||
|
// Read onto a pointer
|
||||||
|
res = ReadJSON(instancePtr, data, err)
|
||||||
|
if *err != nil {
|
||||||
|
t.Fatalf("Failed to read cat: %v", *err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if res != instancePtr {
|
||||||
|
t.Errorf("Expected pointer to pass through")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate object
|
||||||
|
testCase.Validator(reflect.ValueOf(res).Elem().Interface(), t)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,15 @@ func BinaryBytes(o interface{}) []byte {
|
|||||||
return w.Bytes()
|
return w.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func JSONBytes(o interface{}) []byte {
|
||||||
|
w, n, err := new(bytes.Buffer), new(int64), new(error)
|
||||||
|
WriteJSON(o, w, n, err)
|
||||||
|
if *err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return w.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: does not care about the type, only the binary representation.
|
// NOTE: does not care about the type, only the binary representation.
|
||||||
func BinaryEqual(a, b interface{}) bool {
|
func BinaryEqual(a, b interface{}) bool {
|
||||||
aBytes := BinaryBytes(a)
|
aBytes := BinaryBytes(a)
|
||||||
|
@ -2,7 +2,6 @@ package rpc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
@ -31,10 +30,7 @@ func MempoolHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
ReturnJSON(API_ERROR, Fmt("Error broadcasting transaction: %v", err))
|
ReturnJSON(API_ERROR, Fmt("Error broadcasting transaction: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonBytes, err := json.MarshalIndent(tx, "", " ")
|
jsonBytes := JSONBytes(tx)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fmt.Println(">>", string(jsonBytes))
|
fmt.Println(">>", string(jsonBytes))
|
||||||
|
|
||||||
ReturnJSON(API_OK, Fmt("Broadcasted tx: %X", tx))
|
ReturnJSON(API_OK, Fmt("Broadcasted tx: %X", tx))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user