Skip to content

Commit 1edf4fb

Browse files
committed
refactor tests to make them more readable
this splits TestValues_types into multiple test functions focused on different types of values. Also, instead of testing multiples types at a time by having a single large struct with lots of different fields, this switches to testing lots of small structs with a single field. This does result in longer code in some cases (specifically slices and arrays, which tend to span multiple lines), but it makes the individual cases much easier to read, since the input and expected output are directly next to each other. More cleanup to come; this just focused on the TestValues_types func.
1 parent e5b6f12 commit 1edf4fb

File tree

3 files changed

+195
-106
lines changed

3 files changed

+195
-106
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module github.com/google/go-querystring
22

33
go 1.10
4+
5+
require github.com/google/go-cmp v0.5.2

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
2+
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
3+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

query/encode_test.go

Lines changed: 190 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -10,125 +10,216 @@ import (
1010
"reflect"
1111
"testing"
1212
"time"
13+
14+
"github.com/google/go-cmp/cmp"
1315
)
1416

15-
type Nested struct {
16-
A SubNested `url:"a"`
17-
B *SubNested `url:"b"`
18-
Ptr *SubNested `url:"ptr,omitempty"`
17+
// test that Values(input) matches want. If not, report an error on t.
18+
func testValue(t *testing.T, input interface{}, want url.Values) {
19+
v, err := Values(input)
20+
if err != nil {
21+
t.Errorf("Values(%q) returned error: %v", input, err)
22+
}
23+
if diff := cmp.Diff(want, v); diff != "" {
24+
t.Errorf("Values(%q) mismatch:\n%s", input, diff)
25+
}
1926
}
2027

21-
type SubNested struct {
22-
Value string `url:"value"`
28+
func TestValues_BasicTypes(t *testing.T) {
29+
tests := []struct {
30+
input interface{}
31+
want url.Values
32+
}{
33+
// zero values
34+
{struct{ V string }{}, url.Values{"V": {""}}},
35+
{struct{ V int }{}, url.Values{"V": {"0"}}},
36+
{struct{ V uint }{}, url.Values{"V": {"0"}}},
37+
{struct{ V float32 }{}, url.Values{"V": {"0"}}},
38+
{struct{ V bool }{}, url.Values{"V": {"false"}}},
39+
40+
// simple non-zero values
41+
{struct{ V string }{"v"}, url.Values{"V": {"v"}}},
42+
{struct{ V int }{1}, url.Values{"V": {"1"}}},
43+
{struct{ V uint }{1}, url.Values{"V": {"1"}}},
44+
{struct{ V float32 }{0.1}, url.Values{"V": {"0.1"}}},
45+
{struct{ V bool }{true}, url.Values{"V": {"true"}}},
46+
47+
// bool-specific options
48+
{
49+
struct {
50+
V bool `url:",int"`
51+
}{false},
52+
url.Values{"V": {"0"}},
53+
},
54+
{
55+
struct {
56+
V bool `url:",int"`
57+
}{true},
58+
url.Values{"V": {"1"}},
59+
},
60+
61+
// time values
62+
{
63+
struct {
64+
V time.Time
65+
}{time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC)},
66+
url.Values{"V": {"2000-01-01T12:34:56Z"}},
67+
},
68+
{
69+
struct {
70+
V time.Time `url:",unix"`
71+
}{time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC)},
72+
url.Values{"V": {"946730096"}},
73+
},
74+
}
75+
76+
for _, tt := range tests {
77+
testValue(t, tt.input, tt.want)
78+
}
2379
}
2480

25-
func TestValues_types(t *testing.T) {
26-
str := "string"
81+
func TestValues_Pointers(t *testing.T) {
82+
str := "s"
2783
strPtr := &str
28-
timeVal := time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC)
2984

3085
tests := []struct {
31-
in interface{}
32-
want url.Values
86+
input interface{}
87+
want url.Values
3388
}{
89+
// nil pointers (zero values)
90+
{struct{ V *string }{}, url.Values{"V": {""}}},
91+
{struct{ V *int }{}, url.Values{"V": {""}}},
92+
93+
// non-zero pointer values
94+
{struct{ V *string }{&str}, url.Values{"V": {"s"}}},
95+
{struct{ V **string }{&strPtr}, url.Values{"V": {"s"}}},
96+
97+
// pointer values for the input struct itself
98+
{(*struct{})(nil), url.Values{}},
99+
{&struct{}{}, url.Values{}},
100+
{&struct{ V string }{}, url.Values{"V": {""}}},
101+
{&struct{ V string }{"v"}, url.Values{"V": {"v"}}},
102+
}
103+
104+
for _, tt := range tests {
105+
testValue(t, tt.input, tt.want)
106+
}
107+
}
108+
109+
func TestValues_Slices(t *testing.T) {
110+
tests := []struct {
111+
input interface{}
112+
want url.Values
113+
}{
114+
// slices of strings
115+
{
116+
struct{ V []string }{},
117+
url.Values{},
118+
},
119+
{
120+
struct{ V []string }{[]string{"a", "b"}},
121+
url.Values{"V": {"a", "b"}},
122+
},
34123
{
35-
// basic primitives
36124
struct {
37-
A string
38-
B int
39-
C uint
40-
D float32
41-
E bool
42-
}{},
43-
url.Values{
44-
"A": {""},
45-
"B": {"0"},
46-
"C": {"0"},
47-
"D": {"0"},
48-
"E": {"false"},
49-
},
125+
V []string `url:",comma"`
126+
}{[]string{"a", "b"}},
127+
url.Values{"V": {"a,b"}},
50128
},
51129
{
52-
// pointers
53130
struct {
54-
A *string
55-
B *int
56-
C **string
57-
D *time.Time
58-
}{
59-
A: strPtr,
60-
C: &strPtr,
61-
D: &timeVal,
62-
},
63-
url.Values{
64-
"A": {str},
65-
"B": {""},
66-
"C": {str},
67-
"D": {"2000-01-01T12:34:56Z"},
68-
},
131+
V []string `url:",space"`
132+
}{[]string{"a", "b"}},
133+
url.Values{"V": {"a b"}},
69134
},
70135
{
71-
// slices and arrays
72136
struct {
73-
A []string
74-
B []string `url:",comma"`
75-
C []string `url:",space"`
76-
D [2]string
77-
E [2]string `url:",comma"`
78-
F [2]string `url:",space"`
79-
G []*string `url:",space"`
80-
H []bool `url:",int,space"`
81-
I []string `url:",brackets"`
82-
J []string `url:",semicolon"`
83-
K []string `url:",numbered"`
84-
}{
85-
A: []string{"a", "b"},
86-
B: []string{"a", "b"},
87-
C: []string{"a", "b"},
88-
D: [2]string{"a", "b"},
89-
E: [2]string{"a", "b"},
90-
F: [2]string{"a", "b"},
91-
G: []*string{&str, &str},
92-
H: []bool{true, false},
93-
I: []string{"a", "b"},
94-
J: []string{"a", "b"},
95-
K: []string{"a", "b"},
96-
},
97-
url.Values{
98-
"A": {"a", "b"},
99-
"B": {"a,b"},
100-
"C": {"a b"},
101-
"D": {"a", "b"},
102-
"E": {"a,b"},
103-
"F": {"a b"},
104-
"G": {"string string"},
105-
"H": {"1 0"},
106-
"I[]": {"a", "b"},
107-
"J": {"a;b"},
108-
"K0": {"a"},
109-
"K1": {"b"},
110-
},
137+
V []string `url:",semicolon"`
138+
}{[]string{"a", "b"}},
139+
url.Values{"V": {"a;b"}},
111140
},
112141
{
113-
// other types
114142
struct {
115-
A time.Time
116-
B time.Time `url:",unix"`
117-
C bool `url:",int"`
118-
D bool `url:",int"`
119-
}{
120-
A: time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC),
121-
B: time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC),
122-
C: true,
123-
D: false,
124-
},
125-
url.Values{
126-
"A": {"2000-01-01T12:34:56Z"},
127-
"B": {"946730096"},
128-
"C": {"1"},
129-
"D": {"0"},
130-
},
143+
V []string `url:",brackets"`
144+
}{[]string{"a", "b"}},
145+
url.Values{"V[]": {"a", "b"}},
146+
},
147+
{
148+
struct {
149+
V []string `url:",numbered"`
150+
}{[]string{"a", "b"}},
151+
url.Values{"V0": {"a"}, "V1": {"b"}},
152+
},
153+
154+
// arrays of strings
155+
{
156+
struct{ V [2]string }{},
157+
url.Values{"V": {"", ""}},
158+
},
159+
{
160+
struct{ V [2]string }{[2]string{"a", "b"}},
161+
url.Values{"V": {"a", "b"}},
162+
},
163+
{
164+
struct {
165+
V [2]string `url:",comma"`
166+
}{[2]string{"a", "b"}},
167+
url.Values{"V": {"a,b"}},
131168
},
169+
{
170+
struct {
171+
V [2]string `url:",space"`
172+
}{[2]string{"a", "b"}},
173+
url.Values{"V": {"a b"}},
174+
},
175+
{
176+
struct {
177+
V [2]string `url:",semicolon"`
178+
}{[2]string{"a", "b"}},
179+
url.Values{"V": {"a;b"}},
180+
},
181+
{
182+
struct {
183+
V [2]string `url:",brackets"`
184+
}{[2]string{"a", "b"}},
185+
url.Values{"V[]": {"a", "b"}},
186+
},
187+
{
188+
struct {
189+
V [2]string `url:",numbered"`
190+
}{[2]string{"a", "b"}},
191+
url.Values{"V0": {"a"}, "V1": {"b"}},
192+
},
193+
194+
// slice of bools with additional options
195+
{
196+
struct {
197+
V []bool `url:",space,int"`
198+
}{[]bool{true, false}},
199+
url.Values{"V": {"1 0"}},
200+
},
201+
}
202+
203+
for _, tt := range tests {
204+
testValue(t, tt.input, tt.want)
205+
}
206+
}
207+
208+
func TestValues_NestedTypes(t *testing.T) {
209+
type SubNested struct {
210+
Value string `url:"value"`
211+
}
212+
213+
type Nested struct {
214+
A SubNested `url:"a"`
215+
B *SubNested `url:"b"`
216+
Ptr *SubNested `url:"ptr,omitempty"`
217+
}
218+
219+
tests := []struct {
220+
input interface{}
221+
want url.Values
222+
}{
132223
{
133224
struct {
134225
Nest Nested `url:"nest"`
@@ -166,15 +257,8 @@ func TestValues_types(t *testing.T) {
166257
},
167258
}
168259

169-
for i, tt := range tests {
170-
v, err := Values(tt.in)
171-
if err != nil {
172-
t.Errorf("%d. Values(%q) returned error: %v", i, tt.in, err)
173-
}
174-
175-
if !reflect.DeepEqual(tt.want, v) {
176-
t.Errorf("%d. Values(%q) returned %v, want %v", i, tt.in, v, tt.want)
177-
}
260+
for _, tt := range tests {
261+
testValue(t, tt.input, tt.want)
178262
}
179263
}
180264

0 commit comments

Comments
 (0)