From a3b558bec0cfec2b1dae903b59dbca49285eb04b Mon Sep 17 00:00:00 2001 From: Markus Schirp Date: Sat, 12 Apr 2014 01:12:49 +0000 Subject: [PATCH] Remove guard via identity * Simplify spec helper via mutation verifier class * There was no need to guard via mapped identity anymore. --- Gemfile | 2 + lib/mutant/mutator.rb | 28 +-------- lib/mutant/mutator/node/rescue.rb | 12 ---- lib/mutant/node_helpers.rb | 6 +- spec/shared/mutator_behavior.rb | 94 +++++++----------------------- spec/spec_helper.rb | 4 +- spec/support/mutation_verifier.rb | 96 +++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 114 deletions(-) create mode 100644 spec/support/mutation_verifier.rb diff --git a/Gemfile b/Gemfile index 39e6cb41..75557ecb 100644 --- a/Gemfile +++ b/Gemfile @@ -4,6 +4,8 @@ source 'https://rubygems.org' gem 'mutant', path: '.' +gem 'unparser', git: 'https://github.com/mbj/unparser.git' + gemspec name: 'mutant' gem 'devtools', git: 'https://github.com/rom-rb/devtools.git' diff --git a/lib/mutant/mutator.rb b/lib/mutant/mutator.rb index 9e25c648..b396338d 100644 --- a/lib/mutant/mutator.rb +++ b/lib/mutant/mutator.rb @@ -33,18 +33,6 @@ module Mutant end private_class_method :handle - # Return identity of object (for deduplication) - # - # @param [Object] object - # - # @return [Object] - # - # @api private - # - def self.identity(object) - object - end - # Return input # # @return [Object] @@ -92,7 +80,7 @@ module Mutant # @api private # def new?(object) - !@seen.include?(identity(object)) + !@seen.include?(object) end # Add object to guarded values @@ -104,19 +92,7 @@ module Mutant # @api private # def guard(object) - @seen << identity(object) - end - - # Return identity for input - # - # @param [Object] input - # - # @return [Object] - # - # @api private - # - def identity(input) - self.class.identity(input) + @seen << object end # Dispatch node generations diff --git a/lib/mutant/mutator/node/rescue.rb b/lib/mutant/mutator/node/rescue.rb index d4e3e127..8626423c 100644 --- a/lib/mutant/mutator/node/rescue.rb +++ b/lib/mutant/mutator/node/rescue.rb @@ -8,18 +8,6 @@ module Mutant handle :rescue - # Return identity - # - # @param [Parser::AST::Node] node - # - # @return [String] - # - # @api private - # - def self.identity(node) - super(NodeHelpers.s(:kwbegin, node)) - end - end # Rescue end # Node end # Mutator diff --git a/lib/mutant/node_helpers.rb b/lib/mutant/node_helpers.rb index c538f441..c1b90e75 100644 --- a/lib/mutant/node_helpers.rb +++ b/lib/mutant/node_helpers.rb @@ -18,13 +18,13 @@ module Mutant module_function :s NAN = - s(:send, s(:float, 0.0), :/, s(:args, s(:float, 0.0))) + s(:send, s(:float, 0.0), :/, s(:float, 0.0)) INFINITY = - s(:send, s(:float, 1.0), :/, s(:args, s(:float, 0.0))) + s(:send, s(:float, 1.0), :/, s(:float, 0.0)) NEW_OBJECT = s(:send, s(:const, s(:cbase), :Object), :new) NEGATIVE_INFINITY = - s(:send, s(:float, -1.0), :/, s(:args, s(:float, 0.0))) + s(:send, s(:float, -1.0), :/, s(:float, 0.0)) RAISE = s(:send, nil, :raise) diff --git a/spec/shared/mutator_behavior.rb b/spec/shared/mutator_behavior.rb index 9dade885..97ae66d2 100644 --- a/spec/shared/mutator_behavior.rb +++ b/spec/shared/mutator_behavior.rb @@ -1,52 +1,12 @@ -# encoding: utf-8 - -class Subject - - include Equalizer.new(:source) - - Undefined = Object.new.freeze - - attr_reader :source - - def self.coerce(input) - case input - when Parser::AST::Node - new(input) - when String - new(Parser::CurrentRuby.parse(input)) - else - raise - end - end - - def to_s - "#{@node.inspect}\n#{@source}" - end - - def initialize(node) - source = Unparser.unparse(node) - @node, @source = node, source - end - - def assert_transitive! - generated = Unparser.generate(@node) - parsed = Parser::CurrentRuby.parse(generated) - again = Unparser.generate(parsed) - unless generated == again - # mostly an unparser bug! - fail sprintf("Untransitive:\n%s\n---\n%s", generated, again) - end - self - end -end +# encoding: UTF-8 shared_examples_for 'a mutator' do - subject { object.each(node) { |item| yields << item } } + subject { object.each(node, &yields.method(:<<)) } let(:yields) { [] } let(:object) { described_class } - unless instance_methods.map(&:to_s).include?('node') + unless instance_methods.include?(:node) let(:node) { parse(source) } end @@ -57,42 +17,32 @@ shared_examples_for 'a mutator' do it { should be_instance_of(to_enum.class) } - let(:expected_mutations) do - mutations.map(&Subject.method(:coerce)) + def coerce(input) + case input + when String + Parser::CurrentRuby.parse(input) + when Parser::AST::Node + input + else + raise + end end - let(:generated_mutations) do + def normalize(node) + Unparser::Preprocessor.run(node) + end + + let(:expected_mutations) do + mutations.map(&method(:coerce)).map(&method(:normalize)) end it 'generates the expected mutations' do + generated_mutations = subject.map(&method(:normalize)) - generated = subject.map { |node| Subject.new(node) } + verifier = MutationVerifier.new(node, expected_mutations, generated_mutations) - missing = expected_mutations - generated - unexpected = generated - expected_mutations - - message = [] - - if missing.any? - message << sprintf('Missing mutations (%i):', missing.length) - message.concat(missing) - end - - if unexpected.any? - message << sprintf('Unexpected mutations (%i):', unexpected.length) - message.concat(unexpected) - end - - if message.any? - - message = sprintf( - "Original:\n%s\n%s\n-----\n%s", - generate(node), - node.inspect, - message.join("\n-----\n") - ) - - fail message + unless verifier.success? + fail verifier.error_report end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 19813314..fd3e1369 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -21,8 +21,10 @@ if ENV['COVERAGE'] == 'true' end end -require 'equalizer' +require 'concord' +require 'adamantium' require 'devtools/spec_helper' +require 'unparser/cli' require 'mutant' $LOAD_PATH << File.join(TestApp.root, 'lib') diff --git a/spec/support/mutation_verifier.rb b/spec/support/mutation_verifier.rb new file mode 100644 index 00000000..a07196fe --- /dev/null +++ b/spec/support/mutation_verifier.rb @@ -0,0 +1,96 @@ +# encoding: UTF-8 + +class MutationVerifier + include Adamantium::Flat, Concord.new(:original_node, :expected, :generated) + + # Test if mutation was verified successfully + # + # @return [Boolean] + # + # @api private + # + def success? + unparser.success? && missing.empty? && unexpected.empty? + end + + # Return error report + # + # @return [String] + # + # @api private + # + def error_report + unless unparser.success? + return unparser.error_report + end + mutation_report + end + +private + + # Return unexpected mutationso + # + # @return [Array] + # + # @api private + # + def unexpected + generated - expected + end + memoize :unexpected + + # Return mutation report + # + # @return [String] + # + # @api private + # + def mutation_report + message = ['Original:', original_node.inspect] + if missing.any? + message << 'Missing mutations:' + message << missing.map(&method(:format_mutation)).join("\n-----\n") + end + if unexpected.any? + message << 'Unexpected mutations:' + message << unexpected.map(&method(:format_mutation)).join("\n-----\n") + end + message.join("\n======\n") + end + + # Format mutation + # + # @return [String] + # + # @api private + # + def format_mutation(node) + [ + node.inspect, + Unparser.unparse(node) + ].join("\n") + end + + # Return missing mutationso + # + # @return [Array] + # + # @api private + # + def missing + expected - generated + end + memoize :missing + + # Return unparser verifier + # + # @return [Unparser::CLI::Source] + # + # @api private + # + def unparser + Unparser::CLI::Source::Node.new(original_node) + end + memoize :unparser +end # MutationVerifier +