Add Ruby 2.4 support for mutant

Several steps were made to achieve mutant working with Ruby 2.4 without
warnings and spec failures:

* Fix Fixnum deprecation warning
* Update RuboCop to 0.47 and fix offenses
* Relax version requirements on parser gem
* Update diff-lcs to 1.3
* Update rake 11.x -> 12.x
* Update reek 4.5 -> 4.6 (to work with parser 2.4)
* Update json 2.0 -> 2.1
* Update parallel 1.10 -> 1.11
* Update simplecov 0.12 -> 0.14
* Run regexp_parser integration against v0.4.3 (as we requiring this
    exact version)
* Update warnings.yml with new whitelist
* Run CircleCI tests on Ruby 2.3 and 2.4 (Bundler.with_clean_env
    was causing troubles on new CircleCI 2.0 setup, so it was removed)
This commit is contained in:
Bartek Bułat 2017-07-06 09:45:17 +02:00
parent 58c6ad31ef
commit 0be9fa75d6
32 changed files with 128 additions and 107 deletions

View file

@ -7,13 +7,13 @@ PATH
anima (~> 0.3.0)
ast (~> 2.2)
concord (~> 0.1.5)
diff-lcs (~> 1.2)
diff-lcs (~> 1.3)
equalizer (~> 0.0.9)
ice_nine (~> 0.11.1)
memoizable (~> 0.4.2)
morpher (~> 0.2.6)
parallel (~> 1.3)
parser (~> 2.3.1, >= 2.3.1.4)
parser (>= 2.3.1.4, < 2.5)
procto (~> 0.0.2)
regexp_parser (~> 0.4.3)
unparser (~> 0.2.5)
@ -46,7 +46,8 @@ GEM
equalizer (~> 0.0.9)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devtools (0.1.15)
devtools (0.1.18)
abstract_type (~> 0.0.7)
adamantium (~> 0.2.0)
anima (~> 0.3.0)
concord (~> 0.1.5)
@ -55,31 +56,31 @@ GEM
mutant (~> 0.8.11)
mutant-rspec (~> 0.8.11)
procto (~> 0.0.3)
rake (~> 11.3.0)
reek (~> 4.5.0)
rake (~> 12.0.0)
reek (~> 4.6.0)
rspec (~> 3.5.0)
rspec-core (~> 3.5.4)
rspec-its (~> 1.2.0)
rubocop (~> 0.46.0)
simplecov (~> 0.12.0)
rubocop (~> 0.47.0)
simplecov (~> 0.14.0)
yard (~> 0.9.1)
yardstick (~> 0.9.9)
diff-lcs (1.2.5)
diff-lcs (1.3)
docile (1.1.5)
equalizer (0.0.11)
erubis (2.7.0)
ffi (1.9.14)
ffi (1.9.18)
flay (2.8.1)
erubis (~> 2.7.0)
path_expander (~> 1.0)
ruby_parser (~> 3.0)
sexp_processor (~> 4.0)
flog (4.4.0)
flog (4.4.1)
path_expander (~> 1.0)
ruby_parser (~> 3.1, > 3.1.0)
sexp_processor (~> 4.4)
ice_nine (0.11.2)
json (2.0.2)
json (2.1.0)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
morpher (0.2.6)
@ -91,17 +92,18 @@ GEM
equalizer (~> 0.0.9)
ice_nine (~> 0.11.0)
procto (~> 0.0.2)
parallel (1.10.0)
parser (2.3.3.1)
parallel (1.11.2)
parser (2.4.0.0)
ast (~> 2.2)
path_expander (1.0.1)
path_expander (1.0.2)
powerpack (0.1.1)
procto (0.0.3)
rainbow (2.1.0)
rake (11.3.0)
reek (4.5.2)
rainbow (2.2.2)
rake
rake (12.0.0)
reek (4.6.2)
codeclimate-engine-rb (~> 0.4.0)
parser (~> 2.3.1, >= 2.3.1.2)
parser (>= 2.4.0.0, < 2.5)
rainbow (~> 2.0)
regexp_parser (0.4.3)
rspec (3.5.0)
@ -120,37 +122,37 @@ GEM
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.5.0)
rspec-support (3.5.0)
rubocop (0.46.0)
parser (>= 2.3.1.1, < 3.0)
rubocop (0.47.1)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.8.1)
ruby_parser (3.8.3)
ruby_parser (3.9.0)
sexp_processor (~> 4.1)
sexp_processor (4.7.0)
simplecov (0.12.0)
sexp_processor (4.9.0)
simplecov (0.14.1)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
thread_safe (0.3.5)
unicode-display_width (1.1.1)
unparser (0.2.5)
simplecov-html (0.10.1)
thread_safe (0.3.6)
unicode-display_width (1.3.0)
unparser (0.2.6)
abstract_type (~> 0.0.7)
adamantium (~> 0.2.0)
concord (~> 0.1.5)
diff-lcs (~> 1.2.5)
diff-lcs (~> 1.3)
equalizer (~> 0.0.9)
parser (~> 2.3.0)
parser (>= 2.3.1.2, < 2.5)
procto (~> 0.0.2)
virtus (1.0.5)
axiom-types (~> 0.1)
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
yard (0.9.5)
yard (0.9.9)
yardstick (0.9.9)
yard (~> 0.8, >= 0.8.7.2)

View file

@ -1,7 +1,23 @@
---
machine:
ruby:
version: '2.3.3'
test:
override:
- bundle exec rake ci
defaults: &defaults
working_directory: ~/mutant
steps:
- checkout
- run: bundle install
- run: bundle exec rake ci
version: 2
jobs:
ruby_2_3:
<<: *defaults
docker:
- image: circleci/ruby:2.3.3
ruby_2_4:
<<: *defaults
docker:
- image: circleci/ruby:2.4.1
workflows:
version: 2
test:
jobs:
- ruby_2_3
- ruby_2_4

View file

@ -96,7 +96,7 @@ SymbolArray:
# Align if/else blocks with the variable assignment
EndAlignment:
AlignWith: variable
EnforcedStyleAlignWith: variable
# Prefer #kind_of? over #is_a?
ClassCheck:
@ -110,6 +110,9 @@ UnneededPercentQ:
Metrics/AbcSize:
Max: 21.02
Metrics/BlockLength:
Enabled: false
# Do not prefer lambda.call(...) over lambda.(...)
LambdaCall:
Enabled: false

View file

@ -102,7 +102,7 @@ require 'mutant/mutator/node/literal/boolean'
require 'mutant/mutator/node/literal/range'
require 'mutant/mutator/node/literal/symbol'
require 'mutant/mutator/node/literal/string'
require 'mutant/mutator/node/literal/fixnum'
require 'mutant/mutator/node/literal/integer'
require 'mutant/mutator/node/literal/float'
require 'mutant/mutator/node/literal/array'
require 'mutant/mutator/node/literal/hash'

View file

@ -38,7 +38,7 @@ module Mutant
# Define named child
#
# @param [Symbol] name
# @param [Fixnum] index
# @param [Integer] index
#
# @return [undefined]
def define_named_child(name, index)

View file

@ -31,6 +31,7 @@ module Mutant
[:regexp_backslash_escape, %i[escape backslash], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_tab_escape, %i[escape tab], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_codepoint_list_escape, %i[escape codepoint_list], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_codepoint_escape, %i[escape codepoint], ::Regexp::Expression::EscapeSequence::Literal],
[:regexp_control_escape, %i[escape control], ::Regexp::Expression::EscapeSequence::Control],
[:regexp_meta_sequence_escape, %i[escape meta_sequence], ::Regexp::Expression::EscapeSequence::Control]
)

View file

@ -57,6 +57,7 @@ module Mutant
regexp_character_set
regexp_character_set
regexp_codepoint_list_escape
regexp_codepoint_escape
regexp_comment_free_space
regexp_comment_group
regexp_control_escape

View file

@ -86,7 +86,7 @@ module Mutant
# Max length of source line in new and old
#
# @return [Fixnum]
# @return [Integer]
def max_length
[old, new].map(&:length).max
end

View file

@ -19,7 +19,7 @@ module Mutant
#
# @param [Expression] other
#
# @return [Fixnum]
# @return [Integer]
def match_length(other)
if eql?(other)
syntax.length

View file

@ -37,7 +37,7 @@ module Mutant
#
# @param [Expression] expression
#
# @return [Fixnum]
# @return [Integer]
def match_length(expression)
if expression.syntax.start_with?(syntax)
syntax.length

View file

@ -40,7 +40,7 @@ module Mutant
#
# @param [Expression] expression
#
# @return [Fixnum]
# @return [Integer]
def match_length(expression)
if @recursion_pattern =~ expression.syntax
scope_name.length

View file

@ -93,7 +93,7 @@ module Mutant
# Parse example into test
#
# @param [RSpec::Core::Example] example
# @param [Fixnum] index
# @param [Integer] index
#
# @return [Test]
def parse_example(example, index)

View file

@ -91,14 +91,14 @@ module Mutant
# Source file line
#
# @return [Fixnum]
# @return [Integer]
def source_line
source_location.last
end
# Full source location
#
# @return [Array{String,Fixnum}]
# @return [Array{String,Integer}]
def source_location
target_method.source_location
end

View file

@ -48,7 +48,7 @@ module Mutant
# Source location
#
# @return [Array{String,Fixnum}]
# @return [Array{String,Integer}]
def source_location
scope
.unmemoized_instance_method(method_name)

View file

@ -14,7 +14,7 @@ module Mutant
#
# @param [Parser::AST::Node] node
#
# @param [Fixnum] index
# @param [Integer] index
#
# @return [undefined]
def self.define_named_child(name, index)
@ -51,7 +51,7 @@ module Mutant
# Dispatch on child index
#
# @param [Fixnum] index
# @param [Integer] index
#
# @return [undefined]
def mutate_child(index, &block)
@ -64,7 +64,7 @@ module Mutant
# Emit delete child mutation
#
# @param [Fixnum] index
# @param [Integer] index
#
# @return [undefined]
def delete_child(index)
@ -75,7 +75,7 @@ module Mutant
# Emit updated child
#
# @param [Fixnum] index
# @param [Integer] index
# @param [Parser::AST::Node] node
#
# @return [undefined]
@ -149,7 +149,7 @@ module Mutant
#
# @param [Range] range
#
# @return [Enumerable<Fixnum>]
# @return [Enumerable<Integer>]
def children_indices(range)
range.begin.upto(children.length + range.end)
end

View file

@ -62,7 +62,7 @@ module Mutant
# Multiple left hand side childs
#
# @return [Enumerable<Parser::AST::Node, Fixnum>]
# @return [Enumerable<Parser::AST::Node, Integer>]
def mlhs_childs_with_index
children.each_with_index.select do |child, _index|
n_mlhs?(child)

View file

@ -2,8 +2,8 @@ module Mutant
class Mutator
class Node
class Literal < self
# Mutator for fixnum literals
class Fixnum < self
# Mutator for integer literals
class Integer < self
handle(:int)
@ -28,10 +28,11 @@ module Mutant
#
# @return [Object]
def value
children.first
value, = children
value
end
end # Fixnum
end # Integer
end # Literal
end # Node
end # Mutator

View file

@ -52,7 +52,7 @@ module Mutant
# Index of body node
#
# @return [Fixnum]
# @return [Integer]
def body_index
children.length - 1
end

View file

@ -27,7 +27,7 @@ module Mutant
# Test if diff changes file at line range
#
# @param [Pathname] path
# @param [Range<Fixnum>] line_range
# @param [Range<Integer>] line_range
#
# @return [Boolean]
#

View file

@ -94,14 +94,14 @@ module Mutant
# Amount of mutations
#
# @return [Fixnum]
# @return [Integer]
def amount_mutations
env.mutations.length
end
# Amount of subjects
#
# @return [Fixnum]
# @return [Integer]
def amount_subjects
env.subjects.length
end
@ -146,28 +146,28 @@ module Mutant
# Amount of mutations
#
# @return [Fixnum]
# @return [Integer]
def amount_mutation_results
mutation_results.length
end
# Amount of mutations
#
# @return [Fixnum]
# @return [Integer]
def amount_mutations
subject.mutations.length
end
# Number of killed mutations
#
# @return [Fixnum]
# @return [Integer]
def amount_mutations_killed
killed_mutation_results.length
end
# Number of alive mutations
#
# @return [Fixnum]
# @return [Integer]
def amount_mutations_alive
alive_mutation_results.length
end

View file

@ -33,7 +33,7 @@ module Mutant
# Source line range
#
# @return [Range<Fixnum>]
# @return [Range<Integer>]
def source_lines
expression = node.location.expression
expression.line..expression.source_buffer.decompose_position(expression.end_pos).first
@ -42,7 +42,7 @@ module Mutant
# First source line
#
# @return [Fixnum]
# @return [Integer]
def source_line
source_lines.begin
end

View file

@ -29,7 +29,6 @@ Mutant::Meta::Example.add :case do
RUBY
end
# rubocop:disable Metrics/BlockLength
Mutant::Meta::Example.add :case do
source <<-RUBY
case condition

View file

@ -1,6 +1,5 @@
require File.expand_path('../lib/mutant/version', __FILE__)
# rubocop:disable Metrics/BlockLength
Gem::Specification.new do |gem|
gem.name = 'mutant'
gem.version = Mutant::VERSION.dup
@ -22,9 +21,9 @@ Gem::Specification.new do |gem|
gem.required_ruby_version = '>= 2.1'
gem.add_runtime_dependency('parser', '~> 2.3.1', '>= 2.3.1.4')
gem.add_runtime_dependency('parser', '>= 2.3.1.4', '< 2.5')
gem.add_runtime_dependency('ast', '~> 2.2')
gem.add_runtime_dependency('diff-lcs', '~> 1.2')
gem.add_runtime_dependency('diff-lcs', '~> 1.3')
gem.add_runtime_dependency('parallel', '~> 1.3')
gem.add_runtime_dependency('morpher', '~> 0.2.6')
gem.add_runtime_dependency('procto', '~> 0.0.2')

View file

@ -18,7 +18,7 @@
- name: regexp_parser
namespace: Regexp
repo_uri: 'https://github.com/ammar/regexp_parser.git'
repo_ref: 'v0.4.1'
repo_ref: 'v0.4.3'
ruby_glob_pattern: '**/*.rb'
mutation_coverage: false
mutation_generation: true

View file

@ -1,11 +1,12 @@
RSpec.shared_examples_for 'framework integration' do
def system_with_gemfile(*command)
Kernel.system({ 'BUNDLE_GEMFILE' => gemfile }, *command)
end
around do |example|
Bundler.with_clean_env do
Dir.chdir(TestApp.root) do
Kernel.system("bundle install --gemfile=#{gemfile}") || fail('Bundle install failed!')
ENV['BUNDLE_GEMFILE'] = gemfile
example.run
end
Dir.chdir(TestApp.root) do
Kernel.system('bundle', 'install', '--gemfile', gemfile) || fail('Bundle install failed!')
example.run
end
end
@ -20,16 +21,16 @@ RSpec.shared_examples_for 'framework integration' do
TestApp::Literal#uncovered_string
--ignore-subject TestApp::Literal#uncovered_string
CMD
expect(Kernel.system(cli)).to be(true)
expect(system_with_gemfile(cli)).to be(true)
end
specify 'fails to kill mutations when they are not covered' do
cli = "#{base_cmd} TestApp::Literal#uncovered_string"
expect(Kernel.system(cli)).to be(false)
expect(system_with_gemfile(cli)).to be(false)
end
specify 'fails when some mutations are not covered' do
cli = "#{base_cmd} TestApp::Literal"
expect(Kernel.system(cli)).to be(false)
expect(system_with_gemfile(cli)).to be(false)
end
end

View file

@ -50,18 +50,16 @@ module MutantSpec
def verify_mutation_coverage
checkout
Dir.chdir(repo_path) do
Bundler.with_clean_env do
install_mutant
system(
%W[
bundle exec mutant
--use rspec
--include lib
--require #{name}
#{namespace}*
]
)
end
install_mutant
system(
%W[
bundle exec mutant
--use rspec
--include lib
--require #{name}
#{namespace}*
]
)
end
end
@ -123,7 +121,7 @@ module MutantSpec
#
# @param path [Pathname] path responsible for exception
#
# @return [Fixnum] mutations generated
# @return [Integer] mutations generated
def count_mutations_and_check_errors(path)
relative_path = path.relative_path_from(repo_path)
@ -144,7 +142,7 @@ module MutantSpec
#
# @raise [Exception] any error specified by integrations.yml
#
# @return [Fixnum] number of mutations generated
# @return [Integer] number of mutations generated
def count_mutations(path)
node = Parser::CurrentRuby.parse(path.read)
@ -181,7 +179,7 @@ module MutantSpec
# Number of parallel processes to use
#
# @return [Fixnum]
# @return [Integer]
def parallel_processes
if ENV.key?('CI')
CIRCLE_CI_CONTAINER_PROCESSES
@ -207,7 +205,7 @@ module MutantSpec
# Print start progress
#
# @param [Pathname] path
# @param [Fixnum] _index
# @param [Integer] _index
#
# @return [undefined]
#
@ -220,8 +218,8 @@ module MutantSpec
# Print finish progress
#
# @param [Pathname] path
# @param [Fixnum] _index
# @param [Fixnum] count
# @param [Integer] _index
# @param [Integer] count
#
# @return [undefined]
#

View file

@ -57,7 +57,7 @@ module MutantSpec
end
warnings = Pathname.new(__dir__).join('warnings.yml').freeze
whitelist = IceNine.deep_freeze(YAML.load(warnings.read))
whitelist = IceNine.deep_freeze(YAML.load(warnings.read)) # rubocop:disable Security/YAMLLoad
EXTRACTOR = Extractor.new(STDERR, whitelist)
end

View file

@ -1,4 +1,5 @@
---
- 'lib/parallel.rb:222: warning: shadowing outer local variable - args'
- 'lib/parallel.rb:227: warning: shadowing outer local variable - args'
- 'lib/parser/lexer.rb:10922: warning: assigned but unused variable - testEof'
- 'lib/parser/source/rewriter.rb:392: warning: assigned but unused variable - begin_pos'
- 'lib/regexp_parser/scanner.rb:1674: warning: assigned but unused variable - testEof'

View file

@ -14,7 +14,7 @@ RSpec.describe Mutant::Isolation::Fork do
let(:isolated_block) { -> { block_return } }
let(:marshal) { class_double(Marshal) }
let(:process) { class_double(Process) }
let(:pid) { class_double(Fixnum) }
let(:pid) { class_double(0.class) }
let(:reader) { instance_double(IO, :reader) }
let(:stderr) { instance_double(IO, :stderr) }
let(:stdout) { instance_double(IO, :stdout) }

View file

@ -10,7 +10,7 @@ RSpec.describe Mutant::Loader, '.call' do
let(:path) { instance_double(Pathname, to_s: path_str) }
let(:path_str) { instance_double(String) }
let(:line) { instance_double(Fixnum) }
let(:line) { instance_double(0.class) }
let(:kernel) { class_double(Kernel) }
let(:binding) { instance_double(Binding) }
let(:source) { instance_double(String) }

View file

@ -38,7 +38,7 @@ RSpec.describe Mutant::Parallel::Worker do
message_sequence.add(:worker, :stop)
end
let(:index) { instance_double(Fixnum) }
let(:index) { instance_double(0.class) }
let(:job_result) { Mutant::Parallel::JobResult.new(job: job, payload: result_payload) }
let(:job) { Mutant::Parallel::Job.new(index: index, payload: payload) }

View file

@ -9,8 +9,7 @@ RSpec.describe Mutant::Subject::Method::Singleton do
let(:scope) do
Class.new do
def self.foo
end
def self.foo; end
def self.name
'Test'