clone_test.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. // Copyright 2011 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. package proto_test
  5. import (
  6. "testing"
  7. "github.com/golang/protobuf/proto"
  8. proto3pb "github.com/golang/protobuf/proto/proto3_proto"
  9. pb "github.com/golang/protobuf/proto/test_proto"
  10. )
  11. var cloneTestMessage = &pb.MyMessage{
  12. Count: proto.Int32(42),
  13. Name: proto.String("Dave"),
  14. Pet: []string{"bunny", "kitty", "horsey"},
  15. Inner: &pb.InnerMessage{
  16. Host: proto.String("niles"),
  17. Port: proto.Int32(9099),
  18. Connected: proto.Bool(true),
  19. },
  20. Others: []*pb.OtherMessage{
  21. {
  22. Value: []byte("some bytes"),
  23. },
  24. },
  25. Somegroup: &pb.MyMessage_SomeGroup{
  26. GroupField: proto.Int32(6),
  27. },
  28. RepBytes: [][]byte{[]byte("sham"), []byte("wow")},
  29. }
  30. func init() {
  31. ext := &pb.Ext{
  32. Data: proto.String("extension"),
  33. }
  34. if err := proto.SetExtension(cloneTestMessage, pb.E_Ext_More, ext); err != nil {
  35. panic("SetExtension: " + err.Error())
  36. }
  37. if err := proto.SetExtension(cloneTestMessage, pb.E_Ext_Text, proto.String("hello")); err != nil {
  38. panic("SetExtension: " + err.Error())
  39. }
  40. if err := proto.SetExtension(cloneTestMessage, pb.E_Greeting, []string{"one", "two"}); err != nil {
  41. panic("SetExtension: " + err.Error())
  42. }
  43. }
  44. func TestClone(t *testing.T) {
  45. // Create a clone using a marshal/unmarshal roundtrip.
  46. vanilla := new(pb.MyMessage)
  47. b, err := proto.Marshal(cloneTestMessage)
  48. if err != nil {
  49. t.Errorf("unexpected Marshal error: %v", err)
  50. }
  51. if err := proto.Unmarshal(b, vanilla); err != nil {
  52. t.Errorf("unexpected Unarshal error: %v", err)
  53. }
  54. // Create a clone using Clone and verify that it is equal to the original.
  55. m := proto.Clone(cloneTestMessage).(*pb.MyMessage)
  56. if !proto.Equal(m, cloneTestMessage) {
  57. t.Fatalf("Clone(%v) = %v", cloneTestMessage, m)
  58. }
  59. // Mutate the clone, which should not affect the original.
  60. x1, err := proto.GetExtension(m, pb.E_Ext_More)
  61. if err != nil {
  62. t.Errorf("unexpected GetExtension(%v) error: %v", pb.E_Ext_More.Name, err)
  63. }
  64. x2, err := proto.GetExtension(m, pb.E_Ext_Text)
  65. if err != nil {
  66. t.Errorf("unexpected GetExtension(%v) error: %v", pb.E_Ext_Text.Name, err)
  67. }
  68. x3, err := proto.GetExtension(m, pb.E_Greeting)
  69. if err != nil {
  70. t.Errorf("unexpected GetExtension(%v) error: %v", pb.E_Greeting.Name, err)
  71. }
  72. *m.Inner.Port++
  73. *(x1.(*pb.Ext)).Data = "blah blah"
  74. *(x2.(*string)) = "goodbye"
  75. x3.([]string)[0] = "zero"
  76. if !proto.Equal(cloneTestMessage, vanilla) {
  77. t.Fatalf("mutation on original detected:\ngot %v\nwant %v", cloneTestMessage, vanilla)
  78. }
  79. }
  80. func TestCloneNil(t *testing.T) {
  81. var m *pb.MyMessage
  82. if c := proto.Clone(m); !proto.Equal(m, c) {
  83. t.Errorf("Clone(%v) = %v", m, c)
  84. }
  85. }
  86. var mergeTests = []struct {
  87. src, dst, want proto.Message
  88. }{
  89. {
  90. src: &pb.MyMessage{
  91. Count: proto.Int32(42),
  92. },
  93. dst: &pb.MyMessage{
  94. Name: proto.String("Dave"),
  95. },
  96. want: &pb.MyMessage{
  97. Count: proto.Int32(42),
  98. Name: proto.String("Dave"),
  99. },
  100. },
  101. {
  102. src: &pb.MyMessage{
  103. Inner: &pb.InnerMessage{
  104. Host: proto.String("hey"),
  105. Connected: proto.Bool(true),
  106. },
  107. Pet: []string{"horsey"},
  108. Others: []*pb.OtherMessage{
  109. {
  110. Value: []byte("some bytes"),
  111. },
  112. },
  113. },
  114. dst: &pb.MyMessage{
  115. Inner: &pb.InnerMessage{
  116. Host: proto.String("niles"),
  117. Port: proto.Int32(9099),
  118. },
  119. Pet: []string{"bunny", "kitty"},
  120. Others: []*pb.OtherMessage{
  121. {
  122. Key: proto.Int64(31415926535),
  123. },
  124. {
  125. // Explicitly test a src=nil field
  126. Inner: nil,
  127. },
  128. },
  129. },
  130. want: &pb.MyMessage{
  131. Inner: &pb.InnerMessage{
  132. Host: proto.String("hey"),
  133. Connected: proto.Bool(true),
  134. Port: proto.Int32(9099),
  135. },
  136. Pet: []string{"bunny", "kitty", "horsey"},
  137. Others: []*pb.OtherMessage{
  138. {
  139. Key: proto.Int64(31415926535),
  140. },
  141. {},
  142. {
  143. Value: []byte("some bytes"),
  144. },
  145. },
  146. },
  147. },
  148. {
  149. src: &pb.MyMessage{
  150. RepBytes: [][]byte{[]byte("wow")},
  151. },
  152. dst: &pb.MyMessage{
  153. Somegroup: &pb.MyMessage_SomeGroup{
  154. GroupField: proto.Int32(6),
  155. },
  156. RepBytes: [][]byte{[]byte("sham")},
  157. },
  158. want: &pb.MyMessage{
  159. Somegroup: &pb.MyMessage_SomeGroup{
  160. GroupField: proto.Int32(6),
  161. },
  162. RepBytes: [][]byte{[]byte("sham"), []byte("wow")},
  163. },
  164. },
  165. // Check that a scalar bytes field replaces rather than appends.
  166. {
  167. src: &pb.OtherMessage{Value: []byte("foo")},
  168. dst: &pb.OtherMessage{Value: []byte("bar")},
  169. want: &pb.OtherMessage{Value: []byte("foo")},
  170. },
  171. {
  172. src: &pb.MessageWithMap{
  173. NameMapping: map[int32]string{6: "Nigel"},
  174. MsgMapping: map[int64]*pb.FloatingPoint{
  175. 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)},
  176. 0x4002: &pb.FloatingPoint{
  177. F: proto.Float64(2.0),
  178. },
  179. },
  180. ByteMapping: map[bool][]byte{true: []byte("wowsa")},
  181. },
  182. dst: &pb.MessageWithMap{
  183. NameMapping: map[int32]string{
  184. 6: "Bruce", // should be overwritten
  185. 7: "Andrew",
  186. },
  187. MsgMapping: map[int64]*pb.FloatingPoint{
  188. 0x4002: &pb.FloatingPoint{
  189. F: proto.Float64(3.0),
  190. Exact: proto.Bool(true),
  191. }, // the entire message should be overwritten
  192. },
  193. },
  194. want: &pb.MessageWithMap{
  195. NameMapping: map[int32]string{
  196. 6: "Nigel",
  197. 7: "Andrew",
  198. },
  199. MsgMapping: map[int64]*pb.FloatingPoint{
  200. 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)},
  201. 0x4002: &pb.FloatingPoint{
  202. F: proto.Float64(2.0),
  203. },
  204. },
  205. ByteMapping: map[bool][]byte{true: []byte("wowsa")},
  206. },
  207. },
  208. // proto3 shouldn't merge zero values,
  209. // in the same way that proto2 shouldn't merge nils.
  210. {
  211. src: &proto3pb.Message{
  212. Name: "Aaron",
  213. Data: []byte(""), // zero value, but not nil
  214. },
  215. dst: &proto3pb.Message{
  216. HeightInCm: 176,
  217. Data: []byte("texas!"),
  218. },
  219. want: &proto3pb.Message{
  220. Name: "Aaron",
  221. HeightInCm: 176,
  222. Data: []byte("texas!"),
  223. },
  224. },
  225. { // Oneof fields should merge by assignment.
  226. src: &pb.Communique{Union: &pb.Communique_Number{41}},
  227. dst: &pb.Communique{Union: &pb.Communique_Name{"Bobby Tables"}},
  228. want: &pb.Communique{Union: &pb.Communique_Number{41}},
  229. },
  230. { // Oneof nil is the same as not set.
  231. src: &pb.Communique{},
  232. dst: &pb.Communique{Union: &pb.Communique_Name{"Bobby Tables"}},
  233. want: &pb.Communique{Union: &pb.Communique_Name{"Bobby Tables"}},
  234. },
  235. {
  236. src: &pb.Communique{Union: &pb.Communique_Number{1337}},
  237. dst: &pb.Communique{},
  238. want: &pb.Communique{Union: &pb.Communique_Number{1337}},
  239. },
  240. {
  241. src: &pb.Communique{Union: &pb.Communique_Col{pb.MyMessage_RED}},
  242. dst: &pb.Communique{},
  243. want: &pb.Communique{Union: &pb.Communique_Col{pb.MyMessage_RED}},
  244. },
  245. {
  246. src: &pb.Communique{Union: &pb.Communique_Data{[]byte("hello")}},
  247. dst: &pb.Communique{},
  248. want: &pb.Communique{Union: &pb.Communique_Data{[]byte("hello")}},
  249. },
  250. {
  251. src: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{BytesField: []byte{1, 2, 3}}}},
  252. dst: &pb.Communique{},
  253. want: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{BytesField: []byte{1, 2, 3}}}},
  254. },
  255. {
  256. src: &pb.Communique{Union: &pb.Communique_Msg{}},
  257. dst: &pb.Communique{},
  258. want: &pb.Communique{Union: &pb.Communique_Msg{}},
  259. },
  260. {
  261. src: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{StringField: proto.String("123")}}},
  262. dst: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{BytesField: []byte{1, 2, 3}}}},
  263. want: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{StringField: proto.String("123"), BytesField: []byte{1, 2, 3}}}},
  264. },
  265. {
  266. src: &proto3pb.Message{
  267. Terrain: map[string]*proto3pb.Nested{
  268. "kay_a": &proto3pb.Nested{Cute: true}, // replace
  269. "kay_b": &proto3pb.Nested{Bunny: "rabbit"}, // insert
  270. },
  271. },
  272. dst: &proto3pb.Message{
  273. Terrain: map[string]*proto3pb.Nested{
  274. "kay_a": &proto3pb.Nested{Bunny: "lost"}, // replaced
  275. "kay_c": &proto3pb.Nested{Bunny: "bunny"}, // keep
  276. },
  277. },
  278. want: &proto3pb.Message{
  279. Terrain: map[string]*proto3pb.Nested{
  280. "kay_a": &proto3pb.Nested{Cute: true},
  281. "kay_b": &proto3pb.Nested{Bunny: "rabbit"},
  282. "kay_c": &proto3pb.Nested{Bunny: "bunny"},
  283. },
  284. },
  285. },
  286. {
  287. src: &pb.GoTest{
  288. F_BoolRepeated: []bool{},
  289. F_Int32Repeated: []int32{},
  290. F_Int64Repeated: []int64{},
  291. F_Uint32Repeated: []uint32{},
  292. F_Uint64Repeated: []uint64{},
  293. F_FloatRepeated: []float32{},
  294. F_DoubleRepeated: []float64{},
  295. F_StringRepeated: []string{},
  296. F_BytesRepeated: [][]byte{},
  297. },
  298. dst: &pb.GoTest{},
  299. want: &pb.GoTest{
  300. F_BoolRepeated: []bool{},
  301. F_Int32Repeated: []int32{},
  302. F_Int64Repeated: []int64{},
  303. F_Uint32Repeated: []uint32{},
  304. F_Uint64Repeated: []uint64{},
  305. F_FloatRepeated: []float32{},
  306. F_DoubleRepeated: []float64{},
  307. F_StringRepeated: []string{},
  308. F_BytesRepeated: [][]byte{},
  309. },
  310. },
  311. {
  312. src: &pb.GoTest{},
  313. dst: &pb.GoTest{
  314. F_BoolRepeated: []bool{},
  315. F_Int32Repeated: []int32{},
  316. F_Int64Repeated: []int64{},
  317. F_Uint32Repeated: []uint32{},
  318. F_Uint64Repeated: []uint64{},
  319. F_FloatRepeated: []float32{},
  320. F_DoubleRepeated: []float64{},
  321. F_StringRepeated: []string{},
  322. F_BytesRepeated: [][]byte{},
  323. },
  324. want: &pb.GoTest{
  325. F_BoolRepeated: []bool{},
  326. F_Int32Repeated: []int32{},
  327. F_Int64Repeated: []int64{},
  328. F_Uint32Repeated: []uint32{},
  329. F_Uint64Repeated: []uint64{},
  330. F_FloatRepeated: []float32{},
  331. F_DoubleRepeated: []float64{},
  332. F_StringRepeated: []string{},
  333. F_BytesRepeated: [][]byte{},
  334. },
  335. },
  336. {
  337. src: &pb.GoTest{
  338. F_BytesRepeated: [][]byte{nil, []byte{}, []byte{0}},
  339. },
  340. dst: &pb.GoTest{},
  341. want: &pb.GoTest{
  342. F_BytesRepeated: [][]byte{nil, []byte{}, []byte{0}},
  343. },
  344. },
  345. {
  346. src: &pb.MyMessage{
  347. Others: []*pb.OtherMessage{},
  348. },
  349. dst: &pb.MyMessage{},
  350. want: &pb.MyMessage{
  351. Others: []*pb.OtherMessage{},
  352. },
  353. },
  354. }
  355. func TestMerge(t *testing.T) {
  356. for _, m := range mergeTests {
  357. got := proto.Clone(m.dst)
  358. if !proto.Equal(got, m.dst) {
  359. t.Errorf("Clone()\ngot %v\nwant %v", got, m.dst)
  360. continue
  361. }
  362. proto.Merge(got, m.src)
  363. if !proto.Equal(got, m.want) {
  364. t.Errorf("Merge(%v, %v)\ngot %v\nwant %v", m.dst, m.src, got, m.want)
  365. }
  366. }
  367. }