diff --git a/lib/mutant/meta.rb b/lib/mutant/meta.rb index aaff26f8..fdbaeb9c 100644 --- a/lib/mutant/meta.rb +++ b/lib/mutant/meta.rb @@ -18,9 +18,9 @@ module Mutant # @return [undefined] # # rubocop:disable Performance/Caller - def self.add(type, &block) + def self.add(*types, &block) file = caller.first.split(':in', 2).first - ALL << DSL.call(file, type, block) + ALL << DSL.call(file, Set.new(types), block) end Pathname.glob(Pathname.new(__dir__).parent.parent.join('meta', '*.rb')) diff --git a/lib/mutant/meta/example.rb b/lib/mutant/meta/example.rb index 5787aa97..5e2ab277 100644 --- a/lib/mutant/meta/example.rb +++ b/lib/mutant/meta/example.rb @@ -3,7 +3,7 @@ module Mutant module Meta class Example - include Adamantium, Anima.new(:file, :node, :node_type, :expected) + include Adamantium, Anima.new(:file, :node, :types, :expected) # Verification instance for example # diff --git a/lib/mutant/meta/example/dsl.rb b/lib/mutant/meta/example/dsl.rb index 3455d070..262763b2 100644 --- a/lib/mutant/meta/example/dsl.rb +++ b/lib/mutant/meta/example/dsl.rb @@ -9,9 +9,12 @@ module Mutant # Run DSL on block # + # @param [Pathname] file + # @param [Set] types + # # @return [Example] - def self.call(file, type, block) - instance = new(file, type) + def self.call(file, types, block) + instance = new(file, types) instance.instance_eval(&block) instance.example end @@ -21,9 +24,9 @@ module Mutant # Initialize object # # @return [undefined] - def initialize(file, type) + def initialize(file, types) @file = file - @type = type + @types = types @node = nil @expected = [] end @@ -37,10 +40,10 @@ module Mutant def example fail 'source not defined' unless @node Example.new( - file: @file, - node: @node, - node_type: @type, - expected: @expected + file: @file, + node: @node, + types: @types, + expected: @expected ) end diff --git a/meta/regexp.rb b/meta/regexp.rb index 8ed5dae0..8952a5a1 100644 --- a/meta/regexp.rb +++ b/meta/regexp.rb @@ -80,10 +80,3 @@ Pathname .glob(Pathname.new(__dir__).join('regexp', '*.rb')) .sort .each(&Kernel.public_method(:require)) - -# Re-register examples for all regular expression nodes for node_type `:regexp` -Mutant::Meta::Example::ALL.each do |example| - next unless example.node_type.to_s.start_with?('regexp_') - - Mutant::Meta::Example::ALL << example.with(node_type: :regexp) -end diff --git a/meta/regexp/character_types.rb b/meta/regexp/character_types.rb index 4255e759..240e9d31 100644 --- a/meta/regexp/character_types.rb +++ b/meta/regexp/character_types.rb @@ -12,7 +12,7 @@ mutations = { mutations = mutations.merge(mutations.invert) mutations.each do |(source_type, source_mutation), (_, regexp_mutation)| - Mutant::Meta::Example.add source_type do + Mutant::Meta::Example.add :regexp, source_type do source(source_mutation) singleton_mutations diff --git a/spec/unit/mutant/meta/example/dsl_spec.rb b/spec/unit/mutant/meta/example/dsl_spec.rb index 6e8d3daa..182e1bb1 100644 --- a/spec/unit/mutant/meta/example/dsl_spec.rb +++ b/spec/unit/mutant/meta/example/dsl_spec.rb @@ -2,19 +2,19 @@ RSpec.describe Mutant::Meta::Example::DSL do describe '.call' do - subject { described_class.call(file, type, block) } + subject { described_class.call(file, types, block) } - let(:file) { 'foo.rb' } - let(:node) { s(:false) } - let(:type) { node.type } - let(:expected) { [] } + let(:file) { 'foo.rb' } + let(:node) { s(:false) } + let(:types) { Set.new([node.type]) } + let(:expected) { [] } let(:expected_example) do Mutant::Meta::Example.new( - file: file, - node: node, - node_type: type, - expected: expected + file: file, + node: node, + types: types, + expected: expected ) end diff --git a/spec/unit/mutant/meta/example/verification_spec.rb b/spec/unit/mutant/meta/example/verification_spec.rb index d38809f7..c331af1c 100644 --- a/spec/unit/mutant/meta/example/verification_spec.rb +++ b/spec/unit/mutant/meta/example/verification_spec.rb @@ -5,10 +5,10 @@ RSpec.describe Mutant::Meta::Example::Verification do let(:example) do Mutant::Meta::Example.new( - file: 'foo.rb', - node: s(:true), - node_type: :true, - expected: expected_nodes + file: 'foo.rb', + node: s(:true), + types: [:true], + expected: expected_nodes ) end diff --git a/spec/unit/mutant/meta/example_spec.rb b/spec/unit/mutant/meta/example_spec.rb index 4179d868..fa39e7f8 100644 --- a/spec/unit/mutant/meta/example_spec.rb +++ b/spec/unit/mutant/meta/example_spec.rb @@ -3,10 +3,10 @@ RSpec.describe Mutant::Meta::Example do let(:object) do described_class.new( - file: file, - node: node, - node_type: node.type, - expected: mutation_nodes + file: file, + node: node, + types: [node.type], + expected: mutation_nodes ) end diff --git a/spec/unit/mutant/mutator/node_spec.rb b/spec/unit/mutant/mutator/node_spec.rb index cb569185..a678e3f5 100644 --- a/spec/unit/mutant/mutator/node_spec.rb +++ b/spec/unit/mutant/mutator/node_spec.rb @@ -1,15 +1,20 @@ # frozen_string_literal: true -Mutant::Meta::Example::ALL.each.group_by(&:node_type).each do |type, examples| - RSpec.describe Mutant::Mutator::REGISTRY.lookup(type) do - toplevel_nodes = examples.map { |example| example.node.type }.uniq +aggregate = Hash.new { |hash, key| hash[key] = [] } - it "generates the correct mutations on #{toplevel_nodes} toplevel examples" do +Mutant::Meta::Example::ALL + .each_with_object(aggregate) do |example, agg| + example.types.each do |type| + agg[Mutant::Mutator::REGISTRY.lookup(type)] << example + end + end + +aggregate.each do |mutator, examples| + RSpec.describe mutator do + it 'generates expected mutations' do examples.each do |example| verification = example.verification - unless verification.success? - fail verification.error_report - end + fail verification.error_report unless verification.success? end end end