Remove guard via identity

* Simplify spec helper via mutation verifier class
* There was no need to guard via mapped identity anymore.
This commit is contained in:
Markus Schirp 2014-04-12 01:12:49 +00:00
parent c1f3295013
commit a3b558bec0
7 changed files with 128 additions and 114 deletions

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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')

View file

@ -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<Parser::AST::Node>]
#
# @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<Parser::AST::Node>]
#
# @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