mutant 0.8.10 → 0.8.11

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 37c56c026986c92dd3afb4306adaea0d80b130f2
4
- data.tar.gz: 0513911185fbe4a6967146e75ebec39e77537875
3
+ metadata.gz: 2b6726d9cc7696a22bc3de412e2aec93c6098212
4
+ data.tar.gz: 1c68cebbe3bd9faf603b604621a5af7cfb6402d1
5
5
  SHA512:
6
- metadata.gz: 838d0e823d5666c5b615aa4c3f94af69c90034873cf07bc113524dfad2b265cdda16b350d189e410ff0229657fc425ddb0d34d442f19091a11151f2757f10b06
7
- data.tar.gz: 60493346edfd51f98857e94c286de02c6293933ad379331f4513f18ec82b35f5c93ae5b6f14f8a196ac69d071004ba8529bd0ef902acf8ea8a32eb471b41f4b3
6
+ metadata.gz: c9a1dd4866a3264565adccb269d212b0609bdd806fc94e9f42b3366deb951967c48d0595f6044158a1719155557af450fb949821eadb7699432aa73262e7e1cf
7
+ data.tar.gz: 2cb50707ab5a178bb9eb8d1288251e978db32fbd92efddc1a4417e772df2ec4f2cefa86fceaeeb2dc5a7b7a654afe9c9182d548183a733497d17fdc9459515ea
@@ -1,10 +1,7 @@
1
1
  AllCops:
2
- Include:
3
- - 'Gemfile'
4
2
  Exclude:
5
- - 'Gemfile.devtools'
6
3
  - 'vendor/**/*'
7
4
  - 'tmp/**/*'
8
5
  - 'test_app/**/*'
9
- - 'benchmarks/**/*'
10
6
  - 'bin/mutant'
7
+ TargetRubyVersion: 2.2
@@ -1,3 +1,11 @@
1
+ # v0.8.11 2016-01-xx
2
+
3
+ * Add support for rspec-3.5
4
+ * Remove misleading --debug option
5
+ * Remove misleading --expect-coverage option
6
+ * Add basic support for regexp mutations (machinery and simple anchor mutations)
7
+ * Add support for mutating csend (duck tape operator) into regular sends
8
+
1
9
  # v0.8.10 2016-01-24
2
10
 
3
11
  * Add support for parser 2.3 (via unparser 0.2.5)
data/README.md CHANGED
@@ -7,10 +7,11 @@ mutant
7
7
  [![Inline docs](http://inch-ci.org/github/mbj/mutant.png)](http://inch-ci.org/github/mbj/mutant)
8
8
  [![Gem Version](https://img.shields.io/gem/v/mutant.svg)](https://rubygems.org/gems/mutant)
9
9
  [![Flattr](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/thing/1823010/mbjmutant-on-GitHub)
10
+ [![Slack Status](https://mutation-testing-slack.herokuapp.com/badge.svg)](https://mutation-testing.slack.com/messages/mutant)
10
11
 
11
12
  Mutant is a mutation testing tool for Ruby.
12
13
 
13
- The idea is that if code can be changed and your tests do not notice, either that code isn't being covered
14
+ The idea is that if code can be changed and your tests do not notice, then either that code isn't being covered
14
15
  or it does not have a speced side effect.
15
16
 
16
17
  Mutant supports ruby >= 2.1, while support for JRuby is planned.
@@ -25,7 +26,7 @@ Installation
25
26
  ------------
26
27
 
27
28
  As mutant right now only supports rspec, install the gem `mutant-rspec` via your preferred method.
28
- It'll pull the `mutant` gem (in correct version), that contains the main engine.
29
+ It'll pull the `mutant` gem (in the correct version), that contains the main engine.
29
30
 
30
31
  ```ruby
31
32
  gem install mutant-rspec
@@ -48,29 +49,24 @@ mutant --include lib --require virtus --use rspec Virtus::Attribute.build
48
49
  mutant --include lib --require virtus --use rspec Virtus::Attribute#type
49
50
  ```
50
51
 
51
- Configuration
52
- -------------
52
+ Rails
53
+ -------
53
54
 
54
- Occasionally mutant will produce a mutation with an infinite runtime. When this happens
55
- mutant will look like it is running indefinitely without killing a remaining mutation. To
56
- avoid mutations like this, consider adding a timeout around your tests. For example, in
57
- RSpec you can add the following to your `spec_helper`:
55
+ To mutation test Rails models with rspec, comment out ```require 'rspec/autorun'``` from your spec_helper.rb file. Having done so you should be able to use commands like the following:
58
56
 
59
- ```ruby
60
- config.around(:each) do |example|
61
- Timeout.timeout(5_000, &example)
62
- end
57
+ ```sh
58
+ RAILS_ENV=test bundle exec mutant -r ./config/environment --use rspec User
63
59
  ```
64
60
 
65
- which will fail specs which run for longer than 5 seconds.
61
+ Passing in RSpec Options
62
+ ------------------------
66
63
 
67
- Rails
68
- -------
64
+ **NOTE: Experimental**
69
65
 
70
- To mutation test Rails models with rspec comment out ```require 'rspec/autorun'``` from your spec_helper.rb file. Having done so you should be able to use commands like the following:
66
+ You can control some aspects of RSpec using the `SPEC_OPTS` environment variable as usual. If you want mutant to only pay attention to specs in a certain directory, you can run
71
67
 
72
68
  ```sh
73
- RAILS_ENV=test bundle exec mutant -r ./config/environment --use rspec User
69
+ SPEC_OPTS="--pattern spec/subdir_only/**/*_spec.rb" mutant --use rspec SomeClass
74
70
  ```
75
71
 
76
72
  Limitations
@@ -121,8 +117,8 @@ Mutant cannot emit mutations for...
121
117
  end
122
118
  ```
123
119
 
124
- Mutation-Operators:
125
- -------------------
120
+ Mutation-Operators
121
+ ------------------
126
122
 
127
123
  Mutant supports a wide range of mutation operators. An exhaustive list can be found in the [mutant-meta](https://github.com/mbj/mutant/tree/master/meta).
128
124
  The `mutant-meta` is arranged to the AST-Node-Types of parser. Refer to parsers [AST documentation](https://github.com/whitequark/parser/blob/master/doc/AST_FORMAT.md) in doubt.
@@ -220,34 +216,66 @@ Mutation output is grouped by selection groups. Each group contains three sectio
220
216
  -----------------------
221
217
  ```
222
218
 
223
- Presentations
224
- -------------
219
+ Concurrency
220
+ -----------
225
221
 
226
- There are some presentations about mutant in the wild:
222
+ By default, mutant will test mutations in parallel by running up to one process for each core on your system. You can control the number of processes created using the `--jobs` argument.
227
223
 
228
- * [RailsConf 2014](http://railsconf.com/) / http://confreaks.com/videos/3333-railsconf-mutation-testing-with-mutant
229
- * [Wrocloverb 2014](http://wrocloverb.com/) / https://www.youtube.com/watch?v=rz-lFKEioLk
230
- * [eurucamp 2013](http://2013.eurucamp.org/) / FrOSCon-2013 http://slid.es/markusschirp/mutation-testing
231
- * [Cologne.rb](http://www.colognerb.de/topics/mutation-testing-mit-mutant) / https://github.com/DonSchado/colognerb-on-mutant/blob/master/mutation_testing_slides.pdf
224
+ Mutant forks a new process for each mutation to be tested to prevent side affects in your specs and the lack of thread safety in rspec from impacting the results.
232
225
 
233
- Blog posts
234
- ----------
226
+ If the code under test relies on a database, you may experience problems when running mutant because of conflicting data in the database. For example, if you have a test like this:
227
+ ```
228
+ m = MyModel.create!(...)
229
+ expect(MyModel.first.name).to eql(m.name)
230
+ ```
231
+ It might fail if some other test wrote a record to the MyModel table at the same time as this test was executed. (It would find the MyModel record created by the other test.) Most of these issues can be fixed by writing more specific tests. Here is a concurrent safe version of the same test:
232
+ ```
233
+ m = MyModel.create!(...)
234
+ expect(MyModel.find_by_id(m.id).name).to eql(m.name)
235
+ ```
236
+ You may also try wrapping your test runs in transactions.
235
237
 
236
- Sorted by recency:
238
+ Note that some databases, SQLite in particular, are not designed for concurrent access and will fail if used in this manner. If you are using SQLite, you should set the `--jobs` to 1.
237
239
 
238
- * [How to write better code using mutation testing (November 2015)][blockscore]
239
- * [How good are your Ruby tests? Testing your tests with mutant (June 2015)][arkency1]
240
- * [Mutation testing and continuous integration (May 2015)][arkency2]
241
- * [Why I want to introduce mutation testing to the `rails_event_store` gem (April 2015)][arkency3]
242
- * [Mutation testing with mutant (April 2014)][sitepoint]
243
- * [Mutation testing with mutant (January 2013)][solnic]
240
+ Neutral (noop) Tests
241
+ --------------------
244
242
 
245
- [blockscore]: https://blog.blockscore.com/how-to-write-better-code-using-mutation-testing/
246
- [sitepoint]: http://www.sitepoint.com/mutation-testing-mutant/
247
- [arkency1]: http://blog.arkency.com/2015/06/how-good-are-your-ruby-tests-testing-your-tests-with-mutant/
248
- [arkency2]: http://blog.arkency.com/2015/05/mutation-testing-and-continuous-integration/
249
- [arkency3]: http://blog.arkency.com/2015/04/why-i-want-to-introduce-mutation-testing-to-the-rails-event-store-gem/
250
- [solnic]: http://solnic.eu/2013/01/23/mutation-testing-with-mutant.html
243
+ Mutant will also test the original, unmutated, version your code. This ensures that mutant is able to properly setup and run your tests.
244
+ If an error occurs while mutant/rspec is running testing the original code, you will receive an error like the following:
245
+ ```
246
+ --- Neutral failure ---
247
+ Original code was inserted unmutated. And the test did NOT PASS.
248
+ Your tests do not pass initially or you found a bug in mutant / unparser.
249
+ ...
250
+ Test Output:
251
+ marshal data too short
252
+ ```
253
+ Currently, troubleshooting these errors requires using a debugger and/or modyifying mutant to print out the error. You will want to rescue and inspect exceptions raised in this method: lib/mutant/integration/rspec.rb:call
254
+
255
+ Only Mutating Changed Code
256
+ --------------------------
257
+
258
+ Running mutant for the first time on an existing codebase can be a rather disheartening experience due to the large number of alive mutations found! Mutant has a setting that can help. Using the `--since` argument, mutant will only mutate code that has been modified. This allows you to introduce mutant into an existing code base without drowning in errors. Example usage that will mutate all code changed between master and the current branch:
259
+ ```
260
+ mutant --include lib --require virtus --since master --use rspec Virtus::Attribute#type
261
+ ```
262
+
263
+ Known Problems
264
+ ==============
265
+
266
+ Mutations with Infinite Runtimes
267
+ ---------------------------------
268
+
269
+ Occasionally mutant will produce a mutation with an infinite runtime. When this happens
270
+ mutant will look like it is running indefinitely without killing a remaining mutation. To
271
+ avoid mutations like this, consider adding a timeout around your tests. For example, in
272
+ RSpec you can add the following to your `spec_helper`:
273
+ ```ruby
274
+ config.around(:each) do |example|
275
+ Timeout.timeout(5, &example)
276
+ end
277
+ ```
278
+ which will fail specs which run for longer than 5 seconds.
251
279
 
252
280
  The Crash / Stuck Problem (MRI)
253
281
  -------------------------------
@@ -277,6 +305,17 @@ References:
277
305
  * [Upstream bug redmine](https://bugs.ruby-lang.org/issues/10460)
278
306
  * [Upstream bug github](https://github.com/ruby/ruby/pull/822)
279
307
 
308
+ Presentations
309
+ -------------
310
+
311
+ There are some presentations about mutant in the wild:
312
+
313
+ * [RailsConf 2014](http://railsconf.com/) / http://confreaks.com/videos/3333-railsconf-mutation-testing-with-mutant
314
+ * [Wrocloverb 2014](http://wrocloverb.com/) / https://www.youtube.com/watch?v=rz-lFKEioLk
315
+ * [eurucamp 2013](http://2013.eurucamp.org/) / FrOSCon-2013 http://slid.es/markusschirp/mutation-testing
316
+ * [Cologne.rb](http://www.colognerb.de/topics/mutation-testing-mit-mutant) / https://github.com/DonSchado/colognerb-on-mutant/blob/master/mutation_testing_slides.pdf
317
+
318
+
280
319
  Planning a presentation?
281
320
  ------------------------
282
321
 
@@ -296,6 +335,25 @@ assumptions based on the absence of docs, use the tool authors brain to fill the
296
335
 
297
336
  Hint, same applies to papers.
298
337
 
338
+ Blog posts
339
+ ----------
340
+
341
+ Sorted by recency:
342
+
343
+ * [How to write better code using mutation testing (November 2015)][blockscore]
344
+ * [How good are your Ruby tests? Testing your tests with mutant (June 2015)][arkency1]
345
+ * [Mutation testing and continuous integration (May 2015)][arkency2]
346
+ * [Why I want to introduce mutation testing to the `rails_event_store` gem (April 2015)][arkency3]
347
+ * [Mutation testing with mutant (April 2014)][sitepoint]
348
+ * [Mutation testing with mutant (January 2013)][solnic]
349
+
350
+ [blockscore]: https://blog.blockscore.com/how-to-write-better-code-using-mutation-testing/
351
+ [sitepoint]: http://www.sitepoint.com/mutation-testing-mutant/
352
+ [arkency1]: http://blog.arkency.com/2015/06/how-good-are-your-ruby-tests-testing-your-tests-with-mutant/
353
+ [arkency2]: http://blog.arkency.com/2015/05/mutation-testing-and-continuous-integration/
354
+ [arkency3]: http://blog.arkency.com/2015/04/why-i-want-to-introduce-mutation-testing-to-the-rails-event-store-gem/
355
+ [solnic]: http://solnic.eu/2013/01/23/mutation-testing-with-mutant.html
356
+
299
357
  Support
300
358
  -------
301
359
 
@@ -306,8 +364,19 @@ Your options:
306
364
  * [GitHub Issues](https://github.com/mbj/mutant/issues)
307
365
  * Ping me on [twitter](https://twitter.com/_m_b_j_)
308
366
 
309
- There is also a mutant [slack chat](https://mutation-testing.slack.com/).
310
- @mention [@\_m\_b\_j\_](https://twitter.com/_m_b_j_) on twitter for an invite.
367
+ There is also a mutation testing slack chat. Get an invite [here](https://mutation-testing-slack.herokuapp.com).
368
+ For discussing this project, join [#mutant](https://mutation-testing.slack.com/messages/#mutant).
369
+
370
+ Other Channels:
371
+
372
+ - [#cosmic-ray](https://mutation-testing.slack.com/messages/cosmic-ray): for discussing `cosmic-ray`, the python mutation testing tool.
373
+ - [#devtools](https://mutation-testing.slack.com/messages/devtools): for discussing the `devtools` metagem.
374
+ - [#general](https://mutation-testing.slack.com/messages/general): for general discussions about mutation testing.
375
+ - [#mutagen](https://mutation-testing.slack.com/messages/mutagen): for discussing `mutagen`, the javascript mutation testing tool.
376
+ - [#random](https://mutation-testing.slack.com/messages/random): for misc. off topic discussion.
377
+ - [#stryker](https://mutation-testing.slack.com/messages/stryker): for discussing `stryker`, the javascript mutation testing tool.
378
+ - [#wtf-dev](https://mutation-testing.slack.com/messages/wtf-dev): for sharing software development wtfs.
379
+
311
380
 
312
381
  Credits
313
382
  -------
data/Rakefile CHANGED
@@ -9,30 +9,16 @@ namespace :metrics do
9
9
  task mutant: :coverage do
10
10
  arguments = %w[
11
11
  bundle exec mutant
12
- --ignore-subject Mutant::Meta*
13
12
  --include lib
14
13
  --since HEAD~1
15
14
  --require mutant
16
15
  --use rspec
17
16
  --zombie
18
17
  ]
19
- arguments.concat(%W[--jobs 4]) if ENV.key?('CIRCLE_CI')
18
+ arguments.concat(%w[--jobs 4]) if ENV.key?('CIRCLECI')
20
19
 
21
20
  arguments.concat(%w[-- Mutant*])
22
21
 
23
- success = Kernel.system(*arguments) or fail 'Mutant task is not successful'
24
- end
25
- end
26
-
27
- desc 'Generate mutation operator listing'
28
- task :list do
29
- require 'mutant'
30
- # TODO: Add a nice public interface
31
- registry = Mutant::Mutator::Registry.send(:registry)
32
- registry.keys.select do |key|
33
- key.is_a?(Symbol)
34
- end.sort.each do |type|
35
- mutator = registry.fetch(type)
36
- puts '%-18s: %s' % [type, mutator.name.sub(/\AMutant::Mutator::Node::/, '')]
22
+ Kernel.system(*arguments) or fail 'Mutant task is not successful'
37
23
  end
38
24
  end
data/circle.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  machine:
3
3
  ruby:
4
- version: '2.2'
4
+ version: '2.3.0'
5
5
  dependencies:
6
6
  pre:
7
7
  - bundle -v | grep -Fx "Bundler version 1.10.6" || gem install bundler --version 1.10.6
@@ -1,3 +1,3 @@
1
1
  ---
2
- threshold: 18
3
- total_score: 1171
2
+ threshold: 16
3
+ total_score: 1284
@@ -1,2 +1,2 @@
1
1
  ---
2
- threshold: 29.3
2
+ threshold: 27.7
@@ -32,6 +32,7 @@ LongParameterList:
32
32
  enabled: true
33
33
  exclude:
34
34
  - Mutant::Matcher::Method::Instance#self.build
35
+ - Mutant::Meta::Example::DSL # 3 vars
35
36
  max_params: 2
36
37
  LongYieldList:
37
38
  enabled: true
@@ -42,7 +43,6 @@ NestedIterators:
42
43
  exclude:
43
44
  - Mutant#self.singleton_subclass_instance
44
45
  - Mutant::CLI#parse
45
- - Mutant::Isolation::Fork#self.call
46
46
  - Mutant::Mutator::Node::Arguments#emit_argument_mutations
47
47
  - Mutant::Mutator::Node::Resbody#mutate_captures
48
48
  - Mutant::Mutator::Util::Array::Element#dispatch
@@ -65,12 +65,12 @@ TooManyInstanceVariables:
65
65
  exclude:
66
66
  - Mutant::Mutator # 4 vars
67
67
  - Mutant::Parallel::Master # 4 vars
68
+ - Mutant::Meta::Example::DSL # 4 vars
68
69
  max_instance_variables: 3
69
70
  TooManyMethods:
70
71
  enabled: true
71
72
  exclude:
72
73
  - Mutant::CLI
73
- - Mutant::Meta::Example::Verification
74
74
  - Mutant::Mutator::Node
75
75
  - Mutant::Parallel::Master
76
76
  max_methods: 10
@@ -79,7 +79,6 @@ TooManyStatements:
79
79
  exclude:
80
80
  - Mutant::CLI#add_debug_options
81
81
  - Mutant::CLI#add_environment_options
82
- - Mutant::Isolation::Fork#self.call
83
82
  - Mutant::Reporter::CLI::Printer::Config#run
84
83
  - Mutant::Reporter::CLI::Printer::EnvProgress#run
85
84
  - Mutant::Runner#run_driver
@@ -130,7 +129,7 @@ UtilityFunction:
130
129
  - Mutant::Integration::Null#call
131
130
  - Mutant::Integration::Rspec#parse_example
132
131
  - Mutant::Integration::Rspec#parse_expression # intentional, private
133
- - Mutant::Meta::Example::Verification#format_mutation
132
+ - Mutant::Meta::Example::Verification#format_mutations # intentional, private
134
133
  - Mutant::Reporter::CLI::Format::Progressive#new_buffer
135
134
  - Mutant::Reporter::CLI::Printer::StatusProgressive#object # False positive calls super
136
135
  - Mutant::Repository::Diff#tracks? # intentional, private
@@ -11,20 +11,15 @@ BlockNesting:
11
11
 
12
12
  # Align with the style guide.
13
13
  CollectionMethods:
14
+ Enabled: true
14
15
  PreferredMethods:
15
16
  collect: 'map'
16
17
  inject: 'reduce'
17
18
  find: 'detect'
18
19
  find_all: 'select'
19
20
 
20
- # Do not force public/protected/private keyword to be indented at the same
21
- # level as the def keyword. My personal preference is to outdent these keywords
22
- # because I think when scanning code it makes it easier to identify the
23
- # sections of code and visually separate them. When the keyword is at the same
24
- # level I think it sort of blends in with the def keywords and makes it harder
25
- # to scan the code and see where the sections are.
26
21
  AccessModifierIndentation:
27
- Enabled: false
22
+ EnforcedStyle: outdent
28
23
 
29
24
  # Limit line length
30
25
  LineLength:
@@ -34,9 +29,17 @@ LineLength:
34
29
  Documentation:
35
30
  Enabled: false
36
31
 
37
- # Do not always use &&/|| instead of and/or.
32
+ # Permit
33
+ #
34
+ # boolean_check? or fail
35
+ #
36
+ # Reject
37
+ #
38
+ # if foo or bar
39
+ # ...
40
+ # end
38
41
  AndOr:
39
- Enabled: false
42
+ EnforcedStyle: conditionals
40
43
 
41
44
  # Do not favor modifier if/unless usage when you have a single-line body
42
45
  IfUnlessModifier:
@@ -72,7 +75,7 @@ MultilineOperationIndentation:
72
75
 
73
76
  # Prefer String#% over Kernel#sprintf
74
77
  FormatString:
75
- Enabled: false
78
+ EnforcedStyle: percent
76
79
 
77
80
  # Use square brackets for literal Array objects
78
81
  PercentLiteralDelimiters:
@@ -95,11 +98,6 @@ SymbolArray:
95
98
  EndAlignment:
96
99
  AlignWith: variable
97
100
 
98
- # Do not always align parameters when it is easier to read
99
- AlignParameters:
100
- Exclude:
101
- - spec/**/*_spec.rb
102
-
103
101
  # Prefer #kind_of? over #is_a?
104
102
  ClassCheck:
105
103
  EnforcedStyle: kind_of?
@@ -135,8 +133,47 @@ ParallelAssignment:
135
133
 
136
134
  # Allow additional specs
137
135
  ExtraSpacing:
138
- Enabled: false
136
+ AllowForAlignment: true
139
137
 
140
138
  # Buggy
141
139
  FormatParameterMismatch:
142
140
  Enabled: false
141
+
142
+ # Different preference
143
+ SignalException:
144
+ EnforcedStyle: semantic
145
+
146
+ # Do not use `alias`
147
+ Alias:
148
+ EnforcedStyle: prefer_alias_method
149
+
150
+ # Teaching people to ignore singleton class is pointless
151
+ RedundantFreeze:
152
+ Enabled: false
153
+
154
+ # Do not waste my horizontal or vertical space
155
+ IndentArray:
156
+ Enabled: false
157
+
158
+ # Prefer
159
+ #
160
+ # some_receiver
161
+ # .foo
162
+ # .bar
163
+ # .baz
164
+ #
165
+ # Over
166
+ #
167
+ # some_receiver.foo
168
+ # .bar
169
+ # .baz
170
+ MultilineMethodCallIndentation:
171
+ EnforcedStyle: indented
172
+
173
+ # Align keys and values in a multiline hash
174
+ AlignHash:
175
+ EnforcedColonStyle: table
176
+
177
+ # Prefer `public_send` and `__send__` over `send`
178
+ Send:
179
+ Enabled: true