mutant 0.2.12 → 0.2.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 (48) hide show
  1. data/Changelog.md +4 -0
  2. data/Gemfile +1 -1
  3. data/Gemfile.devtools +39 -19
  4. data/README.md +3 -2
  5. data/TODO +3 -1
  6. data/config/flay.yml +1 -1
  7. data/config/site.reek +10 -3
  8. data/lib/mutant.rb +6 -73
  9. data/lib/mutant/constants.rb +49 -0
  10. data/lib/mutant/killer/forking.rb +6 -2
  11. data/lib/mutant/loader.rb +6 -79
  12. data/lib/mutant/matcher/scope_methods.rb +2 -2
  13. data/lib/mutant/mutation.rb +3 -2
  14. data/lib/mutant/mutation/filter/whitelist.rb +2 -0
  15. data/lib/mutant/mutator/node.rb +20 -9
  16. data/lib/mutant/mutator/node/assignment.rb +8 -1
  17. data/lib/mutant/mutator/node/block.rb +1 -0
  18. data/lib/mutant/mutator/node/default_arguments.rb +1 -0
  19. data/lib/mutant/mutator/node/formal_arguments_19.rb +1 -0
  20. data/lib/mutant/mutator/node/formal_arguments_19/default_mutations.rb +1 -0
  21. data/lib/mutant/mutator/node/{if_statement.rb → if.rb} +21 -6
  22. data/lib/mutant/mutator/node/iter_19.rb +1 -0
  23. data/lib/mutant/mutator/node/literal.rb +4 -3
  24. data/lib/mutant/mutator/node/literal/hash.rb +2 -1
  25. data/lib/mutant/mutator/node/literal/range.rb +2 -1
  26. data/lib/mutant/mutator/node/noop.rb +2 -0
  27. data/lib/mutant/mutator/node/receiver_case.rb +1 -19
  28. data/lib/mutant/mutator/node/send.rb +8 -136
  29. data/lib/mutant/mutator/node/send/binary_operator_method.rb +61 -0
  30. data/lib/mutant/mutator/node/send/with_arguments.rb +81 -0
  31. data/lib/mutant/mutator/node/super.rb +2 -0
  32. data/lib/mutant/mutator/node/{arguments.rb → when.rb} +4 -4
  33. data/lib/mutant/mutator/node/while.rb +2 -0
  34. data/lib/mutant/mutator/util/array.rb +2 -1
  35. data/lib/mutant/mutator/util/symbol.rb +1 -1
  36. data/lib/mutant/reporter/null.rb +1 -0
  37. data/lib/mutant/runner.rb +3 -4
  38. data/lib/mutant/singleton_methods.rb +28 -0
  39. data/lib/mutant/strategy.rb +2 -0
  40. data/lib/mutant/strategy/rspec/example_lookup.rb +4 -2
  41. data/mutant.gemspec +4 -4
  42. data/spec/shared/mutator_behavior.rb +1 -2
  43. data/spec/support/zombie.rb +35 -2
  44. data/spec/unit/mutant/loader/eval/class_methods/run_spec.rb +5 -6
  45. data/spec/unit/mutant/mutator/node/literal/float_spec.rb +1 -1
  46. data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +61 -61
  47. metadata +12 -10
  48. data/spec/unit/mutant/loader/rubinius/class_methods/run_spec.rb +0 -42
@@ -1,3 +1,7 @@
1
+ # v0.2.13 2013-01-05
2
+
3
+ * [fixed] Capture failures that occur in the window between mutation insertion and spec run as kills
4
+
1
5
  # v0.2.12 2013-01-03
2
6
 
3
7
  * [fixed] Do not crash when trying to load methods from precompiled ruby under rbx
data/Gemfile CHANGED
@@ -2,5 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'devtools', :git => 'https://github.com/mbj/devtools.git'
5
+ gem 'devtools', :git => 'https://github.com/datamapper/devtools.git'
6
6
  eval(File.read(File.join(File.dirname(__FILE__),'Gemfile.devtools')))
@@ -1,30 +1,36 @@
1
+ # encoding: utf-8
2
+
1
3
  group :development do
2
- gem 'rake', '~> 10.0'
3
- gem 'rspec', '~> 2.12.0'
4
- gem 'yard', '~> 0.8.3'
4
+ gem 'rake', '~> 10.0.3'
5
+ gem 'rspec', '~> 2.12.0'
6
+ gem 'yard', '~> 0.8.3'
7
+ end
8
+
9
+ group :yard do
10
+ gem 'redcarpet', '~> 2.2.2', :platforms => [ :mri, :rbx ]
5
11
  end
6
12
 
7
13
  group :guard do
8
- gem 'guard', '~> 1.5.4'
14
+ gem 'guard', '~> 1.6.1'
9
15
  gem 'guard-bundler', '~> 1.0.0'
10
- gem 'guard-rspec', '~> 2.1.1'
11
- gem 'rb-inotify', :git => 'https://github.com/mbj/rb-inotify'
12
- end
16
+ gem 'guard-rspec', '~> 2.3.3'
13
17
 
14
- group :benchmarks do
15
- gem 'rbench', '~> 0.2.3'
16
- end
18
+ # file system change event handling
19
+ gem 'rb-fchange', '~> 0.0.6', :require => false
20
+ gem 'rb-fsevent', '~> 0.9.3', :require => false
21
+ gem 'rb-inotify', '~> 0.8.8', :require => false, :git => 'https://github.com/nex3/rb-inotify'
17
22
 
18
- platform :jruby do
19
- group :jruby do
20
- gem 'jruby-openssl', '~> 0.7.4'
21
- end
23
+ # notification handling
24
+ gem 'libnotify', '~> 0.8.0', :require => false
25
+ gem 'rb-notifu', '~> 0.0.4', :require => false
26
+ gem 'terminal-notifier-guard', '~> 1.5.3', :require => false
22
27
  end
23
28
 
24
29
  group :metrics do
25
- gem 'flay', '~> 1.4.2'
26
- gem 'flog', '~> 2.5.1'
27
- gem 'reek', '~> 1.2.8', :git => 'https://github.com/dkubb/reek.git'
30
+ gem 'backports', '~> 2.6.5'
31
+ gem 'flay', '~> 1.4.3'
32
+ gem 'flog', '~> 2.5.3'
33
+ gem 'reek', '~> 1.2.13', :git => 'https://github.com/dkubb/reek.git', :branch => 'fix-redundant-irresponsible-module-warnings'
28
34
  gem 'roodi', '~> 2.1.0'
29
35
  gem 'yardstick', '~> 0.8.0'
30
36
 
@@ -33,11 +39,25 @@ group :metrics do
33
39
  gem 'yard-spellcheck', '~> 0.1.5'
34
40
  end
35
41
 
42
+ platforms :mri_18 do
43
+ gem 'rcov', '~> 1.0.0'
44
+ end
45
+
36
46
  platforms :mri_19 do
37
- gem 'simplecov', '~> 0.7'
47
+ gem 'simplecov', '~> 0.7.1'
38
48
  end
39
49
 
40
50
  platforms :rbx do
41
- gem 'pelusa', '~> 0.2.1'
51
+ gem 'pelusa', '~> 0.2.2'
52
+ end
53
+ end
54
+
55
+ group :benchmarks do
56
+ gem 'rbench', '~> 0.2.3'
57
+ end
58
+
59
+ platform :jruby do
60
+ group :jruby do
61
+ gem 'jruby-openssl', '~> 0.8.2'
42
62
  end
43
63
  end
data/README.md CHANGED
@@ -64,8 +64,8 @@ The following specs are executed to kill a mutation on:
64
64
  ```
65
65
  Public instance methods: spec/unit/#{namespace}/#{class_name}/#{method_name}_spec.rb
66
66
  Public singleton methods: spec/unit/#{namespace}/#{class_name}/class_methods/#{method_name}_spec.rb
67
- Public instance methods: spec/unit/#{namespace}/#{class_name}/
68
- Public singleton methods: spec/unit/#{namespace}/#{class_name}/class_methods
67
+ Private instance methods: spec/unit/#{namespace}/#{class_name}/*_spec.rb
68
+ Private singleton methods: spec/unit/#{namespace}/#{class_name}/class_methods/*_spec.rb
69
69
  ```
70
70
 
71
71
  ### --rspec-unit
@@ -91,6 +91,7 @@ Alternatives
91
91
  Credits
92
92
  -------
93
93
 
94
+ * [Markus Schirp (mbj)](https://github.com/mbj)
94
95
  * A [gist](https://gist.github.com/1065789) from [dkubb](https://github.com/dkubb) showing ideas.
95
96
  * Older abandoned [mutant](https://github.com/txus/mutant). For motivating me doing this one.
96
97
  * [heckle](https://github.com/seattlerb/heckle). For getting me into mutation testing.
data/TODO CHANGED
@@ -2,6 +2,7 @@ Code:
2
2
  * Test mutant with dynamically created zombie.
3
3
  * Fix ugly code within default parameter mutations
4
4
  * Break up lib/mutant/mutator/node/send.rb in class specific files
5
+ * Log all warnings throug reporter, so remove random $stderr.puts calls
5
6
 
6
7
  AST:
7
8
  * Fix the rubinius AST to allow setting @vcall_style variable in Rubinius::AST::Send nodes.
@@ -27,11 +28,12 @@ Loader:
27
28
  * Make sure loader does not change visibility of injected mutants
28
29
 
29
30
  Killers:
30
- * Aggregate warnings on missing spec files
31
+ * Move test framework specific stuff to strategy
31
32
  * Add a general master <=> killer IPC interface. So different strategies of isolation
32
33
  (fork, vs jruby runtime creation) will work without big impact.
33
34
 
34
35
  Strategy:
36
+ * Aggregate warnings on missing spec files
35
37
  * Provide "expicit files to kill with" strategy
36
38
  * Automatically load ./spec/spec_helper.rb for rspec strategies (No need to specify -I and -r anymore)
37
39
 
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 25 # Todo bring down to ~20
3
- total_score: 902
3
+ total_score: 914
@@ -10,13 +10,14 @@ UncommunicativeParameterName:
10
10
  LargeClass:
11
11
  max_methods: 10
12
12
  exclude:
13
- #- "Mutant::Matcher::Method" # 13 methods
14
13
  - "Mutant::Reporter::CLI" # 16 methods TODO Reduce!
14
+ - "Mutant::Reporter::Stats" # 6 ivars TODO Reduce!
15
15
  - "Mutant::CLI" # 19 methods and 7 ivars, TODO Reduce!
16
16
  enabled: true
17
17
  max_instance_variables: 3
18
18
  UncommunicativeMethodName:
19
- accept: []
19
+ accept:
20
+ - sha1
20
21
  exclude: []
21
22
  enabled: true
22
23
  reject:
@@ -26,7 +27,9 @@ UncommunicativeMethodName:
26
27
  LongParameterList:
27
28
  max_params: 2
28
29
  exclude:
30
+ - "Mutant::Mutator::Node#new_send_with_arguments" # 3 params
29
31
  - "Mutant::Context::Constant#initialize" # 3 params
32
+ - "Mutant::Subject#initialize" # 3 params
30
33
  enabled: true
31
34
  overrides: {}
32
35
  FeatureEnvy:
@@ -43,6 +46,7 @@ IrresponsibleModule:
43
46
  enabled: true
44
47
  UncommunicativeModuleName:
45
48
  accept:
49
+ - Mutant::Mutator::Node::Iter19
46
50
  - Mutant::Strategy::Rspec::DM2
47
51
  exclude: []
48
52
  enabled: true
@@ -53,6 +57,8 @@ NestedIterators:
53
57
  ignore_iterators: []
54
58
  exclude:
55
59
  - Mutant#self.define_singleton_subclass
60
+ - Mutant::Mutator::Util::Array::Element#dispatch
61
+ - Mutant::Mutator::Node::ReceiverCase#emit_when_branch_mutation
56
62
  enabled: true
57
63
  max_allowed_nesting: 1
58
64
  LongMethod:
@@ -61,7 +67,8 @@ LongMethod:
61
67
  enabled: true
62
68
  Duplication:
63
69
  allow_calls: []
64
- exclude: []
70
+ exclude:
71
+ - Mutant::Mutator::Node::Literal::Hash#emit_element_presence
65
72
  enabled: true
66
73
  max_calls: 1
67
74
  UtilityFunction:
@@ -29,80 +29,10 @@ end
29
29
 
30
30
  # Library namespace
31
31
  module Mutant
32
-
33
- # The list of ruby kewords from http://ruby-doc.org/docs/keywords/1.9/
34
- KEYWORDS = %w(
35
- BEGIN END __ENCODING__ __END__ __FILE__
36
- __LINE__ alias and begin break case class
37
- def define do else elsif end ensure false
38
- for if in module next nil not or redo
39
- rescue retry return self super then true
40
- undef unless until when while yield
41
- ).map(&:to_sym).to_set.freeze
42
-
43
- BINARY_METHOD_OPERATOR_EXPANSIONS = {
44
- :<=> => :spaceship_operator,
45
- :=== => :case_equality_operator,
46
- :[]= => :element_writer,
47
- :[] => :element_reader,
48
- :<= => :less_than_or_equal_to_operator,
49
- :>= => :greater_than_or_equal_to_operator,
50
- :== => :equality_operator,
51
- :'!~' => :nomatch_operator,
52
- :'!=' => :inequality_operator,
53
- :=~ => :match_operator,
54
- :<< => :left_shift_operator,
55
- :>> => :right_shift_operator,
56
- :** => :exponentation_operator,
57
- :* => :multiplication_operator,
58
- :% => :modulo_operator,
59
- :/ => :division_operator,
60
- :| => :bitwise_or_operator,
61
- :^ => :bitwise_xor_operator,
62
- :& => :bitwise_and_operator,
63
- :< => :less_than_operator,
64
- :> => :greater_than_operator,
65
- :+ => :addition_operator,
66
- :- => :substraction_operator
67
- }.freeze
68
-
69
- UNARY_METHOD_OPERATOR_EXPANSIONS = {
70
- :~@ => :unary_match_operator,
71
- :+@ => :unary_addition_operator,
72
- :-@ => :unary_substraction_operator,
73
- :'!' => :negation_operator
74
- }.freeze
75
-
76
- BINARY_METHOD_OPERATORS = BINARY_METHOD_OPERATOR_EXPANSIONS.keys.to_set.freeze
77
-
78
- OPERATOR_EXPANSIONS = BINARY_METHOD_OPERATOR_EXPANSIONS.merge(UNARY_METHOD_OPERATOR_EXPANSIONS).freeze
79
-
80
- # Define instance of subclassed superclass as constant
81
- #
82
- # @param [Class] superclass
83
- # @param [Symbol] name
84
- #
85
- # @return [self]
86
- #
87
- # @api private
88
- #
89
- def self.define_singleton_subclass(name, superclass, &block)
90
- klass = Class.new(superclass) do
91
-
92
- def inspect; self.class.name; end
93
-
94
- define_singleton_method(:name) do
95
- "#{superclass.name}::#{name}".freeze
96
- end
97
-
98
- end
99
- klass.class_eval(&block)
100
- superclass.const_set(name, klass.new)
101
- self
102
- end
103
-
104
32
  end
105
33
 
34
+ require 'mutant/singleton_methods'
35
+ require 'mutant/constants'
106
36
  require 'mutant/support/method_object'
107
37
  require 'mutant/helper'
108
38
  require 'mutant/random'
@@ -133,6 +63,9 @@ require 'mutant/mutator/node/block'
133
63
  require 'mutant/mutator/node/while'
134
64
  require 'mutant/mutator/node/super'
135
65
  require 'mutant/mutator/node/send'
66
+ require 'mutant/mutator/node/send/with_arguments'
67
+ require 'mutant/mutator/node/send/binary_operator_method'
68
+ require 'mutant/mutator/node/when'
136
69
  require 'mutant/mutator/node/assignment'
137
70
  require 'mutant/mutator/node/define'
138
71
  require 'mutant/mutator/node/formal_arguments_19'
@@ -145,7 +78,7 @@ require 'mutant/mutator/node/pattern_variable'
145
78
  require 'mutant/mutator/node/default_arguments'
146
79
  require 'mutant/mutator/node/return'
147
80
  require 'mutant/mutator/node/iter_19'
148
- require 'mutant/mutator/node/if_statement'
81
+ require 'mutant/mutator/node/if'
149
82
  require 'mutant/mutator/node/receiver_case'
150
83
  require 'mutant/loader'
151
84
  require 'mutant/context'
@@ -0,0 +1,49 @@
1
+ module Mutant
2
+
3
+ # The list of ruby kewords from http://ruby-doc.org/docs/keywords/1.9/
4
+ KEYWORDS = %w(
5
+ BEGIN END __ENCODING__ __END__ __FILE__
6
+ __LINE__ alias and begin break case class
7
+ def define do else elsif end ensure false
8
+ for if in module next nil not or redo
9
+ rescue retry return self super then true
10
+ undef unless until when while yield
11
+ ).map(&:to_sym).to_set.freeze
12
+
13
+ BINARY_METHOD_OPERATOR_EXPANSIONS = {
14
+ :<=> => :spaceship_operator,
15
+ :=== => :case_equality_operator,
16
+ :[]= => :element_writer,
17
+ :[] => :element_reader,
18
+ :<= => :less_than_or_equal_to_operator,
19
+ :>= => :greater_than_or_equal_to_operator,
20
+ :== => :equality_operator,
21
+ :'!~' => :nomatch_operator,
22
+ :'!=' => :inequality_operator,
23
+ :=~ => :match_operator,
24
+ :<< => :left_shift_operator,
25
+ :>> => :right_shift_operator,
26
+ :** => :exponentation_operator,
27
+ :* => :multiplication_operator,
28
+ :% => :modulo_operator,
29
+ :/ => :division_operator,
30
+ :| => :bitwise_or_operator,
31
+ :^ => :bitwise_xor_operator,
32
+ :& => :bitwise_and_operator,
33
+ :< => :less_than_operator,
34
+ :> => :greater_than_operator,
35
+ :+ => :addition_operator,
36
+ :- => :substraction_operator
37
+ }.freeze
38
+
39
+ UNARY_METHOD_OPERATOR_EXPANSIONS = {
40
+ :~@ => :unary_match_operator,
41
+ :+@ => :unary_addition_operator,
42
+ :-@ => :unary_substraction_operator,
43
+ :'!' => :negation_operator
44
+ }.freeze
45
+
46
+ BINARY_METHOD_OPERATORS = BINARY_METHOD_OPERATOR_EXPANSIONS.keys.to_set.freeze
47
+
48
+ OPERATOR_EXPANSIONS = BINARY_METHOD_OPERATOR_EXPANSIONS.merge(UNARY_METHOD_OPERATOR_EXPANSIONS).freeze
49
+ end
@@ -41,8 +41,12 @@ module Mutant
41
41
  #
42
42
  def run
43
43
  fork do
44
- killer = @killer.new(strategy, mutation)
45
- Kernel.exit(killer.fail? ? 1 : 0)
44
+ begin
45
+ killer = @killer.new(strategy, mutation)
46
+ Kernel.exit(killer.fail? ? 1 : 0)
47
+ rescue
48
+ Kernel.exit(1)
49
+ end
46
50
  end
47
51
 
48
52
  status = Process.wait2.last
@@ -17,21 +17,21 @@ module Mutant
17
17
  # Initialize and insert mutation into vm
18
18
  #
19
19
  # @param [Rubinius::AST::Script] root
20
- # @param [String] file
21
- # @param [Fixnum] line
20
+ # @param [Subject] subject
22
21
  #
23
22
  # @return [undefined]
24
23
  #
25
24
  # @api private
26
25
  #
27
- def initialize(root, file, line)
28
- @root, @file, @line = root, file, line
26
+ def initialize(root, subject)
27
+ @root, @subject = root, subject
29
28
  run
30
29
  end
31
30
 
32
31
  # Eval based loader
33
32
  class Eval < self
34
- private
33
+
34
+ private
35
35
 
36
36
  # Run loader
37
37
  #
@@ -40,7 +40,7 @@ module Mutant
40
40
  # @api private
41
41
  #
42
42
  def run
43
- eval(source, TOPLEVEL_BINDING, @file, @line)
43
+ Kernel.eval(source, TOPLEVEL_BINDING, @subject.source_path, @subject.source_line)
44
44
  end
45
45
 
46
46
  # Return source
@@ -54,78 +54,5 @@ module Mutant
54
54
  end
55
55
  end
56
56
 
57
- # Rubinius script node based loaded
58
- class Rubinius < self
59
- private
60
-
61
- # Run loader
62
- #
63
- # @return [undefined]
64
- #
65
- # @api private
66
- #
67
- def run(root)
68
- Rubinius.run_script(compiled_code)
69
- end
70
-
71
- # Return compiled code
72
- #
73
- # @return [Rubinius::CompiledCode]
74
- #
75
- # @api private
76
- #
77
- # FIXME: rbx on travis is older than on my devbox.
78
- #
79
- def compiled_code
80
- _script = script
81
- _script.respond_to?(:compiled_code) ? _script.compiled_code : _script.compiled_method
82
- end
83
-
84
- # Return code script
85
- #
86
- # @return [Rubinius::CompiledCode::Script]
87
- #
88
- # @api private
89
- #
90
- def script
91
- compiled_code_raw.create_script
92
- end
93
-
94
- # Return compiled code for node
95
- #
96
- # @return [Rubinius::CompiledCode]
97
- #
98
- # @api private
99
- #
100
- def compiled_code_raw
101
- compiler.run
102
- end
103
-
104
- # Return compiler loaded with mutated ast
105
- #
106
- # @return [Rubinius::Compiler]
107
- #
108
- # @api private
109
- #
110
- def compiler
111
- Rubinius::Compiler.new(:bytecode, :compiled_method).tap do |compiler|
112
- compiler.generator.input(@root)
113
- end
114
- end
115
-
116
- # Return script node
117
- #
118
- # @param [Rubinius::AST::Node] node
119
- #
120
- # @return [Rubinius::AST::Script]
121
- #
122
- # @api private
123
- #
124
- def script(node)
125
- Rubinius::AST::Script.new(node).tap do |script|
126
- script.file = source_path
127
- end
128
- end
129
- end
130
57
  end
131
58
  end