You've already forked go-sqlxmock
							
							
				mirror of
				https://github.com/zhashkevych/go-sqlxmock.git
				synced 2025-10-30 23:27:38 +02:00 
			
		
		
		
	added support for mammoths
This commit is contained in:
		| @@ -338,18 +338,3 @@ type queryBasedExpectation struct { | ||||
| 	converter driver.ValueConverter | ||||
| 	args      []driver.Value | ||||
| } | ||||
|  | ||||
| func (e *queryBasedExpectation) attemptArgMatch(args []driver.NamedValue) (err error) { | ||||
| 	// catch panic | ||||
| 	defer func() { | ||||
| 		if e := recover(); e != nil { | ||||
| 			_, ok := e.(error) | ||||
| 			if !ok { | ||||
| 				err = fmt.Errorf(e.(string)) | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	err = e.argsMatches(args) | ||||
| 	return | ||||
| } | ||||
|   | ||||
| @@ -15,7 +15,7 @@ func (e *ExpectedQuery) WillReturnRows(rows *Rows) *ExpectedQuery { | ||||
| 	return e | ||||
| } | ||||
|  | ||||
| func (e *queryBasedExpectation) argsMatches(args []driver.NamedValue) error { | ||||
| func (e *queryBasedExpectation) argsMatches(args []namedValue) error { | ||||
| 	if nil == e.args { | ||||
| 		return nil | ||||
| 	} | ||||
| @@ -50,3 +50,18 @@ func (e *queryBasedExpectation) argsMatches(args []driver.NamedValue) error { | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (e *queryBasedExpectation) attemptArgMatch(args []namedValue) (err error) { | ||||
| 	// catch panic | ||||
| 	defer func() { | ||||
| 		if e := recover(); e != nil { | ||||
| 			_, ok := e.(error) | ||||
| 			if !ok { | ||||
| 				err = fmt.Errorf(e.(string)) | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	err = e.argsMatches(args) | ||||
| 	return | ||||
| } | ||||
|   | ||||
							
								
								
									
										95
									
								
								expectations_before_go18_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								expectations_before_go18_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| // +build !go1.8 | ||||
|  | ||||
| package sqlmock | ||||
|  | ||||
| func TestQueryExpectationArgComparison(t *testing.T) { | ||||
| 	e := &queryBasedExpectation{converter: driver.DefaultParameterConverter} | ||||
| 	against := []namedValue{{Value: int64(5), Ordinal: 1}} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Errorf("arguments should match, since the no expectation was set, but got err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	e.args = []driver.Value{5, "str"} | ||||
|  | ||||
| 	against = []namedValue{{Value: int64(5), Ordinal: 1}} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since the size is not the same") | ||||
| 	} | ||||
|  | ||||
| 	against = []namedValue{ | ||||
| 		{Value: int64(3), Ordinal: 1}, | ||||
| 		{Value: "str", Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since the first argument (int value) is different") | ||||
| 	} | ||||
|  | ||||
| 	against = []namedValue{ | ||||
| 		{Value: int64(5), Ordinal: 1}, | ||||
| 		{Value: "st", Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since the second argument (string value) is different") | ||||
| 	} | ||||
|  | ||||
| 	against = []namedValue{ | ||||
| 		{Value: int64(5), Ordinal: 1}, | ||||
| 		{Value: "str", Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Errorf("arguments should match, but it did not: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	const longForm = "Jan 2, 2006 at 3:04pm (MST)" | ||||
| 	tm, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)") | ||||
| 	e.args = []driver.Value{5, tm} | ||||
|  | ||||
| 	against = []namedValue{ | ||||
| 		{Value: int64(5), Ordinal: 1}, | ||||
| 		{Value: tm, Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Error("arguments should match, but it did not") | ||||
| 	} | ||||
|  | ||||
| 	e.args = []driver.Value{5, AnyArg()} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Errorf("arguments should match, but it did not: %s", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestQueryExpectationArgComparisonBool(t *testing.T) { | ||||
| 	var e *queryBasedExpectation | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{true}, converter: driver.DefaultParameterConverter} | ||||
| 	against := []namedValue{ | ||||
| 		{Value: true, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Error("arguments should match, since arguments are the same") | ||||
| 	} | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{false}, converter: driver.DefaultParameterConverter} | ||||
| 	against = []namedValue{ | ||||
| 		{Value: false, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Error("arguments should match, since argument are the same") | ||||
| 	} | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{true}, converter: driver.DefaultParameterConverter} | ||||
| 	against = []namedValue{ | ||||
| 		{Value: false, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since argument is different") | ||||
| 	} | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{false}, converter: driver.DefaultParameterConverter} | ||||
| 	against = []namedValue{ | ||||
| 		{Value: true, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since argument is different") | ||||
| 	} | ||||
| } | ||||
| @@ -60,3 +60,18 @@ func (e *queryBasedExpectation) argsMatches(args []driver.NamedValue) error { | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (e *queryBasedExpectation) attemptArgMatch(args []driver.NamedValue) (err error) { | ||||
| 	// catch panic | ||||
| 	defer func() { | ||||
| 		if e := recover(); e != nil { | ||||
| 			_, ok := e.(error) | ||||
| 			if !ok { | ||||
| 				err = fmt.Errorf(e.(string)) | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	err = e.argsMatches(args) | ||||
| 	return | ||||
| } | ||||
|   | ||||
| @@ -6,8 +6,101 @@ import ( | ||||
| 	"database/sql" | ||||
| 	"database/sql/driver" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func TestQueryExpectationArgComparison(t *testing.T) { | ||||
| 	e := &queryBasedExpectation{converter: driver.DefaultParameterConverter} | ||||
| 	against := []driver.NamedValue{{Value: int64(5), Ordinal: 1}} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Errorf("arguments should match, since the no expectation was set, but got err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	e.args = []driver.Value{5, "str"} | ||||
|  | ||||
| 	against = []driver.NamedValue{{Value: int64(5), Ordinal: 1}} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since the size is not the same") | ||||
| 	} | ||||
|  | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: int64(3), Ordinal: 1}, | ||||
| 		{Value: "str", Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since the first argument (int value) is different") | ||||
| 	} | ||||
|  | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: int64(5), Ordinal: 1}, | ||||
| 		{Value: "st", Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since the second argument (string value) is different") | ||||
| 	} | ||||
|  | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: int64(5), Ordinal: 1}, | ||||
| 		{Value: "str", Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Errorf("arguments should match, but it did not: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	const longForm = "Jan 2, 2006 at 3:04pm (MST)" | ||||
| 	tm, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)") | ||||
| 	e.args = []driver.Value{5, tm} | ||||
|  | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: int64(5), Ordinal: 1}, | ||||
| 		{Value: tm, Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Error("arguments should match, but it did not") | ||||
| 	} | ||||
|  | ||||
| 	e.args = []driver.Value{5, AnyArg()} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Errorf("arguments should match, but it did not: %s", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestQueryExpectationArgComparisonBool(t *testing.T) { | ||||
| 	var e *queryBasedExpectation | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{true}, converter: driver.DefaultParameterConverter} | ||||
| 	against := []driver.NamedValue{ | ||||
| 		{Value: true, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Error("arguments should match, since arguments are the same") | ||||
| 	} | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{false}, converter: driver.DefaultParameterConverter} | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: false, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Error("arguments should match, since argument are the same") | ||||
| 	} | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{true}, converter: driver.DefaultParameterConverter} | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: false, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since argument is different") | ||||
| 	} | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{false}, converter: driver.DefaultParameterConverter} | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: true, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since argument is different") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestQueryExpectationNamedArgComparison(t *testing.T) { | ||||
| 	e := &queryBasedExpectation{converter: driver.DefaultParameterConverter} | ||||
| 	against := []driver.NamedValue{{Value: int64(5), Name: "id"}} | ||||
|   | ||||
| @@ -4,9 +4,27 @@ package sqlmock | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"database/sql/driver" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| type CustomConverter struct{} | ||||
|  | ||||
| func (s CustomConverter) ConvertValue(v interface{}) (driver.Value, error) { | ||||
| 	switch v.(type) { | ||||
| 	case string: | ||||
| 		return v.(string), nil | ||||
| 	case []string: | ||||
| 		return v.([]string), nil | ||||
| 	case int: | ||||
| 		return v.(int), nil | ||||
| 	default: | ||||
| 		return nil, errors.New(fmt.Sprintf("cannot convert %T with value %v", v, v)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestCustomValueConverterExec(t *testing.T) { | ||||
| 	db, mock, _ := New(ValueConverterOption(CustomConverter{})) | ||||
| 	expectedQuery := "INSERT INTO tags \\(name,email,age,hobbies\\) VALUES \\(\\?,\\?,\\?,\\?\\)" | ||||
|   | ||||
| @@ -1,106 +1,11 @@ | ||||
| package sqlmock | ||||
|  | ||||
| import ( | ||||
| 	"database/sql/driver" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func TestQueryExpectationArgComparison(t *testing.T) { | ||||
| 	e := &queryBasedExpectation{converter: driver.DefaultParameterConverter} | ||||
| 	against := []driver.NamedValue{{Value: int64(5), Ordinal: 1}} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Errorf("arguments should match, since the no expectation was set, but got err: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	e.args = []driver.Value{5, "str"} | ||||
|  | ||||
| 	against = []driver.NamedValue{{Value: int64(5), Ordinal: 1}} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since the size is not the same") | ||||
| 	} | ||||
|  | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: int64(3), Ordinal: 1}, | ||||
| 		{Value: "str", Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since the first argument (int value) is different") | ||||
| 	} | ||||
|  | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: int64(5), Ordinal: 1}, | ||||
| 		{Value: "st", Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since the second argument (string value) is different") | ||||
| 	} | ||||
|  | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: int64(5), Ordinal: 1}, | ||||
| 		{Value: "str", Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Errorf("arguments should match, but it did not: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	const longForm = "Jan 2, 2006 at 3:04pm (MST)" | ||||
| 	tm, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)") | ||||
| 	e.args = []driver.Value{5, tm} | ||||
|  | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: int64(5), Ordinal: 1}, | ||||
| 		{Value: tm, Ordinal: 2}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Error("arguments should match, but it did not") | ||||
| 	} | ||||
|  | ||||
| 	e.args = []driver.Value{5, AnyArg()} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Errorf("arguments should match, but it did not: %s", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestQueryExpectationArgComparisonBool(t *testing.T) { | ||||
| 	var e *queryBasedExpectation | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{true}, converter: driver.DefaultParameterConverter} | ||||
| 	against := []driver.NamedValue{ | ||||
| 		{Value: true, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Error("arguments should match, since arguments are the same") | ||||
| 	} | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{false}, converter: driver.DefaultParameterConverter} | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: false, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err != nil { | ||||
| 		t.Error("arguments should match, since argument are the same") | ||||
| 	} | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{true}, converter: driver.DefaultParameterConverter} | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: false, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since argument is different") | ||||
| 	} | ||||
|  | ||||
| 	e = &queryBasedExpectation{args: []driver.Value{false}, converter: driver.DefaultParameterConverter} | ||||
| 	against = []driver.NamedValue{ | ||||
| 		{Value: true, Ordinal: 1}, | ||||
| 	} | ||||
| 	if err := e.argsMatches(against); err == nil { | ||||
| 		t.Error("arguments should not match, since argument is different") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ExampleExpectedExec() { | ||||
| 	db, mock, _ := New() | ||||
| 	result := NewErrorResult(fmt.Errorf("some error")) | ||||
| @@ -140,20 +45,6 @@ func TestBuildQuery(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type CustomConverter struct{} | ||||
|  | ||||
| func (s CustomConverter) ConvertValue(v interface{}) (driver.Value, error) { | ||||
| 	switch v.(type) { | ||||
| 	case string: | ||||
| 		return v.(string), nil | ||||
| 	case []string: | ||||
| 		return v.([]string), nil | ||||
| 	case int: | ||||
| 		return v.(int), nil | ||||
| 	default: | ||||
| 		return nil, errors.New(fmt.Sprintf("cannot convert %T with value %v", v, v)) | ||||
| 	} | ||||
| } | ||||
| func TestCustomValueConverterQueryScan(t *testing.T) { | ||||
| 	db, mock, _ := New(ValueConverterOption(CustomConverter{})) | ||||
| 	query := ` | ||||
|   | ||||
							
								
								
									
										74
									
								
								sqlmock_before_go18.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								sqlmock_before_go18.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| // +build !go1.8 | ||||
|  | ||||
| /* | ||||
| Package sqlmock is a mock library implementing sql driver. Which has one and only | ||||
| purpose - to simulate any sql driver behavior in tests, without needing a real | ||||
| database connection. It helps to maintain correct **TDD** workflow. | ||||
|  | ||||
| It does not require any modifications to your source code in order to test | ||||
| and mock database operations. Supports concurrency and multiple database mocking. | ||||
|  | ||||
| The driver allows to mock any sql driver method behavior. | ||||
| */ | ||||
| package sqlmock | ||||
|  | ||||
| func (c *sqlmock) exec(query string, args []namedValue) (*ExpectedExec, error) { | ||||
| 	var expected *ExpectedExec | ||||
| 	var fulfilled int | ||||
| 	var ok bool | ||||
| 	for _, next := range c.expected { | ||||
| 		next.Lock() | ||||
| 		if next.fulfilled() { | ||||
| 			next.Unlock() | ||||
| 			fulfilled++ | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if c.ordered { | ||||
| 			if expected, ok = next.(*ExpectedExec); ok { | ||||
| 				break | ||||
| 			} | ||||
| 			next.Unlock() | ||||
| 			return nil, fmt.Errorf("call to ExecQuery '%s' with args %+v, was not expected, next expectation is: %s", query, args, next) | ||||
| 		} | ||||
| 		if exec, ok := next.(*ExpectedExec); ok { | ||||
| 			if err := c.queryMatcher.Match(exec.expectSQL, query); err != nil { | ||||
| 				next.Unlock() | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			if err := exec.attemptArgMatch(args); err == nil { | ||||
| 				expected = exec | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		next.Unlock() | ||||
| 	} | ||||
| 	if expected == nil { | ||||
| 		msg := "call to ExecQuery '%s' with args %+v was not expected" | ||||
| 		if fulfilled == len(c.expected) { | ||||
| 			msg = "all expectations were already fulfilled, " + msg | ||||
| 		} | ||||
| 		return nil, fmt.Errorf(msg, query, args) | ||||
| 	} | ||||
| 	defer expected.Unlock() | ||||
|  | ||||
| 	if err := c.queryMatcher.Match(expected.expectSQL, query); err != nil { | ||||
| 		return nil, fmt.Errorf("ExecQuery: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := expected.argsMatches(args); err != nil { | ||||
| 		return nil, fmt.Errorf("ExecQuery '%s', arguments do not match: %s", query, err) | ||||
| 	} | ||||
|  | ||||
| 	expected.triggered = true | ||||
| 	if expected.err != nil { | ||||
| 		return expected, expected.err // mocked to return error | ||||
| 	} | ||||
|  | ||||
| 	if expected.result == nil { | ||||
| 		return nil, fmt.Errorf("ExecQuery '%s' with args %+v, must return a database/sql/driver.Result, but it was not set for expectation %T as %+v", query, args, expected, expected) | ||||
| 	} | ||||
|  | ||||
| 	return expected, nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user