mutant 0.5.12 → 0.5.13

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 (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