From 8cf5e0f079002ce7bd838817c207e9bc8ca32932 Mon Sep 17 00:00:00 2001 From: Markus Schirp Date: Mon, 24 Dec 2018 15:41:15 +0000 Subject: [PATCH] Change to skip regexp bodies regexp_parser does not accept [Fix #813] --- lib/mutant/ast/regexp.rb | 7 ++++++- lib/mutant/mutator/node/literal/regex.rb | 8 ++++---- meta/regexp.rb | 9 +++++++++ spec/integrations.yml | 10 +--------- spec/unit/mutant/ast/regexp/parse_spec.rb | 16 ++++++++++++++-- 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/lib/mutant/ast/regexp.rb b/lib/mutant/ast/regexp.rb index eee61cfc..39a8aa67 100644 --- a/lib/mutant/ast/regexp.rb +++ b/lib/mutant/ast/regexp.rb @@ -8,10 +8,15 @@ module Mutant # # @param regexp [String] # - # @return [Regexp::Expression] + # @return [Regexp::Expression, nil] + # + # rubocop:disable Lint/HandleExceptions def self.parse(regexp) ::Regexp::Parser.parse(regexp) + # regexp_parser is more strict than MRI + rescue ::Regexp::Scanner::PrematureEndError end + # rubocop:enable Lint/HandleExceptions # Convert expression into ast node # diff --git a/lib/mutant/mutator/node/literal/regex.rb b/lib/mutant/mutator/node/literal/regex.rb index 39d779ea..5d0e4e9a 100644 --- a/lib/mutant/mutator/node/literal/regex.rb +++ b/lib/mutant/mutator/node/literal/regex.rb @@ -42,7 +42,7 @@ module Mutant # # @return [undefined] def mutate_body - return unless body.all?(&method(:n_str?)) + return unless body.all?(&method(:n_str?)) && body_ast Mutator.mutate(body_ast).each do |mutation| source = AST::Regexp.to_expression(mutation).to_s @@ -52,14 +52,14 @@ module Mutant # AST representation of regexp body # - # @return [Parser::AST::Node] + # @return [Parser::AST::Node, nil] def body_ast - AST::Regexp.to_ast(body_expression) + body_expression and AST::Regexp.to_ast(body_expression) end # Expression representation of regexp body # - # @return [Regexp::Expression] + # @return [Regexp::Expression, nil] def body_expression AST::Regexp.parse(body.map(&:children).join) end diff --git a/meta/regexp.rb b/meta/regexp.rb index 8952a5a1..ca127f03 100644 --- a/meta/regexp.rb +++ b/meta/regexp.rb @@ -76,6 +76,15 @@ Mutant::Meta::Example.add :regexp do mutation '/(?(1)(foo)(?:bar))/' end +# Case where MRI would accept an expression but regexp_parser not. +Mutant::Meta::Example.add :regexp do + source '/u{/' + + singleton_mutations + mutation '//' + mutation '/nomatch\A/' +end + Pathname .glob(Pathname.new(__dir__).join('regexp', '*.rb')) .sort diff --git a/spec/integrations.yml b/spec/integrations.yml index 1f5dac3d..0b260fca 100644 --- a/spec/integrations.yml +++ b/spec/integrations.yml @@ -7,15 +7,7 @@ ruby_glob_pattern: '**/*_spec.rb' mutation_coverage: false mutation_generation: true - expected_errors: - "#": - - language/regexp/escapes_spec.rb - '#': - - language/regexp/escapes_spec.rb - "#": - - language/regexp/interpolation_spec.rb - '#': - - language/regexp/escapes_spec.rb + expected_errors: {} exclude: - core/string/casecmp_spec.rb - core/symbol/casecmp_spec.rb diff --git a/spec/unit/mutant/ast/regexp/parse_spec.rb b/spec/unit/mutant/ast/regexp/parse_spec.rb index 3094b64e..b0062cd4 100644 --- a/spec/unit/mutant/ast/regexp/parse_spec.rb +++ b/spec/unit/mutant/ast/regexp/parse_spec.rb @@ -1,7 +1,19 @@ # frozen_string_literal: true RSpec.describe Mutant::AST::Regexp, '.parse' do - it 'parses using minor ruby version' do - expect(described_class.parse(/foo/).to_re).to eql(/foo/) + def apply(input) + described_class.parse(input) + end + + context 'on regexp regexp_parser does accept' do + it 'parses using minor ruby version' do + expect(apply(/foo/).to_re).to eql(/foo/) + end + end + + context 'on regexp regexp_parser does not accept' do + it 'returns nil' do + expect(apply(/u{/)).to be(nil) + end end end