You've already forked go-sqlmock
							
							
				mirror of
				https://github.com/DATA-DOG/go-sqlmock.git
				synced 2025-10-30 23:47:46 +02:00 
			
		
		
		
	add readme and update error messages
This commit is contained in:
		
							
								
								
									
										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() | ||||
| db.ExpectTransactionBegin().WillReturnError("some error") | ||||
| db.ExpectQuery("SELECT bla").With(5, 8, "stat").WillReturnNone() | ||||
| 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 */) | ||||
| db.ExpectQuery("SELECT bla").With(5, 8, "stat").WillReturnRows() | ||||
| ## Install | ||||
|  | ||||
|     go get github.com/l3pp4rd/go-sqlmock | ||||
|  | ||||
| ## Use it with pleasure | ||||
|  | ||||
| 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) { | ||||
| 		return false | ||||
| 	} | ||||
| 	for k, v := range e.args { | ||||
| 	for k, v := range args { | ||||
| 		vi := reflect.ValueOf(v) | ||||
| 		ai := reflect.ValueOf(args[k]) | ||||
| 		ai := reflect.ValueOf(e.args[k]) | ||||
| 		switch vi.Kind() { | ||||
| 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 			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)) | ||||
| 		for i, v := range r { | ||||
| 			v := strings.TrimSpace(v) | ||||
| 			row[i] = v | ||||
| 			row[i] = []byte(v) | ||||
| 		} | ||||
| 		rs.rows = append(rs.rows, row) | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										38
									
								
								sqlmock.go
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								sqlmock.go
									
									
									
									
									
								
							| @@ -6,6 +6,7 @@ import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| var mock *mockDriver | ||||
| @@ -35,10 +36,17 @@ type conn struct { | ||||
| 	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) { | ||||
| 	for _, e := range mock.conn.expectations { | ||||
| 		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 | ||||
| 		} | ||||
| 	} | ||||
| @@ -81,7 +89,7 @@ func (c *conn) Begin() (driver.Tx, error) { | ||||
|  | ||||
| 	etb, ok := e.(*expectedBegin) | ||||
| 	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 | ||||
| 	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) { | ||||
| 	e := c.next() | ||||
| 	query = stripQuery(query) | ||||
| 	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) | ||||
| 	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 | ||||
| @@ -114,15 +123,15 @@ func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) { | ||||
| 	} | ||||
|  | ||||
| 	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) { | ||||
| 		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) { | ||||
| 		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 | ||||
| @@ -162,7 +171,7 @@ func (c *conn) WithArgs(args ...driver.Value) Mock { | ||||
| func (c *conn) WillReturnResult(result driver.Result) Mock { | ||||
| 	eq, ok := c.active.(*expectedExec) | ||||
| 	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 | ||||
| 	return c | ||||
| @@ -171,25 +180,26 @@ func (c *conn) WillReturnResult(result driver.Result) Mock { | ||||
| func (c *conn) WillReturnRows(rows driver.Rows) Mock { | ||||
| 	eq, ok := c.active.(*expectedQuery) | ||||
| 	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 | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| 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) { | ||||
| 	e := c.next() | ||||
| 	query = stripQuery(query) | ||||
| 	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) | ||||
| 	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 | ||||
| @@ -198,7 +208,7 @@ func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) { | ||||
| 	} | ||||
|  | ||||
| 	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) { | ||||
| @@ -206,7 +216,7 @@ func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) { | ||||
| 	} | ||||
|  | ||||
| 	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 | ||||
|   | ||||
| @@ -10,7 +10,6 @@ type statement struct { | ||||
| } | ||||
|  | ||||
| func (stmt *statement) Close() error { | ||||
| 	stmt.conn = nil | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user