-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathnamedParameterQuery_test.go
365 lines (317 loc) · 10.2 KB
/
namedParameterQuery_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
package namedParameterQuery
import (
"testing"
)
/*
Represents a single test of query parsing.
Given an [Input] query, if the actual result of parsing
does not match the [Expected] string, the test fails
*/
type QueryParsingTest struct {
Name string
Input string
Expected string
ExpectedParameters int
}
/*
Represents a single test of parameter parsing.
Given the [Query] and a set of [Parameters], if the actual parameter output
from GetParsedParameters() matches the given [ExpectedParameters].
These tests specifically check type of output parameters, too.
*/
type ParameterParsingTest struct {
Name string
Query string
Parameters []TestQueryParameter
ExpectedParameters []interface{}
}
type TestQueryParameter struct {
Name string
Value interface{}
}
func TestQueryParsing(test *testing.T) {
var query *NamedParameterQuery
// Each of these represents a single test.
queryParsingTests := []QueryParsingTest {
QueryParsingTest {
Input: "SELECT * FROM table WHERE col1 = 1",
Expected: "SELECT * FROM table WHERE col1 = 1",
Name: "NoParameter",
},
QueryParsingTest {
Input: "SELECT * FROM table WHERE col1 = :name",
Expected: "SELECT * FROM table WHERE col1 = ?",
ExpectedParameters: 1,
Name: "SingleParameter",
},
QueryParsingTest {
Input: "SELECT * FROM table WHERE col1 = :name AND col2 = :occupation",
Expected: "SELECT * FROM table WHERE col1 = ? AND col2 = ?",
ExpectedParameters: 2,
Name: "TwoParameters",
},
QueryParsingTest {
Input: "SELECT * FROM table WHERE col1 = :name AND col2 = :occupation",
Expected: "SELECT * FROM table WHERE col1 = ? AND col2 = ?",
ExpectedParameters: 2,
Name: "OneParameterMultipleTimes",
},
QueryParsingTest {
Input: "SELECT * FROM table WHERE col1 IN (:something, :else)",
Expected: "SELECT * FROM table WHERE col1 IN (?, ?)",
ExpectedParameters: 2,
Name: "ParametersInParenthesis",
},
QueryParsingTest {
Input: "SELECT * FROM table WHERE col1 = ':literal' AND col2 LIKE ':literal'",
Expected: "SELECT * FROM table WHERE col1 = ':literal' AND col2 LIKE ':literal'",
Name: "ParametersInQuotes",
},
QueryParsingTest {
Input: "SELECT * FROM table WHERE col1 = ':literal' AND col2 = :literal AND col3 LIKE ':literal'",
Expected: "SELECT * FROM table WHERE col1 = ':literal' AND col2 = ? AND col3 LIKE ':literal'",
ExpectedParameters: 1,
Name: "ParametersInQuotes2",
},
QueryParsingTest {
Input: "SELECT * FROM table WHERE col1 = :foo AND col2 IN (SELECT id FROM tabl2 WHERE col10 = :bar)",
Expected: "SELECT * FROM table WHERE col1 = ? AND col2 IN (SELECT id FROM tabl2 WHERE col10 = ?)",
ExpectedParameters: 2,
Name: "ParametersInSubclause",
},
QueryParsingTest {
Input: "SELECT * FROM table WHERE col1 = :1234567890 AND col2 = :0987654321",
Expected: "SELECT * FROM table WHERE col1 = ? AND col2 = ?",
ExpectedParameters: 2,
Name: "NumericParameters",
},
QueryParsingTest {
Input: "SELECT * FROM table WHERE col1 = :ABCDEFGHIJKLMNOPQRSTUVWXYZ",
Expected: "SELECT * FROM table WHERE col1 = ?",
ExpectedParameters: 1,
Name: "CapsParameters",
},
QueryParsingTest {
Input: "SELECT * FROM table WHERE col1 = :abc123ABC098",
Expected: "SELECT * FROM table WHERE col1 = ?",
ExpectedParameters: 1,
Name: "AltcapsParameters",
},
}
// Run each test.
for _, parsingTest := range queryParsingTests {
query = NewNamedParameterQuery(parsingTest.Input)
// test query texts
if(query.GetParsedQuery() != parsingTest.Expected) {
test.Log("Test '", parsingTest.Name, "': Expected query text did not match actual parsed output")
test.Log("Actual: ", query.GetParsedQuery())
test.Fail()
}
// test parameters
if(len(query.GetParsedParameters()) != parsingTest.ExpectedParameters) {
test.Log("Test '", parsingTest.Name, "': Expected parameters did not match actual parsed parameter count")
test.Fail()
}
}
test.Logf("Run %d query parsing tests", len(queryParsingTests))
}
/*
Tests to ensure that setting parameter values turns out correct when using GetParsedParameters().
These tests ensure correct positioning and type.
*/
func TestParameterReplacement(test *testing.T) {
var query *NamedParameterQuery
var parameterMap map[string]interface{}
// note that if you're adding or editing these tests,
// you'll also want to edit the associated struct for this test below,
// in the next test func.
queryVariableTests := []ParameterParsingTest {
ParameterParsingTest {
Name: "SingleStringParameter",
Query: "SELECT * FROM table WHERE col1 = :foo",
Parameters: []TestQueryParameter {
TestQueryParameter {
Name: "foo",
Value: "bar",
},
},
ExpectedParameters: []interface{} {
"bar",
},
},
ParameterParsingTest {
Name: "TwoStringParameter",
Query: "SELECT * FROM table WHERE col1 = :foo AND col2 = :foo2",
Parameters: []TestQueryParameter {
TestQueryParameter {
Name: "foo",
Value: "bar",
},
TestQueryParameter {
Name: "foo2",
Value: "bart",
},
},
ExpectedParameters: []interface{} {
"bar", "bart",
},
},
ParameterParsingTest {
Name: "TwiceOccurringParameter",
Query: "SELECT * FROM table WHERE col1 = :foo AND col2 = :foo",
Parameters: []TestQueryParameter {
TestQueryParameter {
Name: "foo",
Value: "bar",
},
},
ExpectedParameters: []interface{} {
"bar", "bar",
},
},
ParameterParsingTest {
Name: "ParameterTyping",
Query: "SELECT * FROM table WHERE col1 = :str AND col2 = :int AND col3 = :pi",
Parameters: []TestQueryParameter {
TestQueryParameter {
Name: "str",
Value: "foo",
},
TestQueryParameter {
Name: "int",
Value: 1,
},
TestQueryParameter {
Name: "pi",
Value: 3.14,
},
},
ExpectedParameters: []interface{} {
"foo", 1, 3.14,
},
},
ParameterParsingTest {
Name: "ParameterOrdering",
Query: "SELECT * FROM table WHERE col1 = :foo AND col2 = :bar AND col3 = :foo AND col4 = :foo AND col5 = :bar",
Parameters: []TestQueryParameter {
TestQueryParameter {
Name: "foo",
Value: "something",
},
TestQueryParameter {
Name: "bar",
Value: "else",
},
},
ExpectedParameters: []interface{} {
"something", "else", "something", "something", "else",
},
},
ParameterParsingTest {
Name: "ParameterCaseSensitivity",
Query: "SELECT * FROM table WHERE col1 = :foo AND col2 = :FOO",
Parameters: []TestQueryParameter {
TestQueryParameter {
Name: "foo",
Value: "baz",
},
TestQueryParameter {
Name: "FOO",
Value: "quux",
},
},
ExpectedParameters: []interface{} {
"baz", "quux",
},
},
}
// run variable tests.
for _, variableTest := range queryVariableTests {
// parse query and set values.
parameterMap = make(map[string]interface{}, 8)
query = NewNamedParameterQuery(variableTest.Query)
for _, queryVariable := range variableTest.Parameters {
query.SetValue(queryVariable.Name, queryVariable.Value)
parameterMap[queryVariable.Name] = queryVariable.Value
}
// Test outputs
for index, queryVariable := range query.GetParsedParameters() {
if(queryVariable != variableTest.ExpectedParameters[index]) {
test.Log("Test '", variableTest.Name, "' did not produce the expected parameter output. Actual: '", queryVariable, "', Expected: '", variableTest.ExpectedParameters[index], "'")
test.Fail()
}
}
query = NewNamedParameterQuery(variableTest.Query)
query.SetValuesFromMap(parameterMap)
// test map parameter outputs.
for index, queryVariable := range query.GetParsedParameters() {
if(queryVariable != variableTest.ExpectedParameters[index]) {
test.Log("Test '", variableTest.Name, "' did not produce the expected parameter output when using parameter map. Actual: '", queryVariable, "', Expected: '", variableTest.ExpectedParameters[index], "'")
test.Fail()
}
}
}
test.Logf("Run %d query replacement tests", len(queryVariableTests))
}
// Test for struct parameters.
// TODO: Figure out a way to tie this together with tests for maps/singles.
// Right now, each test needs to be hand-defined with its own struct and test method.
type SingleParameterTest struct {
Foo string
Bar string
Baz int
unexported string
notExported int
}
func TestStructParameters(test *testing.T) {
var query *NamedParameterQuery
var singleParam SingleParameterTest
singleParam.Foo = "foo"
singleParam.Bar = "bar"
singleParam.Baz = 15
singleParam.unexported = "nothing"
singleParam.notExported = -1
//
query = NewNamedParameterQuery("SELECT * FROM table WHERE col1 = :Foo AND col2 = :Bar AND col3 = :Baz")
query.SetValuesFromStruct(singleParam)
verifyStructParameters("MultipleStructReplacement", test, query, []interface{} {
"foo",
"bar",
15,
})
//
query = NewNamedParameterQuery("SELECT * FROM table WHERE col1 = :Foo AND col2 = :Bar AND col3 = :Foo AND col4 = :Foo AND col5 = :Baz")
query.SetValuesFromStruct(singleParam)
verifyStructParameters("RecurringStructParameterReplacement", test, query, []interface{} {
"foo",
"bar",
"foo",
"foo",
15,
})
//
query = NewNamedParameterQuery("SELECT * FROM table WHERE col1 = :unexported AND col2 = :notExported AND col3 = :Foo")
query.SetValuesFromStruct(singleParam)
verifyStructParameters("UnexportedStructReplacement", test, query, []interface{} {
nil,
nil,
"foo",
})
}
func verifyStructParameters(testName string, test *testing.T, query *NamedParameterQuery, expectedParameters []interface{}) {
var actualParameters []interface{}
actualParameters = query.GetParsedParameters()
actualParameterLength := len(actualParameters)
expectedParameterLength := len(expectedParameters)
if(actualParameterLength != expectedParameterLength) {
test.Log("Test ", testName, ": Actual parameters (", actualParameterLength, ") returned from struct query did not match expected parameters (", expectedParameterLength, ")")
test.Fail()
}
for index, parameter := range actualParameters {
if(parameter != expectedParameters[index]) {
test.Log("Test ", testName, ": Actual parameter at position ", index, " (", parameter, ") did not match expected parameter (", expectedParameters[index], ")")
test.Fail()
}
}
test.Logf("Run %d struct reflection parameter tests", actualParameterLength)
}