Skip method subjects defined in blocks
* No easy way to insert mutants on these via current monkey patching loader * The blocks are typically part of a method building library when those libraries are mutated the def/defs nodes will be part of an mutated block that is included in a subject. [fix #254]
This commit is contained in:
parent
bfac03f29d
commit
a2de0442f6
6 changed files with 154 additions and 129 deletions
|
@ -1,3 +1,3 @@
|
|||
---
|
||||
threshold: 18
|
||||
total_score: 1094
|
||||
total_score: 1098
|
||||
|
|
|
@ -3,7 +3,7 @@ module Mutant
|
|||
# Matcher for subjects that are a specific method
|
||||
class Method < self
|
||||
include Adamantium::Flat, Concord::Public.new(:env, :scope, :target_method)
|
||||
include Equalizer.new(:identification)
|
||||
include AST::NodePredicates, Equalizer.new(:identification)
|
||||
|
||||
# Methods within rbx kernel directory are precompiled and their source
|
||||
# cannot be accessed via reading source location. Same for methods created by eval.
|
||||
|
@ -40,7 +40,10 @@ module Mutant
|
|||
def skip?
|
||||
location = source_location
|
||||
if location.nil? || BLACKLIST.match(location.first)
|
||||
env.warn(format('%s does not have valid source location unable to emit matcher', target_method.inspect))
|
||||
env.warn(format('%s does not have valid source location unable to emit subject', target_method.inspect))
|
||||
true
|
||||
elsif matched_node_path.any?(&method(:n_block?))
|
||||
env.warn(format('%s is defined from a 3rd party lib unable to emit subject', target_method.inspect))
|
||||
true
|
||||
else
|
||||
false
|
||||
|
|
|
@ -17,7 +17,7 @@ RSpec.shared_examples_for 'a method matcher' do
|
|||
end
|
||||
|
||||
it 'should have correct line number' do
|
||||
expect(node.location.expression.line - base).to eql(method_line)
|
||||
expect(node.location.expression.line).to eql(method_line)
|
||||
end
|
||||
|
||||
it 'should have correct arity' do
|
||||
|
|
|
@ -11,10 +11,10 @@ RSpec.describe Mutant::Matcher::Method::Instance do
|
|||
let(:method) { scope.instance_method(method_name) }
|
||||
let(:yields) { [] }
|
||||
let(:namespace) { self.class }
|
||||
let(:scope) { self.class::Foo }
|
||||
let(:type) { :def }
|
||||
let(:method_name) { :bar }
|
||||
let(:method_name) { :foo }
|
||||
let(:method_arity) { 0 }
|
||||
let(:base) { TestApp::InstanceMethodTests }
|
||||
|
||||
def name
|
||||
node.children[0]
|
||||
|
@ -36,109 +36,79 @@ RSpec.describe Mutant::Matcher::Method::Instance do
|
|||
it 'does warn' do
|
||||
subject
|
||||
expect(reporter.warn_calls.last).to(
|
||||
eql("#{method.inspect} does not have valid source location unable to emit matcher")
|
||||
eql("#{method.inspect} does not have valid source location unable to emit subject")
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when method is defined once' do
|
||||
let(:base) { __LINE__ }
|
||||
class self::Foo
|
||||
def bar; end
|
||||
end
|
||||
|
||||
let(:method_line) { 2 }
|
||||
let(:scope) { base::DefinedOnce }
|
||||
let(:method_line) { 7 }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
end
|
||||
|
||||
context 'when method is defined once with a memoizer' do
|
||||
let(:base) { __LINE__ }
|
||||
class self::Foo
|
||||
def bar; end
|
||||
include Adamantium
|
||||
memoize :bar
|
||||
end
|
||||
|
||||
let(:method_line) { 2 }
|
||||
let(:scope) { base::WithMemoizer }
|
||||
let(:method_line) { 12 }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
end
|
||||
|
||||
context 'when method is defined multiple times' do
|
||||
context 'on different lines' do
|
||||
let(:base) { __LINE__ }
|
||||
class self::Foo
|
||||
def bar
|
||||
end
|
||||
|
||||
def bar(_arg)
|
||||
end
|
||||
end
|
||||
|
||||
let(:method_line) { 5 }
|
||||
let(:scope) { base::DefinedMultipleTimes::DifferentLines }
|
||||
let(:method_line) { 21 }
|
||||
let(:method_arity) { 1 }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
end
|
||||
|
||||
context 'on the same line' do
|
||||
let(:base) { __LINE__ }
|
||||
class self::Foo
|
||||
def bar; end; def bar(_arg); end
|
||||
end
|
||||
|
||||
let(:method_line) { 2 }
|
||||
let(:scope) { base::DefinedMultipleTimes::SameLineSameScope }
|
||||
let(:method_line) { 26 }
|
||||
let(:method_arity) { 1 }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
end
|
||||
|
||||
context 'on the same line with different scope' do
|
||||
let(:base) { __LINE__ }
|
||||
class self::Foo
|
||||
def self.bar; end; def bar(_arg); end
|
||||
end
|
||||
|
||||
let(:method_line) { 2 }
|
||||
let(:scope) { base::DefinedMultipleTimes::SameLineDifferentScope }
|
||||
let(:method_line) { 30 }
|
||||
let(:method_arity) { 1 }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
end
|
||||
|
||||
context 'when nested' do
|
||||
let(:pattern) { 'Foo::Bar#baz' }
|
||||
context 'in module eval' do
|
||||
let(:scope) { base::InModuleEval }
|
||||
|
||||
context 'in class' do
|
||||
let(:base) { __LINE__ }
|
||||
class self::Foo
|
||||
class Bar
|
||||
def baz
|
||||
it 'does not emit matcher' do
|
||||
subject
|
||||
expect(yields.length).to be(0)
|
||||
end
|
||||
|
||||
it 'does warn' do
|
||||
subject
|
||||
expect(reporter.warn_calls.last).to(
|
||||
eql("#{method.inspect} is defined from a 3rd party lib unable to emit subject")
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
let(:method_line) { 3 }
|
||||
let(:method_name) { :baz }
|
||||
let(:scope) { self.class::Foo::Bar }
|
||||
context 'in class eval' do
|
||||
let(:scope) { base::InClassEval }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
it 'does not emit matcher' do
|
||||
subject
|
||||
expect(yields.length).to be(0)
|
||||
end
|
||||
|
||||
context 'in module' do
|
||||
let(:base) { __LINE__ }
|
||||
module self::Foo
|
||||
class Bar
|
||||
def baz
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:method_line) { 3 }
|
||||
let(:method_name) { :baz }
|
||||
let(:scope) { self.class::Foo::Bar }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
it 'does warn' do
|
||||
subject
|
||||
expect(reporter.warn_calls.last).to(
|
||||
eql("#{method.inspect} is defined from a 3rd party lib unable to emit subject")
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,10 +6,10 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|||
let(:method) { scope.method(method_name) }
|
||||
let(:env) { Fixtures::TEST_ENV }
|
||||
let(:yields) { [] }
|
||||
let(:namespace) { self.class }
|
||||
let(:scope) { self.class::Foo }
|
||||
let(:type) { :defs }
|
||||
let(:method_name) { :foo }
|
||||
let(:method_arity) { 0 }
|
||||
let(:base) { TestApp::SingletonMethodTests }
|
||||
|
||||
def name
|
||||
node.children[1]
|
||||
|
@ -22,14 +22,8 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|||
context 'on singleton methods' do
|
||||
|
||||
context 'when also defined on lvar' do
|
||||
let(:base) { __LINE__ }
|
||||
class self::Foo
|
||||
a = Object.new
|
||||
def a.bar; end; def self.bar; end
|
||||
end
|
||||
|
||||
let(:method_name) { :bar }
|
||||
let(:method_line) { 3 }
|
||||
let(:scope) { base::AlsoDefinedOnLvar }
|
||||
let(:method_line) { 63 }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
|
||||
|
@ -42,13 +36,8 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|||
end
|
||||
|
||||
context 'when defined on self' do
|
||||
let(:base) { __LINE__ }
|
||||
class self::Foo
|
||||
def self.bar; end
|
||||
end
|
||||
|
||||
let(:method_name) { :bar }
|
||||
let(:method_line) { 2 }
|
||||
let(:scope) { base::DefinedOnSelf }
|
||||
let(:method_line) { 58 }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
end
|
||||
|
@ -56,34 +45,15 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|||
context 'when defined on constant' do
|
||||
|
||||
context 'inside namespace' do
|
||||
let(:base) { __LINE__ }
|
||||
module self::Namespace
|
||||
class Foo
|
||||
def Foo.bar
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:scope) { self.class::Namespace::Foo }
|
||||
let(:method_name) { :bar }
|
||||
let(:method_line) { 3 }
|
||||
let(:scope) { base::DefinedOnConstant::InsideNamespace }
|
||||
let(:method_line) { 68 }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
end
|
||||
|
||||
context 'outside namespace' do
|
||||
let(:base) { __LINE__ }
|
||||
module self::Namespace
|
||||
class Foo
|
||||
end
|
||||
|
||||
def Foo.bar
|
||||
end
|
||||
end
|
||||
|
||||
let(:method_name) { :bar }
|
||||
let(:method_line) { 5 }
|
||||
let(:scope) { self.class::Namespace::Foo }
|
||||
let(:method_line) { 75 }
|
||||
let(:scope) { base::DefinedOnConstant::OutsideNamespace }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
end
|
||||
|
@ -91,21 +61,9 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|||
|
||||
context 'when defined multiple times in the same line' do
|
||||
context 'with method on different scope' do
|
||||
let(:base) { __LINE__ }
|
||||
module self::Namespace
|
||||
module Foo; end
|
||||
module Bar
|
||||
def self.baz
|
||||
end
|
||||
def Foo.baz(_arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:scope) { self.class::Namespace::Bar }
|
||||
let(:method_name) { :baz }
|
||||
let(:method_line) { 4 }
|
||||
let(:method_arity) { 0 }
|
||||
let(:scope) { base::DefinedMultipleTimes::SameLine::DifferentScope }
|
||||
let(:method_line) { 94 }
|
||||
let(:method_arity) { 1 }
|
||||
|
||||
it_should_behave_like 'a method matcher'
|
||||
end
|
||||
|
|
|
@ -2,6 +2,100 @@
|
|||
|
||||
# Namespace for test application
|
||||
module TestApp
|
||||
module InstanceMethodTests
|
||||
module DefinedOnce
|
||||
def foo; end
|
||||
end
|
||||
|
||||
class WithMemoizer
|
||||
include Adamantium
|
||||
def foo; end
|
||||
memoize :foo
|
||||
end
|
||||
|
||||
module DefinedMultipleTimes
|
||||
class DifferentLines
|
||||
def foo
|
||||
end
|
||||
|
||||
def foo(_arg)
|
||||
end
|
||||
end
|
||||
|
||||
class SameLineSameScope
|
||||
def foo; end; def foo(_arg); end
|
||||
end
|
||||
|
||||
class SameLineDifferentScope
|
||||
def self.foo; end; def foo(_arg); end
|
||||
end
|
||||
end
|
||||
|
||||
class InClassEval
|
||||
class_eval do
|
||||
def foo
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class InModuleEval
|
||||
module_eval do
|
||||
def foo
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class InInstanceEval
|
||||
module_eval do
|
||||
def foo
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module SingletonMethodTests
|
||||
module DefinedOnSelf
|
||||
def self.foo; end
|
||||
end
|
||||
|
||||
module AlsoDefinedOnLvar
|
||||
a = Object.new
|
||||
def a.foo; end; def self.foo; end
|
||||
end
|
||||
|
||||
module DefinedOnConstant
|
||||
module InsideNamespace
|
||||
def InsideNamespace.foo
|
||||
end
|
||||
end
|
||||
|
||||
module OutsideNamespace
|
||||
end
|
||||
|
||||
def OutsideNamespace.foo
|
||||
end
|
||||
end
|
||||
|
||||
module DefinedMultipleTimes
|
||||
module DifferentLines
|
||||
def self.foo
|
||||
end
|
||||
|
||||
def self.foo(_arg)
|
||||
end
|
||||
end
|
||||
|
||||
module SameLine
|
||||
module SameScope
|
||||
def self.foo; end; def self.foo(_arg); end;
|
||||
end
|
||||
|
||||
module DifferentScope
|
||||
def self.foo; end; def DifferentScope.foo(_arg); end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'test_app/literal'
|
||||
|
|
Loading…
Reference in a new issue