Skip to content

Instantly share code, notes, and snippets.

@dmaze
Created November 29, 2015 23:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmaze/be159301fac5007dda41 to your computer and use it in GitHub Desktop.
Save dmaze/be159301fac5007dda41 to your computer and use it in GitHub Desktop.
github.com/ugorji/go/codec decode issue with extension objects
// This file demonstrates an issue decoding nested extension objects.
// The actual extension is a simple wrapper for a Python tuple, which
// is implemented by wrapping a simple CBOR list with CBOR tag 128.
package main
import (
"github.com/ugorji/go/codec"
"reflect"
"testing"
)
// Tuple wrapper object ---------------------------------------------
// PythonTuple is a simple Go wrapper representing a Python tuple.
// This is a fixed-length, ordered, immutable sequence of arbitrary
// items.
type PythonTuple struct {
Items []interface{}
}
// Codec library extension ------------------------------------------
// pythonTupleExt is a codec extension plugin to encode and decode
// PythonTuple objects.
type pythonTupleExt struct {
}
func (x pythonTupleExt) ConvertExt(v interface{}) interface{} {
var ptuple *PythonTuple
ptuple, ok := v.(*PythonTuple)
if !ok {
tuple := v.(PythonTuple)
ptuple = &tuple
}
if ptuple.Items != nil {
return ptuple.Items
}
return []interface{}{}
}
func (x pythonTupleExt) UpdateExt(dest interface{}, v interface{}) {
items := v.([]interface{})
tuple := dest.(*PythonTuple)
*tuple = PythonTuple{items}
}
// SetExts assigns the Python tuple extension to a CBOR transcoder
// with tag 128.
func SetExts(cbor *codec.CborHandle) error {
var tuple PythonTuple
return cbor.SetInterfaceExt(reflect.TypeOf(tuple), 128,
&pythonTupleExt{})
}
// Test data --------------------------------------------------------
// Data produces the test data. The output of this are a fully set
// up CBOR transcoder, reference byte data, and a reference object.
// data should be a valid CBOR encoding of obj.
//
// This appears to be a minimal object tree to reproduce the issue.
// Removing any single object from the tree results in the decode
// test passing.
func Data() (cbor *codec.CborHandle, data []byte, obj interface{}) {
cbor = new(codec.CborHandle)
err := SetExts(cbor)
if err != nil {
panic(err)
}
bottomV := []interface{}{}
bottomD := []byte{0x80}
tupleV := PythonTuple{Items: []interface{}{bottomV}}
tupleD := append([]byte{0xD8, 0x80, 0x81}, bottomD...)
listV := []interface{}{tupleV}
listD := append([]byte{0x81}, tupleD...)
listTupleV := PythonTuple{Items: []interface{}{listV}}
listTupleD := append([]byte{0xD8, 0x80, 0x81}, listD...)
topV := []interface{}{listTupleV}
topD := append([]byte{0x81}, listTupleD...)
return cbor, topD, topV
}
// Tests ------------------------------------------------------------
// TestEncode verifies that encoding the reference object produces the
// reference data. This test passes.
func TestEncode(t *testing.T) {
cbor, expected, obj := Data()
var actual []byte
encoder := codec.NewEncoderBytes(&actual, cbor)
encoder.MustEncode(obj)
if !reflect.DeepEqual(expected, actual) {
t.Errorf("encode: expected %+v actual %+v", expected, actual)
}
}
// TestDecode verifies that decoding the reference data produces the
// reference data. This test fails: instead of producing a list of
// a single tuple object, it produces an empty list.
func TestDecode(t *testing.T) {
cbor, data, expected := Data()
decoder := codec.NewDecoderBytes(data, cbor)
var actual interface{}
decoder.MustDecode(&actual)
if !reflect.DeepEqual(expected, actual) {
t.Errorf("decode: expected %+v actual %+v", expected, actual)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment