mirror of
https://github.com/DATA-DOG/go-sqlmock.git
synced 2025-01-07 23:01:44 +02:00
add readme and update error messages
This commit is contained in:
parent
3e67393335
commit
2fc5a0dd15
28
LICENSE
Normal file
28
LICENSE
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
The three clause BSD license (http://en.wikipedia.org/wiki/BSD_licenses)
|
||||||
|
|
||||||
|
Copyright (c) 2013, DataDog.lt team
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* The name DataDog.lt may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
304
README.md
304
README.md
@ -1,10 +1,300 @@
|
|||||||
|
# Sql driver mock for Golang
|
||||||
|
|
||||||
db = mock.Open("test", "")
|
This is a **mock** driver as **database/sql/driver** which is very flexible and pragmatic to
|
||||||
|
manage and mock expected queries. All the expectations should be met and all queries and actions
|
||||||
|
triggered should be mocked in order to pass a test.
|
||||||
|
|
||||||
db.ExpectTransactionBegin()
|
## Install
|
||||||
db.ExpectTransactionBegin().WillReturnError("some error")
|
|
||||||
db.ExpectQuery("SELECT bla").With(5, 8, "stat").WillReturnNone()
|
go get github.com/l3pp4rd/go-sqlmock
|
||||||
db.ExpectExec("UPDATE tbl SET").With(5, "val").WillReturnResult(res /* sql.Result */)
|
|
||||||
db.ExpectExec("INSERT INTO bla").With(5, 8, "stat").WillReturnResult(res /* sql.Result */)
|
## Use it with pleasure
|
||||||
db.ExpectQuery("SELECT bla").With(5, 8, "stat").WillReturnRows()
|
|
||||||
|
An example of some database interaction which you want to test:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/kisielk/sqlstruct"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ORDER_PENDING = 0
|
||||||
|
const ORDER_CANCELLED = 1
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Id int `sql:"id"`
|
||||||
|
Username string `sql:"username"`
|
||||||
|
Balance float64 `sql:"balance"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Order struct {
|
||||||
|
Id int `sql:"id"`
|
||||||
|
Value float64 `sql:"value"`
|
||||||
|
ReservedFee float64 `sql:"reserved_fee"`
|
||||||
|
Status int `sql:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func cancelOrder(id int, db *sql.DB) (err error) {
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var order Order
|
||||||
|
var user User
|
||||||
|
sql := fmt.Sprintf(`
|
||||||
|
SELECT %s, %s
|
||||||
|
FROM orders AS o
|
||||||
|
INNER JOIN users AS u ON o.buyer_id = u.id
|
||||||
|
WHERE o.id = ?
|
||||||
|
FOR UPDATE`,
|
||||||
|
sqlstruct.ColumnsAliased(order, "o"),
|
||||||
|
sqlstruct.ColumnsAliased(user, "u"))
|
||||||
|
|
||||||
|
// fetch order to cancel
|
||||||
|
rows, err := tx.Query(sql, id)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer rows.Close()
|
||||||
|
// no rows, nothing to do
|
||||||
|
if !rows.Next() {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// read order
|
||||||
|
err = sqlstruct.ScanAliased(&order, rows, "o")
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure order status
|
||||||
|
if order.Status != ORDER_PENDING {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// read user
|
||||||
|
err = sqlstruct.ScanAliased(&user, rows, "u")
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rows.Close() // manually close before other prepared statements
|
||||||
|
|
||||||
|
// refund order value
|
||||||
|
sql = "UPDATE users SET balance = balance + ? WHERE id = ?"
|
||||||
|
refundStmt, err := tx.Prepare(sql)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer refundStmt.Close()
|
||||||
|
_, err = refundStmt.Exec(order.Value + order.ReservedFee, user.Id)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// update order status
|
||||||
|
order.Status = ORDER_CANCELLED
|
||||||
|
sql = "UPDATE orders SET status = ?, updated = NOW() WHERE id = ?"
|
||||||
|
orderUpdStmt, err := tx.Prepare(sql)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer orderUpdStmt.Close()
|
||||||
|
_, err = orderUpdStmt.Exec(order.Status, order.Id)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return tx.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
db, err := sql.Open("mysql", "root:nimda@/test")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
err = cancelOrder(1, db)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And the clean nice test:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"github.com/l3pp4rd/go-sqlmock"
|
||||||
|
"testing"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// will test that order with a different status, cannot be cancelled
|
||||||
|
func TestShouldNotCancelOrderWithNonPendingStatus(t *testing.T) {
|
||||||
|
// open database stub
|
||||||
|
db, err := sql.Open("mock", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("An error '%s' was not expected when opening a stub database connection", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// columns are prefixed with "o" since we used sqlstruct to generate them
|
||||||
|
columns := []string{"o_id", "o_status"}
|
||||||
|
// expect transaction begin
|
||||||
|
sqlmock.ExpectBegin()
|
||||||
|
// expect query to fetch order and user, match it with regexp
|
||||||
|
sqlmock.ExpectQuery("SELECT (.+) FROM orders AS o INNER JOIN users AS u (.+) FOR UPDATE").
|
||||||
|
WithArgs(1).
|
||||||
|
WillReturnRows(sqlmock.RowsFromCSVString(columns, "1,1"))
|
||||||
|
// expect transaction rollback, since order status is "cancelled"
|
||||||
|
sqlmock.ExpectRollback()
|
||||||
|
|
||||||
|
// run the cancel order function
|
||||||
|
err = cancelOrder(1, db)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, but got %s instead", err)
|
||||||
|
}
|
||||||
|
// db.Close() ensures that all expectations have been met
|
||||||
|
if err = db.Close(); err != nil {
|
||||||
|
t.Errorf("Error '%s' was not expected while closing the database", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// will test order cancellation
|
||||||
|
func TestShouldRefundUserWhenOrderIsCancelled(t *testing.T) {
|
||||||
|
// open database stub
|
||||||
|
db, err := sql.Open("mock", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("An error '%s' was not expected when opening a stub database connection", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// columns are prefixed with "o" since we used sqlstruct to generate them
|
||||||
|
columns := []string{"o_id", "o_status", "o_value", "o_reserved_fee", "u_id", "u_balance"}
|
||||||
|
// expect transaction begin
|
||||||
|
sqlmock.ExpectBegin()
|
||||||
|
// expect query to fetch order and user, match it with regexp
|
||||||
|
sqlmock.ExpectQuery("SELECT (.+) FROM orders AS o INNER JOIN users AS u (.+) FOR UPDATE").
|
||||||
|
WithArgs(1).
|
||||||
|
WillReturnRows(sqlmock.RowsFromCSVString(columns, "1,0,25.75,3.25,2,10.00"))
|
||||||
|
// expect user balance update
|
||||||
|
sqlmock.ExpectExec("UPDATE users SET balance").
|
||||||
|
WithArgs(25.75 + 3.25, 2). // refund amount, user id
|
||||||
|
WillReturnResult(sqlmock.NewResult(0, 1)) // no insert id, 1 affected row
|
||||||
|
// expect order status update
|
||||||
|
sqlmock.ExpectExec("UPDATE orders SET status").
|
||||||
|
WithArgs(ORDER_CANCELLED, 1). // status, id
|
||||||
|
WillReturnResult(sqlmock.NewResult(0, 1)) // no insert id, 1 affected row
|
||||||
|
// expect a transaction commit
|
||||||
|
sqlmock.ExpectCommit()
|
||||||
|
|
||||||
|
// run the cancel order function
|
||||||
|
err = cancelOrder(1, db)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, but got %s instead", err)
|
||||||
|
}
|
||||||
|
// db.Close() ensures that all expectations have been met
|
||||||
|
if err = db.Close(); err != nil {
|
||||||
|
t.Errorf("Error '%s' was not expected while closing the database", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// will test order cancellation
|
||||||
|
func TestShouldRollbackOnError(t *testing.T) {
|
||||||
|
// open database stub
|
||||||
|
db, err := sql.Open("mock", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("An error '%s' was not expected when opening a stub database connection", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect transaction begin
|
||||||
|
sqlmock.ExpectBegin()
|
||||||
|
// expect query to fetch order and user, match it with regexp
|
||||||
|
sqlmock.ExpectQuery("SELECT (.+) FROM orders AS o INNER JOIN users AS u (.+) FOR UPDATE").
|
||||||
|
WithArgs(1).
|
||||||
|
WillReturnError(fmt.Errorf("Some error"))
|
||||||
|
// should rollback since error was returned from query execution
|
||||||
|
sqlmock.ExpectRollback()
|
||||||
|
|
||||||
|
// run the cancel order function
|
||||||
|
err = cancelOrder(1, db)
|
||||||
|
// error should return back
|
||||||
|
if err == nil {
|
||||||
|
t.Error("Expected error, but got none")
|
||||||
|
}
|
||||||
|
// db.Close() ensures that all expectations have been met
|
||||||
|
if err = db.Close(); err != nil {
|
||||||
|
t.Errorf("Error '%s' was not expected while closing the database", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expectations
|
||||||
|
|
||||||
|
All **Expect** methods return a **Mock** interface which allow you to describe
|
||||||
|
expectations in more details: return an error, expect specific arguments, return rows and so on.
|
||||||
|
**NOTE:** that if you call **WithArgs** on a non query based expectation, it will panic
|
||||||
|
|
||||||
|
A **Mock** interface:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
type Mock interface {
|
||||||
|
WithArgs(...driver.Value) Mock
|
||||||
|
WillReturnError(error) Mock
|
||||||
|
WillReturnRows(driver.Rows) Mock
|
||||||
|
WillReturnResult(driver.Result) Mock
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
As an example we can expect a transaction commit and simulate an error for it:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
sqlmock.ExpectCommit().WillReturnError(fmt.Errorf("Deadlock occured"))
|
||||||
|
```
|
||||||
|
|
||||||
|
In same fashion, we can expect queries to match arguments. If there are any, it must be matched.
|
||||||
|
Instead of result we can return error..
|
||||||
|
|
||||||
|
``` go
|
||||||
|
sqlmock.ExpectQuery("SELECT (.*) FROM orders").
|
||||||
|
WithArgs("string value").
|
||||||
|
WillReturnResult(sqlmock.NewResult(0, 1))
|
||||||
|
```
|
||||||
|
|
||||||
|
**WithArgs** expectation, compares values based on their type, for usual values like **string, float, int**
|
||||||
|
it matches the actual value. Types like **time** are compared only by type. Other types might require different ways
|
||||||
|
to compare them correctly, this may be improved.
|
||||||
|
|
||||||
|
## Run tests
|
||||||
|
|
||||||
|
go test
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- export to godoc
|
||||||
|
- handle argument comparison more efficiently
|
||||||
|
|
||||||
|
## Contributions
|
||||||
|
|
||||||
|
Feel free to open a pull request.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The [three clause BSD license](http://en.wikipedia.org/wiki/BSD_licenses)
|
||||||
|
|
||||||
|
@ -41,9 +41,9 @@ func (e *queryBasedExpectation) argsMatches(args []driver.Value) bool {
|
|||||||
if len(args) != len(e.args) {
|
if len(args) != len(e.args) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for k, v := range e.args {
|
for k, v := range args {
|
||||||
vi := reflect.ValueOf(v)
|
vi := reflect.ValueOf(v)
|
||||||
ai := reflect.ValueOf(args[k])
|
ai := reflect.ValueOf(e.args[k])
|
||||||
switch vi.Kind() {
|
switch vi.Kind() {
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
if vi.Int() != ai.Int() {
|
if vi.Int() != ai.Int() {
|
||||||
|
2
rows.go
2
rows.go
@ -54,7 +54,7 @@ func RowsFromCSVString(columns []string, s string) driver.Rows {
|
|||||||
row := make([]driver.Value, len(columns))
|
row := make([]driver.Value, len(columns))
|
||||||
for i, v := range r {
|
for i, v := range r {
|
||||||
v := strings.TrimSpace(v)
|
v := strings.TrimSpace(v)
|
||||||
row[i] = v
|
row[i] = []byte(v)
|
||||||
}
|
}
|
||||||
rs.rows = append(rs.rows, row)
|
rs.rows = append(rs.rows, row)
|
||||||
}
|
}
|
||||||
|
38
sqlmock.go
38
sqlmock.go
@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var mock *mockDriver
|
var mock *mockDriver
|
||||||
@ -35,10 +36,17 @@ type conn struct {
|
|||||||
active expectation
|
active expectation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stripQuery(q string) (s string) {
|
||||||
|
s = strings.Replace(q, "\n", " ", -1)
|
||||||
|
s = strings.Replace(s, "\r", "", -1)
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (c *conn) Close() (err error) {
|
func (c *conn) Close() (err error) {
|
||||||
for _, e := range mock.conn.expectations {
|
for _, e := range mock.conn.expectations {
|
||||||
if !e.fulfilled() {
|
if !e.fulfilled() {
|
||||||
err = errors.New(fmt.Sprintf("There is expectation %+v which was not matched yet", e))
|
err = errors.New(fmt.Sprintf("There is a remaining expectation %T which was not matched yet", e))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +89,7 @@ func (c *conn) Begin() (driver.Tx, error) {
|
|||||||
|
|
||||||
etb, ok := e.(*expectedBegin)
|
etb, ok := e.(*expectedBegin)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New(fmt.Sprintf("Call to Begin transaction, was not expected, next expectation is %v", e))
|
return nil, errors.New(fmt.Sprintf("Call to Begin transaction, was not expected, next expectation is %+v", e))
|
||||||
}
|
}
|
||||||
etb.triggered = true
|
etb.triggered = true
|
||||||
return &transaction{c}, etb.err
|
return &transaction{c}, etb.err
|
||||||
@ -99,13 +107,14 @@ func (c *conn) next() (e expectation) {
|
|||||||
|
|
||||||
func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
|
func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
|
||||||
e := c.next()
|
e := c.next()
|
||||||
|
query = stripQuery(query)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return nil, errors.New(fmt.Sprintf("All expectations were already fulfilled, call to Exec '%s' query with args [%v] was not expected", query, args))
|
return nil, errors.New(fmt.Sprintf("All expectations were already fulfilled, call to Exec '%s' query with args %+v was not expected", query, args))
|
||||||
}
|
}
|
||||||
|
|
||||||
eq, ok := e.(*expectedExec)
|
eq, ok := e.(*expectedExec)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New(fmt.Sprintf("Call to Exec query '%s' with args [%v], was not expected, next expectation is %v", query, args, e))
|
return nil, errors.New(fmt.Sprintf("Call to Exec query '%s' with args %+v, was not expected, next expectation is %+v", query, args, e))
|
||||||
}
|
}
|
||||||
|
|
||||||
eq.triggered = true
|
eq.triggered = true
|
||||||
@ -114,15 +123,15 @@ func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if eq.result == nil {
|
if eq.result == nil {
|
||||||
return nil, errors.New(fmt.Sprintf("Exec query '%s' with args [%v], must return a database/sql/driver.Result, but it was not set for expectation %v", query, args, eq))
|
return nil, errors.New(fmt.Sprintf("Exec query '%s' with args %+v, must return a database/sql/driver.Result, but it was not set for expectation %+v", query, args, eq))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !eq.queryMatches(query) {
|
if !eq.queryMatches(query) {
|
||||||
return nil, errors.New(fmt.Sprintf("Exec query '%s', does not match regex [%s]", query, eq.sqlRegex.String()))
|
return nil, errors.New(fmt.Sprintf("Exec query '%s', does not match regex '%s'", query, eq.sqlRegex.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !eq.argsMatches(args) {
|
if !eq.argsMatches(args) {
|
||||||
return nil, errors.New(fmt.Sprintf("Exec query '%s', args [%v] does not match expected [%v]", query, args, eq.args))
|
return nil, errors.New(fmt.Sprintf("Exec query '%s', args %+v does not match expected %+v", query, args, eq.args))
|
||||||
}
|
}
|
||||||
|
|
||||||
return eq.result, nil
|
return eq.result, nil
|
||||||
@ -162,7 +171,7 @@ func (c *conn) WithArgs(args ...driver.Value) Mock {
|
|||||||
func (c *conn) WillReturnResult(result driver.Result) Mock {
|
func (c *conn) WillReturnResult(result driver.Result) Mock {
|
||||||
eq, ok := c.active.(*expectedExec)
|
eq, ok := c.active.(*expectedExec)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("driver.Result may be returned only by Exec expectations, current is %v", c.active))
|
panic(fmt.Sprintf("driver.Result may be returned only by Exec expectations, current is %+v", c.active))
|
||||||
}
|
}
|
||||||
eq.result = result
|
eq.result = result
|
||||||
return c
|
return c
|
||||||
@ -171,25 +180,26 @@ func (c *conn) WillReturnResult(result driver.Result) Mock {
|
|||||||
func (c *conn) WillReturnRows(rows driver.Rows) Mock {
|
func (c *conn) WillReturnRows(rows driver.Rows) Mock {
|
||||||
eq, ok := c.active.(*expectedQuery)
|
eq, ok := c.active.(*expectedQuery)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("driver.Rows may be returned only by Query expectations, current is %v", c.active))
|
panic(fmt.Sprintf("driver.Rows may be returned only by Query expectations, current is %+v", c.active))
|
||||||
}
|
}
|
||||||
eq.rows = rows
|
eq.rows = rows
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) Prepare(query string) (driver.Stmt, error) {
|
func (c *conn) Prepare(query string) (driver.Stmt, error) {
|
||||||
return &statement{c, query}, nil
|
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) (driver.Rows, error) {
|
||||||
e := c.next()
|
e := c.next()
|
||||||
|
query = stripQuery(query)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return nil, errors.New(fmt.Sprintf("All expectations were already fulfilled, call to Query '%s' with args [%v] was not expected", query, args))
|
return nil, errors.New(fmt.Sprintf("All expectations were already fulfilled, call to Query '%s' with args %+v was not expected", query, args))
|
||||||
}
|
}
|
||||||
|
|
||||||
eq, ok := e.(*expectedQuery)
|
eq, ok := e.(*expectedQuery)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New(fmt.Sprintf("Call to Query '%s' with args [%v], was not expected, next expectation is %v", query, args, e))
|
return nil, errors.New(fmt.Sprintf("Call to Query '%s' with args %+v, was not expected, next expectation is %+v", query, args, e))
|
||||||
}
|
}
|
||||||
|
|
||||||
eq.triggered = true
|
eq.triggered = true
|
||||||
@ -198,7 +208,7 @@ func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if eq.rows == nil {
|
if eq.rows == nil {
|
||||||
return nil, errors.New(fmt.Sprintf("Query '%s' with args [%v], must return a database/sql/driver.Rows, but it was not set for expectation %v", query, args, eq))
|
return nil, errors.New(fmt.Sprintf("Query '%s' with args %+v, must return a database/sql/driver.Rows, but it was not set for expectation %+v", query, args, eq))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !eq.queryMatches(query) {
|
if !eq.queryMatches(query) {
|
||||||
@ -206,7 +216,7 @@ func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !eq.argsMatches(args) {
|
if !eq.argsMatches(args) {
|
||||||
return nil, errors.New(fmt.Sprintf("Query '%s', args [%v] does not match expected [%v]", query, args, eq.args))
|
return nil, errors.New(fmt.Sprintf("Query '%s', args %+v does not match expected %+v", query, args, eq.args))
|
||||||
}
|
}
|
||||||
|
|
||||||
return eq.rows, nil
|
return eq.rows, nil
|
||||||
|
@ -10,7 +10,6 @@ type statement struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (stmt *statement) Close() error {
|
func (stmt *statement) Close() error {
|
||||||
stmt.conn = nil
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user