json_test.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. // Copyright 2015 Google Inc. 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 gensupport
  5. import (
  6. "encoding/json"
  7. "reflect"
  8. "testing"
  9. "google.golang.org/api/googleapi"
  10. )
  11. type schema struct {
  12. // Basic types
  13. B bool `json:"b,omitempty"`
  14. F float64 `json:"f,omitempty"`
  15. I int64 `json:"i,omitempty"`
  16. Istr int64 `json:"istr,omitempty,string"`
  17. Str string `json:"str,omitempty"`
  18. // Pointers to basic types
  19. PB *bool `json:"pb,omitempty"`
  20. PF *float64 `json:"pf,omitempty"`
  21. PI *int64 `json:"pi,omitempty"`
  22. PIStr *int64 `json:"pistr,omitempty,string"`
  23. PStr *string `json:"pstr,omitempty"`
  24. // Other types
  25. Int64s googleapi.Int64s `json:"i64s,omitempty"`
  26. S []int `json:"s,omitempty"`
  27. M map[string]string `json:"m,omitempty"`
  28. Any interface{} `json:"any,omitempty"`
  29. Child *child `json:"child,omitempty"`
  30. ForceSendFields []string `json:"-"`
  31. }
  32. type child struct {
  33. B bool `json:"childbool,omitempty"`
  34. }
  35. type testCase struct {
  36. s schema
  37. want string
  38. }
  39. func TestBasics(t *testing.T) {
  40. for _, tc := range []testCase{
  41. {
  42. s: schema{},
  43. want: `{}`,
  44. },
  45. {
  46. s: schema{
  47. ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"},
  48. },
  49. want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":""}`,
  50. },
  51. {
  52. s: schema{
  53. B: true,
  54. F: 1.2,
  55. I: 1,
  56. Istr: 2,
  57. Str: "a",
  58. PB: googleapi.Bool(true),
  59. PF: googleapi.Float64(1.2),
  60. PI: googleapi.Int64(int64(1)),
  61. PIStr: googleapi.Int64(int64(2)),
  62. PStr: googleapi.String("a"),
  63. },
  64. want: `{"b":true,"f":1.2,"i":1,"istr":"2","str":"a","pb":true,"pf":1.2,"pi":1,"pistr":"2","pstr":"a"}`,
  65. },
  66. {
  67. s: schema{
  68. B: false,
  69. F: 0.0,
  70. I: 0,
  71. Istr: 0,
  72. Str: "",
  73. PB: googleapi.Bool(false),
  74. PF: googleapi.Float64(0.0),
  75. PI: googleapi.Int64(int64(0)),
  76. PIStr: googleapi.Int64(int64(0)),
  77. PStr: googleapi.String(""),
  78. },
  79. want: `{"pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`,
  80. },
  81. {
  82. s: schema{
  83. B: false,
  84. F: 0.0,
  85. I: 0,
  86. Istr: 0,
  87. Str: "",
  88. PB: googleapi.Bool(false),
  89. PF: googleapi.Float64(0.0),
  90. PI: googleapi.Int64(int64(0)),
  91. PIStr: googleapi.Int64(int64(0)),
  92. PStr: googleapi.String(""),
  93. ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"},
  94. },
  95. want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":"","pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`,
  96. },
  97. } {
  98. checkMarshalJSON(t, tc)
  99. }
  100. }
  101. func TestSliceFields(t *testing.T) {
  102. for _, tc := range []testCase{
  103. {
  104. s: schema{},
  105. want: `{}`,
  106. },
  107. {
  108. s: schema{S: []int{}, Int64s: googleapi.Int64s{}},
  109. want: `{}`,
  110. },
  111. {
  112. s: schema{S: []int{1}, Int64s: googleapi.Int64s{1}},
  113. want: `{"s":[1],"i64s":["1"]}`,
  114. },
  115. {
  116. s: schema{
  117. ForceSendFields: []string{"S", "Int64s"},
  118. },
  119. want: `{"s":[],"i64s":[]}`,
  120. },
  121. {
  122. s: schema{
  123. S: []int{},
  124. Int64s: googleapi.Int64s{},
  125. ForceSendFields: []string{"S", "Int64s"},
  126. },
  127. want: `{"s":[],"i64s":[]}`,
  128. },
  129. {
  130. s: schema{
  131. S: []int{1},
  132. Int64s: googleapi.Int64s{1},
  133. ForceSendFields: []string{"S", "Int64s"},
  134. },
  135. want: `{"s":[1],"i64s":["1"]}`,
  136. },
  137. } {
  138. checkMarshalJSON(t, tc)
  139. }
  140. }
  141. func TestMapField(t *testing.T) {
  142. for _, tc := range []testCase{
  143. {
  144. s: schema{},
  145. want: `{}`,
  146. },
  147. {
  148. s: schema{M: make(map[string]string)},
  149. want: `{}`,
  150. },
  151. {
  152. s: schema{M: map[string]string{"a": "b"}},
  153. want: `{"m":{"a":"b"}}`,
  154. },
  155. {
  156. s: schema{
  157. ForceSendFields: []string{"M"},
  158. },
  159. want: `{"m":{}}`,
  160. },
  161. {
  162. s: schema{
  163. M: make(map[string]string),
  164. ForceSendFields: []string{"M"},
  165. },
  166. want: `{"m":{}}`,
  167. },
  168. {
  169. s: schema{
  170. M: map[string]string{"a": "b"},
  171. ForceSendFields: []string{"M"},
  172. },
  173. want: `{"m":{"a":"b"}}`,
  174. },
  175. } {
  176. checkMarshalJSON(t, tc)
  177. }
  178. }
  179. type anyType struct {
  180. Field int
  181. }
  182. func (a anyType) MarshalJSON() ([]byte, error) {
  183. return []byte(`"anyType value"`), nil
  184. }
  185. func TestAnyField(t *testing.T) {
  186. // ForceSendFields has no effect on nil interfaces and interfaces that contain nil pointers.
  187. var nilAny *anyType
  188. for _, tc := range []testCase{
  189. {
  190. s: schema{},
  191. want: `{}`,
  192. },
  193. {
  194. s: schema{Any: nilAny},
  195. want: `{"any": null}`,
  196. },
  197. {
  198. s: schema{Any: &anyType{}},
  199. want: `{"any":"anyType value"}`,
  200. },
  201. {
  202. s: schema{Any: anyType{}},
  203. want: `{"any":"anyType value"}`,
  204. },
  205. {
  206. s: schema{
  207. ForceSendFields: []string{"Any"},
  208. },
  209. want: `{}`,
  210. },
  211. {
  212. s: schema{
  213. Any: nilAny,
  214. ForceSendFields: []string{"Any"},
  215. },
  216. want: `{"any": null}`,
  217. },
  218. {
  219. s: schema{
  220. Any: &anyType{},
  221. ForceSendFields: []string{"Any"},
  222. },
  223. want: `{"any":"anyType value"}`,
  224. },
  225. {
  226. s: schema{
  227. Any: anyType{},
  228. ForceSendFields: []string{"Any"},
  229. },
  230. want: `{"any":"anyType value"}`,
  231. },
  232. } {
  233. checkMarshalJSON(t, tc)
  234. }
  235. }
  236. func TestSubschema(t *testing.T) {
  237. // Subschemas are always stored as pointers, so ForceSendFields has no effect on them.
  238. for _, tc := range []testCase{
  239. {
  240. s: schema{},
  241. want: `{}`,
  242. },
  243. {
  244. s: schema{
  245. ForceSendFields: []string{"Child"},
  246. },
  247. want: `{}`,
  248. },
  249. {
  250. s: schema{Child: &child{}},
  251. want: `{"child":{}}`,
  252. },
  253. {
  254. s: schema{
  255. Child: &child{},
  256. ForceSendFields: []string{"Child"},
  257. },
  258. want: `{"child":{}}`,
  259. },
  260. {
  261. s: schema{Child: &child{B: true}},
  262. want: `{"child":{"childbool":true}}`,
  263. },
  264. {
  265. s: schema{
  266. Child: &child{B: true},
  267. ForceSendFields: []string{"Child"},
  268. },
  269. want: `{"child":{"childbool":true}}`,
  270. },
  271. } {
  272. checkMarshalJSON(t, tc)
  273. }
  274. }
  275. // checkMarshalJSON verifies that calling schemaToMap on tc.s yields a result which is equivalent to tc.want.
  276. func checkMarshalJSON(t *testing.T, tc testCase) {
  277. doCheckMarshalJSON(t, tc.s, tc.s.ForceSendFields, tc.want)
  278. if len(tc.s.ForceSendFields) == 0 {
  279. // verify that the code path used when ForceSendFields
  280. // is non-empty produces the same output as the fast
  281. // path that is used when it is empty.
  282. doCheckMarshalJSON(t, tc.s, []string{"dummy"}, tc.want)
  283. }
  284. }
  285. func doCheckMarshalJSON(t *testing.T, s schema, forceSendFields []string, wantJSON string) {
  286. encoded, err := MarshalJSON(s, forceSendFields)
  287. if err != nil {
  288. t.Fatalf("encoding json:\n got err: %v", err)
  289. }
  290. // The expected and obtained JSON can differ in field ordering, so unmarshal before comparing.
  291. var got interface{}
  292. var want interface{}
  293. err = json.Unmarshal(encoded, &got)
  294. if err != nil {
  295. t.Fatalf("decoding json:\n got err: %v", err)
  296. }
  297. err = json.Unmarshal([]byte(wantJSON), &want)
  298. if err != nil {
  299. t.Fatalf("decoding json:\n got err: %v", err)
  300. }
  301. if !reflect.DeepEqual(got, want) {
  302. t.Errorf("schemaToMap:\ngot :%s\nwant:%s", got, want)
  303. }
  304. }
  305. func TestParseJSONTag(t *testing.T) {
  306. for _, tc := range []struct {
  307. tag string
  308. want jsonTag
  309. }{
  310. {
  311. tag: "-",
  312. want: jsonTag{ignore: true},
  313. }, {
  314. tag: "name,omitempty",
  315. want: jsonTag{apiName: "name"},
  316. }, {
  317. tag: "name,omitempty,string",
  318. want: jsonTag{apiName: "name", stringFormat: true},
  319. },
  320. } {
  321. got, err := parseJSONTag(tc.tag)
  322. if err != nil {
  323. t.Fatalf("parsing json:\n got err: %v\ntag: %q", err, tc.tag)
  324. }
  325. if !reflect.DeepEqual(got, tc.want) {
  326. t.Errorf("parseJSONTage:\ngot :%s\nwant:%s", got, tc.want)
  327. }
  328. }
  329. }
  330. func TestParseMalformedJSONTag(t *testing.T) {
  331. for _, tag := range []string{
  332. "",
  333. "name",
  334. "name,",
  335. "name,blah",
  336. "name,blah,string",
  337. ",omitempty",
  338. ",omitempty,string",
  339. "name,omitempty,string,blah",
  340. } {
  341. _, err := parseJSONTag(tag)
  342. if err == nil {
  343. t.Fatalf("parsing json: expected err, got nil for tag: %v", tag)
  344. }
  345. }
  346. }