-
Notifications
You must be signed in to change notification settings - Fork 2
/
binary_test.go
133 lines (122 loc) · 3.67 KB
/
binary_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package connectproto
import (
"bytes"
"testing"
"time"
"go.akshayshah.org/attest"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/descriptorpb"
"google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
)
func TestBinaryUnmarshal(t *testing.T) {
codec := &binaryCodec{
name: "proto",
unmarshal: proto.UnmarshalOptions{Merge: true},
}
t.Run("merge", func(t *testing.T) {
enum := descriptorpb.EnumDescriptorProto{Name: ptr("foo")}
err := codec.Unmarshal([]byte{}, &enum)
attest.Ok(t, err)
attest.Equal(t, *enum.Name, "foo")
})
t.Run("empty input", func(t *testing.T) {
var empty emptypb.Empty
err := codec.Unmarshal([]byte{}, &empty)
attest.Ok(t, err)
})
t.Run("not protobuf", func(t *testing.T) {
err := codec.Unmarshal([]byte{}, &struct{}{})
attest.Error(t, err)
})
}
func TestBinaryMarshal(t *testing.T) {
codec := newBinaryCodec(proto.MarshalOptions{}, proto.UnmarshalOptions{})
dict, err := structpb.NewStruct(map[string]any{
"foo": "bar",
"baz": "quux",
})
attest.Ok(t, err)
t.Run("unstable", func(t *testing.T) {
out, err := codec.Marshal(dict)
attest.Ok(t, err)
roundtrip := &structpb.Struct{}
attest.Ok(t, proto.Unmarshal(out, roundtrip))
attest.Equal(t, roundtrip, dict, attest.Cmp(protocmp.Transform()))
})
t.Run("stable", func(t *testing.T) {
out, err := codec.MarshalStable(dict)
attest.Ok(t, err)
roundtrip := &structpb.Struct{}
attest.Ok(t, proto.Unmarshal(out, roundtrip))
attest.Equal(t, roundtrip, dict, attest.Cmp(protocmp.Transform()))
for i := 0; i < 100; i++ {
again, err := codec.MarshalStable(dict)
attest.Ok(t, err)
attest.True(t, bytes.Equal(out, again), attest.Sprint("MarshalStable produced unstable output"))
}
})
t.Run("append", func(t *testing.T) {
out, err := codec.MarshalAppend(make([]byte, 0, 128), dict)
attest.Ok(t, err)
roundtrip := &structpb.Struct{}
attest.Ok(t, proto.Unmarshal(out, roundtrip))
attest.Equal(t, roundtrip, dict, attest.Cmp(protocmp.Transform()))
})
t.Run("not protobuf", func(t *testing.T) {
_, err := codec.Marshal(struct{}{})
attest.Error(t, err)
_, err = codec.MarshalStable(struct{}{})
attest.Error(t, err)
})
}
func TestBinaryMetadata(t *testing.T) {
codec := newBinaryCodec(proto.MarshalOptions{}, proto.UnmarshalOptions{})
attest.Equal(t, codec.Name(), "proto")
attest.True(t, codec.IsBinary())
}
func TestVTUnmarshal(t *testing.T) {
codec := newBinaryVTCodec()
pb := timestamppb.Now()
bin, err := proto.Marshal(pb)
attest.Ok(t, err)
var vt timestampVT
attest.Ok(t, codec.Unmarshal(bin, &vt))
attest.Equal(t, vt.t, pb.AsTime())
// also ensure codec can unmarshal to non-VT structs
attest.Ok(t, codec.Unmarshal(bin, ×tamppb.Timestamp{}))
}
func TestVTMarshal(t *testing.T) {
codec := newBinaryVTCodec()
vt := ×tampVT{time.Now()}
bin, err := codec.Marshal(vt)
attest.Ok(t, err)
var pb timestamppb.Timestamp
attest.Ok(t, proto.Unmarshal(bin, &pb))
attest.Equal(t, pb.AsTime(), vt.t)
// also ensure codec can marshal non-VT structs
_, err = codec.Marshal(×tamppb.Timestamp{})
attest.Ok(t, err)
}
func TestVTMetadata(t *testing.T) {
codec := newBinaryVTCodec()
attest.Equal(t, codec.Name(), "proto")
attest.True(t, codec.IsBinary())
}
type timestampVT struct {
t time.Time
}
func (t *timestampVT) MarshalVT() ([]byte, error) {
msg := timestamppb.New(t.t)
return proto.Marshal(msg)
}
func (t *timestampVT) UnmarshalVT(binary []byte) error {
var msg timestamppb.Timestamp
if err := proto.Unmarshal(binary, &msg); err != nil {
return err
}
t.t = msg.AsTime()
return nil
}