mirror of
https://github.com/DATA-DOG/go-sqlmock.git
synced 2024-11-24 08:32:36 +02:00
update formatting and readme
This commit is contained in:
parent
27fabfa23a
commit
4c6f0e69c3
@ -320,6 +320,7 @@ Visit [godoc](http://godoc.org/github.com/DATA-DOG/go-sqlmock)
|
|||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
|
- **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
|
- **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).
|
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.
|
This way on Close it will surely assert if all expectations are met, even if database was not triggered at all.
|
||||||
|
152
connection.go
152
connection.go
@ -1,118 +1,118 @@
|
|||||||
package sqlmock
|
package sqlmock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type conn struct {
|
type conn struct {
|
||||||
expectations []expectation
|
expectations []expectation
|
||||||
active expectation
|
active expectation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close a mock database driver connection. It should
|
// Close a mock database driver connection. It should
|
||||||
// be always called to ensure that all expectations
|
// be always called to ensure that all expectations
|
||||||
// were met successfully. Returns error if there is any
|
// were met successfully. Returns error if there is any
|
||||||
func (c *conn) Close() (err error) {
|
func (c *conn) Close() (err error) {
|
||||||
for _, e := range mock.conn.expectations {
|
for _, e := range mock.conn.expectations {
|
||||||
if !e.fulfilled() {
|
if !e.fulfilled() {
|
||||||
err = fmt.Errorf("there is a remaining expectation %T which was not matched yet", e)
|
err = fmt.Errorf("there is a remaining expectation %T which was not matched yet", e)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mock.conn.expectations = []expectation{}
|
mock.conn.expectations = []expectation{}
|
||||||
mock.conn.active = nil
|
mock.conn.active = nil
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) Begin() (driver.Tx, error) {
|
func (c *conn) Begin() (driver.Tx, error) {
|
||||||
e := c.next()
|
e := c.next()
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return nil, fmt.Errorf("all expectations were already fulfilled, call to begin transaction was not expected")
|
return nil, fmt.Errorf("all expectations were already fulfilled, call to begin transaction was not expected")
|
||||||
}
|
}
|
||||||
|
|
||||||
etb, ok := e.(*expectedBegin)
|
etb, ok := e.(*expectedBegin)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("call to begin transaction, was not expected, next expectation is %T as %+v", e, e)
|
return nil, fmt.Errorf("call to begin transaction, was not expected, next expectation is %T as %+v", e, e)
|
||||||
}
|
}
|
||||||
etb.triggered = true
|
etb.triggered = true
|
||||||
return &transaction{c}, etb.err
|
return &transaction{c}, etb.err
|
||||||
}
|
}
|
||||||
|
|
||||||
// get next unfulfilled expectation
|
// get next unfulfilled expectation
|
||||||
func (c *conn) next() (e expectation) {
|
func (c *conn) next() (e expectation) {
|
||||||
for _, e = range c.expectations {
|
for _, e = range c.expectations {
|
||||||
if !e.fulfilled() {
|
if !e.fulfilled() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil // all expectations were fulfilled
|
return nil // all expectations were fulfilled
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
|
func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
|
||||||
e := c.next()
|
e := c.next()
|
||||||
query = stripQuery(query)
|
query = stripQuery(query)
|
||||||
if e == nil {
|
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)
|
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)
|
eq, ok := e.(*expectedExec)
|
||||||
if !ok {
|
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)
|
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
|
eq.triggered = true
|
||||||
if eq.err != nil {
|
if eq.err != nil {
|
||||||
return nil, eq.err // mocked to return error
|
return nil, eq.err // mocked to return error
|
||||||
}
|
}
|
||||||
|
|
||||||
if eq.result == nil {
|
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 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !eq.queryMatches(query) {
|
if !eq.queryMatches(query) {
|
||||||
return nil, fmt.Errorf("exec query '%s', does not match regex '%s'", query, eq.sqlRegex.String())
|
return nil, fmt.Errorf("exec query '%s', does not match regex '%s'", query, eq.sqlRegex.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !eq.argsMatches(args) {
|
if !eq.argsMatches(args) {
|
||||||
return nil, fmt.Errorf("exec query '%s', args %+v does not match expected %+v", query, args, eq.args)
|
return nil, fmt.Errorf("exec query '%s', args %+v does not match expected %+v", query, args, eq.args)
|
||||||
}
|
}
|
||||||
|
|
||||||
return eq.result, nil
|
return eq.result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) Prepare(query string) (driver.Stmt, error) {
|
func (c *conn) Prepare(query string) (driver.Stmt, error) {
|
||||||
return &statement{mock.conn, stripQuery(query)}, nil
|
return &statement{mock.conn, stripQuery(query)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
|
func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
|
||||||
e := c.next()
|
e := c.next()
|
||||||
query = stripQuery(query)
|
query = stripQuery(query)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return nil, fmt.Errorf("all expectations were already fulfilled, call to query '%s' with args %+v was not expected", query, args)
|
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)
|
eq, ok := e.(*expectedQuery)
|
||||||
if !ok {
|
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)
|
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
|
eq.triggered = true
|
||||||
if eq.err != nil {
|
if eq.err != nil {
|
||||||
return nil, eq.err // mocked to return error
|
return nil, eq.err // mocked to return error
|
||||||
}
|
}
|
||||||
|
|
||||||
if eq.rows == nil {
|
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 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !eq.queryMatches(query) {
|
if !eq.queryMatches(query) {
|
||||||
return nil, fmt.Errorf("query '%s', does not match regex [%s]", query, eq.sqlRegex.String())
|
return nil, fmt.Errorf("query '%s', does not match regex [%s]", query, eq.sqlRegex.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !eq.argsMatches(args) {
|
if !eq.argsMatches(args) {
|
||||||
return nil, fmt.Errorf("query '%s', args %+v does not match expected %+v", query, args, eq.args)
|
return nil, fmt.Errorf("query '%s', args %+v does not match expected %+v", query, args, eq.args)
|
||||||
}
|
}
|
||||||
|
|
||||||
return eq.rows, nil
|
return eq.rows, nil
|
||||||
}
|
}
|
||||||
|
124
expectations.go
124
expectations.go
@ -1,119 +1,119 @@
|
|||||||
package sqlmock
|
package sqlmock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Argument interface allows to match
|
// Argument interface allows to match
|
||||||
// any argument in specific way
|
// any argument in specific way
|
||||||
type Argument interface {
|
type Argument interface {
|
||||||
Match(driver.Value) bool
|
Match(driver.Value) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// an expectation interface
|
// an expectation interface
|
||||||
type expectation interface {
|
type expectation interface {
|
||||||
fulfilled() bool
|
fulfilled() bool
|
||||||
setError(err error)
|
setError(err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// common expectation struct
|
// common expectation struct
|
||||||
// satisfies the expectation interface
|
// satisfies the expectation interface
|
||||||
type commonExpectation struct {
|
type commonExpectation struct {
|
||||||
triggered bool
|
triggered bool
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *commonExpectation) fulfilled() bool {
|
func (e *commonExpectation) fulfilled() bool {
|
||||||
return e.triggered
|
return e.triggered
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *commonExpectation) setError(err error) {
|
func (e *commonExpectation) setError(err error) {
|
||||||
e.err = err
|
e.err = err
|
||||||
}
|
}
|
||||||
|
|
||||||
// query based expectation
|
// query based expectation
|
||||||
// adds a query matching logic
|
// adds a query matching logic
|
||||||
type queryBasedExpectation struct {
|
type queryBasedExpectation struct {
|
||||||
commonExpectation
|
commonExpectation
|
||||||
sqlRegex *regexp.Regexp
|
sqlRegex *regexp.Regexp
|
||||||
args []driver.Value
|
args []driver.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *queryBasedExpectation) queryMatches(sql string) bool {
|
func (e *queryBasedExpectation) queryMatches(sql string) bool {
|
||||||
return e.sqlRegex.MatchString(sql)
|
return e.sqlRegex.MatchString(sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *queryBasedExpectation) argsMatches(args []driver.Value) bool {
|
func (e *queryBasedExpectation) argsMatches(args []driver.Value) bool {
|
||||||
if nil == e.args {
|
if nil == e.args {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if len(args) != len(e.args) {
|
if len(args) != len(e.args) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for k, v := range args {
|
for k, v := range args {
|
||||||
matcher, ok := e.args[k].(Argument)
|
matcher, ok := e.args[k].(Argument)
|
||||||
if ok {
|
if ok {
|
||||||
if !matcher.Match(v) {
|
if !matcher.Match(v) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
vi := reflect.ValueOf(v)
|
vi := reflect.ValueOf(v)
|
||||||
ai := reflect.ValueOf(e.args[k])
|
ai := reflect.ValueOf(e.args[k])
|
||||||
switch vi.Kind() {
|
switch vi.Kind() {
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
if vi.Int() != ai.Int() {
|
if vi.Int() != ai.Int() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case reflect.Float32, reflect.Float64:
|
case reflect.Float32, reflect.Float64:
|
||||||
if vi.Float() != ai.Float() {
|
if vi.Float() != ai.Float() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
if vi.Uint() != ai.Uint() {
|
if vi.Uint() != ai.Uint() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
if vi.String() != ai.String() {
|
if vi.String() != ai.String() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// compare types like time.Time based on type only
|
// compare types like time.Time based on type only
|
||||||
if vi.Kind() != ai.Kind() {
|
if vi.Kind() != ai.Kind() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// begin transaction
|
// begin transaction
|
||||||
type expectedBegin struct {
|
type expectedBegin struct {
|
||||||
commonExpectation
|
commonExpectation
|
||||||
}
|
}
|
||||||
|
|
||||||
// tx commit
|
// tx commit
|
||||||
type expectedCommit struct {
|
type expectedCommit struct {
|
||||||
commonExpectation
|
commonExpectation
|
||||||
}
|
}
|
||||||
|
|
||||||
// tx rollback
|
// tx rollback
|
||||||
type expectedRollback struct {
|
type expectedRollback struct {
|
||||||
commonExpectation
|
commonExpectation
|
||||||
}
|
}
|
||||||
|
|
||||||
// query expectation
|
// query expectation
|
||||||
type expectedQuery struct {
|
type expectedQuery struct {
|
||||||
queryBasedExpectation
|
queryBasedExpectation
|
||||||
|
|
||||||
rows driver.Rows
|
rows driver.Rows
|
||||||
}
|
}
|
||||||
|
|
||||||
// exec query expectation
|
// exec query expectation
|
||||||
type expectedExec struct {
|
type expectedExec struct {
|
||||||
queryBasedExpectation
|
queryBasedExpectation
|
||||||
|
|
||||||
result driver.Result
|
result driver.Result
|
||||||
}
|
}
|
||||||
|
@ -1,59 +1,59 @@
|
|||||||
package sqlmock
|
package sqlmock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type matcher struct {
|
type matcher struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m matcher) Match(driver.Value) bool {
|
func (m matcher) Match(driver.Value) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQueryExpectationArgComparison(t *testing.T) {
|
func TestQueryExpectationArgComparison(t *testing.T) {
|
||||||
e := &queryBasedExpectation{}
|
e := &queryBasedExpectation{}
|
||||||
against := []driver.Value{5}
|
against := []driver.Value{5}
|
||||||
if !e.argsMatches(against) {
|
if !e.argsMatches(against) {
|
||||||
t.Error("arguments should match, since the no expectation was set")
|
t.Error("arguments should match, since the no expectation was set")
|
||||||
}
|
}
|
||||||
|
|
||||||
e.args = []driver.Value{5, "str"}
|
e.args = []driver.Value{5, "str"}
|
||||||
|
|
||||||
against = []driver.Value{5}
|
against = []driver.Value{5}
|
||||||
if e.argsMatches(against) {
|
if e.argsMatches(against) {
|
||||||
t.Error("arguments should not match, since the size is not the same")
|
t.Error("arguments should not match, since the size is not the same")
|
||||||
}
|
}
|
||||||
|
|
||||||
against = []driver.Value{3, "str"}
|
against = []driver.Value{3, "str"}
|
||||||
if e.argsMatches(against) {
|
if e.argsMatches(against) {
|
||||||
t.Error("arguments should not match, since the first argument (int value) is different")
|
t.Error("arguments should not match, since the first argument (int value) is different")
|
||||||
}
|
}
|
||||||
|
|
||||||
against = []driver.Value{5, "st"}
|
against = []driver.Value{5, "st"}
|
||||||
if e.argsMatches(against) {
|
if e.argsMatches(against) {
|
||||||
t.Error("arguments should not match, since the second argument (string value) is different")
|
t.Error("arguments should not match, since the second argument (string value) is different")
|
||||||
}
|
}
|
||||||
|
|
||||||
against = []driver.Value{5, "str"}
|
against = []driver.Value{5, "str"}
|
||||||
if !e.argsMatches(against) {
|
if !e.argsMatches(against) {
|
||||||
t.Error("arguments should match, but it did not")
|
t.Error("arguments should match, but it did not")
|
||||||
}
|
}
|
||||||
|
|
||||||
e.args = []driver.Value{5, time.Now()}
|
e.args = []driver.Value{5, time.Now()}
|
||||||
|
|
||||||
const longForm = "Jan 2, 2006 at 3:04pm (MST)"
|
const longForm = "Jan 2, 2006 at 3:04pm (MST)"
|
||||||
tm, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)")
|
tm, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)")
|
||||||
|
|
||||||
against = []driver.Value{5, tm}
|
against = []driver.Value{5, tm}
|
||||||
if !e.argsMatches(against) {
|
if !e.argsMatches(against) {
|
||||||
t.Error("arguments should match (time will be compared only by type), but it did not")
|
t.Error("arguments should match (time will be compared only by type), but it did not")
|
||||||
}
|
}
|
||||||
|
|
||||||
against = []driver.Value{5, matcher{}}
|
against = []driver.Value{5, matcher{}}
|
||||||
if !e.argsMatches(against) {
|
if !e.argsMatches(against) {
|
||||||
t.Error("arguments should match, but it did not")
|
t.Error("arguments should match, but it did not")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user