2015-07-17 12:14:30 +02:00
|
|
|
package sqlmock
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"database/sql/driver"
|
|
|
|
"fmt"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
|
|
|
var pool *mockDriver
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
pool = &mockDriver{
|
2015-08-28 10:06:14 +02:00
|
|
|
conns: make(map[string]*sqlmock),
|
2015-07-17 12:14:30 +02:00
|
|
|
}
|
|
|
|
sql.Register("sqlmock", pool)
|
|
|
|
}
|
|
|
|
|
|
|
|
type mockDriver struct {
|
|
|
|
sync.Mutex
|
|
|
|
counter int
|
2015-08-28 10:06:14 +02:00
|
|
|
conns map[string]*sqlmock
|
2015-07-17 12:14:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (d *mockDriver) Open(dsn string) (driver.Conn, error) {
|
|
|
|
d.Lock()
|
|
|
|
defer d.Unlock()
|
|
|
|
|
|
|
|
c, ok := d.conns[dsn]
|
|
|
|
if !ok {
|
|
|
|
return c, fmt.Errorf("expected a connection to be available, but it is not")
|
|
|
|
}
|
|
|
|
|
|
|
|
c.opened++
|
|
|
|
return c, nil
|
|
|
|
}
|
|
|
|
|
2018-09-14 11:03:24 +02:00
|
|
|
// New creates sqlmock database connection and a mock to manage expectations.
|
|
|
|
// Accepts options, like ValueConverterOption, to use a ValueConverter from
|
|
|
|
// a specific driver.
|
2015-07-17 12:14:30 +02:00
|
|
|
// Pings db so that all expectations could be
|
|
|
|
// asserted.
|
2022-12-22 09:39:33 +02:00
|
|
|
func New(options ...SqlMockOption) (*sql.DB, Sqlmock, error) {
|
2015-07-17 12:14:30 +02:00
|
|
|
pool.Lock()
|
|
|
|
dsn := fmt.Sprintf("sqlmock_db_%d", pool.counter)
|
|
|
|
pool.counter++
|
|
|
|
|
2015-08-28 10:06:14 +02:00
|
|
|
smock := &sqlmock{dsn: dsn, drv: pool, ordered: true}
|
|
|
|
pool.conns[dsn] = smock
|
2015-07-17 12:14:30 +02:00
|
|
|
pool.Unlock()
|
|
|
|
|
2018-08-06 22:29:24 +02:00
|
|
|
return smock.open(options)
|
2015-09-10 20:31:35 +02:00
|
|
|
}
|
|
|
|
|
2018-09-14 11:03:24 +02:00
|
|
|
// NewWithDSN creates sqlmock database connection with a specific DSN
|
|
|
|
// and a mock to manage expectations.
|
|
|
|
// Accepts options, like ValueConverterOption, to use a ValueConverter from
|
|
|
|
// a specific driver.
|
2015-09-10 20:31:35 +02:00
|
|
|
// Pings db so that all expectations could be asserted.
|
|
|
|
//
|
|
|
|
// This method is introduced because of sql abstraction
|
|
|
|
// libraries, which do not provide a way to initialize
|
|
|
|
// with sql.DB instance. For example GORM library.
|
|
|
|
//
|
|
|
|
// Note, it will error if attempted to create with an
|
|
|
|
// already used dsn
|
|
|
|
//
|
|
|
|
// It is not recommended to use this method, unless you
|
|
|
|
// really need it and there is no other way around.
|
2022-12-22 09:39:33 +02:00
|
|
|
func NewWithDSN(dsn string, options ...SqlMockOption) (*sql.DB, Sqlmock, error) {
|
2015-09-10 20:31:35 +02:00
|
|
|
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)
|
2015-07-17 12:14:30 +02:00
|
|
|
}
|
2015-09-10 20:31:35 +02:00
|
|
|
smock := &sqlmock{dsn: dsn, drv: pool, ordered: true}
|
|
|
|
pool.conns[dsn] = smock
|
|
|
|
pool.Unlock()
|
|
|
|
|
2018-08-06 22:29:24 +02:00
|
|
|
return smock.open(options)
|
|
|
|
}
|