Permalink
Browse files

Infinite loop detection (take that halting problem!)

[git-p4: depot-paths = "//src/heckle/dev/": change = 2875]
  • Loading branch information...
1 parent fc171ce commit 9b1f0e209fde868689fbfdf0f0ce30c6312c31eb @kevinclark kevinclark committed Jan 10, 2007
Showing with 50 additions and 13 deletions.
  1. +29 −13 lib/heckle.rb
  2. +8 −0 lib/test_unit_heckler.rb
  3. +9 −0 sample/lib/heckled.rb
  4. +4 −0 sample/test/test_heckled.rb
View
@@ -1,6 +1,7 @@
require 'rubygems'
require 'parse_tree'
require 'ruby2ruby'
+require 'timeout'
class String
def to_class
@@ -18,11 +19,16 @@ class Heckle < SexpProcessor
:original_tree, :mutation_count, :node_count,
:failures, :count)
- @@debug = false;
+ @@debug = false
+ @@timeout = 60 # default to something longer (can be overridden by runners)
def self.debug=(value)
@@debug = value
end
+
+ def self.timeout=(value)
+ @@timeout = value
+ end
def initialize(klass_name=nil, method_name=nil, reporter = Reporter.new)
super()
@@ -82,9 +88,11 @@ def validate
reset_tree
begin
process current_tree
- silence_stream { run_tests }
+ silence_stream { timeout(@@timeout) { run_tests } }
rescue SyntaxError => e
- puts "Mutation caused a syntax error: #{e.message}"
+ @reporter.warning "Mutation caused a syntax error: #{e.message}"
+ rescue Timeout::Error
+ @reporter.warning "Your tests timed out. Heckle may have caused an infinite loop."
end
end
@@ -361,25 +369,33 @@ def silence_stream
class Reporter
def no_mutations(method_name)
- puts
- puts "!"*70
- puts "!!! #{method_name} has a thick skin. There's nothing to heckle."
- puts "!"*70
- puts
+ warning "#{method_name} has a thick skin. There's nothing to heckle."
end
def method_loaded(klass_name, method_name, mutations_left)
- puts
- puts "*"*70
- puts "*** #{klass_name}\##{method_name} loaded with #{mutations_left} possible mutations"
- puts "*"*70
- puts
+ info "#{klass_name}\##{method_name} loaded with #{mutations_left} possible mutations"
end
def remaining_mutations(mutations_left)
puts "#{mutations_left} mutations remaining..."
end
+ def warning(message)
+ puts
+ puts "!" * 70
+ puts "!!! #{message}"
+ puts "!" * 70
+ puts
+ end
+
+ def info(message)
+ puts
+ puts "*"*70
+ puts "*** #{message}"
+ puts "*"*70
+ puts
+ end
+
def no_failures
puts "\nThe following mutations didn't cause test failures:\n"
end
View
@@ -21,11 +21,19 @@ def self.validate(klass_name, method_name = nil)
load_test_files
klass = klass_name.to_class
+ initial_time = Time.now
unless self.new(klass_name).tests_pass? then
abort "Initial run of tests failed... fix and run heckle again"
end
+ running_time = (Time.now - initial_time)
+ adjusted_timeout = (running_time * 2 < 5) ? 5 : (running_time * 2)
+ self.timeout = adjusted_timeout
+
puts "Initial tests pass. Let's rumble."
+ puts "Setting timeout at #{adjusted_timeout} seconds." if @@debug
+
+
methods = method_name ? Array(method_name) : klass.instance_methods(false)
methods.each do |method_name|
View
@@ -64,4 +64,13 @@ def uses_unless
def uses_masignment
one, two = [1, 2]
end
+
+ def uses_infinite_loop?
+ # Converts to a infinite loop actually
+ some_func until true
+ end
+
+ # placeholder
+ def some_func
+ end
end
@@ -16,4 +16,8 @@ def test_uses_strings
@heckled.uses_strings
assert_equal ["Hello, Robert", "Hello, Jeff", "Hi, Frank"], @heckled.names
end
+
+ def test_uses_infinite_loop
+ @heckled.uses_infinite_loop?
+ end
end

0 comments on commit 9b1f0e2

Please sign in to comment.