From 4856ed5251af618e9fcdd7e9b221546fa287ced6 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 19:00:42 -0700 Subject: [PATCH 01/12] Change sha1 mutation hash to use a separator between strings * When concatenating strings together to hash you need to use a separator that does not exist in the strings, otherwise you can easily get duplicate hashes, eg: Digest::SHA1.hexdigest('ab' + 'c') # => "a9993e364706816aba3e25717850c26c9cd0d89d" Digest::SHA1.hexdigest('a' + 'bc') # => "a9993e364706816aba3e25717850c26c9cd0d89d" Using a null character as a separator works around this problem: Digest::SHA1.hexdigest('a' + 0.chr + 'bc') # => "0b2749668f0ea8df8a630da13f0d218709efd5ca" Digest::SHA1.hexdigest('ab' + 0.chr + 'c') # => "dbdd4f85d8a56500aa5c9c8a0d456f96280c92e5" --- lib/mutant/mutation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mutant/mutation.rb b/lib/mutant/mutation.rb index a3fa6b49..98e54ae4 100644 --- a/lib/mutant/mutation.rb +++ b/lib/mutant/mutation.rb @@ -97,7 +97,7 @@ module Mutant # @api private # def sha1 - Digest::SHA1.hexdigest(subject.identification + source) + Digest::SHA1.hexdigest(subject.identification + 0.chr + source) end memoize :sha1 From ddec0126803b978598af64d28c10170bdd3863a7 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 19:11:12 -0700 Subject: [PATCH 02/12] Fix YARD docs to have 100% coverage again --- lib/mutant/reporter/stats.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/mutant/reporter/stats.rb b/lib/mutant/reporter/stats.rb index 73a6595b..7b0afc9f 100644 --- a/lib/mutant/reporter/stats.rb +++ b/lib/mutant/reporter/stats.rb @@ -8,6 +8,12 @@ module Mutant class Counter include Equalizer.new(:count, :fails) + # Return count + # + # @return [Fixnum] + # + # @api private + # attr_reader :count # Return fail count @@ -105,6 +111,8 @@ module Mutant # @return [false] # otherwise # + # @api private + # def success? @counts[:subject].nonzero? && !errors? end @@ -131,6 +139,8 @@ module Mutant # @return [false] # otherwise # + # @api private + # def errors? @killers.values.any? do |counter| counter.nonzero? From 92cb508c6e4e6cd0d9c3249dfd62b6bd1a4a404a Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 18:57:17 -0700 Subject: [PATCH 03/12] Fix code to no longer reference a non-existant method in subject --- lib/mutant/runner/subject.rb | 2 +- .../mutant/runner/subject/mutations_spec.rb | 24 ------------------- .../runner/subject/success_predicate_spec.rb | 14 +++++------ 3 files changed, 8 insertions(+), 32 deletions(-) delete mode 100644 spec/unit/mutant/runner/subject/mutations_spec.rb diff --git a/lib/mutant/runner/subject.rb b/lib/mutant/runner/subject.rb index 1352f522..d6e40d37 100644 --- a/lib/mutant/runner/subject.rb +++ b/lib/mutant/runner/subject.rb @@ -68,7 +68,7 @@ module Mutant # @api private # def run - @mutations = subject.mutations.map do |mutation| + @mutations = subject.map do |mutation| Mutation.run(config, mutation) end end diff --git a/spec/unit/mutant/runner/subject/mutations_spec.rb b/spec/unit/mutant/runner/subject/mutations_spec.rb deleted file mode 100644 index d46b857f..00000000 --- a/spec/unit/mutant/runner/subject/mutations_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'spec_helper' - -describe Mutant::Runner::Subject, '#mutations' do - let(:object) { described_class.run(config, mutation_subject) } - - subject { object.mutations } - - let(:config) { mock('Config') } - let(:mutation) { mock('Mutation') } - let(:mutation_subject) { mock('Subject', :mutations => [mutation]) } - - class DummyRunner - include Concord.new(:config, :mutation) - def self.run(*args); new(*args); end - end - - before do - stub_const('Mutant::Runner::Mutation', DummyRunner) - end - - it { should eql([DummyRunner.new(config, mutation)]) } - - it_should_behave_like 'an idempotent method' -end diff --git a/spec/unit/mutant/runner/subject/success_predicate_spec.rb b/spec/unit/mutant/runner/subject/success_predicate_spec.rb index 05e14a4e..916a1ded 100644 --- a/spec/unit/mutant/runner/subject/success_predicate_spec.rb +++ b/spec/unit/mutant/runner/subject/success_predicate_spec.rb @@ -5,11 +5,11 @@ describe Mutant::Runner::Subject, '#success?' do let(:object) { described_class.run(config, mutation_subject) } - let(:mutation_subject) { mock('Subject', :mutations => mutations) } - let(:config) { mock('Config') } - let(:mutation_a) { mock('Mutation A', :fails? => false) } - let(:mutation_b) { mock('Mutation B', :fails? => false) } - let(:mutations) { [mutation_a, mutation_b] } + let(:mutation_subject) { mock('Subject', :map => mutations) } + let(:config) { mock('Config') } + let(:mutation_a) { mock('Mutation A', :failed? => false) } + let(:mutation_b) { mock('Mutation B', :failed? => false) } + let(:mutations) { [mutation_a, mutation_b] } class DummyMutationRunner include Concord.new(:config, :mutation) @@ -19,7 +19,7 @@ describe Mutant::Runner::Subject, '#success?' do end def failed? - @mutation.fails? + @mutation.failed? end end @@ -36,7 +36,7 @@ describe Mutant::Runner::Subject, '#success?' do context 'with failing evil mutations' do before do - mutation_a.stub(:fails? => true) + mutation_a.stub(:failed? => true) end it { should be(false) } From 10321549cd657d265e904c5fcd7c8beb462a9f5b Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 18:58:44 -0700 Subject: [PATCH 04/12] Fix code to use proper method --- lib/mutant/killer/forked.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mutant/killer/forked.rb b/lib/mutant/killer/forked.rb index fe839d04..4f790ddb 100644 --- a/lib/mutant/killer/forked.rb +++ b/lib/mutant/killer/forked.rb @@ -33,7 +33,7 @@ module Mutant fork do begin killer = @killer.new(strategy, mutation) - Kernel.exit(killer.fail? ? 1 : 0) + Kernel.exit(killer.success? ? 0 : 1) rescue Kernel.exit(1) end From c00d39d855449009fbb8cf40c1a95e1cdd2b5b3d Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 18:59:32 -0700 Subject: [PATCH 05/12] Fix cli matchers to only include actual matcher objects --- lib/mutant/cli.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/mutant/cli.rb b/lib/mutant/cli.rb index 4cd89880..2f27cfe2 100644 --- a/lib/mutant/cli.rb +++ b/lib/mutant/cli.rb @@ -157,7 +157,8 @@ module Mutant def dispatch_matcher argument = current_argument consume(1) - @matchers << Classifier.build(argument) + matcher = Classifier.build(argument) + @matchers << matcher if matcher end # Process option argument From bf06f6b056afd8e1df86cef27f928d849fe5a9b0 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 19:04:49 -0700 Subject: [PATCH 06/12] Fix code to no longer reference non-existent methods * This code is not final, but I could not figure out a clean way to reference the error and output stream from this method. --- lib/mutant/killer/rspec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/mutant/killer/rspec.rb b/lib/mutant/killer/rspec.rb index efb05908..a7fc2a8a 100644 --- a/lib/mutant/killer/rspec.rb +++ b/lib/mutant/killer/rspec.rb @@ -17,7 +17,9 @@ module Mutant # def run mutation.insert - !!::RSpec::Core::Runner.run(command_line_arguments, strategy.error_stream, strategy.output_stream).nonzero? + # TODO: replace with real streams from configuration + null = StringIO.new + !::RSpec::Core::Runner.run(command_line_arguments, null, null).zero? end # Return command line arguments From f10f0120dc5c6ea64d6f3654f8f7dbb6d4c74fdc Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 19:12:46 -0700 Subject: [PATCH 07/12] Rename reek configuration --- config/{site.reek => reek.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename config/{site.reek => reek.yml} (100%) diff --git a/config/site.reek b/config/reek.yml similarity index 100% rename from config/site.reek rename to config/reek.yml From e9b51a93b52e7a1cc7e381af08dbe64554da8dd9 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 19:14:05 -0700 Subject: [PATCH 08/12] Upgrade gem dependencies --- Gemfile.devtools | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile.devtools b/Gemfile.devtools index 9696b9fa..91c7518d 100644 --- a/Gemfile.devtools +++ b/Gemfile.devtools @@ -3,7 +3,7 @@ group :development do gem 'rake', '~> 10.0.4' gem 'rspec', '~> 2.13.0' - gem 'yard', '~> 0.8.5.2' + gem 'yard', '~> 0.8.6' end group :yard do @@ -13,7 +13,7 @@ end group :guard do gem 'guard', '~> 1.7.0' gem 'guard-bundler', '~> 1.0.0' - gem 'guard-rspec', '~> 2.5.2' + gem 'guard-rspec', '~> 2.5.3' # file system change event handling gem 'listen', '~> 0.7.3' @@ -29,12 +29,12 @@ end group :metrics do gem 'backports', '~> 3.3', '>= 3.3.0' - gem 'coveralls', '~> 0.6.4' - gem 'flay', '~> 2.1.0' + gem 'coveralls', '~> 0.6.5' + gem 'flay', '~> 2.2.0' gem 'flog', '~> 3.2.3' gem 'reek', '~> 1.3.1', :git => 'https://github.com/troessner/reek.git' gem 'simplecov', '~> 0.7.1' - gem 'yardstick', '~> 0.9.5' + gem 'yardstick', '~> 0.9.6' gem 'yard-spellcheck', '~> 0.1.5' platforms :rbx do From 40b162db6ec3da34440a454b3a557ad2432cb134 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 19:14:39 -0700 Subject: [PATCH 09/12] Remove config file no longer used by devtools --- config/roodi.yml | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 config/roodi.yml diff --git a/config/roodi.yml b/config/roodi.yml deleted file mode 100644 index 522e1fe3..00000000 --- a/config/roodi.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -AbcMetricMethodCheck: - score: 12.2 -AssignmentInConditionalCheck: {} -CaseMissingElseCheck: {} -ClassLineCountCheck: - line_count: 324 -ClassNameCheck: - pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/ -ClassVariableCheck: {} -CyclomaticComplexityBlockCheck: - complexity: 2 -CyclomaticComplexityMethodCheck: - complexity: 4 -EmptyRescueBodyCheck: {} -ForLoopCheck: {} -MethodLineCountCheck: - line_count: 9 -MethodNameCheck: - pattern: !ruby/regexp /\A(?:[a-z\d](?:_?[a-z\d])+[?!=]?|\[\]=?|==|<=>|<<|[+*&|-])\z/ -ModuleLineCountCheck: - line_count: 327 -ModuleNameCheck: - pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/ -ParameterNumberCheck: - parameter_count: 3 From a56e680b02dc8230ec2dce28624d283fee69b53b Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 19:41:11 -0700 Subject: [PATCH 10/12] Update reek config to use devtools defaults as base --- config/reek.yml | 248 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 170 insertions(+), 78 deletions(-) diff --git a/config/reek.yml b/config/reek.yml index 2406b1c4..66fc2169 100644 --- a/config/reek.yml +++ b/config/reek.yml @@ -1,104 +1,196 @@ --- -UncommunicativeParameterName: - accept: [] - exclude: [] +Attribute: enabled: true - reject: - - !ruby/regexp /^.$/ - - !ruby/regexp /[0-9]$/ - - !ruby/regexp /[A-Z]/ -LargeClass: - max_methods: 10 exclude: - - "Mutant::Reporter::CLI" # 16 methods TODO Reduce! - - "Mutant::Reporter::Stats" # 6 ivars TODO Reduce! - - "Mutant::CLI" # 19 methods and 7 ivars, TODO Reduce! + - Mutant::CLI::Classifier + - Mutant::Context + - Mutant::Context::Scope + - Mutant::Killer + - Mutant::Killer::Forking + - Mutant::Matcher::Chain + - Mutant::Matcher::Method + - Mutant::Matcher::Methods + - Mutant::Matcher::Namespace + - Mutant::Mutation + - Mutant::Mutation::Filter::Code + - Mutant::Mutation::Filter::Whitelist + - Mutant::Mutator + - Mutant::Reporter + - Mutant::Reporter::CLI + - Mutant::Reporter::Stats + - Mutant::Reporter::Stats::Counter + - Mutant::Runner + - Mutant::Runner::Config + - Mutant::Runner::Mutation + - Mutant::Runner::Subject + - Mutant::Strategy + - Mutant::Strategy::Rspec::DM2::Lookup + - Mutant::Subject +BooleanParameter: enabled: true - max_instance_variables: 3 -UncommunicativeMethodName: - accept: - - sha1 exclude: [] +ClassVariable: enabled: true + exclude: [] +ControlParameter: + enabled: true + exclude: [] +DataClump: + enabled: true + exclude: [] + max_copies: 2 + min_clump_size: 2 +DuplicateMethodCall: + enabled: true + exclude: + - Mutant::CLI::Classifier::Method#method + - Mutant::Killer#run_with_benchmark + - Mutant::Mutator::Node::FormalArguments19::DefaultMutations#dispatch + - Mutant::Mutator::Node::FormalArguments19::RequireDefaults#dispatch + - Mutant::Mutator::Node::Literal::Hash#emit_element_presence + - Mutant::Mutator::Node::Send::WithArguments#emit_argument_mutations + - Mutant::Reporter::CLI#colorized_diff + - Mutant::Reporter::CLI#report_killer + - Mutant::Runner::Config#run + max_calls: 1 + allow_calls: [] +FeatureEnvy: + enabled: true + exclude: + - Mutant::Matcher::Method::Instance#match? + - Mutant::Matcher::Namespace#emit_scope_matches + - Mutant::Mutation::Evil#success? + - Mutant::Mutation::Neutral#success? + - Mutant::Mutator::Node::DefaultArguments#dispatch + - Mutant::Mutator::Node::FormalArguments19#emit_required_mutations + - Mutant::Mutator::Node::FormalArguments19::DefaultMutations#dispatch + - Mutant::Mutator::Node::FormalArguments19::RequireDefaults#dispatch + - Mutant::Mutator::Node::PatternArguments#allow? + - Mutant::Reporter::CLI#report_killer + - Mutant::Reporter::CLI#start +IrresponsibleModule: + enabled: true + exclude: + - Mutant::Matcher::Methods::Instance + - Mutant::Mutator::Node::Define + - Mutant::Mutator::Node::DefineSingleton + - Mutant::Strategy::Rspec::DM2::Lookup::Method + - Mutant::Strategy::Rspec::DM2::Lookup::Method::Instance + - Mutant::Strategy::Rspec::DM2::Lookup::Method::Singleton +LongParameterList: + enabled: true + exclude: + - Mutant::Mutator::Node#new_send_with_arguments + max_params: 2 + overrides: + initialize: + max_params: 3 +LongYieldList: + enabled: true + exclude: [] + max_params: 2 +NestedIterators: + enabled: true + exclude: + - Mutant#self.define_singleton_subclass + - Mutant::Mutator::Node::FormalArguments19::PatternArgumentExpansion#dispatch + - Mutant::Mutator::Node::FormalArguments19::RequireDefaults#dispatch + - Mutant::Mutator::Node::ReceiverCase#emit_when_branch_mutations + - Mutant::Mutator::Util::Array::Element#dispatch + max_allowed_nesting: 1 + ignore_iterators: [] +NilCheck: + enabled: true + exclude: + - Mutant::Matcher::Method#skip? +RepeatedConditional: + enabled: true + exclude: + - Mutant::Reporter::CLI + max_ifs: 1 +TooManyInstanceVariables: + enabled: true + exclude: + - Mutant::CLI + - Mutant::Killer + max_instance_variables: 3 +TooManyMethods: + enabled: true + exclude: + - Mutant::CLI + - Mutant::Matcher::Method + - Mutant::Reporter::CLI + max_methods: 10 +TooManyStatements: + enabled: true + exclude: + - Mutant#self.define_singleton_subclass + - Mutant::CLI#self.run + - Mutant::Differ#diff + - Mutant::Killer::Forked#run + - Mutant::Mutator::Node#emit_attribute_mutations + - Mutant::Mutator::Node::FormalArguments19::DefaultMutations#dispatch + - Mutant::Mutator::Node::FormalArguments19::PatternArgumentExpansion#dispatch + - Mutant::Mutator::Node::FormalArguments19::RequireDefaults#dispatch + - Mutant::Mutator::Node::If#dispatch + - Mutant::Reporter::CLI#colorized_diff + - Mutant::Reporter::CLI#report_killer + - Mutant::Reporter::CLI#start + - each + max_statements: 5 +UncommunicativeMethodName: + enabled: true + exclude: + - Mutant::Mutation#sha1 reject: - !ruby/regexp /^[a-z]$/ - !ruby/regexp /[0-9]$/ - !ruby/regexp /[A-Z]/ -LongParameterList: - max_params: 2 - exclude: - - "Mutant::Mutator::Node#new_send_with_arguments" # 3 params - - "Mutant::Context::Constant#initialize" # 3 params - - "Mutant::Subject#initialize" # 3 params - enabled: true - overrides: {} -FeatureEnvy: - exclude: [] - enabled: true -ClassVariable: - exclude: [] - enabled: true -BooleanParameter: - exclude: [] - enabled: true -IrresponsibleModule: - exclude: [] - enabled: true + accept: [] UncommunicativeModuleName: - accept: + enabled: true + exclude: + - Mutant::Mutator::Node::FormalArguments19 - Mutant::Mutator::Node::Iter19 - Mutant::Strategy::Rspec::DM2 - exclude: [] - enabled: true reject: - !ruby/regexp /^.$/ - !ruby/regexp /[0-9]$/ -NestedIterators: - ignore_iterators: [] - exclude: - - Mutant#self.define_singleton_subclass - - Mutant::Mutator::Util::Array::Element#dispatch - - Mutant::Mutator::Node::ReceiverCase#emit_when_branch_mutation - enabled: true - max_allowed_nesting: 1 -LongMethod: - max_statements: 6 - exclude: [] - enabled: true -Duplication: - allow_calls: [] - exclude: - - Mutant::Mutator::Node::Literal::Hash#emit_element_presence - enabled: true - max_calls: 1 -UtilityFunction: - max_helper_calls: 0 - exclude: [] - enabled: true -Attribute: - exclude: [] - enabled: false -UncommunicativeVariableName: accept: [] - exclude: [] +UncommunicativeParameterName: enabled: true + exclude: [] reject: - !ruby/regexp /^.$/ - !ruby/regexp /[0-9]$/ - !ruby/regexp /[A-Z]/ -SimulatedPolymorphism: - exclude: [] + accept: [] +UncommunicativeVariableName: enabled: true - max_ifs: 1 -DataClump: exclude: [] + reject: + - !ruby/regexp /^.$/ + - !ruby/regexp /[0-9]$/ + - !ruby/regexp /[A-Z]/ + accept: [] +UnusedParameters: enabled: true - max_copies: 2 - min_clump_size: 2 -ControlCouple: - exclude: [] - enabled: true -LongYieldList: - max_params: 1 - exclude: [] + exclude: + - Mutant::Mutation::Filter#match? + - Mutant::Mutation::Filter#self.handle + - Mutant::Mutator#allow? + - Mutant::Strategy::Rspec::Full#spec_files + - Mutant::Strategy::Rspec::Integration#spec_files + - Mutant::Strategy::Rspec::Unit#spec_files +UtilityFunction: enabled: true + exclude: + - Mutant::Matcher::Namespace#emit_scope_matches + - Mutant::Mutation::Evil#success? + - Mutant::Mutation::Neutral#success? + - Mutant::Mutator::Node::PatternArguments#allow? + - Mutant::Strategy::Rspec::DM2#spec_files + - Mutant::Strategy::Rspec::Full#spec_files + - Mutant::Strategy::Rspec::Integration#spec_files + - Mutant::Strategy::Rspec::Unit#spec_files + max_helper_calls: 0 From 37d5a0635381dc9ce0fad744acdaac26fc166acf Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 19:42:07 -0700 Subject: [PATCH 11/12] Update flay and flog thresholds --- config/flay.yml | 4 ++-- config/flog.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/flay.yml b/config/flay.yml index 1fbb7d1a..e5817985 100644 --- a/config/flay.yml +++ b/config/flay.yml @@ -1,3 +1,3 @@ --- -threshold: 25 # Todo bring down to ~20 -total_score: 914 +threshold: 16 +total_score: 577 diff --git a/config/flog.yml b/config/flog.yml index 5704a723..0b91a104 100644 --- a/config/flog.yml +++ b/config/flog.yml @@ -1,2 +1,2 @@ --- -threshold: 44.0 +threshold: 37.6 From 10b1e106ffcf8d22b6943d7dbd14f3cc55b1fcfe Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Wed, 17 Apr 2013 20:24:14 -0700 Subject: [PATCH 12/12] Add require stringio temporarily to rspec killer --- lib/mutant/killer/rspec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/mutant/killer/rspec.rb b/lib/mutant/killer/rspec.rb index a7fc2a8a..80c2c901 100644 --- a/lib/mutant/killer/rspec.rb +++ b/lib/mutant/killer/rspec.rb @@ -18,6 +18,7 @@ module Mutant def run mutation.insert # TODO: replace with real streams from configuration + require 'stringio' null = StringIO.new !::RSpec::Core::Runner.run(command_line_arguments, null, null).zero? end