• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

smallnest / exp / 12311584661

13 Dec 2024 07:40AM UTC coverage: 74.187% (-0.3%) from 74.448%
12311584661

push

github

chaoyuepan
improve sqlmock

6 of 8 new or added lines in 1 file covered. (75.0%)

14 existing lines in 3 files now uncovered.

2555 of 3444 relevant lines covered (74.19%)

3039036.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.16
/sqlmock/sqlmock.go
1
package sqlmock
2

3
import (
4
        "bytes"
5
        "context"
6
        "database/sql"
7
        "database/sql/driver"
8
        "encoding/json"
9
        "fmt"
10
        "regexp"
11
        "sync"
12
)
13

14
var (
15
        _ driver.Connector = &MockConnector{}
16
        _ driver.Driver    = &MockDriver{}
17
        _ driver.Conn      = &MockConn{}
18
        _ driver.Stmt      = &MockStmt{}
19
        _ driver.Result    = &MockResult{}
20
        _ driver.Rows      = &MockRows{}
21
        _ driver.Tx        = &MockTx{}
22
)
23

24
// ExpectedQuery represents an expected query
25
type ExpectedQuery struct {
26
        query   string
27
        matcher *regexp.Regexp
28
        args    []driver.Value
29
        rows    [][]driver.Value
30
        columns []string
31
        err     error
32

33
        CallCount int
34
}
35

36
// MockDB simulates a database connection
37
type MockDB struct {
38
        mu       sync.Mutex
39
        expected []*ExpectedQuery
40
}
41

42
// NewMock creates a new mock database
43
func NewMock() *MockDB {
7✔
44
        return &MockDB{
7✔
45
                expected: []*ExpectedQuery{},
7✔
46
        }
7✔
47
}
7✔
48

49
// ExpectQuery expects a specific query
50
func (m *MockDB) ExpectQuery(query string, args ...driver.Value) *ExpectedQuery {
6✔
51
        m.mu.Lock()
6✔
52
        defer m.mu.Unlock()
6✔
53

6✔
54
        eq := &ExpectedQuery{
6✔
55
                query: query,
6✔
56
                args:  args,
6✔
57
        }
6✔
58
        m.expected = append(m.expected, eq)
6✔
59
        return eq
6✔
60
}
6✔
61

62
// Match expects a specific query with a matcher
63
func (m *MockDB) Match(matcher string, args ...driver.Value) *ExpectedQuery {
2✔
64
        m.mu.Lock()
2✔
65
        defer m.mu.Unlock()
2✔
66

2✔
67
        eq := &ExpectedQuery{
2✔
68
                args:    args,
2✔
69
                matcher: regexp.MustCompile(matcher),
2✔
70
        }
2✔
71
        m.expected = append(m.expected, eq)
2✔
72
        return eq
2✔
73
}
2✔
74

75
func (eq *ExpectedQuery) WithArgs(args ...driver.Value) *ExpectedQuery {
4✔
76
        eq.args = args
4✔
77
        return eq
4✔
78
}
4✔
79

80
// WillReturnRows sets the rows to be returned for the query
81
func (eq *ExpectedQuery) WillReturnRows(columns []string, rows [][]driver.Value) *ExpectedQuery {
7✔
82
        eq.rows = rows
7✔
83
        eq.columns = columns
7✔
84
        return eq
7✔
85
}
7✔
86

87
// WillReturnError sets the error to be returned for the query
88
func (eq *ExpectedQuery) WillReturnError(columns []string, err error) *ExpectedQuery {
1✔
89
        eq.err = err
1✔
90
        eq.columns = columns
1✔
91
        return eq
1✔
92
}
1✔
93

94
// Open simulates a database connection
95
func (m *MockDB) Open(driverName string) (*sql.DB, error) {
7✔
96
        connector := &MockConnector{mockDB: m}
7✔
97
        return sql.OpenDB(connector), nil
7✔
98
}
7✔
99

100
// MockConnector implements the driver.Connector interface
101
type MockConnector struct {
102
        mockDB *MockDB
103
}
104

105
func (mc *MockConnector) Connect(ctx context.Context) (driver.Conn, error) {
7✔
106
        return &MockConn{mockDB: mc.mockDB}, nil
7✔
107
}
7✔
108

109
func (mc *MockConnector) Driver() driver.Driver {
×
110
        return &MockDriver{mockDB: mc.mockDB}
×
111
}
×
112

113
// MockDriver implements the driver.Driver interface
114
type MockDriver struct {
115
        mockDB *MockDB
116
}
117

118
func (md *MockDriver) Open(name string) (driver.Conn, error) {
×
119
        return &MockConn{mockDB: md.mockDB}, nil
×
120
}
×
121

122
// MockConn implements the driver.Conn interface
123
type MockConn struct {
124
        mockDB *MockDB
125
}
126

127
func (mc *MockConn) Prepare(query string) (driver.Stmt, error) {
8✔
128
        return &MockStmt{
8✔
129
                mockDB: mc.mockDB,
8✔
130
                query:  query,
8✔
131
        }, nil
8✔
132
}
8✔
133

134
func (mc *MockConn) Close() error {
×
135
        return nil
×
136
}
×
137

138
func (mc *MockConn) Begin() (driver.Tx, error) {
×
139
        return &MockTx{}, nil
×
140
}
×
141

142
// MockStmt implements the driver.Stmt interface
143
type MockStmt struct {
144
        mockDB *MockDB
145
        query  string
146
}
147

148
func (ms *MockStmt) Close() error {
8✔
149
        return nil
8✔
150
}
8✔
151

152
func (ms *MockStmt) NumInput() int {
8✔
153
        return -1
8✔
154
}
8✔
155

156
func (ms *MockStmt) Exec(args []driver.Value) (driver.Result, error) {
1✔
157
        ms.mockDB.mu.Lock()
1✔
158
        defer ms.mockDB.mu.Unlock()
1✔
159

1✔
160
        for i, expected := range ms.mockDB.expected {
2✔
161
                if expected.matcher != nil && expected.matcher.MatchString(ms.query) && matchArgs(ms.mockDB.expected[i].args, args) {
1✔
NEW
162
                        // ms.mockDB.expected = append(ms.mockDB.expected[:i], ms.mockDB.expected[i+1:]...)
×
NEW
163
                        expected.CallCount++
×
164

×
165
                        if expected.err != nil {
×
166
                                return nil, expected.err
×
167
                        }
×
168

169
                        return &MockResult{}, nil
×
170
                }
171

172
                if CompareSQL(expected.query, ms.query) && matchArgs(expected.args, args) {
2✔
173
                        // ms.mockDB.expected = append(ms.mockDB.expected[:i], ms.mockDB.expected[i+1:]...)
1✔
174
                        expected.CallCount++
1✔
175

1✔
176
                        if expected.err != nil {
1✔
177
                                return nil, expected.err
×
178
                        }
×
179

180
                        return &MockResult{}, nil
1✔
181
                }
182
        }
183

184
        return nil, fmt.Errorf("unexpected query: %s", ms.query)
×
185
}
186

187
func (ms *MockStmt) Query(args []driver.Value) (driver.Rows, error) {
7✔
188
        ms.mockDB.mu.Lock()
7✔
189
        defer ms.mockDB.mu.Unlock()
7✔
190

7✔
191
        for i, expected := range ms.mockDB.expected {
15✔
192
                if expected.matcher != nil && expected.matcher.MatchString(ms.query) && matchArgs(ms.mockDB.expected[i].args, args) {
9✔
193
                        // ms.mockDB.expected = append(ms.mockDB.expected[:i], ms.mockDB.expected[i+1:]...)
1✔
194
                        expected.CallCount++
1✔
195

1✔
196
                        if expected.err != nil {
1✔
197
                                return nil, expected.err
×
198
                        }
×
199

200
                        return &MockRows{columns: expected.columns, rows: expected.rows}, nil
1✔
201
                }
202

203
                if CompareSQL(expected.query, ms.query) && matchArgs(expected.args, args) {
12✔
204
                        // ms.mockDB.expected = append(ms.mockDB.expected[:i], ms.mockDB.expected[i+1:]...)
5✔
205
                        expected.CallCount++
5✔
206

5✔
207
                        if expected.err != nil {
6✔
208
                                return nil, expected.err
1✔
209
                        }
1✔
210

211
                        return &MockRows{columns: expected.columns, rows: expected.rows}, nil
4✔
212
                }
213
        }
214

215
        return nil, fmt.Errorf("unexpected query: %s", ms.query)
1✔
216
}
217

218
// MockResult implements the driver.Result interface
219
type MockResult struct{}
220

221
func (mr *MockResult) LastInsertId() (int64, error) {
×
222
        return 0, nil
×
223
}
×
224

225
func (mr *MockResult) RowsAffected() (int64, error) {
×
226
        return 0, nil
×
227
}
×
228

229
// MockRows implements the driver.Rows interface
230
type MockRows struct {
231
        rows    [][]driver.Value
232
        columns []string
233
        cursor  int
234
}
235

236
func (mr *MockRows) Columns() []string {
5✔
237
        return mr.columns
5✔
238
}
5✔
239

240
func (mr *MockRows) Close() error {
5✔
241
        return nil
5✔
242
}
5✔
243

244
func (mr *MockRows) Next(dest []driver.Value) error {
7✔
245
        if mr.cursor >= len(mr.rows) {
8✔
246
                return sql.ErrNoRows
1✔
247
        }
1✔
248

249
        copy(dest, mr.rows[mr.cursor])
6✔
250
        mr.cursor++
6✔
251
        return nil
6✔
252
}
253

254
// MockTx implements the driver.Tx interface
255
type MockTx struct{}
256

257
func (mt *MockTx) Commit() error {
×
258
        return nil
×
259
}
×
260

261
func (mt *MockTx) Rollback() error {
×
262
        return nil
×
263
}
×
264

265
// Helper function: match query arguments
266
func matchArgs(expected, actual []driver.Value) bool {
8✔
267
        if len(expected) != len(actual) {
8✔
268
                return false
×
269
        }
×
270

271
        for i := range expected {
16✔
272
                a, _ := json.Marshal(expected[i])
8✔
273
                b, _ := json.Marshal(actual[i])
8✔
274

8✔
275
                if !bytes.Equal(a, b) {
9✔
276
                        return false
1✔
277
                }
1✔
278
        }
279

280
        return true
7✔
281
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc