From d040864e9376c561248c395819d7f7c93566ee8e Mon Sep 17 00:00:00 2001 From: Markus Schirp Date: Sat, 27 Apr 2013 17:43:17 +0200 Subject: [PATCH] Refactor method matcher And add proper unit specs --- lib/mutant/matcher/method.rb | 52 ++----- .../matcher/method/instance/each_spec.rb | 138 ++++++++++++++++++ 2 files changed, 150 insertions(+), 40 deletions(-) create mode 100644 spec/unit/mutant/matcher/method/instance/each_spec.rb diff --git a/lib/mutant/matcher/method.rb b/lib/mutant/matcher/method.rb index 058eb476..0a4b6870 100644 --- a/lib/mutant/matcher/method.rb +++ b/lib/mutant/matcher/method.rb @@ -2,7 +2,7 @@ module Mutant class Matcher # Matcher for subjects that are a specific method class Method < self - include Adamantium::Flat, Equalizer.new(:identification) + include Adamantium::Flat, Concord.new(:scope, :method) # Methods within rbx kernel directory are precompiled and their source # cannot be accessed via reading source location @@ -29,47 +29,8 @@ module Mutant self end - # Return method - # - # @return [UnboundMethod, Method] - # - # @api private - # - attr_reader :method - - # Return scope - # - # @return [Class|Module] - # - # @api private - # - attr_reader :scope - - # Return method name - # - # @return [String] - # - # @api private - # - def method_name - method.name - end - private - # Initialize method filter - # - # @param [Class|Module] scope - # @param [Method, UnboundMethod] method - # - # @return [undefined] - # - # @api private - # - def initialize(scope, method) - @scope, @method = scope, method - end - # Test if method is skipped # # @return [true] @@ -90,6 +51,16 @@ module Mutant false end + # Return method name + # + # @return [String] + # + # @api private + # + def method_name + method.name + end + # Return context # # @return [Context::Scope] @@ -171,6 +142,7 @@ module Mutant end last_match end + end end end diff --git a/spec/unit/mutant/matcher/method/instance/each_spec.rb b/spec/unit/mutant/matcher/method/instance/each_spec.rb new file mode 100644 index 00000000..f1aeb37e --- /dev/null +++ b/spec/unit/mutant/matcher/method/instance/each_spec.rb @@ -0,0 +1,138 @@ +require 'spec_helper' + +describe Mutant::Matcher::Method::Instance, '#each' do + let(:object) { described_class.new(scope, method) } + let(:method) { scope.instance_method(method_name) } + + let(:yields) { [] } + + let(:namespace) do + klass = self.class + end + + let(:scope) { self.class::Foo } + + subject { object.each { |subject| yields << subject } } + + shared_examples_for 'a method match' do + before do + subject + end + + let(:node) { mutation_subject.node } + let(:context) { mutation_subject.context } + let(:mutation_subject) { yields.first } + + it 'should return one subject' do + yields.size.should be(1) + end + + it 'should have correct method name' do + node.name.should eql(method_name) + end + + it 'should have correct line number' do + (node.line - base).should eql(method_line) + end + + it 'should have correct arity' do + node.arguments.required.length.should eql(method_arity) + end + + it 'should have correct scope in context' do + context.send(:scope).should eql(scope) + end + + it 'should have the correct node class' do + node.should be_a(node_class) + end + end + + let(:node_class) { Rubinius::AST::Define } + let(:method_name) { :bar } + let(:method_arity) { 0 } + + context 'when method is defined once' do + let(:base) { __LINE__ } + class self::Foo + def bar; end + end + + let(:method_line) { 2 } + + it_should_behave_like 'a method match' + end + + context 'when method is defined multiple times' do + context 'on differend lines' do + let(:base) { __LINE__ } + class self::Foo + def bar; end + def bar(arg); end + end + + let(:method_line) { 3 } + let(:method_arity) { 1 } + + it_should_behave_like 'a method match' + 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(:method_arity) { 1 } + + it_should_behave_like 'a method match' + end + + context 'on the same line with differend scope' do + let(:base) { __LINE__ } + class self::Foo + def self.bar; end; def bar(arg); end + end + + let(:method_line) { 2 } + let(:method_arity) { 1 } + + it_should_behave_like 'a method match' + end + + context 'when nested' do + let(:pattern) { 'Foo::Bar#baz' } + + context 'in class' do + let(:base) { __LINE__ } + class 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 match' + 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 match' + end + end + end +end