encode_test.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. // Copyright 2013 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 query
  5. import (
  6. "fmt"
  7. "net/url"
  8. "reflect"
  9. "testing"
  10. "time"
  11. )
  12. type Nested struct {
  13. A SubNested `url:"a"`
  14. B *SubNested `url:"b"`
  15. Ptr *SubNested `url:"ptr,omitempty"`
  16. }
  17. type SubNested struct {
  18. Value string `url:"value"`
  19. }
  20. func TestValues_types(t *testing.T) {
  21. str := "string"
  22. strPtr := &str
  23. timeVal := time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC)
  24. tests := []struct {
  25. in interface{}
  26. want url.Values
  27. }{
  28. {
  29. // basic primitives
  30. struct {
  31. A string
  32. B int
  33. C uint
  34. D float32
  35. E bool
  36. }{},
  37. url.Values{
  38. "A": {""},
  39. "B": {"0"},
  40. "C": {"0"},
  41. "D": {"0"},
  42. "E": {"false"},
  43. },
  44. },
  45. {
  46. // pointers
  47. struct {
  48. A *string
  49. B *int
  50. C **string
  51. D *time.Time
  52. }{
  53. A: strPtr,
  54. C: &strPtr,
  55. D: &timeVal,
  56. },
  57. url.Values{
  58. "A": {str},
  59. "B": {""},
  60. "C": {str},
  61. "D": {"2000-01-01T12:34:56Z"},
  62. },
  63. },
  64. {
  65. // slices and arrays
  66. struct {
  67. A []string
  68. B []string `url:",comma"`
  69. C []string `url:",space"`
  70. D [2]string
  71. E [2]string `url:",comma"`
  72. F [2]string `url:",space"`
  73. G []*string `url:",space"`
  74. H []bool `url:",int,space"`
  75. I []string `url:",brackets"`
  76. J []string `url:",semicolon"`
  77. K []string `url:",numbered"`
  78. }{
  79. A: []string{"a", "b"},
  80. B: []string{"a", "b"},
  81. C: []string{"a", "b"},
  82. D: [2]string{"a", "b"},
  83. E: [2]string{"a", "b"},
  84. F: [2]string{"a", "b"},
  85. G: []*string{&str, &str},
  86. H: []bool{true, false},
  87. I: []string{"a", "b"},
  88. J: []string{"a", "b"},
  89. K: []string{"a", "b"},
  90. },
  91. url.Values{
  92. "A": {"a", "b"},
  93. "B": {"a,b"},
  94. "C": {"a b"},
  95. "D": {"a", "b"},
  96. "E": {"a,b"},
  97. "F": {"a b"},
  98. "G": {"string string"},
  99. "H": {"1 0"},
  100. "I[]": {"a", "b"},
  101. "J": {"a;b"},
  102. "K0": {"a"},
  103. "K1": {"b"},
  104. },
  105. },
  106. {
  107. // other types
  108. struct {
  109. A time.Time
  110. B time.Time `url:",unix"`
  111. C bool `url:",int"`
  112. D bool `url:",int"`
  113. }{
  114. A: time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC),
  115. B: time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC),
  116. C: true,
  117. D: false,
  118. },
  119. url.Values{
  120. "A": {"2000-01-01T12:34:56Z"},
  121. "B": {"946730096"},
  122. "C": {"1"},
  123. "D": {"0"},
  124. },
  125. },
  126. {
  127. struct {
  128. Nest Nested `url:"nest"`
  129. }{
  130. Nested{
  131. A: SubNested{
  132. Value: "that",
  133. },
  134. },
  135. },
  136. url.Values{
  137. "nest[a][value]": {"that"},
  138. "nest[b]": {""},
  139. },
  140. },
  141. {
  142. struct {
  143. Nest Nested `url:"nest"`
  144. }{
  145. Nested{
  146. Ptr: &SubNested{
  147. Value: "that",
  148. },
  149. },
  150. },
  151. url.Values{
  152. "nest[a][value]": {""},
  153. "nest[b]": {""},
  154. "nest[ptr][value]": {"that"},
  155. },
  156. },
  157. {
  158. nil,
  159. url.Values{},
  160. },
  161. }
  162. for i, tt := range tests {
  163. v, err := Values(tt.in)
  164. if err != nil {
  165. t.Errorf("%d. Values(%q) returned error: %v", i, tt.in, err)
  166. }
  167. if !reflect.DeepEqual(tt.want, v) {
  168. t.Errorf("%d. Values(%q) returned %v, want %v", i, tt.in, v, tt.want)
  169. }
  170. }
  171. }
  172. func TestValues_omitEmpty(t *testing.T) {
  173. str := ""
  174. s := struct {
  175. a string
  176. A string
  177. B string `url:",omitempty"`
  178. C string `url:"-"`
  179. D string `url:"omitempty"` // actually named omitempty, not an option
  180. E *string `url:",omitempty"`
  181. }{E: &str}
  182. v, err := Values(s)
  183. if err != nil {
  184. t.Errorf("Values(%q) returned error: %v", s, err)
  185. }
  186. want := url.Values{
  187. "A": {""},
  188. "omitempty": {""},
  189. "E": {""}, // E is included because the pointer is not empty, even though the string being pointed to is
  190. }
  191. if !reflect.DeepEqual(want, v) {
  192. t.Errorf("Values(%q) returned %v, want %v", s, v, want)
  193. }
  194. }
  195. type A struct {
  196. B
  197. }
  198. type B struct {
  199. C string
  200. }
  201. type D struct {
  202. B
  203. C string
  204. }
  205. type e struct {
  206. B
  207. C string
  208. }
  209. type F struct {
  210. e
  211. }
  212. func TestValues_embeddedStructs(t *testing.T) {
  213. tests := []struct {
  214. in interface{}
  215. want url.Values
  216. }{
  217. {
  218. A{B{C: "foo"}},
  219. url.Values{"C": {"foo"}},
  220. },
  221. {
  222. D{B: B{C: "bar"}, C: "foo"},
  223. url.Values{"C": {"foo", "bar"}},
  224. },
  225. {
  226. F{e{B: B{C: "bar"}, C: "foo"}}, // With unexported embed
  227. url.Values{"C": {"foo", "bar"}},
  228. },
  229. }
  230. for i, tt := range tests {
  231. v, err := Values(tt.in)
  232. if err != nil {
  233. t.Errorf("%d. Values(%q) returned error: %v", i, tt.in, err)
  234. }
  235. if !reflect.DeepEqual(tt.want, v) {
  236. t.Errorf("%d. Values(%q) returned %v, want %v", i, tt.in, v, tt.want)
  237. }
  238. }
  239. }
  240. func TestValues_invalidInput(t *testing.T) {
  241. _, err := Values("")
  242. if err == nil {
  243. t.Errorf("expected Values() to return an error on invalid input")
  244. }
  245. }
  246. type EncodedArgs []string
  247. func (m EncodedArgs) EncodeValues(key string, v *url.Values) error {
  248. for i, arg := range m {
  249. v.Set(fmt.Sprintf("%s.%d", key, i), arg)
  250. }
  251. return nil
  252. }
  253. func TestValues_Marshaler(t *testing.T) {
  254. s := struct {
  255. Args EncodedArgs `url:"arg"`
  256. }{[]string{"a", "b", "c"}}
  257. v, err := Values(s)
  258. if err != nil {
  259. t.Errorf("Values(%q) returned error: %v", s, err)
  260. }
  261. want := url.Values{
  262. "arg.0": {"a"},
  263. "arg.1": {"b"},
  264. "arg.2": {"c"},
  265. }
  266. if !reflect.DeepEqual(want, v) {
  267. t.Errorf("Values(%q) returned %v, want %v", s, v, want)
  268. }
  269. }
  270. func TestValues_MarshalerWithNilPointer(t *testing.T) {
  271. s := struct {
  272. Args *EncodedArgs `url:"arg"`
  273. }{}
  274. v, err := Values(s)
  275. if err != nil {
  276. t.Errorf("Values(%q) returned error: %v", s, err)
  277. }
  278. want := url.Values{}
  279. if !reflect.DeepEqual(want, v) {
  280. t.Errorf("Values(%q) returned %v, want %v", s, v, want)
  281. }
  282. }
  283. func TestTagParsing(t *testing.T) {
  284. name, opts := parseTag("field,foobar,foo")
  285. if name != "field" {
  286. t.Fatalf("name = %q, want field", name)
  287. }
  288. for _, tt := range []struct {
  289. opt string
  290. want bool
  291. }{
  292. {"foobar", true},
  293. {"foo", true},
  294. {"bar", false},
  295. {"field", false},
  296. } {
  297. if opts.Contains(tt.opt) != tt.want {
  298. t.Errorf("Contains(%q) = %v", tt.opt, !tt.want)
  299. }
  300. }
  301. }