mutant 0.5.12 → 0.5.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +10 -0
  3. data/circle.yml +1 -1
  4. data/config/flay.yml +1 -1
  5. data/config/flog.yml +1 -1
  6. data/config/mutant.yml +1 -2
  7. data/config/reek.yml +12 -3
  8. data/config/rubocop.yml +4 -0
  9. data/lib/mutant.rb +45 -16
  10. data/lib/mutant/constants.rb +11 -11
  11. data/lib/mutant/delegator.rb +50 -0
  12. data/lib/mutant/{differ.rb → diff.rb} +5 -5
  13. data/lib/mutant/killer.rb +29 -106
  14. data/lib/mutant/matcher/method.rb +2 -11
  15. data/lib/mutant/mutation.rb +17 -3
  16. data/lib/mutant/mutation/evil.rb +2 -10
  17. data/lib/mutant/mutation/neutral.rb +4 -30
  18. data/lib/mutant/mutator/node/literal/fixnum.rb +0 -1
  19. data/lib/mutant/mutator/node/literal/float.rb +0 -1
  20. data/lib/mutant/mutator/node/literal/string.rb +0 -1
  21. data/lib/mutant/mutator/node/literal/symbol.rb +6 -2
  22. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +8 -3
  23. data/lib/mutant/mutator/util/symbol.rb +3 -1
  24. data/lib/mutant/node_helpers.rb +1 -3
  25. data/lib/mutant/reporter.rb +10 -0
  26. data/lib/mutant/reporter/cli.rb +15 -2
  27. data/lib/mutant/reporter/cli/printer.rb +12 -105
  28. data/lib/mutant/reporter/cli/progress.rb +12 -0
  29. data/lib/mutant/reporter/cli/progress/config.rb +32 -0
  30. data/lib/mutant/reporter/cli/{printer/killer.rb → progress/mutation.rb} +9 -16
  31. data/lib/mutant/reporter/cli/progress/noop.rb +22 -0
  32. data/lib/mutant/reporter/cli/progress/subject.rb +118 -0
  33. data/lib/mutant/reporter/cli/registry.rb +77 -0
  34. data/lib/mutant/reporter/cli/report.rb +12 -0
  35. data/lib/mutant/reporter/cli/report/config.rb +118 -0
  36. data/lib/mutant/reporter/cli/report/mutation.rb +112 -0
  37. data/lib/mutant/reporter/cli/report/subject.rb +33 -0
  38. data/lib/mutant/reporter/null.rb +13 -0
  39. data/lib/mutant/reporter/trace.rb +41 -0
  40. data/lib/mutant/runner.rb +22 -20
  41. data/lib/mutant/runner/config.rb +6 -5
  42. data/lib/mutant/runner/killer.rb +59 -0
  43. data/lib/mutant/runner/mutation.rb +17 -10
  44. data/lib/mutant/runner/subject.rb +14 -4
  45. data/lib/mutant/strategy.rb +30 -16
  46. data/lib/mutant/subject/method/instance.rb +1 -1
  47. data/lib/mutant/test.rb +86 -0
  48. data/lib/mutant/version.rb +1 -1
  49. data/spec/integration/mutant/null_spec.rb +18 -0
  50. data/spec/integration/mutant/rspec_spec.rb +1 -1
  51. data/spec/spec_helper.rb +0 -2
  52. data/spec/unit/mutant/diff_spec.rb +162 -0
  53. data/spec/unit/mutant/mutation_spec.rb +8 -5
  54. data/spec/unit/mutant/mutator/node/and_asgn_spec.rb +1 -9
  55. data/spec/unit/mutant/mutator/node/block_spec.rb +6 -18
  56. data/spec/unit/mutant/mutator/node/case_spec.rb +10 -16
  57. data/spec/unit/mutant/mutator/node/define_spec.rb +5 -17
  58. data/spec/unit/mutant/mutator/node/dstr_spec.rb +0 -6
  59. data/spec/unit/mutant/mutator/node/dsym_spec.rb +0 -5
  60. data/spec/unit/mutant/mutator/node/if_spec.rb +13 -17
  61. data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +1 -7
  62. data/spec/unit/mutant/mutator/node/literal/float_spec.rb +0 -9
  63. data/spec/unit/mutant/mutator/node/literal/range_spec.rb +0 -10
  64. data/spec/unit/mutant/mutator/node/literal/string_spec.rb +1 -5
  65. data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +1 -5
  66. data/spec/unit/mutant/mutator/node/named_value/access_spec.rb +4 -7
  67. data/spec/unit/mutant/mutator/node/named_value/constant_assignment_spec.rb +1 -5
  68. data/spec/unit/mutant/mutator/node/named_value/variable_assignment_spec.rb +4 -8
  69. data/spec/unit/mutant/mutator/node/op_assgn_spec.rb +0 -7
  70. data/spec/unit/mutant/mutator/node/or_asgn_spec.rb +1 -9
  71. data/spec/unit/mutant/mutator/node/rescue_spec.rb +0 -4
  72. data/spec/unit/mutant/reporter/null_spec.rb +11 -0
  73. data/spec/unit/mutant/runner/config_spec.rb +6 -7
  74. data/spec/unit/mutant/runner/mutation_spec.rb +101 -0
  75. data/spec/unit/mutant/runner/subject_spec.rb +10 -7
  76. data/spec/unit/mutant_spec.rb +53 -0
  77. metadata +65 -62
  78. data/lib/mutant/killer/forked.rb +0 -46
  79. data/lib/mutant/killer/forking.rb +0 -46
  80. data/lib/mutant/killer/static.rb +0 -34
  81. data/lib/mutant/mutator/node/literal/dynamic.rb +0 -27
  82. data/lib/mutant/random.rb +0 -38
  83. data/lib/mutant/reporter/cli/printer/config.rb +0 -154
  84. data/lib/mutant/reporter/cli/printer/mutation.rb +0 -103
  85. data/lib/mutant/reporter/cli/printer/subject.rb +0 -150
  86. data/spec/unit/mutant/differ/diff_spec.rb +0 -123
  87. data/spec/unit/mutant/differ_spec.rb +0 -42
  88. data/spec/unit/mutant/killer/success_predicate_spec.rb +0 -30
  89. data/spec/unit/mutant/rspec/killer_spec.rb +0 -57
  90. data/spec/unit/mutant/runner/mutation/killer_spec.rb +0 -44
@@ -0,0 +1,112 @@
1
+ # encoding: utf-8
2
+
3
+ module Mutant
4
+ class Reporter
5
+ class CLI
6
+ class Report
7
+
8
+ # Reporter for mutations
9
+ class Mutation < self
10
+
11
+ # Run report printer
12
+ #
13
+ # @return [self]
14
+ #
15
+ # @api private
16
+ #
17
+ def run
18
+ puts(object.identification)
19
+ puts(details)
20
+ self
21
+ end
22
+
23
+ # Reporter for noop mutations
24
+ class Noop < self
25
+ handle(Mutant::Mutation::Neutral::Noop)
26
+
27
+ MESSAGE = [
28
+ 'Parsed subject AST:',
29
+ '%s',
30
+ 'Unparsed source:',
31
+ '%s'
32
+ ].join("\n").freeze
33
+
34
+ delegate :killers
35
+
36
+ private
37
+
38
+ # Return details
39
+ #
40
+ # @return [self]
41
+ #
42
+ # @api private
43
+ #
44
+ def details
45
+ info(MESSAGE, object.subject.node.inspect, object.original_source)
46
+ end
47
+
48
+ end # Noop
49
+
50
+ # Reporter for mutations producing a diff
51
+ class Diff < self
52
+ handle(Mutant::Mutation::Evil)
53
+ handle(Mutant::Mutation::Neutral)
54
+
55
+ private
56
+
57
+ # Run report printer
58
+ #
59
+ # @return [self]
60
+ #
61
+ # @api private
62
+ #
63
+ def details
64
+ original, current = object.original_source, object.source
65
+ diff = Mutant::Diff.build(original, current)
66
+ color? ? diff.colorized_diff : diff.diff
67
+ end
68
+
69
+ end # Diff
70
+ end # Mutation
71
+
72
+ # Subject report printer
73
+ class MutationRunner < self
74
+ handle(Mutant::Runner::Mutation)
75
+
76
+ # Run report printer
77
+ #
78
+ # @return [self]
79
+ #
80
+ # @api private
81
+ #
82
+ def run
83
+ visit(object.mutation)
84
+ if object.mutation.kind_of?(Mutant::Mutation::Neutral::Noop)
85
+ report_noop
86
+ end
87
+ self
88
+ end
89
+
90
+ delegate :killers
91
+
92
+ private
93
+
94
+ # Report noop output
95
+ #
96
+ # @return [undefined]
97
+ #
98
+ # @api private
99
+ #
100
+ def report_noop
101
+ info('NOOP MUTATION TESTS FAILED!')
102
+ killers.reject(&:success?).map(&:report).map(&:test_report).each do |report|
103
+ puts(report.test.identification)
104
+ puts(report.output)
105
+ end
106
+ end
107
+
108
+ end # Mutation
109
+ end # Report
110
+ end # CLI
111
+ end # Reporter
112
+ end # Mutant
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ module Mutant
4
+ class Reporter
5
+ class CLI
6
+ class Report
7
+
8
+ # Subject report printer
9
+ class Subject < self
10
+ handle(Mutant::Runner::Subject)
11
+
12
+ delegate :subject, :failed_mutations
13
+
14
+ # Run report printer
15
+ #
16
+ # @return [self]
17
+ #
18
+ # @api private
19
+ #
20
+ def run
21
+ status(subject.identification)
22
+ object.tests.each do |test|
23
+ puts("- #{test.identification}")
24
+ end
25
+ object.failed_mutations.each(&method(:visit))
26
+ self
27
+ end
28
+
29
+ end # Subject
30
+ end # Report
31
+ end # CLI
32
+ end # Reporter
33
+ end # Mutant
@@ -5,6 +5,7 @@ module Mutant
5
5
 
6
6
  # Null reporter
7
7
  class Null < self
8
+ include Equalizer.new
8
9
 
9
10
  # Report object
10
11
  #
@@ -18,6 +19,18 @@ module Mutant
18
19
  self
19
20
  end
20
21
 
22
+ # Report progress on object
23
+ #
24
+ # @param [Object] _object
25
+ #
26
+ # @return [self]
27
+ #
28
+ # @api private
29
+ #
30
+ def progress(_object)
31
+ self
32
+ end
33
+
21
34
  end # Null
22
35
  end # Reporter
23
36
  end # Mutant
@@ -0,0 +1,41 @@
1
+ module Mutant
2
+ class Reporter
3
+ # Reporter to trace report calls, used as a spec adapter
4
+ class Trace
5
+ include Concord::Public.new(:progress_calls, :report_calls)
6
+
7
+ # Return new trace reporter
8
+ #
9
+ # @return [Tracer]
10
+ #
11
+ # @api private
12
+ #
13
+ def self.new
14
+ super([], [])
15
+ end
16
+
17
+ # Report object
18
+ #
19
+ # @param [Object] object
20
+ #
21
+ # @return [self]
22
+ #
23
+ def report(object)
24
+ report_calls << object
25
+ self
26
+ end
27
+
28
+ # Report new progress on object
29
+ #
30
+ # @param [Object] object
31
+ #
32
+ # @return [self]
33
+ #
34
+ def progress(object)
35
+ progress_calls << object
36
+ self
37
+ end
38
+
39
+ end # Tracker
40
+ end # reporter
41
+ end # Mutant
@@ -48,9 +48,9 @@ module Mutant
48
48
  #
49
49
  # @api private
50
50
  #
51
- def self.run(config, object)
51
+ def self.run(config, object, *arguments)
52
52
  handler = lookup(object.class)
53
- handler.new(config, object)
53
+ handler.new(config, object, *arguments)
54
54
  end
55
55
 
56
56
  # Return config
@@ -101,16 +101,6 @@ module Mutant
101
101
  (@end || Time.now) - @start
102
102
  end
103
103
 
104
- # Return reporter
105
- #
106
- # @return [Reporter]
107
- #
108
- # @api private
109
- #
110
- def reporter
111
- config.reporter
112
- end
113
-
114
104
  # Test if runner is successful
115
105
  #
116
106
  # @return [true]
@@ -133,7 +123,7 @@ module Mutant
133
123
  #
134
124
  abstract_method :run
135
125
 
136
- # Return reporter
126
+ # Run reporter on object
137
127
  #
138
128
  # @param [Object] object
139
129
  #
@@ -141,20 +131,32 @@ module Mutant
141
131
  #
142
132
  # @api private
143
133
  #
144
- def report(object)
145
- reporter.report(object)
134
+ def progress(object)
135
+ reporter.progress(object)
146
136
  end
147
137
 
148
- # Perform dispatch
138
+ # Return reporter
139
+ #
140
+ # @return [Reporter]
141
+ #
142
+ # @api private
143
+ #
144
+ def reporter
145
+ config.reporter
146
+ end
147
+
148
+ # Perform dispatch on multiple inputs
149
+ #
150
+ # @param [Enumerable<Object>] input
149
151
  #
150
152
  # @return [Enumerable<Runner>]
151
153
  #
152
154
  # @api private
153
155
  #
154
- def dispatch(input)
156
+ def visit_collection(input, *arguments)
155
157
  collection = []
156
158
  input.each do |object|
157
- runner = visit(object)
159
+ runner = visit(object, *arguments)
158
160
  collection << runner
159
161
  @stop = runner.stop?
160
162
  break if @stop
@@ -170,8 +172,8 @@ module Mutant
170
172
  #
171
173
  # @api private
172
174
  #
173
- def visit(object)
174
- Runner.run(config, object)
175
+ def visit(object, *arguments)
176
+ Runner.run(config, object, *arguments)
175
177
  end
176
178
 
177
179
  end # Runner
@@ -5,6 +5,9 @@ module Mutant
5
5
  # Runner for object config
6
6
  class Config < self
7
7
 
8
+ # The expected coverage precision
9
+ COVERAGE_PRECISION = 1
10
+
8
11
  register Mutant::Config
9
12
 
10
13
  # Run runner for object
@@ -40,8 +43,6 @@ module Mutant
40
43
  end
41
44
  memoize :failed_subjects
42
45
 
43
- COVERAGE_PRECISION = 1
44
-
45
46
  # Test if run was successful
46
47
  #
47
48
  # @return [true]
@@ -122,7 +123,7 @@ module Mutant
122
123
  def run_subjects
123
124
  strategy = self.strategy
124
125
  strategy.setup
125
- @subjects = dispatch(config.subjects)
126
+ @subjects = visit_collection(config.subjects)
126
127
  strategy.teardown
127
128
  end
128
129
 
@@ -133,10 +134,10 @@ module Mutant
133
134
  # @api private
134
135
  #
135
136
  def run
136
- report(config)
137
+ progress(config)
137
138
  run_subjects
138
139
  @end = Time.now
139
- report(self)
140
+ reporter.report(self)
140
141
  end
141
142
 
142
143
  end # Config
@@ -0,0 +1,59 @@
1
+ module Mutant
2
+ class Runner
3
+ # Killer runner
4
+ class Killer < self
5
+ include Equalizer.new(:config, :killer)
6
+
7
+ register Mutant::Killer
8
+
9
+ # Return killer
10
+ #
11
+ # @return [Killer]
12
+ #
13
+ # @api private
14
+ #
15
+ attr_reader :killer
16
+ protected :killer
17
+
18
+ # Return kill report
19
+ #
20
+ # @return [Killer::Report]
21
+ #
22
+ # @api private
23
+ #
24
+ attr_reader :report
25
+
26
+ # Test if killer ran successfully
27
+ #
28
+ # @return [Boolean]
29
+ #
30
+ # @api private
31
+ def success?
32
+ @report.success?
33
+ end
34
+
35
+ # Initialize object
36
+ #
37
+ # @param [Config] config
38
+ # @param [Mutation] mutation
39
+ #
40
+ # @return [undefined]
41
+ #
42
+ # @api private
43
+ #
44
+ def initialize(config, killer)
45
+ @killer = killer
46
+ super(config)
47
+ end
48
+
49
+ # Run killer
50
+ #
51
+ # @api private
52
+ #
53
+ def run
54
+ @report = killer.run
55
+ end
56
+
57
+ end # Killer
58
+ end # Runner
59
+ end # Mutant
@@ -4,7 +4,7 @@ module Mutant
4
4
  class Runner
5
5
  # Mutation runner
6
6
  class Mutation < self
7
- include Equalizer.new(:config, :mutation)
7
+ include Equalizer.new(:config, :mutation, :tests)
8
8
 
9
9
  register Mutant::Mutation
10
10
 
@@ -16,26 +16,28 @@ module Mutant
16
16
  #
17
17
  attr_reader :mutation
18
18
 
19
- # Return killer instance
19
+ # Return killers
20
20
  #
21
- # @return [Killer]
21
+ # @return [Enumerable<Runner::Killer>]
22
22
  #
23
23
  # @api private
24
24
  #
25
- attr_reader :killer
25
+ attr_reader :killers
26
26
 
27
27
  # Initialize object
28
28
  #
29
29
  # @param [Config] config
30
30
  # @param [Mutation] mutation
31
+ # @param [Enumerable<Test>] tests
31
32
  #
32
33
  # @return [undefined]
33
34
  #
34
35
  # @api private
35
36
  #
36
- def initialize(config, mutation)
37
- @mutation = mutation
37
+ def initialize(config, mutation, tests)
38
+ @mutation, @tests = mutation, tests
38
39
  super(config)
40
+ @stop = config.fail_fast && !success?
39
41
  end
40
42
 
41
43
  # Test if mutation was handeled successfully
@@ -49,7 +51,7 @@ module Mutant
49
51
  # @api private
50
52
  #
51
53
  def success?
52
- mutation.success?(killer)
54
+ killers.any?(&:success?)
53
55
  end
54
56
 
55
57
  private
@@ -61,9 +63,14 @@ module Mutant
61
63
  # @api private
62
64
  #
63
65
  def run
64
- @killer = config.strategy.kill(mutation)
65
- report(killer)
66
- @stop = config.fail_fast && !killer.success?
66
+ progress(mutation)
67
+ @killers = @tests.map do |test|
68
+ Mutant::Killer.new(
69
+ mutation: mutation,
70
+ test: test
71
+ )
72
+ end.map(&method(:visit))
73
+ progress(self)
67
74
  end
68
75
 
69
76
  end # Mutation