Code Monkey home page Code Monkey logo

mutant's Introduction

mutant

Build Status Gem Version Discord

What is Mutant?

An automated code review tool, with a side effect of producing semantic code coverage metrics.

Think of mutant as an expert developer that simplifies your code while making sure that all tests pass.

That developer never has a bad day and is always ready to jump on your PR.

Each reported simplification signifies either:

A) A piece of code that does more than the tests ask for. You can probably use the simplified version of the code. OR:

B) If you have a reason to not take the simplified version as it violates a requirement: There was no test that proves the extra requirement. Likely you are missing an important test for that requirement.

On extensive mutant use A) happens more often than B), which leads to overall less code enter your repository at higher confidence for both the author and the reviewer.

BTW: Mutant is a mutation testing tool, which is a form of code coverage. But each reported uncovered mutation is actually a call to action, just like a flag in a code review would be.

Getting started:

  • Start with reading the nomenclature. No way around that one, sorry.
  • Then select and setup your integration, also make sure you can reproduce the examples in the integration specific documentation.
  • Use mutant during code reviews and on CI in incremental mode.
  • Do not merge code with new alive mutations. If you really must bypass: Add the subjects with open problems to the ignored subjects.

Operating Systems

Mutant is supported and tested under Linux and Mac OS X.

Ruby Versions

Mutant supports multiple ruby versions at different levels:

  • Runtime, indicates mutant can execute on a specific Ruby Version / implementation.
  • Syntax, depends on Runtime support, and indicates syntax new to that Ruby version can be used.
  • Mutations, depends on Syntax support, and indicates syntax new to that Ruby version is being analysed.

Supported indicates if a specific Ruby version / Implementation is actively supported. Which means:

  • New releases will only be done if all tests pass on supported Ruby versions / implementations.
  • New features will be available.
Implementation Version Runtime Syntax Mutations Supported
cRUBY/MRI 3.1 ✔️ ✔️ ✔️ ✔️
cRUBY/MRI 3.2 ✔️ ✔️ ✔️ ✔️
cRUBY/MRI 3.3 ✔️ ✔️ ✔️ ✔️
jruby TBD 📧 📧 📧 📧
mruby TBD 📧 📧 📧 📧
cRUBY/MRI < 3.1

Labels:

  • ✔️ Supported.
  • ⚠️ Experimental Support.
  • 🔜 Active work in progress.
  • 📧 Planned, please contact me on interest.
  • ⛔ Not being planned, or considered, still contact me on interest.

Licensing

Mutant is commercial software, with a free usage option for opensource projects. Opensource projects have to be on a public repository.

Commercial projects have to pay a monthly or annual subscription fee.

Opensource usage

Usage is free and does not require a signup. But it requires the code is under an opensource license and public. Specify --usage opensource on the CLI or usage: opensource in the config file.

Commercial usage

Commercial use requires payment via a subscription and requires a signup. See pricing for available plans.

After payment specify --usage commercial on the CLI or usage: commercial in the config file.

Pricing

Mutant is free for opensource use!

For commercial use mutants pricing is subscription based.

Currency Duration Cost Payment Methods
USD 1 month 90$ Credit Card
USD 1 year 900$ Credit Card, ACH transfer
EUR 1 month 90€ Credit Card, SEPA Direct Debit
EUR 1 year 900€ Credit Card, SEPA Direct Debit, SEPA Transfer

Costs are per developer using mutant on any number of repositories.

Volume subscriptions with custom plans are available on request.

Should you want to procure a commercial mutant subscription please mail me to start the payment process.

Please include the following information:

  • Your business invoice address.
  • A payment email address, if different from your email address.
  • Only for the EU: A valid VAT-ID is required, no sales to private customers to avoid the horrors cross border VAT / MOSS. VAT for EU customers outside of Malta will use reverse charging.

Also feel free to ask any other question I forgot to proactively answer here.

Also checkout the commercial FAQ.

Topics

Communication

Try the following:

Sponsoring

Mutant, as published in the opensource version, would not exist without the help of contributors spending lots of their private time.

Additionally, the following features where sponsored by organizations:

  • The mutant-minitest integration was sponsored by Arkency
  • Mutant's initial concurrency support was sponsored by an undisclosed company that does currently not wish to be listed here.

Legal

Contents of this repository are maintained by:

Schirp DSO LTD
Director: Markus Schirp
Email: [email protected]
Vat-ID: MT24186727
Registration: C80467

Office address:
2, Carob Lane,
Sir Harry Luke Street
Naxxar NXR 2209,
Malta

Registred Address
Phoenix Business Centre,
The Penthouse,
Old Railway Track,
Santa Venera SVR9022,
Malta

mutant's People

Contributors

abrahamsangha avatar andyw8 avatar backus avatar barthez avatar dependabot[bot] avatar dgollahon avatar dkubb avatar jschirp avatar kbrock avatar kevinrutherford avatar krzysiek1507 avatar lucaspinto avatar matkoniecz avatar mbj avatar michaelherold avatar mikeweaver avatar mjago avatar mostlyobvious avatar mvz avatar nwjsmith avatar olivierlacan avatar olleolleolle avatar postmodern avatar ptico avatar rewinfrey avatar rrrene avatar snusnu avatar solnic avatar tjchambers avatar zaidan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mutant's Issues

Mutant does not emit ranges correctly

Hi,

I tried to write a bit demo code and wanted to see how many mutants are still alive. Unfortunately mutant cannot run even the unmutated code, because the parser seems to remove the parentheses around the range.

Failures:

  1) Calculator#two_raised_by returns 8 if your exponent is 3
     Failure/Error: subject.two_raised_by(3).should eq(8)
     NoMethodError:
       undefined method `each' for 3:Fixnum
     # ./lib/calculator.rb:21:in `two_raised_by'
     # ./spec/unit/calculator_spec.rb:45:in `block (3 levels) in <top (required)>'

Finished in 0.00441 seconds
8 examples, 1 failure

Failed examples:

rspec ./spec/unit/calculator_spec.rb:44 # Calculator#two_raised_by returns 8 if your exponent is 3
Killed: rspec:noop:Calculator#two_raised_by:/home/stormwind/beyondtdd/calculator/lib/calculator.rb:15:1d9ec (0.05s)
def two_raised_by(exponent)
  if ((exponent) == (0))
    return 0
  end
  result = 1
  1..exponent.each do
    result = multiply(2, result)
  end
  result
end

The test code:
(I deleted the unnecessary parts, hope I didn't delete too much. ;) )
https://gist.github.com/cfbba9f7f3ed0bbfa8ab

Mutation: Else branch addition

@dkubb Proposed the following mutation:

one mutation that might work is adding an else condition to an if/elsif branch that returns true. there should be a spec to handle the case when the if or elsif are not taken.. I suppose the same kind of mutation could be done on a case statement with a missing else too

Tracking as issue to test how this feels outside of the TODO file.

Syntax error in case statement "else" with super

I think this may be a bug in unparser but since the stack trace reports mutant I thought I'd report it here to start.

I just ran mutant against axiom-types and saw the same class of error twice:

/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/loader.rb:43:in `eval': /Users/dkubb/Dropbox/Home/Programming/open-source/axiom-types/lib/axiom/types/hash.rb:30: syntax error, unexpected keyword_else, expecting keyword_when (SyntaxError)
/Users/dkubb/Dropbox/Home/Programming/open-source/axiom-types/lib/axiom/types/hash.rb:36: syntax error, unexpected keyword_end, expecting $end
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/loader.rb:43:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/loader.rb:28:in `initialize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/support/method_object.rb:29:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutation.rb:38:in `insert'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/killer/rspec.rb:19:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/killer.rb:93:in `run_with_benchmark'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/killer.rb:33:in `initialize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/killer/forked.rb:35:in `block in run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/killer/forked.rb:33:in `fork'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/killer/forked.rb:33:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/killer.rb:93:in `run_with_benchmark'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/killer.rb:33:in `initialize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/killer/forked.rb:17:in `initialize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/killer/forking.rb:39:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/strategy.rb:36:in `kill'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner/mutation.rb:52:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner.rb:26:in `initialize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner/mutation.rb:26:in `initialize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/support/method_object.rb:29:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner/subject.rb:74:in `block in run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/subject.rb:19:in `block in each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator.rb:165:in `call'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator.rb:165:in `emit!'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator.rb:121:in `emit'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node.rb:171:in `emit_self'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node.rb:159:in `emit_child_update'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node.rb:129:in `block in mutate_child'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator.rb:165:in `call'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator.rb:165:in `emit!'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator.rb:121:in `emit'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node.rb:171:in `emit_self'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node/case.rb:53:in `mutate_index'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node/case.rb:34:in `block in emit_branch_mutations'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node/case.rb:32:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node/case.rb:32:in `emit_branch_mutations'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node/case.rb:22:in `dispatch'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator.rb:70:in `initialize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator.rb:17:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node.rb:128:in `mutate_child'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node.rb:35:in `block in define_named_child'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator/node/define.rb:18:in `dispatch'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator.rb:70:in `initialize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/mutator.rb:17:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/subject.rb:18:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner/subject.rb:73:in `map'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner/subject.rb:73:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner.rb:26:in `initialize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner/subject.rb:26:in `initialize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/support/method_object.rb:29:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner/config.rb:62:in `block in run_subjects'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/methods.rb:63:in `block in emit_matches'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/method.rb:27:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/methods.rb:62:in `emit_matches'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/methods.rb:21:in `block in each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/methods.rb:20:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/methods.rb:20:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher.rb:21:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/scope.rb:26:in `block in each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/scope.rb:25:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/scope.rb:25:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher.rb:21:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/namespace.rb:22:in `block in each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/namespace.rb:65:in `emit_scope'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/namespace.rb:51:in `block in scopes'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/namespace.rb:50:in `each_object'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/namespace.rb:50:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/namespace.rb:50:in `scopes'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/namespace.rb:21:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/matcher/namespace.rb:21:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/cli/classifier.rb:94:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/config.rb:22:in `subjects'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner/config.rb:61:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner/config.rb:61:in `map'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner/config.rb:61:in `run_subjects'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner/config.rb:75:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/runner.rb:26:in `initialize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/support/method_object.rb:29:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-c1b10253f6f6/lib/mutant/cli.rb:26:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/devtools-5606c70d0f21/tasks/metrics/mutant.rake:18:in `block (2 levels) in <top (required)>'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/task.rb:236:in `call'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/task.rb:236:in `block in execute'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/task.rb:231:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/task.rb:231:in `execute'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/task.rb:175:in `block in invoke_with_call_chain'
    from /Users/dkubb/.rvm/rubies/ruby-1.9.3-p429/lib/ruby/1.9.1/monitor.rb:211:in `mon_synchronize'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/task.rb:168:in `invoke_with_call_chain'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/task.rb:161:in `invoke'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/application.rb:149:in `invoke_task'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/application.rb:106:in `block (2 levels) in top_level'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/application.rb:106:in `each'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/application.rb:106:in `block in top_level'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/application.rb:115:in `run_with_threads'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/application.rb:100:in `top_level'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/application.rb:78:in `block in run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/application.rb:165:in `standard_exception_handling'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/lib/rake/application.rb:75:in `run'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/rake-10.1.0/bin/rake:33:in `<top (required)>'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bin/rake:19:in `load'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bin/rake:19:in `<main>'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bin/ruby_noexec_wrapper:14:in `eval'
    from /Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bin/ruby_noexec_wrapper:14:in `<main>'

I saw this in one other place. The common feature of the code is that it has a case statement where the else block calls super, eg:

case something
# ...
else
  super
end

One suggestion I'd have is that if there's a syntax error, mutant should output the actual code in the error before the stacktrace is outputted. That way we can visually see what unparser is generating right in the error and syntax errors like this will become self evident at a glance.

% operator crashes mutant

Trying to run mutant on ronin-sql and Ronin::SQL::Operators#% appears to crash mutant.

Subject: Ronin::SQL::Operators#%:/vault/1/code/ronin/ronin-sql/lib/ronin/sql/operators.rb:57
/home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/reporter/cli.rb:273:in `%': malformed format string - %: (ArgumentError)
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/reporter/cli.rb:273:in `print_killer'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/reporter/cli.rb:87:in `noop'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/runner.rb:110:in `noop'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/runner.rb:88:in `run_subject'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/runner.rb:75:in `block in run'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/scope_methods.rb:96:in `block in emit_matches'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/method.rb:39:in `block in each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/method.rb:38:in `tap'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/method.rb:38:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/scope_methods.rb:95:in `emit_matches'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/scope_methods.rb:29:in `block in each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/scope_methods.rb:28:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/scope_methods.rb:28:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:81:in `block in emit_scope_matches'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:80:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:80:in `emit_scope_matches'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:42:in `block in each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:109:in `emit_scope'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:95:in `block in scopes'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:94:in `each_object'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:94:in `scopes'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:41:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:41:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/runner.rb:73:in `run'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/runner.rb:52:in `initialize'
    from /home/hal/.gem/ruby/1.9.1/gems/adamantium-0.0.5/lib/adamantium/class_methods.rb:15:in `new'
    from /home/hal/.gem/ruby/1.9.1/gems/adamantium-0.0.5/lib/adamantium/class_methods.rb:15:in `new'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/support/method_object.rb:28:in `run'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/cli.rb:22:in `run'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/bin/mutant:14:in `'
    from /home/hal/bin/mutant:23:in `load'
    from /home/hal/bin/mutant:23:in `'

Add a self-test mode

Right now in order to test mutant we run it against existing projects that we own, and then report issues. The problem is that mutant proceeds through all the mutations in series, and stops at the first error. This is pretty inefficient, since it means we have to do multiple round-trips in order to report bugs that may have always been there.

What I propose we setup is:

  • A rake task that uses a special Gemfile containing a list of all known 100% mutation covered ruby gems (and/or a list of gems that use mutant in any way). It will fetch and run their rake metrics:mutant tasks with the current version of mutant.

Allow subject blacklisting from CLI

As much as I want to strive for 100% mutation coverage, there's some cases where it just becomes tedious:

  • Accessors with default values
  • Configuration objects
  • Private utility methods
  • etc

I find myself working around that. What do you guys think about adding a --skip-missing-specs flag that only runs mutations for methods that you have specs defined for?

Dealing with instance variable not initialized warnings

I'm struggling to find a good pattern for gating a single-run block of code, while also appeasing the mutation testing:

class Parent
  def self.do_stuff
    unless defined? @done_stuff
      # do heavy stuff
      @done_stuff = true
    end

    :did_stuff
  end
end

class Child < Parent; end

By using defined? instead of a straight up unless @done_stuff test, I avoid warning: instance variable @done_stuff not initialized. However mutant rightly complains that the value of the @done_stuff = true assignment is irrelevant.

I could add an extra check and test over the value of @done_stuff, but that's pointless and doesn't help the logic any. Or I could drop the defined? check, and just suffer through the warning.

And in my particular case, I've got a class hierarchy: I want the block to run once per class, and I'd like to avoid metaprogramming to fill in a value for @done_stuff on subclassing events.

Have you guys run into any patterns to tackle this?

Class method called "underscore" is not tested correctly

Given there is a method Inflecto.underscore, then mutant tries to test spec/unit//class_methods/underscore_spec.rb

:!mutant -r ./spec/spec_helper.rb --rspec-dm2 ::Inflecto\.underscore

Spec file(s): "spec/unit//class_methods/underscore_spec.rb" not found for Inflecto.underscore:/Users/indrek/inflecto/lib/inflecto.rb:43:9f2af
...
...
Took: (0.05s)

subjects:   1
mutations:  52
noop_fails: 0
kills:      17
alive:      35
mtime:      3.23s
rtime:      3.56s

Using it on a Rails app

Is anyone using this on a Rails app?

I'm sure it's possible but I can not find an example or documentation for the mutant command line parameters to figure out what is the correct way to use it on a rails app.

Any help or pointers appreciated.

Add Mutation: !!expression -> expression

The purpose behind the double-bang statement is to coerce the value returned by expression into a boolean. It is assumed that it is not a boolean, and rather a nil or some other object.

This mutation will ensure that the tests actually test the non-boolean case and/or identify a place where code was cargo-culted, and the expression cannot actually be anything besides a boolean.

Failing noop mutations

This evening to git abstract_type to pass with mutant and devtools (yay!). After that I decided to try to refactor the string based class_eval to simply use #define_method to add the methods. When I finished I ran the specs, and they passed, then I ran mutant and got this:

!!! Mutant alive: rspec:noop:AbstractType::ClassMethods#create_abstract_instance_method:/Users/dkubb/Dropbox/Home/Programming/open-source/abstract_type/lib/abstract_type.rb:108:35545 !!!
def create_abstract_instance_method(name)
  define_method(name) do
    raise(NotImplementedError, "#{self.class.inspect}##{name} is not implemented")
  end
end
Took: (0.07s)
!!! Mutant alive: rspec:noop:AbstractType::ClassMethods#create_abstract_singleton_method:/Users/dkubb/Dropbox/Home/Programming/open-source/abstract_type/lib/abstract_type.rb:92:8a5ec !!!
def create_abstract_singleton_method(name)
  singleton_class.class_eval do
    define_method(name) do
      raise(NotImplementedError, "#{inspect}.#{name} is not implemented")
    end
  end
end

I'm not entirely sure what this means, but I assume it has something to do with mutant taking the method, not performing any mutations on it, and just using to_source to write it out and run the specs against that. I figured you'd want reports when this happens.

Visibility mutation

Mutate method from having public visibility, to having private visibility. This makes sure cases where the method is called from other member method, but not from its public interface, are caught.

Emitter#visit error: undefined method `type' for nil:NilClass

I just ran mutant against axiom and saw the following error:

0
(00/00)   0% - 0.00s
Axiom::Algebra::Rename::Aliases#union:/Users/dkubb/Dropbox/Home/Programming/open-source/axiom/lib/axiom/algebra/rename/aliases.rb:86
.............................rake aborted!
undefined method `type' for nil:NilClass
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:83:in `visit'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:164:in `visit'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:179:in `block in delimited'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:178:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:178:in `each_with_index'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:178:in `delimited'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter/send/index.rb:70:in `block in emit_arguments'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:141:in `parentheses'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter/send/index.rb:27:in `parentheses'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter/send/index.rb:69:in `emit_arguments'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter/send/index.rb:17:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:68:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:53:in `emit'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter/send.rb:108:in `run'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter/send.rb:40:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:68:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:53:in `emit'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser/emitter.rb:87:in `visit'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/unparser-0.0.3/lib/unparser.rb:23:in `unparse'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node.rb:17:in `identity'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:85:in `new?'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:117:in `emit'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node.rb:171:in `emit_self'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node/send.rb:71:in `mutate_arguments'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node/send.rb:46:in `normal_dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node/send.rb:25:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:70:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:17:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node.rb:128:in `mutate_child'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node.rb:35:in `block in define_named_child'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node/if.rb:60:in `mutate_else_branch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node/if.rb:22:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:70:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:17:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:44:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:44:in `block in dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:43:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:43:in `each_with_index'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:43:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:70:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:176:in `run'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:63:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:70:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util.rb:21:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node/begin.rb:19:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:70:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:17:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node.rb:128:in `mutate_child'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node.rb:35:in `block in define_named_child'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node/block.rb:23:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:70:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:17:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:44:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:44:in `block in dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:43:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:43:in `each_with_index'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:43:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:70:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:176:in `run'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util/array.rb:63:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:70:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/util.rb:21:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node/begin.rb:19:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:70:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:17:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node.rb:128:in `mutate_child'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node.rb:35:in `block in define_named_child'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator/node/define.rb:18:in `dispatch'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:70:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/mutator.rb:17:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/subject.rb:18:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/runner/subject.rb:73:in `map'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/runner/subject.rb:73:in `run'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/runner.rb:26:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/runner/subject.rb:26:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/support/method_object.rb:29:in `run'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/runner/config.rb:62:in `block in run_subjects'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/methods.rb:63:in `block in emit_matches'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/method.rb:27:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/methods.rb:62:in `emit_matches'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/methods.rb:21:in `block in each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/methods.rb:20:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/methods.rb:20:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher.rb:21:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/scope.rb:26:in `block in each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/scope.rb:25:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/scope.rb:25:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher.rb:21:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/namespace.rb:22:in `block in each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/namespace.rb:65:in `emit_scope'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/namespace.rb:51:in `block in scopes'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/namespace.rb:50:in `each_object'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/namespace.rb:50:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/namespace.rb:50:in `scopes'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/namespace.rb:21:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/matcher/namespace.rb:21:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/cli/classifier.rb:94:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/config.rb:22:in `subjects'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/runner/config.rb:61:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/runner/config.rb:61:in `map'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/runner/config.rb:61:in `run_subjects'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/runner/config.rb:75:in `run'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/runner.rb:26:in `initialize'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/support/method_object.rb:29:in `run'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/mutant-8c9411cfbab4/lib/mutant/cli.rb:26:in `run'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bundler/gems/devtools-e9a19f03c4b9/tasks/metrics/mutant.rake:18:in `block (2 levels) in <top (required)>'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/task.rb:246:in `call'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/task.rb:246:in `block in execute'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/task.rb:241:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/task.rb:241:in `execute'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/task.rb:184:in `block in invoke_with_call_chain'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/task.rb:177:in `invoke_with_call_chain'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/task.rb:170:in `invoke'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/application.rb:143:in `invoke_task'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/application.rb:101:in `block (2 levels) in top_level'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/application.rb:101:in `each'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/application.rb:101:in `block in top_level'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/application.rb:110:in `run_with_threads'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/application.rb:95:in `top_level'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/application.rb:73:in `block in run'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/application.rb:160:in `standard_exception_handling'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429@global/gems/rake-10.0.4/lib/rake/application.rb:70:in `run'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bin/ruby_noexec_wrapper:14:in `eval'
/Users/dkubb/.rvm/gems/ruby-1.9.3-p429/bin/ruby_noexec_wrapper:14:in `<main>'
Tasks: TOP => metrics:mutant
(See full trace by running task with --trace)

Bizarre mutation of empty method

In one of my classes I have something like this:

class ApplicationController < ActionController::API
  def flash
  end
end

It's just a stub method I had to add for inherited_resources to function, since I'm not using flash messages in this app, yet i_r assumes it's always present.

Anyway, the resulting mutation is quite bizarre:

@@ -1,3 +2,4 @@
+  ::Object.new
 def flash
 end
(00/01)   0% - 0.12s

Obviously this is one mutation I can't kill ;)

Add a switch to disable return value propagation

  def emit_statement(stmt)
    sql = emit_keyword(stmt.keyword)

    unless stmt.argument.nil?
      sql << @space << emit(stmt.argument)
    end

    unless stmt.clauses.empty?
      sql << @space << emit_clauses(stmt.clauses)
    end

-    return sql
+    sql
  end

Rescue Interrupt

When Ctrl^Cing during mutations, mutant prints a very long backtrace.

Scalar boundary mutations (dkubb)

rather than taking literals and mutating them to random values, wdyt about tiny mutations that are designed to ensure boundary tests are covered? so
for example, the literal integer 10 would be mutated to both 9 and 11. a string could add/remove the leading or trailing characters, etc

Add --rspec-per-file strategy

I'm not sure if this is the best name, but the general idea is that the majority of rails projects organize their specs in a class-per-spec-file organization.

For example a class named User will have a spec named user_spec.rb and it'll include the tests for all the methods in User.

Now, the tricky part is that not everyone has these in the same location. In my rails app, assuming User is a model, I would have this in spec/unit/models/user_spec.rb. Some rails users may have this in spec/models/user_spec.rb. I'm not sure the spec root can be configurable, but it's something to keep in mind.

This feature would make mutant more usable to rails users and greatly speed up the time it takes to run against medium/large rails apps.

Random mutations should be deterministic

Hi,

if Mutant uses random values for mutations the resulting hashes are also different. This makes it for example impossible to use the whitelist feature I just discovered with this mutations.

@@ -1,5 +1,5 @@
 def initialize(template_path, type_map = {})
   @template_path = ((template_path) + ("/"))
-  @type_map = type_map
+  @s5fb367a6064f25db2c12 = type_map
 end

[...]

Finished in 0.05208 seconds
2 examples, 1 failure

Failed examples:

rspec ./spec/unit/zero/renderer/render_spec.rb:31 # Zero::Renderer#render renders json content

Randomized with seed 32825

Killed: rspec:Zero::Renderer#initialize:/home/stormwind/zero/lib/zero/renderer.rb:36:6fd6f (0.36s)

6fd6f here.

@@ -1,5 +1,5 @@
 def initialize(template_path, type_map = {})
   @template_path = ((template_path) + ("/"))
-  @type_map = type_map
+  @sa906d63019dc844d8bf6 = type_map
 end

[...]

Finished in 0.10745 seconds
44 examples, 1 failure

Failed examples:

rspec ./spec/unit/zero/renderer/render_spec.rb:50 # Zero::Renderer#render uses the context

Randomized with seed 3820

Killed: rspec:Zero::Renderer#initialize:/home/stormwind/zero/lib/zero/renderer.rb:36:76bc8 (0.37s)

And 76bc8 here.

Expand complex predicates into simpler conditional, then mutate

One thing I've found when specifying compound statements like foo <= bar is that to test it properly, I need to expand it into foo < bar || foo == bar, then mutate that statement. Simply changing the sign does not expose all possible mutations.

It would be nice for mutant to expand those statements first, then mutate the expanded expression.

Mutant crash when mutating binary operator with splat arguments.

Hi.

I'm running mutant over my project at cstorey/srsrb, and I seem to have found a crasher bug.

If you check out the project from the above URL, and setup with bundler install --binstubs bin. Under ruby-1.9.3-p392 (although I don't think it's ruby version specific), I run:

bin/mutant -I lib -r srsrb/main --rspec-full  ::'SRSRB::CardEditorApp#card_models_as_dictionary'

I get a crash as shown in https://gist.github.com/cstorey/5329832 . As you can see from the output, I've added some debugging around Mutant::Mutator::Node::Send::BinaryOperatorMethod#dispatch, that just dumps out self and re-raises when it encounters an ArgumentError.

The code in question is lib/srsrb/rackapp.rb:113, which looks like:

      deck_view.card_models.to_enum.
        flat_map { |model_id| [model_id.to_guid, deck_view.card_model(model_id).name] }.
        into { |kvs| Hash[*kvs] }

The offending line is the #into call. Looking at Mutant::Mutator::Node::Send::BinaryOperatorMethod, it looks like @right is unexpectedly nil. At that point, @right is:

  #<Rubinius::AST::ActualArguments:0x007f84e6f8a6e8
   @array=[],
   @line=113,
   @splat=
    #<Rubinius::AST::SplatValue:0x007f84e6f8a738
     @line=113,
     @value=
      #<Rubinius::AST::LocalVariableAccess:0x007f84e6f8a760
       @line=113,
       @name=:kvs,
       @variable=nil>>>

So It looks like we don't handle the case where the right hand side of the operator is a splat. Granted, that's probably a quite unusual case.

The trivial patch in hack.patch seems to allow mutant to continue beyond that point, but I'm really not sure if that's the right thing to do.

I'm happy to provide a pull request, but I'm not familiar enough with the code base to know what the right fix would be. I'd guess we'd need to have a case to handle splats, but I don't see any references to splat in mutant, at least.

New mutation for splat array to nil

In ice_nine there is a method called IceNine::Freezer.const_lookup. It has a #const_defined? method that accepts a splat of *SKIP_ANCESTORS.

The thing is this passed mutant until I changed it to false, so I had:

const_get(namespace) if const_defined?(namespace, false)

mutant changed this to:

const_get(namespace) if const_defined?(namespace, nil)

.. and the specs still passed.

I think a new mutation should be added that will replace the splat arguments with nil.

Noop fail

!!! Mutant alive: rspec:noop:Ronin::SQL::Emitter#emit_null:/vault/1/code/ronin/ronin-sql/lib/ronin/sql/emitter.rb:111:6eba2 !!!
def emit_null
  emit_keyword(:NULL)
end

Original code:

  def emit_null
    emit_keyword(:NULL)
  end

Error running mutant -I lib -r lib-name --rspec-unit ::ModuleName

After running the above command I got the following error message:

/home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-melbourne-2.0.3/lib/melbourne/processor.rb:7:in `process_parse_error': undefined method `from' for SyntaxError:Class (NoMethodError)
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-melbourne-2.0.3/lib/melbourne.rb:109:in `string_to_ast_19'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-melbourne-2.0.3/lib/melbourne.rb:109:in `parse_string'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-melbourne-2.0.3/lib/melbourne.rb:55:in `parse_string'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-melbourne-2.0.3/lib/melbourne.rb:29:in `to_ast'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/method.rb:137:in `ast'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/method.rb:195:in `matched_node'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/method.rb:181:in `subject'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/adamantium-0.0.7/lib/adamantium/module_methods.rb:86:in `call'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/adamantium-0.0.7/lib/adamantium/module_methods.rb:86:in `block (2 levels) in define_memoize_method'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/adamantium-0.0.7/lib/adamantium/module_methods.rb:85:in `fetch'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/adamantium-0.0.7/lib/adamantium/module_methods.rb:85:in `block in define_memoize_method'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/method.rb:38:in `each'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/scope_methods.rb:95:in `emit_matches'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/scope_methods.rb:29:in `block in each'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/scope_methods.rb:28:in `each'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/scope_methods.rb:28:in `each'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/object_space.rb:81:in `block in emit_scope_matches'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/object_space.rb:80:in `each'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/object_space.rb:80:in `emit_scope_matches'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/object_space.rb:42:in `block in each'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/object_space.rb:109:in `emit_scope'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/object_space.rb:95:in `block in scopes'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/object_space.rb:94:in `each_object'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/object_space.rb:94:in `scopes'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/object_space.rb:41:in `each'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/matcher/object_space.rb:41:in `each'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/runner.rb:73:in `run'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/runner.rb:52:in `initialize'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/adamantium-0.0.7/lib/adamantium/class_methods.rb:17:in `new'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/support/method_object.rb:28:in `run'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/lib/mutant/cli.rb:22:in `run'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/gems/mutant-0.2.20/bin/mutant:14:in `<top (required)>'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/bin/mutant:19:in `load'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/bin/mutant:19:in `<main>'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/bin/ruby_noexec_wrapper:14:in `eval'
from /home/homer/.rvm/gems/ruby-1.9.3-p392@taskmapper/bin/ruby_noexec_wrapper:14:in `<main>'

Error coming from mutant-melbourne

$ mutant -r ./spec/sql/functions_spec.rb "::Ronin::SQL::Functions" --rspec-full
Mutant configuration:
Matcher:   #
Filter:    Mutant::Mutation::Filter::ALL
Strategy:  #
/home/hal/.gem/ruby/1.9.1/gems/mutant-melbourne-2.0.3/lib/compiler/ast/sends.rb:222:in `initialize': undefined method `peel_lhs' for # (NoMethodError)
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-melbourne-2.0.3/lib/compiler/ast/sends.rb:60:in `new'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-melbourne-2.0.3/lib/compiler/ast/sends.rb:60:in `initialize'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-melbourne-2.0.3/lib/melbourne/processor.rb:106:in `new'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-melbourne-2.0.3/lib/melbourne/processor.rb:106:in `process_call'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-melbourne-2.0.3/lib/melbourne.rb:109:in `string_to_ast_19'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-melbourne-2.0.3/lib/melbourne.rb:109:in `parse_string'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-melbourne-2.0.3/lib/melbourne.rb:55:in `parse_string'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-melbourne-2.0.3/lib/melbourne.rb:29:in `to_ast'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/method.rb:137:in `ast'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/method.rb:195:in `matched_node'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/method.rb:181:in `subject'
    from /home/hal/.gem/ruby/1.9.1/gems/adamantium-0.0.5/lib/adamantium/module_methods.rb:84:in `call'
    from /home/hal/.gem/ruby/1.9.1/gems/adamantium-0.0.5/lib/adamantium/module_methods.rb:84:in `block (2 levels) in define_memoize_method'
    from /home/hal/.gem/ruby/1.9.1/gems/adamantium-0.0.5/lib/adamantium/module_methods.rb:83:in `fetch'
    from /home/hal/.gem/ruby/1.9.1/gems/adamantium-0.0.5/lib/adamantium/module_methods.rb:83:in `block in define_memoize_method'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/method.rb:38:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/scope_methods.rb:95:in `emit_matches'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/scope_methods.rb:29:in `block in each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/scope_methods.rb:28:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/scope_methods.rb:28:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:81:in `block in emit_scope_matches'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:80:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:80:in `emit_scope_matches'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:42:in `block in each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:109:in `emit_scope'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:95:in `block in scopes'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:94:in `each_object'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:94:in `scopes'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:41:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/matcher/object_space.rb:41:in `each'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/runner.rb:73:in `run'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/runner.rb:52:in `initialize'
    from /home/hal/.gem/ruby/1.9.1/gems/adamantium-0.0.5/lib/adamantium/class_methods.rb:15:in `new'
    from /home/hal/.gem/ruby/1.9.1/gems/adamantium-0.0.5/lib/adamantium/class_methods.rb:15:in `new'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/support/method_object.rb:28:in `run'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/lib/mutant/cli.rb:22:in `run'
    from /home/hal/.gem/ruby/1.9.1/gems/mutant-0.2.16/bin/mutant:14:in `'
    from /home/hal/bin/mutant:23:in `load'
    from /home/hal/bin/mutant:23:in `'
$ ruby -v
ruby 1.9.3p362 (2012-12-25 revision 38607) [x86_64-linux]

Mutation causes syntax error

@mbj just testing mutant against ice_nine and I ran into a situation where a block was being mutated, and then the source was outputted as something with a syntax error.

For example it will take something like:

[].each { false or break true }

And transform it into:

[].each { false || break true }

Which causes a syntax error.

Mutant clobbers method visibility for private (class) methods

Today @mbj and I were debugging an issue with Axiom::Types::Set.base? visibility being private when it was defined, but public by the time mutant saw it.

I printed out the source_location for the method before and after and saw that the method was defined 3 lines apart from the original. I think it may be due to how mutant is evaling the source to define a new method, but is forgetting to set the visibility of the method explicitly to match the original.

To test this theory, I printed out the @subject.public? results both before and after the eval in Mutant::Loader#run, and what happened was interesting... printing it out beforehand caused the visibility to be cached, which fixed the whole problem! I think this is a case where laziness was the source of a bug.

I would probably suggest that the visibility (and other information that is modified when the code is eval'd) be cached beforehand in the initialize method or elsewhere.

License missing from gemspec

Some companies will only use gems with a certain license.
The canonical and easy way to check is via the gemspec
via e.g.

spec.license = 'MIT'
# or
spec.licenses = ['MIT', 'GPL-2']

There is even a License Finder to help companies ensure all gems they use
meet their licensing needs. This tool depends on license information being available in the gemspec.
Including a license in your gemspec is a good practice, in any case.

How did I find you?

I'm using a script to collect stats on gems, originally looking for download data, but decided to collect licenses too,
and make issues for missing ones as a public service :)
https://gist.github.com/bf4/5952053#file-license_issue-rb-L13 So far it's going pretty well

Pointless Mutation: adding excess parenthesis

Original code:

  def emit_statement(stmt)
    sql = emit_keyword(stmt.keyword)

    unless stmt.argument.nil?
      sql << @space << emit(stmt.argument)
    end

    unless stmt.clauses.empty?
      sql << @space << emit_clauses(stmt.clauses)
    end

    return sql
  end

Mutated Code:

def emit_statement(stmt)
  sql = emit_keyword(stmt.keyword)
  unless stmt.argument.nil?
    ((((sql) << (@space))) << (emit(stmt.argument)))
  end
  unless stmt.clauses.empty?
    ((((sql) << (@space))) << (emit_clauses(stmt.clauses)))
  end
  return(sql)
end

Mutant tries to mutate methods outside of the target namespace

I had this problem when I used Virtus::ValueObject (master). e.g: https://gist.github.com/indrekj/5278023

Also this:

require "mutant"

module Foo
  module InstanceMethods
    def foo
    end
  end
end

module PublicFoo
  def self.included(base)
    base.instance_eval do
      include Foo::InstanceMethods
    end
  end
end

module PrivateFoo
  def self.included(base)
    base.instance_eval do
      include Foo::InstanceMethods
      private :foo
    end
  end
end

class WithPublicFoo
  include PublicFoo
end

class WithPrivateFoo
  include PrivateFoo
end

puts Mutant::Matcher::ScopeMethods.method_names(WithPublicFoo).inspect #=> []
puts Mutant::Matcher::ScopeMethods.method_names(WithPrivateFoo).inspect #=> [:foo]

ruby 1.9.3p392
mutant 0.2.20

Mutate regexp body

The rbx AST exposes the regexp as #source attribute that containts the source as string. This string could be parsed by a regexp library and the AST could be mutated by an additional mutator tree Mutant::Mutator::Regexp. This will outline many missing testcases.

Regexp literals with interpolation getting mutated into invalid syntax

Regexp literals with interpolation are getting mutated into syntactically invalid structures which is causing mutant to mark these mutations as alive. Example:

-  /#{string}n/
+  //"n"
/Users/michaelfairley/.rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/mutant-.3.0.beta17/lib/mutant/loader.rb:43:in `eval': /Users/michaelfairley/p/mutant-regex/broken.rb:4: syntax error, unexpected tSTRING_BEG, expecting keyword_end (SyntaxError)
    //"n"

I've put together a minimal repro. This behavior occurs on MRI 1.9.3, MRI 2.0.0, and rbx 2.0.0-rc1.

Noop mutation failure

I just ran the latest mutant against a rails app and I saw a noop failure. This was the output:

noop:User.authenticate:/Users/dkubb/Dropbox/Home/Programming/work/jettstream/api/app/models/user.rb:17:d80ba
Parsed subject AST:
(defs
  (self) :authenticate
  (args
    (arg :username)
    (arg :password))
  (send
    (send nil :Maybe
      (send nil :first
        (hash
          (pair
            (sym :email)
            (send
              (send
                (lvar :username) :to_s) :strip))))) :authenticate
    (lvar :password)))
Unparsed source:
def self.authenticate(username, password)
  Maybe(first({:email => username.to_s.strip})).authenticate(password)
end

Neutral mutation that forces default args are specified

def foo(args=[])
  do_something(args)
end

Suggested mutation:

def foo(args=[])
  args = []
  do_something(args)
end

This will force spec author to test both, default and non default behavior.

This is a neutral mutation. A mutation that should NOT make your specs red.

Dubious Mutation: super(*arguments) -> super

Alive: rspec:Ronin::SQL::Fields#method_missing:/vault/1/code/ronin/ronin-sql/lib/ronin/sql/fields.rb:55:1ff3e (2.24s)
@@ -2,7 +2,7 @@
   if ((arguments.empty?) && (block.nil?))
     Field.new(name)
   else
-    super(name, *arguments, &block)
+    super
   end
 end

Mutation bug: "Can't change the value of self"

I just found a bug in how mutant mutates expressions like: self.attr ||= something, eg:

/Users/dkubb/.rvm/gems/ruby-2.0.0-p247@jettstream-api/gems/mutant-0.3.0.beta13/lib/mutant/loader.rb:43:in `eval': /Users/dkubb/Dropbox/Home/Programming/work/jettstream/api/app/models/child/questionnaire/answer.rb:37: Can't change the value of self (SyntaxError)
          self ||= option.questionnaire_id
                  ^
evil:Child::Questionnaire::Answer#set_default_questionnaire_id:/Users/dkubb/Dropbox/Home/Programming/work/jettstream/api/app/models/child/questionnaire/answer.rb:32:bce57
@@ -1,6 +1,6 @@
 def set_default_questionnaire_id
   if option
-    self.questionnaire_id ||= option.questionnaire_id
+    self ||= option.questionnaire_id
   end
 end

noop mutation failure

I'm running into a bizarre problem with noop mutations. I have an rspec suite that passes, but the noop mutator immediately breaks them.

I don't understand what's going on, so I've tried to cut down the code to the minimal failing case. I've stuck the code here: https://github.com/jessekempf/mutant-breaker.

I've included the gemspec and Gemfile.lock because there is a non-zero probability that there's some version conflict going on under the hood that's subtly breaking mutant, since when I added the mutant-breaker code to mutant/test_app, I was unable to reproduce the problem.

Here's a terminal transcript showing what I'm seeing:

jesse.kempf:~/workspace/account-reifier/ddiflib-mutant2 [git: extract_ddiflib] $ gem install mutant --pre
skip "always_verify_ssl_certificates"
Fetching: mutant-0.3.0.beta18.gem (100%)
Successfully installed mutant-0.3.0.beta18
1 gem installed
Installing ri documentation for mutant-0.3.0.beta18...
Building YARD (yri) index for mutant-0.3.0.beta18...
Installing RDoc documentation for mutant-0.3.0.beta18...
jesse.kempf:~/workspace/account-reifier/ddiflib-mutant2 [git: master] $ gem list | grep mutant
skip "always_verify_ssl_certificates"
mutant (0.3.0.beta18)
jesse.kempf:~/workspace/account-reifier/ddiflib-mutant2 [git: extract_ddiflib] $ bundle update
Fetching gem metadata from http://rubygems.org/...........
Fetching gem metadata from http://rubygems.org/..
Resolving dependencies...
Using i18n (0.6.4) 
Using minitest (4.7.5) 
Using multi_json (1.7.7) 
Using atomic (1.1.10) 
Using thread_safe (0.1.0) 
Using tzinfo (0.3.37) 
Using activesupport (4.0.0) 
Using arrayfields (4.7.4) 
Using ast (1.1.0) 
Using awesome_print (1.1.0) 
Using bluff (0.1.0) 
Using parallel (0.6.2) 
Using cane (2.5.2) 
Using ffi (1.9.0) 
Using childprocess (0.3.9) 
Using chronic (0.9.1) 
Using hirb (0.7.1) 
Using json_pure (1.8.0) 
Using fattr (2.2.1) 
Using map (6.2.0) 
Using main (5.2.0) 
Using sexp_processor (4.2.1) 
Using ruby_parser (3.1.3) 
Using churn (0.0.28) 
Using code_analyzer (0.3.2) 
Using coderay (1.0.9) 
Using colored (1.2) 
Using sysexits (1.0.2) 
Using thor (0.15.3) 
Using ddiflib (0.0.1) from source at /Users/jessekempf/workspace/account-reifier/ddiflib-mutant2 
Using diff-lcs (1.2.4) 
Using erubis (2.7.0) 
Using flay (2.0.1) 
Using flog (3.2.2) 
Using formatador (0.2.4) 
Using rb-fsevent (0.9.3) 
Using rb-inotify (0.9.0) 
Using rb-kqueue (0.2.0) 
Using listen (1.2.2) 
Using lumberjack (1.0.4) 
Using method_source (0.8.1) 
Using slop (3.4.5) 
Using pry (0.9.12.2) 
Using guard (1.8.1) 
Using ruby2ruby (2.0.6) 
Using reek (1.3.1) 
Using guard-reek (0.0.4) 
Using rspec-core (2.13.1) 
Using rspec-expectations (2.13.0) 
Using rspec-mocks (2.13.1) 
Using rspec (2.13.0) 
Using guard-rspec (3.0.2) 
Using parser (2.0.0.beta5) 
Using rainbow (1.1.4) 
Using rubocop (0.8.3) 
Using tins (0.8.3) 
Using term-ansicolor (1.2.2) 
Using guard-rubocop (0.0.4) 
Using japgolly-Saikuro (1.1.1.0) 
Using metric_fu-roodi (2.2.1) 
Using progressbar (0.20.0) 
Using rails_best_practices (1.13.2) 
Using redcard (1.1.0) 
Using metric_fu (4.2.1) 
Using simplecov-html (0.7.1) 
Using simplecov (0.7.1) 
Using bundler (1.3.5) 
Your bundle is updated!
jesse.kempf:~/workspace/account-reifier/ddiflib-mutant2 [git: master] $ rspec
.

Finished in 0.00135 seconds
1 example, 0 failures
jesse.kempf:~/workspace/account-reifier/ddiflib-mutant2 [git: master] $ RUBYLIB=lib RUBYOPT="-r ddiflib" mutant --rspec-full '::DDIFLib.decode'
Mutant configuration:
Matcher:  #<Mutant::CLI::Classifier::Method identifier="::DDIFLib.decode">
Filter:   Mutant::Mutation::Filter::ALL
Strategy: Mutant::Strategy::Rspec::Full
DDIFLib.decode:/Users/jessekempf/workspace/account-reifier/ddiflib-mutant2/lib/ddiflib.rb:7
F................
(16/17)  94% - 3.46s
DDIFLib.decode:/Users/jessekempf/workspace/account-reifier/ddiflib-mutant2/lib/ddiflib.rb:7
noop:DDIFLib.decode:/Users/jessekempf/workspace/account-reifier/ddiflib-mutant2/lib/ddiflib.rb:7:60fde
Parsed subject AST:
(defs
  (self) :decode
  (args)
  (begin
    (lvasgn :envelope
      (send
        (const nil :JSON) :load
        (str "")))
    (if
      (lvar :envelope) nil
      (send nil :raise
        (const nil :CorruptDataError)))))
Unparsed source:
def self.decode
  envelope = JSON.load("")
  unless envelope
    raise(CorruptDataError)
  end
end
(16/17)  94% - 3.46s
Subjects:  1
Mutations: 17
Kills:     16
Runtime:   3.47s
Killtime:  3.46s
Overhead:  0.43%
Coverage:  94.12%
Alive:     1
Nodes handled by genric mutator (type:occurances):
const     : 2
lvar      : 1
self      : 1

Mutant looks pretty spiffy and I really want to use it for a bunch of projects my team is doing at work, so let me know what I can do to help you track this problem down.

BTW, I am in UTC-7.

PS:

To reproduce the issue, here's how I'm invoking mutant:

RUBYLIB=lib RUBYOPT="-r ddiflib" mutant --rspec-full '::DDIFLib.decode'

I have successfully run mutant on other parts of the ddiflib codebase (which I cut out from mutant-breaker because they don't break mutant), so I don't think it's a problem with how I'm running mutant.

Dealing with abstract methods (and unused arguments)

Another question-as-an-issue. What do you guys think the right pattern for dealing with abstract methods is? Similarly: how do we deal w/ unused arguments passed down via the class hierarchy?

Say I've got:

def some_abstract_method(arg1, arg2)
  raise NotImplementedError, "#{self.class}#process_block_annotation is not implemented!"
end

In this case, I can appease mutant by placing arg1 and arg2 in the exception, and test for the specifically. That's ok, I guess.

But there seem to be legitimate cases where you'll want to adhere to a method signature, but not use all of the arguments.

Do we need some way to tag unused arguments that are ok to ignore?

Mutate module or class constant

This is an edge case, but the following code has identical behaviour, provided the same-named method isn't declared in that scope:

Kernel.system(...)
system(...)

@mbj I know you've said you prefer the first one for understandability. I think if the code works the same with less information, then the other should be preferred.

The same rule can be applied to self.class, eg:

class MyClass < ParentClass
  def call(*args)
    self.class.call(*args)
  end

  def one
    self.class.call(1)
  end
end

In this example the self.class could be removed in #one and the code would continue to work.

No mutator to handle: :or_asgn

I just ran edge mutant against axiom-types and with a few tiny tweaks to the rake task in devtools I was able to run mutant and got the following output:

Mutant configuration:
Matcher:  #<Mutant::CLI::Classifier::Namespace::Recursive identification="Axiom::Types*">
Filter:   Mutant::Mutation::Filter::ALL
Strategy: Mutant::Strategy::Rspec::DM2
Axiom::Types.finalize:/Users/dkubb/Dropbox/Home/Programming/open-source/axiom-types/lib/axiom/types.rb:55
......
(100/1)
(06/06) 100% - 0.60s
Axiom::Types.infer:/Users/dkubb/Dropbox/Home/Programming/open-source/axiom-types/lib/axiom/types.rb:43
....
(100/1)
(04/04) 100% - 0.36s
Axiom::Types::Options#accept_options:/Users/dkubb/Dropbox/Home/Programming/open-source/axiom-types/lib/axiom/types/support/options.rb:22
....................
(100/1)
(20/20) 100% - 1.84s
Axiom::Types::Options#accepted_options:/Users/dkubb/Dropbox/Home/Programming/open-source/axiom-types/lib/axiom/types/support/options.rb:103
rake aborted!
No mutator to handle: :or_asgn

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.