encode_test.go 7.4 KB

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