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:
parent
c1f3295013
commit
a3b558bec0
7 changed files with 128 additions and 114 deletions
2
Gemfile
2
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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
96
spec/support/mutation_verifier.rb
Normal file
96
spec/support/mutation_verifier.rb
Normal 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
|
||||
|
Loading…
Reference in a new issue