github.com/segmentio/encoding@v0.4.0/proto/proto_test.go (about)

     1  package proto
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"math"
     7  	"os"
     8  	"reflect"
     9  	"testing"
    10  )
    11  
    12  func TestEncodeDecodeVarint(t *testing.T) {
    13  	b := [8]byte{}
    14  
    15  	n, err := encodeVarint(b[:], 42)
    16  	if err != nil {
    17  		t.Fatal(err)
    18  	}
    19  
    20  	v, n2, err := decodeVarint(b[:n])
    21  	if err != nil {
    22  		t.Fatal(err)
    23  	}
    24  	if v != 42 {
    25  		t.Errorf("decoded value mismatch: want %d, got %d", 42, v)
    26  	}
    27  	if n2 != n {
    28  		t.Errorf("decoded byte count mismatch: want %d, got %d", n, n2)
    29  	}
    30  }
    31  
    32  func TestEncodeDecodeVarintZigZag(t *testing.T) {
    33  	b := [8]byte{}
    34  
    35  	n, err := encodeVarintZigZag(b[:], -42)
    36  	if err != nil {
    37  		t.Fatal(err)
    38  	}
    39  
    40  	v, n2, err := decodeVarintZigZag(b[:n])
    41  	if err != nil {
    42  		t.Fatal(err)
    43  	}
    44  	if v != -42 {
    45  		t.Errorf("decoded value mismatch: want %d, got %d", -42, v)
    46  	}
    47  	if n2 != n {
    48  		t.Errorf("decoded byte count mismatch: want %d, got %d", n, n2)
    49  	}
    50  }
    51  
    52  func TestEncodeDecodeTag(t *testing.T) {
    53  	b := [8]byte{}
    54  
    55  	n, err := encodeTag(b[:], 1, varint)
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  
    60  	num, typ, n2, err := decodeTag(b[:n])
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  	if num != 1 {
    65  		t.Errorf("decoded field number mismatch: want %d, got %d", 1, num)
    66  	}
    67  	if typ != varint {
    68  		t.Errorf("decoded wire type mismatch: want %d, got %d", varint, typ)
    69  	}
    70  	if n2 != n {
    71  		t.Errorf("decoded byte count mismatch: want %d, got %d", n, n2)
    72  	}
    73  }
    74  
    75  type key struct {
    76  	Hi uint64
    77  	Lo uint64
    78  }
    79  
    80  type message struct {
    81  	A int
    82  	B int
    83  	C int
    84  	S submessage
    85  }
    86  
    87  type submessage struct {
    88  	X string
    89  	Y string
    90  }
    91  
    92  type structWithMap struct {
    93  	M map[int]string
    94  }
    95  
    96  type custom [16]byte
    97  
    98  func (c *custom) Size() int { return len(c) }
    99  
   100  func (c *custom) MarshalTo(b []byte) (int, error) {
   101  	return copy(b, c[:]), nil
   102  }
   103  
   104  func (c *custom) Unmarshal(b []byte) error {
   105  	copy(c[:], b)
   106  	return nil
   107  }
   108  
   109  type messageWithRawMessage struct {
   110  	Raw RawMessage
   111  }
   112  
   113  type messageWithCustomField struct {
   114  	Custom custom
   115  }
   116  
   117  func TestMarshalUnmarshal(t *testing.T) {
   118  	intVal := 42
   119  	values := []interface{}{
   120  		// bool
   121  		true,
   122  		false,
   123  
   124  		// zig-zag varint
   125  		0,
   126  		1,
   127  		1234567890,
   128  		-1,
   129  		-1234567890,
   130  
   131  		// sfixed32
   132  		int32(0),
   133  		int32(math.MinInt32),
   134  		int32(math.MaxInt32),
   135  
   136  		// sfixed64
   137  		int64(0),
   138  		int64(math.MinInt64),
   139  		int64(math.MaxInt64),
   140  
   141  		// varint
   142  		uint(0),
   143  		uint(1),
   144  		uint(1234567890),
   145  
   146  		// fixed32
   147  		uint32(0),
   148  		uint32(1234567890),
   149  
   150  		// fixed64
   151  		uint64(0),
   152  		uint64(1234567890),
   153  
   154  		// float
   155  		float32(0),
   156  		float32(math.Copysign(0, -1)),
   157  		float32(0.1234),
   158  
   159  		// double
   160  		float64(0),
   161  		float64(math.Copysign(0, -1)),
   162  		float64(0.1234),
   163  
   164  		// string
   165  		"",
   166  		"A",
   167  		"Hello World!",
   168  
   169  		// bytes
   170  		([]byte)(nil),
   171  		[]byte(""),
   172  		[]byte("A"),
   173  		[]byte("Hello World!"),
   174  
   175  		// messages
   176  		struct{ B bool }{B: false},
   177  		struct{ B bool }{B: true},
   178  
   179  		struct{ I int }{I: 0},
   180  		struct{ I int }{I: 1},
   181  
   182  		struct{ I32 int32 }{I32: 0},
   183  		struct{ I32 int32 }{I32: -1234567890},
   184  
   185  		struct{ I64 int64 }{I64: 0},
   186  		struct{ I64 int64 }{I64: -1234567890},
   187  
   188  		struct{ U int }{U: 0},
   189  		struct{ U int }{U: 1},
   190  
   191  		struct{ U32 uint32 }{U32: 0},
   192  		struct{ U32 uint32 }{U32: 1234567890},
   193  
   194  		struct{ U64 uint64 }{U64: 0},
   195  		struct{ U64 uint64 }{U64: 1234567890},
   196  
   197  		struct{ F32 float32 }{F32: 0},
   198  		struct{ F32 float32 }{F32: 0.1234},
   199  
   200  		struct{ F64 float64 }{F64: 0},
   201  		struct{ F64 float64 }{F64: 0.1234},
   202  
   203  		struct{ S string }{S: ""},
   204  		struct{ S string }{S: "E"},
   205  
   206  		struct{ B []byte }{B: nil},
   207  		struct{ B []byte }{B: []byte{}},
   208  		struct{ B []byte }{B: []byte{1, 2, 3}},
   209  
   210  		&message{
   211  			A: 1,
   212  			B: 2,
   213  			C: 3,
   214  			S: submessage{
   215  				X: "hello",
   216  				Y: "world",
   217  			},
   218  		},
   219  
   220  		struct {
   221  			Min int64 `protobuf:"zigzag64,1,opt,name=min,proto3"`
   222  			Max int64 `protobuf:"zigzag64,2,opt,name=min,proto3"`
   223  		}{Min: math.MinInt64, Max: math.MaxInt64},
   224  
   225  		// pointers
   226  		struct{ M *message }{M: nil},
   227  		struct {
   228  			M1 *message
   229  			M2 *message
   230  			M3 *message
   231  		}{
   232  			M1: &message{A: 10, B: 100, C: 1000},
   233  			M2: &message{S: submessage{X: "42"}},
   234  		},
   235  
   236  		// byte arrays
   237  		[0]byte{},
   238  		[8]byte{},
   239  		[16]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF},
   240  		&[...]byte{},
   241  		&[...]byte{3, 2, 1},
   242  
   243  		// slices (repeated)
   244  		struct{ S []int }{S: nil},
   245  		struct{ S []int }{S: []int{0}},
   246  		struct{ S []int }{S: []int{0, 0, 0}},
   247  		struct{ S []int }{S: []int{1, 2, 3}},
   248  		struct{ S []string }{S: nil},
   249  		struct{ S []string }{S: []string{""}},
   250  		struct{ S []string }{S: []string{"A", "B", "C"}},
   251  		struct{ K []key }{
   252  			K: []key{
   253  				{Hi: 0, Lo: 0},
   254  				{Hi: 0, Lo: 1},
   255  				{Hi: 0, Lo: 2},
   256  				{Hi: 0, Lo: 3},
   257  				{Hi: 0, Lo: 4},
   258  			},
   259  		},
   260  
   261  		// maps (repeated)
   262  		struct{ M map[int]string }{},
   263  		struct{ M map[int]string }{
   264  			M: map[int]string{0: ""},
   265  		},
   266  		struct{ M map[int]string }{
   267  			M: map[int]string{0: "A", 1: "B", 2: "C"},
   268  		},
   269  		&struct{ M map[int]string }{
   270  			M: map[int]string{0: "A", 1: "B", 2: "C"},
   271  		},
   272  		struct {
   273  			M1 map[int]int
   274  			M2 map[string]string
   275  			M3 map[string]message
   276  			M4 map[string]*message
   277  			M5 map[key]uint
   278  		}{
   279  			M1: map[int]int{0: 1},
   280  			M2: map[string]string{"": "A"},
   281  			M3: map[string]message{
   282  				"m0": message{},
   283  				"m1": message{A: 42},
   284  				"m3": message{S: submessage{X: "X", Y: "Y"}},
   285  			},
   286  			M4: map[string]*message{
   287  				"m0": &message{},
   288  				"m1": &message{A: 42},
   289  				"m3": &message{S: submessage{X: "X", Y: "Y"}},
   290  			},
   291  			M5: map[key]uint{
   292  				key{Hi: 0, Lo: 0}: 0,
   293  				key{Hi: 1, Lo: 0}: 1,
   294  				key{Hi: 0, Lo: 1}: 2,
   295  				key{Hi: math.MaxUint64, Lo: math.MaxUint64}: 3,
   296  			},
   297  		},
   298  
   299  		// more complex inlined types use cases
   300  		struct{ I *int }{},
   301  		struct{ I *int }{I: new(int)},
   302  		struct{ I *int }{I: &intVal},
   303  		struct{ M *message }{},
   304  		struct{ M *message }{M: new(message)},
   305  		struct{ M map[int]int }{},
   306  		struct{ M map[int]int }{M: map[int]int{}},
   307  		struct{ S structWithMap }{
   308  			S: structWithMap{
   309  				M: map[int]string{0: "A", 1: "B", 2: "C"},
   310  			},
   311  		},
   312  		&struct{ S structWithMap }{
   313  			S: structWithMap{
   314  				M: map[int]string{0: "A", 1: "B", 2: "C"},
   315  			},
   316  		},
   317  
   318  		// raw messages
   319  		RawMessage(nil),
   320  		RawMessage{0x08, 0x96, 0x01},
   321  		messageWithRawMessage{
   322  			Raw: RawMessage{1, 2, 3, 4},
   323  		},
   324  		struct {
   325  			A int
   326  			B string
   327  			C RawMessage
   328  		}{A: 42, B: "Hello World!", C: RawMessage{1, 2, 3, 4}},
   329  
   330  		// custom messages
   331  		custom{},
   332  		custom{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   333  		messageWithCustomField{
   334  			Custom: custom{1: 42},
   335  		},
   336  		struct {
   337  			A int
   338  			B string
   339  			C custom
   340  		}{A: 42, B: "Hello World!", C: custom{1: 42}},
   341  	}
   342  
   343  	for _, v := range values {
   344  		t.Run(fmt.Sprintf("%T/%+v", v, v), func(t *testing.T) {
   345  			n := Size(v)
   346  
   347  			b, err := Marshal(v)
   348  			if err != nil {
   349  				t.Fatal(err)
   350  			}
   351  			if n != len(b) {
   352  				t.Fatalf("value size and buffer length mismatch (%d != %d)", n, len(b))
   353  			}
   354  
   355  			p := reflect.New(reflect.TypeOf(v))
   356  			if err := Unmarshal(b, p.Interface()); err != nil {
   357  				t.Fatal(err)
   358  			}
   359  
   360  			x := p.Elem().Interface()
   361  			if !reflect.DeepEqual(v, x) {
   362  				t.Errorf("values mismatch:\nexpected: %#v\nfound:    %#v", v, x)
   363  			}
   364  		})
   365  	}
   366  }
   367  
   368  func loadProtobuf(t *testing.T, fileName string) RawMessage {
   369  	b, err := os.ReadFile("fixtures/protobuf/" + fileName)
   370  	if err != nil {
   371  		t.Fatal(err)
   372  	}
   373  	return RawMessage(b)
   374  }
   375  
   376  func makeVarint(v uint64) []byte {
   377  	b := [12]byte{}
   378  	n := binary.PutUvarint(b[:], v)
   379  	return b[:n]
   380  }
   381  
   382  func makeFixed32(v uint32) []byte {
   383  	b := [4]byte{}
   384  	binary.LittleEndian.PutUint32(b[:], v)
   385  	return b[:]
   386  }
   387  
   388  func makeFixed64(v uint64) []byte {
   389  	b := [8]byte{}
   390  	binary.LittleEndian.PutUint64(b[:], v)
   391  	return b[:]
   392  }