Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 

517 rindas
11 KiB

  1. // Copyright 2015 Google LLC
  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. MapToAnyArray map[string][]interface{} `json:"maptoanyarray,omitempty"`
  31. ForceSendFields []string `json:"-"`
  32. NullFields []string `json:"-"`
  33. }
  34. type child struct {
  35. B bool `json:"childbool,omitempty"`
  36. }
  37. type testCase struct {
  38. s schema
  39. want string
  40. }
  41. func TestBasics(t *testing.T) {
  42. for _, tc := range []testCase{
  43. {
  44. s: schema{},
  45. want: `{}`,
  46. },
  47. {
  48. s: schema{
  49. ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"},
  50. },
  51. want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":""}`,
  52. },
  53. {
  54. s: schema{
  55. NullFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"},
  56. },
  57. want: `{"b":null,"f":null,"i":null,"istr":null,"str":null,"pb":null,"pf":null,"pi":null,"pistr":null,"pstr":null}`,
  58. },
  59. {
  60. s: schema{
  61. B: true,
  62. F: 1.2,
  63. I: 1,
  64. Istr: 2,
  65. Str: "a",
  66. PB: googleapi.Bool(true),
  67. PF: googleapi.Float64(1.2),
  68. PI: googleapi.Int64(int64(1)),
  69. PIStr: googleapi.Int64(int64(2)),
  70. PStr: googleapi.String("a"),
  71. },
  72. want: `{"b":true,"f":1.2,"i":1,"istr":"2","str":"a","pb":true,"pf":1.2,"pi":1,"pistr":"2","pstr":"a"}`,
  73. },
  74. {
  75. s: schema{
  76. B: false,
  77. F: 0.0,
  78. I: 0,
  79. Istr: 0,
  80. Str: "",
  81. PB: googleapi.Bool(false),
  82. PF: googleapi.Float64(0.0),
  83. PI: googleapi.Int64(int64(0)),
  84. PIStr: googleapi.Int64(int64(0)),
  85. PStr: googleapi.String(""),
  86. },
  87. want: `{"pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`,
  88. },
  89. {
  90. s: schema{
  91. B: false,
  92. F: 0.0,
  93. I: 0,
  94. Istr: 0,
  95. Str: "",
  96. PB: googleapi.Bool(false),
  97. PF: googleapi.Float64(0.0),
  98. PI: googleapi.Int64(int64(0)),
  99. PIStr: googleapi.Int64(int64(0)),
  100. PStr: googleapi.String(""),
  101. ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"},
  102. },
  103. want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":"","pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`,
  104. },
  105. {
  106. s: schema{
  107. B: false,
  108. F: 0.0,
  109. I: 0,
  110. Istr: 0,
  111. Str: "",
  112. PB: googleapi.Bool(false),
  113. PF: googleapi.Float64(0.0),
  114. PI: googleapi.Int64(int64(0)),
  115. PIStr: googleapi.Int64(int64(0)),
  116. PStr: googleapi.String(""),
  117. NullFields: []string{"B", "F", "I", "Istr", "Str"},
  118. },
  119. want: `{"b":null,"f":null,"i":null,"istr":null,"str":null,"pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`,
  120. },
  121. } {
  122. checkMarshalJSON(t, tc)
  123. }
  124. }
  125. func TestSliceFields(t *testing.T) {
  126. for _, tc := range []testCase{
  127. {
  128. s: schema{},
  129. want: `{}`,
  130. },
  131. {
  132. s: schema{S: []int{}, Int64s: googleapi.Int64s{}},
  133. want: `{}`,
  134. },
  135. {
  136. s: schema{S: []int{1}, Int64s: googleapi.Int64s{1}},
  137. want: `{"s":[1],"i64s":["1"]}`,
  138. },
  139. {
  140. s: schema{
  141. ForceSendFields: []string{"S", "Int64s"},
  142. },
  143. want: `{"s":[],"i64s":[]}`,
  144. },
  145. {
  146. s: schema{
  147. S: []int{},
  148. Int64s: googleapi.Int64s{},
  149. ForceSendFields: []string{"S", "Int64s"},
  150. },
  151. want: `{"s":[],"i64s":[]}`,
  152. },
  153. {
  154. s: schema{
  155. S: []int{1},
  156. Int64s: googleapi.Int64s{1},
  157. ForceSendFields: []string{"S", "Int64s"},
  158. },
  159. want: `{"s":[1],"i64s":["1"]}`,
  160. },
  161. {
  162. s: schema{
  163. NullFields: []string{"S", "Int64s"},
  164. },
  165. want: `{"s":null,"i64s":null}`,
  166. },
  167. } {
  168. checkMarshalJSON(t, tc)
  169. }
  170. }
  171. func TestMapField(t *testing.T) {
  172. for _, tc := range []testCase{
  173. {
  174. s: schema{},
  175. want: `{}`,
  176. },
  177. {
  178. s: schema{M: make(map[string]string)},
  179. want: `{}`,
  180. },
  181. {
  182. s: schema{M: map[string]string{"a": "b"}},
  183. want: `{"m":{"a":"b"}}`,
  184. },
  185. {
  186. s: schema{
  187. ForceSendFields: []string{"M"},
  188. },
  189. want: `{"m":{}}`,
  190. },
  191. {
  192. s: schema{
  193. NullFields: []string{"M"},
  194. },
  195. want: `{"m":null}`,
  196. },
  197. {
  198. s: schema{
  199. M: make(map[string]string),
  200. ForceSendFields: []string{"M"},
  201. },
  202. want: `{"m":{}}`,
  203. },
  204. {
  205. s: schema{
  206. M: make(map[string]string),
  207. NullFields: []string{"M"},
  208. },
  209. want: `{"m":null}`,
  210. },
  211. {
  212. s: schema{
  213. M: map[string]string{"a": "b"},
  214. ForceSendFields: []string{"M"},
  215. },
  216. want: `{"m":{"a":"b"}}`,
  217. },
  218. {
  219. s: schema{
  220. M: map[string]string{"a": "b"},
  221. NullFields: []string{"M.a", "M."},
  222. },
  223. want: `{"m": {"a": null, "":null}}`,
  224. },
  225. {
  226. s: schema{
  227. M: map[string]string{"a": "b"},
  228. NullFields: []string{"M.c"},
  229. },
  230. want: `{"m": {"a": "b", "c": null}}`,
  231. },
  232. {
  233. s: schema{
  234. NullFields: []string{"M.a"},
  235. ForceSendFields: []string{"M"},
  236. },
  237. want: `{"m": {"a": null}}`,
  238. },
  239. {
  240. s: schema{
  241. NullFields: []string{"M.a"},
  242. },
  243. want: `{}`,
  244. },
  245. } {
  246. checkMarshalJSON(t, tc)
  247. }
  248. }
  249. func TestMapToAnyArray(t *testing.T) {
  250. for _, tc := range []testCase{
  251. {
  252. s: schema{},
  253. want: `{}`,
  254. },
  255. {
  256. s: schema{MapToAnyArray: make(map[string][]interface{})},
  257. want: `{}`,
  258. },
  259. {
  260. s: schema{
  261. MapToAnyArray: map[string][]interface{}{
  262. "a": {2, "b"},
  263. },
  264. },
  265. want: `{"maptoanyarray":{"a":[2, "b"]}}`,
  266. },
  267. {
  268. s: schema{
  269. MapToAnyArray: map[string][]interface{}{
  270. "a": nil,
  271. },
  272. },
  273. want: `{"maptoanyarray":{"a": null}}`,
  274. },
  275. {
  276. s: schema{
  277. MapToAnyArray: map[string][]interface{}{
  278. "a": {nil},
  279. },
  280. },
  281. want: `{"maptoanyarray":{"a":[null]}}`,
  282. },
  283. {
  284. s: schema{
  285. ForceSendFields: []string{"MapToAnyArray"},
  286. },
  287. want: `{"maptoanyarray":{}}`,
  288. },
  289. {
  290. s: schema{
  291. NullFields: []string{"MapToAnyArray"},
  292. },
  293. want: `{"maptoanyarray":null}`,
  294. },
  295. {
  296. s: schema{
  297. MapToAnyArray: make(map[string][]interface{}),
  298. ForceSendFields: []string{"MapToAnyArray"},
  299. },
  300. want: `{"maptoanyarray":{}}`,
  301. },
  302. {
  303. s: schema{
  304. MapToAnyArray: map[string][]interface{}{
  305. "a": {2, "b"},
  306. },
  307. ForceSendFields: []string{"MapToAnyArray"},
  308. },
  309. want: `{"maptoanyarray":{"a":[2, "b"]}}`,
  310. },
  311. } {
  312. checkMarshalJSON(t, tc)
  313. }
  314. }
  315. type anyType struct {
  316. Field int
  317. }
  318. func (a anyType) MarshalJSON() ([]byte, error) {
  319. return []byte(`"anyType value"`), nil
  320. }
  321. func TestAnyField(t *testing.T) {
  322. // ForceSendFields has no effect on nil interfaces and interfaces that contain nil pointers.
  323. var nilAny *anyType
  324. for _, tc := range []testCase{
  325. {
  326. s: schema{},
  327. want: `{}`,
  328. },
  329. {
  330. s: schema{Any: nilAny},
  331. want: `{"any": null}`,
  332. },
  333. {
  334. s: schema{Any: &anyType{}},
  335. want: `{"any":"anyType value"}`,
  336. },
  337. {
  338. s: schema{Any: anyType{}},
  339. want: `{"any":"anyType value"}`,
  340. },
  341. {
  342. s: schema{
  343. ForceSendFields: []string{"Any"},
  344. },
  345. want: `{}`,
  346. },
  347. {
  348. s: schema{
  349. NullFields: []string{"Any"},
  350. },
  351. want: `{"any":null}`,
  352. },
  353. {
  354. s: schema{
  355. Any: nilAny,
  356. ForceSendFields: []string{"Any"},
  357. },
  358. want: `{"any": null}`,
  359. },
  360. {
  361. s: schema{
  362. Any: &anyType{},
  363. ForceSendFields: []string{"Any"},
  364. },
  365. want: `{"any":"anyType value"}`,
  366. },
  367. {
  368. s: schema{
  369. Any: anyType{},
  370. ForceSendFields: []string{"Any"},
  371. },
  372. want: `{"any":"anyType value"}`,
  373. },
  374. } {
  375. checkMarshalJSON(t, tc)
  376. }
  377. }
  378. func TestSubschema(t *testing.T) {
  379. // Subschemas are always stored as pointers, so ForceSendFields has no effect on them.
  380. for _, tc := range []testCase{
  381. {
  382. s: schema{},
  383. want: `{}`,
  384. },
  385. {
  386. s: schema{
  387. ForceSendFields: []string{"Child"},
  388. },
  389. want: `{}`,
  390. },
  391. {
  392. s: schema{
  393. NullFields: []string{"Child"},
  394. },
  395. want: `{"child":null}`,
  396. },
  397. {
  398. s: schema{Child: &child{}},
  399. want: `{"child":{}}`,
  400. },
  401. {
  402. s: schema{
  403. Child: &child{},
  404. ForceSendFields: []string{"Child"},
  405. },
  406. want: `{"child":{}}`,
  407. },
  408. {
  409. s: schema{Child: &child{B: true}},
  410. want: `{"child":{"childbool":true}}`,
  411. },
  412. {
  413. s: schema{
  414. Child: &child{B: true},
  415. ForceSendFields: []string{"Child"},
  416. },
  417. want: `{"child":{"childbool":true}}`,
  418. },
  419. } {
  420. checkMarshalJSON(t, tc)
  421. }
  422. }
  423. // checkMarshalJSON verifies that calling schemaToMap on tc.s yields a result which is equivalent to tc.want.
  424. func checkMarshalJSON(t *testing.T, tc testCase) {
  425. doCheckMarshalJSON(t, tc.s, tc.s.ForceSendFields, tc.s.NullFields, tc.want)
  426. if len(tc.s.ForceSendFields) == 0 && len(tc.s.NullFields) == 0 {
  427. // verify that the code path used when ForceSendFields and NullFields
  428. // are non-empty produces the same output as the fast path that is used
  429. // when they are empty.
  430. doCheckMarshalJSON(t, tc.s, []string{"dummy"}, []string{"dummy"}, tc.want)
  431. }
  432. }
  433. func doCheckMarshalJSON(t *testing.T, s schema, forceSendFields, nullFields []string, wantJSON string) {
  434. encoded, err := MarshalJSON(s, forceSendFields, nullFields)
  435. if err != nil {
  436. t.Fatalf("encoding json:\n got err: %v", err)
  437. }
  438. // The expected and obtained JSON can differ in field ordering, so unmarshal before comparing.
  439. var got interface{}
  440. var want interface{}
  441. err = json.Unmarshal(encoded, &got)
  442. if err != nil {
  443. t.Fatalf("decoding json:\n got err: %v", err)
  444. }
  445. err = json.Unmarshal([]byte(wantJSON), &want)
  446. if err != nil {
  447. t.Fatalf("decoding json:\n got err: %v", err)
  448. }
  449. if !reflect.DeepEqual(got, want) {
  450. t.Errorf("schemaToMap:\ngot :%v\nwant: %v", got, want)
  451. }
  452. }
  453. func TestParseJSONTag(t *testing.T) {
  454. for _, tc := range []struct {
  455. tag string
  456. want jsonTag
  457. }{
  458. {
  459. tag: "-",
  460. want: jsonTag{ignore: true},
  461. }, {
  462. tag: "name,omitempty",
  463. want: jsonTag{apiName: "name"},
  464. }, {
  465. tag: "name,omitempty,string",
  466. want: jsonTag{apiName: "name", stringFormat: true},
  467. },
  468. } {
  469. got, err := parseJSONTag(tc.tag)
  470. if err != nil {
  471. t.Fatalf("parsing json:\n got err: %v\ntag: %q", err, tc.tag)
  472. }
  473. if !reflect.DeepEqual(got, tc.want) {
  474. t.Errorf("parseJSONTage:\ngot :%v\nwant:%v", got, tc.want)
  475. }
  476. }
  477. }
  478. func TestParseMalformedJSONTag(t *testing.T) {
  479. for _, tag := range []string{
  480. "",
  481. "name",
  482. "name,",
  483. "name,blah",
  484. "name,blah,string",
  485. ",omitempty",
  486. ",omitempty,string",
  487. "name,omitempty,string,blah",
  488. } {
  489. _, err := parseJSONTag(tag)
  490. if err == nil {
  491. t.Fatalf("parsing json: expected err, got nil for tag: %v", tag)
  492. }
  493. }
  494. }