diff --git a/Changelog.md b/Changelog.md index 4b7914520..f0c69a11f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,10 @@ * `a.match(/\Atext/)` -> `b.start_with?('text')` * `a.match?(/\Atext/)` -> `b.start_with?('text')` * `a =~ /\Atext/` -> `b.start_with?('text')` + * Add `/static\z/` -> `#end_with?` mutations: + * `a.match(/text\z/)` -> `b.end_with?('text')` + * `a.match?(/text\z/)` -> `b.end_with?('text')` + * `a =~ /text\z/` -> `b.end_with?('text')` # v0.10.25 2021-01-02-03 diff --git a/lib/mutant/mutator/node/send.rb b/lib/mutant/mutator/node/send.rb index fdfbd8aa7..40ccead8c 100644 --- a/lib/mutant/mutator/node/send.rb +++ b/lib/mutant/mutator/node/send.rb @@ -51,7 +51,9 @@ class Send < self } ) - REGEXP_MATCH_METHODS = %i[=~ match match?].freeze + REGEXP_MATCH_METHODS = %i[=~ match match?].freeze + REGEXP_START_WITH_NODES = %i[regexp_bos_anchor regexp_literal_literal].freeze + REGEXP_END_WITH_NODES = %i[regexp_literal_literal regexp_eos_anchor].freeze private @@ -86,7 +88,7 @@ def normal_dispatch end def emit_selector_specific_mutations - emit_start_with_mutation + emit_start_end_with_mutations emit_predicate_mutations emit_array_mutation emit_static_send @@ -97,9 +99,8 @@ def emit_selector_specific_mutations emit_lambda_mutation end - def emit_start_with_mutation - return unless REGEXP_MATCH_METHODS.include?(selector) - return unless arguments.one? + def emit_start_end_with_mutations # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength + return unless REGEXP_MATCH_METHODS.include?(selector) && arguments.one? argument = Mutant::Util.one(arguments) @@ -109,11 +110,22 @@ def emit_start_with_mutation regexp_children = regexp_ast.children - return unless regexp_children.map(&:type).eql?(%i[regexp_bos_anchor regexp_literal_literal]) + case regexp_children.map(&:type) + when REGEXP_START_WITH_NODES + emit_start_with(regexp_children) + when REGEXP_END_WITH_NODES + emit_end_with(regexp_children) + end + end - literal = Mutant::Util.one(regexp_children.last.children) + def emit_start_with(regexp_nodes) + literal = Mutant::Util.one(regexp_nodes.last.children) + emit_type(receiver, :start_with?, s(:str, literal)) + end - emit(s(:send, receiver, :start_with?, s(:str, literal))) + def emit_end_with(regexp_nodes) + literal = Mutant::Util.one(regexp_nodes.first.children) + emit_type(receiver, :end_with?, s(:str, literal)) end def emit_predicate_mutations diff --git a/meta/send.rb b/meta/send.rb index 79c48d663..ddf530e42 100644 --- a/meta/send.rb +++ b/meta/send.rb @@ -811,3 +811,18 @@ mutation 'foo(//)' mutation 'foo(/nomatch\A/)' end + +Mutant::Meta::Example.add :send do + source 'a.match(/foo\z/)' + + singleton_mutations + + mutation 'a.match?(/foo\z/)' + mutation 'a.match' + mutation 'a' + mutation '/foo\z/' + mutation 'a.match(//)' + mutation 'a.match(/nomatch\A/)' + mutation 'self.match(/foo\z/)' + mutation "a.end_with?('foo')" +end