mutant 0.5.26 → 0.6.0

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 (127) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.travis.yml +1 -0
  4. data/Changelog.md +16 -3
  5. data/Gemfile +0 -2
  6. data/Gemfile.devtools +2 -2
  7. data/README.md +9 -15
  8. data/bin/mutant +0 -1
  9. data/config/flay.yml +1 -1
  10. data/config/flog.yml +1 -1
  11. data/config/mutant.yml +1 -1
  12. data/config/reek.yml +14 -11
  13. data/config/rubocop.yml +1 -1
  14. data/lib/mutant.rb +22 -21
  15. data/lib/mutant/ast.rb +47 -0
  16. data/lib/mutant/cli.rb +7 -4
  17. data/lib/mutant/config.rb +1 -0
  18. data/lib/mutant/context.rb +1 -1
  19. data/lib/mutant/diff.rb +38 -7
  20. data/lib/mutant/env.rb +22 -3
  21. data/lib/mutant/expression.rb +15 -4
  22. data/lib/mutant/integration.rb +1 -1
  23. data/lib/mutant/isolation.rb +2 -4
  24. data/lib/mutant/matcher.rb +1 -1
  25. data/lib/mutant/matcher/method.rb +1 -1
  26. data/lib/mutant/matcher/method/singleton.rb +1 -1
  27. data/lib/mutant/matcher/methods.rb +0 -2
  28. data/lib/mutant/meta/example.rb +0 -2
  29. data/lib/mutant/meta/example/dsl.rb +1 -1
  30. data/lib/mutant/mutator.rb +1 -1
  31. data/lib/mutant/mutator/node.rb +3 -3
  32. data/lib/mutant/mutator/node/begin.rb +1 -1
  33. data/lib/mutant/mutator/node/block.rb +16 -3
  34. data/lib/mutant/mutator/node/if.rb +1 -1
  35. data/lib/mutant/mutator/node/literal/fixnum.rb +1 -1
  36. data/lib/mutant/mutator/node/resbody.rb +0 -2
  37. data/lib/mutant/mutator/node/send.rb +17 -7
  38. data/lib/mutant/mutator/node/send/index.rb +0 -2
  39. data/lib/mutant/mutator/registry.rb +1 -1
  40. data/lib/mutant/mutator/util.rb +1 -1
  41. data/lib/mutant/mutator/util/array.rb +1 -1
  42. data/lib/mutant/reporter.rb +13 -3
  43. data/lib/mutant/reporter/cli.rb +54 -8
  44. data/lib/mutant/reporter/cli/format.rb +197 -0
  45. data/lib/mutant/reporter/cli/printer.rb +402 -22
  46. data/lib/mutant/reporter/cli/tput.rb +27 -0
  47. data/lib/mutant/reporter/null.rb +4 -34
  48. data/lib/mutant/reporter/trace.rb +6 -38
  49. data/lib/mutant/result.rb +44 -56
  50. data/lib/mutant/runner.rb +99 -52
  51. data/lib/mutant/runner/collector.rb +134 -0
  52. data/lib/mutant/subject/method/instance.rb +12 -4
  53. data/lib/mutant/version.rb +1 -1
  54. data/lib/mutant/warning_filter.rb +0 -2
  55. data/lib/mutant/zombifier/file.rb +1 -1
  56. data/meta/block.rb +17 -1
  57. data/meta/send.rb +123 -1
  58. data/mutant-rspec.gemspec +3 -3
  59. data/mutant.gemspec +1 -1
  60. data/spec/integration/mutant/corpus_spec.rb +4 -195
  61. data/spec/integration/mutant/null_spec.rb +1 -3
  62. data/spec/integration/mutant/rspec_spec.rb +1 -3
  63. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +1 -3
  64. data/spec/integration/mutant/zombie_spec.rb +1 -3
  65. data/spec/integrations.yml +7 -0
  66. data/spec/shared/method_matcher_behavior.rb +1 -1
  67. data/spec/spec_helper.rb +1 -0
  68. data/spec/support/compress_helper.rb +1 -0
  69. data/spec/support/corpus.rb +239 -0
  70. data/spec/support/mutation_verifier.rb +2 -4
  71. data/spec/unit/mutant/cli_spec.rb +20 -13
  72. data/spec/unit/mutant/context/root_spec.rb +1 -3
  73. data/spec/unit/mutant/context/scope/root_spec.rb +1 -3
  74. data/spec/unit/mutant/context/scope/unqualified_name_spec.rb +1 -3
  75. data/spec/unit/mutant/diff_spec.rb +37 -19
  76. data/spec/unit/mutant/expression/method_spec.rb +5 -7
  77. data/spec/unit/mutant/expression/methods_spec.rb +5 -7
  78. data/spec/unit/mutant/expression/namespace/flat_spec.rb +6 -8
  79. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +6 -7
  80. data/spec/unit/mutant/expression_spec.rb +14 -5
  81. data/spec/unit/mutant/integration_spec.rb +14 -3
  82. data/spec/unit/mutant/isolation_spec.rb +2 -4
  83. data/spec/unit/mutant/loader/eval_spec.rb +1 -3
  84. data/spec/unit/mutant/matcher/chain_spec.rb +1 -3
  85. data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +21 -0
  86. data/spec/unit/mutant/matcher/compiler_spec.rb +28 -3
  87. data/spec/unit/mutant/matcher/filter_spec.rb +1 -3
  88. data/spec/unit/mutant/matcher/method/instance_spec.rb +3 -5
  89. data/spec/unit/mutant/matcher/method/singleton_spec.rb +22 -4
  90. data/spec/unit/mutant/matcher/methods/instance_spec.rb +7 -6
  91. data/spec/unit/mutant/matcher/methods/singleton_spec.rb +4 -6
  92. data/spec/unit/mutant/matcher/namespace_spec.rb +1 -3
  93. data/spec/unit/mutant/matcher/null_spec.rb +1 -3
  94. data/spec/unit/mutant/mutation_spec.rb +1 -3
  95. data/spec/unit/mutant/mutator/node_spec.rb +1 -3
  96. data/spec/unit/mutant/reporter/cli_spec.rb +444 -206
  97. data/spec/unit/mutant/reporter/null_spec.rb +1 -3
  98. data/spec/unit/mutant/require_highjack_spec.rb +1 -3
  99. data/spec/unit/mutant/runner_spec.rb +42 -28
  100. data/spec/unit/mutant/subject/context_spec.rb +1 -3
  101. data/spec/unit/mutant/subject/method/instance_spec.rb +27 -19
  102. data/spec/unit/mutant/subject/method/singleton_spec.rb +49 -17
  103. data/spec/unit/mutant/subject_spec.rb +1 -3
  104. data/spec/unit/mutant/test_spec.rb +1 -3
  105. data/spec/unit/mutant/warning_expectation.rb +1 -3
  106. data/spec/unit/mutant/warning_filter_spec.rb +1 -3
  107. data/spec/unit/mutant_spec.rb +13 -3
  108. data/test_app/Gemfile.devtools +2 -2
  109. data/test_app/spec/unit/test_app/literal/string_spec.rb +1 -1
  110. metadata +10 -21
  111. data/lib/mutant/matcher/method/finder.rb +0 -72
  112. data/lib/mutant/reporter/cli/progress.rb +0 -10
  113. data/lib/mutant/reporter/cli/progress/config.rb +0 -30
  114. data/lib/mutant/reporter/cli/progress/env.rb +0 -30
  115. data/lib/mutant/reporter/cli/progress/noop.rb +0 -27
  116. data/lib/mutant/reporter/cli/progress/result.rb +0 -12
  117. data/lib/mutant/reporter/cli/progress/result/mutation.rb +0 -45
  118. data/lib/mutant/reporter/cli/progress/result/subject.rb +0 -54
  119. data/lib/mutant/reporter/cli/progress/subject.rb +0 -27
  120. data/lib/mutant/reporter/cli/registry.rb +0 -81
  121. data/lib/mutant/reporter/cli/report.rb +0 -10
  122. data/lib/mutant/reporter/cli/report/env.rb +0 -92
  123. data/lib/mutant/reporter/cli/report/mutation.rb +0 -103
  124. data/lib/mutant/reporter/cli/report/subject.rb +0 -32
  125. data/lib/mutant/reporter/cli/report/test.rb +0 -28
  126. data/lib/mutant/walker.rb +0 -53
  127. data/spec/shared/mutator_behavior.rb +0 -55
@@ -1,72 +0,0 @@
1
- module Mutant
2
- class Matcher
3
- class Method
4
-
5
- # Visitor to find last match inside AST
6
- class Finder
7
-
8
- # Run finder
9
- #
10
- # @param [Parser::AST::Node]
11
- #
12
- # @return [Parser::AST::Node]
13
- # if found
14
- #
15
- # @return [nil]
16
- # otherwise
17
- #
18
- # @api private
19
- #
20
- #
21
- def self.run(root, &predicate)
22
- new(root, predicate).match
23
- end
24
-
25
- private_class_method :new
26
-
27
- # Return match
28
- #
29
- # @return [Parser::AST::Node]
30
- #
31
- # @api private
32
- #
33
- attr_reader :match
34
-
35
- private
36
-
37
- # Initialize object
38
- #
39
- # @param [Parer::AST::Node]
40
- #
41
- # @return [undefined]
42
- #
43
- # @api private
44
- #
45
- #
46
- def initialize(root, predicate)
47
- @root, @predicate = root, predicate
48
- visit(root)
49
- end
50
-
51
- # Visit node
52
- #
53
- # @param [Parser::AST::Node] node
54
- #
55
- # @return [undefined]
56
- #
57
- # @api private
58
- #
59
- def visit(node)
60
- if @predicate.call(node)
61
- @match = node
62
- end
63
-
64
- node.children.each do |child|
65
- visit(child) if child.kind_of?(Parser::AST::Node)
66
- end
67
- end
68
-
69
- end # Finder
70
- end # Method
71
- end # Matcher
72
- end # Mutant
@@ -1,10 +0,0 @@
1
- module Mutant
2
- class Reporter
3
- class CLI
4
- # Abstract base and namespace class for process printers
5
- class Progress < Printer
6
- include AbstractType, Registry.new
7
- end # Progress
8
- end # CLI
9
- end # Reporter
10
- end # Mutant
@@ -1,30 +0,0 @@
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
- # Report configuration
11
- #
12
- # @param [Mutant::Config] config
13
- #
14
- # @return [self]
15
- #
16
- # @api private
17
- #
18
- def run
19
- info 'Mutant configuration:'
20
- info 'Matcher: %s', object.matcher_config.inspect
21
- info 'Integration: %s', object.integration.name
22
- info 'Expect Coverage: %0.2f%%', object.expected_coverage.inspect
23
- self
24
- end
25
-
26
- end # Progress
27
- end # Printer
28
- end # CLI
29
- end # Reporter
30
- end # Mutant
@@ -1,30 +0,0 @@
1
- module Mutant
2
- class Reporter
3
- class CLI
4
- class Progress
5
- # Progress printer for configuration
6
- class Env < self
7
-
8
- handle Mutant::Env
9
-
10
- delegate :config
11
-
12
- # Report configuration
13
- #
14
- # @param [Mutant::Config] config
15
- #
16
- # @return [self]
17
- #
18
- # @api private
19
- #
20
- def run
21
- visit(config)
22
- info 'Available Subjects: %d', object.matchable_scopes.length
23
- info 'Subjects: %d', object.subjects.length
24
- end
25
-
26
- end # Progress
27
- end # Printer
28
- end # CLI
29
- end # Reporter
30
- end # Mutant
@@ -1,27 +0,0 @@
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::Test)
9
- handle(Mutant::Mutation)
10
- handle(Mutant::Result::Env)
11
- handle(Mutant::Result::Test)
12
-
13
- # Noop progress report
14
- #
15
- # @return [self]
16
- #
17
- # @api private
18
- #
19
- def run
20
- self
21
- end
22
-
23
- end # Noop
24
- end # Progress
25
- end # CLI
26
- end # Reporter
27
- end # Mutant
@@ -1,12 +0,0 @@
1
- module Mutant
2
- class Reporter
3
- class CLI
4
- class Progress
5
- # Abstract namespace class for result progress printers
6
- class Result < self
7
- include AbstractType
8
- end # Result
9
- end # Progress
10
- end # CLI
11
- end # Reporter
12
- end # Mutant
@@ -1,45 +0,0 @@
1
- module Mutant
2
- class Reporter
3
- class CLI
4
- class Progress
5
- class Result
6
- # Mutation test result progress reporter
7
- class Mutation < self
8
-
9
- handle(Mutant::Result::Mutation)
10
-
11
- SUCCESS = '.'.freeze
12
- FAILURE = 'F'.freeze
13
-
14
- # Run printer
15
- #
16
- # @return [self]
17
- #
18
- # @api private
19
- #
20
- def run
21
- char(success? ? SUCCESS : FAILURE)
22
- self
23
- end
24
-
25
- private
26
-
27
- # Write colorized char
28
- #
29
- # @param [String] char
30
- #
31
- # @return [undefined]
32
- #
33
- # @api private
34
- #
35
- def char(char)
36
- output.write(colorize(status_color, char))
37
- output.flush
38
- end
39
-
40
- end # Mutation
41
- end # Result
42
- end # Progress
43
- end # CLI
44
- end # Reporter
45
- end # Mutant
@@ -1,54 +0,0 @@
1
- module Mutant
2
- class Reporter
3
- class CLI
4
- class Progress
5
- class Result
6
- # Reporter for subject runners
7
- class Subject < self
8
-
9
- FORMAT = '(%02d/%02d) %3d%% - killtime: %0.02fs runtime: %0.02fs overhead: %0.02fs'.freeze
10
-
11
- handle(Mutant::Result::Subject)
12
-
13
- # Run printer
14
- #
15
- # @return [self]
16
- #
17
- # @api private
18
- #
19
- def run
20
- print_progress_bar_finish
21
- print_stats
22
- self
23
- end
24
-
25
- delegate :coverage, :runtime, :amount_mutations_killed, :amount_mutations, :killtime, :overhead
26
-
27
- private
28
-
29
- # Print stats
30
- #
31
- # @return [undefined]
32
- #
33
- # @api private
34
- #
35
- def print_stats
36
- status(FORMAT, amount_mutations_killed, amount_mutations, coverage * 100, killtime, runtime, overhead)
37
- end
38
-
39
- # Print progress bar finish
40
- #
41
- # @return [undefined]
42
- #
43
- # @api private
44
- #
45
- def print_progress_bar_finish
46
- puts unless amount_mutations.zero?
47
- end
48
-
49
- end # Subject
50
- end # Result
51
- end # Progress
52
- end # CLI
53
- end # Reporter
54
- end # Mutant
@@ -1,27 +0,0 @@
1
- module Mutant
2
- class Reporter
3
- class CLI
4
- class Progress
5
- # CLI progress reporter for subjects
6
- class Subject < self
7
-
8
- handle Mutant::Subject
9
-
10
- # Run printer
11
- #
12
- # @return [undefined]
13
- #
14
- # @api private
15
- #
16
- def run
17
- puts("#{object.identification} mutations: #{object.mutations.length}")
18
- object.tests.each do |test|
19
- puts "- #{test.identification}"
20
- end
21
- end
22
-
23
- end # Subject
24
- end # Progress
25
- end # CLI
26
- end # Reporter
27
- end # Mutant
@@ -1,81 +0,0 @@
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.equal?(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
- # @api private
62
- #
63
- def included(host)
64
- super
65
-
66
- object = self
67
- host.class_eval do
68
- define_singleton_method(:lookup, &object.method(:lookup))
69
- private_class_method :lookup
70
-
71
- define_singleton_method(:handle) do |subject|
72
- object.handle(subject, self)
73
- end
74
- private_class_method :handle
75
- end
76
- end
77
-
78
- end # Registry
79
- end # CLI
80
- end # Reporter
81
- end # Mutant
@@ -1,10 +0,0 @@
1
- module Mutant
2
- class Reporter
3
- class CLI
4
- # Abstract base class for process printers
5
- class Report < Printer
6
- include AbstractType, Registry.new
7
- end # Report
8
- end # CLI
9
- end # Reporter
10
- end # Mutant
@@ -1,92 +0,0 @@
1
- module Mutant
2
- class Reporter
3
- class CLI
4
- class Report
5
-
6
- # Env result reporter
7
- class Env < self
8
-
9
- handle(Result::Env)
10
-
11
- delegate(
12
- :coverage, :failed_subject_results, :amount_subjects, :amount_mutations,
13
- :amount_mutations_alive, :amount_mutations_killed, :runtime, :killtime, :overhead, :env
14
- )
15
-
16
- # Run printer
17
- #
18
- # @return [self]
19
- #
20
- # @api private
21
- #
22
- def run
23
- visit_collection(failed_subject_results)
24
- info 'Subjects: %s', amount_subjects
25
- info 'Mutations: %s', amount_mutations
26
- info 'Kills: %s', amount_mutations_killed
27
- info 'Alive: %s', amount_mutations_alive
28
- info 'Runtime: %0.2fs', runtime
29
- info 'Killtime: %0.2fs', killtime
30
- info 'Overhead: %0.2f%%', overhead_percent
31
- status 'Coverage: %0.2f%%', coverage_percent
32
- status 'Expected: %0.2f%%', env.config.expected_coverage
33
- print_generic_stats
34
- self
35
- end
36
-
37
- private
38
-
39
- # Print generic stats
40
- #
41
- # @return [undefined]
42
- #
43
- # @api private
44
- #
45
- def print_generic_stats
46
- stats = generic_stats.to_a.sort_by(&:last)
47
- return if stats.empty?
48
- info('Nodes handled by generic mutator (type:occurrences):')
49
- stats.reverse_each do |type, amount|
50
- info('%-10s: %d', type, amount)
51
- end
52
- end
53
-
54
- # Return coverage percent
55
- #
56
- # @return [Float]
57
- #
58
- # @api private
59
- #
60
- def coverage_percent
61
- coverage * 100
62
- end
63
-
64
- # Return overhead percent
65
- #
66
- # @return [Float]
67
- #
68
- # @api private
69
- #
70
- def overhead_percent
71
- (overhead / killtime) * 100
72
- end
73
-
74
- # Return stats for nodes handled by generic mutator
75
- #
76
- # @return [Hash<Symbo, Fixnum>]
77
- #
78
- # @api private
79
- #
80
- def generic_stats
81
- object.subject_results.each_with_object(Hash.new(0)) do |result, stats|
82
- Walker.run(result.subject.node) do |node|
83
- stats[node.type] += 1 if Mutator::Registry.lookup(node).equal?(Mutator::Node::Generic)
84
- end
85
- end
86
- end
87
-
88
- end # Env
89
- end # Report
90
- end # CLI
91
- end # Reporter
92
- end # Mutant