Unverified Commit e34a566d authored by Rod Vagg's avatar Rod Vagg

make it so

parents
package dagpb
// mirrored in JavaScript @ https://github.com/ipld/js-dag-pb/blob/master/test/test-compat.js
import (
"encoding/hex"
"encoding/json"
"testing"
)
var dataZero []byte = make([]byte, 0)
var dataSome []byte = []byte{0, 1, 2, 3, 4}
var cidBytes []byte = []byte{1, 85, 0, 5, 0, 1, 2, 3, 4}
var zeroName string = ""
var someName string = "some name"
var zeroTsize uint64 = 0
var someTsize uint64 = 1010
var largeTsize uint64 = 9007199254740991 // JavaScript Number.MAX_SAFE_INTEGER
type testCase struct {
name string
node *PBNode
expectedBytes string
expectedForm string
}
var testCases = []testCase{
{
name: "empty",
node: &PBNode{},
expectedBytes: "",
expectedForm: "{}",
},
{
name: "Data zero",
node: &PBNode{Data: dataZero},
expectedBytes: "0a00",
expectedForm: `{
"Data": ""
}`,
},
{
name: "Data some",
node: &PBNode{Data: dataSome},
expectedBytes: "0a050001020304",
expectedForm: `{
"Data": "0001020304"
}`,
},
{
name: "Links zero",
node: &PBNode{Links: make([]*PBLink, 0)},
expectedBytes: "",
expectedForm: "{}",
},
{
name: "Data some Links zero",
node: &PBNode{Data: dataSome, Links: make([]*PBLink, 0)},
expectedBytes: "0a050001020304",
expectedForm: `{
"Data": "0001020304"
}`,
},
{
name: "Links empty",
node: &PBNode{Links: []*PBLink{{}}},
expectedBytes: "1200",
expectedForm: `{
"Links": [
{}
]
}`,
},
{
name: "Data some Links empty",
node: &PBNode{Data: dataSome, Links: []*PBLink{{}}},
expectedBytes: "12000a050001020304",
expectedForm: `{
"Data": "0001020304",
"Links": [
{}
]
}`,
},
{
name: "Links Hash zero",
node: &PBNode{Links: []*PBLink{{Hash: dataZero}}},
expectedBytes: "12020a00",
expectedForm: `{
"Links": [
{
"Hash": ""
}
]
}`,
},
{
name: "Links Hash some",
node: &PBNode{Links: []*PBLink{{Hash: cidBytes}}},
expectedBytes: "120b0a09015500050001020304",
expectedForm: `{
"Links": [
{
"Hash": "015500050001020304"
}
]
}`,
},
{
name: "Links Name zero",
node: &PBNode{Links: []*PBLink{{Name: &zeroName}}},
expectedBytes: "12021200",
expectedForm: `{
"Links": [
{
"Name": ""
}
]
}`,
},
{
name: "Links Hash some Name zero",
node: &PBNode{Links: []*PBLink{{Hash: cidBytes, Name: &zeroName}}},
expectedBytes: "120d0a090155000500010203041200",
expectedForm: `{
"Links": [
{
"Hash": "015500050001020304",
"Name": ""
}
]
}`,
},
{
name: "Links Name some",
node: &PBNode{Links: []*PBLink{{Name: &someName}}},
expectedBytes: "120b1209736f6d65206e616d65",
expectedForm: `{
"Links": [
{
"Name": "some name"
}
]
}`,
},
{
name: "Links Hash some Name some",
node: &PBNode{Links: []*PBLink{{Hash: cidBytes, Name: &someName}}},
expectedBytes: "12160a090155000500010203041209736f6d65206e616d65",
expectedForm: `{
"Links": [
{
"Hash": "015500050001020304",
"Name": "some name"
}
]
}`,
},
{
name: "Links Tsize zero",
node: &PBNode{Links: []*PBLink{{Tsize: &zeroTsize}}},
expectedBytes: "12021800",
expectedForm: `{
"Links": [
{
"Tsize": 0
}
]
}`,
},
{
name: "Links Hash some Tsize zero",
node: &PBNode{Links: []*PBLink{{Hash: cidBytes, Tsize: &zeroTsize}}},
expectedBytes: "120d0a090155000500010203041800",
expectedForm: `{
"Links": [
{
"Hash": "015500050001020304",
"Tsize": 0
}
]
}`,
},
{
name: "Links Tsize some",
node: &PBNode{Links: []*PBLink{{Tsize: &someTsize}}},
expectedBytes: "120318f207",
expectedForm: `{
"Links": [
{
"Tsize": 1010
}
]
}`,
},
{
name: "Links Hash some Tsize some",
node: &PBNode{Links: []*PBLink{{Hash: cidBytes, Tsize: &largeTsize}}},
expectedBytes: "12140a0901550005000102030418ffffffffffffff0f",
expectedForm: `{
"Links": [
{
"Hash": "015500050001020304",
"Tsize": 9007199254740991
}
]
}`,
},
}
func TestCompat(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
verifyRoundTrip(t, tc)
})
}
}
func verifyRoundTrip(t *testing.T, tc testCase) {
actualBytes, actualForm, err := nodeRoundTripToString(t, tc.node)
if err != nil {
t.Fatal(err)
}
if actualBytes != tc.expectedBytes {
t.Logf(
"Expected bytes: [%v]\nGot: [%v]\n",
tc.expectedBytes,
actualBytes)
t.Error("Did not match")
}
if actualForm != tc.expectedForm {
t.Logf(
"Expected form: [%v]\nGot: [%v]\n",
tc.expectedForm,
actualForm)
t.Error("Did not match")
}
}
func nodeRoundTripToString(t *testing.T, n *PBNode) (string, string, error) {
bytes, err := n.Marshal()
if err != nil {
return "", "", err
}
t.Logf("[%v]\n", hex.EncodeToString(bytes))
rt := new(PBNode)
if err := rt.Unmarshal(bytes); err != nil {
return "", "", err
}
str, err := json.MarshalIndent(cleanPBNode(t, rt), "", "\t")
if err != nil {
return "", "", err
}
return hex.EncodeToString(bytes), string(str), nil
}
// convert a PBLink into a map for clean JSON marshalling
func cleanPBLink(t *testing.T, link *PBLink) map[string]interface{} {
if link == nil {
return nil
}
nl := make(map[string]interface{})
if link.Hash != nil {
nl["Hash"] = hex.EncodeToString(link.Hash)
}
if link.Name != nil {
nl["Name"] = link.Name
}
if link.Tsize != nil {
nl["Tsize"] = link.Tsize
}
return nl
}
// convert a PBNode into a map for clean JSON marshalling
func cleanPBNode(t *testing.T, node *PBNode) map[string]interface{} {
nn := make(map[string]interface{})
if node.Data != nil {
nn["Data"] = hex.EncodeToString(node.Data)
}
if node.Links != nil {
links := make([]map[string]interface{}, len(node.Links))
for i, l := range node.Links {
links[i] = cleanPBLink(t, l)
}
nn["Links"] = links
}
return nn
}
package dagpb
// PBLink ...
type PBLink struct {
Hash []byte
Name *string
Tsize *uint64
}
// PBNode ...
type PBNode struct {
Links []*PBLink
Data []byte
}
package dagpb
// based on the original pb codegen
import (
math_bits "math/bits"
)
// Marshal TODO
func (m *PBNode) Marshal() (data []byte, err error) {
size := m.size()
data = make([]byte, size)
i := len(data)
if m.Data != nil {
i -= len(m.Data)
copy(data[i:], m.Data)
i = encodeVarint(data, i, uint64(len(m.Data))) - 1
data[i] = 0xa
}
if len(m.Links) > 0 {
for iNdEx := len(m.Links) - 1; iNdEx >= 0; iNdEx-- {
size, err := m.Links[iNdEx].marshal(data[:i])
if err != nil {
return nil, err
}
i -= size
i = encodeVarint(data, i, uint64(size)) - 1
data[i] = 0x12
}
}
return data[:size], nil
}
func (m *PBLink) marshal(data []byte) (int, error) {
i := len(data)
if m.Tsize != nil {
i = encodeVarint(data, i, uint64(*m.Tsize)) - 1
data[i] = 0x18
}
if m.Name != nil {
i -= len(*m.Name)
copy(data[i:], *m.Name)
i = encodeVarint(data, i, uint64(len(*m.Name))) - 1
data[i] = 0x12
}
if m.Hash != nil {
i -= len(m.Hash)
copy(data[i:], m.Hash)
i = encodeVarint(data, i, uint64(len(m.Hash))) - 1
data[i] = 0xa
}
return len(data) - i, nil
}
func (m *PBLink) size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Hash != nil {
l = len(m.Hash)
n += 1 + l + sizeOfVarint(uint64(l))
}
if m.Name != nil {
l = len(*m.Name)
n += 1 + l + sizeOfVarint(uint64(l))
}
if m.Tsize != nil {
n += 1 + sizeOfVarint(uint64(*m.Tsize))
}
return n
}
func (m *PBNode) size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Data != nil {
l = len(m.Data)
n += 1 + l + sizeOfVarint(uint64(l))
}
if len(m.Links) > 0 {
for _, e := range m.Links {
l = e.size()
n += 1 + l + sizeOfVarint(uint64(l))
}
}
return n
}
func encodeVarint(data []byte, offset int, v uint64) int {
offset -= sizeOfVarint(v)
base := offset
for v >= 1<<7 {
data[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
data[offset] = uint8(v)
return base
}
func sizeOfVarint(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
package dagpb
import (
"fmt"
"io"
)
// Unmarshal TODO
func (node *PBNode) Unmarshal(data []byte) error {
var err error
var fieldNum, wireType int
l := len(data)
index := 0
for index < l {
if fieldNum, wireType, index, err = decodeKey(data, index); err != nil {
return err
}
if wireType != 2 {
return fmt.Errorf("protobuf: (PBNode) invalid wireType, expected 2, got %d", wireType)
}
if fieldNum == 1 {
if node.Data != nil {
return fmt.Errorf("protobuf: (PBNode) duplicate Data section")
}
if node.Data, index, err = decodeBytes(data, index); err != nil {
return err
}
} else if fieldNum == 2 {
if node.Data != nil {
return fmt.Errorf("protobuf: (PBNode) invalid order, found Data before Links content")
}
var chunk []byte
if chunk, index, err = decodeBytes(data, index); err != nil {
return err
}
node.Links = append(node.Links, &PBLink{})
if err := node.Links[len(node.Links)-1].unmarshal(chunk); err != nil {
return err
}
} else {
return fmt.Errorf("protobuf: (PBNode) invalid fieldNumber, expected 1 or 2, got %d", fieldNum)
}
}
if index > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (link *PBLink) unmarshal(data []byte) error {
var err error
var fieldNum, wireType int
l := len(data)
index := 0
for index < l {
if fieldNum, wireType, index, err = decodeKey(data, index); err != nil {
return err
}
if fieldNum == 1 {
if link.Hash != nil {
return fmt.Errorf("protobuf: (PBLink) duplicate Hash section")
}
if link.Name != nil {
return fmt.Errorf("protobuf: (PBLink) invalid order, found Name before Hash")
}
if link.Tsize != nil {
return fmt.Errorf("protobuf: (PBLink) invalid order, found Tsize before Hash")
}
if wireType != 2 {
return fmt.Errorf("protobuf: (PBLink) wrong wireType (%d) for Hash", wireType)
}
if link.Hash, index, err = decodeBytes(data, index); err != nil {
return err
}
} else if fieldNum == 2 {
if link.Name != nil {
return fmt.Errorf("protobuf: (PBLink) duplicate Name section")
}
if link.Tsize != nil {
return fmt.Errorf("protobuf: (PBLink) invalid order, found Tsize before Name")
}
if wireType != 2 {
return fmt.Errorf("protobuf: (PBLink) wrong wireType (%d) for Name", wireType)
}
var chunk []byte
if chunk, index, err = decodeBytes(data, index); err != nil {
return err
}
s := string(chunk)
link.Name = &s
} else if fieldNum == 3 {
if link.Tsize != nil {
return fmt.Errorf("protobuf: (PBLink) duplicate Tsize section")
}
if wireType != 0 {
return fmt.Errorf("protobuf: (PBLink) wrong wireType (%d) for Tsize", wireType)
}
var v uint64
if v, index, err = decodeVarint(data, index); err != nil {
return err
}
link.Tsize = &v
} else {
return fmt.Errorf("protobuf: (PBLink) invalid fieldNumber, expected 1, 2 or 3, got %d", fieldNum)
}
}
if index > l {
return io.ErrUnexpectedEOF
}
return nil
}
func decodeKey(data []byte, offset int) (int, int, int, error) {
var wire uint64
var err error
if wire, offset, err = decodeVarint(data, offset); err != nil {
return 0, 0, 0, err
}
fieldNum := int(wire >> 3)
wireType := int(wire & 0x7)
return fieldNum, wireType, offset, nil
}
func decodeBytes(data []byte, offset int) ([]byte, int, error) {
var bytesLen uint64
var err error
if bytesLen, offset, err = decodeVarint(data, offset); err != nil {
return nil, 0, err
}
postOffset := offset + int(bytesLen)
if postOffset > len(data) {
return nil, 0, io.ErrUnexpectedEOF
}
return data[offset:postOffset], postOffset, nil
}
func decodeVarint(data []byte, offset int) (uint64, int, error) {
var v uint64
l := len(data)
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, 0, ErrIntOverflow
}
if offset >= l {
return 0, 0, io.ErrUnexpectedEOF
}
b := data[offset]
offset++
v |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
return v, offset, nil
}
// ErrIntOverflow TODO
var ErrIntOverflow = fmt.Errorf("protobuf: varint overflow")
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