ronin-code-sql 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.document +4 -0
  3. data/.editorconfig +11 -0
  4. data/.github/workflows/ruby.yml +27 -0
  5. data/.gitignore +11 -0
  6. data/.mailmap +1 -0
  7. data/.rspec +1 -0
  8. data/.ruby-version +1 -0
  9. data/.yardopts +1 -0
  10. data/COPYING.txt +165 -0
  11. data/ChangeLog.md +104 -0
  12. data/Gemfile +28 -0
  13. data/README.md +212 -0
  14. data/Rakefile +30 -0
  15. data/gemspec.yml +25 -0
  16. data/lib/ronin/code/sql/binary_expr.rb +53 -0
  17. data/lib/ronin/code/sql/clause.rb +74 -0
  18. data/lib/ronin/code/sql/clauses.rb +310 -0
  19. data/lib/ronin/code/sql/emittable.rb +88 -0
  20. data/lib/ronin/code/sql/emitter.rb +406 -0
  21. data/lib/ronin/code/sql/field.rb +110 -0
  22. data/lib/ronin/code/sql/fields.rb +82 -0
  23. data/lib/ronin/code/sql/function.rb +53 -0
  24. data/lib/ronin/code/sql/functions.rb +1265 -0
  25. data/lib/ronin/code/sql/injection.rb +168 -0
  26. data/lib/ronin/code/sql/injection_expr.rb +113 -0
  27. data/lib/ronin/code/sql/literal.rb +40 -0
  28. data/lib/ronin/code/sql/literals.rb +83 -0
  29. data/lib/ronin/code/sql/operators.rb +384 -0
  30. data/lib/ronin/code/sql/statement.rb +72 -0
  31. data/lib/ronin/code/sql/statement_list.rb +112 -0
  32. data/lib/ronin/code/sql/statements.rb +117 -0
  33. data/lib/ronin/code/sql/unary_expr.rb +38 -0
  34. data/lib/ronin/code/sql/version.rb +28 -0
  35. data/lib/ronin/code/sql.rb +96 -0
  36. data/ronin-code-sql.gemspec +62 -0
  37. data/spec/spec_helper.rb +3 -0
  38. data/spec/sql/binary_expr_examples.rb +25 -0
  39. data/spec/sql/binary_expr_spec.rb +5 -0
  40. data/spec/sql/clause_examples.rb +43 -0
  41. data/spec/sql/clause_spec.rb +31 -0
  42. data/spec/sql/clauses_spec.rb +47 -0
  43. data/spec/sql/emittable_spec.rb +41 -0
  44. data/spec/sql/emitter_spec.rb +533 -0
  45. data/spec/sql/field_spec.rb +103 -0
  46. data/spec/sql/fields_spec.rb +40 -0
  47. data/spec/sql/function_examples.rb +30 -0
  48. data/spec/sql/function_spec.rb +25 -0
  49. data/spec/sql/functions_spec.rb +113 -0
  50. data/spec/sql/injection_expr_spec.rb +98 -0
  51. data/spec/sql/injection_spec.rb +172 -0
  52. data/spec/sql/literal_spec.rb +5 -0
  53. data/spec/sql/literals_spec.rb +46 -0
  54. data/spec/sql/operators_spec.rb +44 -0
  55. data/spec/sql/statement_examples.rb +39 -0
  56. data/spec/sql/statement_list_spec.rb +48 -0
  57. data/spec/sql/statement_spec.rb +38 -0
  58. data/spec/sql/statements_spec.rb +22 -0
  59. data/spec/sql/unary_expr_examples.rb +20 -0
  60. data/spec/sql/unary_expr_spec.rb +5 -0
  61. data/spec/sql_spec.rb +18 -0
  62. metadata +157 -0
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ require 'ronin/code/sql/function'
4
+
5
+ describe Ronin::Code::SQL::Function do
6
+ describe "#initialize" do
7
+ context "with no arguments" do
8
+ subject { described_class.new(:f) }
9
+
10
+ it "should set arguments to []" do
11
+ expect(subject.arguments).to eq([])
12
+ end
13
+ end
14
+
15
+ context "with multiple arguments" do
16
+ let(:arguments) { [1,2,3] }
17
+
18
+ subject { described_class.new(:f,*arguments) }
19
+
20
+ it "should set arguments" do
21
+ expect(subject.arguments).to eq(arguments)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+ require 'sql/function_examples'
3
+ require 'ronin/code/sql/functions'
4
+ require 'ronin/code/sql/binary_expr'
5
+
6
+ describe Ronin::Code::SQL::Functions do
7
+ subject { Object.new.extend(described_class) }
8
+
9
+ describe "#count" do
10
+ it "should create a COUNT function" do
11
+ expect(subject.count.name).to eq(:COUNT)
12
+ end
13
+
14
+ context "without arguments" do
15
+ it "should default arguments to *" do
16
+ expect(subject.count.arguments).to eq([:*])
17
+ end
18
+ end
19
+ end
20
+
21
+ include_examples "Function", :max, [:column]
22
+ include_examples "Function", :min, [:column]
23
+ include_examples "Function", :avg, [:column]
24
+ include_examples "Function", :sum, [:column]
25
+ include_examples "Function", :sqrt, [1]
26
+ include_examples "Function", :rand, [1]
27
+ include_examples "Function", :abs, [-1]
28
+ include_examples "Function", :acos, [30]
29
+ include_examples "Function", :asin, [30]
30
+ include_examples "Function", :atan, [30]
31
+ include_examples "Function", :atan2, [30,60]
32
+ include_examples "Function", :bit_and, [0xff]
33
+ include_examples "Function", :bit_count, [0xff]
34
+ include_examples "Function", :bit_or, [0xff]
35
+ include_examples "Function", :ceil, [0.5]
36
+ include_examples "Function", :ceiling, [0.5]
37
+ include_examples "Function", :cos, [0.5]
38
+ include_examples "Function", :cot, [0.5]
39
+ include_examples "Function", :degrees, [0.5]
40
+ include_examples "Function", :exp, [0.5]
41
+ include_examples "Function", :floor, [0.5]
42
+ include_examples "Function", :format, [:date, 'YYYY-MM-DD']
43
+ include_examples "Function", :greatest, [1,2,3,4]
44
+ include_examples "Function", :interval, [1,2,3,4]
45
+ include_examples "Function", :least, [1,2,3,4]
46
+ include_examples "Function", :log, [2], [10,2]
47
+ include_examples "Function", :log10, [2]
48
+ include_examples "Function", :mod, [2,10]
49
+ include_examples "Function", :pi
50
+ include_examples "Function", :pow, [2,10]
51
+ include_examples "Function", :power, [2,10]
52
+ include_examples "Function", :radians, [30]
53
+ include_examples "Function", :random
54
+ include_examples "Function", :round, [15.79], [15.79, 1]
55
+ include_examples "Function", :sign, [10]
56
+ include_examples "Function", :sin, [30]
57
+ include_examples "Function", :sqrt, [100]
58
+ include_examples "Function", :std, [:column]
59
+ include_examples "Function", :stddev, [:column]
60
+ include_examples "Function", :tan, [30]
61
+ include_examples "Function", :truncate, [:price,2]
62
+ include_examples "Function", :ascii, ["hello"]
63
+ include_examples "Function", :bin, [12]
64
+ include_examples "Function", :bit_length, ["hello"]
65
+ include_examples "Function", :char, [104, 101, 108, 108, 111]
66
+ include_examples "Function", :char_length, ["hello"]
67
+ include_examples "Function", :character_length, ["hello"]
68
+ include_examples "Function", :concat, ["he", "ll", "o"]
69
+ include_examples "Function", :concat_ws, ["he", "ll", "o"]
70
+ include_examples "Function", :conv, ["ff", 16, 10]
71
+ include_examples "Function", :elt, ["ff", 16, 10]
72
+ include_examples "Function", :export_set, [5, 'Y', 'N']
73
+ include_examples "Function", :field, ["hello", "lo"]
74
+ include_examples "Function", :find_in_set, ['b', 'a,b,c,d']
75
+ include_examples "Function", :glob, [:name, '*foo*']
76
+ include_examples "Function", :hex, ["hello"]
77
+ include_examples "Function", :insert, ["hello",1,2,"foo"]
78
+ include_examples "Function", :instr, ["hello","lo"]
79
+ include_examples "Function", :lcase, ["HELLO"]
80
+ include_examples "Function", :left, ["hello", 10]
81
+ include_examples "Function", :length, ["hello"]
82
+ include_examples "Function", :like, [:name, '%foo%']
83
+ include_examples "Function", :load_file, ["path"]
84
+ include_examples "Function", :locate, ["o", "hello"]
85
+ include_examples "Function", :lower, ["HELLO"]
86
+ include_examples "Function", :lpad, ["hello", 10, ' ']
87
+ include_examples "Function", :ltrim, [" hello"]
88
+ include_examples "Function", :make_set, [8|1, 'a', 'b', 'c', 'd']
89
+ include_examples "Function", :mid, ["hello",2,3]
90
+ include_examples "Function", :oct, ["55"]
91
+ include_examples "Function", :octet_length, ["55"]
92
+ include_examples "Function", :ord, ["55"]
93
+ include_examples "Function", :position, [
94
+ Ronin::Code::SQL::BinaryExpr.new('55',:IN,:name)
95
+ ]
96
+ include_examples "Function", :quote, ["hello"]
97
+ include_examples "Function", :repeat, ["A", 100]
98
+ include_examples "Function", :replace, ["foox", "foo", "bar"]
99
+ include_examples "Function", :reverse, ["hello"]
100
+ include_examples "Function", :right, ["hello", 10]
101
+ include_examples "Function", :rpad, ["hello", 10, ' ']
102
+ include_examples "Function", :rtrim, ["hello "]
103
+ include_examples "Function", :soundex, ["smythe"]
104
+ include_examples "Function", :space, [10]
105
+ include_examples "Function", :strcmp, ['foo', 'foox']
106
+ include_examples "Function", :substring, ['hello', 2, 1]
107
+ include_examples "Function", :substring_index, ['foo-bar', '-', 1]
108
+ include_examples "Function", :trim, [' foo ']
109
+ include_examples "Function", :ucase, ['foo']
110
+ include_examples "Function", :unhex, ['4D7953514C']
111
+ include_examples "Function", :upper, ['hello']
112
+ include_examples "Function", :sleep, [5]
113
+ end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+ require 'ronin/code/sql/injection_expr'
3
+
4
+ describe Ronin::Code::SQL::InjectionExpr do
5
+ let(:initial_value) { 1 }
6
+
7
+ subject { described_class.new(initial_value) }
8
+
9
+ describe "#and" do
10
+ context "on first call" do
11
+ before { subject.and { 1 } }
12
+
13
+ it "should create a 'AND' BinaryExpr" do
14
+ expect(subject.expression.operator).to eq(:AND)
15
+ end
16
+
17
+ it "should create an expression with the initial value" do
18
+ expect(subject.expression.left).to eq(initial_value)
19
+ end
20
+
21
+ it "should create an expression with the expression" do
22
+ expect(subject.expression.right).to eq(1)
23
+ end
24
+ end
25
+
26
+ context "on multiple calls" do
27
+ before { subject.and { 1 }.and { 2 } }
28
+
29
+ it "should create another 'AND' BinaryExpr" do
30
+ expect(subject.expression.operator).to eq(:AND)
31
+ end
32
+
33
+ it "should nest the expressions" do
34
+ expect(subject.expression.left.right).to eq(1)
35
+ expect(subject.expression.right).to eq(2)
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "#or" do
41
+ context "on first call" do
42
+ before { subject.or { 1 } }
43
+
44
+ it "should create a 'OR' BinaryExpr" do
45
+ expect(subject.expression.operator).to eq(:OR)
46
+ end
47
+
48
+ it "should create an expression with the initial value" do
49
+ expect(subject.expression.left).to eq(initial_value)
50
+ end
51
+
52
+ it "should create an expression with the expression" do
53
+ expect(subject.expression.right).to eq(1)
54
+ end
55
+ end
56
+
57
+ context "on multiple calls" do
58
+ before { subject.or { 1 }.or { 2 } }
59
+
60
+ it "should create another 'OR' BinaryExpr" do
61
+ expect(subject.expression.operator).to eq(:OR)
62
+ end
63
+
64
+ it "should nest the expressions" do
65
+ expect(subject.expression.left.right).to eq(1)
66
+ expect(subject.expression.right).to eq(2)
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "#to_sql" do
72
+ context "without additional expressions" do
73
+ subject { described_class.new(1) }
74
+
75
+ it "should still emit the initial value" do
76
+ expect(subject.to_sql).to eq('1')
77
+ end
78
+ end
79
+
80
+ context "with an additional expression" do
81
+ subject do
82
+ sqli = described_class.new(1)
83
+ sqli.or { 1 == 1 }
84
+ sqli
85
+ end
86
+
87
+ it "should emit the expression" do
88
+ expect(subject.to_sql).to eq('1 OR 1=1')
89
+ end
90
+
91
+ context "when given emitter options" do
92
+ it "should accept additional options" do
93
+ expect(subject.to_sql(case: :lower)).to eq('1 or 1=1')
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,172 @@
1
+ require 'spec_helper'
2
+ require 'ronin/code/sql/injection'
3
+
4
+ describe Ronin::Code::SQL::Injection do
5
+ describe "PLACE_HOLDERS" do
6
+ subject { described_class::PLACE_HOLDERS }
7
+
8
+ it { should include(integer: 1) }
9
+ it { should include(decimal: 1.0) }
10
+ it { should include(string: '1') }
11
+ it { should include(list: [nil]) }
12
+ it { should include(column: :id) }
13
+ end
14
+
15
+ describe "#initialize" do
16
+ context "with no arguments" do
17
+ it { expect(subject.escape).to eq(:integer) }
18
+ it { expect(subject.place_holder).to eq(1) }
19
+ end
20
+
21
+ context "with :escape" do
22
+ context "with no :place_holder" do
23
+ let(:place_holders) { described_class::PLACE_HOLDERS }
24
+ let(:escape) { :string }
25
+
26
+ subject { described_class.new(escape: escape) }
27
+
28
+ it "should default the place_holder based on the :escape type" do
29
+ expect(subject.place_holder).to eq(place_holders[escape])
30
+ end
31
+ end
32
+ end
33
+
34
+ context "with :place_holder" do
35
+ let(:data) { 'A' }
36
+
37
+ subject { described_class.new(place_holder: data) }
38
+
39
+ it "should pass it to the InjectionExpr" do
40
+ expect(subject.expression.expression).to eq(data)
41
+ end
42
+ end
43
+
44
+ context "when a block is given" do
45
+ subject { described_class.new { @x = 1 } }
46
+
47
+ it "should instance_eval the block" do
48
+ expect(subject.instance_variable_get(:@x)).to eq(1)
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#to_sql" do
54
+ context "without an expression" do
55
+ subject { described_class.new(place_holder: 1) }
56
+
57
+ it "should still emit the place-holder value" do
58
+ expect(subject.to_sql).to eq('1')
59
+ end
60
+
61
+ context "with clauses" do
62
+ subject do
63
+ sqli = described_class.new(place_holder: 1)
64
+ sqli.limit(100).offset(10)
65
+ sqli
66
+ end
67
+
68
+ it "should emit the clauses" do
69
+ expect(subject.to_sql).to eq('1 LIMIT 100 OFFSET 10')
70
+ end
71
+ end
72
+ end
73
+
74
+ context "with an expression" do
75
+ subject do
76
+ sqli = described_class.new
77
+ sqli.or { 1 == 1 }
78
+ sqli
79
+ end
80
+
81
+ it "should emit the expression" do
82
+ expect(subject.to_sql).to eq('1 OR 1=1')
83
+ end
84
+
85
+ context "with clauses" do
86
+ subject do
87
+ sqli = described_class.new
88
+ sqli.or { 1 == 1 }.limit(100).offset(10)
89
+ sqli
90
+ end
91
+
92
+ it "should emit the clauses" do
93
+ expect(subject.to_sql).to eq('1 OR 1=1 LIMIT 100 OFFSET 10')
94
+ end
95
+
96
+ context "with :space" do
97
+ it "should emit the clauses with custom spaces" do
98
+ expect(subject.to_sql(space: '/**/')).to eq('1/**/OR/**/1=1/**/LIMIT/**/100/**/OFFSET/**/10')
99
+ end
100
+ end
101
+ end
102
+
103
+ context "with statements" do
104
+ subject do
105
+ sqli = described_class.new
106
+ sqli.or { 1 == 1 }.select(1,2,3)
107
+ sqli
108
+ end
109
+
110
+ it "should emit the clauses" do
111
+ expect(subject.to_sql).to eq('1 OR 1=1; SELECT (1,2,3)')
112
+ end
113
+
114
+ context "with :space" do
115
+ it "should emit the statements with custom spaces" do
116
+ expect(subject.to_sql(space: '/**/')).to eq('1/**/OR/**/1=1;/**/SELECT/**/(1,2,3)')
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ context "when escaping a string value" do
123
+ context "when the place-holder and last operand are Strings" do
124
+ subject do
125
+ sqli = described_class.new(escape: :string)
126
+ sqli.or { string(1) == string(1) }
127
+ sqli
128
+ end
129
+
130
+ it "should balance the quotes" do
131
+ expect(subject.to_sql).to eq("1' OR '1'='1")
132
+ end
133
+ end
134
+
135
+ context "when the place-holder and last operand are not both Strings" do
136
+ subject do
137
+ sqli = described_class.new(escape: :string)
138
+ sqli.or { int(1) == int(1) }
139
+ sqli
140
+ end
141
+
142
+ it "should terminate the SQL statement" do
143
+ expect(subject.to_sql).to eq("1' OR 1=1;--")
144
+ end
145
+ end
146
+
147
+ context "when terminating" do
148
+ subject do
149
+ sqli = described_class.new(escape: :string)
150
+ sqli.or { string(1) == string(1) }
151
+ sqli
152
+ end
153
+
154
+ it "should terminate the SQL statement" do
155
+ expect(subject.to_sql(terminate: true)).to eq("1' OR '1'='1';--")
156
+ end
157
+ end
158
+ end
159
+
160
+ context "when terminating" do
161
+ subject do
162
+ sqli = described_class.new(escape: :integer)
163
+ sqli.or { 1 == 1 }
164
+ sqli
165
+ end
166
+
167
+ it "should terminate the SQL statement" do
168
+ expect(subject.to_sql(terminate: true)).to eq("1 OR 1=1;--")
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+ require 'ronin/code/sql/literal'
3
+
4
+ describe Ronin::Code::SQL::Literal do
5
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ require 'ronin/code/sql/literals'
3
+
4
+ describe Ronin::Code::SQL::Literals do
5
+ subject { Object.new.extend(described_class) }
6
+
7
+ describe "#null" do
8
+ it "should return a Literal" do
9
+ expect(subject.null).to be_kind_of(Ronin::Code::SQL::Literal)
10
+ end
11
+
12
+ it "should have the value of :NULL" do
13
+ expect(subject.null.value).to eq(:NULL)
14
+ end
15
+ end
16
+
17
+ describe "#int" do
18
+ it "should return a Literal" do
19
+ expect(subject.int(5)).to be_kind_of(Ronin::Code::SQL::Literal)
20
+ end
21
+
22
+ it "should convert the value to an Integer" do
23
+ expect(subject.int('5').value).to eq(5)
24
+ end
25
+ end
26
+
27
+ describe "#float" do
28
+ it "should return a Literal" do
29
+ expect(subject.float(1.5)).to be_kind_of(Ronin::Code::SQL::Literal)
30
+ end
31
+
32
+ it "should convert the value to a Float" do
33
+ expect(subject.float('1.5').value).to eq(1.5)
34
+ end
35
+ end
36
+
37
+ describe "#float" do
38
+ it "should return a Literal" do
39
+ expect(subject.string('A')).to be_kind_of(Ronin::Code::SQL::Literal)
40
+ end
41
+
42
+ it "should convert the value to a String" do
43
+ expect(subject.string(42).value).to eq('42')
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'ronin/code/sql/operators'
3
+ require 'sql/binary_expr_examples'
4
+ require 'sql/unary_expr_examples'
5
+
6
+ describe Ronin::Code::SQL::Operators do
7
+ subject { Object.new.extend(described_class) }
8
+
9
+ let(:operand) { 1 }
10
+
11
+ include_examples "BinaryExpr", :*
12
+ include_examples "BinaryExpr", :/
13
+ include_examples "BinaryExpr", :%
14
+ include_examples "BinaryExpr", :+
15
+ include_examples "BinaryExpr", :-
16
+ include_examples "BinaryExpr", :<<
17
+ include_examples "BinaryExpr", :>>
18
+ include_examples "BinaryExpr", :&
19
+ include_examples "BinaryExpr", :|
20
+ include_examples "BinaryExpr", :<
21
+ include_examples "BinaryExpr", :<=
22
+ include_examples "BinaryExpr", :>
23
+ include_examples "BinaryExpr", :>=
24
+ include_examples "BinaryExpr", :==, :"="
25
+ include_examples "BinaryExpr", :!=
26
+ include_examples "BinaryExpr", :as, :AS
27
+ include_examples "BinaryExpr", :is, :IS
28
+ include_examples "BinaryExpr", :is_not, [:IS, :NOT]
29
+ include_examples "BinaryExpr", :like, :LIKE
30
+ include_examples "BinaryExpr", :glob, :GLOB
31
+ include_examples "BinaryExpr", :match, :MATCH
32
+ include_examples "BinaryExpr", :regexp, :REGEXP
33
+ include_examples "BinaryExpr", :in, :IN
34
+
35
+ include_examples "UnaryExpr", :-@, :-
36
+ include_examples "UnaryExpr", :+@, :+
37
+
38
+ include_examples "UnaryExpr", :~
39
+ include_examples "UnaryExpr", :!
40
+ include_examples "UnaryExpr", :not, :NOT
41
+
42
+ include_examples "BinaryExpr", :and, :AND
43
+ include_examples "BinaryExpr", :or, :OR
44
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for "Statement" do |method,keyword,argument=nil|
4
+ describe "##{method}" do
5
+ case argument
6
+ when Array
7
+ let(:arguments) { argument }
8
+
9
+ let(:statement) { subject.send(method,*arguments) }
10
+ when NilClass
11
+ let(:statement) { subject.send(method) }
12
+ else
13
+ let(:statement) { subject.send(method,argument) }
14
+ end
15
+
16
+ it "should add a #{keyword} clause" do
17
+ expect(statement.keyword).to eq(keyword)
18
+ end
19
+
20
+ case argument
21
+ when Proc
22
+ it "should accept a block" do
23
+ expect(statement.argument).not_to be_nil
24
+ end
25
+ when NilClass
26
+ it "should not have an argument" do
27
+ expect(statement.argument).to be_nil
28
+ end
29
+ when Array
30
+ it "should accept an argument" do
31
+ expect(statement.argument).to eq(arguments)
32
+ end
33
+ else
34
+ it "should accept an argument" do
35
+ expect(statement.argument).to eq(argument)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ require 'ronin/code/sql/statement_list'
3
+
4
+ describe Ronin::Code::SQL::StatementList do
5
+ describe "#initialize" do
6
+ context "when given a block" do
7
+ subject do
8
+ described_class.new { @x = 1 }
9
+ end
10
+
11
+ it "should instance_eval the block" do
12
+ expect(subject.instance_variable_get(:@x)).to eq(1)
13
+ end
14
+
15
+ context "that accepts an argument" do
16
+ it "should yield itself" do
17
+ yielded_statement_list = nil
18
+
19
+ described_class.new do |statement_list|
20
+ yielded_statement_list = statement_list
21
+ end
22
+
23
+ expect(yielded_statement_list).to be_kind_of(described_class)
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ describe "#<<" do
30
+ let(:keyword) { :SELECT }
31
+
32
+ before { subject << Ronin::Code::SQL::Statement.new(keyword) }
33
+
34
+ it "should append a new statement" do
35
+ expect(subject.statements.last.keyword).to eq(keyword)
36
+ end
37
+ end
38
+
39
+ describe "#statement" do
40
+ let(:keyword) { [:ALTER, :TABLE] }
41
+
42
+ before { subject.statement(keyword) }
43
+
44
+ it "should create and append a new Statement" do
45
+ expect(subject.statements.last.keyword).to eq(keyword)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'ronin/code/sql/statement'
3
+
4
+ describe Ronin::Code::SQL::Statement do
5
+ describe "#initialize" do
6
+ context "when given an argument" do
7
+ let(:argument) { 1 }
8
+
9
+ subject { described_class.new(:STATEMENT,argument) }
10
+
11
+ it "should set the argument" do
12
+ expect(subject.argument).to eq(argument)
13
+ end
14
+ end
15
+
16
+ context "when given a block" do
17
+ subject do
18
+ described_class.new(:STATEMENT) { @x = 1 }
19
+ end
20
+
21
+ it "should instance_eval the block" do
22
+ expect(subject.instance_variable_get(:@x)).to eq(1)
23
+ end
24
+
25
+ context "that accepts an argument" do
26
+ it "should yield itself" do
27
+ yielded_statement = nil
28
+
29
+ described_class.new(:STATEMENT) do |stmt|
30
+ yielded_statement = stmt
31
+ end
32
+
33
+ expect(yielded_statement).to be_kind_of(described_class)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'sql/statement_examples'
3
+ require 'ronin/code/sql/statement'
4
+ require 'ronin/code/sql/statements'
5
+
6
+ describe Ronin::Code::SQL::Statements do
7
+ subject { Object.new.extend(described_class) }
8
+
9
+ describe "#statement" do
10
+ let(:keyword) { :EXEC }
11
+
12
+ it "should create an arbitrary statement" do
13
+ expect(subject.statement(keyword).keyword).to eq(keyword)
14
+ end
15
+ end
16
+
17
+ include_examples "Statement", :select, :SELECT, [1,2,3,:id]
18
+ include_examples "Statement", :insert, :INSERT
19
+ include_examples "Statement", :update, :UPDATE, :table
20
+ include_examples "Statement", :delete, [:DELETE, :FROM], :table
21
+ include_examples "Statement", :drop_table, [:DROP, :TABLE], :table
22
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require 'ronin/code/sql/unary_expr'
3
+
4
+ shared_examples_for "UnaryExpr" do |method,operator=method|
5
+ describe "##{method}" do
6
+ let(:expr) { subject.send(method) }
7
+
8
+ it "should be a UnaryExpr" do
9
+ expect(expr).to be_kind_of(Ronin::Code::SQL::UnaryExpr)
10
+ end
11
+
12
+ it "should set the operand" do
13
+ expect(expr.operand).to eq(subject)
14
+ end
15
+
16
+ it "should have a '#{operator}' operator" do
17
+ expect(expr.operator).to eq(operator)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+ require 'ronin/code/sql/unary_expr'
3
+
4
+ describe Ronin::Code::SQL::UnaryExpr do
5
+ end