mutant 0.9.8 → 0.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -2
- data/Changelog.md +6 -0
- data/README.md +63 -23
- data/config/reek.yml +1 -0
- data/lib/mutant.rb +4 -0
- data/lib/mutant/ast.rb +0 -9
- data/lib/mutant/ast/find_metaclass_containing.rb +48 -0
- data/lib/mutant/ast/meta/send.rb +0 -6
- data/lib/mutant/bootstrap.rb +0 -36
- data/lib/mutant/cli.rb +5 -49
- data/lib/mutant/color.rb +0 -3
- data/lib/mutant/config.rb +0 -8
- data/lib/mutant/context.rb +0 -3
- data/lib/mutant/diff.rb +0 -17
- data/lib/mutant/env.rb +0 -6
- data/lib/mutant/expression/method.rb +6 -6
- data/lib/mutant/expression/methods.rb +6 -6
- data/lib/mutant/expression/parser.rb +0 -6
- data/lib/mutant/integration.rb +0 -18
- data/lib/mutant/isolation/fork.rb +0 -22
- data/lib/mutant/license.rb +11 -0
- data/lib/mutant/matcher.rb +0 -14
- data/lib/mutant/matcher/config.rb +0 -11
- data/lib/mutant/matcher/method.rb +0 -31
- data/lib/mutant/matcher/method/instance.rb +0 -8
- data/lib/mutant/matcher/method/metaclass.rb +86 -0
- data/lib/mutant/matcher/method/singleton.rb +0 -25
- data/lib/mutant/matcher/methods.rb +17 -28
- data/lib/mutant/matcher/namespace.rb +0 -10
- data/lib/mutant/matcher/scope.rb +2 -4
- data/lib/mutant/meta/example/dsl.rb +0 -21
- data/lib/mutant/meta/example/verification.rb +0 -20
- data/lib/mutant/mutation.rb +0 -3
- data/lib/mutant/mutator.rb +1 -29
- data/lib/mutant/mutator/node.rb +1 -66
- data/lib/mutant/mutator/node/and_asgn.rb +0 -3
- data/lib/mutant/mutator/node/argument.rb +0 -15
- data/lib/mutant/mutator/node/arguments.rb +0 -20
- data/lib/mutant/mutator/node/begin.rb +0 -3
- data/lib/mutant/mutator/node/binary.rb +0 -23
- data/lib/mutant/mutator/node/block.rb +0 -15
- data/lib/mutant/mutator/node/break.rb +0 -3
- data/lib/mutant/mutator/node/case.rb +0 -9
- data/lib/mutant/mutator/node/class.rb +0 -3
- data/lib/mutant/mutator/node/conditional_loop.rb +0 -3
- data/lib/mutant/mutator/node/const.rb +0 -3
- data/lib/mutant/mutator/node/define.rb +0 -11
- data/lib/mutant/mutator/node/defined.rb +0 -3
- data/lib/mutant/mutator/node/dstr.rb +0 -3
- data/lib/mutant/mutator/node/dsym.rb +0 -3
- data/lib/mutant/mutator/node/generic.rb +0 -3
- data/lib/mutant/mutator/node/if.rb +0 -12
- data/lib/mutant/mutator/node/index.rb +0 -27
- data/lib/mutant/mutator/node/kwbegin.rb +0 -3
- data/lib/mutant/mutator/node/literal.rb +0 -3
- data/lib/mutant/mutator/node/literal/array.rb +0 -6
- data/lib/mutant/mutator/node/literal/boolean.rb +0 -4
- data/lib/mutant/mutator/node/literal/float.rb +0 -9
- data/lib/mutant/mutator/node/literal/hash.rb +0 -9
- data/lib/mutant/mutator/node/literal/integer.rb +0 -9
- data/lib/mutant/mutator/node/literal/nil.rb +0 -3
- data/lib/mutant/mutator/node/literal/range.rb +0 -6
- data/lib/mutant/mutator/node/literal/regex.rb +0 -6
- data/lib/mutant/mutator/node/literal/string.rb +0 -3
- data/lib/mutant/mutator/node/literal/symbol.rb +0 -3
- data/lib/mutant/mutator/node/masgn.rb +0 -3
- data/lib/mutant/mutator/node/match_current_line.rb +0 -3
- data/lib/mutant/mutator/node/mlhs.rb +0 -3
- data/lib/mutant/mutator/node/named_value/access.rb +2 -14
- data/lib/mutant/mutator/node/named_value/constant_assignment.rb +0 -9
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +0 -6
- data/lib/mutant/mutator/node/next.rb +0 -3
- data/lib/mutant/mutator/node/noop.rb +0 -3
- data/lib/mutant/mutator/node/nthref.rb +0 -3
- data/lib/mutant/mutator/node/op_asgn.rb +0 -3
- data/lib/mutant/mutator/node/or_asgn.rb +0 -3
- data/lib/mutant/mutator/node/procarg_zero.rb +0 -3
- data/lib/mutant/mutator/node/regopt.rb +0 -6
- data/lib/mutant/mutator/node/resbody.rb +0 -6
- data/lib/mutant/mutator/node/rescue.rb +2 -19
- data/lib/mutant/mutator/node/return.rb +0 -3
- data/lib/mutant/mutator/node/sclass.rb +20 -0
- data/lib/mutant/mutator/node/send.rb +2 -61
- data/lib/mutant/mutator/node/send/attribute_assignment.rb +0 -9
- data/lib/mutant/mutator/node/send/binary.rb +0 -11
- data/lib/mutant/mutator/node/send/conditional.rb +0 -3
- data/lib/mutant/mutator/node/splat.rb +0 -3
- data/lib/mutant/mutator/node/super.rb +0 -3
- data/lib/mutant/mutator/node/when.rb +0 -19
- data/lib/mutant/mutator/node/yield.rb +0 -3
- data/lib/mutant/mutator/node/zsuper.rb +0 -3
- data/lib/mutant/mutator/util/array.rb +0 -6
- data/lib/mutant/mutator/util/symbol.rb +0 -3
- data/lib/mutant/parallel.rb +0 -13
- data/lib/mutant/parallel/driver.rb +0 -10
- data/lib/mutant/parallel/worker.rb +0 -22
- data/lib/mutant/reporter/cli.rb +0 -5
- data/lib/mutant/reporter/cli/format.rb +0 -9
- data/lib/mutant/reporter/cli/printer.rb +0 -40
- data/lib/mutant/reporter/cli/printer/env_progress.rb +0 -15
- data/lib/mutant/reporter/cli/printer/isolation_result.rb +0 -18
- data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +0 -5
- data/lib/mutant/reporter/cli/printer/mutation_result.rb +0 -21
- data/lib/mutant/reporter/cli/printer/status_progressive.rb +0 -8
- data/lib/mutant/reporter/cli/printer/subject_progress.rb +0 -9
- data/lib/mutant/repository/diff.rb +1 -13
- data/lib/mutant/repository/diff/ranges.rb +0 -11
- data/lib/mutant/result.rb +0 -3
- data/lib/mutant/runner.rb +0 -18
- data/lib/mutant/runner/sink.rb +0 -5
- data/lib/mutant/subject.rb +0 -8
- data/lib/mutant/subject/method.rb +0 -3
- data/lib/mutant/subject/method/instance.rb +0 -5
- data/lib/mutant/subject/method/metaclass.rb +30 -0
- data/lib/mutant/transform.rb +0 -92
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/warnings.rb +0 -6
- data/lib/mutant/zombifier.rb +2 -34
- data/meta/and.rb +0 -2
- data/meta/array.rb +0 -3
- data/meta/begin.rb +0 -3
- data/meta/block.rb +0 -3
- data/meta/break.rb +0 -1
- data/meta/case.rb +0 -6
- data/meta/casgn.rb +0 -3
- data/meta/cvasgn.rb +0 -1
- data/meta/def.rb +0 -7
- data/meta/ensure.rb +0 -1
- data/meta/false.rb +0 -1
- data/meta/gvasgn.rb +0 -1
- data/meta/hash.rb +0 -4
- data/meta/if.rb +0 -5
- data/meta/ivasgn.rb +0 -1
- data/meta/kwbegin.rb +0 -1
- data/meta/lvasgn.rb +0 -1
- data/meta/match_current_line.rb +0 -1
- data/meta/next.rb +0 -1
- data/meta/or.rb +0 -2
- data/meta/regexp.rb +0 -1
- data/meta/rescue.rb +0 -6
- data/meta/sclass.rb +12 -0
- data/meta/send.rb +0 -4
- data/meta/true.rb +0 -1
- data/meta/until.rb +0 -1
- data/meta/while.rb +0 -2
- data/meta/yield.rb +0 -1
- data/mutant.sh +12 -0
- data/spec/unit/mutant/ast/find_metaclass_containing_spec.rb +64 -0
- data/spec/unit/mutant/expression/methods_spec.rb +7 -2
- data/spec/unit/mutant/license_spec.rb +15 -3
- data/spec/unit/mutant/matcher/method/metaclass_spec.rb +108 -0
- data/spec/unit/mutant/matcher/methods/metaclass_spec.rb +62 -0
- data/spec/unit/mutant/matcher/namespace_spec.rb +3 -1
- data/spec/unit/mutant/matcher/scope_spec.rb +11 -1
- data/spec/unit/mutant/meta/example_spec.rb +3 -3
- data/spec/unit/mutant/mutator/node_spec.rb +1 -6
- data/spec/unit/mutant/subject/method/metaclass_spec.rb +63 -0
- data/test_app/lib/test_app.rb +1 -0
- data/test_app/lib/test_app/metaclasses.rb +108 -0
- metadata +17 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e6e6e125d0e2736934ed481945e35eada9a1b8fffaf05641a5410a2ed25b9b20
|
|
4
|
+
data.tar.gz: 13e2b48cbc500aab1ef792ccbaff86de593337f7213bdcf7d0d81afa21e7a641
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a3bfbaffad39ee2bc7cf41a07c19031704c26c7d05ba9b3f07d59d3b82965311c0822aec10ab359570fc8c3d3235f36d461fbe39cddb6349997b2b8bd0fa5d3
|
|
7
|
+
data.tar.gz: a1caa7e5f3318001137239c613ddd50bdeabe981fa132f4e9e5a383019a24a53075da121b290e98dcb61c93a1900f79f8e1207ce7ac282d049b2af0351b26e64
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -31,7 +31,7 @@ jobs:
|
|
|
31
31
|
ruby-mutant:
|
|
32
32
|
name: Mutation coverage
|
|
33
33
|
runs-on: ${{ matrix.os }}
|
|
34
|
-
timeout-minutes:
|
|
34
|
+
timeout-minutes: 30
|
|
35
35
|
strategy:
|
|
36
36
|
fail-fast: false
|
|
37
37
|
matrix:
|
|
@@ -47,7 +47,7 @@ jobs:
|
|
|
47
47
|
- run: |
|
|
48
48
|
gem install bundler
|
|
49
49
|
bundle install
|
|
50
|
-
- run:
|
|
50
|
+
- run: ./mutant.sh
|
|
51
51
|
ruby-integration-minitest:
|
|
52
52
|
name: Integration Minitest
|
|
53
53
|
runs-on: ${{ matrix.os }}
|
data/Changelog.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# v0.9.9 2020-09-25
|
|
2
|
+
|
|
3
|
+
+ Add support for mutating methods inside eigenclasses `class <<`. [#1009](https://github.com/mbj/mutant/pull/1009)
|
|
4
|
+
- Remove `<` -> `<=` and `>` -> `>=` mutations as non canonical. [#1020](https://github.com/mbj/mutant/pull/1020)
|
|
5
|
+
- Remove `true` -> `nil` and `false` -> `nil` mutations as non canonical. [#1018](https://github.com/mbj/mutant/pull/1018)
|
|
6
|
+
|
|
1
7
|
# v0.9.8 2020-08-02
|
|
2
8
|
|
|
3
9
|
* Change to generic catch all node mutator. This allows better cross parser version compatibility.
|
data/README.md
CHANGED
|
@@ -7,31 +7,41 @@ mutant
|
|
|
7
7
|
|
|
8
8
|
## What is Mutant?
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
An automated code review tool, with a side effect of producing semantic code coverage
|
|
11
|
+
metrics.
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
Think of mutant as an expert developer that simplifies your code while making sure that all tests pass.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
Coverage becomes a meaningful metric!
|
|
15
|
+
That developer never has a bad day and is always ready to jump on your PR.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Each reported simplification signifies either:
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* Learn something new about the semantics of Ruby and your direct and indirect dependencies.
|
|
19
|
+
A) A piece of code that does more than the tests ask for.
|
|
20
|
+
You can probably use the simplified version of the code. OR:
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
B) If you have a reason to not take the simplified version as it violates a requirement:
|
|
23
|
+
There was no test that proves the extra requirement. Likely you are missing an
|
|
24
|
+
important test for that requirement.
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
On extensive mutant use A) happens more often than B), which leads to overall less code enter
|
|
27
|
+
your repository at higher confidence for both the author and the reviewer.
|
|
28
|
+
|
|
29
|
+
BTW: Mutant is a mutation testing tool, which is a form of code coverage.
|
|
30
|
+
But each reported uncovered mutation is actually a call to action, just like a flag in a code review
|
|
31
|
+
would be.
|
|
32
|
+
|
|
33
|
+
## Getting started:
|
|
34
|
+
|
|
35
|
+
* Start with reading the [nomenclature](/docs/nomenclature.md). No way around that one, sorry.
|
|
26
36
|
* Then select and setup your [integration](/docs/nomenclature.md#integration), also make sure
|
|
27
37
|
you can reproduce the examples in the integration specific documentation.
|
|
28
|
-
*
|
|
29
|
-
|
|
30
|
-
|
|
38
|
+
* Use mutant during code reviews and on CI in [incremental](/docs/incremental.md) mode.
|
|
39
|
+
* Do not merge code with new alive mutations. If you really must bypass:
|
|
40
|
+
Add the subjects with open problems to the ignored subjects.
|
|
31
41
|
|
|
32
42
|
## Ruby Versions
|
|
33
43
|
|
|
34
|
-
Mutant currently only works on cRuby/MRI. Starting with version 2.5.x. It supports all syntax features
|
|
44
|
+
Mutant currently only works on cRuby/MRI. Starting with version 2.5.x. It supports all syntax features up to and
|
|
35
45
|
including Ruby 2.6.
|
|
36
46
|
|
|
37
47
|
Support for 2.7 syntax features is pending, see unparser issue: https://github.com/mbj/unparser/issues/129.
|
|
@@ -43,7 +53,7 @@ Mutant will work under Ruby 2.7 just fine, unless a 2.7 syntax feature is used.
|
|
|
43
53
|
Mutant was recently transitioned commercial software, with a free usage plan for opensource projects.
|
|
44
54
|
|
|
45
55
|
Commercial projects have to acquire a license per developer, with unlimited repositories
|
|
46
|
-
per developer.
|
|
56
|
+
per developer. CI usage for licensed developers is included.
|
|
47
57
|
|
|
48
58
|
Opensource projects have to acquire their free license per repository.
|
|
49
59
|
|
|
@@ -65,22 +75,52 @@ The mutant license gem contains metadata that allows mutant to verify licensed u
|
|
|
65
75
|
For commercial licenses mutant checks the git commit author or the configured git email
|
|
66
76
|
to be in the set of licensed developers.
|
|
67
77
|
|
|
68
|
-
For opensource licenses mutant checks the git remotes against the
|
|
78
|
+
For opensource licenses mutant checks the git remotes against the licensed git repositories.
|
|
69
79
|
This allows the project maintainer to sign up and not bother collaborators with the details.
|
|
70
80
|
|
|
71
|
-
There are, apart from initial license gem installation, no remote
|
|
81
|
+
There are, apart from initial license gem installation, no remote interaction for
|
|
72
82
|
license validation.
|
|
73
83
|
|
|
74
|
-
|
|
84
|
+
### Getting an Opensource license
|
|
85
|
+
|
|
86
|
+
As stated above: Opensource projects of any kind are free to use mutant.
|
|
87
|
+
|
|
88
|
+
Just mail [me](mailto:mbj@schirp-dso.com?subject=Mutant%20Opensource%20License): Please
|
|
89
|
+
include:
|
|
90
|
+
|
|
91
|
+
* Just the git remote URL of your repository. Repository can be anywhere, must not be on Github, just has to be public.
|
|
92
|
+
|
|
93
|
+
I do not need any more details.
|
|
94
|
+
|
|
95
|
+
### Getting a commercial license
|
|
96
|
+
|
|
97
|
+
Mutant offers a per developer subscription a monthly plan for 30$, or an annual plan for 300$.
|
|
98
|
+
|
|
99
|
+
Above 10 developer licensees per customer I'm open to negotiate more discounts.
|
|
100
|
+
|
|
101
|
+
Should you want to procure a commercial mutant license please [mail me](mailto:mbj@schirp-dso.com?subject=Mutant%20Commercial%20License).
|
|
102
|
+
|
|
103
|
+
Please include the following information:
|
|
104
|
+
|
|
105
|
+
* Your invoice address, including your Tax ID (For EU customers VAT-ID is mandatory)
|
|
106
|
+
* Per licensed user the git author email address as returned by `git config user.email`
|
|
107
|
+
|
|
108
|
+
Also feel free to ask any other question I forgot to proactively answer here.
|
|
109
|
+
|
|
110
|
+
#### Payment methods
|
|
111
|
+
|
|
112
|
+
* For monthly subscriptions: Exclusively CC.
|
|
113
|
+
* For annual subscriptions: CC (worldwide) or ACH (US) / SEPA (EU) wire transfer.
|
|
75
114
|
|
|
76
|
-
|
|
115
|
+
#### Pricing Why?
|
|
77
116
|
|
|
78
|
-
|
|
117
|
+
The idea is to charge 1$ per developer per day. Mutant reduces the time spend on code reviews.
|
|
79
118
|
|
|
80
|
-
|
|
81
|
-
Yearly prepayments with discounts are available.
|
|
119
|
+
This time saved should be worth way more than the 1$ per day.
|
|
82
120
|
|
|
83
|
-
|
|
121
|
+
If you think this is not true for your code base, either my claims are wrong our your use of mutant is wrong.
|
|
122
|
+
I'd be happy to hear about your case as I'm certainly willing to help you in using mutant right, and in case
|
|
123
|
+
I'm wrong I'd be happy to improve mutant to the point I'm right again.
|
|
84
124
|
|
|
85
125
|
## Topics
|
|
86
126
|
|
data/config/reek.yml
CHANGED
|
@@ -136,3 +136,4 @@ detectors:
|
|
|
136
136
|
- Mutant::Reporter::CLI::Printer::StatusProgressive#object # False positive calls super
|
|
137
137
|
- Mutant::Repository::Diff#tracks? # intentional, private
|
|
138
138
|
- Mutant::Repository::Diff#within_working_directory? # intentional, private
|
|
139
|
+
- Mutant::AST::FindMetaclassContaining#include_exact? # intentional, private
|
data/lib/mutant.rb
CHANGED
|
@@ -51,6 +51,7 @@ require 'mutant/ast/types'
|
|
|
51
51
|
require 'mutant/ast/nodes'
|
|
52
52
|
require 'mutant/ast/named_children'
|
|
53
53
|
require 'mutant/ast/node_predicates'
|
|
54
|
+
require 'mutant/ast/find_metaclass_containing'
|
|
54
55
|
require 'mutant/ast/meta'
|
|
55
56
|
require 'mutant/ast/meta/send'
|
|
56
57
|
require 'mutant/ast/meta/const'
|
|
@@ -112,6 +113,7 @@ require 'mutant/mutator/node/send/conditional'
|
|
|
112
113
|
require 'mutant/mutator/node/send/attribute_assignment'
|
|
113
114
|
require 'mutant/mutator/node/when'
|
|
114
115
|
require 'mutant/mutator/node/class'
|
|
116
|
+
require 'mutant/mutator/node/sclass'
|
|
115
117
|
require 'mutant/mutator/node/define'
|
|
116
118
|
require 'mutant/mutator/node/mlhs'
|
|
117
119
|
require 'mutant/mutator/node/nthref'
|
|
@@ -134,11 +136,13 @@ require 'mutant/subject'
|
|
|
134
136
|
require 'mutant/subject/method'
|
|
135
137
|
require 'mutant/subject/method/instance'
|
|
136
138
|
require 'mutant/subject/method/singleton'
|
|
139
|
+
require 'mutant/subject/method/metaclass'
|
|
137
140
|
require 'mutant/matcher'
|
|
138
141
|
require 'mutant/matcher/config'
|
|
139
142
|
require 'mutant/matcher/chain'
|
|
140
143
|
require 'mutant/matcher/method'
|
|
141
144
|
require 'mutant/matcher/method/singleton'
|
|
145
|
+
require 'mutant/matcher/method/metaclass'
|
|
142
146
|
require 'mutant/matcher/method/instance'
|
|
143
147
|
require 'mutant/matcher/methods'
|
|
144
148
|
require 'mutant/matcher/namespace'
|
data/lib/mutant/ast.rb
CHANGED
|
@@ -27,15 +27,6 @@ module Mutant
|
|
|
27
27
|
path
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
# Walk all ast nodes keeping track of path
|
|
31
|
-
#
|
|
32
|
-
# @param [Parser::AST::Node] root
|
|
33
|
-
# @param [Array<Parser::AST::Node>] stack
|
|
34
|
-
#
|
|
35
|
-
# @yield [Parser::AST::Node]
|
|
36
|
-
# all nodes visited recursively including root
|
|
37
|
-
#
|
|
38
|
-
# @return [undefined]
|
|
39
30
|
def self.walk(node, stack, &block)
|
|
40
31
|
block.call(node, stack)
|
|
41
32
|
node.children.grep(::Parser::AST::Node) do |child|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mutant
|
|
4
|
+
module AST
|
|
5
|
+
# Given an AST, finds the sclass that directly(-ish) contains the provided
|
|
6
|
+
# node.
|
|
7
|
+
# This won't match arbitrarily complex structures - it only searches the
|
|
8
|
+
# first level deep (no begins-in-begins, for example). This is in
|
|
9
|
+
# keeping with mutant generally not supporting 'weird' syntax.
|
|
10
|
+
# Descending into 'begin' nodes is supported because these are generated for
|
|
11
|
+
# the one-line syntax class << self; def foo; end
|
|
12
|
+
class FindMetaclassContaining
|
|
13
|
+
include NodePredicates, Concord.new(:root, :target), Procto.call
|
|
14
|
+
|
|
15
|
+
SCLASS_BODY_INDEX = 1
|
|
16
|
+
|
|
17
|
+
private_constant(*constants(false))
|
|
18
|
+
|
|
19
|
+
# Find metaclass node containing target node
|
|
20
|
+
#
|
|
21
|
+
# @return [Parser::AST::Node, nil]
|
|
22
|
+
#
|
|
23
|
+
# @api private
|
|
24
|
+
def call
|
|
25
|
+
AST.find_last_path(root) do |current|
|
|
26
|
+
next unless n_sclass?(current)
|
|
27
|
+
|
|
28
|
+
metaclass_of?(current)
|
|
29
|
+
end.last
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def metaclass_of?(sclass)
|
|
35
|
+
body = sclass.children.fetch(SCLASS_BODY_INDEX)
|
|
36
|
+
body.equal?(target) || transparently_contains?(body)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def transparently_contains?(body)
|
|
40
|
+
n_begin?(body) && include_exact?(body.children, target)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def include_exact?(haystack, needle)
|
|
44
|
+
haystack.any? { |elem| elem.equal?(needle) }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
data/lib/mutant/ast/meta/send.rb
CHANGED
|
@@ -56,16 +56,10 @@ module Mutant
|
|
|
56
56
|
|
|
57
57
|
private
|
|
58
58
|
|
|
59
|
-
# Test if node is `proc { ... }`
|
|
60
|
-
#
|
|
61
|
-
# @return [Boolean]
|
|
62
59
|
def naked_proc?
|
|
63
60
|
!receiver && selector.equal?(:proc)
|
|
64
61
|
end
|
|
65
62
|
|
|
66
|
-
# Test if node is `Proc.new { ... }`
|
|
67
|
-
#
|
|
68
|
-
# @return [Boolean]
|
|
69
63
|
def proc_new?
|
|
70
64
|
receiver &&
|
|
71
65
|
selector.equal?(:new) &&
|
data/lib/mutant/bootstrap.rb
CHANGED
|
@@ -49,9 +49,6 @@ module Mutant
|
|
|
49
49
|
end
|
|
50
50
|
# rubocop:enable Metrics/MethodLength
|
|
51
51
|
|
|
52
|
-
# Infect environment
|
|
53
|
-
#
|
|
54
|
-
# @return [undefined]
|
|
55
52
|
def self.infect(env)
|
|
56
53
|
config, world = env.config, env.world
|
|
57
54
|
|
|
@@ -60,12 +57,6 @@ module Mutant
|
|
|
60
57
|
end
|
|
61
58
|
private_class_method :infect
|
|
62
59
|
|
|
63
|
-
# Matchable scopes
|
|
64
|
-
#
|
|
65
|
-
# @param [World] world
|
|
66
|
-
# @param [Config] config
|
|
67
|
-
#
|
|
68
|
-
# @return [Array<Scope>]
|
|
69
60
|
def self.matchable_scopes(world, config)
|
|
70
61
|
scopes = world.object_space.each_object(Module).each_with_object([]) do |scope, aggregate|
|
|
71
62
|
expression = expression(config.reporter, config.expression_parser, scope) || next
|
|
@@ -76,15 +67,6 @@ module Mutant
|
|
|
76
67
|
end
|
|
77
68
|
private_class_method :matchable_scopes
|
|
78
69
|
|
|
79
|
-
# Scope name from scoping object
|
|
80
|
-
#
|
|
81
|
-
# @param [Class, Module] scope
|
|
82
|
-
#
|
|
83
|
-
# @return [String]
|
|
84
|
-
# if scope has a name and does not raise exceptions obtaining it
|
|
85
|
-
#
|
|
86
|
-
# @return [nil]
|
|
87
|
-
# otherwise
|
|
88
70
|
def self.scope_name(reporter, scope)
|
|
89
71
|
scope.name
|
|
90
72
|
rescue => exception
|
|
@@ -99,20 +81,7 @@ module Mutant
|
|
|
99
81
|
end
|
|
100
82
|
private_class_method :scope_name
|
|
101
83
|
|
|
102
|
-
# Try to turn scope into expression
|
|
103
|
-
#
|
|
104
|
-
# @param [Expression::Parser] expression_parser
|
|
105
|
-
# @param [Class, Module] scope
|
|
106
|
-
#
|
|
107
|
-
# @return [Expression]
|
|
108
|
-
# if scope can be represented in an expression
|
|
109
|
-
#
|
|
110
|
-
# @return [nil]
|
|
111
|
-
# otherwise
|
|
112
|
-
#
|
|
113
84
|
# rubocop:disable Metrics/MethodLength
|
|
114
|
-
#
|
|
115
|
-
# ignore :reek:LongParameterList
|
|
116
85
|
def self.expression(reporter, expression_parser, scope)
|
|
117
86
|
name = scope_name(reporter, scope) or return
|
|
118
87
|
|
|
@@ -132,11 +101,6 @@ module Mutant
|
|
|
132
101
|
private_class_method :expression
|
|
133
102
|
# rubocop:enable Metrics/MethodLength
|
|
134
103
|
|
|
135
|
-
# Write a semantics warning
|
|
136
|
-
#
|
|
137
|
-
# @return [undefined]
|
|
138
|
-
#
|
|
139
|
-
# ignore :reek:LongParameterList
|
|
140
104
|
def self.semantics_warning(reporter, format, options)
|
|
141
105
|
reporter.warn(SEMANTICS_MESSAGE_FORMAT % { message: format % options })
|
|
142
106
|
end
|
data/lib/mutant/cli.rb
CHANGED
|
@@ -88,23 +88,12 @@ module Mutant
|
|
|
88
88
|
|
|
89
89
|
private
|
|
90
90
|
|
|
91
|
-
# Parse matchers
|
|
92
|
-
#
|
|
93
|
-
# @param [Array<String>] expressions
|
|
94
|
-
#
|
|
95
|
-
# @return [undefined]
|
|
96
91
|
def parse_match_expressions(expressions)
|
|
97
92
|
expressions.each do |expression|
|
|
98
93
|
add_matcher(:match_expressions, config.expression_parser.apply(expression).from_right)
|
|
99
94
|
end
|
|
100
95
|
end
|
|
101
96
|
|
|
102
|
-
# Add environmental options
|
|
103
|
-
#
|
|
104
|
-
# @param [Object] opts
|
|
105
|
-
#
|
|
106
|
-
# @return [undefined]
|
|
107
|
-
#
|
|
108
97
|
# rubocop:disable Metrics/MethodLength
|
|
109
98
|
def add_environment_options(opts)
|
|
110
99
|
opts.separator('Environment:')
|
|
@@ -121,12 +110,8 @@ module Mutant
|
|
|
121
110
|
with(jobs: Integer(number))
|
|
122
111
|
end
|
|
123
112
|
end
|
|
113
|
+
# rubocop:enable Metrics/MethodLength
|
|
124
114
|
|
|
125
|
-
# Add mutation options
|
|
126
|
-
#
|
|
127
|
-
# @param [OptionParser] opts
|
|
128
|
-
#
|
|
129
|
-
# @return [undefined]
|
|
130
115
|
def add_mutation_options(opts)
|
|
131
116
|
opts.separator(nil)
|
|
132
117
|
opts.separator('Options:')
|
|
@@ -136,11 +121,7 @@ module Mutant
|
|
|
136
121
|
end
|
|
137
122
|
end
|
|
138
123
|
|
|
139
|
-
#
|
|
140
|
-
#
|
|
141
|
-
# @param [OptionParser] opts
|
|
142
|
-
#
|
|
143
|
-
# @return [undefined]
|
|
124
|
+
# rubocop:disable Metrics/MethodLength
|
|
144
125
|
def add_filter_options(opts)
|
|
145
126
|
opts.on('--ignore-subject EXPRESSION', 'Ignore subjects that match EXPRESSION as prefix') do |pattern|
|
|
146
127
|
add_matcher(:ignore_expressions, config.expression_parser.apply(pattern).from_right)
|
|
@@ -154,12 +135,9 @@ module Mutant
|
|
|
154
135
|
)
|
|
155
136
|
end
|
|
156
137
|
end
|
|
138
|
+
# rubocop:enable Metrics/MethodLength
|
|
157
139
|
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
# @param [OptionParser] opts
|
|
161
|
-
#
|
|
162
|
-
# @return [undefined]
|
|
140
|
+
# rubocop:disable Metrics/MethodLength
|
|
163
141
|
def add_debug_options(opts)
|
|
164
142
|
opts.on('--fail-fast', 'Fail fast') do
|
|
165
143
|
with(fail_fast: true)
|
|
@@ -173,38 +151,16 @@ module Mutant
|
|
|
173
151
|
world.kernel.exit
|
|
174
152
|
end
|
|
175
153
|
end
|
|
154
|
+
# rubocop:enable Metrics/MethodLength
|
|
176
155
|
|
|
177
|
-
# With configuration
|
|
178
|
-
#
|
|
179
|
-
# @param [Hash<Symbol, Object>] attributes
|
|
180
|
-
#
|
|
181
|
-
# @return [undefined]
|
|
182
156
|
def with(attributes)
|
|
183
157
|
@config = config.with(attributes)
|
|
184
158
|
end
|
|
185
159
|
|
|
186
|
-
# Add configuration
|
|
187
|
-
#
|
|
188
|
-
# @param [Symbol] attribute
|
|
189
|
-
# the attribute to add to
|
|
190
|
-
#
|
|
191
|
-
# @param [Object] value
|
|
192
|
-
# the value to add
|
|
193
|
-
#
|
|
194
|
-
# @return [undefined]
|
|
195
160
|
def add(attribute, value)
|
|
196
161
|
with(attribute => config.public_send(attribute) + [value])
|
|
197
162
|
end
|
|
198
163
|
|
|
199
|
-
# Add matcher configuration
|
|
200
|
-
#
|
|
201
|
-
# @param [Symbol] attribute
|
|
202
|
-
# the attribute to add to
|
|
203
|
-
#
|
|
204
|
-
# @param [Object] value
|
|
205
|
-
# the value to add
|
|
206
|
-
#
|
|
207
|
-
# @return [undefined]
|
|
208
164
|
def add_matcher(attribute, value)
|
|
209
165
|
with(matcher: config.matcher.add(attribute, value))
|
|
210
166
|
end
|