lib/mutant/mutator/node/send.rb in mutant-0.10.25 vs lib/mutant/mutator/node/send.rb in mutant-0.10.26

- old
+ new

@@ -11,11 +11,11 @@ handle(:send) children :receiver, :selector - SELECTOR_REPLACEMENTS = IceNine.deep_freeze( + SELECTOR_REPLACEMENTS = { :< => %i[== eql? equal?], :<= => %i[< == eql? equal?], :== => %i[eql? equal?], :=== => %i[is_a?], :=~ => %i[match?], @@ -30,29 +30,33 @@ flat_map: %i[map], gsub: %i[sub], is_a?: %i[instance_of?], kind_of?: %i[instance_of?], map: %i[each], - method: %i[public_method], match: %i[match?], + method: %i[public_method], reverse_each: %i[each], reverse_map: %i[map each], reverse_merge: %i[merge], send: %i[public_send __send__], to_a: %i[to_ary], to_h: %i[to_hash], to_i: %i[to_int], to_s: %i[to_str], values_at: %i[fetch_values] - ) + }.freeze.tap { |hash| hash.values(&:freeze) } - RECEIVER_SELECTOR_REPLACEMENTS = IceNine.deep_freeze( + RECEIVER_SELECTOR_REPLACEMENTS = { Date: { parse: %i[jd civil strptime iso8601 rfc3339 xmlschema rfc2822 rfc822 httpdate jisx0301] - } - ) + }.freeze + }.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 def dispatch emit_singletons @@ -82,17 +86,47 @@ mutate_receiver mutate_arguments end def emit_selector_specific_mutations + emit_start_end_with_mutations emit_predicate_mutations emit_array_mutation emit_static_send emit_const_get_mutation emit_integer_mutation emit_dig_mutation emit_double_negation_mutation emit_lambda_mutation + end + + 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) + + return unless argument.type.equal?(:regexp) && ( + regexp_ast = AST::Regexp.expand_regexp_ast(argument) + ) + + regexp_children = regexp_ast.children + + 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 + + def emit_start_with(regexp_nodes) + literal = Mutant::Util.one(regexp_nodes.last.children) + emit_type(receiver, :start_with?, s(:str, literal)) + end + + 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 return unless selector.match?(/\?\z/) && !selector.equal?(:defined?)