Skip to content

Commit de514b7

Browse files
committed
closes #31
1 parent 808cdc9 commit de514b7

File tree

4 files changed

+64
-93
lines changed

4 files changed

+64
-93
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ It only asserts that argument is of `time.Time` type.
188188

189189
## Changes
190190

191+
192+
- **2016-02-23** - convert expected arguments to driver.Value as natural
193+
driver does, the change may affect time.Time comparison and will be
194+
stricter. See [issue](https://github.com/DATA-DOG/go-sqlmock/issues/31).
191195
- **2015-08-27** - **v1** api change, concurrency support, all known issues fixed.
192196
- **2014-08-16** instead of **panic** during reflect type mismatch when comparing query arguments - now return error
193197
- **2014-08-14** added **sqlmock.NewErrorResult** which gives an option to return driver.Result with errors for

expectations.go

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package sqlmock
33
import (
44
"database/sql/driver"
55
"fmt"
6-
"reflect"
76
"regexp"
87
"strings"
98
"sync"
@@ -307,67 +306,59 @@ type queryBasedExpectation struct {
307306
args []driver.Value
308307
}
309308

310-
func (e *queryBasedExpectation) attemptMatch(sql string, args []driver.Value) (ret bool) {
309+
func (e *queryBasedExpectation) attemptMatch(sql string, args []driver.Value) (err error) {
311310
if !e.queryMatches(sql) {
312-
return
311+
return fmt.Errorf(`could not match sql: "%s" with expected regexp "%s"`, sql, e.sqlRegex.String())
313312
}
314313

315-
defer recover() // ignore panic since we attempt a match
314+
// catch panic
315+
defer func() {
316+
if e := recover(); e != nil {
317+
_, ok := e.(error)
318+
if !ok {
319+
err = fmt.Errorf(e.(string))
320+
}
321+
}
322+
}()
316323

317-
if e.argsMatches(args) {
318-
return true
319-
}
324+
err = e.argsMatches(args)
320325
return
321326
}
322327

323328
func (e *queryBasedExpectation) queryMatches(sql string) bool {
324329
return e.sqlRegex.MatchString(sql)
325330
}
326331

327-
func (e *queryBasedExpectation) argsMatches(args []driver.Value) bool {
332+
func (e *queryBasedExpectation) argsMatches(args []driver.Value) error {
328333
if nil == e.args {
329-
return true
334+
return nil
330335
}
331336
if len(args) != len(e.args) {
332-
return false
337+
return fmt.Errorf("expected %d, but got %d arguments", len(e.args), len(args))
333338
}
334339
for k, v := range args {
340+
// custom argument matcher
335341
matcher, ok := e.args[k].(Argument)
336342
if ok {
337343
if !matcher.Match(v) {
338-
return false
344+
return fmt.Errorf("matcher %T could not match %d argument %T - %+v", matcher, k, args[k], args[k])
339345
}
340346
continue
341347
}
342-
vi := reflect.ValueOf(v)
343-
ai := reflect.ValueOf(e.args[k])
344-
switch vi.Kind() {
345-
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
346-
if vi.Int() != ai.Int() {
347-
return false
348-
}
349-
case reflect.Float32, reflect.Float64:
350-
if vi.Float() != ai.Float() {
351-
return false
352-
}
353-
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
354-
if vi.Uint() != ai.Uint() {
355-
return false
356-
}
357-
case reflect.String:
358-
if vi.String() != ai.String() {
359-
return false
360-
}
361-
case reflect.Bool:
362-
if vi.Bool() != ai.Bool() {
363-
return false
364-
}
365-
default:
366-
// compare types like time.Time based on type only
367-
if vi.Kind() != ai.Kind() {
368-
return false
369-
}
348+
349+
// convert to driver converter
350+
darg, err := driver.DefaultParameterConverter.ConvertValue(e.args[k])
351+
if err != nil {
352+
return fmt.Errorf("could not convert %d argument %T - %+v to driver value: %s", k, e.args[k], e.args[k], err)
353+
}
354+
355+
if !driver.IsValue(darg) {
356+
return fmt.Errorf("argument %d: non-subset type %T returned from Value", k, darg)
357+
}
358+
359+
if darg != args[k] {
360+
return fmt.Errorf("argument %d expected [%T - %+v] does not match actual [%T - %+v]", k, darg, darg, args[k], args[k])
370361
}
371362
}
372-
return true
363+
return nil
373364
}

expectations_test.go

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,46 +17,45 @@ func (m matcher) Match(driver.Value) bool {
1717

1818
func TestQueryExpectationArgComparison(t *testing.T) {
1919
e := &queryBasedExpectation{}
20-
against := []driver.Value{5}
21-
if !e.argsMatches(against) {
22-
t.Error("arguments should match, since the no expectation was set")
20+
against := []driver.Value{int64(5)}
21+
if err := e.argsMatches(against); err != nil {
22+
t.Errorf("arguments should match, since the no expectation was set, but got err: %s", err)
2323
}
2424

2525
e.args = []driver.Value{5, "str"}
2626

27-
against = []driver.Value{5}
28-
if e.argsMatches(against) {
27+
against = []driver.Value{int64(5)}
28+
if err := e.argsMatches(against); err == nil {
2929
t.Error("arguments should not match, since the size is not the same")
3030
}
3131

32-
against = []driver.Value{3, "str"}
33-
if e.argsMatches(against) {
32+
against = []driver.Value{int64(3), "str"}
33+
if err := e.argsMatches(against); err == nil {
3434
t.Error("arguments should not match, since the first argument (int value) is different")
3535
}
3636

37-
against = []driver.Value{5, "st"}
38-
if e.argsMatches(against) {
37+
against = []driver.Value{int64(5), "st"}
38+
if err := e.argsMatches(against); err == nil {
3939
t.Error("arguments should not match, since the second argument (string value) is different")
4040
}
4141

42-
against = []driver.Value{5, "str"}
43-
if !e.argsMatches(against) {
44-
t.Error("arguments should match, but it did not")
42+
against = []driver.Value{int64(5), "str"}
43+
if err := e.argsMatches(against); err != nil {
44+
t.Errorf("arguments should match, but it did not: %s", err)
4545
}
4646

47-
e.args = []driver.Value{5, time.Now()}
48-
4947
const longForm = "Jan 2, 2006 at 3:04pm (MST)"
5048
tm, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)")
49+
e.args = []driver.Value{5, tm}
5150

52-
against = []driver.Value{5, tm}
53-
if !e.argsMatches(against) {
54-
t.Error("arguments should match (time will be compared only by type), but it did not")
51+
against = []driver.Value{int64(5), tm}
52+
if err := e.argsMatches(against); err != nil {
53+
t.Error("arguments should match, but it did not")
5554
}
5655

57-
against = []driver.Value{5, matcher{}}
58-
if !e.argsMatches(against) {
59-
t.Error("arguments should match, but it did not")
56+
e.args = []driver.Value{5, matcher{}}
57+
if err := e.argsMatches(against); err != nil {
58+
t.Errorf("arguments should match, but it did not: %s", err)
6059
}
6160
}
6261

@@ -65,25 +64,25 @@ func TestQueryExpectationArgComparisonBool(t *testing.T) {
6564

6665
e = &queryBasedExpectation{args: []driver.Value{true}}
6766
against := []driver.Value{true}
68-
if !e.argsMatches(against) {
67+
if err := e.argsMatches(against); err != nil {
6968
t.Error("arguments should match, since arguments are the same")
7069
}
7170

7271
e = &queryBasedExpectation{args: []driver.Value{false}}
7372
against = []driver.Value{false}
74-
if !e.argsMatches(against) {
73+
if err := e.argsMatches(against); err != nil {
7574
t.Error("arguments should match, since argument are the same")
7675
}
7776

7877
e = &queryBasedExpectation{args: []driver.Value{true}}
7978
against = []driver.Value{false}
80-
if e.argsMatches(against) {
79+
if err := e.argsMatches(against); err == nil {
8180
t.Error("arguments should not match, since argument is different")
8281
}
8382

8483
e = &queryBasedExpectation{args: []driver.Value{false}}
8584
against = []driver.Value{true}
86-
if e.argsMatches(against) {
85+
if err := e.argsMatches(against); err == nil {
8786
t.Error("arguments should not match, since argument is different")
8887
}
8988
}

sqlmock.go

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"database/sql"
1515
"database/sql/driver"
1616
"fmt"
17-
"reflect"
1817
"regexp"
1918
)
2019

@@ -216,7 +215,7 @@ func (c *sqlmock) Exec(query string, args []driver.Value) (res driver.Result, er
216215
return nil, fmt.Errorf("call to exec query '%s' with args %+v, was not expected, next expectation is: %s", query, args, next)
217216
}
218217
if exec, ok := next.(*ExpectedExec); ok {
219-
if exec.attemptMatch(query, args) {
218+
if err := exec.attemptMatch(query, args); err == nil {
220219
expected = exec
221220
break
222221
}
@@ -233,24 +232,13 @@ func (c *sqlmock) Exec(query string, args []driver.Value) (res driver.Result, er
233232

234233
defer expected.Unlock()
235234
expected.triggered = true
236-
// converts panic to error in case of reflect value type mismatch
237-
defer func(errp *error, exp *ExpectedExec, q string, a []driver.Value) {
238-
if e := recover(); e != nil {
239-
if se, ok := e.(*reflect.ValueError); ok { // catch reflect error, failed type conversion
240-
msg := "exec query \"%s\", args \"%+v\" failed to match with error \"%s\" expectation: %s"
241-
*errp = fmt.Errorf(msg, q, a, se, exp)
242-
} else {
243-
panic(e) // overwise if unknown error panic
244-
}
245-
}
246-
}(&err, expected, query, args)
247235

248236
if !expected.queryMatches(query) {
249237
return nil, fmt.Errorf("exec query '%s', does not match regex '%s'", query, expected.sqlRegex.String())
250238
}
251239

252-
if !expected.argsMatches(args) {
253-
return nil, fmt.Errorf("exec query '%s', args %+v does not match expected %+v", query, args, expected.args)
240+
if err := expected.argsMatches(args); err != nil {
241+
return nil, fmt.Errorf("exec query '%s', arguments do not match: %s", query, err)
254242
}
255243

256244
if expected.err != nil {
@@ -335,7 +323,7 @@ func (c *sqlmock) Query(query string, args []driver.Value) (rw driver.Rows, err
335323
return nil, fmt.Errorf("call to query '%s' with args %+v, was not expected, next expectation is: %s", query, args, next)
336324
}
337325
if qr, ok := next.(*ExpectedQuery); ok {
338-
if qr.attemptMatch(query, args) {
326+
if err := qr.attemptMatch(query, args); err == nil {
339327
expected = qr
340328
break
341329
}
@@ -353,24 +341,13 @@ func (c *sqlmock) Query(query string, args []driver.Value) (rw driver.Rows, err
353341

354342
defer expected.Unlock()
355343
expected.triggered = true
356-
// converts panic to error in case of reflect value type mismatch
357-
defer func(errp *error, exp *ExpectedQuery, q string, a []driver.Value) {
358-
if e := recover(); e != nil {
359-
if se, ok := e.(*reflect.ValueError); ok { // catch reflect error, failed type conversion
360-
msg := "query \"%s\", args \"%+v\" failed to match with error \"%s\" expectation: %s"
361-
*errp = fmt.Errorf(msg, q, a, se, exp)
362-
} else {
363-
panic(e) // overwise if unknown error panic
364-
}
365-
}
366-
}(&err, expected, query, args)
367344

368345
if !expected.queryMatches(query) {
369346
return nil, fmt.Errorf("query '%s', does not match regex [%s]", query, expected.sqlRegex.String())
370347
}
371348

372-
if !expected.argsMatches(args) {
373-
return nil, fmt.Errorf("query '%s', args %+v does not match expected %+v", query, args, expected.args)
349+
if err := expected.argsMatches(args); err != nil {
350+
return nil, fmt.Errorf("exec query '%s', arguments do not match: %s", query, err)
374351
}
375352

376353
if expected.err != nil {

0 commit comments

Comments
 (0)