heckle 1.4.3 → 2.0.0.b1
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/.autotest +4 -2
- data/.gemtest +0 -0
- data/History.txt +16 -0
- data/Manifest.txt +9 -1
- data/README.txt +5 -4
- data/Rakefile +13 -13
- data/bin/heckle +5 -93
- data/lib/heckle.rb +122 -16
- data/lib/heckle_runner.rb +113 -0
- data/lib/minitest_heckler.rb +33 -0
- data/lib/test_unit_heckler.rb +0 -1
- data/test/fixtures/heckle_dummy.rb +200 -0
- data/test/fixtures/heckled.rb +4 -0
- data/test/fixtures/minitest_project/README.txt +57 -0
- data/test/fixtures/minitest_project/Rakefile +17 -0
- data/test/fixtures/minitest_project/lib/doubler.rb +9 -0
- data/test/fixtures/minitest_project/test/test_doubler_with_a_number.rb +12 -0
- data/test/fixtures/minitest_project/test/test_doubler_with_bad_input.rb +16 -0
- data/test/test_heckle.rb +634 -356
- data/test/test_heckle_runner.rb +54 -0
- metadata +117 -42
- metadata.gz.sig +0 -0
- data/sample/lib/heckled.rb +0 -80
data.tar.gz.sig
CHANGED
Binary file
|
data/.autotest
CHANGED
@@ -3,10 +3,12 @@
|
|
3
3
|
require 'autotest/restart'
|
4
4
|
|
5
5
|
Autotest.add_hook :initialize do |at|
|
6
|
+
at.libs << ":../../ParseTree/dev/lib"
|
7
|
+
at.libs << ":../../ParseTree/dev/test"
|
6
8
|
at.libs << ":../../RubyInline/dev/lib"
|
7
|
-
at.libs << ":../../
|
9
|
+
at.libs << ":../../ruby2ruby/1.3.1/lib"
|
10
|
+
at.libs << ":../../ZenTest/dev/lib"
|
8
11
|
at.libs << ":../../sexp_processor/dev/lib"
|
9
|
-
at.libs << ":../../ruby2ruby/dev/lib"
|
10
12
|
|
11
13
|
%w(Dasgn Iter Dasgncurr Cvasgn Boolean Call Callblock
|
12
14
|
ClassMethod Gasgn Iasgn If Lasgn Masgn Ranges Regexes
|
data/.gemtest
ADDED
File without changes
|
data/History.txt
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
=== 2.0.0.b1 / 2012-10-02
|
2
|
+
|
3
|
+
* 1 major enhancement:
|
4
|
+
|
5
|
+
* Hot damn! It works with ruby_parser!!! (phiggins)
|
6
|
+
|
7
|
+
* 1 minor enhancement:
|
8
|
+
|
9
|
+
* 1.9 support! (phiggins)
|
10
|
+
|
11
|
+
* 3 bug fixes:
|
12
|
+
|
13
|
+
* Fixed Ruby2Ruby usage (raggi)
|
14
|
+
* Fixed dependencies so heckle doesn't use ruby_parser 3 and friends.
|
15
|
+
* Fixed grammar in description. Reported by Jean Lange.
|
16
|
+
|
1
17
|
=== 1.4.3 / 2009-06-23
|
2
18
|
|
3
19
|
* 2 minor enhancements:
|
data/Manifest.txt
CHANGED
@@ -6,10 +6,18 @@ Rakefile
|
|
6
6
|
bin/heckle
|
7
7
|
lib/autotest/heckle.rb
|
8
8
|
lib/heckle.rb
|
9
|
+
lib/heckle_runner.rb
|
10
|
+
lib/minitest_heckler.rb
|
9
11
|
lib/test_unit_heckler.rb
|
10
12
|
sample/Rakefile
|
11
13
|
sample/changes.log
|
12
|
-
sample/lib/heckled.rb
|
13
14
|
sample/test/test_heckled.rb
|
15
|
+
test/fixtures/heckle_dummy.rb
|
14
16
|
test/fixtures/heckled.rb
|
17
|
+
test/fixtures/minitest_project/README.txt
|
18
|
+
test/fixtures/minitest_project/Rakefile
|
19
|
+
test/fixtures/minitest_project/lib/doubler.rb
|
20
|
+
test/fixtures/minitest_project/test/test_doubler_with_a_number.rb
|
21
|
+
test/fixtures/minitest_project/test/test_doubler_with_bad_input.rb
|
15
22
|
test/test_heckle.rb
|
23
|
+
test/test_heckle_runner.rb
|
data/README.txt
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
= heckle
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
home :: http://ruby.sadi.st/Heckle.html
|
4
|
+
repo :: https://github.com/seattlerb/heckle
|
5
|
+
rdoc :: http://seattlerb.rubyforge.org/heckle
|
5
6
|
|
6
7
|
== DESCRIPTION:
|
7
8
|
|
8
|
-
Heckle is unit test sadism(tm) at
|
9
|
+
Heckle is unit test sadism(tm) at its core. Heckle is a mutation tester. It modifies your code and runs your tests to make sure they fail. The idea is that if code can be changed and your tests don't notice, either that code isn't being covered or it doesn't do anything.
|
9
10
|
|
10
11
|
It's like hiring a white-hat hacker to try to break into your server and making sure you detect it. You learn the most by trying to break things and watching the outcome in an act of unit test sadism.
|
11
12
|
|
@@ -32,7 +33,7 @@ It's like hiring a white-hat hacker to try to break into your server and making
|
|
32
33
|
|
33
34
|
(The MIT License)
|
34
35
|
|
35
|
-
Copyright (c)
|
36
|
+
Copyright (c) Ryan Davis, seattle.rb, and Kevin Clark
|
36
37
|
|
37
38
|
Permission is hereby granted, free of charge, to any person obtaining
|
38
39
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
@@ -3,28 +3,28 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'hoe'
|
5
5
|
|
6
|
-
Hoe.add_include_dirs("../../
|
7
|
-
"../../
|
8
|
-
"../../RubyInline/dev/lib",
|
9
|
-
"../../ruby2ruby/dev/lib",
|
6
|
+
Hoe.add_include_dirs("../../RubyInline/dev/lib",
|
7
|
+
"../../ruby2ruby/1.3.1/lib",
|
10
8
|
"../../ZenTest/dev/lib",
|
11
9
|
"../../sexp_processor/dev/lib",
|
10
|
+
"../../ruby_parser/2.3.1/lib",
|
12
11
|
"lib")
|
13
12
|
|
14
13
|
Hoe.plugin :seattlerb
|
15
14
|
|
16
15
|
Hoe.spec 'heckle' do
|
17
|
-
developer 'Ryan Davis',
|
18
|
-
developer '
|
19
|
-
developer '
|
16
|
+
developer 'Ryan Davis', 'ryand-ruby@zenspider.com'
|
17
|
+
developer 'Pete Higgins', 'pete@peterhiggins.org'
|
18
|
+
# developer 'Eric Hodel', 'drbrain@segment7.net'
|
19
|
+
# developer 'Kevin Clark', 'kevin.clark@gmail.com'
|
20
20
|
|
21
|
-
|
21
|
+
clean_globs << File.expand_path("~/.ruby_inline")
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
dependency 'ruby_parser', '~> 2.3.1'
|
24
|
+
dependency 'ruby2ruby', '~> 1.3.0'
|
25
|
+
dependency 'ZenTest', '~> 4.7.0'
|
26
|
+
|
27
|
+
self.test_globs = ["test/test_*.rb"]
|
28
28
|
end
|
29
29
|
|
30
30
|
# vim: syntax=ruby
|
data/bin/heckle
CHANGED
@@ -1,96 +1,8 @@
|
|
1
|
-
#!/usr/
|
1
|
+
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
require 'optparse'
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
4
|
+
$LOAD_PATH << 'lib'
|
6
5
|
|
7
|
-
|
8
|
-
nodes = Heckle::MUTATABLE_NODES
|
9
|
-
|
10
|
-
opts = OptionParser.new do |opts|
|
11
|
-
opts.banner = "Usage: #{File.basename($0)} class_name [method_name]"
|
12
|
-
opts.on("-v", "--verbose", "Loudly explain heckle run") do |opt|
|
13
|
-
TestUnitHeckler.debug = true
|
14
|
-
end
|
15
|
-
|
16
|
-
opts.on("-V", "--version", "Prints Heckle's version number") do |opt|
|
17
|
-
puts "Heckle #{Heckle::VERSION}"
|
18
|
-
exit 0
|
19
|
-
end
|
20
|
-
|
21
|
-
opts.on("-t", "--tests TEST_PATTERN",
|
22
|
-
"Location of tests (glob)") do |pattern|
|
23
|
-
TestUnitHeckler.test_pattern = pattern
|
24
|
-
end
|
25
|
-
|
26
|
-
opts.on("-F", "--force", "Ignore initial test failures",
|
27
|
-
"Best used with --focus") do |opt|
|
28
|
-
force = true
|
29
|
-
end
|
30
|
-
|
31
|
-
opts.on( "--assignments", "Only mutate assignments") do |opt|
|
32
|
-
puts "!"*70
|
33
|
-
puts "!!! Heckling assignments only"
|
34
|
-
puts "!"*70
|
35
|
-
puts
|
36
|
-
|
37
|
-
nodes = Heckle::ASGN_NODES
|
38
|
-
end
|
39
|
-
|
40
|
-
opts.on("-b", "--branches", "Only mutate branches") do |opt|
|
41
|
-
puts "!"*70
|
42
|
-
puts "!!! Heckling branches only"
|
43
|
-
puts "!"*70
|
44
|
-
puts
|
45
|
-
|
46
|
-
nodes = Heckle::BRANCH_NODES
|
47
|
-
end
|
48
|
-
|
49
|
-
opts.on("-f", "--focus", "Apply the eye of sauron") do |opt|
|
50
|
-
puts "!"*70
|
51
|
-
puts "!!! Running in focused mode. FEEL THE EYE OF SAURON!!!"
|
52
|
-
puts "!"*70
|
53
|
-
puts
|
54
|
-
|
55
|
-
TestUnitHeckler.focus = true
|
56
|
-
end
|
57
|
-
|
58
|
-
opts.on("-T", "--timeout SECONDS", "The maximum time for a test run in seconds",
|
59
|
-
"Used to catch infinite loops") do |timeout|
|
60
|
-
Heckle.timeout = timeout.to_i
|
61
|
-
puts "Setting timeout at #{timeout} seconds."
|
62
|
-
end
|
63
|
-
|
64
|
-
opts.on("-n", "--nodes NODES", "Nodes to mutate",
|
65
|
-
"Possible values: #{Heckle::MUTATABLE_NODES.join(',')}") do |opt|
|
66
|
-
nodes = opt.split(',').collect {|n| n.to_sym }
|
67
|
-
puts "Mutating nodes: #{nodes.inspect}"
|
68
|
-
end
|
69
|
-
|
70
|
-
opts.on("-x", "--exclude-nodes NODES", "Nodes to exclude") do |opt|
|
71
|
-
exclusions = opt.split(',').collect {|n| n.to_sym }
|
72
|
-
nodes = nodes - exclusions
|
73
|
-
puts "Mutating without nodes: #{exclusions.inspect}"
|
74
|
-
end
|
75
|
-
|
76
|
-
opts.on("-h", "--help", "Show this message") do |opt|
|
77
|
-
puts opts
|
78
|
-
exit 0
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
looks_like_rails = test ?f, 'config/environment.rb'
|
83
|
-
TestUnitHeckler.test_pattern = "test/**/*.rb" if looks_like_rails
|
84
|
-
|
85
|
-
opts.parse!
|
86
|
-
|
87
|
-
impl = ARGV.shift
|
88
|
-
meth = ARGV.shift
|
89
|
-
|
90
|
-
unless impl then
|
91
|
-
puts opts
|
92
|
-
exit 1
|
93
|
-
end
|
94
|
-
|
95
|
-
exit TestUnitHeckler.validate(impl, meth, nodes, force)
|
6
|
+
require 'heckle_runner'
|
96
7
|
|
8
|
+
exit HeckleRunner.run
|
data/lib/heckle.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require '
|
2
|
+
require 'ruby_parser'
|
3
3
|
require 'sexp_processor'
|
4
4
|
require 'ruby2ruby'
|
5
5
|
require 'timeout'
|
@@ -11,6 +11,17 @@ class String # :nodoc:
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
class Sexp
|
15
|
+
# REFACTOR: move to sexp.rb
|
16
|
+
def each_sexp
|
17
|
+
self.each do |sexp|
|
18
|
+
next unless Sexp === sexp
|
19
|
+
|
20
|
+
yield sexp
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
14
25
|
##
|
15
26
|
# Test Unit Sadism
|
16
27
|
|
@@ -21,7 +32,7 @@ class Heckle < SexpProcessor
|
|
21
32
|
##
|
22
33
|
# The version of Heckle you are using.
|
23
34
|
|
24
|
-
VERSION = '
|
35
|
+
VERSION = '2.0.0.b1'
|
25
36
|
|
26
37
|
##
|
27
38
|
# Branch node types.
|
@@ -131,9 +142,11 @@ class Heckle < SexpProcessor
|
|
131
142
|
|
132
143
|
@mutated = false
|
133
144
|
|
145
|
+
@original_tree = rewrite find_scope_and_method
|
146
|
+
@current_tree = @original_tree.deep_clone
|
147
|
+
|
134
148
|
grab_mutatees
|
135
149
|
|
136
|
-
@original_tree = current_tree.deep_clone
|
137
150
|
@original_mutatees = mutatees.deep_clone
|
138
151
|
end
|
139
152
|
|
@@ -203,21 +216,23 @@ class Heckle < SexpProcessor
|
|
203
216
|
end
|
204
217
|
|
205
218
|
def heckle(exp)
|
206
|
-
|
219
|
+
@current_tree = exp.deep_clone
|
207
220
|
src = begin
|
208
221
|
Ruby2Ruby.new.process(exp)
|
209
222
|
rescue => e
|
210
|
-
puts "Error: #{e.message} with: #{klass_name}##{method_name}: #{
|
223
|
+
puts "Error: #{e.message} with: #{klass_name}##{method_name}: #{@current_tree.inspect}"
|
211
224
|
raise e
|
212
225
|
end
|
213
226
|
|
214
|
-
|
215
|
-
|
227
|
+
if @@debug
|
228
|
+
original = Ruby2Ruby.new.process(@original_tree.deep_clone)
|
229
|
+
@reporter.replacing(klass_name, method_name, original, src)
|
230
|
+
end
|
216
231
|
|
217
|
-
clean_name = method_name.to_s.gsub(/self\./, '')
|
218
232
|
self.count += 1
|
219
|
-
new_name = "h#{count}_#{clean_name}"
|
220
233
|
|
234
|
+
clean_name = method_name.to_s.gsub(/self\./, '')
|
235
|
+
new_name = "h#{count}_#{clean_name}"
|
221
236
|
klass = aliasing_class method_name
|
222
237
|
klass.send :remove_method, new_name rescue nil
|
223
238
|
klass.send :alias_method, new_name, clean_name
|
@@ -499,13 +514,102 @@ class Heckle < SexpProcessor
|
|
499
514
|
end
|
500
515
|
|
501
516
|
def current_tree
|
502
|
-
|
517
|
+
@current_tree.deep_clone
|
518
|
+
end
|
519
|
+
|
520
|
+
# Copied from Flay#process
|
521
|
+
def find_scope_and_method
|
522
|
+
expand_dirs_to_files.each do |file|
|
523
|
+
#warn "Processing #{file}" if option[:verbose]
|
503
524
|
|
504
|
-
|
505
|
-
|
506
|
-
|
525
|
+
ext = File.extname(file).sub(/^\./, '')
|
526
|
+
ext = "rb" if ext.nil? || ext.empty?
|
527
|
+
msg = "process_#{ext}"
|
507
528
|
|
508
|
-
|
529
|
+
unless respond_to? msg then
|
530
|
+
warn " Unknown file type: #{ext}, defaulting to ruby"
|
531
|
+
msg = "process_rb"
|
532
|
+
end
|
533
|
+
|
534
|
+
begin
|
535
|
+
sexp = begin
|
536
|
+
send msg, file
|
537
|
+
rescue => e
|
538
|
+
warn " #{e.message.strip}"
|
539
|
+
warn " skipping #{file}"
|
540
|
+
nil
|
541
|
+
end
|
542
|
+
|
543
|
+
next unless sexp
|
544
|
+
|
545
|
+
found = find_scope sexp
|
546
|
+
|
547
|
+
return found if found
|
548
|
+
rescue SyntaxError => e
|
549
|
+
warn " skipping #{file}: #{e.message}"
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
raise "Couldn't find method."
|
554
|
+
end
|
555
|
+
|
556
|
+
def process_rb file
|
557
|
+
RubyParser.new.process(File.read(file), file)
|
558
|
+
end
|
559
|
+
|
560
|
+
def find_scope sexp, nesting=nil
|
561
|
+
nesting ||= klass_name.split("::").map {|k| k.to_sym }
|
562
|
+
current, *nesting = nesting
|
563
|
+
|
564
|
+
sexp = s(:block, sexp) unless sexp.first == :block
|
565
|
+
|
566
|
+
sexp.each_sexp do |node|
|
567
|
+
next unless [:class, :module].include? node.first
|
568
|
+
next unless node[1] == current
|
569
|
+
|
570
|
+
block = node.detect {|s| Sexp === s && s[0] == :scope }[1]
|
571
|
+
|
572
|
+
if nesting.empty?
|
573
|
+
return sexp if method_name.nil?
|
574
|
+
|
575
|
+
m = find_method block
|
576
|
+
|
577
|
+
return m if m
|
578
|
+
else
|
579
|
+
s = find_scope block, nesting
|
580
|
+
|
581
|
+
return s if s
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
nil
|
586
|
+
end
|
587
|
+
|
588
|
+
def find_method sexp
|
589
|
+
class_method = method_name.to_s =~ /^self\./
|
590
|
+
clean_name = method_name.to_s.sub(/^self\./, '').to_sym
|
591
|
+
|
592
|
+
sexp = s(:block, sexp) unless sexp.first == :block
|
593
|
+
|
594
|
+
sexp.each_sexp do |node|
|
595
|
+
if class_method
|
596
|
+
return node if node[0] == :defs && node[2] == clean_name
|
597
|
+
else
|
598
|
+
return node if node[0] == :defn && node[1] == clean_name
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
nil
|
603
|
+
end
|
604
|
+
|
605
|
+
def expand_dirs_to_files(dirs='.')
|
606
|
+
Array(dirs).flatten.map { |p|
|
607
|
+
if File.directory? p then
|
608
|
+
Dir[File.join(p, '**', "*.rb")]
|
609
|
+
else
|
610
|
+
p
|
611
|
+
end
|
612
|
+
}.flatten
|
509
613
|
end
|
510
614
|
|
511
615
|
def reset
|
@@ -518,6 +622,8 @@ class Heckle < SexpProcessor
|
|
518
622
|
return unless original_tree != current_tree
|
519
623
|
@mutated = false
|
520
624
|
|
625
|
+
@current_tree = original_tree.deep_clone
|
626
|
+
|
521
627
|
self.count += 1
|
522
628
|
|
523
629
|
clean_name = method_name.to_s.gsub(/self\./, '')
|
@@ -600,7 +706,7 @@ class Heckle < SexpProcessor
|
|
600
706
|
end
|
601
707
|
|
602
708
|
def current_code
|
603
|
-
Ruby2Ruby.
|
709
|
+
Ruby2Ruby.new.process current_tree
|
604
710
|
end
|
605
711
|
|
606
712
|
##
|
@@ -744,7 +850,7 @@ class Heckle < SexpProcessor
|
|
744
850
|
# All nodes that can be mutated by Heckle.
|
745
851
|
|
746
852
|
MUTATABLE_NODES = instance_methods.grep(/mutate_/).sort.map do |meth|
|
747
|
-
meth.sub(/mutate_/, '').intern
|
853
|
+
meth.to_s.sub(/mutate_/, '').intern
|
748
854
|
end - [:asgn, :node] # Ignore these methods
|
749
855
|
|
750
856
|
##
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'heckle'
|
3
|
+
require 'minitest_heckler'
|
4
|
+
|
5
|
+
class HeckleRunner
|
6
|
+
def self.run argv=ARGV
|
7
|
+
options = parse_args argv
|
8
|
+
|
9
|
+
class_or_module, method = argv.shift, argv.shift
|
10
|
+
|
11
|
+
new(class_or_module, method, options).run
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.parse_args argv
|
15
|
+
options = {
|
16
|
+
:force => false,
|
17
|
+
:nodes => Heckle::MUTATABLE_NODES,
|
18
|
+
:debug => false,
|
19
|
+
:focus => false,
|
20
|
+
:timeout => 5,
|
21
|
+
:test_pattern => 'test/test_*.rb',
|
22
|
+
}
|
23
|
+
|
24
|
+
OptionParser.new do |opts|
|
25
|
+
opts.version = Heckle::VERSION
|
26
|
+
opts.program_name = File.basename $0
|
27
|
+
opts.banner = "Usage: #{opts.program_name} class_name [method_name]"
|
28
|
+
opts.on("-v", "--verbose", "Loudly explain heckle run") do
|
29
|
+
options[:debug] = true
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on("-t", "--tests TEST_PATTERN",
|
33
|
+
"Location of tests (glob)") do |pattern|
|
34
|
+
options[:test_pattern] = pattern
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on("-F", "--force", "Ignore initial test failures",
|
38
|
+
"Best used with --focus") do
|
39
|
+
options[:force] = true
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.on( "--assignments", "Only mutate assignments") do
|
43
|
+
puts "!"*70
|
44
|
+
puts "!!! Heckling assignments only"
|
45
|
+
puts "!"*70
|
46
|
+
puts
|
47
|
+
|
48
|
+
options[:nodes] = Heckle::ASGN_NODES
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on("-b", "--branches", "Only mutate branches") do
|
52
|
+
puts "!"*70
|
53
|
+
puts "!!! Heckling branches only"
|
54
|
+
puts "!"*70
|
55
|
+
puts
|
56
|
+
|
57
|
+
options[:nodes] = Heckle::BRANCH_NODES
|
58
|
+
end
|
59
|
+
|
60
|
+
opts.on("-f", "--focus", "Apply the eye of sauron") do
|
61
|
+
puts "!"*70
|
62
|
+
puts "!!! Running in focused mode. FEEL THE EYE OF SAURON!!!"
|
63
|
+
puts "!"*70
|
64
|
+
puts
|
65
|
+
|
66
|
+
options[:focus] = true
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.on("-T", "--timeout SECONDS", "The maximum time for a test run in seconds",
|
70
|
+
"Used to catch infinite loops") do |timeout|
|
71
|
+
timeout = timeout.to_i
|
72
|
+
puts "Setting timeout at #{timeout} seconds."
|
73
|
+
options[:timeout] = timeout
|
74
|
+
end
|
75
|
+
|
76
|
+
opts.on("-n", "--nodes NODES", "Nodes to mutate",
|
77
|
+
"Possible values: #{Heckle::MUTATABLE_NODES.join(',')}") do |opt|
|
78
|
+
nodes = opt.split(',').collect {|n| n.to_sym }
|
79
|
+
options[:nodes] = nodes
|
80
|
+
puts "Mutating nodes: #{nodes.inspect}"
|
81
|
+
end
|
82
|
+
|
83
|
+
opts.on("-x", "--exclude-nodes NODES", "Nodes to exclude") do |opt|
|
84
|
+
exclusions = opt.split(',').collect {|n| n.to_sym }
|
85
|
+
options[:nodes] = options[:nodes] - exclusions
|
86
|
+
puts "Mutating without nodes: #{exclusions.inspect}"
|
87
|
+
end
|
88
|
+
end.parse! argv
|
89
|
+
|
90
|
+
p options if options[:debug]
|
91
|
+
|
92
|
+
# TODO: Pass options to Heckle's initializer instead.
|
93
|
+
Heckle.debug = options[:debug]
|
94
|
+
Heckle.timeout = options[:timeout]
|
95
|
+
|
96
|
+
options
|
97
|
+
end
|
98
|
+
|
99
|
+
# TODO: this sucks
|
100
|
+
def heckler
|
101
|
+
MiniTestHeckler
|
102
|
+
end
|
103
|
+
|
104
|
+
def initialize class_or_module, method, options={}
|
105
|
+
@class_or_module = class_or_module
|
106
|
+
@method = method
|
107
|
+
@options = options
|
108
|
+
end
|
109
|
+
|
110
|
+
def run
|
111
|
+
heckler.new(@class_or_module, @method, @options).validate
|
112
|
+
end
|
113
|
+
end
|