Skip to content
Browse files

Fixed manifest for previous refactoring/file-splits.

Fixed requires to not be clever. Added lib to path in Rakefile.
Minor cleanup here and there. Nuked trailing whitespace around.
Trap and deal gracefully with syntax errors in mutations.
Removed all possible warnings from heckle, but can't from heckle mutations.

[git-p4: depot-paths = "//src/heckle/dev/": change = 2777]
  • Loading branch information...
1 parent 16d8d17 commit 8325ac0a913b23567d950cee100975720c2cb203 @zenspider zenspider committed
Showing with 110 additions and 96 deletions.
  1. +2 −0 Manifest.txt
  2. +2 −0 Rakefile
  3. +1 −2 bin/heckle
  4. +2 −7 lib/heckle.rb
  5. +84 −66 lib/heckle/base.rb
  6. +14 −16 lib/test_unit_heckler.rb
  7. +5 −5 test/test_heckle.rb
View
2 Manifest.txt
@@ -4,6 +4,8 @@ README.txt
Rakefile
bin/heckle
lib/heckle.rb
+lib/heckle/base.rb
+lib/heckle/reporter.rb
lib/test_unit_heckler.rb
sample/Rakefile
sample/changes.log
View
2 Rakefile
@@ -1,5 +1,7 @@
# -*- ruby -*-
+$: << 'lib'
+
require 'rubygems'
require 'hoe'
require './lib/heckle.rb'
View
3 bin/heckle
@@ -31,8 +31,7 @@ unless impl then
end
if meth
- heckle = TestUnitHeckler.new(impl, meth)
- heckle.validate
+ TestUnitHeckler.new(impl, meth).validate
else
TestUnitHeckler.validate(impl)
end
View
9 lib/heckle.rb
@@ -2,10 +2,5 @@
require 'parse_tree'
require 'ruby2ruby'
require 'logger'
-
-require File.dirname(__FILE__) + '/heckle/reporter'
-require File.dirname(__FILE__) + '/heckle/base'
-
-Heckle::VERSION = '1.1.0'
-
-
+require 'heckle/reporter'
+require 'heckle/base'
View
150 lib/heckle/base.rb
@@ -4,47 +4,49 @@ def to_class
end
end
-
module Heckle
+ VERSION = '1.1.0'
+
class Base < SexpProcessor
MUTATABLE_NODES = [:if, :lit, :str, :true, :false, :while, :until]
attr_accessor :klass_name, :method_name, :klass, :method, :mutatees, :original_tree,
- :mutation_count, :node_count, :failures
-
+ :mutation_count, :node_count, :failures, :count
+
@@debug = false;
-
+
def self.debug=(value)
@@debug = value
end
-
+
def initialize(klass_name=nil, method_name=nil, reporter = Reporter.new)
super()
@klass_name, @method_name = klass_name, method_name.intern
@klass = @method = nil
@reporter = reporter
-
+
self.strict = false
self.auto_shift_type = true
self.expected = Array
-
+
@mutatees = Hash.new
@mutation_count = Hash.new
@node_count = Hash.new
-
+ @count = 0
+
MUTATABLE_NODES.each {|type| @mutatees[type] = [] }
-
+
@failures = []
-
+
@mutated = false
grab_mutatees
-
+
@original_tree = current_tree.deep_clone
@original_mutatees = mutatees.deep_clone
end
-
+
############################################################
### Overwrite test_pass? for your own Heckle runner.
def tests_pass?
@@ -58,27 +60,31 @@ def run_tests
@reporter.report_test_failures
end
end
-
+
############################################################
### Running the script
-
+
def validate
if mutations_left == 0
@reporter.no_mutations(method_name)
return
end
-
+
@reporter.method_loaded(klass_name, method_name, mutations_left)
-
+
until mutations_left == 0
@reporter.remaining_mutations(mutations_left)
reset_tree
- process current_tree
- silence_stream(STDOUT) { run_tests }
+ begin
+ process current_tree
+ silence_stream(STDOUT) { run_tests }
+ rescue SyntaxError => e
+ puts "Mutation caused a syntax error: #{e.message}"
+ end
end
-
+
reset # in case we're validating again. we should clean up.
-
+
unless @failures.empty?
@reporter.no_failures
@failures.each do |failure|
@@ -92,17 +98,23 @@ def validate
def record_passing_mutation
@failures << current_code
end
-
+
def heckle(exp)
src = RubyToRuby.new.process(exp)
@reporter.replacing(klass_name, method_name, src) if @@debug
- klass_name.to_class.class_eval(src)
- end
-
+ klass = klass_name.to_class
+ self.count += 1
+ new_name = "#{method_name}_#{count}"
+
+ klass.send :undef_method, new_name rescue nil
+ klass.send :alias_method, new_name, method_name
+ klass.class_eval(src)
+ end
+
############################################################
### Processing sexps
-
- def process_defn(exp)
+
+ def process_defn(exp)
self.method = exp.shift
result = [:defn, method]
result << process(exp.shift) until exp.empty?
@@ -112,11 +124,11 @@ def process_defn(exp)
return result
end
-
+
def process_lit(exp)
mutate_node [:lit, exp.shift]
end
-
+
def mutate_lit(exp)
case exp[1]
when Fixnum, Float, Bignum
@@ -127,59 +139,59 @@ def mutate_lit(exp)
[:lit, /#{Regexp.escape(rand_string)}/]
when Range
[:lit, rand_range]
- end
+ end
end
-
+
def process_str(exp)
mutate_node [:str, exp.shift]
end
-
+
def mutate_str(node)
[:str, rand_string]
end
-
- def process_if(exp)
+
+ def process_if(exp)
mutate_node [:if, process(exp.shift), process(exp.shift), process(exp.shift)]
end
-
+
def mutate_if(node)
[:if, node[1], node[3], node[2]]
end
-
+
def process_true(exp)
mutate_node [:true]
end
-
+
def mutate_true(node)
[:false]
end
-
+
def process_false(exp)
mutate_node [:false]
end
-
+
def mutate_false(node)
[:true]
end
-
+
def process_while(exp)
cond, body, head_controlled = grab_conditional_loop_parts(exp)
mutate_node [:while, cond, body, head_controlled]
end
-
+
def mutate_while(node)
[:until, node[1], node[2], node[3]]
end
-
+
def process_until(exp)
cond, body, head_controlled = grab_conditional_loop_parts(exp)
mutate_node [:until, cond, body, head_controlled]
end
-
+
def mutate_until(node)
[:while, node[1], node[2], node[3]]
end
-
+
def mutate_node(node)
raise UnsupportedNodeError unless respond_to? "mutate_#{node.first}"
increment_node_count node
@@ -190,7 +202,7 @@ def mutate_node(node)
node
end
end
-
+
############################################################
### Tree operations
@@ -198,7 +210,7 @@ def walk_and_push(node)
return unless node.respond_to? :each
return if node.is_a? String
node.each { |child| walk_and_push(child) }
- if MUTATABLE_NODES.include? node.first
+ if MUTATABLE_NODES.include? node.first
@mutatees[node.first.to_sym].push(node)
mutation_count[node] = 0
end
@@ -222,9 +234,13 @@ def reset_tree
return unless original_tree != current_tree
@mutated = false
- r2r = RubyToRuby.new
- src = r2r.process(original_tree.deep_clone)
- klass_name.to_class.class_eval(src)
+ klass = klass_name.to_class
+
+ self.count += 1
+ new_name = "#{method_name}_#{count}"
+ klass.send :undef_method, new_name rescue nil
+ klass.send :alias_method, new_name, method_name
+ klass.send :alias_method, method_name, "#{method_name}_1"
end
def reset_mutatees
@@ -238,7 +254,7 @@ def reset_mutation_count
def reset_node_count
node_count.each {|k,v| node_count[k] = 0}
end
-
+
def increment_node_count(node)
if node_count[node].nil?
node_count[node] = 1
@@ -246,69 +262,71 @@ def increment_node_count(node)
node_count[node] += 1
end
end
-
+
def increment_mutation_count(node)
# So we don't re-mutate this later if the tree is reset
mutation_count[node] += 1
- @mutatees[node.first].delete_at(@mutatees[node.first].index(node))
- @mutated = true
+ @mutatees[node.first].delete_at(@mutatees[node.first].index(node))
+ @mutated = true
end
############################################################
### Convenience methods
-
+
def should_heckle?(exp)
return false unless method == method_name
mutation_count[exp] = 0 if mutation_count[exp].nil?
return false if node_count[exp] <= mutation_count[exp]
mutatees[exp.first.to_sym].include?(exp) && !already_mutated?
end
-
+
def grab_conditional_loop_parts(exp)
cond = process(exp.shift)
- body = process(exp.shift)
+ body = process(exp.shift)
head_controlled = exp.shift
return cond, body, head_controlled
end
-
+
def already_mutated?
@mutated
end
-
+
def mutations_left
- @mutatees.inject(0) {|sum, mut| sum = sum + mut.last.size }
+ sum = 0
+ @mutatees.each {|mut| sum += mut.last.size }
+ sum
end
-
+
def current_code
RubyToRuby.translate(klass_name.to_class, method_name)
end
-
+
def rand_number
(rand(10) + 1)*((-1)**rand(2))
end
-
+
def rand_string
size = rand(100)
str = ""
size.times { str << rand(126).chr }
str
end
-
+
def rand_symbol
letters = ('a'..'z').to_a + ('A'..'Z').to_a
str = ""
rand(100).times { str << letters[rand(letters.size)] }
:"#{str}"
end
-
+
def rand_range
min = rand(50)
max = min + rand(50)
min..max
end
-
+
# silence_stream taken from Rails ActiveSupport reporting.rb
-
+
# Silences any stream for the duration of the block.
#
# silence_stream(STDOUT) do
@@ -328,4 +346,4 @@ def silence_stream(stream)
end
end
-end
+end
View
30 lib/test_unit_heckler.rb
@@ -7,23 +7,21 @@ class TestUnitHeckler < Heckle::Base
@@test_pattern = 'test/test_*.rb'
@@tests_loaded = false;
- class << self
- def test_pattern=(value)
- @@test_pattern = value
- end
+ def self.test_pattern=(value)
+ @@test_pattern = value
+ end
- def load_test_files
- @@tests_loaded = true
- Dir.glob(@@test_pattern).each {|test| require test}
- end
+ def self.load_test_files
+ @@tests_loaded = true
+ Dir.glob(@@test_pattern).each {|test| require test}
+ end
- def validate(klass_name)
- load_test_files
- klass = klass_name.to_class
- klass.instance_methods(false).each do |method_name|
- heckler = self.new(klass_name, method_name)
- heckler.test_and_validate
- end
+ def self.validate(klass_name)
+ load_test_files
+ klass = klass_name.to_class
+ klass.instance_methods(false).each do |method_name|
+ heckler = self.new(klass_name, method_name)
+ heckler.test_and_validate
end
end
@@ -44,4 +42,4 @@ def test_and_validate
def tests_pass?
Test::Unit::AutoRunner.run
end
-end
+end
View
10 test/test_heckle.rb
@@ -14,7 +14,7 @@ def setup
def test_should_set_original_tree
expected = [:defn,
:uses_many_things,
- [:scope,
+ [:fbody, [:scope,
[:block,
[:args],
[:lasgn, :i, [:lit, 1]],
@@ -29,7 +29,7 @@ def test_should_set_original_tree
nil],
[:return, [:false]]],
true],
- [:lvar, :i]]]]
+ [:lvar, :i]]]]]
assert_equal expected, @heckler.original_tree
end
@@ -77,7 +77,7 @@ def test_reset
assert_not_equal original_mutatees, @heckler.mutatees
@heckler.reset
- assert_equal original_tree, @heckler.current_tree
+ assert_equal original_tree[2], @heckler.current_tree[2][1]
assert_equal original_mutatees, @heckler.mutatees
end
@@ -386,12 +386,12 @@ def teardown
def test_original_tree
expected = [:defn,
:uses_the_same_literal,
- [:scope,
+ [:fbody, [:scope,
[:block,
[:args],
[:lasgn, :i, [:lit, 1]],
[:lasgn, :i, [:lit, 1]],
- [:lasgn, :i, [:lit, 1]]]]]
+ [:lasgn, :i, [:lit, 1]]]]]]
assert_equal expected, @heckler.current_tree
end

0 comments on commit 8325ac0

Please sign in to comment.
Something went wrong with that request. Please try again.