fuzzbert 1.0.0 → 1.0.1
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.
- data/README.md +104 -51
- data/lib/fuzzbert/autorun.rb +62 -29
- data/lib/fuzzbert/dsl.rb +2 -0
- data/lib/fuzzbert/error_handler.rb +53 -5
- data/lib/fuzzbert/executor.rb +108 -94
- data/lib/fuzzbert/generators.rb +35 -37
- data/lib/fuzzbert/rake_task.rb +13 -12
- data/lib/fuzzbert/template.rb +95 -93
- data/lib/fuzzbert/test_suite.rb +4 -1
- data/spec/autorun_spec.rb +30 -16
- data/spec/dsl_spec.rb +43 -0
- data/spec/executor_spec.rb +26 -8
- data/spec/generator_spec.rb +11 -3
- data/spec/mutator_spec.rb +6 -4
- data/spec/template_spec.rb +20 -3
- metadata +20 -21
- data/lib/fuzzbert/autorun.rb~ +0 -33
data/lib/fuzzbert/generators.rb
CHANGED
@@ -2,51 +2,51 @@ require 'base64'
|
|
2
2
|
|
3
3
|
module FuzzBert::Generators
|
4
4
|
|
5
|
-
|
5
|
+
module_function
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
def random(limit=1024)
|
8
|
+
-> { random_bytes(limit) { |data| data } }
|
9
|
+
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
def random_b64(limit=1024)
|
12
|
+
-> { random_bytes(b64_len(limit)) { |data| Base64.encode64(data) } }
|
13
|
+
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
def random_hex(limit=1024)
|
16
|
+
-> { random_bytes(hex_len(limit)) { |data| data.unpack("H*")[0] } }
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
def random_fixlen(len)
|
20
|
+
-> { random_bytes_fixlen(len) { |data| data } }
|
21
|
+
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
def random_b64_fixlen(len)
|
24
|
+
-> { random_bytes_fixlen(b64_len(len)) { |data| Base64.encode(data) } }
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
def random_hex_fixlen(len)
|
28
|
+
-> { random_bytes_fixlen(hex_len(len)) { |data| data.unpack("H*")[0] } }
|
29
|
+
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def fixed(data)
|
42
|
-
-> { data }
|
31
|
+
def cycle(range)
|
32
|
+
ary = range.to_a
|
33
|
+
i = 0
|
34
|
+
lambda do
|
35
|
+
ret = ary[i]
|
36
|
+
i = (i + 1) % ary.size
|
37
|
+
ret
|
43
38
|
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def fixed(data)
|
42
|
+
-> { data }
|
43
|
+
end
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
def sample(ary)
|
46
|
+
-> { ary.sample }
|
47
|
+
end
|
48
48
|
|
49
|
-
|
49
|
+
private; module_function
|
50
50
|
|
51
51
|
def hex_len(len)
|
52
52
|
len / 2
|
@@ -65,6 +65,4 @@ module FuzzBert::Generators
|
|
65
65
|
yield FuzzBert::PRNG.bytes(len)
|
66
66
|
end
|
67
67
|
|
68
|
-
end
|
69
|
-
|
70
68
|
end
|
data/lib/fuzzbert/rake_task.rb
CHANGED
@@ -64,18 +64,19 @@ class FuzzBert::RakeTask < ::Rake::TaskLib
|
|
64
64
|
|
65
65
|
private
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
67
|
+
def command
|
68
|
+
cmd_parts = []
|
69
|
+
cmd_parts << RUBY
|
70
|
+
cmd_parts << ruby_opts
|
71
|
+
cmd_parts << "-S" << fuzzbert_path
|
72
|
+
cmd_parts << fuzzbert_opts
|
73
|
+
cmd_parts << pattern
|
74
|
+
cmd_parts.flatten.reject(&blank).join(" ")
|
75
|
+
end
|
76
|
+
|
77
|
+
def blank
|
78
|
+
lambda {|s| s.nil? || s == ""}
|
79
|
+
end
|
76
80
|
|
77
|
-
def blank
|
78
|
-
lambda {|s| s.nil? || s == ""}
|
79
|
-
end
|
80
81
|
end
|
81
82
|
|
data/lib/fuzzbert/template.rb
CHANGED
@@ -20,135 +20,137 @@ class FuzzBert::Template
|
|
20
20
|
|
21
21
|
private
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
class Parser
|
24
|
+
|
25
|
+
def initialize(template)
|
26
|
+
@io = StringIO.new(template)
|
27
|
+
@template = []
|
28
|
+
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
def parse
|
31
|
+
@state = determine_state
|
32
|
+
while token = parse_token
|
33
|
+
@template << token
|
34
|
+
end
|
35
|
+
@template
|
34
36
|
end
|
35
|
-
@template
|
36
|
-
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
def parse_token
|
39
|
+
case @state
|
40
|
+
when :TEXT
|
41
|
+
parse_text
|
42
|
+
when :IDENTIFIER
|
43
|
+
parse_identifier
|
44
|
+
else
|
45
|
+
nil
|
46
|
+
end
|
46
47
|
end
|
47
|
-
end
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
def determine_state
|
50
|
+
begin
|
51
|
+
@buf = @io.readchar
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
case @buf
|
54
|
+
when '$'
|
55
|
+
c = @io.readchar
|
56
|
+
if c == "{"
|
57
|
+
@buf = ""
|
58
|
+
:IDENTIFIER
|
59
|
+
else
|
60
|
+
@buf << c
|
61
|
+
:TEXT
|
62
|
+
end
|
63
|
+
when '\\'
|
57
64
|
@buf = ""
|
58
|
-
:
|
65
|
+
:TEXT
|
59
66
|
else
|
60
|
-
@buf << c
|
61
67
|
:TEXT
|
62
68
|
end
|
63
|
-
|
64
|
-
|
65
|
-
:TEXT
|
66
|
-
else
|
67
|
-
:TEXT
|
69
|
+
rescue EOFError
|
70
|
+
:EOF
|
68
71
|
end
|
69
|
-
rescue EOFError
|
70
|
-
:EOF
|
71
72
|
end
|
72
|
-
end
|
73
73
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
74
|
+
def parse_identifier
|
75
|
+
name = ""
|
76
|
+
begin
|
77
|
+
until (c = @io.readchar) == '}'
|
78
|
+
name << c
|
79
|
+
end
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
if name.empty?
|
82
|
+
raise RuntimeError.new("No identifier name given")
|
83
|
+
end
|
84
84
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
85
|
+
@state = determine_state
|
86
|
+
Identifier.new(name)
|
87
|
+
rescue EOFError
|
88
|
+
raise RuntimeError.new("Unclosed identifier")
|
89
|
+
end
|
89
90
|
end
|
90
|
-
end
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
92
|
+
def parse_text
|
93
|
+
text = @buf
|
94
|
+
begin
|
95
|
+
loop do
|
96
|
+
until (c = @io.readchar) == '$'
|
97
|
+
if c == '\\'
|
98
|
+
text << parse_escape
|
99
|
+
else
|
100
|
+
text << c
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
d = @io.readchar
|
105
|
+
if d == "{"
|
106
|
+
@state = :IDENTIFIER
|
107
|
+
return Text.new(text)
|
99
108
|
else
|
100
109
|
text << c
|
110
|
+
text << d
|
101
111
|
end
|
102
112
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
@state = :IDENTIFIER
|
107
|
-
return Text.new(text)
|
108
|
-
else
|
109
|
-
text << c
|
110
|
-
text << d
|
111
|
-
end
|
113
|
+
rescue EOFError
|
114
|
+
@state = :EOF
|
115
|
+
Text.new(text)
|
112
116
|
end
|
113
|
-
rescue EOFError
|
114
|
-
@state = :EOF
|
115
|
-
Text.new(text)
|
116
117
|
end
|
117
|
-
end
|
118
118
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
119
|
+
def parse_escape
|
120
|
+
begin
|
121
|
+
@io.readchar
|
122
|
+
rescue EOFError
|
123
|
+
'\\'
|
124
|
+
end
|
124
125
|
end
|
126
|
+
|
125
127
|
end
|
126
128
|
|
127
|
-
|
129
|
+
class Text
|
128
130
|
|
129
|
-
|
131
|
+
def initialize(text)
|
132
|
+
@text = text
|
133
|
+
end
|
130
134
|
|
131
|
-
|
132
|
-
|
133
|
-
|
135
|
+
def to_data(callbacks)
|
136
|
+
@text
|
137
|
+
end
|
134
138
|
|
135
|
-
def to_data(callbacks)
|
136
|
-
@text
|
137
139
|
end
|
138
140
|
|
139
|
-
|
141
|
+
class Identifier
|
140
142
|
|
141
|
-
|
143
|
+
def initialize(name)
|
144
|
+
@name = name.to_sym
|
145
|
+
end
|
142
146
|
|
143
|
-
|
144
|
-
|
145
|
-
|
147
|
+
def to_data(callbacks)
|
148
|
+
cb = callbacks[@name]
|
149
|
+
raise RuntimeError.new "No callback set for :#{@name}" unless cb
|
150
|
+
cb.call
|
151
|
+
end
|
146
152
|
|
147
|
-
def to_data(callbacks)
|
148
|
-
callbacks[@name].call
|
149
153
|
end
|
150
154
|
|
151
|
-
end
|
152
|
-
|
153
155
|
end
|
154
156
|
|
data/lib/fuzzbert/test_suite.rb
CHANGED
@@ -9,16 +9,19 @@ class FuzzBert::TestSuite
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def deploy(&blk)
|
12
|
+
raise RuntimeError.new "No block was given" unless blk
|
12
13
|
@test = FuzzBert::Test.new(blk)
|
13
14
|
end
|
14
15
|
|
15
16
|
def data(desc, &blk)
|
17
|
+
raise RuntimeError.new "No block was given" unless blk
|
16
18
|
@generators << FuzzBert::Generator.new(desc, blk.call)
|
17
19
|
end
|
18
20
|
|
19
21
|
def self.create(desc, &blk)
|
22
|
+
raise RuntimeError.new "No block was given" unless blk
|
20
23
|
obj = self.new(desc)
|
21
|
-
obj.instance_eval(&blk)
|
24
|
+
obj.instance_eval(&blk)
|
22
25
|
obj
|
23
26
|
end
|
24
27
|
|
data/spec/autorun_spec.rb
CHANGED
@@ -1,39 +1,53 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require 'fuzzbert'
|
3
3
|
|
4
|
+
|
4
5
|
describe FuzzBert::AutoRun do
|
5
6
|
|
7
|
+
after(:each) do
|
8
|
+
#clear any TestSuites that were created
|
9
|
+
FuzzBert::AutoRun::TEST_CASES.clear
|
10
|
+
end
|
11
|
+
|
6
12
|
let(:handler) do
|
7
13
|
c = Class.new
|
8
|
-
def c.handle(
|
14
|
+
def c.handle(error_data)
|
9
15
|
raise RuntimeError.new
|
10
16
|
end
|
11
17
|
c
|
12
18
|
end
|
13
19
|
|
14
|
-
|
15
|
-
|
20
|
+
|
21
|
+
context "with a valid test" do
|
22
|
+
value = "test"
|
23
|
+
called = false
|
16
24
|
|
17
|
-
|
25
|
+
fuzz "autorun" do
|
18
26
|
|
19
|
-
|
20
|
-
|
21
|
-
|
27
|
+
deploy do |data|
|
28
|
+
data.should == value
|
29
|
+
end
|
30
|
+
|
31
|
+
data "1" do
|
32
|
+
called = true
|
33
|
+
-> { value }
|
34
|
+
end
|
22
35
|
|
23
|
-
data "1" do
|
24
|
-
called = true
|
25
|
-
-> { value }
|
26
36
|
end
|
27
37
|
|
38
|
+
it "has added a TestSuite to AutoRun" do
|
39
|
+
FuzzBert::AutoRun::TEST_CASES.size.should == 1
|
40
|
+
FuzzBert::AutoRun.run(pool_size: 1, limit: 1, handler: handler, sleep_delay: 0.05)
|
41
|
+
called.should == true
|
42
|
+
end
|
28
43
|
end
|
29
44
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
45
|
+
context "with no test" do
|
46
|
+
it "raises an error when executed" do
|
47
|
+
FuzzBert::AutoRun::TEST_CASES.should be_empty
|
48
|
+
-> { FuzzBert::AutoRun.run }.should raise_error
|
49
|
+
end
|
35
50
|
end
|
36
51
|
|
37
52
|
end
|
38
53
|
|
39
|
-
|
data/spec/dsl_spec.rb
CHANGED
@@ -84,5 +84,48 @@ describe FuzzBert::TestSuite do
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
+
it "raises an error when no block is given" do
|
88
|
+
-> { FuzzBert::TestSuite.create "test" }.should raise_error
|
89
|
+
end
|
90
|
+
|
91
|
+
it "raises an error when the deploy block is missing" do
|
92
|
+
lambda do
|
93
|
+
FuzzBert::TestSuite.create "test" do
|
94
|
+
data("1") { FuzzBert::Generators.random }
|
95
|
+
end.should raise_error
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it "raises an error when the data blocks are missing" do
|
100
|
+
lambda do
|
101
|
+
FuzzBert::TestSuite.create "test" do
|
102
|
+
deploy { |data| data }
|
103
|
+
end.should raise_error
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "deploy" do
|
108
|
+
it "raises an error when no block is given" do
|
109
|
+
lambda do
|
110
|
+
FuzzBert::TestSuite.create "test" do
|
111
|
+
deploy
|
112
|
+
|
113
|
+
data("1") { FuzzBert::Generators.random }
|
114
|
+
end
|
115
|
+
end.should raise_error
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "data" do
|
120
|
+
it "raises an error when no block is given" do
|
121
|
+
lambda do
|
122
|
+
FuzzBert::TestSuite.create "test" do
|
123
|
+
deploy { |data| data }
|
124
|
+
data("1")
|
125
|
+
end
|
126
|
+
end.should raise_error
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
87
130
|
end
|
88
131
|
|