PageRenderTime 45ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/proto/text_parser_test.go

https://code.google.com/p/goprotobuf/
Go | 340 lines | 268 code | 24 blank | 48 comment | 0 complexity | 9dee6051063dca55ad032342d4f84add MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Go support for Protocol Buffers - Google's data interchange format
  2. //
  3. // Copyright 2010 Google Inc. All rights reserved.
  4. // http://code.google.com/p/goprotobuf/
  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. package proto_test
  32. import (
  33. "reflect"
  34. "testing"
  35. . "./testdata"
  36. . "code.google.com/p/goprotobuf/proto"
  37. )
  38. type UnmarshalTextTest struct {
  39. in string
  40. err string // if "", no error expected
  41. out *MyMessage
  42. }
  43. func buildExtStructTest(text string) UnmarshalTextTest {
  44. msg := &MyMessage{
  45. Count: Int32(42),
  46. }
  47. SetExtension(msg, E_Ext_More, &Ext{
  48. Data: String("Hello, world!"),
  49. })
  50. return UnmarshalTextTest{in: text, out: msg}
  51. }
  52. func buildExtDataTest(text string) UnmarshalTextTest {
  53. msg := &MyMessage{
  54. Count: Int32(42),
  55. }
  56. SetExtension(msg, E_Ext_Text, String("Hello, world!"))
  57. SetExtension(msg, E_Ext_Number, Int32(1729))
  58. return UnmarshalTextTest{in: text, out: msg}
  59. }
  60. var unMarshalTextTests = []UnmarshalTextTest{
  61. // Basic
  62. {
  63. in: " count:42\n name:\"Dave\" ",
  64. out: &MyMessage{
  65. Count: Int32(42),
  66. Name: String("Dave"),
  67. },
  68. },
  69. // Empty quoted string
  70. {
  71. in: `count:42 name:""`,
  72. out: &MyMessage{
  73. Count: Int32(42),
  74. Name: String(""),
  75. },
  76. },
  77. // Quoted string concatenation
  78. {
  79. in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`,
  80. out: &MyMessage{
  81. Count: Int32(42),
  82. Name: String("My name is elsewhere"),
  83. },
  84. },
  85. // Quoted string with escaped apostrophe
  86. {
  87. in: `count:42 name: "HOLIDAY - New Year\'s Day"`,
  88. out: &MyMessage{
  89. Count: Int32(42),
  90. Name: String("HOLIDAY - New Year's Day"),
  91. },
  92. },
  93. // Bad quoted string
  94. {
  95. in: `inner: < host: "\0" >` + "\n",
  96. err: `line 1.15: invalid quoted string "\0"`,
  97. },
  98. // Number too large for int64
  99. {
  100. in: "count: 123456789012345678901",
  101. err: "line 1.7: invalid int32: 123456789012345678901",
  102. },
  103. // Number too large for int32
  104. {
  105. in: "count: 1234567890123",
  106. err: "line 1.7: invalid int32: 1234567890123",
  107. },
  108. // Number too large for float32
  109. {
  110. in: "others:< weight: 12345678901234567890123456789012345678901234567890 >",
  111. err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
  112. },
  113. // Number posing as a quoted string
  114. {
  115. in: `inner: < host: 12 >` + "\n",
  116. err: `line 1.15: invalid string: 12`,
  117. },
  118. // Quoted string posing as int32
  119. {
  120. in: `count: "12"`,
  121. err: `line 1.7: invalid int32: "12"`,
  122. },
  123. // Quoted string posing a float32
  124. {
  125. in: `others:< weight: "17.4" >`,
  126. err: `line 1.17: invalid float32: "17.4"`,
  127. },
  128. // Enum
  129. {
  130. in: `count:42 bikeshed: BLUE`,
  131. out: &MyMessage{
  132. Count: Int32(42),
  133. Bikeshed: NewMyMessage_Color(MyMessage_BLUE),
  134. },
  135. },
  136. // Repeated field
  137. {
  138. in: `count:42 pet: "horsey" pet:"bunny"`,
  139. out: &MyMessage{
  140. Count: Int32(42),
  141. Pet: []string{"horsey", "bunny"},
  142. },
  143. },
  144. // Repeated message with/without colon and <>/{}
  145. {
  146. in: `count:42 others:{} others{} others:<> others:{}`,
  147. out: &MyMessage{
  148. Count: Int32(42),
  149. Others: []*OtherMessage{
  150. &OtherMessage{},
  151. &OtherMessage{},
  152. &OtherMessage{},
  153. &OtherMessage{},
  154. },
  155. },
  156. },
  157. // Missing colon for inner message
  158. {
  159. in: `count:42 inner < host: "cauchy.syd" >`,
  160. out: &MyMessage{
  161. Count: Int32(42),
  162. Inner: &InnerMessage{
  163. Host: String("cauchy.syd"),
  164. },
  165. },
  166. },
  167. // Missing colon for string field
  168. {
  169. in: `name "Dave"`,
  170. err: `line 1.5: expected ':', found "\"Dave\""`,
  171. },
  172. // Missing colon for int32 field
  173. {
  174. in: `count 42`,
  175. err: `line 1.6: expected ':', found "42"`,
  176. },
  177. // Missing required field
  178. {
  179. in: ``,
  180. err: `line 1.0: message testdata.MyMessage missing required field "count"`,
  181. },
  182. // Repeated non-repeated field
  183. {
  184. in: `name: "Rob" name: "Russ"`,
  185. err: `line 1.12: non-repeated field "name" was repeated`,
  186. },
  187. // Group
  188. {
  189. in: `count: 17 SomeGroup { group_field: 12 }`,
  190. out: &MyMessage{
  191. Count: Int32(17),
  192. Somegroup: &MyMessage_SomeGroup{
  193. GroupField: Int32(12),
  194. },
  195. },
  196. },
  197. // Extension
  198. buildExtStructTest(`count: 42 [testdata.Ext.more]:<data:"Hello, world!" >`),
  199. buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`),
  200. buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`),
  201. // Big all-in-one
  202. {
  203. in: "count:42 # Meaning\n" +
  204. `name:"Dave" ` +
  205. `quote:"\"I didn't want to go.\"" ` +
  206. `pet:"bunny" ` +
  207. `pet:"kitty" ` +
  208. `pet:"horsey" ` +
  209. `inner:<` +
  210. ` host:"footrest.syd" ` +
  211. ` port:7001 ` +
  212. ` connected:true ` +
  213. `> ` +
  214. `others:<` +
  215. ` key:3735928559 ` +
  216. ` value:"\x01A\a\f" ` +
  217. `> ` +
  218. `others:<` +
  219. " weight:58.9 # Atomic weight of Co\n" +
  220. ` inner:<` +
  221. ` host:"lesha.mtv" ` +
  222. ` port:8002 ` +
  223. ` >` +
  224. `>`,
  225. out: &MyMessage{
  226. Count: Int32(42),
  227. Name: String("Dave"),
  228. Quote: String(`"I didn't want to go."`),
  229. Pet: []string{"bunny", "kitty", "horsey"},
  230. Inner: &InnerMessage{
  231. Host: String("footrest.syd"),
  232. Port: Int32(7001),
  233. Connected: Bool(true),
  234. },
  235. Others: []*OtherMessage{
  236. &OtherMessage{
  237. Key: Int64(3735928559),
  238. Value: []byte{0x1, 'A', '\a', '\f'},
  239. },
  240. &OtherMessage{
  241. Weight: Float32(58.9),
  242. Inner: &InnerMessage{
  243. Host: String("lesha.mtv"),
  244. Port: Int32(8002),
  245. },
  246. },
  247. },
  248. },
  249. },
  250. }
  251. func TestUnmarshalText(t *testing.T) {
  252. for i, test := range unMarshalTextTests {
  253. pb := new(MyMessage)
  254. err := UnmarshalText(test.in, pb)
  255. if test.err == "" {
  256. // We don't expect failure.
  257. if err != nil {
  258. t.Errorf("Test %d: Unexpected error: %v", i, err)
  259. } else if !reflect.DeepEqual(pb, test.out) {
  260. t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v",
  261. i, pb, test.out)
  262. }
  263. } else {
  264. // We do expect failure.
  265. if err == nil {
  266. t.Errorf("Test %d: Didn't get expected error: %v", i, test.err)
  267. } else if err.Error() != test.err {
  268. t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
  269. i, err.Error(), test.err)
  270. }
  271. }
  272. }
  273. }
  274. // Regression test; this caused a panic.
  275. func TestRepeatedEnum(t *testing.T) {
  276. pb := new(RepeatedEnum)
  277. if err := UnmarshalText("color: RED", pb); err != nil {
  278. t.Fatal(err)
  279. }
  280. exp := &RepeatedEnum{
  281. Color: []RepeatedEnum_Color{RepeatedEnum_RED},
  282. }
  283. if !reflect.DeepEqual(pb, exp) {
  284. t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp)
  285. }
  286. }
  287. var benchInput string
  288. func init() {
  289. benchInput = "count: 4\n"
  290. for i := 0; i < 1000; i++ {
  291. benchInput += "pet: \"fido\"\n"
  292. }
  293. // Check it is valid input.
  294. pb := new(MyMessage)
  295. err := UnmarshalText(benchInput, pb)
  296. if err != nil {
  297. panic("Bad benchmark input: " + err.Error())
  298. }
  299. }
  300. func BenchmarkUnmarshalText(b *testing.B) {
  301. pb := new(MyMessage)
  302. for i := 0; i < b.N; i++ {
  303. UnmarshalText(benchInput, pb)
  304. }
  305. b.SetBytes(int64(len(benchInput)))
  306. }