diff --git a/README.md b/README.md index 6f9de5c..eee8aa9 100644 --- a/README.md +++ b/README.md @@ -323,12 +323,9 @@ rs := sqlmock.NewRows([]string{"column1", "column2"}). Visit [godoc](http://godoc.org/github.com/DATA-DOG/go-sqlmock) -## TODO - -- handle argument comparison more efficiently - ## Changes +- **2014-08-16** instead of **panic** during reflect type mismatch when comparing query arguments - now return error - **2014-08-14** added **sqlmock.NewErrorResult** which gives an option to return driver.Result with errors for interface methods, see [issue](https://github.com/DATA-DOG/go-sqlmock/issues/5) - **2014-05-29** allow to match arguments in more sophisticated ways, by providing an **sqlmock.Argument** interface diff --git a/connection.go b/connection.go index 00cf5cb..171fdbe 100644 --- a/connection.go +++ b/connection.go @@ -3,6 +3,7 @@ package sqlmock import ( "database/sql/driver" "fmt" + "reflect" ) type conn struct { @@ -49,7 +50,7 @@ func (c *conn) next() (e expectation) { return nil // all expectations were fulfilled } -func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) { +func (c *conn) Exec(query string, args []driver.Value) (res driver.Result, err error) { e := c.next() query = stripQuery(query) if e == nil { @@ -70,6 +71,8 @@ func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) { return nil, fmt.Errorf("exec query '%s' with args %+v, must return a database/sql/driver.result, but it was not set for expectation %T as %+v", query, args, eq, eq) } + defer argMatcherErrorHandler(&err) // converts panic to error in case of reflect value type mismatch + if !eq.queryMatches(query) { return nil, fmt.Errorf("exec query '%s', does not match regex '%s'", query, eq.sqlRegex.String()) } @@ -78,14 +81,14 @@ func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) { return nil, fmt.Errorf("exec query '%s', args %+v does not match expected %+v", query, args, eq.args) } - return eq.result, nil + return eq.result, err } func (c *conn) Prepare(query string) (driver.Stmt, error) { return &statement{mock.conn, stripQuery(query)}, nil } -func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) { +func (c *conn) Query(query string, args []driver.Value) (rw driver.Rows, err error) { e := c.next() query = stripQuery(query) if e == nil { @@ -106,6 +109,8 @@ func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) { return nil, fmt.Errorf("query '%s' with args %+v, must return a database/sql/driver.rows, but it was not set for expectation %T as %+v", query, args, eq, eq) } + defer argMatcherErrorHandler(&err) // converts panic to error in case of reflect value type mismatch + if !eq.queryMatches(query) { return nil, fmt.Errorf("query '%s', does not match regex [%s]", query, eq.sqlRegex.String()) } @@ -114,5 +119,15 @@ func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) { return nil, fmt.Errorf("query '%s', args %+v does not match expected %+v", query, args, eq.args) } - return eq.rows, nil + return eq.rows, err +} + +func argMatcherErrorHandler(errp *error) { + if e := recover(); e != nil { + if se, ok := e.(*reflect.ValueError); ok { // catch reflect error, failed type conversion + *errp = fmt.Errorf("Failed to compare query arguments: %s", se) + } else { + panic(e) // overwise panic + } + } } diff --git a/sqlmock_test.go b/sqlmock_test.go index a7d2d61..ff75017 100644 --- a/sqlmock_test.go +++ b/sqlmock_test.go @@ -420,3 +420,19 @@ func TestRowBuilderAndNilTypes(t *testing.T) { t.Errorf("error '%s' was not expected while closing the database", err) } } + +func TestArgumentReflectValueTypeError(t *testing.T) { + db, err := sql.Open("mock", "") + if err != nil { + t.Errorf("an error '%s' was not expected when opening a stub database connection", err) + } + + rs := NewRows([]string{"id"}).AddRow(1) + + ExpectQuery("SELECT (.+) FROM sales").WithArgs(5.5).WillReturnRows(rs) + + _, err = db.Query("SELECT * FROM sales WHERE x = ?", 5) + if err == nil { + t.Error("Expected error, but got none") + } +}