fuzzbert 1.0.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.
@@ -0,0 +1,8 @@
1
+
2
+ module FuzzBert::Generation
3
+
4
+ def generator
5
+ -> { to_data }
6
+ end
7
+
8
+ end
@@ -0,0 +1,18 @@
1
+
2
+ class FuzzBert::Generator
3
+ include FuzzBert::Generation
4
+
5
+ attr_reader :description
6
+
7
+ def initialize(desc, generator=nil, &blk)
8
+ @description = desc
9
+ @generator = generator || blk
10
+ raise RuntimeError.new("No generator given") unless @generator
11
+ end
12
+
13
+ def to_data
14
+ @generator.call
15
+ end
16
+
17
+ end
18
+
@@ -0,0 +1,70 @@
1
+ require 'base64'
2
+
3
+ module FuzzBert::Generators
4
+
5
+ class << self
6
+
7
+ def random(limit=1024)
8
+ -> { random_bytes(limit) { |data| data } }
9
+ end
10
+
11
+ def random_b64(limit=1024)
12
+ -> { random_bytes(b64_len(limit)) { |data| Base64.encode64(data) } }
13
+ end
14
+
15
+ def random_hex(limit=1024)
16
+ -> { random_bytes(hex_len(limit)) { |data| data.unpack("H*")[0] } }
17
+ end
18
+
19
+ def random_fixlen(len)
20
+ -> { random_bytes_fixlen(len) { |data| data } }
21
+ end
22
+
23
+ def random_b64_fixlen(len)
24
+ -> { random_bytes_fixlen(b64_len(len)) { |data| Base64.encode(data) } }
25
+ end
26
+
27
+ def random_hex_fixlen(len)
28
+ -> { random_bytes_fixlen(hex_len(len)) { |data| data.unpack("H*")[0] } }
29
+ end
30
+
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
38
+ end
39
+ end
40
+
41
+ def fixed(data)
42
+ -> { data }
43
+ end
44
+
45
+ def sample(ary)
46
+ -> { ary.sample }
47
+ end
48
+
49
+ private
50
+
51
+ def hex_len(len)
52
+ len / 2
53
+ end
54
+
55
+ def b64_len(len)
56
+ len * 3 / 4
57
+ end
58
+
59
+ def random_bytes(limit)
60
+ len = FuzzBert::PRNG.rand(1..limit)
61
+ yield FuzzBert::PRNG.bytes(len)
62
+ end
63
+
64
+ def random_bytes_fixlen(len)
65
+ yield FuzzBert::PRNG.bytes(len)
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,19 @@
1
+
2
+ class FuzzBert::Mutator < FuzzBert::Generator
3
+
4
+ def initialize(value)
5
+ orig = value.dup
6
+ orig.force_encoding(Encoding::BINARY)
7
+ super("Mutator") do
8
+ #select a byte
9
+ i = FuzzBert::PRNG.rand(value.size)
10
+ old = orig[i].ord
11
+ #map a random value from 0..254 to 0..255 excluding the current value
12
+ b = FuzzBert::PRNG.rand(255)
13
+ b = b < old ? b : b + 1
14
+ orig.dup.tap { |s| s.setbyte(i, b) }
15
+ end
16
+ end
17
+
18
+ end
19
+
@@ -0,0 +1,81 @@
1
+ require 'fuzzbert'
2
+ require 'rake'
3
+ require 'rake/tasklib'
4
+
5
+ class FuzzBert::RakeTask < ::Rake::TaskLib
6
+ include ::Rake::DSL if defined?(::Rake::DSL)
7
+
8
+ # Name of task.
9
+ #
10
+ # default:
11
+ # :fuzz
12
+ attr_accessor :name
13
+
14
+ # Glob pattern to match files.
15
+ #
16
+ # default:
17
+ # 'fuzz/**/fuzz_*.rb'
18
+ attr_accessor :pattern
19
+
20
+ # Command line options to pass to ruby.
21
+ #
22
+ # default:
23
+ # nil
24
+ attr_accessor :ruby_opts
25
+
26
+ # Path to FuzzBert
27
+ #
28
+ # default:
29
+ # 'fuzzbert'
30
+ attr_accessor :fuzzbert_path
31
+
32
+ # Command line options to pass to fuzzbert.
33
+ #
34
+ # default:
35
+ # nil
36
+ attr_accessor :fuzzbert_opts
37
+
38
+ def initialize(*args)
39
+ #configure the rake task
40
+ setup_ivars(args)
41
+ yield self if block_given?
42
+
43
+ desc "Run FuzzBert random test suite" unless ::Rake.application.last_comment
44
+
45
+ task name do
46
+ run_task
47
+ end
48
+ end
49
+
50
+ def setup_ivars(*args)
51
+ @name = args.shift || :fuzz
52
+ @ruby_opts, @fuzzbert_opts = nil, nil
53
+ @fuzzbert_path = 'fuzzbert'
54
+ @pattern = 'fuzz/**/fuzz_*.rb'
55
+ end
56
+
57
+ def run_task
58
+ begin
59
+ system(command)
60
+ rescue
61
+ #silent, user could have interrupted a permanent session
62
+ end
63
+ end
64
+
65
+ private
66
+
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
80
+ end
81
+
@@ -0,0 +1,154 @@
1
+ require 'stringio'
2
+
3
+ class FuzzBert::Template
4
+ include FuzzBert::Generation
5
+
6
+ def initialize(template)
7
+ @template = Parser.new(template).parse
8
+ @callbacks = {}
9
+ end
10
+
11
+ def set(name, &blk)
12
+ @callbacks[name] = blk
13
+ end
14
+
15
+ def to_data
16
+ "".tap do |buf|
17
+ @template.each { |t| buf << t.to_data(@callbacks) }
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ class Parser
24
+
25
+ def initialize(template)
26
+ @io = StringIO.new(template)
27
+ @template = []
28
+ end
29
+
30
+ def parse
31
+ @state = determine_state
32
+ while token = parse_token
33
+ @template << token
34
+ end
35
+ @template
36
+ end
37
+
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
47
+ end
48
+
49
+ def determine_state
50
+ begin
51
+ @buf = @io.readchar
52
+
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 '\\'
64
+ @buf = ""
65
+ :TEXT
66
+ else
67
+ :TEXT
68
+ end
69
+ rescue EOFError
70
+ :EOF
71
+ end
72
+ end
73
+
74
+ def parse_identifier
75
+ name = ""
76
+ begin
77
+ until (c = @io.readchar) == '}'
78
+ name << c
79
+ end
80
+
81
+ if name.empty?
82
+ raise RuntimeError.new("No identifier name given")
83
+ end
84
+
85
+ @state = determine_state
86
+ Identifier.new(name)
87
+ rescue EOFError
88
+ raise RuntimeError.new("Unclosed identifier")
89
+ end
90
+ end
91
+
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)
108
+ else
109
+ text << c
110
+ text << d
111
+ end
112
+ end
113
+ rescue EOFError
114
+ @state = :EOF
115
+ Text.new(text)
116
+ end
117
+ end
118
+
119
+ def parse_escape
120
+ begin
121
+ @io.readchar
122
+ rescue EOFError
123
+ '\\'
124
+ end
125
+ end
126
+
127
+ end
128
+
129
+ class Text
130
+
131
+ def initialize(text)
132
+ @text = text
133
+ end
134
+
135
+ def to_data(callbacks)
136
+ @text
137
+ end
138
+
139
+ end
140
+
141
+ class Identifier
142
+
143
+ def initialize(name)
144
+ @name = name.to_sym
145
+ end
146
+
147
+ def to_data(callbacks)
148
+ callbacks[@name].call
149
+ end
150
+
151
+ end
152
+
153
+ end
154
+
@@ -0,0 +1,13 @@
1
+
2
+ class FuzzBert::Test
3
+
4
+ def initialize(runner)
5
+ @runner = runner
6
+ end
7
+
8
+ def run(data)
9
+ @runner.call data
10
+ end
11
+
12
+ end
13
+
@@ -0,0 +1,25 @@
1
+
2
+ class FuzzBert::TestSuite
3
+
4
+ attr_reader :description, :test, :generators
5
+
6
+ def initialize(desc)
7
+ @description = desc
8
+ @generators = []
9
+ end
10
+
11
+ def deploy(&blk)
12
+ @test = FuzzBert::Test.new(blk)
13
+ end
14
+
15
+ def data(desc, &blk)
16
+ @generators << FuzzBert::Generator.new(desc, blk.call)
17
+ end
18
+
19
+ def self.create(desc, &blk)
20
+ obj = self.new(desc)
21
+ obj.instance_eval(&blk) if blk
22
+ obj
23
+ end
24
+
25
+ end
@@ -0,0 +1,4 @@
1
+ module FuzzBert
2
+ VERSION = "1.0.0"
3
+ end
4
+
@@ -0,0 +1,39 @@
1
+ require 'rspec'
2
+ require 'fuzzbert'
3
+
4
+ describe FuzzBert::AutoRun do
5
+
6
+ let(:handler) do
7
+ c = Class.new
8
+ def c.handle(id, data, pid, status)
9
+ raise RuntimeError.new
10
+ end
11
+ c
12
+ end
13
+
14
+ value = "test"
15
+ called = false
16
+
17
+ fuzz "autorun" do
18
+
19
+ deploy do |data|
20
+ data.should == value
21
+ end
22
+
23
+ data "1" do
24
+ called = true
25
+ -> { value }
26
+ end
27
+
28
+ end
29
+
30
+ it "has added a TestSuite to AutoRun" do
31
+ suite = FuzzBert::AutoRun::TEST_CASES
32
+ suite.size.should == 1
33
+ FuzzBert::Executor.new(suite, pool_size: 1, limit: 1, handler: handler).run
34
+ called.should == true
35
+ end
36
+
37
+ end
38
+
39
+
@@ -0,0 +1,88 @@
1
+ require 'rspec'
2
+ require 'fuzzbert'
3
+
4
+ describe FuzzBert::TestSuite do
5
+ describe "fuzz" do
6
+ context "with one generator" do
7
+ let(:suite) do
8
+ FuzzBert::TestSuite.create "test" do
9
+ deploy { |data| data }
10
+
11
+ data("1") { FuzzBert::Generators.random }
12
+ end
13
+ end
14
+
15
+ it "returns an instance of TestSuite" do
16
+ suite.should be_an_instance_of(FuzzBert::TestSuite)
17
+ suite.description.should == "test"
18
+ end
19
+
20
+ it "defines a test that executes the block in deploy" do
21
+ suite.test.should_not be_nil
22
+ suite.test.should be_an_instance_of(FuzzBert::Test)
23
+ ["a", 10, true, Object.new].each { |o| suite.test.run(o).should == o }
24
+ end
25
+
26
+ it "defines one generator" do
27
+ suite.generators.size.should == 1
28
+ gen = suite.generators.first
29
+ gen.should be_an_instance_of(FuzzBert::Generator)
30
+ gen.description.should == "1"
31
+ gen.to_data.should be_an_instance_of(String)
32
+ end
33
+
34
+ end
35
+
36
+ context "with two generators" do
37
+ let(:suite) do
38
+ FuzzBert::TestSuite.create "test" do
39
+ deploy { |data| data }
40
+
41
+ data("1") { FuzzBert::Generators.fixed(1) }
42
+ data("2") { FuzzBert::Generators.fixed(2) }
43
+ end
44
+ end
45
+
46
+ it "defines two generators" do
47
+ suite.generators.size.should == 2
48
+ gen = suite.generators.first
49
+ gen.should be_an_instance_of(FuzzBert::Generator)
50
+ gen.description.should == "1"
51
+ gen.to_data.should == 1
52
+
53
+ gen = suite.generators[1]
54
+ gen.should be_an_instance_of(FuzzBert::Generator)
55
+ gen.description.should == "2"
56
+ gen.to_data.should == 2
57
+ end
58
+
59
+ end
60
+
61
+ context "with complex data" do
62
+ let(:suite) do
63
+ FuzzBert::TestSuite.create "test" do
64
+ deploy { |data| data }
65
+
66
+ data "1" do
67
+ c = FuzzBert::Container.new
68
+ c << FuzzBert::Generators.fixed("1")
69
+ c << FuzzBert::Generators.fixed("2")
70
+ c << FuzzBert::Generators.fixed("3")
71
+ c.generator
72
+ end
73
+
74
+ end
75
+ end
76
+
77
+ it "applies the container generators in sequence" do
78
+ suite.generators.size.should == 1
79
+ gen = suite.generators.first
80
+ gen.should be_an_instance_of(FuzzBert::Generator)
81
+ gen.description.should == "1"
82
+ gen.to_data.should == "123"
83
+ end
84
+ end
85
+ end
86
+
87
+ end
88
+