Skip to content

Commit

Permalink
rename sqlmock to pgxmock
Browse files Browse the repository at this point in the history
  • Loading branch information
pashagolub committed Feb 5, 2021
1 parent b3b74f9 commit 323932f
Show file tree
Hide file tree
Showing 39 changed files with 1,552 additions and 3,295 deletions.
8 changes: 3 additions & 5 deletions argument.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package sqlmock

import "database/sql/driver"
package pgxmock

// Argument interface allows to match
// any argument in specific way when used with
// ExpectedQuery and ExpectedExec expectations.
type Argument interface {
Match(driver.Value) bool
Match(interface{}) bool
}

// AnyArg will return an Argument which can
Expand All @@ -19,6 +17,6 @@ func AnyArg() Argument {

type anyArgument struct{}

func (a anyArgument) Match(_ driver.Value) bool {
func (a anyArgument) Match(_ interface{}) bool {
return true
}
19 changes: 10 additions & 9 deletions argument_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sqlmock
package pgxmock

import (
"context"
"database/sql/driver"
"testing"
"time"
Expand All @@ -16,17 +17,17 @@ func (a AnyTime) Match(v driver.Value) bool {

func TestAnyTimeArgument(t *testing.T) {
t.Parallel()
db, mock, err := New()
mock, err := New()
if err != nil {
t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
}
defer db.Close()
// defer db.Close()

mock.ExpectExec("INSERT INTO users").
WithArgs("john", AnyTime{}).
WillReturnResult(NewResult(1, 1))
WillReturnResult(NewResult("INSERT", 1))

_, err = db.Exec("INSERT INTO users(name, created_at) VALUES (?, ?)", "john", time.Now())
_, err = mock.Exec(context.Background(), "INSERT INTO users(name, created_at) VALUES (?, ?)", "john", time.Now())
if err != nil {
t.Errorf("error '%s' was not expected, while inserting a row", err)
}
Expand All @@ -38,16 +39,16 @@ func TestAnyTimeArgument(t *testing.T) {

func TestByteSliceArgument(t *testing.T) {
t.Parallel()
db, mock, err := New()
mock, err := New()
if err != nil {
t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
}
defer db.Close()
// defer db.Close()

username := []byte("user")
mock.ExpectExec("INSERT INTO users").WithArgs(username).WillReturnResult(NewResult(1, 1))
mock.ExpectExec("INSERT INTO users").WithArgs(username).WillReturnResult(NewResult("INSERT", 1))

_, err = db.Exec("INSERT INTO users(username) VALUES (?)", username)
_, err = mock.Exec(context.Background(), "INSERT INTO users(username) VALUES (?)", username)
if err != nil {
t.Errorf("error '%s' was not expected, while inserting a row", err)
}
Expand Down
2 changes: 1 addition & 1 deletion column.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sqlmock
package pgxmock

import "reflect"

Expand Down
2 changes: 1 addition & 1 deletion column_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sqlmock
package pgxmock

import (
"reflect"
Expand Down
21 changes: 9 additions & 12 deletions driver.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package sqlmock
package pgxmock

import (
"database/sql"
"database/sql/driver"
"fmt"
"sync"
)
Expand All @@ -11,18 +9,17 @@ var pool *mockDriver

func init() {
pool = &mockDriver{
conns: make(map[string]*sqlmock),
conns: make(map[string]*pgxmock),
}
sql.Register("sqlmock", pool)
}

type mockDriver struct {
sync.Mutex
counter int
conns map[string]*sqlmock
conns map[string]*pgxmock
}

func (d *mockDriver) Open(dsn string) (driver.Conn, error) {
func (d *mockDriver) Open(dsn string) (Pgxmock, error) {
d.Lock()
defer d.Unlock()

Expand All @@ -40,12 +37,12 @@ func (d *mockDriver) Open(dsn string) (driver.Conn, error) {
// a specific driver.
// Pings db so that all expectations could be
// asserted.
func New(options ...func(*sqlmock) error) (*sql.DB, Sqlmock, error) {
func New(options ...func(*pgxmock) error) (Pgxmock, error) {
pool.Lock()
dsn := fmt.Sprintf("sqlmock_db_%d", pool.counter)
pool.counter++

smock := &sqlmock{dsn: dsn, drv: pool, ordered: true}
smock := &pgxmock{dsn: dsn, drv: pool, ordered: true}
pool.conns[dsn] = smock
pool.Unlock()

Expand All @@ -67,13 +64,13 @@ func New(options ...func(*sqlmock) error) (*sql.DB, Sqlmock, error) {
//
// It is not recommended to use this method, unless you
// really need it and there is no other way around.
func NewWithDSN(dsn string, options ...func(*sqlmock) error) (*sql.DB, Sqlmock, error) {
func NewWithDSN(dsn string, options ...func(*pgxmock) error) (Pgxmock, error) {
pool.Lock()
if _, ok := pool.conns[dsn]; ok {
pool.Unlock()
return nil, nil, fmt.Errorf("cannot create a new mock database with the same dsn: %s", dsn)
return nil, fmt.Errorf("cannot create a new mock database with the same dsn: %s", dsn)
}
smock := &sqlmock{dsn: dsn, drv: pool, ordered: true}
smock := &pgxmock{dsn: dsn, drv: pool, ordered: true}
pool.conns[dsn] = smock
pool.Unlock()

Expand Down
76 changes: 22 additions & 54 deletions driver_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package sqlmock
package pgxmock

import (
"context"
"database/sql/driver"
"errors"
"fmt"
"testing"
)

Expand All @@ -17,27 +17,16 @@ func (c *converter) ConvertValue(v interface{}) (driver.Value, error) {
return nil, errors.New("converter disabled")
}

func ExampleNew() {
db, mock, err := New()
if err != nil {
fmt.Println("expected no error, but got:", err)
return
}
defer db.Close()
// now we can expect operations performed on db
mock.ExpectBegin().WillReturnError(fmt.Errorf("an error will occur on db.Begin() call"))
}

func TestShouldOpenConnectionIssue15(t *testing.T) {
db, mock, err := New()
mock, err := New()
if err != nil {
t.Errorf("expected no error, but got: %s", err)
}
if len(pool.conns) != 1 {
t.Errorf("expected 1 connection in pool, but there is: %d", len(pool.conns))
}

smock, _ := mock.(*sqlmock)
smock, _ := mock.(*pgxmock)
if smock.opened != 1 {
t.Errorf("expected 1 connection on mock to be opened, but there is: %d", smock.opened)
}
Expand All @@ -50,14 +39,14 @@ func TestShouldOpenConnectionIssue15(t *testing.T) {
}()

mock.ExpectQuery("SELECT").WillReturnRows(NewRows([]string{"one", "two"}).AddRow("val1", "val2"))
rows, err := db.Query("SELECT")
rows, err := mock.Query(context.Background(), "SELECT")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
defer rows.Close()

mock.ExpectExec("UPDATE").WillReturnResult(NewResult(1, 1))
if _, err = db.Exec("UPDATE"); err != nil {
mock.ExpectExec("UPDATE").WillReturnResult(NewResult("UPDATE", 1))
if _, err = mock.Exec(context.Background(), "UPDATE"); err != nil {
t.Errorf("unexpected error: %s", err)
}

Expand All @@ -67,7 +56,7 @@ func TestShouldOpenConnectionIssue15(t *testing.T) {
}

mock.ExpectClose()
if err = db.Close(); err != nil {
if err = mock.Close(); err != nil {
t.Errorf("expected no error on close, but got: %s", err)
}

Expand All @@ -78,55 +67,34 @@ func TestShouldOpenConnectionIssue15(t *testing.T) {
}

func TestTwoOpenConnectionsOnTheSameDSN(t *testing.T) {
db, mock, err := New()
mock, err := New()
if err != nil {
t.Errorf("expected no error, but got: %s", err)
}
db2, mock2, err := New()
mock2, err := New()
if err != nil {
t.Errorf("expected no error, but got: %s", err)
}
if len(pool.conns) != 2 {
t.Errorf("expected 2 connection in pool, but there is: %d", len(pool.conns))
}

if db == db2 {
if mock == mock2 {
t.Errorf("expected not the same database instance, but it is the same")
}
if mock == mock2 {
t.Errorf("expected not the same mock instance, but it is the same")
}
}

func TestWithOptions(t *testing.T) {
c := &converter{}
_, mock, err := New(ValueConverterOption(c))
if err != nil {
t.Errorf("expected no error, but got: %s", err)
}
smock, _ := mock.(*sqlmock)
if smock.converter.(*converter) != c {
t.Errorf("expected a custom converter to be set")
}
}

func TestWrongDSN(t *testing.T) {
t.Parallel()
db, _, _ := New()
defer db.Close()
if _, err := db.Driver().Open("wrong_dsn"); err == nil {
t.Error("expected error on Open")
}
}

func TestNewDSN(t *testing.T) {
if _, _, err := NewWithDSN("sqlmock_db_99"); err != nil {
t.Errorf("expected no error on NewWithDSN, but got: %s", err)
}
}

func TestDuplicateNewDSN(t *testing.T) {
if _, _, err := NewWithDSN("sqlmock_db_1"); err == nil {
t.Error("expected error on NewWithDSN")
}
}
// func TestWithOptions(t *testing.T) {
// c := &converter{}
// _, mock, err := New(ValueConverterOption(c))
// if err != nil {
// t.Errorf("expected no error, but got: %s", err)
// }
// smock, _ := mock.(*pgxmock)
// if smock.converter.(*converter) != c {
// t.Errorf("expected a custom converter to be set")
// }
// }
34 changes: 25 additions & 9 deletions examples/basic/basic.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,54 @@
package main

import "database/sql"
import (
"context"

func recordStats(db *sql.DB, userID, productID int64) (err error) {
tx, err := db.Begin()
"github.com/jackc/pgconn"
pgx "github.com/jackc/pgx/v4"
)

type PgxIface interface {
Begin(context.Context) (pgx.Tx, error)
Commit(context.Context) error
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
QueryRow(context.Context, string, ...interface{}) pgx.Row
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
Ping(context.Context) error
Prepare(context.Context, string, string) (*pgconn.StatementDescription, error)
Close(context.Context) error
}

func recordStats(db PgxIface, userID, productID int64) (err error) {
tx, err := db.Begin(context.Background())
if err != nil {
return
}

defer func() {
switch err {
case nil:
err = tx.Commit()
err = tx.Commit(context.Background())
default:
tx.Rollback()
tx.Rollback(context.Background())
}
}()

if _, err = tx.Exec("UPDATE products SET views = views + 1"); err != nil {
if _, err = tx.Exec(context.Background(), "UPDATE products SET views = views + 1"); err != nil {
return
}
if _, err = tx.Exec("INSERT INTO product_viewers (user_id, product_id) VALUES (?, ?)", userID, productID); err != nil {
if _, err = tx.Exec(context.Background(), "INSERT INTO product_viewers (user_id, product_id) VALUES (?, ?)", userID, productID); err != nil {
return
}
return
}

func main() {
// @NOTE: the real connection is not required for tests
db, err := sql.Open("mysql", "root@/blog")
db, err := pgx.Connect(context.Background(), "root@/blog")
if err != nil {
panic(err)
}
defer db.Close()
defer db.Close(context.Background())

if err = recordStats(db, 1 /*some user id*/, 5 /*some product id*/); err != nil {
panic(err)
Expand Down
14 changes: 7 additions & 7 deletions examples/basic/basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import (
"fmt"
"testing"

"github.com/DATA-DOG/go-sqlmock"
"github.com/pashagolub/pgxmock"
)

// a successful case
func TestShouldUpdateStats(t *testing.T) {
db, mock, err := sqlmock.New()
mock, err := pgxmock.New()
if err != nil {
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
}
defer db.Close()
defer mock.Close()

mock.ExpectBegin()
mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec("UPDATE products").WillReturnResult(pgxmock.NewResult("UPDATE", 1))
mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnResult(pgxmock.NewResult("INSERT", 1))
mock.ExpectCommit()

// now we execute our method
Expand All @@ -33,14 +33,14 @@ func TestShouldUpdateStats(t *testing.T) {

// a failing test case
func TestShouldRollbackStatUpdatesOnFailure(t *testing.T) {
db, mock, err := sqlmock.New()
db, mock, err := pgxmock.New()
if err != nil {
t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
}
defer db.Close()

mock.ExpectBegin()
mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec("UPDATE products").WillReturnResult(pgxmock.NewResult("UPDATE", 1))
mock.ExpectExec("INSERT INTO product_viewers").
WithArgs(2, 3).
WillReturnError(fmt.Errorf("some error"))
Expand Down
Loading

0 comments on commit 323932f

Please sign in to comment.