Unverified Commit f37d2929 authored by Łukasz Magiera's avatar Łukasz Magiera Committed by GitHub

Merge pull request #50 from dirkmc/feat/round-trip-extra-fields

feat: allow unmarshaling of struct with more fields than marshaled struct
parents 169e9d70 a77f48b5
......@@ -57,6 +57,7 @@ package {{ .Package }}
import (
"fmt"
"io"
"sort"
{{ range .Imports }}{{ .Name }} "{{ .PkgPath }}"
{{ end }}
......@@ -64,6 +65,8 @@ import (
var _ = xerrors.Errorf
var _ = cid.Undef
var _ = sort.Sort
`)
}
......@@ -1269,7 +1272,8 @@ func (t *{{ .Name}}) UnmarshalCBOR(r io.Reader) error {
return doTemplate(w, gti, `
default:
return fmt.Errorf("unknown struct field %d: '%s'", i, name)
// Field doesn't exist on this type, so ignore it
cbg.ScanForLinks(r, func(cid.Cid){})
}
}
......
......@@ -16,6 +16,7 @@ var (
defaultImports = []Import{
{Name: "cbg", PkgPath: "github.com/whyrusleeping/cbor-gen"},
{Name: "xerrors", PkgPath: "golang.org/x/xerrors"},
{Name: "cid", PkgPath: "github.com/ipfs/go-cid"},
}
)
......
......@@ -20,6 +20,8 @@ func main() {
if err := cbg.WriteMapEncodersToFile("testing/cbor_map_gen.go", "testing",
types.SimpleTypeTree{},
types.NeedScratchForMap{},
types.SimpleStructV1{},
types.SimpleStructV2{},
); err != nil {
panic(err)
}
......
......@@ -5,12 +5,16 @@ package testing
import (
"fmt"
"io"
"sort"
cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
xerrors "golang.org/x/xerrors"
)
var _ = xerrors.Errorf
var _ = cid.Undef
var _ = sort.Sort
var lengthBufSignedArray = []byte{129}
......
......@@ -5,12 +5,16 @@ package testing
import (
"fmt"
"io"
"sort"
cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
xerrors "golang.org/x/xerrors"
)
var _ = xerrors.Errorf
var _ = cid.Undef
var _ = sort.Sort
func (t *SimpleTypeTree) MarshalCBOR(w io.Writer) error {
if t == nil {
......@@ -402,7 +406,8 @@ func (t *SimpleTypeTree) UnmarshalCBOR(r io.Reader) error {
}
default:
return fmt.Errorf("unknown struct field %d: '%s'", i, name)
// Field doesn't exist on this type, so ignore it
cbg.ScanForLinks(r, func(cid.Cid) {})
}
}
......@@ -490,7 +495,1096 @@ func (t *NeedScratchForMap) UnmarshalCBOR(r io.Reader) error {
}
default:
return fmt.Errorf("unknown struct field %d: '%s'", i, name)
// Field doesn't exist on this type, so ignore it
cbg.ScanForLinks(r, func(cid.Cid) {})
}
}
return nil
}
func (t *SimpleStructV1) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{167}); err != nil {
return err
}
scratch := make([]byte, 9)
// t.OldStr (string) (string)
if len("OldStr") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldStr\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldStr"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldStr")); err != nil {
return err
}
if len(t.OldStr) > cbg.MaxLength {
return xerrors.Errorf("Value in field t.OldStr was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.OldStr))); err != nil {
return err
}
if _, err := io.WriteString(w, string(t.OldStr)); err != nil {
return err
}
// t.OldBytes ([]uint8) (slice)
if len("OldBytes") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldBytes\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldBytes"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldBytes")); err != nil {
return err
}
if len(t.OldBytes) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Byte array in field t.OldBytes was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.OldBytes))); err != nil {
return err
}
if _, err := w.Write(t.OldBytes[:]); err != nil {
return err
}
// t.OldNum (uint64) (uint64)
if len("OldNum") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldNum\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldNum"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldNum")); err != nil {
return err
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.OldNum)); err != nil {
return err
}
// t.OldPtr (cid.Cid) (struct)
if len("OldPtr") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldPtr\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldPtr"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldPtr")); err != nil {
return err
}
if t.OldPtr == nil {
if _, err := w.Write(cbg.CborNull); err != nil {
return err
}
} else {
if err := cbg.WriteCidBuf(scratch, w, *t.OldPtr); err != nil {
return xerrors.Errorf("failed to write cid field t.OldPtr: %w", err)
}
}
// t.OldMap (map[string]testing.SimpleTypeOne) (map)
if len("OldMap") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldMap\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldMap"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldMap")); err != nil {
return err
}
{
if len(t.OldMap) > 4096 {
return xerrors.Errorf("cannot marshal t.OldMap map too large")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajMap, uint64(len(t.OldMap))); err != nil {
return err
}
keys := make([]string, 0, len(t.OldMap))
for k := range t.OldMap {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
v := t.OldMap[k]
if len(k) > cbg.MaxLength {
return xerrors.Errorf("Value in field k was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(k))); err != nil {
return err
}
if _, err := io.WriteString(w, string(k)); err != nil {
return err
}
if err := v.MarshalCBOR(w); err != nil {
return err
}
}
}
// t.OldArray ([]testing.SimpleTypeOne) (slice)
if len("OldArray") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldArray\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldArray"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldArray")); err != nil {
return err
}
if len(t.OldArray) > cbg.MaxLength {
return xerrors.Errorf("Slice value in field t.OldArray was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.OldArray))); err != nil {
return err
}
for _, v := range t.OldArray {
if err := v.MarshalCBOR(w); err != nil {
return err
}
}
// t.OldStruct (testing.SimpleTypeOne) (struct)
if len("OldStruct") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldStruct\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldStruct"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldStruct")); err != nil {
return err
}
if err := t.OldStruct.MarshalCBOR(w); err != nil {
return err
}
return nil
}
func (t *SimpleStructV1) UnmarshalCBOR(r io.Reader) error {
*t = SimpleStructV1{}
br := cbg.GetPeeker(r)
scratch := make([]byte, 8)
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if maj != cbg.MajMap {
return fmt.Errorf("cbor input should be of type map")
}
if extra > cbg.MaxLength {
return fmt.Errorf("SimpleStructV1: map struct too large (%d)", extra)
}
var name string
n := extra
for i := uint64(0); i < n; i++ {
{
sval, err := cbg.ReadStringBuf(br, scratch)
if err != nil {
return err
}
name = string(sval)
}
switch name {
// t.OldStr (string) (string)
case "OldStr":
{
sval, err := cbg.ReadStringBuf(br, scratch)
if err != nil {
return err
}
t.OldStr = string(sval)
}
// t.OldBytes ([]uint8) (slice)
case "OldBytes":
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if extra > cbg.ByteArrayMaxLen {
return fmt.Errorf("t.OldBytes: byte array too large (%d)", extra)
}
if maj != cbg.MajByteString {
return fmt.Errorf("expected byte array")
}
if extra > 0 {
t.OldBytes = make([]uint8, extra)
}
if _, err := io.ReadFull(br, t.OldBytes[:]); err != nil {
return err
}
// t.OldNum (uint64) (uint64)
case "OldNum":
{
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.OldNum = uint64(extra)
}
// t.OldPtr (cid.Cid) (struct)
case "OldPtr":
{
b, err := br.ReadByte()
if err != nil {
return err
}
if b != cbg.CborNull[0] {
if err := br.UnreadByte(); err != nil {
return err
}
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.OldPtr: %w", err)
}
t.OldPtr = &c
}
}
// t.OldMap (map[string]testing.SimpleTypeOne) (map)
case "OldMap":
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if maj != cbg.MajMap {
return fmt.Errorf("expected a map (major type 5)")
}
if extra > 4096 {
return fmt.Errorf("t.OldMap: map too large")
}
t.OldMap = make(map[string]SimpleTypeOne, extra)
for i, l := 0, int(extra); i < l; i++ {
var k string
{
sval, err := cbg.ReadStringBuf(br, scratch)
if err != nil {
return err
}
k = string(sval)
}
var v SimpleTypeOne
{
if err := v.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling v: %w", err)
}
}
t.OldMap[k] = v
}
// t.OldArray ([]testing.SimpleTypeOne) (slice)
case "OldArray":
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if extra > cbg.MaxLength {
return fmt.Errorf("t.OldArray: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.OldArray = make([]SimpleTypeOne, extra)
}
for i := 0; i < int(extra); i++ {
var v SimpleTypeOne
if err := v.UnmarshalCBOR(br); err != nil {
return err
}
t.OldArray[i] = v
}
// t.OldStruct (testing.SimpleTypeOne) (struct)
case "OldStruct":
{
if err := t.OldStruct.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.OldStruct: %w", err)
}
}
default:
// Field doesn't exist on this type, so ignore it
cbg.ScanForLinks(r, func(cid.Cid) {})
}
}
return nil
}
func (t *SimpleStructV2) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write([]byte{174}); err != nil {
return err
}
scratch := make([]byte, 9)
// t.OldStr (string) (string)
if len("OldStr") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldStr\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldStr"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldStr")); err != nil {
return err
}
if len(t.OldStr) > cbg.MaxLength {
return xerrors.Errorf("Value in field t.OldStr was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.OldStr))); err != nil {
return err
}
if _, err := io.WriteString(w, string(t.OldStr)); err != nil {
return err
}
// t.NewStr (string) (string)
if len("NewStr") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"NewStr\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("NewStr"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("NewStr")); err != nil {
return err
}
if len(t.NewStr) > cbg.MaxLength {
return xerrors.Errorf("Value in field t.NewStr was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.NewStr))); err != nil {
return err
}
if _, err := io.WriteString(w, string(t.NewStr)); err != nil {
return err
}
// t.OldBytes ([]uint8) (slice)
if len("OldBytes") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldBytes\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldBytes"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldBytes")); err != nil {
return err
}
if len(t.OldBytes) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Byte array in field t.OldBytes was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.OldBytes))); err != nil {
return err
}
if _, err := w.Write(t.OldBytes[:]); err != nil {
return err
}
// t.NewBytes ([]uint8) (slice)
if len("NewBytes") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"NewBytes\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("NewBytes"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("NewBytes")); err != nil {
return err
}
if len(t.NewBytes) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Byte array in field t.NewBytes was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.NewBytes))); err != nil {
return err
}
if _, err := w.Write(t.NewBytes[:]); err != nil {
return err
}
// t.OldNum (uint64) (uint64)
if len("OldNum") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldNum\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldNum"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldNum")); err != nil {
return err
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.OldNum)); err != nil {
return err
}
// t.NewNum (uint64) (uint64)
if len("NewNum") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"NewNum\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("NewNum"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("NewNum")); err != nil {
return err
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.NewNum)); err != nil {
return err
}
// t.OldPtr (cid.Cid) (struct)
if len("OldPtr") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldPtr\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldPtr"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldPtr")); err != nil {
return err
}
if t.OldPtr == nil {
if _, err := w.Write(cbg.CborNull); err != nil {
return err
}
} else {
if err := cbg.WriteCidBuf(scratch, w, *t.OldPtr); err != nil {
return xerrors.Errorf("failed to write cid field t.OldPtr: %w", err)
}
}
// t.NewPtr (cid.Cid) (struct)
if len("NewPtr") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"NewPtr\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("NewPtr"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("NewPtr")); err != nil {
return err
}
if t.NewPtr == nil {
if _, err := w.Write(cbg.CborNull); err != nil {
return err
}
} else {
if err := cbg.WriteCidBuf(scratch, w, *t.NewPtr); err != nil {
return xerrors.Errorf("failed to write cid field t.NewPtr: %w", err)
}
}
// t.OldMap (map[string]testing.SimpleTypeOne) (map)
if len("OldMap") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldMap\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldMap"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldMap")); err != nil {
return err
}
{
if len(t.OldMap) > 4096 {
return xerrors.Errorf("cannot marshal t.OldMap map too large")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajMap, uint64(len(t.OldMap))); err != nil {
return err
}
keys := make([]string, 0, len(t.OldMap))
for k := range t.OldMap {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
v := t.OldMap[k]
if len(k) > cbg.MaxLength {
return xerrors.Errorf("Value in field k was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(k))); err != nil {
return err
}
if _, err := io.WriteString(w, string(k)); err != nil {
return err
}
if err := v.MarshalCBOR(w); err != nil {
return err
}
}
}
// t.NewMap (map[string]testing.SimpleTypeOne) (map)
if len("NewMap") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"NewMap\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("NewMap"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("NewMap")); err != nil {
return err
}
{
if len(t.NewMap) > 4096 {
return xerrors.Errorf("cannot marshal t.NewMap map too large")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajMap, uint64(len(t.NewMap))); err != nil {
return err
}
keys := make([]string, 0, len(t.NewMap))
for k := range t.NewMap {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
v := t.NewMap[k]
if len(k) > cbg.MaxLength {
return xerrors.Errorf("Value in field k was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(k))); err != nil {
return err
}
if _, err := io.WriteString(w, string(k)); err != nil {
return err
}
if err := v.MarshalCBOR(w); err != nil {
return err
}
}
}
// t.OldArray ([]testing.SimpleTypeOne) (slice)
if len("OldArray") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldArray\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldArray"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldArray")); err != nil {
return err
}
if len(t.OldArray) > cbg.MaxLength {
return xerrors.Errorf("Slice value in field t.OldArray was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.OldArray))); err != nil {
return err
}
for _, v := range t.OldArray {
if err := v.MarshalCBOR(w); err != nil {
return err
}
}
// t.NewArray ([]testing.SimpleTypeOne) (slice)
if len("NewArray") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"NewArray\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("NewArray"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("NewArray")); err != nil {
return err
}
if len(t.NewArray) > cbg.MaxLength {
return xerrors.Errorf("Slice value in field t.NewArray was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.NewArray))); err != nil {
return err
}
for _, v := range t.NewArray {
if err := v.MarshalCBOR(w); err != nil {
return err
}
}
// t.OldStruct (testing.SimpleTypeOne) (struct)
if len("OldStruct") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"OldStruct\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("OldStruct"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("OldStruct")); err != nil {
return err
}
if err := t.OldStruct.MarshalCBOR(w); err != nil {
return err
}
// t.NewStruct (testing.SimpleTypeOne) (struct)
if len("NewStruct") > cbg.MaxLength {
return xerrors.Errorf("Value in field \"NewStruct\" was too long")
}
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("NewStruct"))); err != nil {
return err
}
if _, err := io.WriteString(w, string("NewStruct")); err != nil {
return err
}
if err := t.NewStruct.MarshalCBOR(w); err != nil {
return err
}
return nil
}
func (t *SimpleStructV2) UnmarshalCBOR(r io.Reader) error {
*t = SimpleStructV2{}
br := cbg.GetPeeker(r)
scratch := make([]byte, 8)
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if maj != cbg.MajMap {
return fmt.Errorf("cbor input should be of type map")
}
if extra > cbg.MaxLength {
return fmt.Errorf("SimpleStructV2: map struct too large (%d)", extra)
}
var name string
n := extra
for i := uint64(0); i < n; i++ {
{
sval, err := cbg.ReadStringBuf(br, scratch)
if err != nil {
return err
}
name = string(sval)
}
switch name {
// t.OldStr (string) (string)
case "OldStr":
{
sval, err := cbg.ReadStringBuf(br, scratch)
if err != nil {
return err
}
t.OldStr = string(sval)
}
// t.NewStr (string) (string)
case "NewStr":
{
sval, err := cbg.ReadStringBuf(br, scratch)
if err != nil {
return err
}
t.NewStr = string(sval)
}
// t.OldBytes ([]uint8) (slice)
case "OldBytes":
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if extra > cbg.ByteArrayMaxLen {
return fmt.Errorf("t.OldBytes: byte array too large (%d)", extra)
}
if maj != cbg.MajByteString {
return fmt.Errorf("expected byte array")
}
if extra > 0 {
t.OldBytes = make([]uint8, extra)
}
if _, err := io.ReadFull(br, t.OldBytes[:]); err != nil {
return err
}
// t.NewBytes ([]uint8) (slice)
case "NewBytes":
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if extra > cbg.ByteArrayMaxLen {
return fmt.Errorf("t.NewBytes: byte array too large (%d)", extra)
}
if maj != cbg.MajByteString {
return fmt.Errorf("expected byte array")
}
if extra > 0 {
t.NewBytes = make([]uint8, extra)
}
if _, err := io.ReadFull(br, t.NewBytes[:]); err != nil {
return err
}
// t.OldNum (uint64) (uint64)
case "OldNum":
{
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.OldNum = uint64(extra)
}
// t.NewNum (uint64) (uint64)
case "NewNum":
{
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.NewNum = uint64(extra)
}
// t.OldPtr (cid.Cid) (struct)
case "OldPtr":
{
b, err := br.ReadByte()
if err != nil {
return err
}
if b != cbg.CborNull[0] {
if err := br.UnreadByte(); err != nil {
return err
}
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.OldPtr: %w", err)
}
t.OldPtr = &c
}
}
// t.NewPtr (cid.Cid) (struct)
case "NewPtr":
{
b, err := br.ReadByte()
if err != nil {
return err
}
if b != cbg.CborNull[0] {
if err := br.UnreadByte(); err != nil {
return err
}
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.NewPtr: %w", err)
}
t.NewPtr = &c
}
}
// t.OldMap (map[string]testing.SimpleTypeOne) (map)
case "OldMap":
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if maj != cbg.MajMap {
return fmt.Errorf("expected a map (major type 5)")
}
if extra > 4096 {
return fmt.Errorf("t.OldMap: map too large")
}
t.OldMap = make(map[string]SimpleTypeOne, extra)
for i, l := 0, int(extra); i < l; i++ {
var k string
{
sval, err := cbg.ReadStringBuf(br, scratch)
if err != nil {
return err
}
k = string(sval)
}
var v SimpleTypeOne
{
if err := v.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling v: %w", err)
}
}
t.OldMap[k] = v
}
// t.NewMap (map[string]testing.SimpleTypeOne) (map)
case "NewMap":
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if maj != cbg.MajMap {
return fmt.Errorf("expected a map (major type 5)")
}
if extra > 4096 {
return fmt.Errorf("t.NewMap: map too large")
}
t.NewMap = make(map[string]SimpleTypeOne, extra)
for i, l := 0, int(extra); i < l; i++ {
var k string
{
sval, err := cbg.ReadStringBuf(br, scratch)
if err != nil {
return err
}
k = string(sval)
}
var v SimpleTypeOne
{
if err := v.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling v: %w", err)
}
}
t.NewMap[k] = v
}
// t.OldArray ([]testing.SimpleTypeOne) (slice)
case "OldArray":
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if extra > cbg.MaxLength {
return fmt.Errorf("t.OldArray: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.OldArray = make([]SimpleTypeOne, extra)
}
for i := 0; i < int(extra); i++ {
var v SimpleTypeOne
if err := v.UnmarshalCBOR(br); err != nil {
return err
}
t.OldArray[i] = v
}
// t.NewArray ([]testing.SimpleTypeOne) (slice)
case "NewArray":
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
if err != nil {
return err
}
if extra > cbg.MaxLength {
return fmt.Errorf("t.NewArray: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.NewArray = make([]SimpleTypeOne, extra)
}
for i := 0; i < int(extra); i++ {
var v SimpleTypeOne
if err := v.UnmarshalCBOR(br); err != nil {
return err
}
t.NewArray[i] = v
}
// t.OldStruct (testing.SimpleTypeOne) (struct)
case "OldStruct":
{
if err := t.OldStruct.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.OldStruct: %w", err)
}
}
// t.NewStruct (testing.SimpleTypeOne) (struct)
case "NewStruct":
{
if err := t.NewStruct.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.NewStruct: %w", err)
}
}
default:
// Field doesn't exist on this type, so ignore it
cbg.ScanForLinks(r, func(cid.Cid) {})
}
}
......
......@@ -3,6 +3,7 @@ package testing
import (
"bytes"
"encoding/json"
"github.com/ipfs/go-cid"
"math/rand"
"reflect"
"testing"
......@@ -162,3 +163,155 @@ func TestTimeIsh(t *testing.T) {
}
}
func TestLessToMoreFieldsRoundTrip(t *testing.T) {
dummyCid, _ := cid.Parse("bafkqaaa")
simpleTypeOne := SimpleTypeOne{
Foo: "foo",
Value: 1,
Binary: []byte("bin"),
Signed: -1,
NString: "namedstr",
}
obj := &SimpleStructV1{
OldStr: "hello",
OldBytes: []byte("bytes"),
OldNum: 10,
OldPtr: &dummyCid,
OldMap: map[string]SimpleTypeOne{"first": simpleTypeOne},
OldArray: []SimpleTypeOne{simpleTypeOne},
OldStruct: simpleTypeOne,
}
buf := new(bytes.Buffer)
if err := obj.MarshalCBOR(buf); err != nil {
t.Fatal("failed marshaling", err)
}
enc := buf.Bytes()
nobj := SimpleStructV2{}
if err := nobj.UnmarshalCBOR(bytes.NewReader(enc)); err != nil {
t.Logf("got bad bytes: %x", enc)
t.Fatal("failed to round trip object: ", err)
}
if obj.OldStr != nobj.OldStr {
t.Fatal("mismatch ", obj.OldStr, " != ", nobj.OldStr)
}
if nobj.NewStr != "" {
t.Fatal("expected field to be zero value")
}
if obj.OldNum != nobj.OldNum {
t.Fatal("mismatch ", obj.OldNum, " != ", nobj.OldNum)
}
if nobj.NewNum != 0 {
t.Fatal("expected field to be zero value")
}
if !bytes.Equal(obj.OldBytes, nobj.OldBytes) {
t.Fatal("mismatch ", obj.OldBytes, " != ", nobj.OldBytes)
}
if nobj.NewBytes != nil {
t.Fatal("expected field to be zero value")
}
if *obj.OldPtr != *nobj.OldPtr {
t.Fatal("mismatch ", obj.OldPtr, " != ", nobj.OldPtr)
}
if nobj.NewPtr != nil {
t.Fatal("expected field to be zero value")
}
if !cmp.Equal(obj.OldMap, nobj.OldMap) {
t.Fatal("mismatch map marshal / unmarshal")
}
if len(nobj.NewMap) != 0 {
t.Fatal("expected field to be zero value")
}
if !cmp.Equal(obj.OldArray, nobj.OldArray) {
t.Fatal("mismatch array marshal / unmarshal")
}
if len(nobj.NewArray) != 0 {
t.Fatal("expected field to be zero value")
}
if !cmp.Equal(obj.OldStruct, nobj.OldStruct) {
t.Fatal("mismatch struct marshal / unmarshal")
}
if !cmp.Equal(nobj.NewStruct, SimpleTypeOne{}) {
t.Fatal("expected field to be zero value")
}
}
func TestMoreToLessFieldsRoundTrip(t *testing.T) {
dummyCid1, _ := cid.Parse("bafkqaaa")
dummyCid2, _ := cid.Parse("bafkqaab")
simpleType1 := SimpleTypeOne{
Foo: "foo",
Value: 1,
Binary: []byte("bin"),
Signed: -1,
NString: "namedstr",
}
simpleType2 := SimpleTypeOne{
Foo: "bar",
Value: 2,
Binary: []byte("bin2"),
Signed: -2,
NString: "namedstr2",
}
obj := &SimpleStructV2{
OldStr: "oldstr",
NewStr: "newstr",
OldBytes: []byte("oldbytes"),
NewBytes: []byte("newbytes"),
OldNum: 10,
NewNum: 11,
OldPtr: &dummyCid1,
NewPtr: &dummyCid2,
OldMap: map[string]SimpleTypeOne{"foo": simpleType1},
NewMap: map[string]SimpleTypeOne{"bar": simpleType2},
OldArray: []SimpleTypeOne{simpleType1},
NewArray: []SimpleTypeOne{simpleType1, simpleType2},
OldStruct: simpleType1,
NewStruct: simpleType2,
}
buf := new(bytes.Buffer)
if err := obj.MarshalCBOR(buf); err != nil {
t.Fatal("failed marshaling", err)
}
enc := buf.Bytes()
nobj := SimpleStructV1{}
if err := nobj.UnmarshalCBOR(bytes.NewReader(enc)); err != nil {
t.Logf("got bad bytes: %x", enc)
t.Fatal("failed to round trip object: ", err)
}
if obj.OldStr != nobj.OldStr {
t.Fatal("mismatch", obj.OldStr, " != ", nobj.OldStr)
}
if obj.OldNum != nobj.OldNum {
t.Fatal("mismatch ", obj.OldNum, " != ", nobj.OldNum)
}
if !bytes.Equal(obj.OldBytes, nobj.OldBytes) {
t.Fatal("mismatch ", obj.OldBytes, " != ", nobj.OldBytes)
}
if *obj.OldPtr != *nobj.OldPtr {
t.Fatal("mismatch ", obj.OldPtr, " != ", nobj.OldPtr)
}
if !cmp.Equal(obj.OldMap, nobj.OldMap) {
t.Fatal("mismatch map marshal / unmarshal")
}
if !cmp.Equal(obj.OldArray, nobj.OldArray) {
t.Fatal("mismatch array marshal / unmarshal")
}
if !cmp.Equal(obj.OldStruct, nobj.OldStruct) {
t.Fatal("mismatch struct marshal / unmarshal")
}
}
package testing
import (
"github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
)
......@@ -43,6 +44,39 @@ type SimpleTypeTree struct {
NotPizza *uint64
}
type SimpleStructV1 struct {
OldStr string
OldBytes []byte
OldNum uint64
OldPtr *cid.Cid
OldMap map[string]SimpleTypeOne
OldArray []SimpleTypeOne
OldStruct SimpleTypeOne
}
type SimpleStructV2 struct {
OldStr string
NewStr string
OldBytes []byte
NewBytes []byte
OldNum uint64
NewNum uint64
OldPtr *cid.Cid
NewPtr *cid.Cid
OldMap map[string]SimpleTypeOne
NewMap map[string]SimpleTypeOne
OldArray []SimpleTypeOne
NewArray []SimpleTypeOne
OldStruct SimpleTypeOne
NewStruct SimpleTypeOne
}
type DeferredContainer struct {
Stuff *SimpleTypeOne
Deferred *cbg.Deferred
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment