mirror of https://github.com/docker/docs.git
adding sqlmock godep
Signed-off-by: David Lawrence <david.lawrence@docker.com> (github: endophage)
This commit is contained in:
parent
6533da1be4
commit
81ab80d0bf
|
@ -9,6 +9,11 @@
|
||||||
"ImportPath": "github.com/BurntSushi/toml",
|
"ImportPath": "github.com/BurntSushi/toml",
|
||||||
"Rev": "bd2bdf7f18f849530ef7a1c29a4290217cab32a1"
|
"Rev": "bd2bdf7f18f849530ef7a1c29a4290217cab32a1"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/DATA-DOG/go-sqlmock",
|
||||||
|
"Comment": "0.1.0-8-ged4836e",
|
||||||
|
"Rev": "ed4836e31d3e9e77420e442ed9b864df55370ee0"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/Sirupsen/logrus",
|
"ImportPath": "github.com/Sirupsen/logrus",
|
||||||
"Comment": "v0.7.3",
|
"Comment": "v0.7.3",
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
/*.test
|
|
@ -0,0 +1,16 @@
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.2
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- release
|
||||||
|
- tip
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go get github.com/kisielk/errcheck
|
||||||
|
- go get ./...
|
||||||
|
|
||||||
|
- go test -v ./...
|
||||||
|
- go test -race ./...
|
||||||
|
- errcheck github.com/DATA-DOG/go-sqlmock
|
||||||
|
|
|
@ -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.
|
|
@ -0,0 +1,360 @@
|
||||||
|
[](https://travis-ci.org/DATA-DOG/go-sqlmock)
|
||||||
|
[](https://godoc.org/github.com/DATA-DOG/go-sqlmock)
|
||||||
|
|
||||||
|
# Sql driver mock for Golang
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
go get github.com/DATA-DOG/go-sqlmock
|
||||||
|
|
||||||
|
## Use it with pleasure
|
||||||
|
|
||||||
|
An example of some database interaction which you may 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/DATA-DOG/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 := sqlmock.New()
|
||||||
|
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.NewRows(columns).FromCSVString("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 := sqlmock.New()
|
||||||
|
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.NewRows(columns).AddRow(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 := sqlmock.New()
|
||||||
|
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").
|
||||||
|
WillReturnRows(sqlmock.NewRows([]string{"col"}).AddRow("val"))
|
||||||
|
```
|
||||||
|
|
||||||
|
**NOTE:** it matches a regular expression. Some regex special characters must be escaped if you want to match them.
|
||||||
|
For example if we want to match a subselect:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
sqlmock.ExpectQuery("SELECT (.*) FROM orders WHERE id IN \\(SELECT id FROM finished WHERE status = 1\\)").
|
||||||
|
WithArgs("string value").
|
||||||
|
WillReturnRows(sqlmock.NewRows([]string{"col"}).AddRow("val"))
|
||||||
|
```
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|
||||||
|
You can build rows either from CSV string or from interface values:
|
||||||
|
|
||||||
|
**Rows** interface, which satisfies sql driver.Rows:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
type Rows interface {
|
||||||
|
AddRow(...driver.Value) Rows
|
||||||
|
FromCSVString(s string) Rows
|
||||||
|
Next([]driver.Value) error
|
||||||
|
Columns() []string
|
||||||
|
Close() error
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example for to build rows:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
rs := sqlmock.NewRows([]string{"column1", "column2"}).
|
||||||
|
FromCSVString("one,1\ntwo,2").
|
||||||
|
AddRow("three", 3)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Prepare** will ignore other expectations if ExpectPrepare not set. When set, can expect normal result or simulate an error:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
rs := sqlmock.ExpectPrepare().
|
||||||
|
WillReturnError(fmt.Errorf("Query prepare failed"))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run tests
|
||||||
|
|
||||||
|
go test
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Visit [godoc](http://godoc.org/github.com/DATA-DOG/go-sqlmock)
|
||||||
|
See **.travis.yml** for supported **go** versions
|
||||||
|
Different use case, is to functionally test with a real database - [go-txdb](https://github.com/DATA-DOG/go-txdb)
|
||||||
|
all database related actions are isolated within a single transaction so the database can remain in the same state.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
- **2014-04-21** introduce **sqlmock.New()** to open a mock database connection for tests. This method
|
||||||
|
calls sql.DB.Ping to ensure that connection is open, see [issue](https://github.com/DATA-DOG/go-sqlmock/issues/4).
|
||||||
|
This way on Close it will surely assert if all expectations are met, even if database was not triggered at all.
|
||||||
|
The old way is still available, but it is advisable to call db.Ping manually before asserting with db.Close.
|
||||||
|
- **2014-02-14** RowsFromCSVString is now a part of Rows interface named as FromCSVString.
|
||||||
|
It has changed to allow more ways to construct rows and to easily extend this API in future.
|
||||||
|
See [issue 1](https://github.com/DATA-DOG/go-sqlmock/issues/1)
|
||||||
|
**RowsFromCSVString** is deprecated and will be removed in future
|
||||||
|
|
||||||
|
## Contributions
|
||||||
|
|
||||||
|
Feel free to open a pull request. Note, if you wish to contribute an extension to public (exported methods or types) -
|
||||||
|
please open an issue before, to discuss whether these changes can be accepted. All backward incompatible changes are
|
||||||
|
and will be treated cautiously
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The [three clause BSD license](http://en.wikipedia.org/wiki/BSD_licenses)
|
||||||
|
|
151
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/connection.go
generated
vendored
Normal file
151
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/connection.go
generated
vendored
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type conn struct {
|
||||||
|
expectations []expectation
|
||||||
|
active expectation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close a mock database driver connection. It should
|
||||||
|
// be always called to ensure that all expectations
|
||||||
|
// were met successfully. Returns error if there is any
|
||||||
|
func (c *conn) Close() (err error) {
|
||||||
|
for _, e := range mock.conn.expectations {
|
||||||
|
if !e.fulfilled() {
|
||||||
|
err = fmt.Errorf("there is a remaining expectation %T which was not matched yet", e)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mock.conn.expectations = []expectation{}
|
||||||
|
mock.conn.active = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) Begin() (driver.Tx, error) {
|
||||||
|
e := c.next()
|
||||||
|
if e == nil {
|
||||||
|
return nil, fmt.Errorf("all expectations were already fulfilled, call to begin transaction was not expected")
|
||||||
|
}
|
||||||
|
|
||||||
|
etb, ok := e.(*expectedBegin)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("call to begin transaction, was not expected, next expectation is %T as %+v", e, e)
|
||||||
|
}
|
||||||
|
etb.triggered = true
|
||||||
|
return &transaction{c}, etb.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// get next unfulfilled expectation
|
||||||
|
func (c *conn) next() (e expectation) {
|
||||||
|
for _, e = range c.expectations {
|
||||||
|
if !e.fulfilled() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil // all expectations were fulfilled
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) Exec(query string, args []driver.Value) (res driver.Result, err error) {
|
||||||
|
e := c.next()
|
||||||
|
query = stripQuery(query)
|
||||||
|
if e == nil {
|
||||||
|
return nil, fmt.Errorf("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, fmt.Errorf("call to exec query '%s' with args %+v, was not expected, next expectation is %T as %+v", query, args, e, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
eq.triggered = true
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !eq.argsMatches(args) {
|
||||||
|
return nil, fmt.Errorf("exec query '%s', args %+v does not match expected %+v", query, args, eq.args)
|
||||||
|
}
|
||||||
|
|
||||||
|
if eq.err != nil {
|
||||||
|
return nil, eq.err // mocked to return error
|
||||||
|
}
|
||||||
|
|
||||||
|
if eq.result == nil {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
return eq.result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) Prepare(query string) (driver.Stmt, error) {
|
||||||
|
e := c.next()
|
||||||
|
|
||||||
|
// for backwards compatibility, ignore when Prepare not expected
|
||||||
|
if e == nil {
|
||||||
|
return &statement{mock.conn, stripQuery(query)}, nil
|
||||||
|
}
|
||||||
|
eq, ok := e.(*expectedPrepare)
|
||||||
|
if !ok {
|
||||||
|
return &statement{mock.conn, stripQuery(query)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
eq.triggered = true
|
||||||
|
if eq.err != nil {
|
||||||
|
return nil, eq.err // mocked to return error
|
||||||
|
}
|
||||||
|
|
||||||
|
return &statement{mock.conn, stripQuery(query)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) Query(query string, args []driver.Value) (rw driver.Rows, err error) {
|
||||||
|
e := c.next()
|
||||||
|
query = stripQuery(query)
|
||||||
|
if e == nil {
|
||||||
|
return nil, fmt.Errorf("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, fmt.Errorf("call to query '%s' with args %+v, was not expected, next expectation is %T as %+v", query, args, e, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
eq.triggered = true
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !eq.argsMatches(args) {
|
||||||
|
return nil, fmt.Errorf("query '%s', args %+v does not match expected %+v", query, args, eq.args)
|
||||||
|
}
|
||||||
|
|
||||||
|
if eq.err != nil {
|
||||||
|
return nil, eq.err // mocked to return error
|
||||||
|
}
|
||||||
|
|
||||||
|
if eq.rows == nil {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
378
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/connection_test.go
generated
vendored
Normal file
378
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/connection_test.go
generated
vendored
Normal file
|
@ -0,0 +1,378 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"errors"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExecNoExpectations(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedExec{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{
|
||||||
|
triggered: true,
|
||||||
|
err: errors.New("WillReturnError"),
|
||||||
|
},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("otherquery")),
|
||||||
|
args: []driver.Value{456},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Exec("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Result should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
pattern := regexp.MustCompile(regexp.QuoteMeta("all expectations were already fulfilled, call to exec"))
|
||||||
|
if !pattern.MatchString(err.Error()) {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecExpectationMismatch(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedQuery{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{
|
||||||
|
err: errors.New("WillReturnError"),
|
||||||
|
},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("otherquery")),
|
||||||
|
args: []driver.Value{456},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Exec("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Result should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
pattern := regexp.MustCompile(regexp.QuoteMeta("was not expected, next expectation is"))
|
||||||
|
if !pattern.MatchString(err.Error()) {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecQueryMismatch(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedExec{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{
|
||||||
|
err: errors.New("WillReturnError"),
|
||||||
|
},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("otherquery")),
|
||||||
|
args: []driver.Value{456},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Exec("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Result should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
pattern := regexp.MustCompile(regexp.QuoteMeta("does not match regex"))
|
||||||
|
if !pattern.MatchString(err.Error()) {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecArgsMismatch(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedExec{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{
|
||||||
|
err: errors.New("WillReturnError"),
|
||||||
|
},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("query")),
|
||||||
|
args: []driver.Value{456},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Exec("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Result should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
pattern := regexp.MustCompile(regexp.QuoteMeta("does not match expected"))
|
||||||
|
if !pattern.MatchString(err.Error()) {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecWillReturnError(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedExec{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{
|
||||||
|
err: errors.New("WillReturnError"),
|
||||||
|
},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("query")),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Exec("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Result should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
if err.Error() != "WillReturnError" {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecMissingResult(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedExec{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("query")),
|
||||||
|
args: []driver.Value{123},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Exec("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Result should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
pattern := regexp.MustCompile(regexp.QuoteMeta("must return a database/sql/driver.result, but it was not set for expectation"))
|
||||||
|
if !pattern.MatchString(err.Error()) {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExec(t *testing.T) {
|
||||||
|
expectedResult := driver.Result(&result{})
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedExec{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("query")),
|
||||||
|
args: []driver.Value{123},
|
||||||
|
},
|
||||||
|
result: expectedResult,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Exec("query", []driver.Value{123})
|
||||||
|
if res == nil {
|
||||||
|
t.Error("Result should not be nil")
|
||||||
|
}
|
||||||
|
if res != expectedResult {
|
||||||
|
t.Errorf("Result should match expected Result (actual %+v)", res)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error should be nil (actual %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQueryNoExpectations(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedQuery{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{
|
||||||
|
triggered: true,
|
||||||
|
err: errors.New("WillReturnError"),
|
||||||
|
},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("otherquery")),
|
||||||
|
args: []driver.Value{456},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Query("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Rows should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
pattern := regexp.MustCompile(regexp.QuoteMeta("all expectations were already fulfilled, call to query"))
|
||||||
|
if !pattern.MatchString(err.Error()) {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQueryExpectationMismatch(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedExec{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{
|
||||||
|
err: errors.New("WillReturnError"),
|
||||||
|
},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("otherquery")),
|
||||||
|
args: []driver.Value{456},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Query("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Rows should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
pattern := regexp.MustCompile(regexp.QuoteMeta("was not expected, next expectation is"))
|
||||||
|
if !pattern.MatchString(err.Error()) {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQueryQueryMismatch(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedQuery{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{
|
||||||
|
err: errors.New("WillReturnError"),
|
||||||
|
},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("otherquery")),
|
||||||
|
args: []driver.Value{456},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Query("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Rows should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
pattern := regexp.MustCompile(regexp.QuoteMeta("does not match regex"))
|
||||||
|
if !pattern.MatchString(err.Error()) {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQueryArgsMismatch(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedQuery{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{
|
||||||
|
err: errors.New("WillReturnError"),
|
||||||
|
},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("query")),
|
||||||
|
args: []driver.Value{456},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Query("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Rows should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
pattern := regexp.MustCompile(regexp.QuoteMeta("does not match expected"))
|
||||||
|
if !pattern.MatchString(err.Error()) {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQueryWillReturnError(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedQuery{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{
|
||||||
|
err: errors.New("WillReturnError"),
|
||||||
|
},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("query")),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Query("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Rows should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
if err.Error() != "WillReturnError" {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQueryMissingRows(t *testing.T) {
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedQuery{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("query")),
|
||||||
|
args: []driver.Value{123},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res, err := c.Query("query", []driver.Value{123})
|
||||||
|
if res != nil {
|
||||||
|
t.Error("Rows should be nil")
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error should not be nil")
|
||||||
|
}
|
||||||
|
pattern := regexp.MustCompile(regexp.QuoteMeta("must return a database/sql/driver.rows, but it was not set for expectation"))
|
||||||
|
if !pattern.MatchString(err.Error()) {
|
||||||
|
t.Errorf("error should match expected error message (actual: %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQuery(t *testing.T) {
|
||||||
|
expectedRows := driver.Rows(&rows{})
|
||||||
|
c := &conn{
|
||||||
|
expectations: []expectation{
|
||||||
|
&expectedQuery{
|
||||||
|
queryBasedExpectation: queryBasedExpectation{
|
||||||
|
commonExpectation: commonExpectation{},
|
||||||
|
sqlRegex: regexp.MustCompile(regexp.QuoteMeta("query")),
|
||||||
|
args: []driver.Value{123},
|
||||||
|
},
|
||||||
|
rows: expectedRows,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rows, err := c.Query("query", []driver.Value{123})
|
||||||
|
if rows == nil {
|
||||||
|
t.Error("Rows should not be nil")
|
||||||
|
}
|
||||||
|
if rows != expectedRows {
|
||||||
|
t.Errorf("Rows should match expected Rows (actual %+v)", rows)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error should be nil (actual %s)", err.Error())
|
||||||
|
}
|
||||||
|
}
|
126
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/expectations.go
generated
vendored
Normal file
126
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/expectations.go
generated
vendored
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Argument interface allows to match
|
||||||
|
// any argument in specific way
|
||||||
|
type Argument interface {
|
||||||
|
Match(driver.Value) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// an expectation interface
|
||||||
|
type expectation interface {
|
||||||
|
fulfilled() bool
|
||||||
|
setError(err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// common expectation struct
|
||||||
|
// satisfies the expectation interface
|
||||||
|
type commonExpectation struct {
|
||||||
|
triggered bool
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *commonExpectation) fulfilled() bool {
|
||||||
|
return e.triggered
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *commonExpectation) setError(err error) {
|
||||||
|
e.err = err
|
||||||
|
}
|
||||||
|
|
||||||
|
// query based expectation
|
||||||
|
// adds a query matching logic
|
||||||
|
type queryBasedExpectation struct {
|
||||||
|
commonExpectation
|
||||||
|
sqlRegex *regexp.Regexp
|
||||||
|
args []driver.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *queryBasedExpectation) queryMatches(sql string) bool {
|
||||||
|
return e.sqlRegex.MatchString(sql)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *queryBasedExpectation) argsMatches(args []driver.Value) bool {
|
||||||
|
if nil == e.args {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if len(args) != len(e.args) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for k, v := range args {
|
||||||
|
matcher, ok := e.args[k].(Argument)
|
||||||
|
if ok {
|
||||||
|
if !matcher.Match(v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vi := reflect.ValueOf(v)
|
||||||
|
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() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
if vi.Float() != ai.Float() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
if vi.Uint() != ai.Uint() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
if vi.String() != ai.String() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// compare types like time.Time based on type only
|
||||||
|
if vi.Kind() != ai.Kind() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// begin transaction
|
||||||
|
type expectedBegin struct {
|
||||||
|
commonExpectation
|
||||||
|
}
|
||||||
|
|
||||||
|
// tx commit
|
||||||
|
type expectedCommit struct {
|
||||||
|
commonExpectation
|
||||||
|
}
|
||||||
|
|
||||||
|
// tx rollback
|
||||||
|
type expectedRollback struct {
|
||||||
|
commonExpectation
|
||||||
|
}
|
||||||
|
|
||||||
|
// query expectation
|
||||||
|
type expectedQuery struct {
|
||||||
|
queryBasedExpectation
|
||||||
|
|
||||||
|
rows driver.Rows
|
||||||
|
}
|
||||||
|
|
||||||
|
// exec query expectation
|
||||||
|
type expectedExec struct {
|
||||||
|
queryBasedExpectation
|
||||||
|
|
||||||
|
result driver.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare expectation
|
||||||
|
type expectedPrepare struct {
|
||||||
|
commonExpectation
|
||||||
|
|
||||||
|
statement driver.Stmt
|
||||||
|
}
|
73
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/expectations_test.go
generated
vendored
Normal file
73
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/expectations_test.go
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type matcher struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m matcher) Match(driver.Value) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQueryExpectationArgComparison(t *testing.T) {
|
||||||
|
e := &queryBasedExpectation{}
|
||||||
|
against := []driver.Value{5}
|
||||||
|
if !e.argsMatches(against) {
|
||||||
|
t.Error("arguments should match, since the no expectation was set")
|
||||||
|
}
|
||||||
|
|
||||||
|
e.args = []driver.Value{5, "str"}
|
||||||
|
|
||||||
|
against = []driver.Value{5}
|
||||||
|
if e.argsMatches(against) {
|
||||||
|
t.Error("arguments should not match, since the size is not the same")
|
||||||
|
}
|
||||||
|
|
||||||
|
against = []driver.Value{3, "str"}
|
||||||
|
if e.argsMatches(against) {
|
||||||
|
t.Error("arguments should not match, since the first argument (int value) is different")
|
||||||
|
}
|
||||||
|
|
||||||
|
against = []driver.Value{5, "st"}
|
||||||
|
if e.argsMatches(against) {
|
||||||
|
t.Error("arguments should not match, since the second argument (string value) is different")
|
||||||
|
}
|
||||||
|
|
||||||
|
against = []driver.Value{5, "str"}
|
||||||
|
if !e.argsMatches(against) {
|
||||||
|
t.Error("arguments should match, but it did not")
|
||||||
|
}
|
||||||
|
|
||||||
|
e.args = []driver.Value{5, time.Now()}
|
||||||
|
|
||||||
|
const longForm = "Jan 2, 2006 at 3:04pm (MST)"
|
||||||
|
tm, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)")
|
||||||
|
|
||||||
|
against = []driver.Value{5, tm}
|
||||||
|
if !e.argsMatches(against) {
|
||||||
|
t.Error("arguments should match (time will be compared only by type), but it did not")
|
||||||
|
}
|
||||||
|
|
||||||
|
against = []driver.Value{5, matcher{}}
|
||||||
|
if !e.argsMatches(against) {
|
||||||
|
t.Error("arguments should match, but it did not")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQueryExpectationSqlMatch(t *testing.T) {
|
||||||
|
e := &expectedExec{}
|
||||||
|
e.sqlRegex = regexp.MustCompile("SELECT x FROM")
|
||||||
|
if !e.queryMatches("SELECT x FROM someting") {
|
||||||
|
t.Errorf("Sql must have matched the query")
|
||||||
|
}
|
||||||
|
|
||||||
|
e.sqlRegex = regexp.MustCompile("SELECT COUNT\\(x\\) FROM")
|
||||||
|
if !e.queryMatches("SELECT COUNT(x) FROM someting") {
|
||||||
|
t.Errorf("Sql must have matched the query")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Result satisfies sql driver Result, which
|
||||||
|
// holds last insert id and rows affected
|
||||||
|
// by Exec queries
|
||||||
|
type result struct {
|
||||||
|
insertID int64
|
||||||
|
rowsAffected int64
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewResult creates a new sql driver Result
|
||||||
|
// for Exec based query mocks.
|
||||||
|
func NewResult(lastInsertID int64, rowsAffected int64) driver.Result {
|
||||||
|
return &result{
|
||||||
|
insertID: lastInsertID,
|
||||||
|
rowsAffected: rowsAffected,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrorResult creates a new sql driver Result
|
||||||
|
// which returns an error given for both interface methods
|
||||||
|
func NewErrorResult(err error) driver.Result {
|
||||||
|
return &result{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *result) LastInsertId() (int64, error) {
|
||||||
|
return r.insertID, r.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *result) RowsAffected() (int64, error) {
|
||||||
|
return r.rowsAffected, r.err
|
||||||
|
}
|
36
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/result_test.go
generated
vendored
Normal file
36
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/result_test.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestShouldReturnValidSqlDriverResult(t *testing.T) {
|
||||||
|
result := NewResult(1, 2)
|
||||||
|
id, err := result.LastInsertId()
|
||||||
|
if 1 != id {
|
||||||
|
t.Errorf("Expected last insert id to be 1, but got: %d", id)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("expected no error, but got: %s", err)
|
||||||
|
}
|
||||||
|
affected, err := result.RowsAffected()
|
||||||
|
if 2 != affected {
|
||||||
|
t.Errorf("Expected affected rows to be 2, but got: %d", affected)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("expected no error, but got: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldReturnErroeSqlDriverResult(t *testing.T) {
|
||||||
|
result := NewErrorResult(fmt.Errorf("some error"))
|
||||||
|
_, err := result.LastInsertId()
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error, but got none")
|
||||||
|
}
|
||||||
|
_, err = result.RowsAffected()
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error, but got none")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"encoding/csv"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Rows interface allows to construct rows
|
||||||
|
// which also satisfies database/sql/driver.Rows interface
|
||||||
|
type Rows interface {
|
||||||
|
driver.Rows // composed interface, supports sql driver.Rows
|
||||||
|
AddRow(...driver.Value) Rows
|
||||||
|
FromCSVString(s string) Rows
|
||||||
|
}
|
||||||
|
|
||||||
|
// a struct which implements database/sql/driver.Rows
|
||||||
|
type rows struct {
|
||||||
|
cols []string
|
||||||
|
rows [][]driver.Value
|
||||||
|
pos int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rows) Columns() []string {
|
||||||
|
return r.cols
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rows) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rows) Err() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// advances to next row
|
||||||
|
func (r *rows) Next(dest []driver.Value) error {
|
||||||
|
r.pos++
|
||||||
|
if r.pos > len(r.rows) {
|
||||||
|
return io.EOF // per interface spec
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, col := range r.rows[r.pos-1] {
|
||||||
|
dest[i] = col
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRows allows Rows to be created from a group of
|
||||||
|
// sql driver.Value or from the CSV string and
|
||||||
|
// to be used as sql driver.Rows
|
||||||
|
func NewRows(columns []string) Rows {
|
||||||
|
return &rows{cols: columns}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRow adds a row which is built from arguments
|
||||||
|
// in the same column order, returns sql driver.Rows
|
||||||
|
// compatible interface
|
||||||
|
func (r *rows) AddRow(values ...driver.Value) Rows {
|
||||||
|
if len(values) != len(r.cols) {
|
||||||
|
panic("Expected number of values to match number of columns")
|
||||||
|
}
|
||||||
|
|
||||||
|
row := make([]driver.Value, len(r.cols))
|
||||||
|
for i, v := range values {
|
||||||
|
row[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
r.rows = append(r.rows, row)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromCSVString adds rows from CSV string.
|
||||||
|
// Returns sql driver.Rows compatible interface
|
||||||
|
func (r *rows) FromCSVString(s string) Rows {
|
||||||
|
res := strings.NewReader(strings.TrimSpace(s))
|
||||||
|
csvReader := csv.NewReader(res)
|
||||||
|
|
||||||
|
for {
|
||||||
|
res, err := csvReader.Read()
|
||||||
|
if err != nil || res == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
row := make([]driver.Value, len(r.cols))
|
||||||
|
for i, v := range res {
|
||||||
|
row[i] = []byte(strings.TrimSpace(v))
|
||||||
|
}
|
||||||
|
r.rows = append(r.rows, row)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// RowsFromCSVString creates Rows from CSV string
|
||||||
|
// to be used for mocked queries. Returns sql driver Rows interface
|
||||||
|
// ** DEPRECATED ** will be removed in the future, use Rows.FromCSVString
|
||||||
|
func RowsFromCSVString(columns []string, s string) driver.Rows {
|
||||||
|
rs := &rows{}
|
||||||
|
rs.cols = columns
|
||||||
|
|
||||||
|
r := strings.NewReader(strings.TrimSpace(s))
|
||||||
|
csvReader := csv.NewReader(r)
|
||||||
|
|
||||||
|
for {
|
||||||
|
r, err := csvReader.Read()
|
||||||
|
if err != nil || r == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
row := make([]driver.Value, len(columns))
|
||||||
|
for i, v := range r {
|
||||||
|
v := strings.TrimSpace(v)
|
||||||
|
row[i] = []byte(v)
|
||||||
|
}
|
||||||
|
rs.rows = append(rs.rows, row)
|
||||||
|
}
|
||||||
|
return rs
|
||||||
|
}
|
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
Package sqlmock provides sql driver mock connecection, which allows to test database,
|
||||||
|
create expectations and ensure the correct execution flow of any database operations.
|
||||||
|
It hooks into Go standard library's database/sql package.
|
||||||
|
|
||||||
|
The package provides convenient methods to mock database queries, transactions and
|
||||||
|
expect the right execution flow, compare query arguments or even return error instead
|
||||||
|
to simulate failures. See the example bellow, which illustrates how convenient it is
|
||||||
|
to work with:
|
||||||
|
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"github.com/DATA-DOG/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 to be used for result
|
||||||
|
columns := []string{"id", "status"}
|
||||||
|
// expect transaction begin
|
||||||
|
sqlmock.ExpectBegin()
|
||||||
|
// expect query to fetch order, match it with regexp
|
||||||
|
sqlmock.ExpectQuery("SELECT (.+) FROM orders (.+) FOR UPDATE").
|
||||||
|
WithArgs(1).
|
||||||
|
WillReturnRows(sqlmock.NewRows(columns).FromCSVString("1,1"))
|
||||||
|
// expect transaction rollback, since order status is "cancelled"
|
||||||
|
sqlmock.ExpectRollback()
|
||||||
|
|
||||||
|
// run the cancel order function
|
||||||
|
someOrderId := 1
|
||||||
|
// call a function which executes expected database operations
|
||||||
|
err = cancelOrder(someOrderId, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mock *mockDriver
|
||||||
|
|
||||||
|
// Mock interface defines a mock which is returned
|
||||||
|
// by any expectation and can be detailed further
|
||||||
|
// with the methods this interface provides
|
||||||
|
type Mock interface {
|
||||||
|
WithArgs(...driver.Value) Mock
|
||||||
|
WillReturnError(error) Mock
|
||||||
|
WillReturnRows(driver.Rows) Mock
|
||||||
|
WillReturnResult(driver.Result) Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockDriver struct {
|
||||||
|
conn *conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *mockDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
|
return mock.conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
mock = &mockDriver{&conn{}}
|
||||||
|
sql.Register("mock", mock)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates sqlmock database connection
|
||||||
|
// and pings it so that all expectations could be
|
||||||
|
// asserted on Close.
|
||||||
|
func New() (db *sql.DB, err error) {
|
||||||
|
db, err = sql.Open("mock", "")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ensure open connection, otherwise Close does not assert expectations
|
||||||
|
return db, db.Ping()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpectBegin expects transaction to be started
|
||||||
|
func ExpectBegin() Mock {
|
||||||
|
e := &expectedBegin{}
|
||||||
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
||||||
|
mock.conn.active = e
|
||||||
|
return mock.conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpectCommit expects transaction to be commited
|
||||||
|
func ExpectCommit() Mock {
|
||||||
|
e := &expectedCommit{}
|
||||||
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
||||||
|
mock.conn.active = e
|
||||||
|
return mock.conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpectRollback expects transaction to be rolled back
|
||||||
|
func ExpectRollback() Mock {
|
||||||
|
e := &expectedRollback{}
|
||||||
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
||||||
|
mock.conn.active = e
|
||||||
|
return mock.conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpectPrepare expects Query to be prepared
|
||||||
|
func ExpectPrepare() Mock {
|
||||||
|
e := &expectedPrepare{}
|
||||||
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
||||||
|
mock.conn.active = e
|
||||||
|
return mock.conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// WillReturnError the expectation will return an error
|
||||||
|
func (c *conn) WillReturnError(err error) Mock {
|
||||||
|
c.active.setError(err)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpectExec expects database Exec to be triggered, which will match
|
||||||
|
// the given query string as a regular expression
|
||||||
|
func ExpectExec(sqlRegexStr string) Mock {
|
||||||
|
e := &expectedExec{}
|
||||||
|
e.sqlRegex = regexp.MustCompile(sqlRegexStr)
|
||||||
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
||||||
|
mock.conn.active = e
|
||||||
|
return mock.conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpectQuery database Query to be triggered, which will match
|
||||||
|
// the given query string as a regular expression
|
||||||
|
func ExpectQuery(sqlRegexStr string) Mock {
|
||||||
|
e := &expectedQuery{}
|
||||||
|
e.sqlRegex = regexp.MustCompile(sqlRegexStr)
|
||||||
|
|
||||||
|
mock.conn.expectations = append(mock.conn.expectations, e)
|
||||||
|
mock.conn.active = e
|
||||||
|
return mock.conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithArgs expectation should be called with given arguments.
|
||||||
|
// Works with Exec and Query expectations
|
||||||
|
func (c *conn) WithArgs(args ...driver.Value) Mock {
|
||||||
|
eq, ok := c.active.(*expectedQuery)
|
||||||
|
if !ok {
|
||||||
|
ee, ok := c.active.(*expectedExec)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("arguments may be expected only with query based expectations, current is %T", c.active))
|
||||||
|
}
|
||||||
|
ee.args = args
|
||||||
|
} else {
|
||||||
|
eq.args = args
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WillReturnResult expectation will return a Result.
|
||||||
|
// Works only with Exec expectations
|
||||||
|
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 %T", c.active))
|
||||||
|
}
|
||||||
|
eq.result = result
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WillReturnRows expectation will return Rows.
|
||||||
|
// Works only with Query expectations
|
||||||
|
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 %T", c.active))
|
||||||
|
}
|
||||||
|
eq.rows = rows
|
||||||
|
return c
|
||||||
|
}
|
532
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/sqlmock_test.go
generated
vendored
Normal file
532
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/sqlmock_test.go
generated
vendored
Normal file
|
@ -0,0 +1,532 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIssue14EscapeSQL(t *testing.T) {
|
||||||
|
db, err := New()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
|
||||||
|
}
|
||||||
|
ExpectExec("INSERT INTO mytable\\(a, b\\)").
|
||||||
|
WithArgs("A", "B").
|
||||||
|
WillReturnResult(NewResult(1, 1))
|
||||||
|
|
||||||
|
_, err = db.Exec("INSERT INTO mytable(a, b) VALUES (?, ?)", "A", "B")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected, while inserting a row", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while closing the database", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test the case when db is not triggered and expectations
|
||||||
|
// are not asserted on close
|
||||||
|
func TestIssue4(t *testing.T) {
|
||||||
|
db, err := New()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
|
||||||
|
}
|
||||||
|
ExpectQuery("some sql query which will not be called").
|
||||||
|
WillReturnRows(NewRows([]string{"id"}))
|
||||||
|
|
||||||
|
err = db.Close()
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Was expecting an error, since expected query was not matched")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMockQuery(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", "title"}).FromCSVString("5,hello world")
|
||||||
|
|
||||||
|
ExpectQuery("SELECT (.+) FROM articles WHERE id = ?").
|
||||||
|
WithArgs(5).
|
||||||
|
WillReturnRows(rs)
|
||||||
|
|
||||||
|
rows, err := db.Query("SELECT (.+) FROM articles WHERE id = ?", 5)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while retrieving mock rows", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if er := rows.Close(); er != nil {
|
||||||
|
t.Error("Unexpected error while trying to close rows")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if !rows.Next() {
|
||||||
|
t.Error("it must have had one row as result, but got empty result set instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
var id int
|
||||||
|
var title string
|
||||||
|
|
||||||
|
err = rows.Scan(&id, &title)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while trying to scan row", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != 5 {
|
||||||
|
t.Errorf("expected mocked id to be 5, but got %d instead", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if title != "hello world" {
|
||||||
|
t.Errorf("expected mocked title to be 'hello world', but got '%s' instead", title)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.Close(); err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while closing the database", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMockQueryTypes(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
columns := []string{"id", "timestamp", "sold"}
|
||||||
|
|
||||||
|
timestamp := time.Now()
|
||||||
|
rs := NewRows(columns)
|
||||||
|
rs.AddRow(5, timestamp, true)
|
||||||
|
|
||||||
|
ExpectQuery("SELECT (.+) FROM sales WHERE id = ?").
|
||||||
|
WithArgs(5).
|
||||||
|
WillReturnRows(rs)
|
||||||
|
|
||||||
|
rows, err := db.Query("SELECT (.+) FROM sales WHERE id = ?", 5)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while retrieving mock rows", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if er := rows.Close(); er != nil {
|
||||||
|
t.Error("Unexpected error while trying to close rows")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if !rows.Next() {
|
||||||
|
t.Error("it must have had one row as result, but got empty result set instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
var id int
|
||||||
|
var time time.Time
|
||||||
|
var sold bool
|
||||||
|
|
||||||
|
err = rows.Scan(&id, &time, &sold)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while trying to scan row", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != 5 {
|
||||||
|
t.Errorf("expected mocked id to be 5, but got %d instead", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if time != timestamp {
|
||||||
|
t.Errorf("expected mocked time to be %s, but got '%s' instead", timestamp, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sold != true {
|
||||||
|
t.Errorf("expected mocked boolean to be true, but got %v instead", sold)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.Close(); err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while closing the database", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTransactionExpectations(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// begin and commit
|
||||||
|
ExpectBegin()
|
||||||
|
ExpectCommit()
|
||||||
|
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("an error '%s' was not expected when beginning a transaction", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("an error '%s' was not expected when commiting a transaction", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// begin and rollback
|
||||||
|
ExpectBegin()
|
||||||
|
ExpectRollback()
|
||||||
|
|
||||||
|
tx, err = db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("an error '%s' was not expected when beginning a transaction", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Rollback()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("an error '%s' was not expected when rolling back a transaction", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// begin with an error
|
||||||
|
ExpectBegin().WillReturnError(fmt.Errorf("some err"))
|
||||||
|
|
||||||
|
tx, err = db.Begin()
|
||||||
|
if err == nil {
|
||||||
|
t.Error("an error was expected when beginning a transaction, but got none")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.Close(); err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while closing the database", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrepareExpectations(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// no expectations, w/o ExpectPrepare()
|
||||||
|
stmt, err := db.Prepare("SELECT (.+) FROM articles WHERE id = ?")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while creating a prepared statement", err)
|
||||||
|
}
|
||||||
|
if stmt == nil {
|
||||||
|
t.Errorf("stmt was expected while creating a prepared statement")
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect something else, w/o ExpectPrepare()
|
||||||
|
var id int
|
||||||
|
var title string
|
||||||
|
rs := NewRows([]string{"id", "title"}).FromCSVString("5,hello world")
|
||||||
|
|
||||||
|
ExpectQuery("SELECT (.+) FROM articles WHERE id = ?").
|
||||||
|
WithArgs(5).
|
||||||
|
WillReturnRows(rs)
|
||||||
|
|
||||||
|
stmt, err = db.Prepare("SELECT (.+) FROM articles WHERE id = ?")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while creating a prepared statement", err)
|
||||||
|
}
|
||||||
|
if stmt == nil {
|
||||||
|
t.Errorf("stmt was expected while creating a prepared statement")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stmt.QueryRow(5).Scan(&id, &title)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while retrieving mock rows", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect normal result
|
||||||
|
ExpectPrepare()
|
||||||
|
stmt, err = db.Prepare("SELECT (.+) FROM articles WHERE id = ?")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while creating a prepared statement", err)
|
||||||
|
}
|
||||||
|
if stmt == nil {
|
||||||
|
t.Errorf("stmt was expected while creating a prepared statement")
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect error result
|
||||||
|
ExpectPrepare().WillReturnError(fmt.Errorf("Some DB error occurred"))
|
||||||
|
stmt, err = db.Prepare("SELECT (.+) FROM articles WHERE id = ?")
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error was expected while creating a prepared statement")
|
||||||
|
}
|
||||||
|
if stmt != nil {
|
||||||
|
t.Errorf("stmt was not expected while creating a prepared statement returning error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.Close(); err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while closing the database", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPreparedQueryExecutions(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
rs1 := NewRows([]string{"id", "title"}).FromCSVString("5,hello world")
|
||||||
|
ExpectQuery("SELECT (.+) FROM articles WHERE id = ?").
|
||||||
|
WithArgs(5).
|
||||||
|
WillReturnRows(rs1)
|
||||||
|
|
||||||
|
rs2 := NewRows([]string{"id", "title"}).FromCSVString("2,whoop")
|
||||||
|
ExpectQuery("SELECT (.+) FROM articles WHERE id = ?").
|
||||||
|
WithArgs(2).
|
||||||
|
WillReturnRows(rs2)
|
||||||
|
|
||||||
|
stmt, err := db.Prepare("SELECT (.+) FROM articles WHERE id = ?")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while creating a prepared statement", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var id int
|
||||||
|
var title string
|
||||||
|
|
||||||
|
err = stmt.QueryRow(5).Scan(&id, &title)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected querying row from statement and scanning", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != 5 {
|
||||||
|
t.Errorf("expected mocked id to be 5, but got %d instead", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if title != "hello world" {
|
||||||
|
t.Errorf("expected mocked title to be 'hello world', but got '%s' instead", title)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stmt.QueryRow(2).Scan(&id, &title)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected querying row from statement and scanning", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != 2 {
|
||||||
|
t.Errorf("expected mocked id to be 2, but got %d instead", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if title != "whoop" {
|
||||||
|
t.Errorf("expected mocked title to be 'whoop', but got '%s' instead", title)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.Close(); err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while closing the database", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnexpectedOperations(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt, err := db.Prepare("SELECT (.+) FROM articles WHERE id = ?")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while creating a prepared statement", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var id int
|
||||||
|
var title string
|
||||||
|
|
||||||
|
err = stmt.QueryRow(5).Scan(&id, &title)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error was expected querying row, since there was no such expectation")
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpectRollback()
|
||||||
|
|
||||||
|
err = db.Close()
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error was expected while closing the database, expectation was not fulfilled", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWrongExpectations(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpectBegin()
|
||||||
|
|
||||||
|
rs1 := NewRows([]string{"id", "title"}).FromCSVString("5,hello world")
|
||||||
|
ExpectQuery("SELECT (.+) FROM articles WHERE id = ?").
|
||||||
|
WithArgs(5).
|
||||||
|
WillReturnRows(rs1)
|
||||||
|
|
||||||
|
ExpectCommit().WillReturnError(fmt.Errorf("deadlock occured"))
|
||||||
|
ExpectRollback() // won't be triggered
|
||||||
|
|
||||||
|
stmt, err := db.Prepare("SELECT (.+) FROM articles WHERE id = ? FOR UPDATE")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while creating a prepared statement", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var id int
|
||||||
|
var title string
|
||||||
|
|
||||||
|
err = stmt.QueryRow(5).Scan(&id, &title)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error was expected while querying row, since there begin transaction expectation is not fulfilled")
|
||||||
|
}
|
||||||
|
|
||||||
|
// lets go around and start transaction
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("an error '%s' was not expected when beginning a transaction", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stmt.QueryRow(5).Scan(&id, &title)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while querying row, since transaction was started", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
if err == nil {
|
||||||
|
t.Error("a deadlock error was expected when commiting a transaction", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.Close()
|
||||||
|
if err == nil {
|
||||||
|
t.Error("error was expected while closing the database, expectation was not fulfilled", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecExpectations(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := NewResult(1, 1)
|
||||||
|
ExpectExec("^INSERT INTO articles").
|
||||||
|
WithArgs("hello").
|
||||||
|
WillReturnResult(result)
|
||||||
|
|
||||||
|
res, err := db.Exec("INSERT INTO articles (title) VALUES (?)", "hello")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected, while inserting a row", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := res.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected, while getting a last insert id", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := res.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected, while getting affected rows", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != 1 {
|
||||||
|
t.Errorf("expected last insert id to be 1, but got %d instead", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if affected != 1 {
|
||||||
|
t.Errorf("expected affected rows to be 1, but got %d instead", affected)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.Close(); err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while closing the database", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRowBuilderAndNilTypes(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", "active", "created", "status"}).
|
||||||
|
AddRow(1, true, time.Now(), 5).
|
||||||
|
AddRow(2, false, nil, nil)
|
||||||
|
|
||||||
|
ExpectQuery("SELECT (.+) FROM sales").WillReturnRows(rs)
|
||||||
|
|
||||||
|
rows, err := db.Query("SELECT * FROM sales")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while retrieving mock rows", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if er := rows.Close(); er != nil {
|
||||||
|
t.Error("Unexpected error while trying to close rows")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// NullTime and NullInt are used from stubs_test.go
|
||||||
|
var (
|
||||||
|
id int
|
||||||
|
active bool
|
||||||
|
created NullTime
|
||||||
|
status NullInt
|
||||||
|
)
|
||||||
|
|
||||||
|
if !rows.Next() {
|
||||||
|
t.Error("it must have had row in rows, but got empty result set instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rows.Scan(&id, &active, &created, &status)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while trying to scan row", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != 1 {
|
||||||
|
t.Errorf("expected mocked id to be 1, but got %d instead", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !active {
|
||||||
|
t.Errorf("expected 'active' to be 'true', but got '%v' instead", active)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !created.Valid {
|
||||||
|
t.Errorf("expected 'created' to be valid, but it %+v is not", created)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !status.Valid {
|
||||||
|
t.Errorf("expected 'status' to be valid, but it %+v is not", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.Integer != 5 {
|
||||||
|
t.Errorf("expected 'status' to be '5', but got '%d'", status.Integer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test second row
|
||||||
|
if !rows.Next() {
|
||||||
|
t.Error("it must have had row in rows, but got empty result set instead")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rows.Scan(&id, &active, &created, &status)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error '%s' was not expected while trying to scan row", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != 2 {
|
||||||
|
t.Errorf("expected mocked id to be 2, but got %d instead", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if active {
|
||||||
|
t.Errorf("expected 'active' to be 'false', but got '%v' instead", active)
|
||||||
|
}
|
||||||
|
|
||||||
|
if created.Valid {
|
||||||
|
t.Errorf("expected 'created' to be invalid, but it %+v is not", created)
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.Valid {
|
||||||
|
t.Errorf("expected 'status' to be invalid, but it %+v is not", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = db.Close(); err != nil {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
)
|
||||||
|
|
||||||
|
type statement struct {
|
||||||
|
conn *conn
|
||||||
|
query string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stmt *statement) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stmt *statement) NumInput() int {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stmt *statement) Exec(args []driver.Value) (driver.Result, error) {
|
||||||
|
return stmt.conn.Exec(stmt.query, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stmt *statement) Query(args []driver.Value) (driver.Rows, error) {
|
||||||
|
return stmt.conn.Query(stmt.query, args)
|
||||||
|
}
|
76
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/stubs_test.go
generated
vendored
Normal file
76
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/stubs_test.go
generated
vendored
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NullTime struct {
|
||||||
|
Time time.Time
|
||||||
|
Valid bool // Valid is true if Time is not NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullInt struct {
|
||||||
|
Integer int
|
||||||
|
Valid bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Satisfy sql.Scanner interface
|
||||||
|
func (ni *NullInt) Scan(value interface{}) (err error) {
|
||||||
|
if value == nil {
|
||||||
|
ni.Integer, ni.Valid = 0, false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := value.(type) {
|
||||||
|
case int, int8, int16, int32, int64:
|
||||||
|
ni.Integer, ni.Valid = v.(int), true
|
||||||
|
return
|
||||||
|
case []byte:
|
||||||
|
ni.Integer, err = strconv.Atoi(string(v))
|
||||||
|
ni.Valid = (err == nil)
|
||||||
|
return
|
||||||
|
case string:
|
||||||
|
ni.Integer, err = strconv.Atoi(v)
|
||||||
|
ni.Valid = (err == nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ni.Valid = false
|
||||||
|
return fmt.Errorf("Can't convert %T to integer", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Satisfy sql.Valuer interface.
|
||||||
|
func (ni NullInt) Value() (driver.Value, error) {
|
||||||
|
if !ni.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return ni.Integer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Satisfy sql.Scanner interface
|
||||||
|
func (nt *NullTime) Scan(value interface{}) (err error) {
|
||||||
|
if value == nil {
|
||||||
|
nt.Time, nt.Valid = time.Time{}, false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := value.(type) {
|
||||||
|
case time.Time:
|
||||||
|
nt.Time, nt.Valid = v, true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nt.Valid = false
|
||||||
|
return fmt.Errorf("Can't convert %T to time.Time", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Satisfy sql.Valuer interface.
|
||||||
|
func (nt NullTime) Value() (driver.Value, error) {
|
||||||
|
if !nt.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nt.Time, nil
|
||||||
|
}
|
37
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/transaction.go
generated
vendored
Normal file
37
Godeps/_workspace/src/github.com/DATA-DOG/go-sqlmock/transaction.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type transaction struct {
|
||||||
|
conn *conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *transaction) Commit() error {
|
||||||
|
e := tx.conn.next()
|
||||||
|
if e == nil {
|
||||||
|
return fmt.Errorf("all expectations were already fulfilled, call to commit transaction was not expected")
|
||||||
|
}
|
||||||
|
|
||||||
|
etc, ok := e.(*expectedCommit)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("call to commit transaction, was not expected, next expectation was %v", e)
|
||||||
|
}
|
||||||
|
etc.triggered = true
|
||||||
|
return etc.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *transaction) Rollback() error {
|
||||||
|
e := tx.conn.next()
|
||||||
|
if e == nil {
|
||||||
|
return fmt.Errorf("all expectations were already fulfilled, call to rollback transaction was not expected")
|
||||||
|
}
|
||||||
|
|
||||||
|
etr, ok := e.(*expectedRollback)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("call to rollback transaction, was not expected, next expectation was %v", e)
|
||||||
|
}
|
||||||
|
etr.triggered = true
|
||||||
|
return etr.err
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var re *regexp.Regexp
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
re = regexp.MustCompile("\\s+")
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip out new lines and trim spaces
|
||||||
|
func stripQuery(q string) (s string) {
|
||||||
|
return strings.TrimSpace(re.ReplaceAllString(q, " "))
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package sqlmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestQueryStringStripping(t *testing.T) {
|
||||||
|
assert := func(actual, expected string) {
|
||||||
|
if res := stripQuery(actual); res != expected {
|
||||||
|
t.Errorf("Expected '%s' to be '%s', but got '%s'", actual, expected, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(" SELECT 1", "SELECT 1")
|
||||||
|
assert("SELECT 1 FROM d", "SELECT 1 FROM d")
|
||||||
|
assert(`
|
||||||
|
SELECT c
|
||||||
|
FROM D
|
||||||
|
`, "SELECT c FROM D")
|
||||||
|
assert("UPDATE (.+) SET ", "UPDATE (.+) SET")
|
||||||
|
}
|
Loading…
Reference in New Issue