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,12 @@
1
+ # encoding: utf-8
2
+
3
+ module Mutant
4
+ class Reporter
5
+ class CLI
6
+ # Abstract base class for process printers
7
+ class Progress < Printer
8
+ include AbstractType, Registry.new
9
+ end # Progress
10
+ end # CLI
11
+ end # Reporter
12
+ end # Mutant
@@ -0,0 +1,32 @@
1
+ module Mutant
2
+ class Reporter
3
+ class CLI
4
+ class Progress
5
+ # Progress printer for configuration
6
+ class Config < self
7
+
8
+ handle(Mutant::Config)
9
+
10
+ delegate :matcher, :strategy, :expected_coverage
11
+
12
+ # Report configuration
13
+ #
14
+ # @param [Mutant::Config] config
15
+ #
16
+ # @return [self]
17
+ #
18
+ # @api private
19
+ #
20
+ def run
21
+ info 'Mutant configuration:'
22
+ info 'Matcher: %s', matcher.inspect
23
+ info 'Strategy: %s', strategy.inspect
24
+ info 'Expect Coverage: %02f%%', expected_coverage.inspect
25
+ self
26
+ end
27
+
28
+ end # Progress
29
+ end # Printer
30
+ end # CLI
31
+ end # Reporter
32
+ end # Mutant
@@ -1,14 +1,12 @@
1
- # encoding: utf-8
2
-
3
1
  module Mutant
4
2
  class Reporter
5
3
  class CLI
6
- class Printer
4
+ class Progress
7
5
 
8
- # Printer for killer results
9
- class Killer < self
6
+ # Mutation progress reporter
7
+ class Mutation < self
10
8
 
11
- handle(Mutant::Killer)
9
+ handle(Runner::Mutation)
12
10
 
13
11
  SUCCESS = '.'.freeze
14
12
  FAILURE = 'F'.freeze
@@ -20,11 +18,7 @@ module Mutant
20
18
  # @api private
21
19
  #
22
20
  def run
23
- if success?
24
- char(SUCCESS, Color::GREEN)
25
- else
26
- char(FAILURE, Color::RED)
27
- end
21
+ char(success? ? SUCCESS : FAILURE)
28
22
  end
29
23
 
30
24
  private
@@ -32,19 +26,18 @@ module Mutant
32
26
  # Write colorized char
33
27
  #
34
28
  # @param [String] char
35
- # @param [Color]
36
29
  #
37
30
  # @return [undefined]
38
31
  #
39
32
  # @api private
40
33
  #
41
- def char(char, color)
42
- output.write(colorize(color, char))
34
+ def char(char)
35
+ output.write(colorize(status_color, char))
43
36
  output.flush
44
37
  end
45
38
 
46
- end # Killer
47
- end # Printer
39
+ end # Mutation
40
+ end # Progress
48
41
  end # CLI
49
42
  end # Reporter
50
43
  end # Mutant
@@ -0,0 +1,22 @@
1
+ module Mutant
2
+ class Reporter
3
+ class CLI
4
+ class Progress
5
+ # Noop CLI progress reporter
6
+ class Noop < self
7
+
8
+ handle(Mutant::Mutation)
9
+
10
+ # Noop progress report
11
+ #
12
+ # @return [self]
13
+ #
14
+ def run
15
+ self
16
+ end
17
+
18
+ end # Noop
19
+ end # Progress
20
+ end # CLI
21
+ end # Reporter
22
+ end # Mutant
@@ -0,0 +1,118 @@
1
+ module Mutant
2
+ class Reporter
3
+ class CLI
4
+ class Progress
5
+ # Subject results printer
6
+ class Subject < self
7
+
8
+ handle(Mutant::Subject)
9
+
10
+ # Run subject results printer
11
+ #
12
+ # @return [undefined]
13
+ #
14
+ # @api private
15
+ #
16
+ def run
17
+ puts(object.identification)
18
+ end
19
+
20
+ end # Subject
21
+
22
+ # Reporter for subject runners
23
+ class SubjectRunner < self
24
+
25
+ FORMAT = '(%02d/%02d) %3d%% - %0.02fs'.freeze
26
+
27
+ handle(Mutant::Runner::Subject)
28
+
29
+ # Run printer
30
+ #
31
+ # @return [undefined]
32
+ #
33
+ # @api private
34
+ #
35
+ def run
36
+ print_progress_bar_finish
37
+ print_stats
38
+ self
39
+ end
40
+
41
+ private
42
+
43
+ # Return mutation time on subject
44
+ #
45
+ # @return [Float]
46
+ #
47
+ # @api private
48
+ #
49
+ def time
50
+ mutations.map(&:runtime).inject(0, :+)
51
+ end
52
+
53
+ # Print stats
54
+ #
55
+ # @return [undefined]
56
+ #
57
+ # @api private
58
+ #
59
+ def print_stats
60
+ status(FORMAT, amount_kills, amount_mutations, coverage, time)
61
+ end
62
+
63
+ # Print progress bar finish
64
+ #
65
+ # @return [undefined]
66
+ #
67
+ # @api private
68
+ #
69
+ def print_progress_bar_finish
70
+ puts unless amount_mutations.zero?
71
+ end
72
+
73
+ # Return kills
74
+ #
75
+ # @return [Fixnum]
76
+ #
77
+ # @api private
78
+ #
79
+ def amount_kills
80
+ amount_mutations - object.failed_mutations.length
81
+ end
82
+
83
+ # Return amount of mutations
84
+ #
85
+ # @return [Array<Mutation>]
86
+ #
87
+ # @api private
88
+ #
89
+ def amount_mutations
90
+ mutations.length
91
+ end
92
+
93
+ # Return mutations
94
+ #
95
+ # @return [Array<Mutation>]
96
+ #
97
+ # @api private
98
+ #
99
+ def mutations
100
+ object.mutations
101
+ end
102
+
103
+ # Return subject coverage
104
+ #
105
+ # @return [Float]
106
+ #
107
+ # @api private
108
+ #
109
+ def coverage
110
+ return 0 if amount_mutations.zero?
111
+ Rational(amount_kills, amount_mutations) * 100
112
+ end
113
+
114
+ end # Runner
115
+ end # Progress
116
+ end # CLI
117
+ end # Reporter
118
+ end # Mutant
@@ -0,0 +1,77 @@
1
+ module Mutant
2
+ class Reporter
3
+ class CLI
4
+ # Mixin to generate registry semantics
5
+ class Registry < Module
6
+ include Concord.new(:registry)
7
+
8
+ # Return new registry
9
+ #
10
+ # @return [Registry]
11
+ #
12
+ # @api private
13
+ #
14
+ def self.new
15
+ super({})
16
+ end
17
+
18
+ # Register handler for class
19
+ #
20
+ # @param [Class] klass
21
+ #
22
+ # @return [self]
23
+ #
24
+ # @api private
25
+ #
26
+ def handle(subject, handler)
27
+ raise "Duplicate registration of #{subject}" if registry.key?(subject)
28
+ registry[subject] = handler
29
+ self
30
+ end
31
+
32
+ # Lookup handler
33
+ #
34
+ # @param [Class] subject
35
+ #
36
+ # @return [Object]
37
+ # if found
38
+ #
39
+ # @raise [RuntimeError]
40
+ # otherwise
41
+ #
42
+ # @api private
43
+ #
44
+ def lookup(subject)
45
+ current = subject
46
+ until current == Object
47
+ if registry.key?(current)
48
+ return registry.fetch(current)
49
+ end
50
+ current = current.superclass
51
+ end
52
+ raise "No printer for: #{subject}"
53
+ end
54
+
55
+ # Hook called when module is included
56
+ #
57
+ # @param [Class,Module] host
58
+ #
59
+ # @return [undefined]
60
+ #
61
+ def included(host)
62
+ object = self
63
+ host.class_eval do
64
+ define_singleton_method(:lookup, &object.method(:lookup))
65
+ private_class_method :lookup
66
+
67
+ define_singleton_method(:handle) do |subject|
68
+ object.handle(subject, self)
69
+ end
70
+ private_class_method :handle
71
+ end
72
+ end
73
+
74
+ end # Registry
75
+ end # CLI
76
+ end # Reporter
77
+ end # Mutant
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module Mutant
4
+ class Reporter
5
+ class CLI
6
+ # Abstract base class for process printers
7
+ class Report < Printer
8
+ include AbstractType, Registry.new
9
+ end # Report
10
+ end # CLI
11
+ end # Reporter
12
+ end # Mutant
@@ -0,0 +1,118 @@
1
+ # encoding: utf-8
2
+
3
+ module Mutant
4
+ class Reporter
5
+ class CLI
6
+ class Report
7
+
8
+ # Printer for configuration
9
+ class Config < self
10
+
11
+ handle(Mutant::Runner::Config)
12
+
13
+ delegate(
14
+ :amount_kills, :amount_mutations, :amount_kils,
15
+ :coverage, :subjects, :failed_subjects, :runtime, :mutations
16
+ )
17
+
18
+ # Run printer
19
+ #
20
+ # @return [self]
21
+ #
22
+ # @api private
23
+ #
24
+ def run
25
+ failed_subjects.each(&method(:visit))
26
+ info 'Subjects: %s', amount_subjects
27
+ info 'Mutations: %s', amount_mutations
28
+ info 'Kills: %s', amount_kills
29
+ info 'Alive: %s', amount_alive
30
+ info 'Runtime: %0.2fs', runtime
31
+ info 'Killtime: %0.2fs', killtime
32
+ info 'Overhead: %0.2f%%', overhead
33
+ status 'Coverage: %0.2f%%', coverage
34
+ status 'Expected: %0.2f%%', object.config.expected_coverage
35
+ print_generic_stats
36
+ self
37
+ end
38
+
39
+ private
40
+
41
+ # Print generic stats
42
+ #
43
+ # @return [undefined]
44
+ #
45
+ # @api private
46
+ #
47
+ def print_generic_stats
48
+ stats = generic_stats.to_a.sort_by(&:last)
49
+ return if stats.empty?
50
+ info('Nodes handled by generic mutator (type:occurrences):')
51
+ stats.reverse_each do |type, amount|
52
+ info('%-10s: %d', type, amount)
53
+ end
54
+ end
55
+
56
+ # Return stats for nodes handled by generic mutator
57
+ #
58
+ # @return [Hash<Symbo, Fixnum>]
59
+ #
60
+ # @api private
61
+ #
62
+ def generic_stats
63
+ subjects.each_with_object(Hash.new(0)) do |runner, stats|
64
+ Walker.run(runner.subject.node) do |node|
65
+ if Mutator::Registry.lookup(node) == Mutator::Node::Generic
66
+ stats[node.type] += 1
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ # Return amount of subjects
73
+ #
74
+ # @return [Fixnum]
75
+ #
76
+ # @api private
77
+ #
78
+ def amount_subjects
79
+ subjects.length
80
+ end
81
+
82
+ # Return amount of time in killers
83
+ #
84
+ # @return [Float]
85
+ #
86
+ # @api private
87
+ #
88
+ def killtime
89
+ mutations.map(&:runtime).inject(0, :+)
90
+ end
91
+ memoize :killtime
92
+
93
+ # Return mutant overhead
94
+ #
95
+ # @return [Float]
96
+ #
97
+ # @api private
98
+ #
99
+ def overhead
100
+ return 0 if runtime.zero?
101
+ Rational(runtime - killtime, runtime) * 100
102
+ end
103
+
104
+ # Return amount of alive mutations
105
+ #
106
+ # @return [Fixnum]
107
+ #
108
+ # @api private
109
+ #
110
+ def amount_alive
111
+ object.amount_mutations - amount_kills
112
+ end
113
+
114
+ end # Config
115
+ end # Report
116
+ end # CLI
117
+ end # Reporter
118
+ end # Mutant