1 package sanitize_test
2
3 import (
4 "testing"
5 "time"
6
7 "github.com/jackc/pgx/v5/internal/sanitize"
8 )
9
10 func TestNewQuery(t *testing.T) {
11 successTests := []struct {
12 sql string
13 expected sanitize.Query
14 }{
15 {
16 sql: "select 42",
17 expected: sanitize.Query{Parts: []sanitize.Part{"select 42"}},
18 },
19 {
20 sql: "select $1",
21 expected: sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
22 },
23 {
24 sql: "select 'quoted $42', $1",
25 expected: sanitize.Query{Parts: []sanitize.Part{"select 'quoted $42', ", 1}},
26 },
27 {
28 sql: `select "doubled quoted $42", $1`,
29 expected: sanitize.Query{Parts: []sanitize.Part{`select "doubled quoted $42", `, 1}},
30 },
31 {
32 sql: "select 'foo''bar', $1",
33 expected: sanitize.Query{Parts: []sanitize.Part{"select 'foo''bar', ", 1}},
34 },
35 {
36 sql: `select "foo""bar", $1`,
37 expected: sanitize.Query{Parts: []sanitize.Part{`select "foo""bar", `, 1}},
38 },
39 {
40 sql: "select '''', $1",
41 expected: sanitize.Query{Parts: []sanitize.Part{"select '''', ", 1}},
42 },
43 {
44 sql: `select """", $1`,
45 expected: sanitize.Query{Parts: []sanitize.Part{`select """", `, 1}},
46 },
47 {
48 sql: "select $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11",
49 expected: sanitize.Query{Parts: []sanitize.Part{"select ", 1, ", ", 2, ", ", 3, ", ", 4, ", ", 5, ", ", 6, ", ", 7, ", ", 8, ", ", 9, ", ", 10, ", ", 11}},
50 },
51 {
52 sql: `select "adsf""$1""adsf", $1, 'foo''$$12bar', $2, '$3'`,
53 expected: sanitize.Query{Parts: []sanitize.Part{`select "adsf""$1""adsf", `, 1, `, 'foo''$$12bar', `, 2, `, '$3'`}},
54 },
55 {
56 sql: `select E'escape string\' $42', $1`,
57 expected: sanitize.Query{Parts: []sanitize.Part{`select E'escape string\' $42', `, 1}},
58 },
59 {
60 sql: `select e'escape string\' $42', $1`,
61 expected: sanitize.Query{Parts: []sanitize.Part{`select e'escape string\' $42', `, 1}},
62 },
63 {
64 sql: `select /* a baby's toy */ 'barbie', $1`,
65 expected: sanitize.Query{Parts: []sanitize.Part{`select /* a baby's toy */ 'barbie', `, 1}},
66 },
67 {
68 sql: `select /* *_* */ $1`,
69 expected: sanitize.Query{Parts: []sanitize.Part{`select /* *_* */ `, 1}},
70 },
71 {
72 sql: `select 42 /* /* /* 42 */ */ */, $1`,
73 expected: sanitize.Query{Parts: []sanitize.Part{`select 42 /* /* /* 42 */ */ */, `, 1}},
74 },
75 {
76 sql: "select -- a baby's toy\n'barbie', $1",
77 expected: sanitize.Query{Parts: []sanitize.Part{"select -- a baby's toy\n'barbie', ", 1}},
78 },
79 {
80 sql: "select 42 -- is a Deep Thought's favorite number",
81 expected: sanitize.Query{Parts: []sanitize.Part{"select 42 -- is a Deep Thought's favorite number"}},
82 },
83 {
84 sql: "select 42, -- \\nis a Deep Thought's favorite number\n$1",
85 expected: sanitize.Query{Parts: []sanitize.Part{"select 42, -- \\nis a Deep Thought's favorite number\n", 1}},
86 },
87 {
88 sql: "select 42, -- \\nis a Deep Thought's favorite number\r$1",
89 expected: sanitize.Query{Parts: []sanitize.Part{"select 42, -- \\nis a Deep Thought's favorite number\r", 1}},
90 },
91 {
92
93 sql: "select 'hello w�rld'",
94 expected: sanitize.Query{Parts: []sanitize.Part{"select 'hello w�rld'"}},
95 },
96 {
97
98 sql: "select 'hello world",
99 expected: sanitize.Query{Parts: []sanitize.Part{"select 'hello world"}},
100 },
101 }
102
103 for i, tt := range successTests {
104 query, err := sanitize.NewQuery(tt.sql)
105 if err != nil {
106 t.Errorf("%d. %v", i, err)
107 }
108
109 if len(query.Parts) == len(tt.expected.Parts) {
110 for j := range query.Parts {
111 if query.Parts[j] != tt.expected.Parts[j] {
112 t.Errorf("%d. expected part %d to be %v but it was %v", i, j, tt.expected.Parts[j], query.Parts[j])
113 }
114 }
115 } else {
116 t.Errorf("%d. expected query parts to be %v but it was %v", i, tt.expected.Parts, query.Parts)
117 }
118 }
119 }
120
121 func TestQuerySanitize(t *testing.T) {
122 successfulTests := []struct {
123 query sanitize.Query
124 args []any
125 expected string
126 }{
127 {
128 query: sanitize.Query{Parts: []sanitize.Part{"select 42"}},
129 args: []any{},
130 expected: `select 42`,
131 },
132 {
133 query: sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
134 args: []any{int64(42)},
135 expected: `select 42 `,
136 },
137 {
138 query: sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
139 args: []any{float64(1.23)},
140 expected: `select 1.23 `,
141 },
142 {
143 query: sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
144 args: []any{true},
145 expected: `select true `,
146 },
147 {
148 query: sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
149 args: []any{[]byte{0, 1, 2, 3, 255}},
150 expected: `select '\x00010203ff' `,
151 },
152 {
153 query: sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
154 args: []any{nil},
155 expected: `select null `,
156 },
157 {
158 query: sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
159 args: []any{"foobar"},
160 expected: `select 'foobar' `,
161 },
162 {
163 query: sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
164 args: []any{"foo'bar"},
165 expected: `select 'foo''bar' `,
166 },
167 {
168 query: sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
169 args: []any{`foo\'bar`},
170 expected: `select 'foo\''bar' `,
171 },
172 {
173 query: sanitize.Query{Parts: []sanitize.Part{"insert ", 1}},
174 args: []any{time.Date(2020, time.March, 1, 23, 59, 59, 999999999, time.UTC)},
175 expected: `insert '2020-03-01 23:59:59.999999Z' `,
176 },
177 {
178 query: sanitize.Query{Parts: []sanitize.Part{"select 1-", 1}},
179 args: []any{int64(-1)},
180 expected: `select 1- -1 `,
181 },
182 {
183 query: sanitize.Query{Parts: []sanitize.Part{"select 1-", 1}},
184 args: []any{float64(-1)},
185 expected: `select 1- -1 `,
186 },
187 }
188
189 for i, tt := range successfulTests {
190 actual, err := tt.query.Sanitize(tt.args...)
191 if err != nil {
192 t.Errorf("%d. %v", i, err)
193 continue
194 }
195
196 if tt.expected != actual {
197 t.Errorf("%d. expected %s, but got %s", i, tt.expected, actual)
198 }
199 }
200
201 errorTests := []struct {
202 query sanitize.Query
203 args []any
204 expected string
205 }{
206 {
207 query: sanitize.Query{Parts: []sanitize.Part{"select ", 1, ", ", 2}},
208 args: []any{int64(42)},
209 expected: `insufficient arguments`,
210 },
211 {
212 query: sanitize.Query{Parts: []sanitize.Part{"select 'foo'"}},
213 args: []any{int64(42)},
214 expected: `unused argument: 0`,
215 },
216 {
217 query: sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
218 args: []any{42},
219 expected: `invalid arg type: int`,
220 },
221 }
222
223 for i, tt := range errorTests {
224 _, err := tt.query.Sanitize(tt.args...)
225 if err == nil || err.Error() != tt.expected {
226 t.Errorf("%d. expected error %v, got %v", i, tt.expected, err)
227 }
228 }
229 }
230
View as plain text