Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

! Hot damn! It works with ruby_parser!!! (phiggins)

[git-p4: depot-paths = "//src/heckle/dev/": change = 7807]
  • Loading branch information...
commit 5d88142ed589e9ba8006d225b4975f188ab8d1a1 1 parent 1c50905
@zenspider zenspider authored
View
6 Rakefile
@@ -12,8 +12,6 @@ Hoe.add_include_dirs("../../ParseTree/dev/lib",
"../../ruby_parser/2.3.1/lib",
"lib")
-Hoe.plugin :seattlerb
-
Hoe.spec 'heckle' do
developer 'Ryan Davis', 'ryand-ruby@zenspider.com'
developer 'Eric Hodel', 'drbrain@segment7.net'
@@ -28,6 +26,10 @@ Hoe.spec 'heckle' do
dependency 'ZenTest', '~> 4.7.0'
multiruby_skip << "1.9" << "trunk"
+
+ self.test_globs = ["test/test_*.rb"]
+
+ self.testlib = :minitest
end
# vim: syntax=ruby
View
98 bin/heckle
@@ -1,96 +1,8 @@
-#!/usr/local/bin/ruby
+#!/usr/bin/env ruby
-$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
-require 'test_unit_heckler'
-require 'optparse'
+$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
+$LOAD_PATH << 'lib'
-force = false
-nodes = Heckle::MUTATABLE_NODES
-
-opts = OptionParser.new do |opts|
- opts.banner = "Usage: #{File.basename($0)} class_name [method_name]"
- opts.on("-v", "--verbose", "Loudly explain heckle run") do |opt|
- TestUnitHeckler.debug = true
- end
-
- opts.on("-V", "--version", "Prints Heckle's version number") do |opt|
- puts "Heckle #{Heckle::VERSION}"
- exit 0
- end
-
- opts.on("-t", "--tests TEST_PATTERN",
- "Location of tests (glob)") do |pattern|
- TestUnitHeckler.test_pattern = pattern
- end
-
- opts.on("-F", "--force", "Ignore initial test failures",
- "Best used with --focus") do |opt|
- force = true
- end
-
- opts.on( "--assignments", "Only mutate assignments") do |opt|
- puts "!"*70
- puts "!!! Heckling assignments only"
- puts "!"*70
- puts
-
- nodes = Heckle::ASGN_NODES
- end
-
- opts.on("-b", "--branches", "Only mutate branches") do |opt|
- puts "!"*70
- puts "!!! Heckling branches only"
- puts "!"*70
- puts
-
- nodes = Heckle::BRANCH_NODES
- end
-
- opts.on("-f", "--focus", "Apply the eye of sauron") do |opt|
- puts "!"*70
- puts "!!! Running in focused mode. FEEL THE EYE OF SAURON!!!"
- puts "!"*70
- puts
-
- TestUnitHeckler.focus = true
- end
-
- opts.on("-T", "--timeout SECONDS", "The maximum time for a test run in seconds",
- "Used to catch infinite loops") do |timeout|
- Heckle.timeout = timeout.to_i
- puts "Setting timeout at #{timeout} seconds."
- end
-
- opts.on("-n", "--nodes NODES", "Nodes to mutate",
- "Possible values: #{Heckle::MUTATABLE_NODES.join(',')}") do |opt|
- nodes = opt.split(',').collect {|n| n.to_sym }
- puts "Mutating nodes: #{nodes.inspect}"
- end
-
- opts.on("-x", "--exclude-nodes NODES", "Nodes to exclude") do |opt|
- exclusions = opt.split(',').collect {|n| n.to_sym }
- nodes = nodes - exclusions
- puts "Mutating without nodes: #{exclusions.inspect}"
- end
-
- opts.on("-h", "--help", "Show this message") do |opt|
- puts opts
- exit 0
- end
-end
-
-looks_like_rails = test ?f, 'config/environment.rb'
-TestUnitHeckler.test_pattern = "test/**/*.rb" if looks_like_rails
-
-opts.parse!
-
-impl = ARGV.shift
-meth = ARGV.shift
-
-unless impl then
- puts opts
- exit 1
-end
-
-exit TestUnitHeckler.validate(impl, meth, nodes, force)
+require 'heckle_runner'
+exit HeckleRunner.run
View
70 lib/heckle.rb
@@ -13,14 +13,6 @@ def to_class
class Sexp
# REFACTOR: move to sexp.rb
- def deep_each(&block)
- self.each_sexp do |sexp|
- block[sexp]
- sexp.deep_each(&block)
- end
- end
-
- # REFACTOR: move to sexp.rb
def each_sexp
self.each do |sexp|
next unless Sexp === sexp
@@ -150,7 +142,7 @@ def initialize(klass_name = nil, method_name = nil,
@mutated = false
- @original_tree = rewrite find_class_and_method
+ @original_tree = rewrite find_scope_and_method
@current_tree = @original_tree.deep_clone
grab_mutatees
@@ -526,8 +518,8 @@ def current_tree
end
# Copied from Flay#process
- def find_class_and_method
- expand_dirs_to_files('.').each do |file|
+ def find_scope_and_method
+ expand_dirs_to_files.each do |file|
#warn "Processing #{file}" if option[:verbose]
ext = File.extname(file).sub(/^\./, '')
@@ -550,7 +542,7 @@ def find_class_and_method
next unless sexp
- found = process_sexp sexp
+ found = find_scope sexp
return found if found
rescue SyntaxError => e
@@ -565,31 +557,55 @@ def process_rb file
RubyParser.new.process(File.read(file), file)
end
- def process_sexp pt
+ def find_scope sexp, nesting=nil
+ nesting ||= klass_name.split("::").map {|k| k.to_sym }
+ current, *nesting = nesting
+
+ sexp = s(:block, sexp) unless sexp.first == :block
+
+ sexp.each_sexp do |node|
+ next unless [:class, :module].include? node.first
+ next unless node[1] == current
+
+ block = node.detect {|s| Sexp === s && s[0] == :scope }[1]
+
+ if nesting.empty?
+ return sexp if method_name.nil?
+
+ m = find_method block
+
+ return m if m
+ else
+ s = find_scope block, nesting
+
+ return s if s
+ end
+ end
+
+ nil
+ end
+
+ def find_method sexp
class_method = method_name.to_s =~ /^self\./
clean_name = method_name.to_s.sub(/^self\./, '').to_sym
- if pt[0] == :class && pt[1] == klass_name.to_sym
- return pt if method_name.nil?
+ sexp = s(:block, sexp) unless sexp.first == :block
- pt.deep_each do |node|
- if class_method
- return node if node[0] == :defs && node[2] == clean_name
- else
- return node if node[0] == :defn && node[1] == clean_name
- end
+ sexp.each_sexp do |node|
+ if class_method
+ return node if node[0] == :defs && node[2] == clean_name
+ else
+ return node if node[0] == :defn && node[1] == clean_name
end
end
nil
end
- def expand_dirs_to_files *dirs
- extensions = ['rb'] # + Flay.load_plugins
-
- dirs.flatten.map { |p|
+ def expand_dirs_to_files(dirs='.')
+ Array(dirs).flatten.map { |p|
if File.directory? p then
- Dir[File.join(p, '**', "*.{#{extensions.join(',')}}")]
+ Dir[File.join(p, '**', "*.rb")]
else
p
end
@@ -690,7 +706,7 @@ def mutations_left
end
def current_code
- Ruby2Ruby.new.process ParseTree.translate(klass_name.to_class, method_name)
+ Ruby2Ruby.new.process current_tree
end
##
View
113 lib/heckle_runner.rb
@@ -0,0 +1,113 @@
+require 'optparse'
+require 'heckle'
+require 'minitest_heckler'
+
+class HeckleRunner
+ def self.run argv=ARGV
+ options = parse_args argv
+
+ class_or_module, method = argv.shift, argv.shift
+
+ new(class_or_module, method, options).run
+ end
+
+ def self.parse_args argv
+ options = {
+ :force => false,
+ :nodes => Heckle::MUTATABLE_NODES,
+ :debug => false,
+ :focus => false,
+ :timeout => 5,
+ :test_pattern => 'test/test_*.rb',
+ }
+
+ OptionParser.new do |opts|
+ opts.version = Heckle::VERSION
+ opts.program_name = File.basename $0
+ opts.banner = "Usage: #{opts.program_name} class_name [method_name]"
+ opts.on("-v", "--verbose", "Loudly explain heckle run") do
+ options[:debug] = true
+ end
+
+ opts.on("-t", "--tests TEST_PATTERN",
+ "Location of tests (glob)") do |pattern|
+ options[:test_pattern] = pattern
+ end
+
+ opts.on("-F", "--force", "Ignore initial test failures",
+ "Best used with --focus") do
+ options[:force] = true
+ end
+
+ opts.on( "--assignments", "Only mutate assignments") do
+ puts "!"*70
+ puts "!!! Heckling assignments only"
+ puts "!"*70
+ puts
+
+ options[:nodes] = Heckle::ASGN_NODES
+ end
+
+ opts.on("-b", "--branches", "Only mutate branches") do
+ puts "!"*70
+ puts "!!! Heckling branches only"
+ puts "!"*70
+ puts
+
+ options[:nodes] = Heckle::BRANCH_NODES
+ end
+
+ opts.on("-f", "--focus", "Apply the eye of sauron") do
+ puts "!"*70
+ puts "!!! Running in focused mode. FEEL THE EYE OF SAURON!!!"
+ puts "!"*70
+ puts
+
+ options[:focus] = true
+ end
+
+ opts.on("-T", "--timeout SECONDS", "The maximum time for a test run in seconds",
+ "Used to catch infinite loops") do |timeout|
+ timeout = timeout.to_i
+ puts "Setting timeout at #{timeout} seconds."
+ options[:timeout] = timeout
+ end
+
+ opts.on("-n", "--nodes NODES", "Nodes to mutate",
+ "Possible values: #{Heckle::MUTATABLE_NODES.join(',')}") do |opt|
+ nodes = opt.split(',').collect {|n| n.to_sym }
+ options[:nodes] = nodes
+ puts "Mutating nodes: #{nodes.inspect}"
+ end
+
+ opts.on("-x", "--exclude-nodes NODES", "Nodes to exclude") do |opt|
+ exclusions = opt.split(',').collect {|n| n.to_sym }
+ options[:nodes] = options[:nodes] - exclusions
+ puts "Mutating without nodes: #{exclusions.inspect}"
+ end
+ end.parse! argv
+
+ p options if options[:debug]
+
+ # TODO: Pass options to Heckle's initializer instead.
+ Heckle.debug = options[:debug]
+ Heckle.timeout = options[:timeout]
+
+ options
+ end
+
+ # TODO: this sucks
+ def heckler
+ MiniTestHeckler
+ end
+
+ def initialize class_or_module, method, options={}
+ @class_or_module = class_or_module
+ @method = method
+ @options = options
+ end
+
+ def run
+ heckler.new(@class_or_module, @method, @options).validate
+ end
+end
View
33 lib/minitest_heckler.rb
@@ -0,0 +1,33 @@
+class MiniTestHeckler < Heckle
+ def initialize(class_or_module, method, options)
+ Dir.glob(options[:test_pattern]).each {|t| load File.expand_path(t) }
+
+ super(class_or_module, method, options[:nodes])
+ end
+
+ def tests_pass?
+ silence do
+ MiniTest::Unit.runner = nil
+
+ MiniTest::Unit.new.run
+
+ runner = MiniTest::Unit.runner
+
+ runner.failures == 0 && runner.errors == 0
+ end
+ end
+
+ # TODO: Windows.
+ def silence
+ return yield if Heckle.debug
+
+ begin
+ original = MiniTest::Unit.output
+ MiniTest::Unit.output = File.open("/dev/null", "w")
+
+ yield
+ ensure
+ MiniTest::Unit.output = original
+ end
+ end
+end
View
200 test/fixtures/heckle_dummy.rb
@@ -0,0 +1,200 @@
+class HeckleDummy
+ attr_accessor :names
+
+ def initialize
+ @names = []
+ end
+
+ def uses_call
+ some_func + some_other_func
+ end
+
+ def uses_callblock
+ x.y { 1 }
+ end
+
+ def uses_cvasgn
+ @@cvar = 5
+ @@cvar = nil
+ end
+
+ def uses_dasgn
+ loop do |dvar|
+ loop do
+ dvar = 5
+ dvar = nil
+ end
+ end
+ end
+
+ def uses_dasgncurr
+ loop do |dvar|
+ dvar = 5
+ dvar = nil
+ end
+ end
+
+ def uses_iasgn
+ @ivar = 5
+ @ivar = nil
+ end
+
+ def uses_gasgn
+ $gvar = 5
+ $gvar = nil
+ end
+
+ def uses_lasgn
+ lvar = 5
+ lvar = nil
+ end
+
+ def uses_masgn
+ @a, $b, c = 5, 6, 7
+ end
+
+ def uses_many_things
+ i = 1
+ while i < 10
+ i += 1
+ until some_func
+ some_other_func
+ end
+ return true if "hi there" == "changeling"
+ return false
+ end
+ i
+ end
+
+ def uses_while
+ while some_func
+ some_other_func
+ end
+ end
+
+ def uses_until
+ until some_func
+ some_other_func
+ end
+ end
+
+ def uses_numeric_literals
+ i = 1
+ i += 2147483648
+ i -= 3.5
+ end
+
+ def uses_strings
+ @names << "Hello, Robert"
+ @names << "Hello, Jeff"
+ @names << "Hi, Frank"
+ end
+
+ def uses_different_types
+ i = 1
+ b = "Hello, Joe"
+ c = 3.3
+ end
+
+ def uses_literal
+ i = 1
+ end
+
+ def uses_same_literal
+ i = 1
+ i = 1
+ i = 1
+ end
+
+ def uses_if
+ if some_func
+ if some_other_func
+ return
+ end
+ end
+ end
+
+ def uses_boolean
+ a = true
+ b = false
+ end
+
+ def uses_unless
+ unless true
+ if false
+ return
+ end
+ end
+ end
+
+ def uses_symbols
+ i = :blah
+ i = :blah
+ i = :and_blah
+ end
+
+ def uses_regexes
+ i = /a.*/
+ i = /c{2,4}+/
+ i = /123/
+ end
+
+ def uses_ranges
+ i = 6..100
+ i = -1..9
+ i = 1..4
+ end
+
+ def uses_nothing
+ end
+
+ def uses_iter
+ x = [ 1, 2, 3 ]
+ x.each { |y| y }
+ end
+
+ def self.is_a_klass_method?
+ true
+ end
+
+ module OuterNesting
+ def foo
+ -1
+ end
+
+ module InnerNesting
+ def foo
+ -2
+ end
+
+ class InnerClass
+ def bar
+ -1
+ end
+ end
+ end
+
+ module InnerNesting
+ def foo
+ -3
+ end
+
+ class InnerClass
+ module DecoyNesting
+ def foo
+ -4
+ end
+ end
+
+ def foo
+ 1337
+ end
+ end
+ end
+ end
+
+ private
+
+ def some_func; end
+ def some_other_func; end
+end
View
57 test/fixtures/minitest_project/README.txt
@@ -0,0 +1,57 @@
+= minitest_project
+
+* FIX (url)
+
+== DESCRIPTION:
+
+FIX (describe your package)
+
+== FEATURES/PROBLEMS:
+
+* FIX (list of features or problems)
+
+== SYNOPSIS:
+
+ FIX (code sample of usage)
+
+== REQUIREMENTS:
+
+* FIX (list of requirements)
+
+== INSTALL:
+
+* FIX (sudo gem install, anything else)
+
+== DEVELOPERS:
+
+After checking out the source, run:
+
+ $ rake newb
+
+This task will install any missing dependencies, run the tests/specs,
+and generate the RDoc.
+
+== LICENSE:
+
+(The MIT License)
+
+Copyright (c) 2012 FIX
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
17 test/fixtures/minitest_project/Rakefile
@@ -0,0 +1,17 @@
+require 'rake/testtask'
+
+Rake::TestTask.new
+
+namespace :heckle do
+ desc "Run heckle with all tests."
+ task :pass do
+ puts `../../../bin/heckle Doubler double`
+ end
+
+ desc "Run heckle with some test."
+ task :fail do
+ puts `../../../bin/heckle Doubler double --tests test/test_doubler_with_a_number.rb`
+ end
+end
+
+task :default => :test
View
9 test/fixtures/minitest_project/lib/doubler.rb
@@ -0,0 +1,9 @@
+class Doubler
+ def double x
+ if Numeric === x
+ x * 2
+ else
+ "NaN"
+ end
+ end
+end
View
12 test/fixtures/minitest_project/test/test_doubler_with_a_number.rb
@@ -0,0 +1,12 @@
+require "minitest/autorun"
+require "doubler"
+
+class TestDoublerWithANumber < MiniTest::Unit::TestCase
+ def setup
+ @doubler = Doubler.new
+ end
+
+ def test_double_with_a_number
+ assert_equal 4, @doubler.double(2)
+ end
+end
View
16 test/fixtures/minitest_project/test/test_doubler_with_bad_input.rb
@@ -0,0 +1,16 @@
+require "minitest/autorun"
+require "doubler"
+
+class TestDoublerWithBadInput < MiniTest::Unit::TestCase
+ def setup
+ @doubler = Doubler.new
+ end
+
+ def test_doubler_with_a_string
+ assert_equal "NaN", @doubler.double("2")
+ end
+
+ def test_doubler_with_nil
+ assert_equal "NaN", @doubler.double(nil)
+ end
+end
View
984 test/test_heckle.rb
@@ -1,5 +1,5 @@
-require 'test_unit_heckler'
-require 'fixtures/heckled'
+require 'fixtures/heckle_dummy'
+require 'heckle'
class TestHeckler < Heckle
def rand(*args)
@@ -17,55 +17,44 @@ def rand_number(*args)
def rand_symbol
:"l33t h4x0r"
end
+
+ # HAX
+ def expand_dirs_to_files(*)
+ super('test/fixtures/heckle_dummy.rb')
+ end
end
class HeckleTestCase < MiniTest::Unit::TestCase
def setup
+ @klass ||= "HeckleDummy"
@nodes ||= Heckle::MUTATABLE_NODES
- unless defined? @hecklee then
- data = self.class.name.sub(/HeckleTestCase/, '').sub(/TestHeckle/, '')
- data = data.gsub(/([A-Z])/, '_\1').downcase
- data = "_many_things" if data.empty?
- @hecklee = "uses#{data}"
- end
+ @method_heckled ||= 'uses_many_things'
- @heckler = TestHeckler.new("Heckled", @hecklee, @nodes)
+ @heckler = TestHeckler.new(@klass, @method_heckled, @nodes)
end
def teardown
@heckler.reset if defined?(@heckler) && @heckler
end
-end
-
-class LiteralHeckleTestCase < HeckleTestCase
- def setup
- @nodes = s(:lit, :str)
- super
- end
- def toggle(value, toggle)
- toggle ? self.class::TOGGLE_VALUE : value
- end
-
- def test_default_structure
- return if self.class == LiteralHeckleTestCase
- assert_equal util_expected, @heckler.current_tree
- end
-
- def test_should_iterate_mutations
- return if self.class == LiteralHeckleTestCase
- @heckler.process(@heckler.current_tree)
- assert_equal util_expected(1), @heckler.current_tree
-
- @heckler.reset_tree
+ def assert_mutations expected, heckle
+ initial = heckle.current_tree.deep_clone
+ mutations = []
- @heckler.process(@heckler.current_tree)
- assert_equal util_expected(2), @heckler.current_tree
+ begin
+ heckle.process(heckle.current_tree)
+ mutant = heckle.current_tree
+ mutations << mutant
+ heckle.reset_tree
+ end until initial == mutant
- @heckler.reset_tree
+ mutations.delete(initial)
- @heckler.process(@heckler.current_tree)
- assert_equal util_expected(3), @heckler.current_tree
+ # HAX: Sorting an array of Sexps blows up in some cases.
+ assert_equal expected.map {|sexp| sexp.to_s }.sort,
+ mutations.map {|sexp| sexp.to_s }.sort,
+ [ "expected(#{expected.size}):", (expected - mutations).map {|m| m.pretty_inspect},
+ "mutations(#{mutations.size}):", (mutations - expected).map {|m| m.pretty_inspect} ].join("\n")
end
end
@@ -202,99 +191,306 @@ def test_reset_mutatees
end
class TestHeckleNumericLiterals < HeckleTestCase
- def toggle(value, toggle)
- value + (toggle ? 5 : 0)
+ def setup
+ @method_heckled = "uses_numeric_literals"
+ @nodes = s(:lit, :str)
+ super
end
- def util_expected(n)
- s(:defn, :uses_numeric_literals,
+ def test_numeric_literals_original_tree
+ expected = s(:defn, :uses_numeric_literals,
s(:args),
s(:scope,
s(:block,
- s(:lasgn, :i, s(:lit, toggle(1, 1 == n))),
+ s(:lasgn, :i, s(:lit, 1)),
s(:lasgn, :i, s(:call, s(:lvar, :i), :+,
- s(:arglist, s(:lit, toggle(2147483648, 2 == n))))),
- s(:lasgn, :i, s(:call, s(:lvar, :i), :-, s(:arglist, s(:lit, toggle(3.5, 3 == n))))))))
+ s(:arglist, s(:lit, 2147483648)))),
+ s(:lasgn, :i, s(:call, s(:lvar, :i), :-, s(:arglist, s(:lit, 3.5)))))))
+
+ assert_equal expected, @heckler.current_tree
+ end
+
+ def test_numeric_literals_mutations
+ expected = [
+ s(:defn, :uses_numeric_literals,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, 6)),
+ s(:lasgn, :i, s(:call, s(:lvar, :i), :+,
+ s(:arglist, s(:lit, 2147483648)))),
+ s(:lasgn, :i, s(:call, s(:lvar, :i), :-, s(:arglist, s(:lit, 3.5))))))),
+ s(:defn, :uses_numeric_literals,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, 1)),
+ s(:lasgn, :i, s(:call, s(:lvar, :i), :+,
+ s(:arglist, s(:lit, 2147483653)))),
+ s(:lasgn, :i, s(:call, s(:lvar, :i), :-, s(:arglist, s(:lit, 3.5))))))),
+ s(:defn, :uses_numeric_literals,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, 1)),
+ s(:lasgn, :i, s(:call, s(:lvar, :i), :+,
+ s(:arglist, s(:lit, 2147483648)))),
+ s(:lasgn, :i, s(:call, s(:lvar, :i), :-, s(:arglist, s(:lit, 8.5))))))),
+ ]
+
+ assert_mutations expected, @heckler
end
end
-class TestHeckleSymbols < LiteralHeckleTestCase
- TOGGLE_VALUE = :"l33t h4x0r"
+class TestHeckleSymbols < HeckleTestCase
+ def setup
+ @method_heckled = "uses_symbols"
+ @nodes = s(:lit, :str)
+ super
+ end
- def util_expected(n = nil)
- s(:defn, :uses_symbols,
+ def test_symbols_original_tree
+ expected = s(:defn, :uses_symbols,
s(:args),
s(:scope,
s(:block,
- s(:lasgn, :i, s(:lit, toggle(:blah, n == 1))),
- s(:lasgn, :i, s(:lit, toggle(:blah, n == 2))),
- s(:lasgn, :i, s(:lit, toggle(:and_blah, n == 3))))))
+ s(:lasgn, :i, s(:lit, :blah)),
+ s(:lasgn, :i, s(:lit, :blah)),
+ s(:lasgn, :i, s(:lit, :and_blah)))))
+
+ assert_equal expected, @heckler.current_tree
+ end
+
+ def test_symbols_mutations
+ expected = [
+ s(:defn, :uses_symbols,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, :"l33t h4x0r")),
+ s(:lasgn, :i, s(:lit, :blah)),
+ s(:lasgn, :i, s(:lit, :and_blah))))),
+ s(:defn, :uses_symbols,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, :blah)),
+ s(:lasgn, :i, s(:lit, :"l33t h4x0r")),
+ s(:lasgn, :i, s(:lit, :and_blah))))),
+ s(:defn, :uses_symbols,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, :blah)),
+ s(:lasgn, :i, s(:lit, :blah)),
+ s(:lasgn, :i, s(:lit, :"l33t h4x0r"))))),
+ ]
+
+ assert_mutations expected, @heckler
end
end
-class TestHeckleRegexes < LiteralHeckleTestCase
- TOGGLE_VALUE = /l33t\ h4x0r/
+class TestHeckleRegexes < HeckleTestCase
+ def setup
+ @method_heckled = "uses_regexes"
+ @nodes = s(:lit, :str)
+ super
+ end
- def util_expected(n = nil)
- s(:defn, :uses_regexes,
+ def test_regexes_original_tree
+ expected = s(:defn, :uses_regexes,
s(:args),
s(:scope,
s(:block,
- s(:lasgn, :i, s(:lit, toggle(/a.*/, n == 1))),
- s(:lasgn, :i, s(:lit, toggle(/c{2,4}+/, n == 2))),
- s(:lasgn, :i, s(:lit, toggle(/123/, n == 3))))))
+ s(:lasgn, :i, s(:lit, /a.*/)),
+ s(:lasgn, :i, s(:lit, /c{2,4}+/)),
+ s(:lasgn, :i, s(:lit, /123/)))))
+
+ assert_equal expected, @heckler.original_tree
+ end
+
+ def test_regexes_mutuations
+ expected = [
+ s(:defn, :uses_regexes,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, /l33t\ h4x0r/)),
+ s(:lasgn, :i, s(:lit, /c{2,4}+/)),
+ s(:lasgn, :i, s(:lit, /123/))))),
+ s(:defn, :uses_regexes,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, /a.*/)),
+ s(:lasgn, :i, s(:lit, /l33t\ h4x0r/)),
+ s(:lasgn, :i, s(:lit, /123/))))),
+ s(:defn, :uses_regexes,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, /a.*/)),
+ s(:lasgn, :i, s(:lit, /c{2,4}+/)),
+ s(:lasgn, :i, s(:lit, /l33t\ h4x0r/))))),
+ ]
+
+ assert_mutations expected, @heckler
end
end
-class TestHeckleRanges < LiteralHeckleTestCase
- TOGGLE_VALUE = 5..10
+class TestHeckleRanges < HeckleTestCase
+ def setup
+ @method_heckled = "uses_ranges"
+ @nodes = s(:lit, :str)
+ super
+ end
- def util_expected(n = nil)
- s(:defn, :uses_ranges,
+ def test_ranges_original_tree
+ expected = s(:defn, :uses_ranges,
s(:args),
s(:scope,
s(:block,
- s(:lasgn, :i, s(:lit, toggle(6..100, n == 1))),
- s(:lasgn, :i, s(:lit, toggle(-1..9, n == 2))),
- s(:lasgn, :i, s(:lit, toggle(1..4, n == 3))))))
+ s(:lasgn, :i, s(:lit, 6..100)),
+ s(:lasgn, :i, s(:lit, -1..9)),
+ s(:lasgn, :i, s(:lit, 1..4)))))
+
+ assert_equal expected, @heckler.current_tree
+ end
+
+ def test_ranges_mutations
+ expected = [
+ s(:defn, :uses_ranges,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, 5..10)),
+ s(:lasgn, :i, s(:lit, -1..9)),
+ s(:lasgn, :i, s(:lit, 1..4))))),
+ s(:defn, :uses_ranges,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, 6..100)),
+ s(:lasgn, :i, s(:lit, 5..10)),
+ s(:lasgn, :i, s(:lit, 1..4))))),
+ s(:defn, :uses_ranges,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, 6..100)),
+ s(:lasgn, :i, s(:lit, -1..9)),
+ s(:lasgn, :i, s(:lit, 5..10))))),
+ ]
+
+ assert_mutations expected, @heckler
+
end
end
-class TestHeckleSameLiteral < LiteralHeckleTestCase
- TOGGLE_VALUE = 6
+class TestHeckleSameLiteral < HeckleTestCase
+ def setup
+ @method_heckled = "uses_same_literal"
+ @nodes = s(:lit, :str)
+ super
+ end
- def util_expected(n = nil)
- s(:defn, :uses_same_literal,
+ def test_same_literal_original_tree
+ expected = s(:defn, :uses_same_literal,
s(:args),
s(:scope,
s(:block,
- s(:lasgn, :i, s(:lit, toggle(1, n == 1))),
- s(:lasgn, :i, s(:lit, toggle(1, n == 2))),
- s(:lasgn, :i, s(:lit, toggle(1, n == 3))))))
+ s(:lasgn, :i, s(:lit, 1)),
+ s(:lasgn, :i, s(:lit, 1)),
+ s(:lasgn, :i, s(:lit, 1)))))
+
+ assert_equal expected, @heckler.current_tree
+ end
+
+ def test_same_literal_mutations
+ expected = [
+ s(:defn, :uses_same_literal,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, 6)),
+ s(:lasgn, :i, s(:lit, 1)),
+ s(:lasgn, :i, s(:lit, 1))))),
+ s(:defn, :uses_same_literal,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, 1)),
+ s(:lasgn, :i, s(:lit, 6)),
+ s(:lasgn, :i, s(:lit, 1))))),
+ s(:defn, :uses_same_literal,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :i, s(:lit, 1)),
+ s(:lasgn, :i, s(:lit, 1)),
+ s(:lasgn, :i, s(:lit, 6))))),
+ ]
+
+ assert_mutations expected, @heckler
end
end
-class TestHeckleStrings < LiteralHeckleTestCase
- TOGGLE_VALUE = "l33t h4x0r"
+class TestHeckleStrings < HeckleTestCase
+ def setup
+ @method_heckled = "uses_strings"
+ @nodes = s(:lit, :str)
+ super
+ end
- def util_expected(n = nil)
- s(:defn, :uses_strings,
+ def test_strings_original_tree
+ expected = s(:defn, :uses_strings,
s(:args),
s(:scope,
s(:block,
- s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, toggle("Hello, Robert", n == 1)))),
- s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, toggle("Hello, Jeff", n == 2)))),
- s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, toggle("Hi, Frank", n == 3)))))))
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "Hello, Robert"))),
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "Hello, Jeff"))),
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "Hi, Frank"))))))
+
+ assert_equal expected, @heckler.current_tree
+ end
+
+ def test_strings_mutations
+ expected = [
+ s(:defn, :uses_strings,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "l33t h4x0r"))),
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "Hello, Jeff"))),
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "Hi, Frank")))))),
+ s(:defn, :uses_strings,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "Hello, Robert"))),
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "l33t h4x0r"))),
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "Hi, Frank")))))),
+ s(:defn, :uses_strings,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "Hello, Robert"))),
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "Hello, Jeff"))),
+ s(:call, s(:ivar, :@names), :<<, s(:arglist, s(:str, "l33t h4x0r")))))),
+ ]
+
+ assert_mutations expected, @heckler
end
end
class TestHeckleIf < HeckleTestCase
def setup
+ @method_heckled = "uses_if"
@nodes = s(:if)
super
end
- def test_default_structure
+ def test_if_original_tree
expected = s(:defn, :uses_if,
s(:args),
s(:scope,
@@ -307,427 +503,513 @@ def test_default_structure
assert_equal expected, @heckler.current_tree
end
- def test_should_flip_if_to_unless
- expected = s(:defn, :uses_if,
- s(:args),
- s(:scope,
- s(:block,
- s(:if,
- s(:call, nil, :some_func, s(:arglist)),
- s(:if, s(:call, nil, :some_other_func, s(:arglist)), nil, s(:return)),
- nil))))
-
- @heckler.process(@heckler.current_tree)
- assert_equal expected, @heckler.current_tree
-
- @heckler.reset_tree
-
- expected = s(:defn, :uses_if,
- s(:args),
- s(:scope,
- s(:block,
- s(:if,
- s(:call, nil, :some_func, s(:arglist)),
- nil,
- s(:if, s(:call, nil, :some_other_func, s(:arglist)), s(:return), nil)))))
-
- @heckler.process(@heckler.current_tree)
- assert_equal expected, @heckler.current_tree
+ def test_if_mutations
+ expected = [
+ s(:defn,
+ :uses_if,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:if,
+ s(:call, nil, :some_func, s(:arglist)),
+ nil,
+ s(:if, s(:call, nil, :some_other_func, s(:arglist)), s(:return), nil))))),
+ s(:defn,
+ :uses_if,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:if,
+ s(:call, nil, :some_func, s(:arglist)),
+ s(:if, s(:call, nil, :some_other_func, s(:arglist)), nil, s(:return)),
+ nil))))
+ ]
+
+ assert_mutations expected, @heckler
end
end
class TestHeckleBoolean < HeckleTestCase
-
def setup
+ @method_heckled = "uses_boolean"
@nodes = s(:true, :false)
super
end
- def toggle(value, toggle)
- (toggle ? ! value : value).to_s.intern
- end
-
- def util_expected(n = nil)
- s(:defn, :uses_boolean,
- s(:args),
- s(:scope,
- s(:block,
- s(:lasgn, :a, s(toggle(true, n == 1))),
- s(:lasgn, :b, s(toggle(false, n == 2))))))
- end
+ def test_boolean_original_tree
+ expected = s(:defn, :uses_boolean,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :a, s(:true)),
+ s(:lasgn, :b, s(:false)))))
- def test_default_structure
- assert_equal util_expected, @heckler.current_tree
+ assert_equal expected, @heckler.current_tree
end
- def test_should_flip_true_to_false_and_false_to_true
- @heckler.process(@heckler.current_tree)
- assert_equal util_expected(1), @heckler.current_tree
-
- @heckler.reset_tree
-
- @heckler.process(@heckler.current_tree)
- assert_equal util_expected(2), @heckler.current_tree
+ def test_boolean_mutations
+ expected = [
+ s(:defn, :uses_boolean,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :a, s(:false)),
+ s(:lasgn, :b, s(:false))))),
+ s(:defn, :uses_boolean,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :a, s(:true)),
+ s(:lasgn, :b, s(:true))))),
+ ]
+
+ assert_mutations expected, @heckler
end
end
class TestHeckleWhile < HeckleTestCase
def setup
+ @method_heckled = "uses_while"
@nodes = s(:while)
super
end
- def test_default_structure
- expected = s(:defn, :uses_while,
- s(:args),
- s(:scope,
- s(:block,
- s(:while, s(:call, nil, :some_func, s(:arglist)),
- s(:call, nil, :some_other_func, s(:arglist)), true))))
+ def test_while_original_tree
+ expected = s(:defn, :uses_while,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:while, s(:call, nil, :some_func, s(:arglist)),
+ s(:call, nil, :some_other_func, s(:arglist)), true))))
+
assert_equal expected, @heckler.current_tree
end
- def test_flips_while_to_until
- expected = s(:defn, :uses_while,
- s(:args),
- s(:scope,
- s(:block,
- s(:until, s(:call, nil, :some_func, s(:arglist)),
- s(:call, nil, :some_other_func, s(:arglist)), true))))
- @heckler.process(@heckler.current_tree)
- assert_equal expected, @heckler.current_tree
+ def test_while_mutations
+ expected = [
+ s(:defn, :uses_while,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:until, s(:call, nil, :some_func, s(:arglist)),
+ s(:call, nil, :some_other_func, s(:arglist)), true))))]
+
+ assert_mutations expected, @heckler
end
end
class TestHeckleUntil < HeckleTestCase
def setup
+ @method_heckled = "uses_until"
@nodes = s(:until)
super
end
- def test_default_structure
- expected = s(:defn, :uses_until,
- s(:args),
- s(:scope,
- s(:block,
- s(:until, s(:call, nil, :some_func, s(:arglist)),
- s(:call, nil, :some_other_func, s(:arglist)), true))))
+ def test_until_original_tree
+ expected = s(:defn, :uses_until,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:until, s(:call, nil, :some_func, s(:arglist)),
+ s(:call, nil, :some_other_func, s(:arglist)), true))))
+
assert_equal expected, @heckler.current_tree
end
- def test_flips_until_to_while
- expected = s(:defn, :uses_until,
- s(:args),
- s(:scope,
- s(:block,
- s(:while, s(:call, nil, :some_func, s(:arglist)),
- s(:call, nil, :some_other_func, s(:arglist)), true))))
- @heckler.process(@heckler.current_tree)
- assert_equal expected, @heckler.current_tree
+ def test_until_mutations
+ expected = [
+ s(:defn, :uses_until,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:while, s(:call, nil, :some_func, s(:arglist)),
+ s(:call, nil, :some_other_func, s(:arglist)), true))))]
+
+ assert_mutations expected, @heckler
end
end
class TestHeckleCall < HeckleTestCase
-
- def test_call_deleted
- expected = s(:defn, :uses_call,
- s(:args),
- s(:scope,
- s(:block,
- s(:nil))))
-
- @heckler.process(@heckler.current_tree) # some_func
- @heckler.reset_tree
- @heckler.process(@heckler.current_tree) # some_other_func
- @heckler.reset_tree
- @heckler.process(@heckler.current_tree) # +
- assert_equal expected, @heckler.current_tree
+ def setup
+ @method_heckled = "uses_call"
+ super
end
- def test_default_structure
- expected = s(:defn, :uses_call,
- s(:args),
- s(:scope,
- s(:block,
- s(:call,
- s(:call, nil, :some_func, s(:arglist)),
- :+,
- s(:arglist, s(:call, nil, :some_other_func, s(:arglist)))))))
+ def test_call_original_tree
+ expected = s(:defn, :uses_call,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:call,
+ s(:call, nil, :some_func, s(:arglist)),
+ :+,
+ s(:arglist, s(:call, nil, :some_other_func, s(:arglist)))))))
assert_equal expected, @heckler.current_tree
end
+ def test_call_mutations
+ expected = [
+ s(:defn, :uses_call,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:call,
+ s(:call, nil, :some_func, s(:arglist)),
+ :+,
+ s(:arglist, s(:nil)))))),
+ s(:defn, :uses_call,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:call,
+ s(:nil),
+ :+,
+ s(:arglist, s(:call, nil, :some_other_func, s(:arglist))))))),
+ s(:defn, :uses_call,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:nil)))),
+ ]
+
+ assert_mutations expected, @heckler
+ end
end
class TestHeckleCallblock < HeckleTestCase
-
def setup
+ @method_heckled = "uses_callblock"
@nodes = s(:call)
super
end
- def test_default_structure
- expected = s(:defn, :uses_callblock,
- s(:args),
- s(:scope,
- s(:block,
- s(:iter,
- s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist)),
- nil,
- s(:lit, 1)))))
+ def test_callblock_original_tree
+ expected = s(:defn, :uses_callblock,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:iter,
+ s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist)),
+ nil,
+ s(:lit, 1)))))
assert_equal expected, @heckler.current_tree
end
- def test_callblock_deleted
- expected = s(:defn, :uses_callblock,
- s(:args),
- s(:scope,
- s(:block,
- s(:iter,
- s(:call, s(:nil), :y, s(:arglist)),
- nil,
- s(:lit, 1)))))
+ def test_callblock_mutations
+ expected = [
+ s(:defn, :uses_callblock,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:iter,
+ s(:call, s(:nil), :y, s(:arglist)),
+ nil,
+ s(:lit, 1)))))
+ ]
- @heckler.process(@heckler.current_tree)
- assert_equal expected, @heckler.current_tree
+ assert_mutations expected, @heckler
end
end
class TestHeckleClassMethod < HeckleTestCase
def setup
- @hecklee = "self.is_a_klass_method?"
+ @method_heckled = "self.is_a_klass_method?"
@nodes = s(:true)
super
end
- def test_default_structure
- expected = s(:defs, s(:self), :is_a_klass_method?,
- s(:args),
- s(:scope,
- s(:block,
- s(:true))))
+ def test_class_method_original_tree
+ expected = s(:defs, s(:self), :is_a_klass_method?,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:true))))
+
assert_equal expected, @heckler.current_tree
end
- def test_heckle_class_methods
- expected = s(:defs, s(:self), :is_a_klass_method?,
- s(:args),
- s(:scope,
- s(:block,
- s(:false))))
- @heckler.process(@heckler.current_tree)
- assert_equal expected, @heckler.current_tree
+ def test_class_methods_mutations
+ expected = [
+ s(:defs, s(:self), :is_a_klass_method?,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:false))))
+ ]
+
+ assert_mutations expected, @heckler
end
end
class TestHeckleCvasgn < HeckleTestCase
-
def setup
+ @method_heckled = "uses_cvasgn"
@nodes = s(:cvasgn)
super
end
- def test_cvasgn_val
- expected = s(:defn, :uses_cvasgn,
- s(:args),
- s(:scope,
- s(:block,
- s(:cvasgn, :@@cvar, s(:nil)),
- s(:cvasgn, :@@cvar, s(:nil)))))
+ def test_cvasgn_original_tree
+ expected = s(:defn, :uses_cvasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:cvasgn, :@@cvar, s(:lit, 5)),
+ s(:cvasgn, :@@cvar, s(:nil)))))
- @heckler.process(@heckler.current_tree)
assert_equal expected, @heckler.current_tree
end
- def test_cvasgn_nil
- expected = s(:defn, :uses_cvasgn,
- s(:args),
- s(:scope,
- s(:block,
- s(:cvasgn, :@@cvar, s(:lit, 5)),
- s(:cvasgn, :@@cvar, s(:lit, 42)))))
-
- @heckler.process(@heckler.current_tree)
- @heckler.reset_tree
- @heckler.process(@heckler.current_tree)
- assert_equal expected, @heckler.current_tree
+ def test_cvasgn_mutations
+ expected = [
+ s(:defn, :uses_cvasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:cvasgn, :@@cvar, s(:lit, 5)),
+ s(:cvasgn, :@@cvar, s(:lit, 42))))),
+ s(:defn, :uses_cvasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:cvasgn, :@@cvar, s(:nil)),
+ s(:cvasgn, :@@cvar, s(:nil))))),
+ ]
+
+ assert_mutations expected, @heckler
end
-
end
class TestHeckleIasgn < HeckleTestCase
-
def setup
+ @method_heckled = "uses_iasgn"
@nodes = s(:iasgn)
super
end
- def test_iasgn_val
- expected = s(:defn, :uses_iasgn,
- s(:args),
- s(:scope,
- s(:block,
- s(:iasgn, :@ivar, s(:nil)),
- s(:iasgn, :@ivar, s(:nil)))))
+ def test_iasgn_original_tree
+ expected = s(:defn, :uses_iasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:iasgn, :@ivar, s(:lit, 5)),
+ s(:iasgn, :@ivar, s(:nil)))))
- @heckler.process(@heckler.current_tree)
assert_equal expected, @heckler.current_tree
end
- def test_iasgn_nil
- expected = s(:defn, :uses_iasgn,
- s(:args),
- s(:scope,
- s(:block,
- s(:iasgn, :@ivar, s(:lit, 5)),
- s(:iasgn, :@ivar, s(:lit, 42)))))
+ def test_iasgn_mutations
+ expected = [
+ s(:defn, :uses_iasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:iasgn, :@ivar, s(:lit, 5)),
+ s(:iasgn, :@ivar, s(:lit, 42))))),
+ s(:defn, :uses_iasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:iasgn, :@ivar, s(:nil)),
+ s(:iasgn, :@ivar, s(:nil))))),
+ ]
- @heckler.process(@heckler.current_tree)
- @heckler.reset_tree
- @heckler.process(@heckler.current_tree)
- assert_equal expected, @heckler.current_tree
+ assert_mutations expected, @heckler
end
end
class TestHeckleGasgn < HeckleTestCase
-
def setup
+ @method_heckled = "uses_gasgn"
+ s(:defn, :uses_cvasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:cvasgn, :@@cvar, s(:lit, 5)),
+ s(:cvasgn, :@@cvar, s(:lit, 42)))))
@nodes = s(:gasgn)
super
end
- def test_gasgn_val
- expected = s(:defn, :uses_gasgn,
- s(:args),
- s(:scope,
- s(:block,
- s(:gasgn, :$gvar, s(:nil)),
- s(:gasgn, :$gvar, s(:nil)))))
+ def test_gasgn_original_tree
+ expected = s(:defn, :uses_gasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:gasgn, :$gvar, s(:lit, 5)),
+ s(:gasgn, :$gvar, s(:nil)))))
- @heckler.process(@heckler.current_tree)
assert_equal expected, @heckler.current_tree
end
- def test_gasgn_nil
- expected = s(:defn, :uses_gasgn,
- s(:args),
- s(:scope,
- s(:block,
- s(:gasgn, :$gvar, s(:lit, 5)),
- s(:gasgn, :$gvar, s(:lit, 42)))))
+ def test_gasgn_mutations
+ expected = [
+ s(:defn, :uses_gasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:gasgn, :$gvar, s(:lit, 5)),
+ s(:gasgn, :$gvar, s(:lit, 42))))),
+ s(:defn, :uses_gasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:gasgn, :$gvar, s(:nil)),
+ s(:gasgn, :$gvar, s(:nil))))),
+ ]
- @heckler.process(@heckler.current_tree)
- @heckler.reset_tree
- @heckler.process(@heckler.current_tree)
- assert_equal expected, @heckler.current_tree
+ assert_mutations expected, @heckler
end
end
class TestHeckleLasgn < HeckleTestCase
-
def setup
+ @method_heckled = "uses_lasgn"
@nodes = s(:lasgn)
super
end
- def test_lasgn_val
- expected = s(:defn, :uses_lasgn,
- s(:args),
- s(:scope,
- s(:block,
- s(:lasgn, :lvar, s(:nil)),
- s(:lasgn, :lvar, s(:nil)))))
+ def test_lasgn_original_tree
+ expected = s(:defn, :uses_lasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :lvar, s(:lit, 5)),
+ s(:lasgn, :lvar, s(:nil)))))
- @heckler.process(@heckler.current_tree)
assert_equal expected, @heckler.current_tree
end
- def test_lasgn_nil
- expected = s(:defn, :uses_lasgn,
- s(:args),
- s(:scope,
- s(:block,
- s(:lasgn, :lvar, s(:lit, 5)),
- s(:lasgn, :lvar, s(:lit, 42)))))
-
- @heckler.process(@heckler.current_tree)
- @heckler.reset_tree
- @heckler.process(@heckler.current_tree)
- assert_equal expected, @heckler.current_tree
+ def test_lasgn_mutations
+ expected = [
+ s(:defn, :uses_lasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :lvar, s(:nil)),
+ s(:lasgn, :lvar, s(:nil))))),
+ s(:defn, :uses_lasgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :lvar, s(:lit, 5)),
+ s(:lasgn, :lvar, s(:lit, 42))))),
+ ]
+
+ assert_mutations expected, @heckler
end
-
end
class TestHeckleMasgn < HeckleTestCase
-
def setup
+ @method_heckled = "uses_masgn"
@nodes = s(:dasgn, :dasgn_curr, :iasgn, :gasgn, :lasgn)
super
end
- # Changed the first :iasgn from an :lasgn to get test to pass. Can't really
- # say what's correct... --PH
- def test_masgn
- expected = s(:defn, :uses_masgn,
- s(:args),
- s(:scope,
- s(:block,
- s(:masgn,
- s(:array,
- s(:iasgn, :_heckle_dummy),
- s(:gasgn, :$b),
- s(:lasgn, :c)),
- s(:array, s(:lit, 5), s(:lit, 6), s(:lit, 7))))))
+ def test_masgn_original_tree
+ expected = s(:defn, :uses_masgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:masgn,
+ s(:array, s(:iasgn, :@a), s(:gasgn, :$b), s(:lasgn, :c)),
+ s(:array, s(:lit, 5), s(:lit, 6), s(:lit, 7))))))
- @heckler.process(@heckler.current_tree)
assert_equal expected, @heckler.current_tree
end
+ def test_masgn_mutations
+ expected = [
+ s(:defn, :uses_masgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:masgn,
+ s(:array, s(:iasgn, :_heckle_dummy), s(:gasgn, :$b), s(:lasgn, :c)),
+ s(:array, s(:lit, 5), s(:lit, 6), s(:lit, 7)))))),
+ s(:defn, :uses_masgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:masgn,
+ s(:array, s(:iasgn, :@a), s(:gasgn, :_heckle_dummy), s(:lasgn, :c)),
+ s(:array, s(:lit, 5), s(:lit, 6), s(:lit, 7)))))),
+ s(:defn, :uses_masgn,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:masgn,
+ s(:array,s(:iasgn, :@a), s(:gasgn, :$b), s(:lasgn, :_heckle_dummy)),
+ s(:array, s(:lit, 5), s(:lit, 6), s(:lit, 7)))))),
+ ]
+
+ assert_mutations expected, @heckler
+ end
+
end
class TestHeckleIter < HeckleTestCase
def setup
+ @method_heckled = "uses_iter"
@nodes = [ :call, :lasgn ]
super
end
-
- def test_iter
- expected = s(:defn, :uses_iter,
- s(:args),
- s(:scope,
- s(:block,
- s(:lasgn, :x, s(:nil)),
- s(:iter,
- s(:call, s(:lvar, :x), :each, s(:arglist)),
- s(:lasgn, :y),
- s(:lvar, :y)))))
-
- # This call causes the replacement of [:lasgn, :x...] above to
- # become [:lasgn, :nil]. We then reset the tree to ensure that
- # the original method is maintained. We are really trying to test
- # the reset_tree method here, not the actual changes.
- @heckler.process(@heckler.current_tree)
- assert_equal(expected, @heckler.current_tree)
+ def test_iter_original_tree
+ expected = s(:defn, :uses_iter,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :x, s(:array, s(:lit, 1), s(:lit, 2), s(:lit, 3))),
+ s(:iter,
+ s(:call, s(:lvar, :x), :each, s(:arglist)),
+ s(:lasgn, :y), s(:lvar, :y)))))
- @heckler.reset_tree
+ assert_equal expected, @heckler.current_tree
+ end
- # Changed the expected value to get test to pass. Can't really say what's
- # correct... --PH
- expected = s(:defn, :uses_iter,
- s(:args),
- s(:scope,
- s(:block,
- s(:lasgn, :x, s(:array, s(:lit, 1), s(:lit, 2), s(:lit, 3))),
- s(:iter,
- s(:call, s(:lvar, :x), :each, s(:arglist)),
- s(:lasgn, :_heckle_dummy),
- #s(:call, nil, :y, s(:arglist))))))
- s(:lvar, :y)))))
+ def test_iter_mutations
+ expected = [
+ s(:defn, :uses_iter,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :x, s(:nil)),
+ s(:iter,
+ s(:call, s(:lvar, :x), :each, s(:arglist)),
+ s(:lasgn, :y), s(:lvar, :y))))),
+ s(:defn, :uses_iter,
+ s(:args),
+ s(:scope,
+ s(:block,
+ s(:lasgn, :x, s(:array, s(:lit, 1), s(:lit, 2), s(:lit, 3))),
+ s(:iter,
+ s(:call, s(:lvar, :x), :each, s(:arglist)),
+ s(:lasgn, :_heckle_dummy), s(:lvar, :y))))),
+ ]
+
+
+ assert_mutations expected, @heckler
+ end
+end
- @heckler.process(@heckler.current_tree)
- assert_equal(expected, @heckler.current_tree)
+
+class TestHeckleFindsNestedClassAndModule < HeckleTestCase
+ def setup
+ @klass = "HeckleDummy::OuterNesting::InnerNesting::InnerClass"
+ @method_heckled = "foo"
+ @nodes = []
+ super
+ end
+
+ def test_nested_class_and_module_original_tree
+ expected = s(:defn, :foo, s(:args), s(:scope,
+ s(:block,
+ s(:lit, 1337))))
+
+ assert_equal expected, @heckler.current_tree
end
end
View
54 test/test_heckle_runner.rb
@@ -0,0 +1,54 @@
+require 'minitest/autorun'
+require 'heckle_runner'
+
+# Tests needed:
+# * if no method, loads all local methods
+# * should raise an exception if the class/module can't be found
+# * should raise an exception if the method can't be found
+# * Tests for option parsing.
+
+class TestHeckleRunnerRun < MiniTest::Unit::TestCase
+ @@dummy_dir = File.expand_path('test/fixtures/minitest_project')
+ dummy_lib = File.join(@@dummy_dir, 'lib')
+
+ $LOAD_PATH << dummy_lib
+
+ def setup
+ super
+
+ @old_pwd = Dir.pwd
+ Dir.chdir @@dummy_dir
+
+ # See MiniTest's test/minitest/metametameta.rb
+ @output = StringIO.new("")
+ MiniTest::Unit::TestCase.reset
+ MiniTest::Unit.output = @output
+ end
+
+ def teardown
+ super
+ Dir.chdir @old_pwd
+ MiniTest::Unit.output = $stdout
+
+ MiniTest::Unit::TestCase.test_suites.each do |test|
+ Object.send :remove_const, test.to_s.to_sym
+ end
+ end
+
+ def test_run_with_full_coverage
+ out, _ = capture_io do
+ HeckleRunner.run %w[Doubler double]
+ end
+
+ assert_match %r{No mutants survived.}, out
+ end
+
+ def test_run_with_partial_coverage
+ out, _ = capture_io do
+ HeckleRunner.run %w[Doubler double --tests test/test_doubler_with_a_number.rb]
+ end
+
+ assert_match %r{The following mutations didn't cause test failures:}, out
+ refute_match %{No mutants survived.}, out
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.