github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/golang/protobuf/proto/text_test.go (about)

     1  // Go support for Protocol Buffers - Google's data interchange format
     2  //
     3  // Copyright 2010 The Go Authors.  All rights reserved.
     4  // https://yougam/libraries/golang/protobuf
     5  //
     6  // Redistribution and use in source and binary forms, with or without
     7  // modification, are permitted provided that the following conditions are
     8  // met:
     9  //
    10  //     * Redistributions of source code must retain the above copyright
    11  // notice, this list of conditions and the following disclaimer.
    12  //     * Redistributions in binary form must reproduce the above
    13  // copyright notice, this list of conditions and the following disclaimer
    14  // in the documentation and/or other materials provided with the
    15  // distribution.
    16  //     * Neither the name of Google Inc. nor the names of its
    17  // contributors may be used to endorse or promote products derived from
    18  // this software without specific prior written permission.
    19  //
    20  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31  
    32  package proto_test
    33  
    34  import (
    35  	"bytes"
    36  	"errors"
    37  	"io/ioutil"
    38  	"math"
    39  	"strings"
    40  	"testing"
    41  
    42  	"github.com/insionng/yougam/libraries/golang/protobuf/proto"
    43  
    44  	proto3pb "github.com/insionng/yougam/libraries/golang/protobuf/proto/proto3_proto"
    45  	pb "github.com/insionng/yougam/libraries/golang/protobuf/proto/testdata"
    46  )
    47  
    48  // textMessage implements the methods that allow it to marshal and unmarshal
    49  // itself as text.
    50  type textMessage struct {
    51  }
    52  
    53  func (*textMessage) MarshalText() ([]byte, error) {
    54  	return []byte("custom"), nil
    55  }
    56  
    57  func (*textMessage) UnmarshalText(bytes []byte) error {
    58  	if string(bytes) != "custom" {
    59  		return errors.New("expected 'custom'")
    60  	}
    61  	return nil
    62  }
    63  
    64  func (*textMessage) Reset()         {}
    65  func (*textMessage) String() string { return "" }
    66  func (*textMessage) ProtoMessage()  {}
    67  
    68  func newTestMessage() *pb.MyMessage {
    69  	msg := &pb.MyMessage{
    70  		Count: proto.Int32(42),
    71  		Name:  proto.String("Dave"),
    72  		Quote: proto.String(`"I didn't want to go."`),
    73  		Pet:   []string{"bunny", "kitty", "horsey"},
    74  		Inner: &pb.InnerMessage{
    75  			Host:      proto.String("footrest.syd"),
    76  			Port:      proto.Int32(7001),
    77  			Connected: proto.Bool(true),
    78  		},
    79  		Others: []*pb.OtherMessage{
    80  			{
    81  				Key:   proto.Int64(0xdeadbeef),
    82  				Value: []byte{1, 65, 7, 12},
    83  			},
    84  			{
    85  				Weight: proto.Float32(6.022),
    86  				Inner: &pb.InnerMessage{
    87  					Host: proto.String("lesha.mtv"),
    88  					Port: proto.Int32(8002),
    89  				},
    90  			},
    91  		},
    92  		Bikeshed: pb.MyMessage_BLUE.Enum(),
    93  		Somegroup: &pb.MyMessage_SomeGroup{
    94  			GroupField: proto.Int32(8),
    95  		},
    96  		// One normally wouldn't do this.
    97  		// This is an undeclared tag 13, as a varint (wire type 0) with value 4.
    98  		XXX_unrecognized: []byte{13<<3 | 0, 4},
    99  	}
   100  	ext := &pb.Ext{
   101  		Data: proto.String("Big gobs for big rats"),
   102  	}
   103  	if err := proto.SetExtension(msg, pb.E_Ext_More, ext); err != nil {
   104  		panic(err)
   105  	}
   106  	greetings := []string{"adg", "easy", "cow"}
   107  	if err := proto.SetExtension(msg, pb.E_Greeting, greetings); err != nil {
   108  		panic(err)
   109  	}
   110  
   111  	// Add an unknown extension. We marshal a pb.Ext, and fake the ID.
   112  	b, err := proto.Marshal(&pb.Ext{Data: proto.String("3G skiing")})
   113  	if err != nil {
   114  		panic(err)
   115  	}
   116  	b = append(proto.EncodeVarint(201<<3|proto.WireBytes), b...)
   117  	proto.SetRawExtension(msg, 201, b)
   118  
   119  	// Extensions can be plain fields, too, so let's test that.
   120  	b = append(proto.EncodeVarint(202<<3|proto.WireVarint), 19)
   121  	proto.SetRawExtension(msg, 202, b)
   122  
   123  	return msg
   124  }
   125  
   126  const text = `count: 42
   127  name: "Dave"
   128  quote: "\"I didn't want to go.\""
   129  pet: "bunny"
   130  pet: "kitty"
   131  pet: "horsey"
   132  inner: <
   133    host: "footrest.syd"
   134    port: 7001
   135    connected: true
   136  >
   137  others: <
   138    key: 3735928559
   139    value: "\001A\007\014"
   140  >
   141  others: <
   142    weight: 6.022
   143    inner: <
   144      host: "lesha.mtv"
   145      port: 8002
   146    >
   147  >
   148  bikeshed: BLUE
   149  SomeGroup {
   150    group_field: 8
   151  }
   152  /* 2 unknown bytes */
   153  13: 4
   154  [testdata.Ext.more]: <
   155    data: "Big gobs for big rats"
   156  >
   157  [testdata.greeting]: "adg"
   158  [testdata.greeting]: "easy"
   159  [testdata.greeting]: "cow"
   160  /* 13 unknown bytes */
   161  201: "\t3G skiing"
   162  /* 3 unknown bytes */
   163  202: 19
   164  `
   165  
   166  func TestMarshalText(t *testing.T) {
   167  	buf := new(bytes.Buffer)
   168  	if err := proto.MarshalText(buf, newTestMessage()); err != nil {
   169  		t.Fatalf("proto.MarshalText: %v", err)
   170  	}
   171  	s := buf.String()
   172  	if s != text {
   173  		t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, text)
   174  	}
   175  }
   176  
   177  func TestMarshalTextCustomMessage(t *testing.T) {
   178  	buf := new(bytes.Buffer)
   179  	if err := proto.MarshalText(buf, &textMessage{}); err != nil {
   180  		t.Fatalf("proto.MarshalText: %v", err)
   181  	}
   182  	s := buf.String()
   183  	if s != "custom" {
   184  		t.Errorf("Got %q, expected %q", s, "custom")
   185  	}
   186  }
   187  func TestMarshalTextNil(t *testing.T) {
   188  	want := "<nil>"
   189  	tests := []proto.Message{nil, (*pb.MyMessage)(nil)}
   190  	for i, test := range tests {
   191  		buf := new(bytes.Buffer)
   192  		if err := proto.MarshalText(buf, test); err != nil {
   193  			t.Fatal(err)
   194  		}
   195  		if got := buf.String(); got != want {
   196  			t.Errorf("%d: got %q want %q", i, got, want)
   197  		}
   198  	}
   199  }
   200  
   201  func TestMarshalTextUnknownEnum(t *testing.T) {
   202  	// The Color enum only specifies values 0-2.
   203  	m := &pb.MyMessage{Bikeshed: pb.MyMessage_Color(3).Enum()}
   204  	got := m.String()
   205  	const want = `bikeshed:3 `
   206  	if got != want {
   207  		t.Errorf("\n got %q\nwant %q", got, want)
   208  	}
   209  }
   210  
   211  func TestTextOneof(t *testing.T) {
   212  	tests := []struct {
   213  		m    proto.Message
   214  		want string
   215  	}{
   216  		// zero message
   217  		{&pb.Communique{}, ``},
   218  		// scalar field
   219  		{&pb.Communique{Union: &pb.Communique_Number{4}}, `number:4`},
   220  		// message field
   221  		{&pb.Communique{Union: &pb.Communique_Msg{
   222  			&pb.Strings{StringField: proto.String("why hello!")},
   223  		}}, `msg:<string_field:"why hello!" >`},
   224  		// bad oneof (should not panic)
   225  		{&pb.Communique{Union: &pb.Communique_Msg{nil}}, `msg:/* nil */`},
   226  	}
   227  	for _, test := range tests {
   228  		got := strings.TrimSpace(test.m.String())
   229  		if got != test.want {
   230  			t.Errorf("\n got %s\nwant %s", got, test.want)
   231  		}
   232  	}
   233  }
   234  
   235  func BenchmarkMarshalTextBuffered(b *testing.B) {
   236  	buf := new(bytes.Buffer)
   237  	m := newTestMessage()
   238  	for i := 0; i < b.N; i++ {
   239  		buf.Reset()
   240  		proto.MarshalText(buf, m)
   241  	}
   242  }
   243  
   244  func BenchmarkMarshalTextUnbuffered(b *testing.B) {
   245  	w := ioutil.Discard
   246  	m := newTestMessage()
   247  	for i := 0; i < b.N; i++ {
   248  		proto.MarshalText(w, m)
   249  	}
   250  }
   251  
   252  func compact(src string) string {
   253  	// s/[ \n]+/ /g; s/ $//;
   254  	dst := make([]byte, len(src))
   255  	space, comment := false, false
   256  	j := 0
   257  	for i := 0; i < len(src); i++ {
   258  		if strings.HasPrefix(src[i:], "/*") {
   259  			comment = true
   260  			i++
   261  			continue
   262  		}
   263  		if comment && strings.HasPrefix(src[i:], "*/") {
   264  			comment = false
   265  			i++
   266  			continue
   267  		}
   268  		if comment {
   269  			continue
   270  		}
   271  		c := src[i]
   272  		if c == ' ' || c == '\n' {
   273  			space = true
   274  			continue
   275  		}
   276  		if j > 0 && (dst[j-1] == ':' || dst[j-1] == '<' || dst[j-1] == '{') {
   277  			space = false
   278  		}
   279  		if c == '{' {
   280  			space = false
   281  		}
   282  		if space {
   283  			dst[j] = ' '
   284  			j++
   285  			space = false
   286  		}
   287  		dst[j] = c
   288  		j++
   289  	}
   290  	if space {
   291  		dst[j] = ' '
   292  		j++
   293  	}
   294  	return string(dst[0:j])
   295  }
   296  
   297  var compactText = compact(text)
   298  
   299  func TestCompactText(t *testing.T) {
   300  	s := proto.CompactTextString(newTestMessage())
   301  	if s != compactText {
   302  		t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v\n===\n", s, compactText)
   303  	}
   304  }
   305  
   306  func TestStringEscaping(t *testing.T) {
   307  	testCases := []struct {
   308  		in  *pb.Strings
   309  		out string
   310  	}{
   311  		{
   312  			// Test data from C++ test (TextFormatTest.StringEscape).
   313  			// Single divergence: we don't escape apostrophes.
   314  			&pb.Strings{StringField: proto.String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and  multiple   spaces")},
   315  			"string_field: \"\\\"A string with ' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and  multiple   spaces\"\n",
   316  		},
   317  		{
   318  			// Test data from the same C++ test.
   319  			&pb.Strings{StringField: proto.String("\350\260\267\346\255\214")},
   320  			"string_field: \"\\350\\260\\267\\346\\255\\214\"\n",
   321  		},
   322  		{
   323  			// Some UTF-8.
   324  			&pb.Strings{StringField: proto.String("\x00\x01\xff\x81")},
   325  			`string_field: "\000\001\377\201"` + "\n",
   326  		},
   327  	}
   328  
   329  	for i, tc := range testCases {
   330  		var buf bytes.Buffer
   331  		if err := proto.MarshalText(&buf, tc.in); err != nil {
   332  			t.Errorf("proto.MarsalText: %v", err)
   333  			continue
   334  		}
   335  		s := buf.String()
   336  		if s != tc.out {
   337  			t.Errorf("#%d: Got:\n%s\nExpected:\n%s\n", i, s, tc.out)
   338  			continue
   339  		}
   340  
   341  		// Check round-trip.
   342  		pb := new(pb.Strings)
   343  		if err := proto.UnmarshalText(s, pb); err != nil {
   344  			t.Errorf("#%d: UnmarshalText: %v", i, err)
   345  			continue
   346  		}
   347  		if !proto.Equal(pb, tc.in) {
   348  			t.Errorf("#%d: Round-trip failed:\nstart: %v\n  end: %v", i, tc.in, pb)
   349  		}
   350  	}
   351  }
   352  
   353  // A limitedWriter accepts some output before it fails.
   354  // This is a proxy for something like a nearly-full or imminently-failing disk,
   355  // or a network connection that is about to die.
   356  type limitedWriter struct {
   357  	b     bytes.Buffer
   358  	limit int
   359  }
   360  
   361  var outOfSpace = errors.New("proto: insufficient space")
   362  
   363  func (w *limitedWriter) Write(p []byte) (n int, err error) {
   364  	var avail = w.limit - w.b.Len()
   365  	if avail <= 0 {
   366  		return 0, outOfSpace
   367  	}
   368  	if len(p) <= avail {
   369  		return w.b.Write(p)
   370  	}
   371  	n, _ = w.b.Write(p[:avail])
   372  	return n, outOfSpace
   373  }
   374  
   375  func TestMarshalTextFailing(t *testing.T) {
   376  	// Try lots of different sizes to exercise more error code-paths.
   377  	for lim := 0; lim < len(text); lim++ {
   378  		buf := new(limitedWriter)
   379  		buf.limit = lim
   380  		err := proto.MarshalText(buf, newTestMessage())
   381  		// We expect a certain error, but also some partial results in the buffer.
   382  		if err != outOfSpace {
   383  			t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", err, outOfSpace)
   384  		}
   385  		s := buf.b.String()
   386  		x := text[:buf.limit]
   387  		if s != x {
   388  			t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, x)
   389  		}
   390  	}
   391  }
   392  
   393  func TestFloats(t *testing.T) {
   394  	tests := []struct {
   395  		f    float64
   396  		want string
   397  	}{
   398  		{0, "0"},
   399  		{4.7, "4.7"},
   400  		{math.Inf(1), "inf"},
   401  		{math.Inf(-1), "-inf"},
   402  		{math.NaN(), "nan"},
   403  	}
   404  	for _, test := range tests {
   405  		msg := &pb.FloatingPoint{F: &test.f}
   406  		got := strings.TrimSpace(msg.String())
   407  		want := `f:` + test.want
   408  		if got != want {
   409  			t.Errorf("f=%f: got %q, want %q", test.f, got, want)
   410  		}
   411  	}
   412  }
   413  
   414  func TestRepeatedNilText(t *testing.T) {
   415  	m := &pb.MessageList{
   416  		Message: []*pb.MessageList_Message{
   417  			nil,
   418  			&pb.MessageList_Message{
   419  				Name: proto.String("Horse"),
   420  			},
   421  			nil,
   422  		},
   423  	}
   424  	want := `Message <nil>
   425  Message {
   426    name: "Horse"
   427  }
   428  Message <nil>
   429  `
   430  	if s := proto.MarshalTextString(m); s != want {
   431  		t.Errorf(" got: %s\nwant: %s", s, want)
   432  	}
   433  }
   434  
   435  func TestProto3Text(t *testing.T) {
   436  	tests := []struct {
   437  		m    proto.Message
   438  		want string
   439  	}{
   440  		// zero message
   441  		{&proto3pb.Message{}, ``},
   442  		// zero message except for an empty byte slice
   443  		{&proto3pb.Message{Data: []byte{}}, ``},
   444  		// trivial case
   445  		{&proto3pb.Message{Name: "Rob", HeightInCm: 175}, `name:"Rob" height_in_cm:175`},
   446  		// empty map
   447  		{&pb.MessageWithMap{}, ``},
   448  		// non-empty map; map format is the same as a repeated struct,
   449  		// and they are sorted by key (numerically for numeric keys).
   450  		{
   451  			&pb.MessageWithMap{NameMapping: map[int32]string{
   452  				-1:      "Negatory",
   453  				7:       "Lucky",
   454  				1234:    "Feist",
   455  				6345789: "Otis",
   456  			}},
   457  			`name_mapping:<key:-1 value:"Negatory" > ` +
   458  				`name_mapping:<key:7 value:"Lucky" > ` +
   459  				`name_mapping:<key:1234 value:"Feist" > ` +
   460  				`name_mapping:<key:6345789 value:"Otis" >`,
   461  		},
   462  		// map with nil value; not well-defined, but we shouldn't crash
   463  		{
   464  			&pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{7: nil}},
   465  			`msg_mapping:<key:7 >`,
   466  		},
   467  	}
   468  	for _, test := range tests {
   469  		got := strings.TrimSpace(test.m.String())
   470  		if got != test.want {
   471  			t.Errorf("\n got %s\nwant %s", got, test.want)
   472  		}
   473  	}
   474  }