other_test.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. package textpb_test
  2. import (
  3. "testing"
  4. protoV1 "github.com/golang/protobuf/proto"
  5. "github.com/golang/protobuf/v2/encoding/textpb"
  6. "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb2"
  7. "github.com/golang/protobuf/v2/proto"
  8. preg "github.com/golang/protobuf/v2/reflect/protoregistry"
  9. // The legacy package must be imported prior to use of any legacy messages.
  10. // TODO: Remove this when protoV1 registers these hooks for you.
  11. "github.com/golang/protobuf/v2/internal/impl"
  12. _ "github.com/golang/protobuf/v2/internal/legacy"
  13. "github.com/golang/protobuf/v2/internal/scalar"
  14. anypb "github.com/golang/protobuf/ptypes/any"
  15. durpb "github.com/golang/protobuf/ptypes/duration"
  16. emptypb "github.com/golang/protobuf/ptypes/empty"
  17. stpb "github.com/golang/protobuf/ptypes/struct"
  18. tspb "github.com/golang/protobuf/ptypes/timestamp"
  19. wpb "github.com/golang/protobuf/ptypes/wrappers"
  20. )
  21. func TestRoundTrip(t *testing.T) {
  22. tests := []struct {
  23. desc string
  24. resolver *preg.Types
  25. message proto.Message
  26. }{{
  27. desc: "well-known type fields set to empty messages",
  28. message: &pb2.KnownTypes{
  29. OptBool: &wpb.BoolValue{},
  30. OptInt32: &wpb.Int32Value{},
  31. OptInt64: &wpb.Int64Value{},
  32. OptUint32: &wpb.UInt32Value{},
  33. OptUint64: &wpb.UInt64Value{},
  34. OptFloat: &wpb.FloatValue{},
  35. OptDouble: &wpb.DoubleValue{},
  36. OptString: &wpb.StringValue{},
  37. OptBytes: &wpb.BytesValue{},
  38. OptDuration: &durpb.Duration{},
  39. OptTimestamp: &tspb.Timestamp{},
  40. OptStruct: &stpb.Struct{},
  41. OptList: &stpb.ListValue{},
  42. OptValue: &stpb.Value{},
  43. OptEmpty: &emptypb.Empty{},
  44. OptAny: &anypb.Any{},
  45. },
  46. }, {
  47. desc: "well-known type scalar fields",
  48. message: &pb2.KnownTypes{
  49. OptBool: &wpb.BoolValue{
  50. Value: true,
  51. },
  52. OptInt32: &wpb.Int32Value{
  53. Value: -42,
  54. },
  55. OptInt64: &wpb.Int64Value{
  56. Value: -42,
  57. },
  58. OptUint32: &wpb.UInt32Value{
  59. Value: 0xff,
  60. },
  61. OptUint64: &wpb.UInt64Value{
  62. Value: 0xffff,
  63. },
  64. OptFloat: &wpb.FloatValue{
  65. Value: 1.234,
  66. },
  67. OptDouble: &wpb.DoubleValue{
  68. Value: 1.23e308,
  69. },
  70. OptString: &wpb.StringValue{
  71. Value: "谷歌",
  72. },
  73. OptBytes: &wpb.BytesValue{
  74. Value: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
  75. },
  76. },
  77. }, {
  78. desc: "well-known type time-related fields",
  79. message: &pb2.KnownTypes{
  80. OptDuration: &durpb.Duration{
  81. Seconds: -3600,
  82. Nanos: -123,
  83. },
  84. OptTimestamp: &tspb.Timestamp{
  85. Seconds: 1257894000,
  86. Nanos: 123,
  87. },
  88. },
  89. }, {
  90. desc: "Struct field and different Value types",
  91. message: &pb2.KnownTypes{
  92. OptStruct: &stpb.Struct{
  93. Fields: map[string]*stpb.Value{
  94. "bool": &stpb.Value{
  95. Kind: &stpb.Value_BoolValue{
  96. BoolValue: true,
  97. },
  98. },
  99. "double": &stpb.Value{
  100. Kind: &stpb.Value_NumberValue{
  101. NumberValue: 3.1415,
  102. },
  103. },
  104. "null": &stpb.Value{
  105. Kind: &stpb.Value_NullValue{
  106. NullValue: stpb.NullValue_NULL_VALUE,
  107. },
  108. },
  109. "string": &stpb.Value{
  110. Kind: &stpb.Value_StringValue{
  111. StringValue: "string",
  112. },
  113. },
  114. "struct": &stpb.Value{
  115. Kind: &stpb.Value_StructValue{
  116. StructValue: &stpb.Struct{
  117. Fields: map[string]*stpb.Value{
  118. "bool": &stpb.Value{
  119. Kind: &stpb.Value_BoolValue{
  120. BoolValue: false,
  121. },
  122. },
  123. },
  124. },
  125. },
  126. },
  127. "list": &stpb.Value{
  128. Kind: &stpb.Value_ListValue{
  129. ListValue: &stpb.ListValue{
  130. Values: []*stpb.Value{
  131. {
  132. Kind: &stpb.Value_BoolValue{
  133. BoolValue: false,
  134. },
  135. },
  136. {
  137. Kind: &stpb.Value_StringValue{
  138. StringValue: "hello",
  139. },
  140. },
  141. },
  142. },
  143. },
  144. },
  145. },
  146. },
  147. },
  148. }, {
  149. desc: "Any field without registered type",
  150. resolver: preg.NewTypes(),
  151. message: func() proto.Message {
  152. m := &pb2.Nested{
  153. OptString: scalar.String("embedded inside Any"),
  154. OptNested: &pb2.Nested{
  155. OptString: scalar.String("inception"),
  156. },
  157. }
  158. // TODO: Switch to V2 marshal when ready.
  159. b, err := protoV1.Marshal(m)
  160. if err != nil {
  161. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  162. }
  163. return &pb2.KnownTypes{
  164. OptAny: &anypb.Any{
  165. TypeUrl: string(m.ProtoReflect().Type().FullName()),
  166. Value: b,
  167. },
  168. }
  169. }(),
  170. }, {
  171. desc: "Any field with registered type",
  172. resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
  173. message: func() proto.Message {
  174. m := &pb2.Nested{
  175. OptString: scalar.String("embedded inside Any"),
  176. OptNested: &pb2.Nested{
  177. OptString: scalar.String("inception"),
  178. },
  179. }
  180. // TODO: Switch to V2 marshal when ready.
  181. b, err := protoV1.Marshal(m)
  182. if err != nil {
  183. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  184. }
  185. return &pb2.KnownTypes{
  186. OptAny: &anypb.Any{
  187. TypeUrl: string(m.ProtoReflect().Type().FullName()),
  188. Value: b,
  189. },
  190. }
  191. }(),
  192. }, {
  193. desc: "Any field containing Any message",
  194. resolver: func() *preg.Types {
  195. mt1 := (&pb2.Nested{}).ProtoReflect().Type()
  196. mt2 := impl.Export{}.MessageTypeOf(&anypb.Any{})
  197. return preg.NewTypes(mt1, mt2)
  198. }(),
  199. message: func() proto.Message {
  200. m1 := &pb2.Nested{
  201. OptString: scalar.String("message inside Any of another Any field"),
  202. }
  203. // TODO: Switch to V2 marshal when ready.
  204. b1, err := protoV1.Marshal(m1)
  205. if err != nil {
  206. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  207. }
  208. m2 := &anypb.Any{
  209. TypeUrl: "pb2.Nested",
  210. Value: b1,
  211. }
  212. // TODO: Switch to V2 marshal when ready.
  213. b2, err := protoV1.Marshal(m2)
  214. if err != nil {
  215. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  216. }
  217. return &pb2.KnownTypes{
  218. OptAny: &anypb.Any{
  219. TypeUrl: "google.protobuf.Any",
  220. Value: b2,
  221. },
  222. }
  223. }(),
  224. }}
  225. for _, tt := range tests {
  226. tt := tt
  227. t.Run(tt.desc, func(t *testing.T) {
  228. t.Parallel()
  229. mo := textpb.MarshalOptions{Resolver: tt.resolver}
  230. umo := textpb.UnmarshalOptions{Resolver: tt.resolver}
  231. b, err := mo.Marshal(tt.message)
  232. if err != nil {
  233. t.Errorf("Marshal() returned error: %v\n\n", err)
  234. }
  235. gotMessage := tt.message.ProtoReflect().Type().New().Interface()
  236. err = umo.Unmarshal(gotMessage, b)
  237. if err != nil {
  238. t.Errorf("Unmarshal() returned error: %v\n\n", err)
  239. }
  240. if !protoV1.Equal(gotMessage.(protoV1.Message), tt.message.(protoV1.Message)) {
  241. t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", gotMessage, tt.message)
  242. }
  243. })
  244. }
  245. }