...

Source file src/google.golang.org/protobuf/encoding/protodelim/protodelim_test.go

Documentation: google.golang.org/protobuf/encoding/protodelim

     1  // Copyright 2022 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package protodelim_test
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"encoding/binary"
    11  	"errors"
    12  	"io"
    13  	"testing"
    14  
    15  	"github.com/google/go-cmp/cmp"
    16  	"google.golang.org/protobuf/encoding/protodelim"
    17  	"google.golang.org/protobuf/encoding/protowire"
    18  	"google.golang.org/protobuf/internal/testprotos/test3"
    19  	"google.golang.org/protobuf/testing/protocmp"
    20  )
    21  
    22  func TestRoundTrip(t *testing.T) {
    23  	msgs := []*test3.TestAllTypes{
    24  		{SingularInt32: 1},
    25  		{SingularString: "hello"},
    26  		{RepeatedDouble: []float64{1.2, 3.4}},
    27  		{
    28  			SingularNestedMessage:  &test3.TestAllTypes_NestedMessage{A: 1},
    29  			RepeatedForeignMessage: []*test3.ForeignMessage{{C: 2}, {D: 3}},
    30  		},
    31  	}
    32  
    33  	buf := &bytes.Buffer{}
    34  
    35  	// Write all messages to buf.
    36  	for _, m := range msgs {
    37  		if n, err := protodelim.MarshalTo(buf, m); err != nil {
    38  			t.Errorf("protodelim.MarshalTo(_, %v) = %d, %v", m, n, err)
    39  		}
    40  	}
    41  
    42  	for _, tc := range []struct {
    43  		name   string
    44  		reader protodelim.Reader
    45  	}{
    46  		{name: "defaultbuffer", reader: bufio.NewReader(bytes.NewBuffer(buf.Bytes()))},
    47  		{name: "smallbuffer", reader: bufio.NewReaderSize(bytes.NewBuffer(buf.Bytes()), 0)},
    48  		{name: "largebuffer", reader: bufio.NewReaderSize(bytes.NewBuffer(buf.Bytes()), 1<<20)},
    49  		{name: "notbufio", reader: notBufioReader{bufio.NewReader(bytes.NewBuffer(buf.Bytes()))}},
    50  	} {
    51  		t.Run(tc.name, func(t *testing.T) {
    52  			// Read and collect messages from buf.
    53  			var got []*test3.TestAllTypes
    54  			for {
    55  				m := &test3.TestAllTypes{}
    56  				err := protodelim.UnmarshalFrom(tc.reader, m)
    57  				if errors.Is(err, io.EOF) {
    58  					break
    59  				}
    60  				if err != nil {
    61  					t.Errorf("protodelim.UnmarshalFrom(_) = %v", err)
    62  					continue
    63  				}
    64  				got = append(got, m)
    65  			}
    66  
    67  			want := msgs
    68  			if diff := cmp.Diff(want, got, protocmp.Transform()); diff != "" {
    69  				t.Errorf("Unmarshaler collected messages: diff -want +got = %s", diff)
    70  			}
    71  		})
    72  	}
    73  }
    74  
    75  // Just a wrapper so that UnmarshalFrom doesn't recognize this as a bufio.Reader
    76  type notBufioReader struct {
    77  	*bufio.Reader
    78  }
    79  
    80  func BenchmarkUnmarshalFrom(b *testing.B) {
    81  	var manyInt32 []int32
    82  	for i := int32(0); i < 10000; i++ {
    83  		manyInt32 = append(manyInt32, i)
    84  	}
    85  	var msgs []*test3.TestAllTypes
    86  	for i := 0; i < 10; i++ {
    87  		msgs = append(msgs, &test3.TestAllTypes{RepeatedInt32: manyInt32})
    88  	}
    89  
    90  	buf := &bytes.Buffer{}
    91  
    92  	// Write all messages to buf.
    93  	for _, m := range msgs {
    94  		if n, err := protodelim.MarshalTo(buf, m); err != nil {
    95  			b.Errorf("protodelim.MarshalTo(_, %v) = %d, %v", m, n, err)
    96  		}
    97  	}
    98  	bufBytes := buf.Bytes()
    99  
   100  	type resetReader interface {
   101  		protodelim.Reader
   102  		Reset(io.Reader)
   103  	}
   104  
   105  	for _, tc := range []struct {
   106  		name   string
   107  		reader resetReader
   108  	}{
   109  		{name: "bufio1mib", reader: bufio.NewReaderSize(nil, 1<<20)},
   110  		{name: "bufio16mib", reader: bufio.NewReaderSize(nil, 1<<24)},
   111  		{name: "notbufio1mib", reader: notBufioReader{bufio.NewReaderSize(nil, 1<<20)}},
   112  		{name: "notbufio16mib", reader: notBufioReader{bufio.NewReaderSize(nil, 1<<24)}},
   113  	} {
   114  		b.Run(tc.name, func(b *testing.B) {
   115  			b.ReportAllocs()
   116  			b.ResetTimer()
   117  			for i := 0; i < b.N; i++ {
   118  				tc.reader.Reset(bytes.NewBuffer(bufBytes))
   119  				var got int
   120  				m := &test3.TestAllTypes{}
   121  				for {
   122  					err := protodelim.UnmarshalFrom(tc.reader, m)
   123  					if errors.Is(err, io.EOF) {
   124  						break
   125  					}
   126  					if err != nil {
   127  						b.Errorf("protodelim.UnmarshalFrom(_) = %v", err)
   128  						continue
   129  					}
   130  					got++
   131  				}
   132  				if got != len(msgs) {
   133  					b.Errorf("Got %v messages. Wanted %v", got, len(msgs))
   134  				}
   135  			}
   136  		})
   137  	}
   138  }
   139  
   140  func TestMaxSize(t *testing.T) {
   141  	in := &test3.TestAllTypes{SingularInt32: 1}
   142  
   143  	buf := &bytes.Buffer{}
   144  
   145  	if n, err := protodelim.MarshalTo(buf, in); err != nil {
   146  		t.Errorf("protodelim.MarshalTo(_, %v) = %d, %v", in, n, err)
   147  	}
   148  
   149  	out := &test3.TestAllTypes{}
   150  	err := protodelim.UnmarshalOptions{MaxSize: 1}.UnmarshalFrom(bufio.NewReader(buf), out)
   151  
   152  	var errSize *protodelim.SizeTooLargeError
   153  	if !errors.As(err, &errSize) {
   154  		t.Errorf("protodelim.UnmarshalOptions{MaxSize: 1}.UnmarshalFrom(_, _) = %v (%T), want %T", err, err, errSize)
   155  	}
   156  	got, want := errSize, &protodelim.SizeTooLargeError{Size: 3, MaxSize: 1}
   157  	if diff := cmp.Diff(want, got); diff != "" {
   158  		t.Errorf("protodelim.UnmarshalOptions{MaxSize: 1}.UnmarshalFrom(_, _): diff -want +got = %s", diff)
   159  	}
   160  }
   161  
   162  func TestUnmarshalFrom_UnexpectedEOF(t *testing.T) {
   163  	buf := &bytes.Buffer{}
   164  
   165  	// Write a size (42), but no subsequent message.
   166  	sb := protowire.AppendVarint(nil, 42)
   167  	if _, err := buf.Write(sb); err != nil {
   168  		t.Fatalf("buf.Write(%v) = _, %v", sb, err)
   169  	}
   170  
   171  	out := &test3.TestAllTypes{}
   172  	err := protodelim.UnmarshalFrom(bufio.NewReader(buf), out)
   173  	if got, want := err, io.ErrUnexpectedEOF; got != want {
   174  		t.Errorf("protodelim.UnmarshalFrom(size-only buf, _) = %v, want %v", got, want)
   175  	}
   176  }
   177  
   178  func TestUnmarshalFrom_PrematureHeader(t *testing.T) {
   179  	var data = []byte{128} // continuation bit set
   180  	err := protodelim.UnmarshalFrom(bytes.NewReader(data[:]), nil)
   181  	if got, want := err, io.ErrUnexpectedEOF; !errors.Is(got, want) {
   182  		t.Errorf("protodelim.UnmarshalFrom(%#v, nil) = %#v; want = %#v", data, got, want)
   183  	}
   184  }
   185  
   186  func TestUnmarshalFrom_InvalidVarint(t *testing.T) {
   187  	var data = bytes.Repeat([]byte{128}, 2*binary.MaxVarintLen64) // continuation bit set
   188  	err := protodelim.UnmarshalFrom(bytes.NewReader(data[:]), nil)
   189  	if err == nil {
   190  		t.Errorf("protodelim.UnmarshalFrom unexpectedly did not error on invalid varint")
   191  	}
   192  }
   193  

View as plain text