text_parser_test.go 8.4 KB

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