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

     1  package proto
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"testing"
     7  )
     8  
     9  type RecursiveMessage struct {
    10  	Next *RecursiveMessage `protobuf:"bytes,1,opt,name=next,proto3"`
    11  }
    12  
    13  func TestTypeOf(t *testing.T) {
    14  	tests := []struct {
    15  		value interface{}
    16  		proto string
    17  	}{
    18  		// primitive types
    19  		{value: true, proto: "bool"},
    20  		{value: int(1), proto: "int64"},
    21  		{value: int32(1), proto: "int32"},
    22  		{value: int64(1), proto: "int64"},
    23  		{value: uint(1), proto: "uint64"},
    24  		{value: uint32(1), proto: "uint32"},
    25  		{value: uint64(1), proto: "uint64"},
    26  		{value: float32(1), proto: "float"},
    27  		{value: float64(1), proto: "double"},
    28  		{value: "hello", proto: "string"},
    29  		{value: []byte("A"), proto: "bytes"},
    30  
    31  		// map types
    32  		{value: map[int]string{}, proto: "map<int64, string>"},
    33  
    34  		// struct types
    35  		{
    36  			value: struct{}{},
    37  			proto: `message {}`,
    38  		},
    39  
    40  		{
    41  			value: struct{ A int }{},
    42  			proto: `message {
    43    int64 A = 1;
    44  }`,
    45  		},
    46  
    47  		{
    48  			value: struct {
    49  				A int    `protobuf:"varint,1,opt,name=hello,proto3"`
    50  				B string `protobuf:"bytes,3,rep,name=world,proto3"`
    51  			}{},
    52  			proto: `message {
    53    int64 hello = 1;
    54    repeated string world = 3;
    55  }`,
    56  		},
    57  
    58  		{
    59  			value: RecursiveMessage{},
    60  			proto: `message RecursiveMessage {
    61    RecursiveMessage next = 1;
    62  }`,
    63  		},
    64  
    65  		{
    66  			value: struct {
    67  				M RawMessage
    68  			}{},
    69  			proto: `message {
    70    bytes M = 1;
    71  }`,
    72  		},
    73  	}
    74  
    75  	for _, test := range tests {
    76  		t.Run(fmt.Sprintf("%T", test.value), func(t *testing.T) {
    77  			typ := TypeOf(reflect.TypeOf(test.value))
    78  			str := typ.String()
    79  
    80  			if str != test.proto {
    81  				t.Error("protobuf representation mismatch")
    82  				t.Log("want:", test.proto)
    83  				t.Log("got: ", str)
    84  			}
    85  		})
    86  	}
    87  }
    88  
    89  func TestTypesAreEqual(t *testing.T) {
    90  	if TypeOf(reflect.TypeOf(true)) != TypeOf(reflect.TypeOf(false)) {
    91  		t.Error("type of true is not equal to type of false")
    92  	}
    93  }
    94  
    95  func TestTypesAreNotEqual(t *testing.T) {
    96  	if TypeOf(reflect.TypeOf(false)) == TypeOf(reflect.TypeOf(0)) {
    97  		t.Error("type of bool equal type of int")
    98  	}
    99  }
   100  
   101  func TestParseStructTag(t *testing.T) {
   102  	tests := []struct {
   103  		str string
   104  		tag structTag
   105  	}{
   106  		{
   107  			str: `bytes,1,rep,name=next,proto3`,
   108  			tag: structTag{
   109  				name:        "next",
   110  				version:     3,
   111  				wireType:    Varlen,
   112  				fieldNumber: 1,
   113  				extensions:  map[string]string{},
   114  				repeated:    true,
   115  			},
   116  		},
   117  
   118  		{
   119  			str: `bytes,5,opt,name=key,proto3`,
   120  			tag: structTag{
   121  				name:        "key",
   122  				version:     3,
   123  				wireType:    Varlen,
   124  				fieldNumber: 5,
   125  				extensions:  map[string]string{},
   126  			},
   127  		},
   128  
   129  		{
   130  			str: `fixed64,6,opt,name=seed,proto3`,
   131  			tag: structTag{
   132  				name:        "seed",
   133  				version:     3,
   134  				wireType:    Fixed64,
   135  				fieldNumber: 6,
   136  				extensions:  map[string]string{},
   137  			},
   138  		},
   139  
   140  		{
   141  			str: `varint,8,opt,name=expire_after,json=expireAfter,proto3`,
   142  			tag: structTag{
   143  				name:        "expire_after",
   144  				json:        "expireAfter",
   145  				version:     3,
   146  				wireType:    Varint,
   147  				fieldNumber: 8,
   148  				extensions:  map[string]string{},
   149  			},
   150  		},
   151  
   152  		{
   153  			str: `bytes,17,opt,name=batch_key,json=batchKey,proto3,customtype=U128`,
   154  			tag: structTag{
   155  				name:        "batch_key",
   156  				json:        "batchKey",
   157  				version:     3,
   158  				wireType:    Varlen,
   159  				fieldNumber: 17,
   160  				extensions: map[string]string{
   161  					"customtype": "U128",
   162  				},
   163  			},
   164  		},
   165  	}
   166  
   167  	for _, test := range tests {
   168  		t.Run(test.str, func(t *testing.T) {
   169  			tag, err := parseStructTag(test.str)
   170  			if err != nil {
   171  				t.Fatal(err)
   172  			}
   173  			if !reflect.DeepEqual(tag, test.tag) {
   174  				t.Errorf("struct tag mismatch\nwant: %+v\ngot: %+v", test.tag, tag)
   175  			}
   176  		})
   177  	}
   178  }