Skip to content

Commit 6316fd4

Browse files
author
timsolov
committed
test coverage
1 parent ce71d5b commit 6316fd4

File tree

5 files changed

+210
-59
lines changed

5 files changed

+210
-59
lines changed

Diff for: external_test.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package rqp
2+
3+
import (
4+
"database/sql"
5+
"database/sql/driver"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
type MyValuer struct{}
12+
13+
func (v MyValuer) Value() (driver.Value, error) {
14+
return "NULL", nil
15+
}
16+
17+
func Test_in(t *testing.T) {
18+
t.Run("ALL OK", func(t *testing.T) {
19+
q, args, err := in("id IN (?)", []string{"1", "2"})
20+
assert.NoError(t, err)
21+
assert.Equal(t, "id IN (?, ?)", q)
22+
assert.Equal(t, []interface{}{"1", "2"}, args)
23+
})
24+
25+
t.Run("Valuer", func(t *testing.T) {
26+
q, args, err := in("id IN (?)", []sql.NullString{{String: "1", Valid: true}, {String: "2"}})
27+
assert.NoError(t, err)
28+
assert.Equal(t, "id IN (?, ?)", q)
29+
assert.Equal(t, []interface{}{sql.NullString{String: "1", Valid: true}, sql.NullString{String: "2", Valid: false}}, args)
30+
})
31+
32+
t.Run("MyValuer", func(t *testing.T) {
33+
q, args, err := in("id IN (?)", MyValuer{})
34+
assert.NoError(t, err)
35+
assert.Equal(t, "id IN (?)", q)
36+
assert.Equal(t, []interface{}{MyValuer{}}, args)
37+
})
38+
39+
t.Run("More arguments", func(t *testing.T) {
40+
_, _, err := in("id IN (?), id2 = ?", []string{"1", "2"})
41+
assert.EqualError(t, err, "number of bindVars exceeds arguments")
42+
})
43+
44+
t.Run("Less arguments", func(t *testing.T) {
45+
s := "2"
46+
sPtr := &s
47+
_, _, err := in("id = ?", []string{"1", "2"}, sPtr)
48+
assert.EqualError(t, err, "number of bindVars less than number arguments")
49+
})
50+
51+
t.Run("No slice", func(t *testing.T) {
52+
_, _, err := in("id IN (?)", "1")
53+
assert.NoError(t, err)
54+
})
55+
56+
t.Run("Empty slice", func(t *testing.T) {
57+
_, _, err := in("id IN (?)", []string{})
58+
assert.Error(t, err, "empty slice passed to 'in' query")
59+
})
60+
61+
t.Run("Skip not slice", func(t *testing.T) {
62+
_, _, err := in("id IN (?), id2 = ?", "1", []interface{}{"2"})
63+
assert.NoError(t, err)
64+
})
65+
}

Diff for: go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ module github.com/timsolov/rest-query-parser
33
go 1.13
44

55
require (
6+
github.com/josharian/impl v0.0.0-20191119165012-6b9658ad00c7 // indirect
67
github.com/pkg/errors v0.9.1
78
github.com/stretchr/testify v1.5.1
9+
golang.org/x/mod v0.3.0 // indirect
10+
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 // indirect
811
)

Diff for: go.sum

+24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
22
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/josharian/impl v0.0.0-20191119165012-6b9658ad00c7 h1:dhk1N6iuFDo1Lcew31sAQxrh8GVWaw0xu0MWNnMc6ao=
4+
github.com/josharian/impl v0.0.0-20191119165012-6b9658ad00c7/go.mod h1:t4Tr0tn92eq5ISef4cS5plFAMYAqZlAXtgUcKE6y8nw=
35
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
46
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
57
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -9,6 +11,28 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
911
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
1012
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
1113
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
14+
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
15+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
16+
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
17+
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
18+
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
19+
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
20+
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
21+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
22+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
23+
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
24+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
25+
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
26+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
27+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
28+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
29+
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
30+
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 h1:vmsb6v0zUdmUlXfwKaYrHPPRCV0lHq/IwNIf0ASGjyQ=
31+
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
32+
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
33+
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
34+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
35+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
1236
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
1337
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1438
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=

Diff for: main_test.go

+109-59
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,21 @@ import (
1111

1212
func TestFields(t *testing.T) {
1313

14+
// mockValidation := func(value interface{}) error { return nil }
15+
validate := In("id", "name")
16+
1417
// Fields:
1518
cases := []struct {
1619
url string
1720
expected string
21+
v ValidationFunc
1822
err error
1923
}{
20-
{url: "?", expected: "*", err: nil},
21-
{url: "?fields=", expected: "*", err: nil},
22-
{url: "?fields=id", expected: "id", err: nil},
23-
{url: "?fields=id,name", expected: "id, name", err: nil},
24+
{url: "?", expected: "*", v: validate, err: nil},
25+
{url: "?fields=", expected: "*", v: validate, err: nil},
26+
{url: "?fields=id", expected: "id", v: validate, err: nil},
27+
{url: "?fields=id,name", expected: "id, name", v: validate, err: nil},
28+
{"?fields=", "*", nil, ErrValidationNotFound},
2429
}
2530

2631
for _, c := range cases {
@@ -29,10 +34,14 @@ func TestFields(t *testing.T) {
2934
assert.NoError(t, err)
3035
q := NewQV(URL.Query(), nil)
3136
assert.NoError(t, err)
32-
q.AddValidation("fields", In("id", "name"))
37+
q.AddValidation("fields", c.v)
3338
err = q.Parse()
34-
assert.Equal(t, c.err, err)
35-
assert.Equal(t, c.expected, q.FieldsString())
39+
if c.err != nil {
40+
assert.Equal(t, c.expected, q.FieldsString())
41+
} else {
42+
assert.NoError(t, err)
43+
assert.Equal(t, c.err, errors.Cause(err))
44+
}
3645
})
3746
}
3847
}
@@ -74,17 +83,24 @@ func TestLimit(t *testing.T) {
7483
}{
7584
{url: "?", expected: ""},
7685
{url: "?limit=", expected: "", err: ErrBadFormat},
86+
{url: "?limit=1,2", expected: "", err: ErrBadFormat},
87+
{url: "?limit=11", expected: "", err: ErrNotInScope},
88+
{url: "?limit=-1", expected: "", err: ErrNotInScope},
89+
{url: "?limit=1", expected: "", err: ErrNotInScope},
90+
{url: "?limit=q", expected: "", err: ErrBadFormat},
7791
{url: "?limit=10", expected: " LIMIT 10"},
7892
}
7993
for _, c := range cases {
80-
URL, err := url.Parse(c.url)
81-
assert.NoError(t, err)
82-
q := New().
83-
SetUrlQuery(URL.Query()).
84-
AddValidation("limit", Max(10))
85-
err = q.Parse()
86-
assert.Equal(t, c.err, errors.Cause(err))
87-
assert.Equal(t, c.expected, q.LIMIT())
94+
t.Run(c.url, func(t *testing.T) {
95+
URL, err := url.Parse(c.url)
96+
assert.NoError(t, err)
97+
q := New().
98+
SetUrlQuery(URL.Query()).
99+
AddValidation("limit", Multi(Min(2), Max(10)))
100+
err = q.Parse()
101+
assert.Equal(t, c.err, errors.Cause(err))
102+
assert.Equal(t, c.expected, q.LIMIT())
103+
})
88104
}
89105
}
90106

@@ -103,21 +119,29 @@ func TestSort(t *testing.T) {
103119
{url: "?sort=id,-name", expected: " ORDER BY id, name DESC"},
104120
}
105121
for _, c := range cases {
106-
URL, err := url.Parse(c.url)
107-
assert.NoError(t, err)
108-
q, err := NewParse(URL.Query(), Validations{"sort": In("id", "name")})
109-
assert.Equal(t, c.err, err)
110-
assert.Equal(t, c.expected, q.ORDER())
122+
t.Run(c.url, func(t *testing.T) {
123+
URL, err := url.Parse(c.url)
124+
assert.NoError(t, err)
125+
q, err := NewParse(URL.Query(), Validations{"sort": In("id", "name")})
126+
assert.Equal(t, c.err, err)
127+
assert.Equal(t, c.expected, q.ORDER())
128+
})
111129
}
112130

113131
q := New().SetValidations(Validations{"sort": In("id")})
114132
err := q.SetUrlString("://")
115133
assert.Error(t, err)
134+
116135
err = q.SetUrlString("?sort=id")
117136
assert.NoError(t, err)
137+
118138
err = q.Parse()
119139
assert.NoError(t, err)
120140
assert.True(t, q.HaveSortBy("id"))
141+
142+
// Test AddSortBy
143+
q.AddSortBy("email", true)
144+
assert.True(t, q.HaveSortBy("email"))
121145
}
122146

123147
func TestWhere(t *testing.T) {
@@ -157,47 +181,53 @@ func TestWhere(t *testing.T) {
157181
{url: "?id[eq]=1&id[eq]=4", err: "id[eq]: bad format"},
158182
{url: "?id[gte]=1&id[lte]=4", expected: " WHERE id >= ? AND id <= ?", expected2: " WHERE id <= ? AND id >= ?"},
159183
{url: "?id[gte]=1|id[lte]=4", expected: " WHERE (id >= ? OR id <= ?)", expected2: " WHERE (id <= ? OR id >= ?)"},
184+
{url: "?u[not]=NULL", expected: " WHERE u IS NOT NULL"},
185+
// bool:
186+
{url: "?b=true", expected: " WHERE b = ?"},
187+
{url: "?b=true1", err: "b: bad format"},
188+
{url: "?b[not]=true", err: "b[not]: method are not allowed"},
189+
{url: "?b[eq]=true,false", err: "b[eq]: method are not allowed"},
160190
}
161191
for _, c := range cases {
162-
//t.Log(c)
163-
164-
URL, err := url.Parse(c.url)
165-
assert.NoError(t, err)
166-
167-
q := NewQV(URL.Query(), Validations{
168-
"id:int": func(value interface{}) error {
169-
if value.(int) > 10 {
170-
return errors.New("can't be greater then 10")
171-
}
172-
return nil
173-
},
174-
"s": In(
175-
"super",
176-
"best",
177-
),
178-
"u:string": nil,
179-
"custom": func(value interface{}) error {
180-
return nil
181-
},
182-
}).IgnoreUnknownFilters(c.ignore)
192+
t.Run(c.url, func(t *testing.T) {
193+
URL, err := url.Parse(c.url)
194+
assert.NoError(t, err)
183195

184-
err = q.Parse()
196+
q := NewQV(URL.Query(), Validations{
197+
"id:int": func(value interface{}) error {
198+
if value.(int) > 10 {
199+
return errors.New("can't be greater then 10")
200+
}
201+
return nil
202+
},
203+
"s": In(
204+
"super",
205+
"best",
206+
),
207+
"u:string": nil,
208+
"b:bool": nil,
209+
"custom": func(value interface{}) error {
210+
return nil
211+
},
212+
}).IgnoreUnknownFilters(c.ignore)
185213

186-
if len(c.err) > 0 {
187-
assert.EqualError(t, err, c.err)
188-
}
189-
where := q.WHERE()
190-
//t.Log(q.SQL("table"), q.Args())
191-
if len(c.expected2) > 0 {
192-
//t.Log("expected:", c.expected, "or:", c.expected2, "got:", where)
193-
assert.True(t, c.expected == where || c.expected2 == where)
194-
} else {
195-
//t.Log("expected:", c.expected, "got:", where)
196-
assert.True(t, c.expected == where)
197-
}
214+
err = q.Parse()
198215

216+
if len(c.err) > 0 {
217+
assert.EqualError(t, err, c.err)
218+
} else {
219+
assert.NoError(t, err)
220+
}
221+
where := q.WHERE()
222+
//t.Log(q.SQL("table"), q.Args())
223+
if len(c.expected2) > 0 {
224+
//t.Log("expected:", c.expected, "or:", c.expected2, "got:", where)
225+
assert.True(t, c.expected == where || c.expected2 == where)
226+
} else {
227+
assert.Equal(t, c.expected, where)
228+
}
229+
})
199230
}
200-
201231
}
202232

203233
func TestWhere2(t *testing.T) {
@@ -230,7 +260,7 @@ func TestArgs(t *testing.T) {
230260
q.SetDelimiterIN("!")
231261
assert.Len(t, q.Args(), 0)
232262
// setup url
233-
URL, err := url.Parse("?fields=id!status&sort=id!+id!-id&offset=10&one=123&two=test&three[like]=*www*&three[in]=www1!www2")
263+
URL, err := url.Parse("?fields=id!status&sort=id!+id!-id&offset=10&one=123&two=test&three[like]=*www*&three[in]=www1!www2&four[not]=NULL")
234264
assert.NoError(t, err)
235265

236266
err = q.SetUrlQuery(URL.Query()).SetValidations(Validations{
@@ -239,15 +269,17 @@ func TestArgs(t *testing.T) {
239269
"one:int": nil,
240270
"two": nil,
241271
"three": nil,
272+
"four": nil,
242273
}).Parse()
243274
assert.NoError(t, err)
244275

245-
assert.Len(t, q.Args(), 5)
276+
assert.Len(t, q.Args(), 6)
246277
assert.Contains(t, q.Args(), 123)
247278
assert.Contains(t, q.Args(), "test")
248279
assert.Contains(t, q.Args(), "%www%")
249280
assert.Contains(t, q.Args(), "www1")
250281
assert.Contains(t, q.Args(), "www2")
282+
assert.Contains(t, q.Args(), "NULL")
251283
}
252284

253285
func TestSQL(t *testing.T) {
@@ -270,11 +302,14 @@ func TestSQL(t *testing.T) {
270302
}
271303

272304
func TestReplaceFiltersNames(t *testing.T) {
273-
URL, err := url.Parse("?one=123&another=yes")
305+
URL, err := url.Parse("?fields=one&sort=one&one=123&another=yes")
274306
assert.NoError(t, err)
275307

276308
q, err := NewParse(URL.Query(), Validations{
277-
"one": nil, "another": nil,
309+
"fields": In("one", "another", "two"),
310+
"sort": In("one", "another", "two"),
311+
"one": nil,
312+
"another": nil,
278313
})
279314
assert.NoError(t, err)
280315
assert.True(t, q.HaveFilter("one"))
@@ -364,3 +399,18 @@ func Test_ignoreUnknown(t *testing.T) {
364399
assert.Equal(t, ErrFilterNotFound, errors.Cause(q.Parse()))
365400

366401
}
402+
403+
func TestRemoveValidation(t *testing.T) {
404+
q := New()
405+
406+
// validation not found case
407+
assert.EqualError(t, q.RemoveValidation("fields"), ErrValidationNotFound.Error())
408+
409+
// remove plain validation
410+
q.AddValidation("fields", In("id"))
411+
assert.NoError(t, q.RemoveValidation("fields"))
412+
413+
// remove typed validation
414+
q.AddValidation("name:string", In("id"))
415+
assert.NoError(t, q.RemoveValidation("name"))
416+
}

Diff for: validation_test.go

+9
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,12 @@ func TestMinMax(t *testing.T) {
5454
assert.EqualError(t, err, "one: not in scope")
5555

5656
}
57+
58+
func TestNotEmpty(t *testing.T) {
59+
// good case
60+
err := NotEmpty()("test")
61+
assert.NoError(t, err)
62+
// bad case
63+
err = NotEmpty()("")
64+
assert.Equal(t, errors.Cause(err), ErrNotInScope)
65+
}

0 commit comments

Comments
 (0)