fuzzbert 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Martin Boßlet
1
+ Copyright (c) 2012-2013 Martin Boßlet
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # FuzzBert [![Build Status](https://secure.travis-ci.org/krypt/FuzzBert.png?branch=master)](http://travis-ci.org/krypt/FuzzBert)
1
+ # FuzzBert [![Build Status](https://secure.travis-ci.org/krypt/FuzzBert.png?branch=master)](http://travis-ci.org/krypt/FuzzBert) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/krypt/FuzzBert)
2
2
 
3
3
  A random testing/fuzzer framework for Ruby.
4
4
 
@@ -162,7 +162,7 @@ fuzz "Define here as usual" do
162
162
  end
163
163
  ```
164
164
 
165
- Then tell fuzzbert by telling it about the custom handler:
165
+ Now you just need to tell FuzzBert to use your custom handler:
166
166
 
167
167
  fuzzbert --handler MyHandler my/fuzzbert/file
168
168
 
@@ -189,8 +189,8 @@ fuzz "My Web App" do
189
189
 
190
190
  data "JSON generated from a template" do
191
191
  t = FuzzBert::Template.new '{ user: { id: ${id}, name: "${name}" } }'
192
- t.set(:id) { FuzzBert::Generators.cycle(1..10000) }
193
- t.set(:name) { FuzzBert::Generators.random }
192
+ t.set(:id, FuzzBert::Generators.cycle(1..10000))
193
+ t.set(:name) { "fixed" + FuzzBert::Generators.random_fixlen(2).call }
194
194
  t.generator
195
195
  end
196
196
 
@@ -198,8 +198,12 @@ end
198
198
  ```
199
199
 
200
200
  Simply specify your template variables using `${..}` and assign a callback for
201
- them via `set`. Of course you may escape the dollar sign with a back slash as
202
- usual.
201
+ them via `set`. Of course you may escape the dollar sign with a backslash as
202
+ usual. The Template#set method takes as its first argument the symbol
203
+ representing the template variable. To specify the data to be generated, it
204
+ either takes a second argument in form of a proc or lambda (to use the
205
+ built-in generators for example, as in `:id` in the example) or it takes a
206
+ block that allows to define the data ad-hoc (as in `:name`).
203
207
 
204
208
  ## Mutators
205
209
 
@@ -252,6 +256,6 @@ connected to Ruby at all - have a look in the examples that ship with FuzzBert.
252
256
 
253
257
  ## License
254
258
 
255
- Copyright (c) 2012 Martin Boßlet. Distributed under the MIT License. See LICENSE for
259
+ Copyright (c) 2012-2013 Martin Boßlet. Distributed under the MIT License. See LICENSE for
256
260
  further details.
257
261
 
data/lib/fuzzbert.rb CHANGED
@@ -4,13 +4,28 @@
4
4
 
5
5
  FuzzBert - Random Testing / Fuzzing in Ruby
6
6
 
7
- Copyright (C) 2012
8
- Martin Bosslet <martin.bosslet@googlemail.com>
7
+ Copyright (C) 2012-2013
8
+ Martin Bosslet <martin.bosslet@gmail.com>
9
9
  All rights reserved.
10
10
 
11
- = License
12
-
13
- See the file 'LICENSE' for further details.
11
+ Permission is hereby granted, free of charge, to any person obtaining
12
+ a copy of this software and associated documentation files (the
13
+ "Software"), to deal in the Software without restriction, including
14
+ without limitation the rights to use, copy, modify, merge, publish,
15
+ distribute, sublicense, and/or sell copies of the Software, and to
16
+ permit persons to whom the Software is furnished to do so, subject to
17
+ the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be
20
+ included in all copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
29
 
15
30
  =end
16
31
 
@@ -11,7 +11,11 @@ module FuzzBert::AutoRun
11
11
  end
12
12
 
13
13
  def autorun
14
- options, files = process_args(ARGV)
14
+ autorun_with_args(ARGV)
15
+ end
16
+
17
+ def autorun_with_args(argv)
18
+ options, files = process_args(argv)
15
19
  load_files(files)
16
20
  run(options)
17
21
  end
@@ -34,8 +38,26 @@ module FuzzBert::AutoRun
34
38
  orig_args = args.dup
35
39
 
36
40
  OptionParser.new do |opts|
37
- opts.banner = 'Usage: fuzzbert [OPTIONS] PATTERN [PATTERNS]'
38
- opts.separator <<-EOS
41
+ add_banner(opts)
42
+
43
+ add_help(opts)
44
+ add_pool_size(opts, options)
45
+ add_limit(opts, options)
46
+ add_console(opts, options)
47
+ add_sleep_delay(opts, options)
48
+ add_handler(opts, options)
49
+ add_bug_dir(opts, options)
50
+
51
+ opts.parse! args
52
+ end
53
+
54
+ raise ArgumentError.new("No file pattern was given") if args.empty?
55
+ [options, args]
56
+ end
57
+
58
+ def add_banner(opts)
59
+ opts.banner = 'Usage: fuzzbert [OPTIONS] PATTERN [PATTERNS]'
60
+ opts.separator <<-EOS
39
61
 
40
62
  Run your random tests by pointing fuzzbert to a single or many explicit files
41
63
  or by providing a pattern. The default pattern is 'fuzz/**/fuzz_*.rb, assuming
@@ -45,53 +67,65 @@ named fuzz located under the current directory that you are in.
45
67
  By default, fuzzbert will run the tests you specify forever, be sure to hit
46
68
  CTRL+C when you are done or specify a limit with '--limit'.
47
69
 
48
- EOS
49
-
50
- opts.version = FuzzBert::VERSION
70
+ EOS
51
71
 
52
- opts.on '-h', '--help', 'Run ' do
53
- puts opts
54
- exit
55
- end
56
-
57
- opts.on '--pool-size SIZE', Integer, "Sets the number of concurrently running processes to SIZE. Default is 4." do |n|
58
- options[:pool_size] = n.to_i
59
- end
60
-
61
- opts.on '--limit LIMIT', Integer, "Instead of running permanently, fuzzing will be stopped after running LIMIT of instances." do |n|
62
- options[:limit] = n.to_i
63
- end
72
+ opts.version = FuzzBert::VERSION
73
+ end
64
74
 
65
- opts.on '--console', "Output the failing cases including data on the console instead of saving them in a file." do
66
- options[:handler] = FuzzBert::Handler::Console.new
67
- end
75
+ def add_help(opts)
76
+ opts.on '-h', '--help', 'Run ' do
77
+ puts opts
78
+ exit
79
+ end
80
+ end
68
81
 
69
- opts.on '--sleep-delay SECONDS', Float, "Specify the number of SECONDS that the main process sleeps before checking that the limit has been reached. Default is 1." do |f|
70
- options[:sleep_delay] = f.to_f
71
- end
82
+ def add_pool_size(opts, options)
83
+ opts.on '--pool-size SIZE', Integer, "Sets the number of concurrently running processes to SIZE. Default is 4." do |n|
84
+ options[:pool_size] = n.to_i
85
+ end
86
+ end
72
87
 
73
- opts.on '--handler CLASS', String, "Specify the full path to a CLASS that will serve as your Handler." do |path|
74
- #lazy initialization: the Handler must be defined in one of the fuzzer files
75
- options[:handler] = Class.new do
76
- @@path = path
88
+ def add_limit(opts, options)
89
+ opts.on '--limit LIMIT', Integer, "Instead of running permanently, fuzzing will be stopped after running LIMIT of instances." do |n|
90
+ options[:limit] = n.to_i
91
+ end
92
+ end
77
93
 
78
- def handle(id, data, pid, status)
79
- @inner ||= Object.const_get(@@path).new
80
- @inner.handle(id, data, pid, status)
81
- end
82
- end.new
83
- end
94
+ def add_console(opts, options)
95
+ opts.on '--console', "Output the failing cases including data on the console instead of saving them in a file." do
96
+ options[:handler] = FuzzBert::Handler::Console.new
97
+ end
98
+ end
84
99
 
85
- opts.on '--bug-dir DIRECTORY', String, "The DIRECTORY where the resulting bug files will be stored. Default is the current directory." do |dir|
86
- raise ArgumentError.new "#{dir} is not a directory" unless Dir.exists?(dir)
87
- options[:handler] = FuzzBert::Handler::FileOutput.new(dir)
88
- end
100
+ def add_sleep_delay(opts, options)
101
+ opts.on '--sleep-delay SECONDS', Float, "Specify the number of SECONDS that the main process sleeps before checking that the limit has been reached. Default is 1." do |f|
102
+ options[:sleep_delay] = f.to_f
103
+ end
104
+ end
89
105
 
90
- opts.parse! args
106
+ def add_handler(opts, options)
107
+ opts.on '--handler CLASS', String, "Specify the full path to a CLASS that will serve as your Handler." do |path|
108
+ #lazy initialization: the Handler must be defined in one of the fuzzer files
109
+ options[:handler] = Class.new do
110
+ @@path = path
111
+
112
+ def handle(error_data)
113
+ @inner ||= class_for_name(@@path).new
114
+ @inner.handle(error_data)
115
+ end
116
+
117
+ def class_for_name(path)
118
+ path.split('::').inject(Object) { |mod, class_name| mod.const_get(class_name) }
119
+ end
120
+ end.new
91
121
  end
122
+ end
92
123
 
93
- raise ArgumentError.new("No file pattern was given") if args.empty?
94
- [options, args]
124
+ def add_bug_dir(opts, options)
125
+ opts.on '--bug-dir DIRECTORY', String, "The DIRECTORY where the resulting bug files will be stored. Default is the current directory." do |dir|
126
+ raise ArgumentError.new "#{dir} is not a directory" unless Dir.exists?(dir)
127
+ options[:handler] = FuzzBert::Handler::FileOutput.new(dir)
128
+ end
95
129
  end
96
130
 
97
131
  end
@@ -56,6 +56,10 @@ module FuzzBert::Handler
56
56
  class Console
57
57
  include FuzzBert::Handler::ConsoleHelper
58
58
 
59
+ def initialize
60
+ $stdout.sync = true
61
+ end
62
+
59
63
  def handle(error_data)
60
64
  puts "#{error_data[:id]} failed. Data: #{error_data[:data].inspect}"
61
65
  info(error_data)
@@ -54,31 +54,48 @@ class FuzzBert::Executor
54
54
 
55
55
  def trap_child_exit
56
56
  trap(:CHLD) do
57
- begin
58
- while exitval = Process.wait2(-1, Process::WNOHANG)
59
- pid = exitval[0]
60
- status = exitval[1]
61
- data_ary = @data_cache.delete(pid)
62
- unless status.success?
63
- handle({
64
- id: data_ary[0],
65
- data: data_ary[1],
66
- pid: pid,
67
- status: status
68
- }) unless interrupted(status)
69
- end
70
- @n += 1
71
- if @limit == -1 || @n < @limit
72
- run_instance(*@producer.next)
73
- else
74
- @running = false
75
- end
76
- end
77
- rescue Errno::ECHILD
57
+ while_child_exits do |exitval|
58
+ pid = exitval[0]
59
+ status = exitval[1]
60
+ data_ary = @data_cache.delete(pid)
61
+
62
+ handle({
63
+ id: data_ary[0],
64
+ data: data_ary[1],
65
+ pid: pid,
66
+ status: status
67
+ }) if status_failed?(status)
68
+
69
+ start_new_child
78
70
  end
79
71
  end
80
72
  end
81
73
 
74
+ def while_child_exits
75
+ while exitval = Process.wait2(-1, Process::WNOHANG)
76
+ yield exitval
77
+ end
78
+ rescue Errno::ECHILD
79
+ # fine
80
+ end
81
+
82
+ def status_failed?(status)
83
+ !status.success? && !interrupted(status)
84
+ end
85
+
86
+ def start_new_child
87
+ @n += 1
88
+ if limit_reached?
89
+ run_instance(*@producer.next)
90
+ else
91
+ @running = false
92
+ end
93
+ end
94
+
95
+ def limit_reached?
96
+ @limit == -1 || @n < @limit
97
+ end
98
+
82
99
  def trap_interrupt
83
100
  trap(:INT) do
84
101
  exit! (1) if @exiting
@@ -65,13 +65,8 @@ class FuzzBert::RakeTask < ::Rake::TaskLib
65
65
  private
66
66
 
67
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(" ")
68
+ cmd = [RUBY, ruby_opts, '-S', fuzzbert_path, fuzzbert_opts, pattern]
69
+ cmd.flatten.reject(&blank).join(" ")
75
70
  end
76
71
 
77
72
  def blank
@@ -8,13 +8,13 @@ class FuzzBert::Template
8
8
  @callbacks = {}
9
9
  end
10
10
 
11
- def set(name, &blk)
12
- @callbacks[name] = blk
11
+ def set(name, cb=nil, &blk)
12
+ @callbacks[name] = cb || blk
13
13
  end
14
14
 
15
15
  def to_data
16
16
  "".tap do |buf|
17
- @template.each { |t| buf << t.to_data(@callbacks) }
17
+ @template.each { |t| buf << t.to_data(@callbacks).to_s }
18
18
  end
19
19
  end
20
20
 
data/spec/autorun_spec.rb CHANGED
@@ -49,5 +49,60 @@ describe FuzzBert::AutoRun do
49
49
  end
50
50
  end
51
51
 
52
+ describe "command line" do
53
+
54
+ def relative_path(filename)
55
+ File.expand_path(filename, File.dirname(File.expand_path(__FILE__)))
56
+ end
57
+
58
+ let (:fuzz_nothing) { relative_path('fuzz/fuzz_nothing.rb') }
59
+ let (:single_test_args) { ['--pool-size', '1', '--limit', '1', '--sleep-delay', '0.05'] }
60
+
61
+ it "accepts pool-size, limit and sleep-delay" do
62
+ args = single_test_args + [fuzz_nothing]
63
+ -> { FuzzBert::AutoRun.autorun_with_args(args) }.should_not raise_error
64
+ end
65
+
66
+ it "accepts console" do
67
+ args = single_test_args + ['--console', fuzz_nothing]
68
+ -> { FuzzBert::AutoRun.autorun_with_args(args) }.should_not raise_error
69
+ end
70
+
71
+ it "accepts bug-dir" do
72
+ args = single_test_args + ['--bug-dir', '.', fuzz_nothing]
73
+ -> { FuzzBert::AutoRun.autorun_with_args(args) }.should_not raise_error
74
+ end
75
+
76
+ it "accepts a custom handler" do
77
+ args = single_test_args + ['--handler', 'FuzzBert::Spec::CustomHandler', relative_path('fuzz/fuzz_custom_handler.rb')]
78
+ -> { FuzzBert::AutoRun.autorun_with_args(args) }.should_not raise_error
79
+ FuzzBert::Spec::CustomHandler.called.should be_true
80
+ end
81
+
82
+ it "accepts multiple single files" do
83
+ args = [
84
+ '--pool-size', '1',
85
+ '--limit', '2',
86
+ '--sleep-delay', '0.05',
87
+ '--handler', 'FuzzBert::Spec::CustomHandler',
88
+ fuzz_nothing, relative_path('fuzz/fuzz_custom_handler.rb')
89
+ ]
90
+ -> { FuzzBert::AutoRun.autorun_with_args(args) }.should_not raise_error
91
+ FuzzBert::Spec::CustomHandler.called.should be_true
92
+ end
93
+
94
+ it "accepts a pattern" do
95
+ args = [
96
+ '--pool-size', '1',
97
+ '--limit', '2',
98
+ '--sleep-delay', '0.05',
99
+ '--handler', 'FuzzBert::Spec::CustomHandler',
100
+ relative_path('fuzz/**/fuzz_*.rb')
101
+ ]
102
+ -> { FuzzBert::AutoRun.autorun_with_args(args) }.should_not raise_error
103
+ FuzzBert::Spec::CustomHandler.called.should be_true
104
+ end
105
+ end
106
+
52
107
  end
53
108
 
@@ -0,0 +1,20 @@
1
+ require 'fuzzbert'
2
+
3
+ module FuzzBert::Spec
4
+ class CustomHandler
5
+ @@called = false
6
+
7
+ def self.called
8
+ @@called
9
+ end
10
+
11
+ def handle(error_data)
12
+ @@called = true
13
+ end
14
+ end
15
+ end
16
+
17
+ fuzz "failing" do
18
+ deploy { |data| raise "boo!" }
19
+ data("some") { -> {"a"} }
20
+ end
@@ -0,0 +1,6 @@
1
+ require 'fuzzbert'
2
+
3
+ fuzz "nothing" do
4
+ deploy { |data| }
5
+ data("some") { -> {"a"} }
6
+ end
@@ -16,6 +16,13 @@ describe FuzzBert::Template do
16
16
  t.to_data.should == "abc"
17
17
  end
18
18
 
19
+ it "takes an optional proc to define the callback" do
20
+ t = FuzzBert::Template.new "a${var}c"
21
+ cb = -> { "b" }
22
+ t.set(:var, cb)
23
+ t.to_data.should == "abc"
24
+ end
25
+
19
26
  it "takes only Symbols to reference the template variables" do
20
27
  t = FuzzBert::Template.new "a${var}c"
21
28
  t.set("var") { "b" }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fuzzbert
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-17 00:00:00.000000000 Z
12
+ date: 2013-03-05 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A random testing / fuzzer framework for Ruby.
15
15
  email: Martin.Bosslet@gmail.com
@@ -19,30 +19,32 @@ extensions: []
19
19
  extra_rdoc_files:
20
20
  - README.md
21
21
  files:
22
- - lib/fuzzbert.rb
23
- - lib/fuzzbert/generators.rb
24
- - lib/fuzzbert/test_suite.rb
25
22
  - lib/fuzzbert/rake_task.rb
23
+ - lib/fuzzbert/generation.rb
26
24
  - lib/fuzzbert/generator.rb
27
- - lib/fuzzbert/error_handler.rb
28
- - lib/fuzzbert/version.rb
25
+ - lib/fuzzbert/test_suite.rb
29
26
  - lib/fuzzbert/autorun.rb
27
+ - lib/fuzzbert/template.rb
28
+ - lib/fuzzbert/generators.rb
30
29
  - lib/fuzzbert/test.rb
31
- - lib/fuzzbert/generation.rb
32
- - lib/fuzzbert/container.rb
30
+ - lib/fuzzbert/version.rb
31
+ - lib/fuzzbert/error_handler.rb
32
+ - lib/fuzzbert/mutator.rb
33
33
  - lib/fuzzbert/executor.rb
34
- - lib/fuzzbert/template.rb
35
34
  - lib/fuzzbert/dsl.rb
36
- - lib/fuzzbert/mutator.rb
35
+ - lib/fuzzbert/container.rb
36
+ - lib/fuzzbert.rb
37
37
  - LICENSE
38
38
  - README.md
39
+ - spec/template_spec.rb
40
+ - spec/dsl_spec.rb
39
41
  - spec/generator_spec.rb
40
- - spec/test_spec.rb
41
- - spec/executor_spec.rb
42
42
  - spec/mutator_spec.rb
43
+ - spec/executor_spec.rb
43
44
  - spec/autorun_spec.rb
44
- - spec/dsl_spec.rb
45
- - spec/template_spec.rb
45
+ - spec/fuzz/fuzz_custom_handler.rb
46
+ - spec/fuzz/fuzz_nothing.rb
47
+ - spec/test_spec.rb
46
48
  - bin/fuzzbert
47
49
  homepage: https://github.com/krypt/FuzzBert
48
50
  licenses:
@@ -65,15 +67,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
67
  version: '0'
66
68
  requirements: []
67
69
  rubyforge_project:
68
- rubygems_version: 1.8.24
70
+ rubygems_version: 1.8.23
69
71
  signing_key:
70
72
  specification_version: 3
71
73
  summary: Fuzz your applications and libraries with minimal effort.
72
74
  test_files:
75
+ - spec/template_spec.rb
76
+ - spec/dsl_spec.rb
73
77
  - spec/generator_spec.rb
74
- - spec/test_spec.rb
75
- - spec/executor_spec.rb
76
78
  - spec/mutator_spec.rb
79
+ - spec/executor_spec.rb
77
80
  - spec/autorun_spec.rb
78
- - spec/dsl_spec.rb
79
- - spec/template_spec.rb
81
+ - spec/fuzz/fuzz_custom_handler.rb
82
+ - spec/fuzz/fuzz_nothing.rb
83
+ - spec/test_spec.rb