From c5cdc05e5e3cd9271f4ac2aea265118ffde9fa93 Mon Sep 17 00:00:00 2001 From: Markus Schirp Date: Mon, 10 Jun 2013 10:15:59 +0200 Subject: [PATCH] Port if node mutator to parser --- lib/mutant/mutator/node.rb | 18 ++- lib/mutant/mutator/node/if.rb | 109 ++++++---------- lib/mutant/mutator/node/literal.rb | 12 -- lib/mutant/mutator/node/send.rb | 118 ------------------ .../mutant/mutator/node/if/mutation_spec.rb | 75 +++++++++++ .../node/if_statement/mutation_spec.rb | 70 ----------- 6 files changed, 126 insertions(+), 276 deletions(-) create mode 100644 spec/unit/mutant/mutator/node/if/mutation_spec.rb delete mode 100644 spec/unit/mutant/mutator/node/if_statement/mutation_spec.rb diff --git a/lib/mutant/mutator/node.rb b/lib/mutant/mutator/node.rb index e9ce398a..43b9fcf2 100644 --- a/lib/mutant/mutator/node.rb +++ b/lib/mutant/mutator/node.rb @@ -43,7 +43,7 @@ module Mutant # def emit_children_mutations Mutator::Util::Array.each(children) do |children| - emit_self(children) + emit_self(*children) end end @@ -85,7 +85,7 @@ module Mutant def emit_child_update(index, update) new_children = children.dup new_children[index]=update - emit_self(new_children) + emit_self(*new_children) end # Emit a new AST node with same class as wrapped node @@ -94,8 +94,8 @@ module Mutant # # @api private # - def emit_self(children) - emit(Parser::AST::Node.new(node.type, children)) + def emit_self(*children) + emit(new_self(*children)) end # Emit a new AST node with NilLiteral class @@ -108,6 +108,16 @@ module Mutant emit(s(:nil)) end + # Return new self typed child + # + # @return [Parser::AST::Node] + # + # @api private + # + def new_self(*children) + Parser::AST::Node.new(node.type, children) + end + end # Node end # Mutator end # Mutant diff --git a/lib/mutant/mutator/node/if.rb b/lib/mutant/mutator/node/if.rb index a5ecfef0..ab0ee5b3 100644 --- a/lib/mutant/mutator/node/if.rb +++ b/lib/mutant/mutator/node/if.rb @@ -6,123 +6,88 @@ module Mutant handle(:if) + CONDITION_INDEX = 0 + IF_BRANCH_INDEX = 1 + ELSE_BRANCH_INDEX = 2 + private - # Emit mutations + # Emit mutations # # @return [undefined] # # @api private # def dispatch - emit_attribute_mutations(:condition) - emit_attribute_mutations(:body) unless nil_literal?(:body) - emit_attribute_mutations(:else) unless nil_literal?(:else) - emit_inverted_condition - emit_deleted_if_branch - emit_deleted_else_branch - emit_true_if_branch - emit_false_if_branch + mutate_condition + mutate_if_branch + mutate_else_branch end - # Test if attribute is non nil literal - # - # @param [Symbol] name - # - # @return [true] - # if attribute value a nil literal - # - # @return [false] - # otherwise - # - # @api private - # - def nil_literal?(name) - node.public_send(name).kind_of?(Rubinius::AST::NilLiteral) - end - - # Emit inverted condition - # - # Especially the same like swap branches but more universal as it also - # covers the case there is no else branch + # Emit conditon mutations # # @return [undefined] # # @api private # - def emit_inverted_condition - emit_self(new_send(condition, :'!'), if_branch, else_branch) + def mutate_condition + mutate_child(CONDITION_INDEX) + emit_self(s(:send, condition, :!), if_branch, else_branch) + emit_self(s(:true), if_branch, else_branch) + emit_self(s(:false), if_branch, else_branch) end - # Emit deleted else branch + # Emit if branch mutations # # @return [undefined] # # @api private # - def emit_deleted_else_branch - emit_self(condition, if_branch, nil) + def mutate_if_branch + mutate_child(IF_BRANCH_INDEX) if if_branch + emit_self(condition, else_branch, nil) + emit_self(condition, if_branch, nil) end - # Emit deleted if branch + # Emit else branch mutations # # @return [undefined] # # @api private # - def emit_deleted_if_branch - body = else_branch || return - emit_self(condition, body, nil) + def mutate_else_branch + mutate_child(ELSE_BRANCH_INDEX) + emit_self(condition, s(:nil), else_branch) end - # Emit true if branch - # - # @return [undefined] - # - # @api private - # - def emit_true_if_branch - emit_self(new(Rubinius::AST::TrueLiteral), if_branch, else_branch) - end - - # Emit false if branch - # - # @return [undefined] - # - # @api private - # - def emit_false_if_branch - emit_self(new(Rubinius::AST::FalseLiteral), if_branch, else_branch) - end - - # Return if_branch of node - # - # @return [Parser::AST::Node] - # - # @api private - # - def if_branch - node.body - end - - # Return condition of node + # Return condition node # # @return [Parser::AST::Node] # # @api private # def condition - node.condition + children[CONDITION_INDEX] end - # Return else body of node + # Return if branch + # + # @return [Parser::AST::Node] + # + # @api private + # + def if_branch + children[IF_BRANCH_INDEX] + end + + # Return else branch # # @return [Parser::AST::Node] # # @api private # def else_branch - node.else + children[ELSE_BRANCH_INDEX] end end # If diff --git a/lib/mutant/mutator/node/literal.rb b/lib/mutant/mutator/node/literal.rb index 77e2b757..9b5bdc4c 100644 --- a/lib/mutant/mutator/node/literal.rb +++ b/lib/mutant/mutator/node/literal.rb @@ -7,18 +7,6 @@ module Mutant private - # Return new float literal - # - # @param [#to_f] value - # - # @return [Parser::Node::FloatLiteral] - # - # @api private - # - def new_float(value) - new(Parser::AST::FloatLiteral, value) - end - # Emit a new node with wrapping class for each entry in values # # @param [Array] values diff --git a/lib/mutant/mutator/node/send.rb b/lib/mutant/mutator/node/send.rb index 92308abc..1dbe5221 100644 --- a/lib/mutant/mutator/node/send.rb +++ b/lib/mutant/mutator/node/send.rb @@ -16,124 +16,6 @@ module Mutant # @api private # def dispatch - emit_receiver - emit_implicit_self_receiver - emit_receiver_mutations - emit_block_mutations - emit_block_absence_mutation - end - - # Emit receiver - # - # @return [undefined] - # - # @api private - # - def emit_receiver - unless to_self? - emit(receiver) - end - end - - # Emit block mutations - # - # @return [undefined] - # - # @api private - # - def emit_block_mutations - emit_attribute_mutations(:block) if node.block - end - - # Emit receiver mutations - # - # @return [undefined] - # - # @api private - # - def emit_receiver_mutations - emit_attribute_mutations(:receiver) - end - - # Emit block absence mutation - # - # @return [undefined] - # - # @api private - # - def emit_block_absence_mutation - dup = dup_node - dup.block = nil - emit(dup) - end - - # Return receiver AST node - # - # @return [Parser::AST::Node] - # - # @api private - # - def receiver - node.receiver - end - - # Return name of call - # - # @return [Symbol] - # - # @api private - # - def name - node.name - end - - # Check if receiver is self - # - # @return [true] - # if receiver is a Rubinius::AST::Self node - # - # @return [false] - # return false otherwise - # - # @api private - # - def to_self? - receiver.kind_of?(Rubinius::AST::Self) - end - - # Emit mutation that replaces explicit send to self with implicit send to self - # - # @example: - # - # # This class does use Foo#a with explicitly specifing the receiver self. - # # But an implicit (privately) call should be used as there is no need for - # # specifing en explicit receiver. - # - # class Foo # Mutation - # def print_a # def print_a - # puts self.a # puts a - # end # end - # - # def a - # :bar - # end - # end - # - # There will not be any exception so the mutant is not killed and such calls where - # implicit receiver should be used will be spotted. - # - # @return [undefined] - # - # @api private - # - def emit_implicit_self_receiver - unless to_self? and !Mutant::KEYWORDS.include?(node.name) - return - end - - mutant = dup_node - mutant.privately = true - emit(mutant) end end # Send diff --git a/spec/unit/mutant/mutator/node/if/mutation_spec.rb b/spec/unit/mutant/mutator/node/if/mutation_spec.rb new file mode 100644 index 00000000..648172b5 --- /dev/null +++ b/spec/unit/mutant/mutator/node/if/mutation_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' + +describe Mutant::Mutator, 'if' do + + before do + Mutant::Random.stub(:hex_string => 'random') + end + + context 'with if and else branches' do + let(:source) { 'if :condition; true; else false; end' } + + let(:mutations) do + mutants = [] + + # mutations of condition + mutants << 'if :srandom; true; else false; end' + mutants << 'if !:condition; true; else false; end' + mutants << 'if nil; true; else false; end' + mutants << 'if true; true; else false; end' + mutants << 'if false; true; else false; end' + + # Deleted else branch + mutants << 'if :condition; true end' + + # Deleted if branch resuting in unless + mutants << 'unless :condition; false; end' + + # Deleted if branch with promoting else branch to if branch + mutants << 'if :condition; false end' + + # mutations of if body + mutants << 'if :condition; false; else false; end' + mutants << 'if :condition; nil; else false; end' + + # mutations of else body + mutants << 'if :condition; true; else true; end' + mutants << 'if :condition; true; else nil; end' + end + + it_should_behave_like 'a mutator' + end + + context 'unless with one branch' do + let(:source) { 'unless :condition; true; end' } + + let(:mutations) do + mutants = [] + mutants << 'unless !:condition; true; end' + mutants << 'unless :srandom; true; end' + mutants << 'unless nil; true; end' + mutants << 'if :condition; true; end' + mutants << 'unless :condition; false; end' + mutants << 'unless :condition; nil; end' + mutants << 'unless true; true; end' + mutants << 'unless false; true; end' + end + + it_should_behave_like 'a mutator' + end + + #context 'if with one branch' do + # let(:source) { 'if condition; true; end' } + + # let(:mutations) do + # mutants = [] + # mutants << 'if !condition; true; end' + # mutants << 'if condition; false; end' + # mutants << 'if condition; nil; end' + # mutants << 'if true; true; end' + # mutants << 'if false; true; end' + # end + + # it_should_behave_like 'a mutator' + #end +end diff --git a/spec/unit/mutant/mutator/node/if_statement/mutation_spec.rb b/spec/unit/mutant/mutator/node/if_statement/mutation_spec.rb deleted file mode 100644 index a22eaf05..00000000 --- a/spec/unit/mutant/mutator/node/if_statement/mutation_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -require 'spec_helper' - -describe Mutant::Mutator, 'if statement' do - - context 'if with two branches' do - let(:source) { 'if self.condition; true; else false; end' } - - let(:mutations) do - mutants = [] - - # mutations of condition - mutants << 'if condition; true; else false; end' - - mutants << 'if !self.condition; true; else false; end' - - # Deleted else branch - mutants << 'if self.condition; true end' - - # Deleted if branch with promoting else branch to if branch - mutants << 'if self.condition; false end' - - # mutations of body - mutants << 'if self.condition; false; else false; end' - mutants << 'if self.condition; nil; else false; end' - - # mutations of else body - mutants << 'if self.condition; true; else true; end' - mutants << 'if self.condition; true; else nil; end' - - # mutation of condition to always be true - mutants << 'if true; true; else false; end' - - # mutation of condition to always be false - mutants << 'if false; true; else false; end' - end - - it_should_behave_like 'a mutator' - end - - context 'unless with one branch' do - let(:source) { 'unless condition; true; end' } - - let(:mutations) do - mutants = [] - mutants << 'unless !condition; true; end' - mutants << 'if condition; true; end' - mutants << 'unless condition; false; end' - mutants << 'unless condition; nil; end' - mutants << 'unless true; true; end' - mutants << 'unless false; true; end' - end - - it_should_behave_like 'a mutator' - end - - context 'if with one branch' do - let(:source) { 'if condition; true; end' } - - let(:mutations) do - mutants = [] - mutants << 'if !condition; true; end' - mutants << 'if condition; false; end' - mutants << 'if condition; nil; end' - mutants << 'if true; true; end' - mutants << 'if false; true; end' - end - - it_should_behave_like 'a mutator' - end -end