encode_test.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. // Copyright 2019 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 json_test
  5. import (
  6. "math"
  7. "strings"
  8. "testing"
  9. "github.com/google/go-cmp/cmp"
  10. "github.com/google/go-cmp/cmp/cmpopts"
  11. "google.golang.org/protobuf/internal/detrand"
  12. "google.golang.org/protobuf/internal/encoding/json"
  13. )
  14. // Disable detrand to enable direct comparisons on outputs.
  15. func init() { detrand.Disable() }
  16. // splitLines is a cmpopts.Option for comparing strings with line breaks.
  17. var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
  18. return strings.Split(s, "\n")
  19. })
  20. func TestEncoder(t *testing.T) {
  21. tests := []struct {
  22. desc string
  23. write func(*json.Encoder)
  24. wantOut string
  25. wantOutIndent string
  26. }{
  27. {
  28. desc: "null",
  29. write: func(e *json.Encoder) {
  30. e.WriteNull()
  31. },
  32. wantOut: `null`,
  33. wantOutIndent: `null`,
  34. },
  35. {
  36. desc: "true",
  37. write: func(e *json.Encoder) {
  38. e.WriteBool(true)
  39. },
  40. wantOut: `true`,
  41. wantOutIndent: `true`,
  42. },
  43. {
  44. desc: "false",
  45. write: func(e *json.Encoder) {
  46. e.WriteBool(false)
  47. },
  48. wantOut: `false`,
  49. wantOutIndent: `false`,
  50. },
  51. {
  52. desc: "string",
  53. write: func(e *json.Encoder) {
  54. e.WriteString("hello world")
  55. },
  56. wantOut: `"hello world"`,
  57. wantOutIndent: `"hello world"`,
  58. },
  59. {
  60. desc: "string contains escaped characters",
  61. write: func(e *json.Encoder) {
  62. e.WriteString("\u0000\"\\/\b\f\n\r\t")
  63. },
  64. wantOut: `"\u0000\"\\/\b\f\n\r\t"`,
  65. },
  66. {
  67. desc: "float64",
  68. write: func(e *json.Encoder) {
  69. e.WriteFloat(1.0199999809265137, 64)
  70. },
  71. wantOut: `1.0199999809265137`,
  72. wantOutIndent: `1.0199999809265137`,
  73. },
  74. {
  75. desc: "float64 max value",
  76. write: func(e *json.Encoder) {
  77. e.WriteFloat(math.MaxFloat64, 64)
  78. },
  79. wantOut: `1.7976931348623157e+308`,
  80. wantOutIndent: `1.7976931348623157e+308`,
  81. },
  82. {
  83. desc: "float64 min value",
  84. write: func(e *json.Encoder) {
  85. e.WriteFloat(-math.MaxFloat64, 64)
  86. },
  87. wantOut: `-1.7976931348623157e+308`,
  88. wantOutIndent: `-1.7976931348623157e+308`,
  89. },
  90. {
  91. desc: "float64 NaN",
  92. write: func(e *json.Encoder) {
  93. e.WriteFloat(math.NaN(), 64)
  94. },
  95. wantOut: `"NaN"`,
  96. wantOutIndent: `"NaN"`,
  97. },
  98. {
  99. desc: "float64 Infinity",
  100. write: func(e *json.Encoder) {
  101. e.WriteFloat(math.Inf(+1), 64)
  102. },
  103. wantOut: `"Infinity"`,
  104. wantOutIndent: `"Infinity"`,
  105. },
  106. {
  107. desc: "float64 -Infinity",
  108. write: func(e *json.Encoder) {
  109. e.WriteFloat(math.Inf(-1), 64)
  110. },
  111. wantOut: `"-Infinity"`,
  112. wantOutIndent: `"-Infinity"`,
  113. },
  114. {
  115. desc: "float32",
  116. write: func(e *json.Encoder) {
  117. e.WriteFloat(1.02, 32)
  118. },
  119. wantOut: `1.02`,
  120. wantOutIndent: `1.02`,
  121. },
  122. {
  123. desc: "float32 max value",
  124. write: func(e *json.Encoder) {
  125. e.WriteFloat(math.MaxFloat32, 32)
  126. },
  127. wantOut: `3.4028235e+38`,
  128. wantOutIndent: `3.4028235e+38`,
  129. },
  130. {
  131. desc: "float32 min value",
  132. write: func(e *json.Encoder) {
  133. e.WriteFloat(-math.MaxFloat32, 32)
  134. },
  135. wantOut: `-3.4028235e+38`,
  136. wantOutIndent: `-3.4028235e+38`,
  137. },
  138. {
  139. desc: "int",
  140. write: func(e *json.Encoder) {
  141. e.WriteInt(-math.MaxInt64)
  142. },
  143. wantOut: `-9223372036854775807`,
  144. wantOutIndent: `-9223372036854775807`,
  145. },
  146. {
  147. desc: "uint",
  148. write: func(e *json.Encoder) {
  149. e.WriteUint(math.MaxUint64)
  150. },
  151. wantOut: `18446744073709551615`,
  152. wantOutIndent: `18446744073709551615`,
  153. },
  154. {
  155. desc: "empty object",
  156. write: func(e *json.Encoder) {
  157. e.StartObject()
  158. e.EndObject()
  159. },
  160. wantOut: `{}`,
  161. wantOutIndent: `{}`,
  162. },
  163. {
  164. desc: "empty array",
  165. write: func(e *json.Encoder) {
  166. e.StartArray()
  167. e.EndArray()
  168. },
  169. wantOut: `[]`,
  170. wantOutIndent: `[]`,
  171. },
  172. {
  173. desc: "object with one member",
  174. write: func(e *json.Encoder) {
  175. e.StartObject()
  176. e.WriteName("hello")
  177. e.WriteString("world")
  178. e.EndObject()
  179. },
  180. wantOut: `{"hello":"world"}`,
  181. wantOutIndent: `{
  182. "hello": "world"
  183. }`,
  184. },
  185. {
  186. desc: "array with one member",
  187. write: func(e *json.Encoder) {
  188. e.StartArray()
  189. e.WriteNull()
  190. e.EndArray()
  191. },
  192. wantOut: `[null]`,
  193. wantOutIndent: `[
  194. null
  195. ]`,
  196. },
  197. {
  198. desc: "simple object",
  199. write: func(e *json.Encoder) {
  200. e.StartObject()
  201. {
  202. e.WriteName("null")
  203. e.WriteNull()
  204. }
  205. {
  206. e.WriteName("bool")
  207. e.WriteBool(true)
  208. }
  209. {
  210. e.WriteName("string")
  211. e.WriteString("hello")
  212. }
  213. {
  214. e.WriteName("float")
  215. e.WriteFloat(6.28318, 64)
  216. }
  217. {
  218. e.WriteName("int")
  219. e.WriteInt(42)
  220. }
  221. {
  222. e.WriteName("uint")
  223. e.WriteUint(47)
  224. }
  225. e.EndObject()
  226. },
  227. wantOut: `{"null":null,"bool":true,"string":"hello","float":6.28318,"int":42,"uint":47}`,
  228. wantOutIndent: `{
  229. "null": null,
  230. "bool": true,
  231. "string": "hello",
  232. "float": 6.28318,
  233. "int": 42,
  234. "uint": 47
  235. }`,
  236. },
  237. {
  238. desc: "simple array",
  239. write: func(e *json.Encoder) {
  240. e.StartArray()
  241. {
  242. e.WriteString("hello")
  243. e.WriteFloat(6.28318, 32)
  244. e.WriteInt(42)
  245. e.WriteUint(47)
  246. e.WriteBool(true)
  247. e.WriteNull()
  248. }
  249. e.EndArray()
  250. },
  251. wantOut: `["hello",6.28318,42,47,true,null]`,
  252. wantOutIndent: `[
  253. "hello",
  254. 6.28318,
  255. 42,
  256. 47,
  257. true,
  258. null
  259. ]`,
  260. },
  261. {
  262. desc: "fancy object",
  263. write: func(e *json.Encoder) {
  264. e.StartObject()
  265. {
  266. e.WriteName("object0")
  267. e.StartObject()
  268. e.EndObject()
  269. }
  270. {
  271. e.WriteName("array0")
  272. e.StartArray()
  273. e.EndArray()
  274. }
  275. {
  276. e.WriteName("object1")
  277. e.StartObject()
  278. {
  279. e.WriteName("null")
  280. e.WriteNull()
  281. }
  282. {
  283. e.WriteName("object1-1")
  284. e.StartObject()
  285. {
  286. e.WriteName("bool")
  287. e.WriteBool(false)
  288. }
  289. {
  290. e.WriteName("float")
  291. e.WriteFloat(3.14159, 32)
  292. }
  293. e.EndObject()
  294. }
  295. e.EndObject()
  296. }
  297. {
  298. e.WriteName("array1")
  299. e.StartArray()
  300. {
  301. e.WriteNull()
  302. e.StartObject()
  303. e.EndObject()
  304. e.StartObject()
  305. {
  306. e.WriteName("hello")
  307. e.WriteString("world")
  308. }
  309. {
  310. e.WriteName("hola")
  311. e.WriteString("mundo")
  312. }
  313. e.EndObject()
  314. e.StartArray()
  315. {
  316. e.WriteUint(1)
  317. e.WriteUint(0)
  318. e.WriteUint(1)
  319. }
  320. e.EndArray()
  321. }
  322. e.EndArray()
  323. }
  324. e.EndObject()
  325. },
  326. wantOutIndent: `{
  327. "object0": {},
  328. "array0": [],
  329. "object1": {
  330. "null": null,
  331. "object1-1": {
  332. "bool": false,
  333. "float": 3.14159
  334. }
  335. },
  336. "array1": [
  337. null,
  338. {},
  339. {
  340. "hello": "world",
  341. "hola": "mundo"
  342. },
  343. [
  344. 1,
  345. 0,
  346. 1
  347. ]
  348. ]
  349. }`,
  350. }}
  351. for _, tc := range tests {
  352. t.Run(tc.desc, func(t *testing.T) {
  353. if tc.wantOut != "" {
  354. enc, err := json.NewEncoder("")
  355. if err != nil {
  356. t.Fatalf("NewEncoder() returned error: %v", err)
  357. }
  358. tc.write(enc)
  359. got := string(enc.Bytes())
  360. if got != tc.wantOut {
  361. t.Errorf("%s:\n<got>:\n%v\n<want>\n%v\n", tc.desc, got, tc.wantOut)
  362. }
  363. }
  364. if tc.wantOutIndent != "" {
  365. enc, err := json.NewEncoder("\t")
  366. if err != nil {
  367. t.Fatalf("NewEncoder() returned error: %v", err)
  368. }
  369. tc.write(enc)
  370. got, want := string(enc.Bytes()), tc.wantOutIndent
  371. if got != want {
  372. t.Errorf("%s(indent):\n<got>:\n%v\n<want>\n%v\n<diff -want +got>\n%v\n",
  373. tc.desc, got, want, cmp.Diff(want, got, splitLines))
  374. }
  375. }
  376. })
  377. }
  378. }
  379. func TestWriteStringError(t *testing.T) {
  380. tests := []string{"abc\xff"}
  381. for _, in := range tests {
  382. t.Run(in, func(t *testing.T) {
  383. enc, err := json.NewEncoder("")
  384. if err != nil {
  385. t.Fatalf("NewEncoder() returned error: %v", err)
  386. }
  387. if err := enc.WriteString(in); err == nil {
  388. t.Errorf("WriteString(%v): got nil error, want error", in)
  389. }
  390. })
  391. }
  392. }