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
@@ -24,17 +24,8 @@ module Mutant
24
24
  def each
25
25
  return to_enum unless block_given?
26
26
 
27
- unless skip?
28
- if subject
29
- yield subject
30
- else
31
- message = sprintf(
32
- 'Cannot find definition of: %s in %s',
33
- identification,
34
- source_location.join(':')
35
- )
36
- $stderr.puts(message)
37
- end
27
+ if !skip? && subject
28
+ yield subject
38
29
  end
39
30
 
40
31
  self
@@ -6,6 +6,9 @@ module Mutant
6
6
  include AbstractType, Adamantium::Flat
7
7
  include Concord::Public.new(:subject, :node)
8
8
 
9
+ CODE_DELIMITER = "\0".freeze
10
+ CODE_RANGE = (0..4).freeze
11
+
9
12
  # Return mutated root node
10
13
  #
11
14
  # @return [Parser::AST::Node]
@@ -54,8 +57,9 @@ module Mutant
54
57
  # @api private
55
58
  #
56
59
  def identification
57
- "#{subject.identification}:#{code}"
60
+ "#{self.class::SYMBOL}:#{subject.identification}:#{code}"
58
61
  end
62
+ memoize :identification
59
63
 
60
64
  # Return mutation code
61
65
  #
@@ -64,7 +68,7 @@ module Mutant
64
68
  # @api private
65
69
  #
66
70
  def code
67
- sha1[0..4]
71
+ sha1[CODE_RANGE]
68
72
  end
69
73
  memoize :code
70
74
 
@@ -89,6 +93,16 @@ module Mutant
89
93
  subject.source
90
94
  end
91
95
 
96
+ # Test if test should fail under mutation
97
+ #
98
+ # @return [Boolean]
99
+ #
100
+ # @api private
101
+ #
102
+ def should_fail?
103
+ self.class::SHOULD_FAIL
104
+ end
105
+
92
106
  private
93
107
 
94
108
  # Return sha1 sum of source and subject identification
@@ -98,7 +112,7 @@ module Mutant
98
112
  # @api private
99
113
  #
100
114
  def sha1
101
- Digest::SHA1.hexdigest(subject.identification + 0.chr + source)
115
+ Digest::SHA1.hexdigest(subject.identification + CODE_DELIMITER + source)
102
116
  end
103
117
  memoize :sha1
104
118
 
@@ -5,16 +5,8 @@ module Mutant
5
5
  # Evul mutation
6
6
  class Evil < self
7
7
 
8
- # Return identification
9
- #
10
- # @return [String]
11
- #
12
- # @api private
13
- #
14
- def identification
15
- "evil:#{super}"
16
- end
17
- memoize :identification
8
+ SHOULD_FAIL = true
9
+ SYMBOL = 'evil'.freeze
18
10
 
19
11
  # Test if killer is successful
20
12
  #
@@ -5,41 +5,15 @@ module Mutant
5
5
  # Neutral mutation
6
6
  class Neutral < self
7
7
 
8
- SYMBOL = 'neutral'
8
+ SYMBOL = 'neutral'.freeze
9
+ SHOULD_FAIL = false
9
10
 
10
11
  # Noop mutation, special case of neutral
11
12
  class Noop < self
12
13
 
13
- SYMBOL = 'noop'
14
+ SYMBOL = 'noop'.freeze
14
15
 
15
- end
16
-
17
- # Return identification
18
- #
19
- # @return [String]
20
- #
21
- # @api private
22
- #
23
- def identification
24
- "#{self.class::SYMBOL}:#{super}"
25
- end
26
- memoize :identification
27
-
28
- # Test if killer is successful
29
- #
30
- # @param [Killer] killer
31
- #
32
- # @return [true]
33
- # if killer did NOT killed mutation
34
- #
35
- # @return [false]
36
- # otherwise
37
- #
38
- # @api private
39
- #
40
- def success?(killer)
41
- !killer.killed?
42
- end
16
+ end # Noop
43
17
 
44
18
  end # Neutral
45
19
  end # Mutation
@@ -20,7 +20,6 @@ module Mutant
20
20
  def dispatch
21
21
  emit_nil
22
22
  emit_values(values)
23
- emit_new { new_self(Random.fixnum) }
24
23
  end
25
24
 
26
25
  # Return values to mutate against
@@ -21,7 +21,6 @@ module Mutant
21
21
  emit_nil
22
22
  emit_values(values)
23
23
  emit_special_cases
24
- emit_new { new_self(Random.float) }
25
24
  end
26
25
 
27
26
  SPECIAL = [
@@ -19,7 +19,6 @@ module Mutant
19
19
  #
20
20
  def dispatch
21
21
  emit_nil
22
- emit_new { new_self(Random.hex_string) }
23
22
  end
24
23
 
25
24
  end # String
@@ -9,7 +9,9 @@ module Mutant
9
9
 
10
10
  handle(:sym)
11
11
 
12
- PREFIX = 's'
12
+ children :value
13
+
14
+ PREFIX = '__mutant__'.freeze
13
15
 
14
16
  private
15
17
 
@@ -21,7 +23,9 @@ module Mutant
21
23
  #
22
24
  def dispatch
23
25
  emit_nil
24
- emit_new { new_self((PREFIX + Random.hex_string).to_sym) }
26
+ Mutator::Util::Symbol.each(value, self) do |value|
27
+ emit_self(value)
28
+ end
25
29
  end
26
30
 
27
31
  end # Symbol
@@ -10,11 +10,15 @@ module Mutant
10
10
 
11
11
  children :name, :value
12
12
 
13
- MAP = IceNine.deep_freeze(
13
+ map = {
14
14
  gvasgn: '$',
15
15
  cvasgn: '@@',
16
16
  ivasgn: '@',
17
17
  lvasgn: ''
18
+ }
19
+
20
+ MAP = IceNine.deep_freeze(
21
+ Hash[map.map { |type, prefix| [type, [prefix, /^#{Regexp.escape(prefix)}/]] }]
18
22
  )
19
23
 
20
24
  handle(*MAP.keys)
@@ -40,8 +44,9 @@ module Mutant
40
44
  # @api private
41
45
  #
42
46
  def mutate_name
43
- prefix = MAP.fetch(node.type)
44
- Mutator::Util::Symbol.each(name, self) do |name|
47
+ prefix, regexp = MAP.fetch(node.type)
48
+ stripped = name.to_s.sub(regexp, EMPTY_STRING)
49
+ Mutator::Util::Symbol.each(stripped, self) do |name|
45
50
  emit_name(:"#{prefix}#{name}")
46
51
  end
47
52
  end
@@ -9,6 +9,8 @@ module Mutant
9
9
 
10
10
  handle(::Symbol)
11
11
 
12
+ POSTFIX = '__mutant__'.freeze
13
+
12
14
  private
13
15
 
14
16
  # Emit mutations
@@ -18,7 +20,7 @@ module Mutant
18
20
  # @api private
19
21
  #
20
22
  def dispatch
21
- emit_new { :"s#{Random.hex_string}" }
23
+ emit((input.to_s + POSTFIX).to_sym)
22
24
  end
23
25
 
24
26
  end # Symbol
@@ -13,7 +13,7 @@ module Mutant
13
13
  # @api private
14
14
  #
15
15
  def s(type, *children)
16
- ::Parser::AST::Node.new(type, children)
16
+ Parser::AST::Node.new(type, children)
17
17
  end
18
18
  module_function :s
19
19
 
@@ -21,8 +21,6 @@ module Mutant
21
21
  s(:send, s(:float, 0.0), :/, s(:float, 0.0))
22
22
  INFINITY =
23
23
  s(:send, s(:float, 1.0), :/, s(:float, 0.0))
24
- NEW_OBJECT =
25
- s(:send, s(:const, s(:cbase), :Object), :new)
26
24
  NEGATIVE_INFINITY =
27
25
  s(:send, s(:float, -1.0), :/, s(:float, 0.0))
28
26
 
@@ -15,5 +15,15 @@ module Mutant
15
15
  #
16
16
  abstract_method :report
17
17
 
18
+ # Report progress on object
19
+ #
20
+ # @param [Object] object
21
+ #
22
+ # @return [self]
23
+ #
24
+ # @api private
25
+ #
26
+ abstract_method :progress
27
+
18
28
  end # Reporter
19
29
  end # Mutant
@@ -4,10 +4,23 @@ module Mutant
4
4
  class Reporter
5
5
  # Reporter that reports in human readable format
6
6
  class CLI < self
7
- include Concord::Public.new(:output)
7
+ include Concord.new(:output)
8
8
 
9
9
  NL = "\n".freeze
10
10
 
11
+ # Report progress object
12
+ #
13
+ # @param [Object] object
14
+ #
15
+ # @return [self]
16
+ #
17
+ # @api private
18
+ #
19
+ def progress(object)
20
+ Progress.run(output, object)
21
+ self
22
+ end
23
+
11
24
  # Report object
12
25
  #
13
26
  # @param [Object] object
@@ -17,7 +30,7 @@ module Mutant
17
30
  # @api private
18
31
  #
19
32
  def report(object)
20
- Printer.visit(object, output)
33
+ Report.run(output, object)
21
34
  self
22
35
  end
23
36
 
@@ -6,120 +6,27 @@ module Mutant
6
6
 
7
7
  # CLI runner status printer base class
8
8
  class Printer
9
- include AbstractType, Adamantium::Flat, Concord.new(:object, :output)
9
+ include AbstractType, Delegator, Adamantium::Flat, Concord.new(:output, :object)
10
10
 
11
- REGISTRY = {}
12
-
13
- # Create delegators to object
14
- #
15
- # @return [undefined]
16
- #
17
- # @api private
18
- #
19
- def self.delegate(*names)
20
- names.each do |name|
21
- define_delegator(name)
22
- end
23
- end
24
- private_class_method :delegate
25
-
26
- # Create delegator to object
27
- #
28
- # @param [Symbol] name
29
- #
30
- # @return [undefined]
31
- #
32
- # @api private
33
- #
34
- def self.define_delegator(name)
35
- define_method(name) do
36
- object.public_send(name)
37
- end
38
- private name
39
- end
40
- private_class_method :define_delegator
41
-
42
- # Registre handler for class
43
- #
44
- # @param [Class] klass
45
- #
46
- # @return [undefined]
11
+ # Run printer on object to output
47
12
  #
48
- # @api private
49
- #
50
- def self.handle(klass)
51
- REGISTRY[klass] = self
52
- end
53
-
54
- # Finalize CLI reporter
55
- #
56
- # @return [undefined]
57
- #
58
- # @api private
59
- #
60
- def self.finalize
61
- REGISTRY.freeze
62
- end
63
-
64
- # Build printer
65
- #
66
- # @return [Printer]
67
- #
68
- # @api private
69
- #
70
- def self.build(*args)
71
- new(*args)
72
- end
73
-
74
- # Run printer
13
+ # @param [IO] output
14
+ # @param [Object] object
75
15
  #
76
16
  # @return [self]
77
17
  #
78
- # @api private
79
- #
80
- def self.run(*args)
81
- build(*args).run
18
+ def self.run(output, object)
19
+ handler = lookup(object.class)
20
+ handler.new(output, object).run
82
21
  self
83
22
  end
84
23
 
85
- # Visit object
86
- #
87
- # @param [Object] object
88
- # @param [IO] output
89
- #
90
- # @return [undefined]
91
- #
92
- # @api private
93
- #
94
- def self.visit(object, output)
95
- printer = lookup(object.class)
96
- printer.run(object, output)
97
- end
98
-
99
- # Lookup printer class
100
- #
101
- # @param [Class] klass
102
- #
103
- # @return [Class:Printer]
104
- # if found
24
+ # Run printer
105
25
  #
106
- # @raise [RuntimeError]
107
- # otherwise
26
+ # @return [self]
108
27
  #
109
28
  # @api private
110
29
  #
111
- def self.lookup(klass)
112
- current = klass
113
- until current == Object
114
- if REGISTRY.key?(current)
115
- return REGISTRY.fetch(current)
116
- end
117
- current = current.superclass
118
- end
119
- raise "No printer for: #{klass}"
120
- end
121
- private_class_method :lookup
122
-
123
30
  abstract_method :run
124
31
 
125
32
  private
@@ -130,7 +37,7 @@ module Mutant
130
37
  #
131
38
  # @api private
132
39
  #
133
- def color
40
+ def status_color
134
41
  success? ? Color::GREEN : Color::RED
135
42
  end
136
43
 
@@ -143,7 +50,7 @@ module Mutant
143
50
  # @api private
144
51
  #
145
52
  def visit(object)
146
- self.class.visit(object, output)
53
+ self.class.run(output, object)
147
54
  end
148
55
 
149
56
  # Print an info line to output
@@ -163,7 +70,7 @@ module Mutant
163
70
  # @api private
164
71
  #
165
72
  def status(string, *arguments)
166
- puts(colorize(color, sprintf(string, *arguments)))
73
+ puts(colorize(status_color, sprintf(string, *arguments)))
167
74
  end
168
75
 
169
76
  # Print a line to output