mutant 0.5.17 → 0.5.18

Sign up to get free protection for your applications and to get access to all the features.
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