fuzzbert 1.0.1 → 1.0.2

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/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