mutant 0.5.17 → 0.5.18

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.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +6 -0
  3. data/Rakefile +13 -0
  4. data/config/flay.yml +1 -1
  5. data/config/reek.yml +8 -1
  6. data/lib/mutant.rb +18 -3
  7. data/lib/mutant/cli.rb +6 -3
  8. data/lib/mutant/constants.rb +3 -0
  9. data/lib/mutant/expression.rb +110 -0
  10. data/lib/mutant/expression/method.rb +92 -0
  11. data/lib/mutant/expression/namespace.rb +90 -0
  12. data/lib/mutant/matcher/namespace.rb +3 -4
  13. data/lib/mutant/meta.rb +31 -0
  14. data/lib/mutant/meta/example.rb +152 -0
  15. data/lib/mutant/meta/example/dsl.rb +105 -0
  16. data/lib/mutant/mutator/node.rb +6 -6
  17. data/lib/mutant/mutator/node/arguments.rb +1 -1
  18. data/lib/mutant/mutator/node/begin.rb +1 -1
  19. data/lib/mutant/mutator/node/const.rb +1 -1
  20. data/lib/mutant/mutator/node/if.rb +6 -6
  21. data/lib/mutant/mutator/node/literal/array.rb +2 -2
  22. data/lib/mutant/mutator/node/literal/hash.rb +2 -2
  23. data/lib/mutant/mutator/node/literal/range.rb +3 -3
  24. data/lib/mutant/mutator/node/literal/regex.rb +2 -2
  25. data/lib/mutant/mutator/node/literal/symbol.rb +1 -1
  26. data/lib/mutant/mutator/node/op_asgn.rb +1 -3
  27. data/lib/mutant/mutator/node/or_asgn.rb +31 -0
  28. data/lib/mutant/mutator/node/send.rb +1 -1
  29. data/lib/mutant/mutator/node/send/attribute_assignment.rb +1 -1
  30. data/lib/mutant/reporter/cli/report/mutation.rb +11 -1
  31. data/lib/mutant/strategy.rb +1 -1
  32. data/lib/mutant/version.rb +1 -1
  33. data/meta/and.rb +12 -0
  34. data/meta/and_asgn.rb +12 -0
  35. data/meta/array.rb +30 -0
  36. data/meta/begin.rb +15 -0
  37. data/meta/binary.rb +12 -0
  38. data/meta/block.rb +55 -0
  39. data/meta/block_pass.rb +8 -0
  40. data/meta/blockarg.rb +10 -0
  41. data/meta/boolean.rb +15 -0
  42. data/meta/break.rb +11 -0
  43. data/meta/case.rb +303 -0
  44. data/meta/casgn.rb +9 -0
  45. data/meta/cbase.rb +8 -0
  46. data/meta/const.rb +9 -0
  47. data/meta/cvar.rb +7 -0
  48. data/meta/cvasgn.rb +10 -0
  49. data/meta/define.rb +118 -0
  50. data/meta/defined.rb +7 -0
  51. data/meta/dstr.rb +10 -0
  52. data/meta/dsym.rb +11 -0
  53. data/meta/ensure.rb +9 -0
  54. data/meta/fixnum.rb +19 -0
  55. data/meta/float.rb +38 -0
  56. data/meta/gvar.rb +7 -0
  57. data/meta/gvasgn.rb +10 -0
  58. data/meta/hash.rb +25 -0
  59. data/meta/if.rb +57 -0
  60. data/meta/ivasgn.rb +10 -0
  61. data/meta/kwbegin.rb +9 -0
  62. data/meta/lvar.rb +14 -0
  63. data/meta/lvasgn.rb +10 -0
  64. data/meta/masgn.rb +7 -0
  65. data/meta/match_current_line.rb +14 -0
  66. data/meta/next.rb +11 -0
  67. data/meta/nil.rb +5 -0
  68. data/meta/nthref.rb +14 -0
  69. data/meta/op_assgn.rb +15 -0
  70. data/meta/or_asgn.rb +22 -0
  71. data/meta/range.rb +41 -0
  72. data/meta/redo.rb +5 -0
  73. data/meta/regex.rb +20 -0
  74. data/meta/rescue.rb +38 -0
  75. data/meta/restarg.rb +11 -0
  76. data/meta/return.rb +15 -0
  77. data/meta/self.rb +7 -0
  78. data/meta/send.rb +240 -0
  79. data/meta/string.rb +7 -0
  80. data/meta/super.rb +26 -0
  81. data/meta/symbol.rb +8 -0
  82. data/meta/unless.rb +15 -0
  83. data/meta/while.rb +24 -0
  84. data/meta/yield.rb +10 -0
  85. data/mutant.gemspec +1 -0
  86. data/spec/integration/mutant/corpus_spec.rb +29 -25
  87. data/spec/spec_helper.rb +2 -0
  88. data/spec/support/mutation_verifier.rb +1 -0
  89. data/spec/unit/mutant/cli_new_spec.rb +6 -6
  90. data/spec/unit/mutant/expression/method_spec.rb +50 -0
  91. data/spec/unit/mutant/expression/namespace/flat_spec.rb +32 -0
  92. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +37 -0
  93. data/spec/unit/mutant/matcher/namespace_spec.rb +2 -2
  94. data/spec/unit/mutant/mutation_spec.rb +1 -1
  95. data/spec/unit/mutant/mutator/node_spec.rb +14 -0
  96. metadata +123 -139
  97. data/lib/mutant/cli/classifier.rb +0 -139
  98. data/lib/mutant/cli/classifier/method.rb +0 -105
  99. data/lib/mutant/cli/classifier/namespace.rb +0 -49
  100. data/spec/unit/mutant/cli/classifier/method_spec.rb +0 -77
  101. data/spec/unit/mutant/cli/classifier/namespace/flat_spec.rb +0 -58
  102. data/spec/unit/mutant/cli/classifier/namespace/recursive_spec.rb +0 -58
  103. data/spec/unit/mutant/cli/classifier_spec.rb +0 -59
  104. data/spec/unit/mutant/mutator/node/and_asgn_spec.rb +0 -19
  105. data/spec/unit/mutant/mutator/node/begin_spec.rb +0 -32
  106. data/spec/unit/mutant/mutator/node/binary_spec.rb +0 -41
  107. data/spec/unit/mutant/mutator/node/block_pass_spec.rb +0 -15
  108. data/spec/unit/mutant/mutator/node/block_spec.rb +0 -83
  109. data/spec/unit/mutant/mutator/node/blockarg_spec.rb +0 -17
  110. data/spec/unit/mutant/mutator/node/case_spec.rb +0 -329
  111. data/spec/unit/mutant/mutator/node/cbase_spec.rb +0 -15
  112. data/spec/unit/mutant/mutator/node/conditional_loop_spec.rb +0 -58
  113. data/spec/unit/mutant/mutator/node/const_spec.rb +0 -16
  114. data/spec/unit/mutant/mutator/node/define_spec.rb +0 -171
  115. data/spec/unit/mutant/mutator/node/defined_spec.rb +0 -14
  116. data/spec/unit/mutant/mutator/node/dstr_spec.rb +0 -17
  117. data/spec/unit/mutant/mutator/node/dsym_spec.rb +0 -18
  118. data/spec/unit/mutant/mutator/node/ensure_spec.rb +0 -16
  119. data/spec/unit/mutant/mutator/node/if_spec.rb +0 -77
  120. data/spec/unit/mutant/mutator/node/kwbegin_spec.rb +0 -16
  121. data/spec/unit/mutant/mutator/node/literal/array_spec.rb +0 -47
  122. data/spec/unit/mutant/mutator/node/literal/boolean_spec.rb +0 -25
  123. data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +0 -13
  124. data/spec/unit/mutant/mutator/node/literal/float_spec.rb +0 -53
  125. data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +0 -33
  126. data/spec/unit/mutant/mutator/node/literal/nil_spec.rb +0 -10
  127. data/spec/unit/mutant/mutator/node/literal/range_spec.rb +0 -56
  128. data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +0 -36
  129. data/spec/unit/mutant/mutator/node/literal/string_spec.rb +0 -15
  130. data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +0 -15
  131. data/spec/unit/mutant/mutator/node/loop_ctrl_spec.rb +0 -37
  132. data/spec/unit/mutant/mutator/node/masgn_spec.rb +0 -14
  133. data/spec/unit/mutant/mutator/node/match_current_line_spec.rb +0 -21
  134. data/spec/unit/mutant/mutator/node/named_value/access_spec.rb +0 -78
  135. data/spec/unit/mutant/mutator/node/named_value/constant_assignment_spec.rb +0 -16
  136. data/spec/unit/mutant/mutator/node/named_value/variable_assignment_spec.rb +0 -61
  137. data/spec/unit/mutant/mutator/node/nthref_spec.rb +0 -19
  138. data/spec/unit/mutant/mutator/node/op_assgn_spec.rb +0 -22
  139. data/spec/unit/mutant/mutator/node/or_asgn_spec.rb +0 -19
  140. data/spec/unit/mutant/mutator/node/redo_spec.rb +0 -10
  141. data/spec/unit/mutant/mutator/node/rescue_spec.rb +0 -63
  142. data/spec/unit/mutant/mutator/node/restarg_spec.rb +0 -18
  143. data/spec/unit/mutant/mutator/node/return_spec.rb +0 -31
  144. data/spec/unit/mutant/mutator/node/send_spec.rb +0 -382
  145. data/spec/unit/mutant/mutator/node/super_spec.rb +0 -46
  146. data/spec/unit/mutant/mutator/node/yield_spec.rb +0 -17
@@ -1,139 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Mutant
4
- class CLI
5
- # A classifier for input strings
6
- class Classifier
7
- include AbstractType, Adamantium::Flat, Concord.new(:cache, :match)
8
-
9
- include Equalizer.new(:identifier)
10
-
11
- SCOPE_NAME_PATTERN = /[A-Za-z][A-Za-z\d_]*/.freeze
12
- SCOPE_OPERATOR = '::'.freeze
13
- CBASE_PATTERN = /\A#{SCOPE_OPERATOR}/.freeze
14
-
15
- METHOD_NAME_PATTERN = Regexp.union(
16
- /[A-Za-z_][A-Za-z\d_]*[!?=]?/,
17
- *OPERATOR_METHODS.map(&:to_s)
18
- ).freeze
19
-
20
- SCOPE_PATTERN = /
21
- (?:#{SCOPE_OPERATOR})?#{SCOPE_NAME_PATTERN}
22
- (?:#{SCOPE_OPERATOR}#{SCOPE_NAME_PATTERN})*
23
- /x.freeze
24
-
25
- REGISTRY = {}
26
-
27
- # Register classifier
28
- #
29
- # @return [undefined]
30
- #
31
- # @api private
32
- #
33
- def self.register(regexp)
34
- REGISTRY[regexp] = self
35
- end
36
- private_class_method :register
37
-
38
- # Return constant
39
- #
40
- # @param [String] location
41
- #
42
- # @return [Class|Module]
43
- #
44
- # @api private
45
- #
46
- def self.constant_lookup(location)
47
- location.sub(CBASE_PATTERN, EMPTY_STRING).split(SCOPE_OPERATOR)
48
- .reduce(Object) do |parent, name|
49
- parent.const_get(name, nil)
50
- end
51
- end
52
-
53
- # Return matchers for input
54
- #
55
- # @param [Cache] cache
56
- # @param [String] pattern
57
- #
58
- # @return [Matcher]
59
- # if a classifier handles the input
60
- #
61
- # @raise [RuntimeError]
62
- # otherwise
63
- #
64
- # @api private
65
- #
66
- def self.run(cache, pattern)
67
- matches = find(pattern)
68
- case matches.length
69
- when 0
70
- raise Error, "No matcher handles: #{pattern.inspect}"
71
- when 1
72
- klass, match = matches.first
73
- klass.new(cache, match).matcher
74
- else
75
- raise Error, "More than one matcher found for: #{pattern.inspect}"
76
- end
77
- end
78
-
79
- # Find classifiers
80
- #
81
- # @param [String] input
82
- #
83
- # @return [Classifier]
84
- # if classifier can be found
85
- #
86
- # @return [nil]
87
- # otherwise
88
- #
89
- # @api private
90
- #
91
- def self.find(input)
92
- REGISTRY.each_with_object([]) do |(regexp, klass), matches|
93
- match = regexp.match(input)
94
- if match
95
- matches << [klass, match]
96
- end
97
- end
98
- end
99
- private_class_method :find
100
-
101
- # Enumerate subjects
102
- #
103
- # @return [self]
104
- # if block given
105
- #
106
- # @return [Enumerator<Subject>]
107
- # otherwise
108
- #
109
- # @api private
110
- #
111
- def each(&block)
112
- return to_enum unless block_given?
113
- matcher.each(&block)
114
- self
115
- end
116
-
117
- # Return identifier
118
- #
119
- # @return [String]
120
- #
121
- # @api private
122
- #
123
- def identifier
124
- match.to_s
125
- end
126
- memoize :identifier
127
-
128
- # Return matcher
129
- #
130
- # @return [Matcher]
131
- #
132
- # @api private
133
- #
134
- abstract_method :matcher
135
- private :matcher
136
-
137
- end # Classifier
138
- end # CLI
139
- end # Mutant
@@ -1,105 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Mutant
4
- class CLI
5
- class Classifier
6
-
7
- # Explicit method classifier
8
- class Method < self
9
-
10
- TABLE = {
11
- '.' => Matcher::Methods::Singleton,
12
- '#' => Matcher::Methods::Instance
13
- }.freeze
14
-
15
- REGEXP = /
16
- \A
17
- (?<scope_name>#{SCOPE_PATTERN})
18
- (?<scope_symbol>[.#])
19
- (?<method_name>#{METHOD_NAME_PATTERN})
20
- \z
21
- /x.freeze
22
-
23
- register(REGEXP)
24
-
25
- # Return method matcher
26
- #
27
- # @return [Matcher::Method]
28
- #
29
- # @api private
30
- #
31
- def matcher
32
- methods_matcher.matcher.build(cache, scope, method)
33
- end
34
- memoize :matcher
35
-
36
- private
37
-
38
- # Return method
39
- #
40
- # @return [Method, UnboundMethod]
41
- #
42
- # @api private
43
- #
44
- def method
45
- methods_matcher.methods.detect do |method|
46
- method.name == method_name
47
- end or raise NameError, "Cannot find method #{identifier}"
48
- end
49
- memoize :method, freezer: :noop
50
-
51
- # Return scope name
52
- #
53
- # @return [String]
54
- #
55
- # @api private
56
- #
57
- def scope_name
58
- match[__method__]
59
- end
60
-
61
- # Return scope
62
- #
63
- # @return [Class, Method]
64
- #
65
- # @api private
66
- #
67
- def scope
68
- Classifier.constant_lookup(scope_name)
69
- end
70
-
71
- # Return method name
72
- #
73
- # @return [String]
74
- #
75
- # @api private
76
- #
77
- def method_name
78
- match[__method__].to_sym
79
- end
80
-
81
- # Return scope symbol
82
- #
83
- # @return [Symbol]
84
- #
85
- # @api private
86
- #
87
- def scope_symbol
88
- match[__method__]
89
- end
90
-
91
- # Return matcher class
92
- #
93
- # @return [Class:Mutant::Matcher]
94
- #
95
- # @api private
96
- #
97
- def methods_matcher
98
- TABLE.fetch(scope_symbol).new(cache, scope)
99
- end
100
- memoize :methods_matcher
101
-
102
- end # Method
103
- end # Classifier
104
- end # CLI
105
- end # Mutant
@@ -1,49 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Mutant
4
- class CLI
5
- class Classifier
6
-
7
- # Namespace classifier
8
- class Namespace < self
9
-
10
- # Return matcher
11
- #
12
- # @return [Matcher]
13
- #
14
- # @api private
15
- #
16
- def matcher
17
- self.class::MATCHER.new(cache, namespace)
18
- end
19
-
20
- private
21
-
22
- # Return namespace
23
- #
24
- # @return [Class, Module]
25
- #
26
- # @api private
27
- #
28
- def namespace
29
- Classifier.constant_lookup(match[__method__].to_s)
30
- end
31
-
32
- # Recursive namespace classifier
33
- class Recursive < self
34
- REGEXP = /\A(?<namespace>#{SCOPE_PATTERN})\*\z/.freeze
35
- MATCHER = Matcher::Namespace
36
- register(REGEXP)
37
- end # Recursive
38
-
39
- # Recursive namespace classifier
40
- class Flat < self
41
- REGEXP = /\A(?<namespace>#{SCOPE_PATTERN})\z/.freeze
42
- MATCHER = Matcher::Scope
43
- register(REGEXP)
44
- end # Flat
45
-
46
- end # Namespace
47
- end # Classifier
48
- end # CLI
49
- end # Mutant
@@ -1,77 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- describe Mutant::CLI::Classifier::Method, '#each' do
6
-
7
- let(:object) { described_class.run(cache, input) }
8
- let(:cache) { Mutant::Cache.new }
9
- let(:instance_method) { '::TestApp::Literal#string' }
10
- let(:singleton_method) { '::TestApp::Literal.string' }
11
- let(:unknown_method) { '::TestApp::Literal#unknown' }
12
-
13
- context 'with a block' do
14
- subject { object.each {} }
15
-
16
- context 'with an instance method name' do
17
- let(:input) { instance_method }
18
-
19
- it_behaves_like 'a command method'
20
-
21
- it 'yield an instance subject' do
22
- expect { |block| object.each(&block) }
23
- .to yield_with_args(Mutant::Subject::Method::Instance)
24
- end
25
- end
26
-
27
- context 'with an singleton method name' do
28
- let(:input) { singleton_method }
29
-
30
- it_behaves_like 'a command method'
31
-
32
- it 'yield an instance subject' do
33
- expect { |block| object.each(&block) }
34
- .to yield_with_args(Mutant::Subject::Method::Singleton)
35
- end
36
- end
37
-
38
- context 'with an unknown method' do
39
- let(:input) { unknown_method }
40
-
41
- it 'raises an exception' do
42
- expect { subject }
43
- .to raise_error(NameError, "Cannot find method #{input}")
44
- end
45
- end
46
- end
47
-
48
- context 'without a block' do
49
- subject { object.each }
50
-
51
- context 'with an instance method name' do
52
- let(:input) { instance_method }
53
-
54
- it 'returns an enumerator' do
55
- should be_instance_of(to_enum.class)
56
- end
57
-
58
- it 'yield an instance subject' do
59
- expect { |block| subject.each(&block) }
60
- .to yield_with_args(Mutant::Subject::Method::Instance)
61
- end
62
- end
63
-
64
- context 'with an singleton method name' do
65
- let(:input) { singleton_method }
66
-
67
- it 'returns an enumerator' do
68
- should be_instance_of(to_enum.class)
69
- end
70
-
71
- it 'yield an instance subject' do
72
- expect { |block| subject.each(&block) }
73
- .to yield_with_args(Mutant::Subject::Method::Singleton)
74
- end
75
- end
76
- end
77
- end
@@ -1,58 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- describe Mutant::CLI::Classifier::Namespace::Flat, '#each' do
6
- let(:object) { described_class.run(cache, input) }
7
- let(:cache) { Mutant::Cache.new }
8
- let(:known_namespace) { '::TestApp::Literal' }
9
- let(:unknown_namespace) { '::TestApp::Object' }
10
-
11
- context 'with a block' do
12
- subject { object.each {} }
13
-
14
- context 'with a known namespace' do
15
- let(:input) { known_namespace }
16
-
17
- it_behaves_like 'a command method'
18
-
19
- it 'yield method subjects' do
20
- expect { |block| object.each(&block) }
21
- .to yield_control.exactly(7).times
22
- end
23
- end
24
-
25
- context 'with an unknown namespace' do
26
- let(:input) { unknown_namespace }
27
-
28
- it 'raises an exception' do
29
- expect { subject }.to raise_error(NameError)
30
- end
31
- end
32
- end
33
-
34
- context 'without a block' do
35
- subject { object.each }
36
-
37
- context 'with a known namespace' do
38
- let(:input) { known_namespace }
39
-
40
- it 'returns an enumerator' do
41
- should be_instance_of(to_enum.class)
42
- end
43
-
44
- it 'yield an instance subject' do
45
- expect { |block| object.each(&block) }
46
- .to yield_control.exactly(7).times
47
- end
48
- end
49
-
50
- context 'with an unknown namespace' do
51
- let(:input) { unknown_namespace }
52
-
53
- it 'raises an exception when #each is called' do
54
- expect { subject.each {} }.to raise_error(NameError)
55
- end
56
- end
57
- end
58
- end
@@ -1,58 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- describe Mutant::CLI::Classifier::Namespace::Recursive, '#each' do
6
- let(:object) { described_class.run(cache, "#{input}*") }
7
- let(:cache) { Mutant::Cache.new }
8
- let(:known_namespace) { '::TestApp::Literal' }
9
- let(:unknown_namespace) { '::TestApp::Object' }
10
-
11
- context 'with a block' do
12
- subject { object.each {} }
13
-
14
- context 'with a known namespace' do
15
- let(:input) { known_namespace }
16
-
17
- it_behaves_like 'a command method'
18
-
19
- it 'yield method subjects' do
20
- expect { |block| object.each(&block) }
21
- .to yield_control.exactly(7).times
22
- end
23
- end
24
-
25
- context 'with an unknown namespace' do
26
- let(:input) { unknown_namespace }
27
-
28
- it 'raises an exception' do
29
- expect { subject }.to raise_error(NameError)
30
- end
31
- end
32
- end
33
-
34
- context 'without a block' do
35
- subject { object.each }
36
-
37
- context 'with a known namespace' do
38
- let(:input) { known_namespace }
39
-
40
- it 'returns an enumerator' do
41
- should be_instance_of(to_enum.class)
42
- end
43
-
44
- it 'yield an instance subject' do
45
- expect { |block| object.each(&block) }
46
- .to yield_control.exactly(7).times
47
- end
48
- end
49
-
50
- context 'with an unknown namespace' do
51
- let(:input) { unknown_namespace }
52
-
53
- it 'raises an exception when #each is called' do
54
- expect { subject.each {} }.to raise_error(NameError)
55
- end
56
- end
57
- end
58
- end