mutant 0.8.10 → 0.8.11

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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -4
  3. data/Changelog.md +8 -0
  4. data/README.md +112 -43
  5. data/Rakefile +2 -16
  6. data/circle.yml +1 -1
  7. data/config/flay.yml +2 -2
  8. data/config/flog.yml +1 -1
  9. data/config/reek.yml +3 -4
  10. data/config/rubocop.yml +53 -16
  11. data/lib/mutant.rb +27 -6
  12. data/lib/mutant/ast/meta/const.rb +2 -0
  13. data/lib/mutant/ast/meta/optarg.rb +2 -0
  14. data/lib/mutant/ast/meta/resbody.rb +2 -0
  15. data/lib/mutant/ast/meta/restarg.rb +2 -0
  16. data/lib/mutant/ast/meta/send.rb +4 -0
  17. data/lib/mutant/ast/meta/symbol.rb +2 -0
  18. data/lib/mutant/ast/named_children.rb +14 -4
  19. data/lib/mutant/ast/nodes.rb +3 -1
  20. data/lib/mutant/ast/regexp.rb +53 -0
  21. data/lib/mutant/ast/regexp/transformer.rb +185 -0
  22. data/lib/mutant/ast/regexp/transformer/alternative.rb +39 -0
  23. data/lib/mutant/ast/regexp/transformer/character_set.rb +46 -0
  24. data/lib/mutant/ast/regexp/transformer/direct.rb +99 -0
  25. data/lib/mutant/ast/regexp/transformer/options_group.rb +66 -0
  26. data/lib/mutant/ast/regexp/transformer/quantifier.rb +112 -0
  27. data/lib/mutant/ast/regexp/transformer/recursive.rb +50 -0
  28. data/lib/mutant/ast/regexp/transformer/root.rb +29 -0
  29. data/lib/mutant/ast/regexp/transformer/text.rb +55 -0
  30. data/lib/mutant/ast/types.rb +92 -5
  31. data/lib/mutant/cli.rb +2 -14
  32. data/lib/mutant/color.rb +1 -1
  33. data/lib/mutant/config.rb +1 -3
  34. data/lib/mutant/expression/methods.rb +1 -1
  35. data/lib/mutant/expression/namespace.rb +2 -2
  36. data/lib/mutant/expression/parser.rb +1 -1
  37. data/lib/mutant/integration.rb +10 -28
  38. data/lib/mutant/isolation.rb +9 -60
  39. data/lib/mutant/isolation/fork.rb +72 -0
  40. data/lib/mutant/isolation/none.rb +25 -0
  41. data/lib/mutant/matcher/config.rb +2 -0
  42. data/lib/mutant/matcher/method/singleton.rb +5 -4
  43. data/lib/mutant/meta.rb +11 -4
  44. data/lib/mutant/meta/example.rb +2 -116
  45. data/lib/mutant/meta/example/dsl.rb +22 -19
  46. data/lib/mutant/meta/example/verification.rb +86 -0
  47. data/lib/mutant/mutator.rb +22 -49
  48. data/lib/mutant/mutator/node.rb +15 -19
  49. data/lib/mutant/mutator/node/and_asgn.rb +1 -1
  50. data/lib/mutant/mutator/node/argument.rb +10 -5
  51. data/lib/mutant/mutator/node/arguments.rb +5 -9
  52. data/lib/mutant/mutator/node/begin.rb +4 -17
  53. data/lib/mutant/mutator/node/block.rb +1 -1
  54. data/lib/mutant/mutator/node/break.rb +1 -1
  55. data/lib/mutant/mutator/node/class.rb +21 -0
  56. data/lib/mutant/mutator/node/conditional_loop.rb +1 -1
  57. data/lib/mutant/mutator/node/define.rb +1 -1
  58. data/lib/mutant/mutator/node/defined.rb +1 -1
  59. data/lib/mutant/mutator/node/dstr.rb +1 -1
  60. data/lib/mutant/mutator/node/dsym.rb +1 -1
  61. data/lib/mutant/mutator/node/generic.rb +3 -3
  62. data/lib/mutant/mutator/node/kwbegin.rb +1 -1
  63. data/lib/mutant/mutator/node/literal.rb +9 -0
  64. data/lib/mutant/mutator/node/literal/boolean.rb +1 -1
  65. data/lib/mutant/mutator/node/literal/fixnum.rb +2 -2
  66. data/lib/mutant/mutator/node/literal/float.rb +4 -6
  67. data/lib/mutant/mutator/node/literal/hash.rb +1 -1
  68. data/lib/mutant/mutator/node/literal/nil.rb +1 -1
  69. data/lib/mutant/mutator/node/literal/range.rb +2 -19
  70. data/lib/mutant/mutator/node/literal/regex.rb +43 -3
  71. data/lib/mutant/mutator/node/literal/string.rb +1 -1
  72. data/lib/mutant/mutator/node/literal/symbol.rb +2 -4
  73. data/lib/mutant/mutator/node/masgn.rb +1 -1
  74. data/lib/mutant/mutator/node/match_current_line.rb +1 -1
  75. data/lib/mutant/mutator/node/mlhs.rb +2 -3
  76. data/lib/mutant/mutator/node/named_value/access.rb +2 -2
  77. data/lib/mutant/mutator/node/named_value/constant_assignment.rb +4 -3
  78. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +4 -4
  79. data/lib/mutant/mutator/node/next.rb +1 -1
  80. data/lib/mutant/mutator/node/nthref.rb +1 -1
  81. data/lib/mutant/mutator/node/or_asgn.rb +1 -1
  82. data/lib/mutant/mutator/node/regexp.rb +44 -0
  83. data/lib/mutant/mutator/node/regopt.rb +31 -0
  84. data/lib/mutant/mutator/node/resbody.rb +1 -1
  85. data/lib/mutant/mutator/node/rescue.rb +1 -3
  86. data/lib/mutant/mutator/node/return.rb +1 -1
  87. data/lib/mutant/mutator/node/send.rb +43 -3
  88. data/lib/mutant/mutator/node/send/attribute_assignment.rb +4 -1
  89. data/lib/mutant/mutator/node/send/conditional.rb +23 -0
  90. data/lib/mutant/mutator/node/send/index.rb +1 -1
  91. data/lib/mutant/mutator/node/splat.rb +1 -1
  92. data/lib/mutant/mutator/node/when.rb +1 -1
  93. data/lib/mutant/mutator/node/yield.rb +1 -1
  94. data/lib/mutant/mutator/util.rb +0 -30
  95. data/lib/mutant/mutator/util/array.rb +4 -16
  96. data/lib/mutant/parallel.rb +1 -1
  97. data/lib/mutant/parallel/worker.rb +1 -1
  98. data/lib/mutant/registry.rb +44 -0
  99. data/lib/mutant/reporter/cli/format.rb +2 -0
  100. data/lib/mutant/reporter/cli/printer.rb +2 -2
  101. data/lib/mutant/reporter/cli/printer/config.rb +0 -1
  102. data/lib/mutant/reporter/cli/printer/env_progress.rb +1 -11
  103. data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +1 -1
  104. data/lib/mutant/reporter/cli/printer/mutation_result.rb +2 -0
  105. data/lib/mutant/reporter/cli/tput.rb +1 -1
  106. data/lib/mutant/reporter/sequence.rb +3 -0
  107. data/lib/mutant/require_highjack.rb +6 -2
  108. data/lib/mutant/result.rb +1 -1
  109. data/lib/mutant/subject.rb +5 -5
  110. data/lib/mutant/subject/method/instance.rb +1 -2
  111. data/lib/mutant/util.rb +18 -0
  112. data/lib/mutant/version.rb +1 -1
  113. data/lib/mutant/zombifier.rb +5 -3
  114. data/meta/and.rb +1 -1
  115. data/meta/and_asgn.rb +1 -1
  116. data/meta/array.rb +2 -2
  117. data/meta/begin.rb +2 -2
  118. data/meta/block.rb +7 -7
  119. data/meta/block_pass.rb +1 -1
  120. data/meta/blockarg.rb +1 -1
  121. data/meta/break.rb +1 -1
  122. data/meta/case.rb +2 -2
  123. data/meta/casgn.rb +11 -2
  124. data/meta/cbase.rb +1 -1
  125. data/meta/class.rb +10 -0
  126. data/meta/const.rb +9 -1
  127. data/meta/csend.rb +8 -0
  128. data/meta/cvar.rb +1 -1
  129. data/meta/cvasgn.rb +1 -1
  130. data/meta/date.rb +4 -4
  131. data/meta/def.rb +14 -14
  132. data/meta/defined.rb +1 -1
  133. data/meta/dstr.rb +1 -1
  134. data/meta/dsym.rb +1 -1
  135. data/meta/ensure.rb +1 -1
  136. data/meta/false.rb +1 -1
  137. data/meta/float.rb +3 -3
  138. data/meta/gvar.rb +1 -1
  139. data/meta/gvasgn.rb +1 -1
  140. data/meta/hash.rb +1 -1
  141. data/meta/if.rb +17 -3
  142. data/meta/int.rb +1 -1
  143. data/meta/ivar.rb +1 -1
  144. data/meta/ivasgn.rb +14 -1
  145. data/meta/kwarg.rb +8 -0
  146. data/meta/kwbegin.rb +1 -1
  147. data/meta/kwoptarg.rb +11 -0
  148. data/meta/lvar.rb +1 -1
  149. data/meta/lvasgn.rb +1 -1
  150. data/meta/masgn.rb +1 -1
  151. data/meta/match_current_line.rb +2 -2
  152. data/meta/next.rb +1 -1
  153. data/meta/nil.rb +1 -1
  154. data/meta/nthref.rb +5 -5
  155. data/meta/op_assgn.rb +1 -1
  156. data/meta/or.rb +1 -1
  157. data/meta/or_asgn.rb +5 -5
  158. data/meta/range.rb +2 -8
  159. data/meta/redo.rb +1 -1
  160. data/meta/regexp.rb +106 -0
  161. data/meta/regexp/regexp_bol_anchor.rb +13 -0
  162. data/meta/regexp/regexp_bos_anchor.rb +26 -0
  163. data/meta/regexp/regexp_root_expression.rb +13 -0
  164. data/meta/regopt.rb +8 -0
  165. data/meta/rescue.rb +49 -4
  166. data/meta/restarg.rb +6 -9
  167. data/meta/return.rb +2 -2
  168. data/meta/self.rb +1 -1
  169. data/meta/send.rb +228 -55
  170. data/meta/str.rb +1 -1
  171. data/meta/super.rb +3 -3
  172. data/meta/{symbol.rb → sym.rb} +1 -1
  173. data/meta/true.rb +1 -1
  174. data/meta/until.rb +1 -1
  175. data/meta/while.rb +2 -2
  176. data/meta/yield.rb +1 -1
  177. data/mutant-rspec.gemspec +2 -2
  178. data/mutant.gemspec +6 -5
  179. data/spec/integration/mutant/isolation/fork_spec.rb +8 -0
  180. data/spec/integration/mutant/rspec_spec.rb +1 -1
  181. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +1 -2
  182. data/spec/integrations.yml +93 -24
  183. data/spec/spec_helper.rb +12 -7
  184. data/spec/support/compress_helper.rb +1 -1
  185. data/spec/support/corpus.rb +115 -50
  186. data/spec/support/fake_actor.rb +5 -5
  187. data/spec/support/file_system.rb +1 -1
  188. data/spec/support/ice_nine_config.rb +3 -3
  189. data/spec/support/ruby_vm.rb +11 -12
  190. data/spec/support/shared_context.rb +22 -13
  191. data/spec/support/test_app.rb +1 -1
  192. data/spec/support/warning.rb +64 -0
  193. data/spec/support/warnings.yml +4 -0
  194. data/spec/support/xspec.rb +177 -0
  195. data/spec/unit/mutant/actor/env_spec.rb +2 -2
  196. data/spec/unit/mutant/actor/sender_spec.rb +1 -1
  197. data/spec/unit/mutant/ast/meta/send_spec.rb +1 -1
  198. data/spec/unit/mutant/ast/named_children_spec.rb +26 -0
  199. data/spec/unit/mutant/ast/regexp/parse_spec.rb +7 -0
  200. data/spec/unit/mutant/ast/regexp/supported_predicate_spec.rb +14 -0
  201. data/spec/unit/mutant/ast/regexp/transformer/lookup_table/table_spec.rb +19 -0
  202. data/spec/unit/mutant/ast/regexp/transformer/lookup_table_spec.rb +33 -0
  203. data/spec/unit/mutant/ast/regexp/transformer_spec.rb +19 -0
  204. data/spec/unit/mutant/ast/regexp_spec.rb +617 -0
  205. data/spec/unit/mutant/cli_spec.rb +7 -45
  206. data/spec/unit/mutant/context_spec.rb +4 -7
  207. data/spec/unit/mutant/env/{boostrap_spec.rb → bootstrap_spec.rb} +2 -2
  208. data/spec/unit/mutant/env_spec.rb +13 -16
  209. data/spec/unit/mutant/expression/namespace/{flat_spec.rb → exact_spec.rb} +0 -0
  210. data/spec/unit/mutant/integration/rspec_spec.rb +2 -2
  211. data/spec/unit/mutant/integration_spec.rb +14 -0
  212. data/spec/unit/mutant/isolation/fork_spec.rb +155 -0
  213. data/spec/unit/mutant/isolation/none_spec.rb +16 -0
  214. data/spec/unit/mutant/loader_spec.rb +1 -1
  215. data/spec/unit/mutant/matcher/methods/instance_spec.rb +2 -4
  216. data/spec/unit/mutant/meta/example/dsl_spec.rb +106 -0
  217. data/spec/unit/mutant/meta/example/verification_spec.rb +120 -0
  218. data/spec/unit/mutant/meta/example_spec.rb +32 -0
  219. data/spec/unit/mutant/mutator/node_spec.rb +37 -4
  220. data/spec/unit/mutant/mutator_spec.rb +21 -0
  221. data/spec/unit/mutant/{runner → parallel}/driver_spec.rb +0 -0
  222. data/spec/unit/mutant/parallel/master_spec.rb +13 -13
  223. data/spec/unit/mutant/registry_spec.rb +47 -0
  224. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +0 -4
  225. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +0 -8
  226. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +0 -2
  227. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +0 -8
  228. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +0 -34
  229. data/spec/unit/mutant/reporter/cli_spec.rb +0 -22
  230. data/spec/unit/mutant/repository/diff_spec.rb +6 -6
  231. data/spec/unit/mutant/require_highjack_spec.rb +38 -14
  232. data/spec/unit/mutant/result/env_spec.rb +1 -4
  233. data/spec/unit/mutant/runner_spec.rb +1 -1
  234. data/spec/unit/mutant/subject/method/instance_spec.rb +1 -1
  235. data/spec/unit/mutant/subject_spec.rb +3 -3
  236. data/spec/unit/mutant/util/one_spec.rb +20 -0
  237. data/spec/unit/mutant/zombifier_spec.rb +18 -18
  238. data/test_app/{Gemfile.rspec3.3 → Gemfile.rspec3.5} +2 -2
  239. metadata +94 -24
  240. data/TODO +0 -21
  241. data/lib/mutant/mutator/node/blockarg.rb +0 -13
  242. data/lib/mutant/mutator/node/restarg.rb +0 -13
  243. data/lib/mutant/mutator/registry.rb +0 -49
  244. data/meta/boolean.rb +0 -13
  245. data/meta/regex.rb +0 -19
  246. data/spec/unit/mutant/isolation_spec.rb +0 -104
  247. data/spec/unit/mutant/mutator/registry_spec.rb +0 -57
@@ -1,4 +1,4 @@
1
- Mutant::Meta::Example.add do
1
+ Mutant::Meta::Example.add :str do
2
2
  source '"foo"'
3
3
 
4
4
  singleton_mutations
@@ -1,17 +1,17 @@
1
- Mutant::Meta::Example.add do
1
+ Mutant::Meta::Example.add :super do
2
2
  source 'super'
3
3
 
4
4
  singleton_mutations
5
5
  mutation 'super()'
6
6
  end
7
7
 
8
- Mutant::Meta::Example.add do
8
+ Mutant::Meta::Example.add :super do
9
9
  source 'super()'
10
10
 
11
11
  singleton_mutations
12
12
  end
13
13
 
14
- Mutant::Meta::Example.add do
14
+ Mutant::Meta::Example.add :super do
15
15
  source 'super(foo, bar)'
16
16
 
17
17
  singleton_mutations
@@ -1,4 +1,4 @@
1
- Mutant::Meta::Example.add do
1
+ Mutant::Meta::Example.add :sym do
2
2
  source ':foo'
3
3
 
4
4
  singleton_mutations
@@ -1,4 +1,4 @@
1
- Mutant::Meta::Example.add do
1
+ Mutant::Meta::Example.add :true do
2
2
  source 'true'
3
3
 
4
4
  mutation 'nil'
@@ -1,4 +1,4 @@
1
- Mutant::Meta::Example.add do
1
+ Mutant::Meta::Example.add :until do
2
2
  source 'until true; foo; bar; end'
3
3
 
4
4
  singleton_mutations
@@ -1,4 +1,4 @@
1
- Mutant::Meta::Example.add do
1
+ Mutant::Meta::Example.add :while do
2
2
  source 'while true; foo; bar; end'
3
3
 
4
4
  singleton_mutations
@@ -14,7 +14,7 @@ Mutant::Meta::Example.add do
14
14
  mutation 'while true; raise; end'
15
15
  end
16
16
 
17
- Mutant::Meta::Example.add do
17
+ Mutant::Meta::Example.add :while do
18
18
  source 'while true; end'
19
19
 
20
20
  singleton_mutations
@@ -1,4 +1,4 @@
1
- Mutant::Meta::Example.add do
1
+ Mutant::Meta::Example.add :yield do
2
2
  source 'yield true'
3
3
 
4
4
  singleton_mutations
@@ -13,10 +13,10 @@ Gem::Specification.new do |gem|
13
13
  gem.require_paths = %w[lib]
14
14
  gem.files = `git ls-files -- lib/mutant/integration/rspec.rb`.split("\n")
15
15
  gem.test_files = `git ls-files -- spec/{integration,unit}/mutant/rspec_spec.rb}`.split("\n")
16
- gem.extra_rdoc_files = %w[TODO LICENSE]
16
+ gem.extra_rdoc_files = %w[LICENSE]
17
17
 
18
18
  gem.add_runtime_dependency('mutant', "~> #{gem.version}")
19
- gem.add_runtime_dependency('rspec-core', '>= 3.3.0', '< 3.5.0')
19
+ gem.add_runtime_dependency('rspec-core', '>= 3.4.0', '< 3.6.0')
20
20
 
21
21
  gem.add_development_dependency('bundler', '~> 1.3', '>= 1.3.5')
22
22
  end
@@ -10,18 +10,18 @@ Gem::Specification.new do |gem|
10
10
  gem.homepage = 'https://github.com/mbj/mutant'
11
11
  gem.license = 'MIT'
12
12
 
13
- gem.require_paths = %w[lib]
13
+ gem.require_paths = %w[lib]
14
14
 
15
- mutant_integration_files = `git ls-files -- lib/mutant/integration/*.rb`.split("\n")
15
+ mutant_integration_files = `git ls-files -- lib/mutant/integration/*.rb`.split("\n")
16
16
 
17
17
  gem.files = `git ls-files`.split("\n") - mutant_integration_files
18
18
  gem.test_files = `git ls-files -- spec/{unit,integration}`.split("\n")
19
- gem.extra_rdoc_files = %w[TODO LICENSE]
19
+ gem.extra_rdoc_files = %w[LICENSE]
20
20
  gem.executables = %w[mutant]
21
21
 
22
22
  gem.required_ruby_version = '>= 2.1'
23
23
 
24
- gem.add_runtime_dependency('parser', '~> 2.3.0')
24
+ gem.add_runtime_dependency('parser', '~> 2.3.0', '>= 2.3.0.2')
25
25
  gem.add_runtime_dependency('ast', '~> 2.2')
26
26
  gem.add_runtime_dependency('diff-lcs', '~> 1.2')
27
27
  gem.add_runtime_dependency('parallel', '~> 1.3')
@@ -35,8 +35,9 @@ Gem::Specification.new do |gem|
35
35
  gem.add_runtime_dependency('equalizer', '~> 0.0.9')
36
36
  gem.add_runtime_dependency('anima', '~> 0.3.0')
37
37
  gem.add_runtime_dependency('concord', '~> 0.1.5')
38
+ gem.add_runtime_dependency('regexp_parser', '~> 0.3.6')
38
39
 
39
- gem.add_development_dependency('devtools', '~> 0.1.3')
40
+ gem.add_development_dependency('devtools', '~> 0.1.4')
40
41
  gem.add_development_dependency('bundler', '~> 1.10')
41
42
  gem.add_development_dependency('ffi', '~> 1.9.6')
42
43
  end
@@ -0,0 +1,8 @@
1
+ RSpec.describe Mutant::Isolation::Fork, mutant: false do
2
+ specify do
3
+ a = 1
4
+ expect do
5
+ Mutant::Config::DEFAULT.isolation.call { a = 2 }
6
+ end.to_not change { a }
7
+ end
8
+ end
@@ -2,7 +2,7 @@ RSpec.describe 'rspec integration', mutant: false do
2
2
 
3
3
  let(:base_cmd) { 'bundle exec mutant -I lib --require test_app --use rspec' }
4
4
 
5
- %w[3.3 3.4].each do |version|
5
+ %w[3.4 3.5].each do |version|
6
6
  context "RSpec #{version}" do
7
7
  let(:gemfile) { "Gemfile.rspec#{version}" }
8
8
 
@@ -1,8 +1,7 @@
1
1
  RSpec.describe 'AST type coverage', mutant: false do
2
-
3
2
  specify 'mutant should not crash for any node parser can generate' do
4
3
  Mutant::AST::Types::ALL.each do |type|
5
- Mutant::Mutator::REGISTRY.lookup(s(type))
4
+ Mutant::Mutator::REGISTRY.lookup(type)
6
5
  end
7
6
  end
8
7
  end
@@ -4,37 +4,106 @@
4
4
  repo_uri: 'https://github.com/ruby/rubyspec.git'
5
5
  mutation_coverage: false
6
6
  mutation_generation: true
7
- expect_coverage: 0 # not run
8
- exclude:
9
- # Binary encoded source subjected to limitations see README of unparser
10
- - core/array/pack/{b,h,u}_spec.rb
11
- - language/regexp/escapes_spec.rb
12
- - core/array/pack/shared/float.rb
13
- - core/array/pack/shared/integer.rb
14
- - core/array/pack/{c,m,w}_spec.rb
15
- - core/regexp/shared/quote.rb
16
- - core/encoding/compatible_spec.rb
17
- - core/io/readpartial_spec.rb
18
- - core/env/element_reference_spec.rb
19
- - core/dir/pwd_spec.rb
20
- - core/string/casecmp_spec.rb
21
- - core/string/unpack/{b,c,h,m,u,w}_spec.rb
22
- - core/string/unpack/b_spec.rb
23
- - core/string/unpack/shared/float.rb
24
- - core/string/unpack/shared/integer.rb
25
- - core/symbol/casecmp_spec.rb
26
- - optional/capi/integer_spec.rb
7
+ expected_errors:
8
+ "#<Parser::SyntaxError: invalid multibyte escape: /\xAA/>":
9
+ - language/regexp/escapes_spec.rb
10
+ "#<Parser::SyntaxError: literal contains escape sequences incompatible with UTF-8>":
11
+ - core/array/fixtures/encoded_strings.rb
12
+ - core/array/pack/shared/string.rb
13
+ - core/array/pack/shared/unicode.rb
14
+ - core/encoding/converter/convert_spec.rb
15
+ - core/encoding/converter/last_error_spec.rb
16
+ - core/encoding/converter/primitive_convert_spec.rb
17
+ - core/encoding/converter/primitive_errinfo_spec.rb
18
+ - core/encoding/converter/putback_spec.rb
19
+ - core/encoding/fixtures/classes.rb
20
+ - core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
21
+ - core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb
22
+ - core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
23
+ - core/encoding/replicate_spec.rb
24
+ - core/file/expand_path_spec.rb
25
+ - core/io/gets_spec.rb
26
+ - core/io/read_spec.rb
27
+ - core/io/shared/gets_ascii.rb
28
+ - core/io/write_spec.rb
29
+ - core/marshal/dump_spec.rb
30
+ - core/marshal/fixtures/marshal_data.rb
31
+ - core/marshal/shared/load.rb
32
+ - core/random/bytes_spec.rb
33
+ - core/regexp/match_spec.rb
34
+ - core/regexp/shared/new_ascii.rb
35
+ - core/string/byteslice_spec.rb
36
+ - core/string/codepoints_spec.rb
37
+ - core/string/comparison_spec.rb
38
+ - core/string/count_spec.rb
39
+ - core/string/delete_spec.rb
40
+ - core/string/element_set_spec.rb
41
+ - core/string/encode_spec.rb
42
+ - core/string/encoding_spec.rb
43
+ - core/string/fixtures/iso-8859-9-encoding.rb
44
+ - core/string/getbyte_spec.rb
45
+ - core/string/gsub_spec.rb
46
+ - core/string/new_spec.rb
47
+ - core/string/scrub_spec.rb
48
+ - core/string/shared/chars.rb
49
+ - core/string/shared/codepoints.rb
50
+ - core/string/shared/each_codepoint_without_block.rb
51
+ - core/string/shared/encode.rb
52
+ - core/string/shared/eql.rb
53
+ - core/string/shared/succ.rb
54
+ - core/string/slice_spec.rb
55
+ - core/string/squeeze_spec.rb
56
+ - core/string/unicode_normalize_spec.rb
57
+ - core/string/valid_encoding_spec.rb
58
+ - core/symbol/casecmp_spec.rb
59
+ - core/time/_dump_spec.rb
60
+ - core/time/_load_spec.rb
61
+ - language/regexp/encoding_spec.rb
62
+ - language/string_spec.rb
63
+ - library/digest/md5/shared/constants.rb
64
+ - library/digest/md5/shared/sample.rb
65
+ - library/digest/sha1/shared/constants.rb
66
+ - library/digest/sha256/shared/constants.rb
67
+ - library/digest/sha384/shared/constants.rb
68
+ - library/digest/sha512/shared/constants.rb
69
+ - library/openssl/shared/constants.rb
70
+ - library/socket/basicsocket/recv_spec.rb
71
+ - library/socket/socket/gethostbyname_spec.rb
72
+ - library/stringscanner/getch_spec.rb
73
+ - library/stringscanner/shared/get_byte.rb
74
+ - library/zlib/deflate/deflate_spec.rb
75
+ - library/zlib/deflate/set_dictionary_spec.rb
76
+ - library/zlib/gzipreader/each_byte_spec.rb
77
+ - library/zlib/gzipreader/eof_spec.rb
78
+ - library/zlib/gzipreader/getc_spec.rb
79
+ - library/zlib/gzipreader/pos_spec.rb
80
+ - library/zlib/gzipreader/read_spec.rb
81
+ - library/zlib/gzipreader/rewind_spec.rb
82
+ - library/zlib/inflate/append_spec.rb
83
+ - library/zlib/inflate/inflate_spec.rb
84
+ - library/zlib/inflate/set_dictionary_spec.rb
85
+ - library/zlib/zstream/flush_next_out_spec.rb
86
+ - optional/capi/encoding_spec.rb
87
+ - optional/capi/string_spec.rb
88
+ '#<RegexpError: invalid multibyte escape: /\xAA/>':
89
+ - language/regexp/escapes_spec.rb
90
+ "#<Regexp::Scanner::PrematureEndError: Premature end of pattern at #{str}>":
91
+ - language/regexp/interpolation_spec.rb
92
+ - name: regexp_parser
93
+ namespace: Regexp
94
+ repo_uri: 'https://github.com/ammar/regexp_parser.git'
95
+ mutation_coverage: false
96
+ mutation_generation: true
97
+ expected_errors: {}
27
98
  - name: auom
28
99
  namespace: AUOM
29
100
  repo_uri: 'https://github.com/mbj/auom.git'
30
101
  mutation_coverage: true
31
102
  mutation_generation: true
32
- exclude: []
33
- expect_coverage: 1
103
+ expected_errors: {}
34
104
  - name: axiom
35
105
  namespace: Axiom
36
106
  repo_uri: 'https://github.com/dkubb/axiom.git'
37
107
  mutation_coverage: false
38
108
  mutation_generation: true
39
- exclude: []
40
- expect_coverage: 1
109
+ expected_errors: {}
@@ -8,16 +8,16 @@ if ENV['COVERAGE'] == 'true'
8
8
  add_filter 'spec'
9
9
  add_filter 'vendor'
10
10
  add_filter 'test_app'
11
- add_filter 'lib/mutant/meta/*'
12
- add_filter 'lib/mutant/zombifier'
13
- add_filter 'lib/mutant/zombifier/*'
14
- # Trace points shadow each other under 2.0 (fixed in 2.1)
15
- add_filter 'lib/mutant/line_trace.rb' if RUBY_VERSION.eql?('2.0.0')
11
+ add_filter 'lib/mutant.rb' # simplecov bug not seeing default block is executed
16
12
 
17
13
  minimum_coverage 100
18
14
  end
19
15
  end
20
16
 
17
+ # Require warning support first in order to catch any warnings emitted during boot
18
+ require_relative './support/warning'
19
+ $stderr = MutantSpec::Warning::EXTRACTOR
20
+
21
21
  require 'tempfile'
22
22
  require 'concord'
23
23
  require 'anima'
@@ -48,13 +48,13 @@ module ParserHelper
48
48
  def parse_expression(string)
49
49
  Mutant::Config::DEFAULT.expression_parser.(string)
50
50
  end
51
- end
51
+ end # ParserHelper
52
52
 
53
53
  module MessageHelper
54
54
  def message(*arguments)
55
55
  Mutant::Actor::Message.new(*arguments)
56
56
  end
57
- end
57
+ end # MessageHelper
58
58
 
59
59
  RSpec.configure do |config|
60
60
  config.extend(SharedContext)
@@ -62,4 +62,9 @@ RSpec.configure do |config|
62
62
  config.include(MessageHelper)
63
63
  config.include(ParserHelper)
64
64
  config.include(Mutant::AST::Sexp)
65
+
66
+ config.after(:suite) do
67
+ $stderr = STDERR
68
+ MutantSpec::Warning.assert_no_warnings
69
+ end
65
70
  end
@@ -6,4 +6,4 @@ module CompressHelper
6
6
  whitespaces = match[1].to_s.length
7
7
  lines.map { |line| line[whitespaces..-1] }.join
8
8
  end
9
- end
9
+ end # CompressHelper
@@ -24,9 +24,15 @@ module MutantSpec
24
24
  # rubocop:disable ClassLength
25
25
  class Project
26
26
  MUTEX = Mutex.new
27
+
28
+ MUTATION_GENERATION_MESSAGE = 'Total Mutations/Time/Parse-Errors: %s/%0.2fs - %0.2f/s'.freeze
29
+ START_MESSAGE = 'Starting - %s'.freeze
30
+ FINISH_MESSAGE = 'Mutations - %4i - %s'.freeze
31
+
32
+ DEFAULT_MUTATION_COUNT = 0
33
+
27
34
  include Adamantium, Anima.new(
28
- :exclude,
29
- :expect_coverage,
35
+ :expected_errors,
30
36
  :mutation_coverage,
31
37
  :mutation_generation,
32
38
  :name,
@@ -51,7 +57,6 @@ module MutantSpec
51
57
  --use rspec
52
58
  --include lib
53
59
  --require #{name}
54
- --expected-coverage #{expect_coverage}
55
60
  #{namespace}*
56
61
  ]
57
62
  )
@@ -75,28 +80,12 @@ module MutantSpec
75
80
  start: method(:start),
76
81
  in_processes: parallel_processes
77
82
  }
78
- total = Parallel.map(effective_ruby_paths, options) do |path|
79
- count = 0
80
- node =
81
- begin
82
- Parser::CurrentRuby.parse(path.read)
83
- rescue EncodingError, ArgumentError
84
- nil # Make rubocop happy
85
- end
86
- if node
87
- Mutant::Mutator::Node.each(node) do
88
- count += 1
89
- end
90
- end
91
- count
92
- end.inject(0, :+)
83
+
84
+ total = Parallel.map(effective_ruby_paths, options, &method(:count_mutations_and_check_errors))
85
+ .inject(DEFAULT_MUTATION_COUNT, :+)
86
+
93
87
  took = Time.now - start
94
- puts format(
95
- 'Total Mutations/Time/Parse-Errors: %s/%0.2fs - %0.2f/s',
96
- total,
97
- took,
98
- total / took
99
- )
88
+ puts MUTATION_GENERATION_MESSAGE % [total, took, total / took]
100
89
  self
101
90
  end
102
91
 
@@ -124,6 +113,40 @@ module MutantSpec
124
113
 
125
114
  private
126
115
 
116
+ # Count mutations and check error results against whitelist
117
+ #
118
+ # @param path [Pathname] path responsible for exception
119
+ #
120
+ # @return [Fixnum] mutations generated
121
+ def count_mutations_and_check_errors(path)
122
+ relative_path = path.relative_path_from(repo_path)
123
+
124
+ count = count_mutations(path)
125
+
126
+ expected_errors.assert_success(relative_path)
127
+
128
+ count
129
+ rescue Exception => exception # rubocop:disable Lint/RescueException
130
+ expected_errors.assert_error(relative_path, exception)
131
+
132
+ DEFAULT_MUTATION_COUNT
133
+ end
134
+
135
+ # Count mutations generated for provided source file
136
+ #
137
+ # @param path [Pathname] path to a source file
138
+ #
139
+ # @raise [Exception] any error specified by integrations.yml
140
+ #
141
+ # @return [Fixnum] number of mutations generated
142
+ def count_mutations(path)
143
+ node = Parser::CurrentRuby.parse(path.read)
144
+
145
+ return DEFAULT_MUTATION_COUNT unless node
146
+
147
+ Mutant::Mutator.mutate(node).length
148
+ end
149
+
127
150
  # Install mutant
128
151
  #
129
152
  # @return [undefined]
@@ -144,19 +167,10 @@ module MutantSpec
144
167
  #
145
168
  # @return [Array<Pathname>]
146
169
  def effective_ruby_paths
147
- paths = Pathname
170
+ Pathname
148
171
  .glob(repo_path.join(RUBY_GLOB_PATTERN))
149
172
  .sort_by(&:size)
150
173
  .reverse
151
-
152
- paths - excluded_paths
153
- end
154
-
155
- # The excluded file paths
156
- #
157
- # @return [Array<Pathname>]
158
- def excluded_paths
159
- Pathname.glob(repo_path.join(EXCLUDE_GLOB_FORMAT % exclude.join(',')))
160
174
  end
161
175
 
162
176
  # Number of parallel processes to use
@@ -193,7 +207,7 @@ module MutantSpec
193
207
  #
194
208
  def start(path, _index)
195
209
  MUTEX.synchronize do
196
- puts format('Starting - %s', path)
210
+ puts START_MESSAGE % path
197
211
  end
198
212
  end
199
213
 
@@ -207,15 +221,18 @@ module MutantSpec
207
221
  #
208
222
  def finish(path, _index, count)
209
223
  MUTEX.synchronize do
210
- puts format('Mutations - %4i - %s', count, path)
224
+ puts FINISH_MESSAGE % [count, path]
211
225
  end
212
226
  end
213
227
 
214
228
  # Helper method to execute system commands
215
229
  #
216
230
  # @param [Array<String>] arguments
231
+ #
232
+ # rubocop:disable GuardClause - guard clause without else does not make sense
217
233
  def system(arguments)
218
234
  return if Kernel.system(*arguments)
235
+
219
236
  if block_given?
220
237
  yield
221
238
  else
@@ -223,7 +240,58 @@ module MutantSpec
223
240
  end
224
241
  end
225
242
 
226
- # rubocop:disable ClosingParenthesisIndentation
243
+ # Mapping of files which we expect to cause errors during mutation generation
244
+ class ErrorWhitelist
245
+ class UnnecessaryExpectation < StandardError
246
+ MESSAGE = 'Expected to encounter %s while mutating "%s"'.freeze
247
+
248
+ def initialize(*error_info)
249
+ super(MESSAGE % error_info)
250
+ end
251
+ end # UnnecessaryExpectation
252
+
253
+ include Concord.new(:map), Adamantium
254
+
255
+ # Assert that we expect to encounter the provided exception for this path
256
+ #
257
+ # @param path [Pathname]
258
+ # @param exception [Exception]
259
+ #
260
+ # @raise provided exception if we are not expecting this error
261
+ #
262
+ # This method is reraising exceptions but rubocop can't tell
263
+ # rubocop:disable Style/SignalException
264
+ #
265
+ # @return [undefined]
266
+ def assert_error(path, exception)
267
+ original_error = exception.cause || exception
268
+
269
+ raise exception unless map.fetch(original_error.inspect, []).include?(path)
270
+ end
271
+
272
+ # Assert that we expect to not encounter an error for the specified path
273
+ #
274
+ # @param path [Pathname]
275
+ #
276
+ # @raise [UnnecessaryExpectation] if we are expecting an exception for this path
277
+ #
278
+ # @return [undefined]
279
+ def assert_success(path)
280
+ map.each do |error, paths|
281
+ fail UnnecessaryExpectation.new(error, path) if paths.include?(path)
282
+ end
283
+ end
284
+
285
+ # Return representation as hash
286
+ #
287
+ # @note this method is necessary for morpher loader to be invertible
288
+ #
289
+ # @return [Hash{Pathname => String}]
290
+ def to_h
291
+ map
292
+ end
293
+ end # ErrorWhitelist
294
+
227
295
  LOADER = Morpher.build do
228
296
  s(:block,
229
297
  s(:guard, s(:primitive, Array)),
@@ -234,23 +302,20 @@ module MutantSpec
234
302
  s(:key_symbolize, :repo_uri, s(:guard, s(:primitive, String))),
235
303
  s(:key_symbolize, :name, s(:guard, s(:primitive, String))),
236
304
  s(:key_symbolize, :namespace, s(:guard, s(:primitive, String))),
237
- s(:key_symbolize, :expect_coverage, s(:guard, s(:primitive, Fixnum))),
238
305
  s(:key_symbolize, :mutation_coverage,
239
306
  s(:guard, s(:or, s(:primitive, TrueClass), s(:primitive, FalseClass)))),
240
307
  s(:key_symbolize, :mutation_generation,
241
308
  s(:guard, s(:or, s(:primitive, TrueClass), s(:primitive, FalseClass)))),
242
- s(:key_symbolize, :exclude, s(:map, s(:guard, s(:primitive, String))))
243
- ),
244
- s(:load_attribute_hash,
245
- # NOTE: The domain param has no DSL currently!
246
- Morpher::Evaluator::Transformer::Domain::Param.new(
247
- Project,
248
- %i[repo_uri name exclude mutation_coverage mutation_generation]
249
- )
250
- )
251
- )
252
- )
253
- )
309
+ s(:key_symbolize, :expected_errors,
310
+ s(:block,
311
+ s(:guard, s(:primitive, Hash)),
312
+ s(:custom,
313
+ [
314
+ ->(hash) { hash.map { |key, values| [key, values.map(&Pathname.method(:new))] }.to_h },
315
+ ->(hash) { hash.map { |key, values| [key, values.map(&:to_s)] }.to_h }
316
+ ]),
317
+ s(:load_attribute_hash, s(:param, ErrorWhitelist))))),
318
+ s(:anima_load, Project))))
254
319
  end
255
320
 
256
321
  ALL = LOADER.call(YAML.load_file(ROOT.join('spec', 'integrations.yml')))