| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748 |
- package wire
- import (
- "bytes"
- "io"
- "testing"
- "github.com/stretchr/testify/assert"
- )
- // errWriter is a writer that always returns an error.
- type errWriter struct{}
- func (errWriter) Write(p []byte) (n int, err error) {
- return 0, io.EOF
- }
- func TestMarshal(t *testing.T) {
- tests := []struct {
- name string
- w io.Writer
- given any
- want []byte
- wantErr error
- }{
- {
- name: "marshal uint8",
- w: &bytes.Buffer{},
- given: struct {
- Val uint8
- }{
- Val: 100,
- },
- want: []byte{0x64},
- },
- {
- name: "marshal uint16",
- w: &bytes.Buffer{},
- given: struct {
- Val uint16
- }{
- Val: 100,
- },
- want: []byte{0x0, 0x64},
- },
- {
- name: "marshal uint32",
- w: &bytes.Buffer{},
- given: struct {
- Val uint32
- }{
- Val: 100,
- },
- want: []byte{0x0, 0x0, 0x0, 0x64},
- },
- {
- name: "marshal uint64",
- w: &bytes.Buffer{},
- given: struct {
- Val uint64
- }{
- Val: 100,
- },
- want: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x64},
- },
- {
- name: "unsupported type",
- w: &bytes.Buffer{},
- given: struct {
- Val int16
- }{
- Val: 100,
- },
- wantErr: ErrMarshalFailure,
- },
- {
- name: "string8",
- w: &bytes.Buffer{},
- given: struct {
- Val string `oscar:"len_prefix=uint8"`
- }{
- Val: "test-value",
- },
- want: append(
- []byte{0xa}, /* len prefix */
- []byte{0x74, 0x65, 0x73, 0x74, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65}...), /* str val */
- },
- {
- name: "string8 write error",
- w: errWriter{},
- given: struct {
- Val string `oscar:"len_prefix=uint8"`
- }{
- Val: "test-value",
- },
- wantErr: io.EOF,
- },
- {
- name: "string16",
- w: &bytes.Buffer{},
- given: struct {
- Val string `oscar:"len_prefix=uint16"`
- }{
- Val: "test-value",
- },
- want: append(
- []byte{0x0, 0xa}, /* len prefix */
- []byte{0x74, 0x65, 0x73, 0x74, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65}...), /* str val */
- },
- {
- name: "null-terminated string16",
- w: &bytes.Buffer{},
- given: struct {
- Val string `oscar:"len_prefix=uint16,nullterm"`
- }{
- Val: "test-value",
- },
- want: append(
- []byte{0x0, 0xb}, /* len prefix */
- []byte{0x74, 0x65, 0x73, 0x74, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00}...), /* str val */
- },
- {
- name: "null-terminated string16 with len 0",
- w: &bytes.Buffer{},
- given: struct {
- Val string `oscar:"len_prefix=uint16,nullterm"`
- }{
- Val: "",
- },
- want: []byte{0x0, 0x0}, /* len prefix */
- },
- {
- name: "string16 write error",
- w: errWriter{},
- given: struct {
- Val string `oscar:"len_prefix=uint16"`
- }{
- Val: "test-value",
- },
- wantErr: io.EOF,
- },
- {
- name: "string with unknown prefix type",
- w: &bytes.Buffer{},
- given: struct {
- Val string `oscar:"len_prefix=uint128"`
- }{
- Val: "test-value",
- },
- wantErr: ErrMarshalFailure,
- },
- {
- name: "byte slice with no prefix",
- w: &bytes.Buffer{},
- given: struct {
- Val []byte
- }{
- Val: []byte(`hello`),
- },
- want: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f},
- },
- {
- name: "byte slice with no prefix with write error",
- w: &bytes.Buffer{},
- given: struct {
- Val []int
- }{
- Val: []int{1, 2, 3, 4},
- },
- wantErr: ErrMarshalFailure,
- },
- {
- name: "byte slice with no prefix with write error",
- w: errWriter{},
- given: struct {
- Val []byte
- }{
- Val: []byte(`hello`),
- },
- wantErr: io.EOF,
- },
- {
- name: "empty byte slice",
- w: &bytes.Buffer{},
- given: struct {
- Val []byte
- }{
- Val: []byte{},
- },
- want: []byte(nil),
- },
- {
- name: "byte slice with uint8 len_prefix",
- w: &bytes.Buffer{},
- given: struct {
- Val []byte `oscar:"len_prefix=uint8"`
- }{
- Val: []byte(`hello`),
- },
- want: append(
- []byte{0x05}, /* len prefix */
- []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f}...), /* slice val */
- },
- {
- name: "byte slice with uint8 len_prefix with error",
- w: errWriter{},
- given: struct {
- Val []byte `oscar:"len_prefix=uint8"`
- }{
- Val: []byte(`hello`),
- },
- wantErr: io.EOF,
- },
- {
- name: "byte slice with uint16 len_prefix",
- w: &bytes.Buffer{},
- given: struct {
- Val []byte `oscar:"len_prefix=uint16"`
- }{
- Val: []byte(`hello`),
- },
- want: append(
- []byte{0x00, 0x05}, /* len prefix */
- []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f}...), /* slice val */
- },
- {
- name: "byte slice with uint16 len_prefix with error",
- w: errWriter{},
- given: struct {
- Val []byte `oscar:"len_prefix=uint16"`
- }{
- Val: []byte(`hello`),
- },
- wantErr: io.EOF,
- },
- {
- name: "empty struct slice",
- w: &bytes.Buffer{},
- given: struct {
- Val []TLV
- }{
- Val: []TLV{},
- },
- want: []byte(nil),
- },
- {
- name: "struct slice with invalid type in struct",
- w: &bytes.Buffer{},
- given: struct {
- Val []struct {
- Val int16
- }
- }{
- Val: []struct {
- Val int16
- }{
- {
- Val: 1234,
- },
- },
- },
- wantErr: ErrMarshalFailure,
- },
- {
- name: "struct slice with uint8 count_prefix",
- w: &bytes.Buffer{},
- given: struct {
- Val []TLV `oscar:"count_prefix=uint8"`
- }{
- Val: []TLV{
- NewTLVBE(10, uint16(1234)),
- NewTLVBE(20, uint16(1234)),
- },
- },
- want: append(
- []byte{0x02}, /* count prefix */
- []byte{0x0, 0xa, 0x0, 0x2, 0x4, 0xd2, 0x0, 0x14, 0x0, 0x2, 0x4, 0xd2}...), /* slice val */
- },
- {
- name: "struct slice with uint8 count_prefix with error",
- w: errWriter{},
- given: struct {
- Val []TLV `oscar:"count_prefix=uint8"`
- }{
- Val: []TLV{
- NewTLVBE(10, uint16(1234)),
- },
- },
- wantErr: io.EOF,
- },
- {
- name: "struct slice with uint16 count_prefix",
- w: &bytes.Buffer{},
- given: struct {
- Val []TLV `oscar:"count_prefix=uint16"`
- }{
- Val: []TLV{
- NewTLVBE(10, uint16(1234)),
- NewTLVBE(20, uint16(1234)),
- },
- },
- want: append(
- []byte{0x00, 0x02}, /* count prefix */
- []byte{0x0, 0xa, 0x0, 0x2, 0x4, 0xd2, 0x0, 0x14, 0x0, 0x2, 0x4, 0xd2}...), /* slice val */
- },
- {
- name: "struct slice with uint16 count_prefix with error",
- w: errWriter{},
- given: struct {
- Val []TLV `oscar:"count_prefix=uint16"`
- }{
- Val: []TLV{
- NewTLVBE(10, uint16(1234)),
- },
- },
- wantErr: io.EOF,
- },
- {
- name: "byte slice with uint16 len_prefix and uint16 count_prefix",
- w: &bytes.Buffer{},
- given: struct {
- Val []byte `oscar:"len_prefix=uint16,count_prefix=uint16"`
- }{
- Val: []byte(`hello`),
- },
- wantErr: ErrMarshalFailure,
- },
- {
- name: "byte slice with unknown len_prefix type",
- w: &bytes.Buffer{},
- given: struct {
- Val []byte `oscar:"len_prefix=uint128"`
- }{
- Val: []byte(`hello`),
- },
- wantErr: ErrMarshalFailure,
- },
- {
- name: "byte slice with unknown count_prefix type",
- w: &bytes.Buffer{},
- given: struct {
- Val []byte `oscar:"count_prefix=uint128"`
- }{
- Val: []byte(`hello`),
- },
- wantErr: errInvalidStructTag,
- },
- {
- name: "empty snac",
- w: &bytes.Buffer{},
- given: nil,
- wantErr: errMarshalFailureNilSNAC,
- },
- {
- name: "struct with uint8 len_prefix",
- w: &bytes.Buffer{},
- given: struct {
- Val0 uint8
- Val1 struct {
- Val2 uint16
- Val3 uint8
- } `oscar:"len_prefix=uint8"`
- Val4 uint16
- }{
- Val0: 34,
- Val1: struct {
- Val2 uint16
- Val3 uint8
- }{
- Val2: 16,
- Val3: 10,
- },
- Val4: 32,
- },
- want: []byte{
- 0x22, // Val0
- 0x03, // Val1 struct len
- 0x00, 0x10, // Val2
- 0x0A, // Val3
- 0x00, 0x20, // Val2
- },
- },
- {
- name: "struct with uint16 len_prefix",
- w: &bytes.Buffer{},
- given: struct {
- Val0 uint8
- Val1 struct {
- Val2 uint16
- Val3 uint8
- } `oscar:"len_prefix=uint16"`
- Val4 uint16
- }{
- Val0: 34,
- Val1: struct {
- Val2 uint16
- Val3 uint8
- }{
- Val2: 16,
- Val3: 10,
- },
- Val4: 32,
- },
- want: []byte{
- 0x22, // Val0
- 0x00, 0x03, // Val1 struct len
- 0x00, 0x10, // Val2
- 0x0A, // Val3
- 0x00, 0x20, // Val2
- },
- },
- {
- name: "invalid struct with uint16 len_prefix",
- w: &bytes.Buffer{},
- given: struct {
- Val1 struct {
- Val2 int
- } `oscar:"len_prefix=uint16"`
- }{
- Val1: struct {
- Val2 int
- }{
- Val2: 16,
- },
- },
- wantErr: ErrMarshalFailure,
- },
- {
- name: "empty struct with uint16 len_prefix",
- w: &bytes.Buffer{},
- given: struct {
- Val1 struct {
- } `oscar:"len_prefix=uint16"`
- }{
- Val1: struct {
- }{},
- },
- want: []byte{
- 0x00, 0x00, // 0-len
- },
- },
- {
- name: "struct with unknown len_prefix",
- w: &bytes.Buffer{},
- given: struct {
- Val1 struct {
- Val2 uint16
- } `oscar:"len_prefix=uint128"`
- }{
- Val1: struct {
- Val2 uint16
- }{
- Val2: 16,
- },
- },
- wantErr: errInvalidStructTag,
- },
- {
- name: "optional struct has value",
- w: &bytes.Buffer{},
- given: struct {
- Val0 uint16
- Optional *struct {
- Val1 uint16
- } `oscar:"optional"`
- }{
- Val0: 34,
- Optional: &struct {
- Val1 uint16
- }{
- Val1: 100,
- },
- },
- want: []byte{
- 0x00, 0x22, // Val0
- 0x00, 0x64, // Val1
- },
- },
- {
- name: "optional struct with value missing `optional` struct tag",
- w: &bytes.Buffer{},
- given: struct {
- Val0 uint16
- Optional *struct {
- Val1 uint16
- }
- }{
- Val0: 34,
- Optional: &struct {
- Val1 uint16
- }{
- Val1: 100,
- },
- },
- wantErr: errNonOptionalPointer,
- },
- {
- name: "optional struct doesn't have value",
- w: &bytes.Buffer{},
- given: struct {
- Val0 uint16
- Optional *struct {
- Val1 uint16
- } `oscar:"optional"`
- }{
- Val0: 34,
- Optional: nil,
- },
- want: []byte{
- 0x00, 0x22, // Val0
- },
- },
- {
- name: "optional struct not last field throws error",
- w: &bytes.Buffer{},
- given: struct {
- Optional *struct {
- Val1 uint16
- } `oscar:"optional"`
- Val0 uint16
- }{
- Optional: nil,
- Val0: 34,
- },
- wantErr: ErrMarshalFailure,
- },
- {
- name: "optional non-pointer struct field throws error",
- w: &bytes.Buffer{},
- given: struct {
- Optional *string `oscar:"optional"`
- }{
- Optional: func() *string {
- v := "blahblah"
- return &v
- }(),
- },
- wantErr: ErrMarshalFailure,
- },
- {
- name: "non-struct pointer value throws error",
- w: &bytes.Buffer{},
- given: func() *string {
- v := "blahblah"
- return &v
- }(),
- wantErr: ErrMarshalFailure,
- },
- {
- name: "optional struct with uint16 len_prefix and value",
- w: &bytes.Buffer{},
- given: struct {
- Val0 uint16
- Optional *struct {
- Val1 uint16
- } `oscar:"len_prefix=uint16,optional"`
- }{
- Val0: 34,
- Optional: &struct {
- Val1 uint16
- }{
- Val1: 100,
- },
- },
- want: []byte{
- 0x00, 0x22, // Val0
- 0x00, 0x02, // Val0
- 0x00, 0x64, // Val1
- },
- },
- {
- name: "optional struct with uint16 len_prefix and no value",
- w: &bytes.Buffer{},
- given: struct {
- Val0 uint16
- Optional *struct {
- Val1 uint16
- } `oscar:"len_prefix=uint16,optional"`
- }{
- Val0: 34,
- Optional: nil,
- },
- want: []byte{
- 0x00, 0x22, // Val0
- },
- },
- {
- name: "optional field that isn't a pointer is unsupported",
- w: &bytes.Buffer{},
- given: struct {
- Val0 uint16
- Optional struct {
- Val1 uint16
- } `oscar:"len_prefix=uint16,optional"`
- }{
- Val0: 34,
- Optional: struct {
- Val1 uint16
- }{
- Val1: 100,
- },
- },
- wantErr: errOptionalNonPointer,
- },
- {
- name: "optional field that isn't a pointer to a struct is unsupported",
- w: &bytes.Buffer{},
- given: struct {
- Optional *string `oscar:"len_prefix=uint16,optional"`
- }{
- Optional: func() *string {
- v := "blahblah"
- return &v
- }(),
- },
- wantErr: ErrMarshalFailure,
- },
- {
- name: "struct with any type field containing a struct",
- w: &bytes.Buffer{},
- given: struct {
- Val1 uint8
- Val2 any
- }{
- Val1: 0x12,
- Val2: struct {
- Field1 uint16
- Field2 uint8
- }{
- Field1: 0x1234,
- Field2: 0x56,
- },
- },
- want: []byte{
- 0x12, // Val1
- 0x12, 0x34, // Val2.Field1 (uint16)
- 0x56, // Val2.Field2 (uint8)
- },
- },
- {
- name: "struct with any type field containing an empty struct",
- w: &bytes.Buffer{},
- given: struct {
- Val1 uint8
- Val2 any
- }{
- Val1: 0x12,
- Val2: struct{}{}, // empty struct
- },
- want: []byte{
- 0x12, // Val1
- },
- },
- {
- name: "struct with any type field containing a non-struct value",
- w: &bytes.Buffer{},
- given: struct {
- Val1 uint8
- Val2 any
- }{
- Val1: 0x12,
- Val2: "non-struct value", // non-struct value
- },
- wantErr: ErrMarshalFailure, // expecting an error because Val2 is not a struct
- },
- {
- name: "struct with ICQMessageReplyEnvelope field",
- w: &bytes.Buffer{},
- given: struct {
- Val1 uint16
- Val2 ICQMessageReplyEnvelope
- }{
- Val1: 0x1234,
- Val2: ICQMessageReplyEnvelope{
- Message: struct {
- Val3 uint16
- }{
- Val3: 0x1234,
- },
- },
- },
- want: []byte{
- // Big-endian encoding for Val1
- 0x12, 0x34, // Val1
- // Little-endian encoding for Val2.Message.Val3
- 0x2, 0x0, // Val2 len
- 0x34, 0x12, // Val2.Message.Val3
- },
- },
- {
- name: "byte array",
- w: &bytes.Buffer{},
- given: struct {
- Val [5]byte
- }{
- Val: [5]byte{'h', 'e', 'l', 'l', 'o'},
- },
- want: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f},
- },
- {
- name: "byte array with error",
- w: errWriter{},
- given: struct {
- Val [5]byte
- }{
- Val: [5]byte{'h', 'e', 'l', 'l', 'o'},
- },
- wantErr: io.EOF,
- },
- {
- name: "struct array",
- w: &bytes.Buffer{},
- given: struct {
- Val [2]TLV
- }{
- Val: [2]TLV{
- NewTLVBE(10, uint16(1234)),
- NewTLVBE(20, uint16(1234)),
- },
- },
- want: []byte{0x0, 0xa, 0x0, 0x2, 0x4, 0xd2, 0x0, 0x14, 0x0, 0x2, 0x4, 0xd2},
- },
- {
- name: "struct array with error",
- w: errWriter{},
- given: struct {
- Val [2]TLV
- }{
- Val: [2]TLV{
- NewTLVBE(10, uint16(1234)),
- NewTLVBE(20, uint16(1234)),
- },
- },
- wantErr: io.EOF,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- err := MarshalBE(tt.given, tt.w)
- assert.ErrorIs(t, err, tt.wantErr)
- if tt.wantErr == nil {
- if w, ok := tt.w.(*bytes.Buffer); ok {
- assert.Equal(t, tt.want, w.Bytes())
- }
- }
- })
- }
- }
|