Make mutant run under MRI 1.9.
* Add a Mutant::Loader::Eval that loads code via Kernel#eval * Move Mutnat::Loader to Mutant::Loader::Rubinius (currently not used)
This commit is contained in:
parent
d77042c872
commit
001f3c7d99
14 changed files with 154 additions and 86 deletions
|
@ -4,6 +4,8 @@ language: ruby
|
|||
script: 'bundle exec rake spec'
|
||||
rvm:
|
||||
# - 1.8.7 disabled while spiking mutations
|
||||
- 1.9.2
|
||||
- 1.9.3
|
||||
- rbx-18mode
|
||||
- rbx-19mode
|
||||
notifications:
|
||||
|
|
1
Gemfile
1
Gemfile
|
@ -7,6 +7,7 @@ gem 'abstract_class', :git => 'https://github.com/dkubb/abstract_class.git'
|
|||
gem 'equalizer', :git => 'https://github.com/dkubb/equalizer.git'
|
||||
gem 'anima', :git => 'https://github.com/mbj/anima.git'
|
||||
gem 'to_source', :git => 'https://github.com/mbj/to_source.git'
|
||||
gem 'melbourne', :git => 'https://github.com/mbj/melbourne.git'
|
||||
|
||||
group :development do
|
||||
gem 'rake', '~> 0.9.2'
|
||||
|
|
|
@ -5,8 +5,6 @@ module Mutant
|
|||
|
||||
# Return root ast node
|
||||
#
|
||||
# @param [Rubinius::AST::Node] node
|
||||
#
|
||||
# @return [Rubinis::AST::Script]
|
||||
#
|
||||
# @api private
|
||||
|
@ -34,19 +32,5 @@ module Mutant
|
|||
def initialize(source_path)
|
||||
@source_path = source_path
|
||||
end
|
||||
|
||||
# Return script node
|
||||
#
|
||||
# @param [Rubinius::AST::Node] node
|
||||
#
|
||||
# @return [Rubinius::AST::Script]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def script(node)
|
||||
Rubinius::AST::Script.new(node).tap do |script|
|
||||
script.file = source_path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,7 +48,7 @@ module Mutant
|
|||
root = root_ast
|
||||
block = Rubinius::AST::Block.new(1, [node])
|
||||
root.body = scope_class.new(1, root.name, block)
|
||||
script(root)
|
||||
root
|
||||
end
|
||||
|
||||
# Return unqualified name of scope
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
module Mutant
|
||||
# A method object for inserting an AST into the Rubinius VM
|
||||
#
|
||||
# The idea is to split the steps for a mutation into documented
|
||||
# methods. Also subclasses can override the steps. Also passing
|
||||
# around the root node is not needed with a method object.
|
||||
#
|
||||
# As the initializer does the work there is no need for the
|
||||
# instances of this class to be used outside of this class, hence
|
||||
# the Loader.new method is private and the Loader.run method
|
||||
# returns self.
|
||||
#
|
||||
# Base class for code loaders
|
||||
class Loader
|
||||
include AbstractClass
|
||||
extend MethodObject
|
||||
|
||||
private
|
||||
|
||||
# Run the loader
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
abstract_method :run
|
||||
|
||||
# Initialize and insert mutation into vm
|
||||
#
|
||||
# @param [Rubinius::AST::Script] root
|
||||
|
@ -25,6 +24,45 @@ module Mutant
|
|||
#
|
||||
def initialize(root)
|
||||
@root = Helper.deep_clone(root)
|
||||
run
|
||||
end
|
||||
|
||||
# Eval based loader
|
||||
class Eval < self
|
||||
private
|
||||
|
||||
# Run loader
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run
|
||||
eval(source, TOPLEVEL_BINDING)
|
||||
end
|
||||
|
||||
# Return source
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def source
|
||||
ToSource.to_source(@root)
|
||||
end
|
||||
end
|
||||
|
||||
# Rubinius script node based loaded
|
||||
class Rubinius < self
|
||||
private
|
||||
|
||||
# Run loader
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def run(root)
|
||||
Rubinius.run_script(compiled_code)
|
||||
end
|
||||
|
||||
|
@ -72,5 +110,20 @@ module Mutant
|
|||
compiler.generator.input(@root)
|
||||
end
|
||||
end
|
||||
|
||||
# Return script node
|
||||
#
|
||||
# @param [Rubinius::AST::Node] node
|
||||
#
|
||||
# @return [Rubinius::AST::Script]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def script(node)
|
||||
Rubinius::AST::Script.new(node).tap do |script|
|
||||
script.file = source_path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -75,7 +75,7 @@ module Mutant
|
|||
def method
|
||||
scope.instance_method(method_name)
|
||||
end
|
||||
memoize :method
|
||||
memoize :method, :freezer => :noop
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -61,7 +61,7 @@ module Mutant
|
|||
def method
|
||||
scope.method(method_name)
|
||||
end
|
||||
memoize :method
|
||||
memoize :method, :freezer => :noop
|
||||
|
||||
# Test for node match
|
||||
#
|
||||
|
|
|
@ -21,7 +21,7 @@ module Mutant
|
|||
|
||||
# Return mutated root node
|
||||
#
|
||||
# @return [Rubinius::AST::Script]
|
||||
# @return [Rubinius::AST::Node]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
|
@ -37,7 +37,7 @@ module Mutant
|
|||
# @api private
|
||||
#
|
||||
def insert
|
||||
Loader.run(root)
|
||||
Loader::Eval.run(root)
|
||||
self
|
||||
end
|
||||
|
||||
|
|
|
@ -100,7 +100,8 @@ module Mutant
|
|||
# @api private
|
||||
#
|
||||
def reset
|
||||
Loader.run(original_root)
|
||||
Loader::Eval.run(original_root)
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -11,7 +11,7 @@ describe Mutant, 'code loading' do
|
|||
let(:node) { 'def foo; :bar; end'.to_ast }
|
||||
let(:root) { context.root(node) }
|
||||
|
||||
subject { Mutant::Loader.run(root) }
|
||||
subject { Mutant::Loader::Eval.run(root) }
|
||||
|
||||
before { subject }
|
||||
|
||||
|
|
|
@ -51,13 +51,7 @@ module Zombie
|
|||
node.body = Rubinius::AST::ModuleScope.new(scope.line, node.name, scope.body)
|
||||
end
|
||||
|
||||
script = Rubinius::AST::Script.new(root)
|
||||
script.file = path
|
||||
|
||||
# For some reason loading is not the same as eval...?
|
||||
# eval(root.to_source)
|
||||
|
||||
::Mutant::Loader.run(script)
|
||||
::Mutant::Loader::Eval.run(root)
|
||||
end
|
||||
private_class_method :zombify
|
||||
|
||||
|
|
|
@ -7,13 +7,9 @@ describe Mutant::Context::Scope, '#root' do
|
|||
let(:path) { mock('Path') }
|
||||
let(:node) { mock('Node') }
|
||||
|
||||
let(:constant) { subject.body }
|
||||
let(:scope) { constant.body }
|
||||
let(:scope) { subject.body }
|
||||
let(:scope_body) { scope.body }
|
||||
|
||||
it { should be_a(Rubinius::AST::Script) }
|
||||
its(:file) { should be(path) }
|
||||
|
||||
it 'should wrap the ast under constant' do
|
||||
scope.should be_kind_of(Rubinius::AST::ClassScope)
|
||||
end
|
||||
|
|
33
spec/unit/mutant/loader/eval/class_methods/run_spec.rb
Normal file
33
spec/unit/mutant/loader/eval/class_methods/run_spec.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Mutant::Loader::Eval, '.run' do
|
||||
|
||||
subject { object.run(node) }
|
||||
|
||||
let(:object) { described_class }
|
||||
|
||||
let(:source) do
|
||||
# This test case will blow up when not executed
|
||||
# under toplevel binding.
|
||||
<<-RUBY
|
||||
class SomeNamespace
|
||||
class Bar
|
||||
end
|
||||
|
||||
class SomeOther
|
||||
class Foo < Bar
|
||||
end
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
let(:node) do
|
||||
source.to_ast
|
||||
end
|
||||
|
||||
it 'should load nodes into vm' do
|
||||
subject
|
||||
::SomeNamespace::SomeOther::Foo
|
||||
end
|
||||
end
|
|
@ -1,6 +1,10 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Mutant::Loader, '.run' do
|
||||
describe Mutant::Loader::Rubinius, '.run' do
|
||||
before do
|
||||
pending
|
||||
end
|
||||
|
||||
subject { object.run(node) }
|
||||
|
||||
let(:object) { described_class }
|
Loading…
Add table
Reference in a new issue