ronin-code-sql 2.0.0.beta1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +15 -0
- data/.rubocop.yml +13 -0
- data/.yardopts +1 -1
- data/ChangeLog.md +10 -1
- data/Gemfile +4 -0
- data/README.md +26 -16
- data/Rakefile +1 -0
- data/gemspec.yml +3 -3
- data/lib/ronin/code/sql/binary_expr.rb +35 -2
- data/lib/ronin/code/sql/clause.rb +19 -8
- data/lib/ronin/code/sql/clauses.rb +17 -15
- data/lib/ronin/code/sql/emittable.rb +9 -2
- data/lib/ronin/code/sql/emitter.rb +65 -26
- data/lib/ronin/code/sql/field.rb +31 -6
- data/lib/ronin/code/sql/fields.rb +1 -1
- data/lib/ronin/code/sql/function.rb +15 -4
- data/lib/ronin/code/sql/functions.rb +3 -15
- data/lib/ronin/code/sql/injection.rb +4 -4
- data/lib/ronin/code/sql/injection_expr.rb +1 -1
- data/lib/ronin/code/sql/literal.rb +17 -2
- data/lib/ronin/code/sql/literals.rb +1 -1
- data/lib/ronin/code/sql/mixin.rb +95 -0
- data/lib/ronin/code/sql/operators.rb +1 -1
- data/lib/ronin/code/sql/statement.rb +14 -3
- data/lib/ronin/code/sql/statement_list.rb +1 -1
- data/lib/ronin/code/sql/statements.rb +1 -1
- data/lib/ronin/code/sql/unary_expr.rb +24 -2
- data/lib/ronin/code/sql/version.rb +3 -3
- data/lib/ronin/code/sql.rb +5 -64
- data/lib/ronin/code/sqli.rb +30 -0
- data/ronin-code-sql.gemspec +5 -5
- metadata +10 -51
- data/spec/spec_helper.rb +0 -3
- data/spec/sql/binary_expr_examples.rb +0 -25
- data/spec/sql/binary_expr_spec.rb +0 -5
- data/spec/sql/clause_examples.rb +0 -43
- data/spec/sql/clause_spec.rb +0 -31
- data/spec/sql/clauses_spec.rb +0 -47
- data/spec/sql/emittable_spec.rb +0 -41
- data/spec/sql/emitter_spec.rb +0 -533
- data/spec/sql/field_spec.rb +0 -103
- data/spec/sql/fields_spec.rb +0 -40
- data/spec/sql/function_examples.rb +0 -30
- data/spec/sql/function_spec.rb +0 -25
- data/spec/sql/functions_spec.rb +0 -113
- data/spec/sql/injection_expr_spec.rb +0 -98
- data/spec/sql/injection_spec.rb +0 -172
- data/spec/sql/literal_spec.rb +0 -5
- data/spec/sql/literals_spec.rb +0 -46
- data/spec/sql/operators_spec.rb +0 -44
- data/spec/sql/statement_examples.rb +0 -39
- data/spec/sql/statement_list_spec.rb +0 -48
- data/spec/sql/statement_spec.rb +0 -38
- data/spec/sql/statements_spec.rb +0 -22
- data/spec/sql/unary_expr_examples.rb +0 -20
- data/spec/sql/unary_expr_spec.rb +0 -5
- data/spec/sql_spec.rb +0 -18
data/spec/sql/emitter_spec.rb
DELETED
@@ -1,533 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'ronin/code/sql/literal'
|
3
|
-
require 'ronin/code/sql/unary_expr'
|
4
|
-
require 'ronin/code/sql/binary_expr'
|
5
|
-
require 'ronin/code/sql/field'
|
6
|
-
require 'ronin/code/sql/statement'
|
7
|
-
require 'ronin/code/sql/statement_list'
|
8
|
-
require 'ronin/code/sql/emitter'
|
9
|
-
|
10
|
-
describe Ronin::Code::SQL::Emitter do
|
11
|
-
describe "#initialize" do
|
12
|
-
context "without options" do
|
13
|
-
it { expect(subject.space).to eq(' ') }
|
14
|
-
it { expect(subject.quotes).to eq(:single) }
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe "#emit_keyword" do
|
19
|
-
context "when passed an Array of Symbols" do
|
20
|
-
let(:keywords) { [:DROP, :TABLE] }
|
21
|
-
|
22
|
-
it "should join the keywords" do
|
23
|
-
expect(subject.emit_keyword(keywords)).to eq("DROP TABLE")
|
24
|
-
end
|
25
|
-
|
26
|
-
context "when :space is set" do
|
27
|
-
subject { described_class.new(space: '/**/') }
|
28
|
-
|
29
|
-
it "should join the keywords" do
|
30
|
-
expect(subject.emit_keyword(keywords)).to eq("DROP/**/TABLE")
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context "when case is :upper" do
|
36
|
-
let(:keyword) { :select }
|
37
|
-
|
38
|
-
subject { described_class.new(case: :upper) }
|
39
|
-
|
40
|
-
it "should upcase the keyword" do
|
41
|
-
expect(subject.emit_keyword(keyword)).to eq('SELECT')
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
context "when case is :lower" do
|
46
|
-
let(:keyword) { :SELECT }
|
47
|
-
|
48
|
-
subject { described_class.new(case: :lower) }
|
49
|
-
|
50
|
-
it "should upcase the keyword" do
|
51
|
-
expect(subject.emit_keyword(keyword)).to eq('select')
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context "when case is :random" do
|
56
|
-
let(:keyword) { :select }
|
57
|
-
|
58
|
-
subject { described_class.new(case: :random) }
|
59
|
-
|
60
|
-
it "should contain at least one upper-case character" do
|
61
|
-
expect(subject.emit_keyword(keyword)).to match(/[SELECT]/)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
context "when case is nil" do
|
66
|
-
subject { described_class.new(case: nil) }
|
67
|
-
|
68
|
-
let(:keyword) { 'Select' }
|
69
|
-
|
70
|
-
it "should emit the keyword as is" do
|
71
|
-
expect(subject.emit_keyword(keyword)).to eq(keyword)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
describe "#emit_operator" do
|
77
|
-
context "when the operator is a symbol" do
|
78
|
-
it "should emit a String" do
|
79
|
-
expect(subject.emit_operator(:"!=")).to eq('!=')
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
context "otherwise" do
|
84
|
-
subject { described_class.new(case: :lower) }
|
85
|
-
|
86
|
-
it "should emit a keyword" do
|
87
|
-
expect(subject.emit_operator(:AS)).to eq('as')
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
describe "#emit_null" do
|
93
|
-
it "should emit the NULL keyword" do
|
94
|
-
expect(subject.emit_null).to eq('NULL')
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
describe "#emit_false" do
|
99
|
-
it "should emit 1=0" do
|
100
|
-
expect(subject.emit_false).to eq('1=0')
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
describe "#emit_true" do
|
105
|
-
it "should emit 1=1" do
|
106
|
-
expect(subject.emit_true).to eq('1=1')
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
describe "#emit_integer" do
|
111
|
-
it "should emit a String" do
|
112
|
-
expect(subject.emit_integer(10)).to eq('10')
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
describe "#emit_decimal" do
|
117
|
-
it "should emit a String" do
|
118
|
-
expect(subject.emit_decimal(2.5)).to eq('2.5')
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
describe "#emit_string" do
|
123
|
-
it "should emit a String" do
|
124
|
-
expect(subject.emit_string("O'Brian")).to eq("'O''Brian'")
|
125
|
-
end
|
126
|
-
|
127
|
-
context "when :quotes is :double" do
|
128
|
-
subject { described_class.new(quotes: :double) }
|
129
|
-
|
130
|
-
it "should double quote Strings" do
|
131
|
-
expect(subject.emit_string("O'Brian")).to eq("\"O'Brian\"")
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
describe "#emit_field" do
|
137
|
-
subject { described_class.new(case: :upper) }
|
138
|
-
|
139
|
-
let(:field) { Ronin::Code::SQL::Field.new(:id) }
|
140
|
-
|
141
|
-
it "should emit the name as a keyword" do
|
142
|
-
expect(subject.emit_field(field)).to eq('ID')
|
143
|
-
end
|
144
|
-
|
145
|
-
context "when the field has a parent" do
|
146
|
-
let(:parent) { Ronin::Code::SQL::Field.new(:users) }
|
147
|
-
let(:field) { Ronin::Code::SQL::Field.new(:id,parent) }
|
148
|
-
|
149
|
-
it "should emit the parent then the field name" do
|
150
|
-
expect(subject.emit_field(field)).to eq('USERS.ID')
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
describe "#emit_list" do
|
156
|
-
it "should emit a ',' separated list" do
|
157
|
-
expect(subject.emit_list([1,2,3,'foo'])).to eq("(1,2,3,'foo')")
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
describe "#emit_assignments" do
|
162
|
-
let(:values) { {x: 1, y: 2} }
|
163
|
-
|
164
|
-
it "should emit a list of column names and values" do
|
165
|
-
expect(subject.emit_assignments(values)).to eq('x=1,y=2')
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
describe "#emit_argument" do
|
170
|
-
context "when the value is a Statement" do
|
171
|
-
let(:stmt) { Ronin::Code::SQL::Statement.new(:SELECT,1) }
|
172
|
-
|
173
|
-
it "should wrap the statement in ( )" do
|
174
|
-
expect(subject.emit_argument(stmt)).to eq('(SELECT 1)')
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
context "otherwise" do
|
179
|
-
let(:value) { 'hello' }
|
180
|
-
|
181
|
-
it "should emit the value" do
|
182
|
-
expect(subject.emit_argument(value)).to eq("'hello'")
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
describe "#emit_expression" do
|
188
|
-
context "when the expression is a BinaryExpr" do
|
189
|
-
context "when the operator is alphabetic" do
|
190
|
-
subject { described_class.new(case: :upper) }
|
191
|
-
|
192
|
-
let(:expr) { Ronin::Code::SQL::BinaryExpr.new(:id,:is,1) }
|
193
|
-
|
194
|
-
it "should emit the operands and operator as a keyword with spaces" do
|
195
|
-
expect(subject.emit_expression(expr)).to eq('ID IS 1')
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
context "when the operator is symbolic" do
|
200
|
-
let(:expr) { Ronin::Code::SQL::BinaryExpr.new(:id,:"=",1) }
|
201
|
-
|
202
|
-
it "should emit the operands and operator without spaces" do
|
203
|
-
expect(subject.emit_expression(expr)).to eq('id=1')
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
context "when the left-hand operand is a Statement" do
|
208
|
-
let(:expr) do
|
209
|
-
Ronin::Code::SQL::BinaryExpr.new(
|
210
|
-
Ronin::Code::SQL::Statement.new(:SELECT,1), :"=", 1
|
211
|
-
)
|
212
|
-
end
|
213
|
-
|
214
|
-
it "should wrap the left-hand operand in parenthesis" do
|
215
|
-
expect(subject.emit_expression(expr)).to eq('(SELECT 1)=1')
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
context "when the right-hand operand is a Statement" do
|
220
|
-
let(:expr) do
|
221
|
-
Ronin::Code::SQL::BinaryExpr.new(
|
222
|
-
1, :"=", Ronin::Code::SQL::Statement.new(:SELECT,1)
|
223
|
-
)
|
224
|
-
end
|
225
|
-
|
226
|
-
it "should wrap the left-hand operand in parenthesis" do
|
227
|
-
expect(subject.emit_expression(expr)).to eq('1=(SELECT 1)')
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
context "when the expression is a UnaryExpr" do
|
233
|
-
context "when the operator is upper-case alpha" do
|
234
|
-
let(:expr) { Ronin::Code::SQL::UnaryExpr.new(:NOT,:admin) }
|
235
|
-
|
236
|
-
it "should emit the operand and operator with spaces" do
|
237
|
-
expect(subject.emit_expression(expr)).to eq('NOT admin')
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
context "when the operator is symbolic" do
|
242
|
-
let(:expr) { Ronin::Code::SQL::UnaryExpr.new(:"-",1) }
|
243
|
-
|
244
|
-
it "should emit the operand and operator without spaces" do
|
245
|
-
expect(subject.emit_expression(expr)).to eq('-1')
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
context "when the operand is a Statement" do
|
250
|
-
let(:expr) do
|
251
|
-
Ronin::Code::SQL::UnaryExpr.new(
|
252
|
-
:NOT, Ronin::Code::SQL::Statement.new(:SELECT,1)
|
253
|
-
)
|
254
|
-
end
|
255
|
-
|
256
|
-
it "should wrap the operand in parenthesis" do
|
257
|
-
expect(subject.emit_expression(expr)).to eq('NOT (SELECT 1)')
|
258
|
-
end
|
259
|
-
end
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
describe "#emit_function" do
|
264
|
-
let(:func) { Ronin::Code::SQL::Function.new(:NOW) }
|
265
|
-
|
266
|
-
it "should emit the function name as a keyword" do
|
267
|
-
expect(subject.emit_function(func)).to eq('NOW()')
|
268
|
-
end
|
269
|
-
|
270
|
-
context "with arguments" do
|
271
|
-
let(:func) { Ronin::Code::SQL::Function.new(:MAX,1,2) }
|
272
|
-
|
273
|
-
it "should emit the function arguments" do
|
274
|
-
expect(subject.emit_function(func)).to eq('MAX(1,2)')
|
275
|
-
end
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
describe "#emit" do
|
280
|
-
context "when passed nil" do
|
281
|
-
it "should emit the NULL keyword" do
|
282
|
-
expect(subject.emit(nil)).to eq('NULL')
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
|
-
context "when passed true" do
|
287
|
-
it "should emit true" do
|
288
|
-
expect(subject.emit(true)).to eq('1=1')
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
context "when passed false" do
|
293
|
-
it "should emit false" do
|
294
|
-
expect(subject.emit(false)).to eq('1=0')
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
context "when passed an Integer" do
|
299
|
-
it "should emit an integer" do
|
300
|
-
expect(subject.emit(10)).to eq('10')
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
context "when passed a Float" do
|
305
|
-
it "should emit a decimal" do
|
306
|
-
expect(subject.emit(2.5)).to eq('2.5')
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
context "when passed a String" do
|
311
|
-
it "should emit a string" do
|
312
|
-
expect(subject.emit("O'Brian")).to eq("'O''Brian'")
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
context "when passed a Literal" do
|
317
|
-
let(:literal) { Ronin::Code::SQL::Literal.new(42) }
|
318
|
-
|
319
|
-
it "should emit the value" do
|
320
|
-
expect(subject.emit(literal)).to eq('42')
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
context "when passed a Field" do
|
325
|
-
let(:table) { Ronin::Code::SQL::Field.new(:users) }
|
326
|
-
let(:column) { Ronin::Code::SQL::Field.new(:id,table) }
|
327
|
-
|
328
|
-
it "should emit a field" do
|
329
|
-
expect(subject.emit(column)).to eq('users.id')
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
context "when passed a Symbol" do
|
334
|
-
it "should emit a field" do
|
335
|
-
expect(subject.emit(:id)).to eq('id')
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
context "when passed an Array" do
|
340
|
-
it "should emit a list" do
|
341
|
-
expect(subject.emit([1,2,3,'foo'])).to eq("(1,2,3,'foo')")
|
342
|
-
end
|
343
|
-
end
|
344
|
-
|
345
|
-
context "when passed a Hash" do
|
346
|
-
it "should emit a list of assignments" do
|
347
|
-
expect(subject.emit(x: 1, y: 2)).to eq('x=1,y=2')
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
context "when passed a BinaryExpr" do
|
352
|
-
let(:expr) { Ronin::Code::SQL::BinaryExpr.new(:id,:"=",1) }
|
353
|
-
|
354
|
-
it "should emit an expression" do
|
355
|
-
expect(subject.emit(expr)).to eq('id=1')
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
context "when passed a UnaryExpr" do
|
360
|
-
let(:expr) { Ronin::Code::SQL::UnaryExpr.new(:NOT,:admin) }
|
361
|
-
|
362
|
-
it "should emit an expression" do
|
363
|
-
expect(subject.emit(expr)).to eq('NOT admin')
|
364
|
-
end
|
365
|
-
end
|
366
|
-
|
367
|
-
context "when passed a Function" do
|
368
|
-
let(:func) { Ronin::Code::SQL::Function.new(:MAX,1,2) }
|
369
|
-
|
370
|
-
it "should emit the function" do
|
371
|
-
expect(subject.emit(func)).to eq('MAX(1,2)')
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
context "when passed a Statment" do
|
376
|
-
let(:stmt) { Ronin::Code::SQL::Statement.new(:SELECT,1) }
|
377
|
-
|
378
|
-
it "should emit a statement" do
|
379
|
-
expect(subject.emit(stmt)).to eq('SELECT 1')
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
|
-
context "when the object responds to #to_sql" do
|
384
|
-
let(:object) { double(:sql_object) }
|
385
|
-
let(:sql) { "EXEC sp_configure 'xp_cmdshell', 0;" }
|
386
|
-
|
387
|
-
it "should call #to_sql" do
|
388
|
-
allow(object).to receive(:to_sql).and_return(sql)
|
389
|
-
|
390
|
-
expect(subject.emit(object)).to eq(sql)
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
context "otherwise" do
|
395
|
-
let(:object) { Object.new }
|
396
|
-
|
397
|
-
it "should raise an ArgumentError" do
|
398
|
-
expect {
|
399
|
-
subject.emit(object)
|
400
|
-
}.to raise_error(ArgumentError)
|
401
|
-
end
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
|
-
describe "#emit_clause" do
|
406
|
-
let(:clause) { Ronin::Code::SQL::Clause.new(:"NOT INDEXED") }
|
407
|
-
|
408
|
-
it "should emit the clause keyword" do
|
409
|
-
expect(subject.emit_clause(clause)).to eq("NOT INDEXED")
|
410
|
-
end
|
411
|
-
|
412
|
-
context "with an argument" do
|
413
|
-
let(:argument) { 100 }
|
414
|
-
let(:clause) { Ronin::Code::SQL::Clause.new(:LIMIT,argument) }
|
415
|
-
|
416
|
-
it "should also emit the clause argument" do
|
417
|
-
expect(subject.emit_clause(clause)).to eq("LIMIT #{argument}")
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
context "with custom :space" do
|
422
|
-
subject { described_class.new(space: '/**/') }
|
423
|
-
|
424
|
-
let(:clause) { Ronin::Code::SQL::Clause.new(:LIMIT,100) }
|
425
|
-
|
426
|
-
it "should emit the custom white-space deliminater" do
|
427
|
-
expect(subject.emit_clause(clause)).to eq('LIMIT/**/100')
|
428
|
-
end
|
429
|
-
end
|
430
|
-
end
|
431
|
-
|
432
|
-
describe "#emit_clauses" do
|
433
|
-
let(:clauses) do
|
434
|
-
[
|
435
|
-
Ronin::Code::SQL::Clause.new(:LIMIT, 100),
|
436
|
-
Ronin::Code::SQL::Clause.new(:OFFSET, 10)
|
437
|
-
]
|
438
|
-
end
|
439
|
-
|
440
|
-
it "should emit multiple clauses" do
|
441
|
-
expect(subject.emit_clauses(clauses)).to eq('LIMIT 100 OFFSET 10')
|
442
|
-
end
|
443
|
-
|
444
|
-
context "with custom :space" do
|
445
|
-
subject { described_class.new(space: '/**/') }
|
446
|
-
|
447
|
-
it "should emit the custom white-space deliminater" do
|
448
|
-
expect(subject.emit_clauses(clauses)).to eq('LIMIT/**/100/**/OFFSET/**/10')
|
449
|
-
end
|
450
|
-
end
|
451
|
-
end
|
452
|
-
|
453
|
-
describe "#emit_statement" do
|
454
|
-
subject { described_class.new(case: :lower) }
|
455
|
-
|
456
|
-
context "without an argument" do
|
457
|
-
let(:stmt) { Ronin::Code::SQL::Statement.new(:SELECT) }
|
458
|
-
|
459
|
-
it "should emit the statment keyword" do
|
460
|
-
expect(subject.emit_statement(stmt)).to eq('select')
|
461
|
-
end
|
462
|
-
end
|
463
|
-
|
464
|
-
context "with an argument" do
|
465
|
-
let(:stmt) { Ronin::Code::SQL::Statement.new(:SELECT,1) }
|
466
|
-
|
467
|
-
it "should emit the statment argument" do
|
468
|
-
expect(subject.emit_statement(stmt)).to eq('select 1')
|
469
|
-
end
|
470
|
-
|
471
|
-
context "when the argument is an Array" do
|
472
|
-
let(:stmt) { Ronin::Code::SQL::Statement.new(:SELECT,[1,2,3]) }
|
473
|
-
|
474
|
-
it "should emit a list" do
|
475
|
-
expect(subject.emit_statement(stmt)).to eq('select (1,2,3)')
|
476
|
-
end
|
477
|
-
|
478
|
-
context "with only one element" do
|
479
|
-
let(:stmt) { Ronin::Code::SQL::Statement.new(:SELECT,[1]) }
|
480
|
-
|
481
|
-
it "should emit the element" do
|
482
|
-
expect(subject.emit_statement(stmt)).to eq('select 1')
|
483
|
-
end
|
484
|
-
end
|
485
|
-
end
|
486
|
-
|
487
|
-
context "with custom :space" do
|
488
|
-
subject { described_class.new(case: :lower, space: '/**/') }
|
489
|
-
|
490
|
-
it "should emit the custom white-space deliminater" do
|
491
|
-
expect(subject.emit_statement(stmt)).to eq('select/**/1')
|
492
|
-
end
|
493
|
-
end
|
494
|
-
end
|
495
|
-
|
496
|
-
context "with clauses" do
|
497
|
-
let(:stmt) { Ronin::Code::SQL::Statement.new(:SELECT,1).offset(1).limit(100) }
|
498
|
-
|
499
|
-
it "should emit the statment argument" do
|
500
|
-
expect(subject.emit_statement(stmt)).to eq('select 1 offset 1 limit 100')
|
501
|
-
end
|
502
|
-
|
503
|
-
context "with custom :space" do
|
504
|
-
subject { described_class.new(case: :lower, space: '/**/') }
|
505
|
-
|
506
|
-
it "should emit the custom white-space deliminater" do
|
507
|
-
expect(subject.emit_statement(stmt)).to eq('select/**/1/**/offset/**/1/**/limit/**/100')
|
508
|
-
end
|
509
|
-
end
|
510
|
-
end
|
511
|
-
end
|
512
|
-
|
513
|
-
describe "#emit_statement_list" do
|
514
|
-
let(:stmts) do
|
515
|
-
sql = Ronin::Code::SQL::StatementList.new
|
516
|
-
sql << Ronin::Code::SQL::Statement.new(:SELECT, 1)
|
517
|
-
sql << Ronin::Code::SQL::Statement.new([:DROP, :TABLE], :users)
|
518
|
-
sql
|
519
|
-
end
|
520
|
-
|
521
|
-
it "should emit multiple statements separated by '; '" do
|
522
|
-
expect(subject.emit_statement_list(stmts)).to eq('SELECT 1; DROP TABLE users')
|
523
|
-
end
|
524
|
-
|
525
|
-
context "with custom :space" do
|
526
|
-
subject { described_class.new(space: '/**/') }
|
527
|
-
|
528
|
-
it "should emit the custom white-space deliminater" do
|
529
|
-
expect(subject.emit_statement_list(stmts)).to eq('SELECT/**/1;/**/DROP/**/TABLE/**/users')
|
530
|
-
end
|
531
|
-
end
|
532
|
-
end
|
533
|
-
end
|
data/spec/sql/field_spec.rb
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'ronin/code/sql/field'
|
3
|
-
|
4
|
-
describe Ronin::Code::SQL::Field do
|
5
|
-
describe "#initialize" do
|
6
|
-
it "should convert name to a String" do
|
7
|
-
expect(described_class.new(:table).name).to eq('table')
|
8
|
-
end
|
9
|
-
|
10
|
-
it "should default parent to nil" do
|
11
|
-
expect(described_class.new('table').parent).to be_nil
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
describe "parse" do
|
16
|
-
context "when passed a single field" do
|
17
|
-
let(:name) { "column" }
|
18
|
-
|
19
|
-
subject { described_class.parse(name) }
|
20
|
-
|
21
|
-
it "should parse the field name" do
|
22
|
-
expect(subject.name).to eq(name)
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should not have a parent" do
|
26
|
-
expect(subject.parent).to be_nil
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
context "when parsing multiple fields" do
|
31
|
-
let(:parent) { "table" }
|
32
|
-
let(:name) { "column" }
|
33
|
-
|
34
|
-
subject { described_class.parse("#{parent}.#{name}") }
|
35
|
-
|
36
|
-
it "should parse the field name" do
|
37
|
-
expect(subject.name).to eq(name)
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should parse the parent field" do
|
41
|
-
expect(subject.parent.name).to eq(parent)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
describe "#to_s" do
|
47
|
-
context "when parent is nil" do
|
48
|
-
let(:name) { "column" }
|
49
|
-
|
50
|
-
subject { described_class.new(name) }
|
51
|
-
|
52
|
-
it "should return the name" do
|
53
|
-
expect(subject.to_s).to eq(name)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
context "when parent is set" do
|
58
|
-
let(:parent) { "table" }
|
59
|
-
let(:name) { "column" }
|
60
|
-
|
61
|
-
subject { described_class.new(name,described_class.new(parent)) }
|
62
|
-
|
63
|
-
it "should return the name" do
|
64
|
-
expect(subject.to_s).to eq("#{parent}.#{name}")
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
describe "#method_missing" do
|
70
|
-
context "at depth 1" do
|
71
|
-
subject { described_class.new('table') }
|
72
|
-
|
73
|
-
it "should allow accessing sub-fields" do
|
74
|
-
expect(subject.column.name).to eq('column')
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context "at depth 2" do
|
79
|
-
subject { described_class.new('table',described_class.new('db')) }
|
80
|
-
|
81
|
-
it "should allow accessing sub-fields" do
|
82
|
-
expect(subject.column.name).to eq('column')
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
context "at depth 3" do
|
87
|
-
subject do
|
88
|
-
described_class.new(
|
89
|
-
'column',
|
90
|
-
described_class.new(
|
91
|
-
'table', described_class.new('db')
|
92
|
-
)
|
93
|
-
)
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should not allow accessing sub-fields" do
|
97
|
-
expect {
|
98
|
-
subject.column
|
99
|
-
}.to raise_error(NoMethodError)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
data/spec/sql/fields_spec.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'ronin/code/sql/fields'
|
3
|
-
|
4
|
-
describe Ronin::Code::SQL::Fields do
|
5
|
-
subject { Object.new.extend(described_class) }
|
6
|
-
|
7
|
-
describe "#respond_to_missing?" do
|
8
|
-
it "should return true" do
|
9
|
-
expect(subject).to respond_to(:foo)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
it { expect(subject.to_ary).to be_nil }
|
14
|
-
|
15
|
-
describe "#method_missing" do
|
16
|
-
let(:name) { 'users' }
|
17
|
-
|
18
|
-
context "when called with no arguments and no block" do
|
19
|
-
it "should create a Field" do
|
20
|
-
expect(subject.send(name).name).to eq(name)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
context "when called with arguments" do
|
25
|
-
it "should raise a NoMethodError" do
|
26
|
-
expect {
|
27
|
-
subject.sned(name,1,2,3)
|
28
|
-
}.to raise_error(NoMethodError)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
context "when called with a block" do
|
33
|
-
it "should raise a NoMethodError" do
|
34
|
-
expect {
|
35
|
-
subject.sned(name) { 1 + 1 }
|
36
|
-
}.to raise_error(NoMethodError)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
shared_examples_for "Function" do |method,arguments=[],additional_arguments=[]|
|
4
|
-
describe "##{method}" do
|
5
|
-
let(:name) { method.upcase }
|
6
|
-
let(:func) { subject.send(method,*arguments) }
|
7
|
-
|
8
|
-
it "should create a #{method.upcase} function" do
|
9
|
-
expect(func.name).to eq(name)
|
10
|
-
end
|
11
|
-
|
12
|
-
unless arguments.empty?
|
13
|
-
it "should set the arguments" do
|
14
|
-
expect(func.arguments).to eq(arguments)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
unless additional_arguments.empty?
|
19
|
-
context "when passed additional arguments" do
|
20
|
-
let(:func) { subject.send(method,*additional_arguments) }
|
21
|
-
|
22
|
-
it "should set the arguments" do
|
23
|
-
expect(func.arguments).to eq(additional_arguments)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
|