mutest 0.0.1 → 0.0.2

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 (401) hide show
  1. checksums.yaml +4 -4
  2. data/.buildkite/hooks/pre-command +3 -0
  3. data/.buildkite/pipeline.yml +51 -0
  4. data/.gitattributes +1 -0
  5. data/.gitignore +38 -0
  6. data/.rspec +5 -0
  7. data/Gemfile +13 -0
  8. data/Gemfile.lock +216 -0
  9. data/Gemfile.shared +3 -0
  10. data/LICENSE +21 -0
  11. data/README.md +8 -0
  12. data/Rakefile +24 -0
  13. data/bin/mutest +39 -0
  14. data/build/Dockerfile +71 -0
  15. data/build/docker-bootstrap.sh +85 -0
  16. data/build/docker-exec +29 -0
  17. data/build/make-docker +3 -0
  18. data/build/ruby_matrix +1 -0
  19. data/build/run +5 -0
  20. data/build/strict-mode.sh +16 -0
  21. data/circle.yml +7 -0
  22. data/config/devtools.yml +2 -0
  23. data/config/flay.yml +3 -0
  24. data/config/flog.yml +2 -0
  25. data/config/reek.yml +137 -0
  26. data/config/rubocop.yml +395 -0
  27. data/config/triage.yml +2 -0
  28. data/config/yardstick.yml +2 -0
  29. data/lib/mutest.rb +243 -0
  30. data/lib/mutest/actor.rb +52 -0
  31. data/lib/mutest/actor/env.rb +28 -0
  32. data/lib/mutest/actor/mailbox.rb +31 -0
  33. data/lib/mutest/actor/receiver.rb +39 -0
  34. data/lib/mutest/actor/sender.rb +22 -0
  35. data/lib/mutest/ast.rb +44 -0
  36. data/lib/mutest/ast/meta.rb +7 -0
  37. data/lib/mutest/ast/meta/const.rb +22 -0
  38. data/lib/mutest/ast/meta/optarg.rb +24 -0
  39. data/lib/mutest/ast/meta/resbody.rb +15 -0
  40. data/lib/mutest/ast/meta/restarg.rb +15 -0
  41. data/lib/mutest/ast/meta/send.rb +89 -0
  42. data/lib/mutest/ast/meta/symbol.rb +15 -0
  43. data/lib/mutest/ast/named_children.rb +86 -0
  44. data/lib/mutest/ast/node_predicates.rb +17 -0
  45. data/lib/mutest/ast/nodes.rb +22 -0
  46. data/lib/mutest/ast/regexp.rb +50 -0
  47. data/lib/mutest/ast/regexp/transformer.rb +184 -0
  48. data/lib/mutest/ast/regexp/transformer/alternative.rb +39 -0
  49. data/lib/mutest/ast/regexp/transformer/character_set.rb +46 -0
  50. data/lib/mutest/ast/regexp/transformer/direct.rb +101 -0
  51. data/lib/mutest/ast/regexp/transformer/options_group.rb +65 -0
  52. data/lib/mutest/ast/regexp/transformer/quantifier.rb +112 -0
  53. data/lib/mutest/ast/regexp/transformer/recursive.rb +50 -0
  54. data/lib/mutest/ast/regexp/transformer/root.rb +28 -0
  55. data/lib/mutest/ast/regexp/transformer/text.rb +55 -0
  56. data/lib/mutest/ast/sexp.rb +26 -0
  57. data/lib/mutest/ast/types.rb +140 -0
  58. data/lib/mutest/cli.rb +196 -0
  59. data/lib/mutest/color.rb +39 -0
  60. data/lib/mutest/config.rb +28 -0
  61. data/lib/mutest/context.rb +98 -0
  62. data/lib/mutest/diff.rb +111 -0
  63. data/lib/mutest/env.rb +59 -0
  64. data/lib/mutest/env/bootstrap.rb +159 -0
  65. data/lib/mutest/expression.rb +55 -0
  66. data/lib/mutest/expression/method.rb +54 -0
  67. data/lib/mutest/expression/methods.rb +58 -0
  68. data/lib/mutest/expression/namespace.rb +75 -0
  69. data/lib/mutest/expression/parser.rb +64 -0
  70. data/lib/mutest/integration.rb +75 -0
  71. data/lib/mutest/isolation.rb +11 -0
  72. data/lib/mutest/isolation/fork.rb +72 -0
  73. data/lib/mutest/isolation/none.rb +23 -0
  74. data/lib/mutest/loader.rb +27 -0
  75. data/lib/mutest/matcher.rb +14 -0
  76. data/lib/mutest/matcher/chain.rb +19 -0
  77. data/lib/mutest/matcher/compiler.rb +55 -0
  78. data/lib/mutest/matcher/config.rb +81 -0
  79. data/lib/mutest/matcher/filter.rb +19 -0
  80. data/lib/mutest/matcher/method.rb +138 -0
  81. data/lib/mutest/matcher/method/instance.rb +63 -0
  82. data/lib/mutest/matcher/method/singleton.rb +88 -0
  83. data/lib/mutest/matcher/methods.rb +109 -0
  84. data/lib/mutest/matcher/namespace.rb +41 -0
  85. data/lib/mutest/matcher/null.rb +17 -0
  86. data/lib/mutest/matcher/scope.rb +38 -0
  87. data/lib/mutest/matcher/static.rb +15 -0
  88. data/lib/mutest/meta.rb +33 -0
  89. data/lib/mutest/meta/example.rb +32 -0
  90. data/lib/mutest/meta/example/dsl.rb +107 -0
  91. data/lib/mutest/meta/example/verification.rb +85 -0
  92. data/lib/mutest/mutation.rb +101 -0
  93. data/lib/mutest/mutator.rb +117 -0
  94. data/lib/mutest/mutator/node.rb +166 -0
  95. data/lib/mutest/mutator/node/and_asgn.rb +25 -0
  96. data/lib/mutest/mutator/node/argument.rb +68 -0
  97. data/lib/mutest/mutator/node/arguments.rb +90 -0
  98. data/lib/mutest/mutator/node/begin.rb +21 -0
  99. data/lib/mutest/mutator/node/binary.rb +64 -0
  100. data/lib/mutest/mutator/node/block.rb +51 -0
  101. data/lib/mutest/mutator/node/break.rb +21 -0
  102. data/lib/mutest/mutator/node/case.rb +47 -0
  103. data/lib/mutest/mutator/node/class.rb +21 -0
  104. data/lib/mutest/mutator/node/conditional_loop.rb +25 -0
  105. data/lib/mutest/mutator/node/const.rb +23 -0
  106. data/lib/mutest/mutator/node/define.rb +79 -0
  107. data/lib/mutest/mutator/node/defined.rb +24 -0
  108. data/lib/mutest/mutator/node/dstr.rb +20 -0
  109. data/lib/mutest/mutator/node/dsym.rb +20 -0
  110. data/lib/mutest/mutator/node/generic.rb +77 -0
  111. data/lib/mutest/mutator/node/if.rb +57 -0
  112. data/lib/mutest/mutator/node/kwbegin.rb +20 -0
  113. data/lib/mutest/mutator/node/literal.rb +19 -0
  114. data/lib/mutest/mutator/node/literal/array.rb +37 -0
  115. data/lib/mutest/mutator/node/literal/boolean.rb +27 -0
  116. data/lib/mutest/mutator/node/literal/fixnum.rb +36 -0
  117. data/lib/mutest/mutator/node/literal/float.rb +45 -0
  118. data/lib/mutest/mutator/node/literal/hash.rb +52 -0
  119. data/lib/mutest/mutator/node/literal/nil.rb +20 -0
  120. data/lib/mutest/mutator/node/literal/range.rb +38 -0
  121. data/lib/mutest/mutator/node/literal/regex.rb +76 -0
  122. data/lib/mutest/mutator/node/literal/string.rb +21 -0
  123. data/lib/mutest/mutator/node/literal/symbol.rb +26 -0
  124. data/lib/mutest/mutator/node/masgn.rb +21 -0
  125. data/lib/mutest/mutator/node/match_current_line.rb +22 -0
  126. data/lib/mutest/mutator/node/mlhs.rb +21 -0
  127. data/lib/mutest/mutator/node/named_value/access.rb +54 -0
  128. data/lib/mutest/mutator/node/named_value/constant_assignment.rb +42 -0
  129. data/lib/mutest/mutator/node/named_value/variable_assignment.rb +47 -0
  130. data/lib/mutest/mutator/node/next.rb +22 -0
  131. data/lib/mutest/mutator/node/noop.rb +19 -0
  132. data/lib/mutest/mutator/node/nthref.rb +22 -0
  133. data/lib/mutest/mutator/node/op_asgn.rb +50 -0
  134. data/lib/mutest/mutator/node/or_asgn.rb +26 -0
  135. data/lib/mutest/mutator/node/regexp.rb +33 -0
  136. data/lib/mutest/mutator/node/regexp/alternation_meta.rb +21 -0
  137. data/lib/mutest/mutator/node/regexp/capture_group.rb +26 -0
  138. data/lib/mutest/mutator/node/regexp/character_type.rb +29 -0
  139. data/lib/mutest/mutator/node/regexp/end_of_line_anchor.rb +21 -0
  140. data/lib/mutest/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +21 -0
  141. data/lib/mutest/mutator/node/regexp/one_or_more.rb +29 -0
  142. data/lib/mutest/mutator/node/regexp/zero_or_more.rb +29 -0
  143. data/lib/mutest/mutator/node/regopt.rb +28 -0
  144. data/lib/mutest/mutator/node/resbody.rb +34 -0
  145. data/lib/mutest/mutator/node/rescue.rb +69 -0
  146. data/lib/mutest/mutator/node/return.rb +24 -0
  147. data/lib/mutest/mutator/node/send.rb +270 -0
  148. data/lib/mutest/mutator/node/send/attribute_assignment.rb +39 -0
  149. data/lib/mutest/mutator/node/send/binary.rb +45 -0
  150. data/lib/mutest/mutator/node/send/conditional.rb +21 -0
  151. data/lib/mutest/mutator/node/send/index.rb +47 -0
  152. data/lib/mutest/mutator/node/splat.rb +23 -0
  153. data/lib/mutest/mutator/node/super.rb +24 -0
  154. data/lib/mutest/mutator/node/when.rb +60 -0
  155. data/lib/mutest/mutator/node/yield.rb +21 -0
  156. data/lib/mutest/mutator/node/zsuper.rb +20 -0
  157. data/lib/mutest/mutator/util.rb +11 -0
  158. data/lib/mutest/mutator/util/array.rb +42 -0
  159. data/lib/mutest/mutator/util/symbol.rb +19 -0
  160. data/lib/mutest/parallel.rb +89 -0
  161. data/lib/mutest/parallel/master.rb +181 -0
  162. data/lib/mutest/parallel/source.rb +57 -0
  163. data/lib/mutest/parallel/worker.rb +76 -0
  164. data/lib/mutest/parser.rb +22 -0
  165. data/lib/mutest/registry.rb +43 -0
  166. data/lib/mutest/reporter.rb +39 -0
  167. data/lib/mutest/reporter/cli.rb +87 -0
  168. data/lib/mutest/reporter/cli/format.rb +135 -0
  169. data/lib/mutest/reporter/cli/printer.rb +124 -0
  170. data/lib/mutest/reporter/cli/printer/config.rb +24 -0
  171. data/lib/mutest/reporter/cli/printer/env_progress.rb +76 -0
  172. data/lib/mutest/reporter/cli/printer/env_result.rb +20 -0
  173. data/lib/mutest/reporter/cli/printer/mutation_progress_result.rb +31 -0
  174. data/lib/mutest/reporter/cli/printer/mutation_result.rb +127 -0
  175. data/lib/mutest/reporter/cli/printer/status.rb +49 -0
  176. data/lib/mutest/reporter/cli/printer/status_progressive.rb +46 -0
  177. data/lib/mutest/reporter/cli/printer/subject_progress.rb +65 -0
  178. data/lib/mutest/reporter/cli/printer/subject_result.rb +23 -0
  179. data/lib/mutest/reporter/cli/printer/test_result.rb +28 -0
  180. data/lib/mutest/reporter/cli/tput.rb +43 -0
  181. data/lib/mutest/reporter/null.rb +14 -0
  182. data/lib/mutest/reporter/sequence.rb +24 -0
  183. data/lib/mutest/repository.rb +80 -0
  184. data/lib/mutest/require_highjack.rb +24 -0
  185. data/lib/mutest/result.rb +212 -0
  186. data/lib/mutest/runner.rb +81 -0
  187. data/lib/mutest/runner/sink.rb +63 -0
  188. data/lib/mutest/scope.rb +6 -0
  189. data/lib/mutest/selector.rb +13 -0
  190. data/lib/mutest/selector/expression.rb +25 -0
  191. data/lib/mutest/source_file.rb +47 -0
  192. data/lib/mutest/subject.rb +94 -0
  193. data/lib/mutest/subject/method.rb +42 -0
  194. data/lib/mutest/subject/method/instance.rb +43 -0
  195. data/lib/mutest/subject/method/singleton.rb +19 -0
  196. data/lib/mutest/test.rb +14 -0
  197. data/lib/mutest/util.rb +18 -0
  198. data/lib/mutest/version.rb +4 -0
  199. data/lib/mutest/warning_filter.rb +58 -0
  200. data/lib/mutest/zombifier.rb +119 -0
  201. data/meta/and.rb +13 -0
  202. data/meta/and_asgn.rb +12 -0
  203. data/meta/array.rb +28 -0
  204. data/meta/begin.rb +19 -0
  205. data/meta/block.rb +104 -0
  206. data/meta/block_pass.rb +6 -0
  207. data/meta/blockarg.rb +8 -0
  208. data/meta/break.rb +8 -0
  209. data/meta/case.rb +221 -0
  210. data/meta/casgn.rb +26 -0
  211. data/meta/cbase.rb +6 -0
  212. data/meta/class.rb +10 -0
  213. data/meta/const.rb +15 -0
  214. data/meta/csend.rb +8 -0
  215. data/meta/cvar.rb +5 -0
  216. data/meta/cvasgn.rb +8 -0
  217. data/meta/date.rb +57 -0
  218. data/meta/def.rb +260 -0
  219. data/meta/defined.rb +7 -0
  220. data/meta/dstr.rb +11 -0
  221. data/meta/dsym.rb +12 -0
  222. data/meta/ensure.rb +7 -0
  223. data/meta/false.rb +6 -0
  224. data/meta/float.rb +35 -0
  225. data/meta/gvar.rb +5 -0
  226. data/meta/gvasgn.rb +8 -0
  227. data/meta/hash.rb +22 -0
  228. data/meta/if.rb +75 -0
  229. data/meta/int.rb +16 -0
  230. data/meta/ivar.rb +6 -0
  231. data/meta/ivasgn.rb +21 -0
  232. data/meta/kwarg.rb +8 -0
  233. data/meta/kwbegin.rb +7 -0
  234. data/meta/kwoptarg.rb +11 -0
  235. data/meta/kwrestarg.rb +17 -0
  236. data/meta/lvar.rb +14 -0
  237. data/meta/lvasgn.rb +8 -0
  238. data/meta/masgn.rb +5 -0
  239. data/meta/match_current_line.rb +13 -0
  240. data/meta/next.rb +9 -0
  241. data/meta/nil.rb +3 -0
  242. data/meta/nthref.rb +12 -0
  243. data/meta/op_assgn.rb +39 -0
  244. data/meta/or.rb +13 -0
  245. data/meta/or_asgn.rb +48 -0
  246. data/meta/range.rb +37 -0
  247. data/meta/redo.rb +3 -0
  248. data/meta/regexp.rb +84 -0
  249. data/meta/regexp/character_types.rb +20 -0
  250. data/meta/regexp/regexp_alternation_meta.rb +11 -0
  251. data/meta/regexp/regexp_bol_anchor.rb +8 -0
  252. data/meta/regexp/regexp_bos_anchor.rb +16 -0
  253. data/meta/regexp/regexp_capture_group.rb +17 -0
  254. data/meta/regexp/regexp_eol_anchor.rb +8 -0
  255. data/meta/regexp/regexp_eos_anchor.rb +6 -0
  256. data/meta/regexp/regexp_eos_ob_eol_anchor.rb +8 -0
  257. data/meta/regexp/regexp_one_or_more.rb +32 -0
  258. data/meta/regexp/regexp_root_expression.rb +8 -0
  259. data/meta/regexp/regexp_zero_or_more.rb +32 -0
  260. data/meta/regopt.rb +8 -0
  261. data/meta/rescue.rb +87 -0
  262. data/meta/restarg.rb +9 -0
  263. data/meta/return.rb +14 -0
  264. data/meta/self.rb +5 -0
  265. data/meta/send.rb +849 -0
  266. data/meta/str.rb +5 -0
  267. data/meta/super.rb +25 -0
  268. data/meta/sym.rb +6 -0
  269. data/meta/true.rb +6 -0
  270. data/meta/until.rb +15 -0
  271. data/meta/while.rb +24 -0
  272. data/meta/yield.rb +8 -0
  273. data/mutest-rspec.gemspec +22 -0
  274. data/mutest.gemspec +45 -0
  275. data/spec/integration/mutest/corpus_spec.rb +18 -0
  276. data/spec/integration/mutest/isolation/fork_spec.rb +8 -0
  277. data/spec/integration/mutest/null_spec.rb +13 -0
  278. data/spec/integration/mutest/rspec_spec.rb +11 -0
  279. data/spec/integration/mutest/test_mutator_handles_types_spec.rb +7 -0
  280. data/spec/integrations.yml +32 -0
  281. data/spec/rcov.opts +7 -0
  282. data/spec/shared/framework_integration_behavior.rb +44 -0
  283. data/spec/shared/method_matcher_behavior.rb +49 -0
  284. data/spec/spec_helper.rb +70 -0
  285. data/spec/support/compress_helper.rb +9 -0
  286. data/spec/support/corpus.rb +331 -0
  287. data/spec/support/fake_actor.rb +107 -0
  288. data/spec/support/file_system.rb +60 -0
  289. data/spec/support/ice_nine_config.rb +8 -0
  290. data/spec/support/rb_bug.rb +15 -0
  291. data/spec/support/ruby_vm.rb +82 -0
  292. data/spec/support/shared_context.rb +125 -0
  293. data/spec/support/test_app.rb +5 -0
  294. data/spec/support/warning.rb +73 -0
  295. data/spec/support/warnings.yml +5 -0
  296. data/spec/support/xspec.rb +175 -0
  297. data/spec/unit/mutest/actor/binding_spec.rb +32 -0
  298. data/spec/unit/mutest/actor/env_spec.rb +29 -0
  299. data/spec/unit/mutest/actor/mailbox_spec.rb +25 -0
  300. data/spec/unit/mutest/actor/message_spec.rb +22 -0
  301. data/spec/unit/mutest/actor/receiver_spec.rb +56 -0
  302. data/spec/unit/mutest/actor/sender_spec.rb +22 -0
  303. data/spec/unit/mutest/ast/meta/optarg_spec.rb +21 -0
  304. data/spec/unit/mutest/ast/meta/send/proc_predicate_spec.rb +28 -0
  305. data/spec/unit/mutest/ast/meta/send/receiver_possible_top_level_const_predicate_spec.rb +37 -0
  306. data/spec/unit/mutest/ast/meta/send_spec.rb +42 -0
  307. data/spec/unit/mutest/ast/named_children_spec.rb +87 -0
  308. data/spec/unit/mutest/ast/regexp/parse_spec.rb +5 -0
  309. data/spec/unit/mutest/ast/regexp/supported_predicate_spec.rb +14 -0
  310. data/spec/unit/mutest/ast/regexp/transformer/lookup_table/table_spec.rb +19 -0
  311. data/spec/unit/mutest/ast/regexp/transformer/lookup_table_spec.rb +33 -0
  312. data/spec/unit/mutest/ast/regexp/transformer_spec.rb +19 -0
  313. data/spec/unit/mutest/ast/regexp_spec.rb +625 -0
  314. data/spec/unit/mutest/ast/sexp_spec.rb +36 -0
  315. data/spec/unit/mutest/ast_spec.rb +55 -0
  316. data/spec/unit/mutest/cli_spec.rb +247 -0
  317. data/spec/unit/mutest/context_spec.rb +141 -0
  318. data/spec/unit/mutest/diff_spec.rb +185 -0
  319. data/spec/unit/mutest/env/bootstrap_spec.rb +188 -0
  320. data/spec/unit/mutest/env_spec.rb +100 -0
  321. data/spec/unit/mutest/expression/method_spec.rb +44 -0
  322. data/spec/unit/mutest/expression/methods_spec.rb +59 -0
  323. data/spec/unit/mutest/expression/namespace/exact_spec.rb +26 -0
  324. data/spec/unit/mutest/expression/namespace/recursive_spec.rb +64 -0
  325. data/spec/unit/mutest/expression/parser_spec.rb +67 -0
  326. data/spec/unit/mutest/expression_spec.rb +45 -0
  327. data/spec/unit/mutest/integration/null_spec.rb +28 -0
  328. data/spec/unit/mutest/integration/rspec_spec.rb +197 -0
  329. data/spec/unit/mutest/integration_spec.rb +26 -0
  330. data/spec/unit/mutest/isolation/fork_spec.rb +155 -0
  331. data/spec/unit/mutest/isolation/none_spec.rb +16 -0
  332. data/spec/unit/mutest/loader_spec.rb +42 -0
  333. data/spec/unit/mutest/matcher/chain_spec.rb +24 -0
  334. data/spec/unit/mutest/matcher/compiler/subject_prefix_spec.rb +24 -0
  335. data/spec/unit/mutest/matcher/compiler_spec.rb +76 -0
  336. data/spec/unit/mutest/matcher/config_spec.rb +45 -0
  337. data/spec/unit/mutest/matcher/filter_spec.rb +20 -0
  338. data/spec/unit/mutest/matcher/method/instance_spec.rb +125 -0
  339. data/spec/unit/mutest/matcher/method/singleton_spec.rb +85 -0
  340. data/spec/unit/mutest/matcher/methods/instance_spec.rb +58 -0
  341. data/spec/unit/mutest/matcher/methods/singleton_spec.rb +54 -0
  342. data/spec/unit/mutest/matcher/namespace_spec.rb +35 -0
  343. data/spec/unit/mutest/matcher/null_spec.rb +10 -0
  344. data/spec/unit/mutest/matcher/scope_spec.rb +33 -0
  345. data/spec/unit/mutest/matcher/static_spec.rb +11 -0
  346. data/spec/unit/mutest/meta/example/dsl_spec.rb +123 -0
  347. data/spec/unit/mutest/meta/example/verification_spec.rb +120 -0
  348. data/spec/unit/mutest/meta/example_spec.rb +32 -0
  349. data/spec/unit/mutest/mutation_spec.rb +129 -0
  350. data/spec/unit/mutest/mutator/node_spec.rb +43 -0
  351. data/spec/unit/mutest/mutator_spec.rb +30 -0
  352. data/spec/unit/mutest/parallel/driver_spec.rb +26 -0
  353. data/spec/unit/mutest/parallel/master_spec.rb +335 -0
  354. data/spec/unit/mutest/parallel/source/array_spec.rb +47 -0
  355. data/spec/unit/mutest/parallel/worker_spec.rb +65 -0
  356. data/spec/unit/mutest/parallel_spec.rb +16 -0
  357. data/spec/unit/mutest/parser_spec.rb +24 -0
  358. data/spec/unit/mutest/registry_spec.rb +45 -0
  359. data/spec/unit/mutest/reporter/cli/printer/config_spec.rb +29 -0
  360. data/spec/unit/mutest/reporter/cli/printer/env_progress_spec.rb +74 -0
  361. data/spec/unit/mutest/reporter/cli/printer/env_result_spec.rb +35 -0
  362. data/spec/unit/mutest/reporter/cli/printer/mutation_progress_result_spec.rb +23 -0
  363. data/spec/unit/mutest/reporter/cli/printer/mutation_result_spec.rb +110 -0
  364. data/spec/unit/mutest/reporter/cli/printer/status_progressive_spec.rb +43 -0
  365. data/spec/unit/mutest/reporter/cli/printer/status_spec.rb +119 -0
  366. data/spec/unit/mutest/reporter/cli/printer/subject_progress_spec.rb +34 -0
  367. data/spec/unit/mutest/reporter/cli/printer/subject_result_spec.rb +37 -0
  368. data/spec/unit/mutest/reporter/cli/printer/test_result_spec.rb +14 -0
  369. data/spec/unit/mutest/reporter/cli/printer_spec.rb +161 -0
  370. data/spec/unit/mutest/reporter/cli/tput_spec.rb +48 -0
  371. data/spec/unit/mutest/reporter/cli_spec.rb +212 -0
  372. data/spec/unit/mutest/reporter/null_spec.rb +12 -0
  373. data/spec/unit/mutest/reporter/sequence_spec.rb +29 -0
  374. data/spec/unit/mutest/repository/diff_spec.rb +106 -0
  375. data/spec/unit/mutest/repository/subject_filter_spec.rb +28 -0
  376. data/spec/unit/mutest/require_highjack_spec.rb +71 -0
  377. data/spec/unit/mutest/result/class_methods_spec.rb +49 -0
  378. data/spec/unit/mutest/result/env_spec.rb +82 -0
  379. data/spec/unit/mutest/result/mutation_spec.rb +37 -0
  380. data/spec/unit/mutest/result/subject_spec.rb +109 -0
  381. data/spec/unit/mutest/result_spec.rb +31 -0
  382. data/spec/unit/mutest/runner/sink_spec.rb +172 -0
  383. data/spec/unit/mutest/runner_spec.rb +69 -0
  384. data/spec/unit/mutest/selector/expression_spec.rb +59 -0
  385. data/spec/unit/mutest/source_file_spec.rb +42 -0
  386. data/spec/unit/mutest/subject/method/instance/memoized_spec.rb +78 -0
  387. data/spec/unit/mutest/subject/method/instance_spec.rb +64 -0
  388. data/spec/unit/mutest/subject/method/singleton_spec.rb +51 -0
  389. data/spec/unit/mutest/subject_spec.rb +87 -0
  390. data/spec/unit/mutest/util/one_spec.rb +20 -0
  391. data/spec/unit/mutest/warning_filter_spec.rb +99 -0
  392. data/spec/unit/mutest/zombifier_spec.rb +120 -0
  393. data/spec/unit/mutest_spec.rb +15 -0
  394. data/test_app/.rspec +1 -0
  395. data/test_app/Gemfile.rspec3.4 +7 -0
  396. data/test_app/Gemfile.rspec3.5 +7 -0
  397. data/test_app/lib/test_app.rb +109 -0
  398. data/test_app/lib/test_app/literal.rb +40 -0
  399. data/test_app/spec/spec_helper.rb +9 -0
  400. data/test_app/spec/unit/test_app/literal_spec.rb +20 -0
  401. metadata +784 -9
@@ -0,0 +1,9 @@
1
+ module CompressHelper
2
+ def strip_indent(string)
3
+ lines = string.lines
4
+ match = /\A( *)/.match(lines.first)
5
+ return string unless match
6
+ whitespaces = match[1].to_s.length
7
+ lines.map { |line| line[whitespaces..-1] }.join
8
+ end
9
+ end # CompressHelper
@@ -0,0 +1,331 @@
1
+ require 'morpher'
2
+ require 'anima'
3
+ require 'mutest'
4
+
5
+ # @api private
6
+ module MutestSpec
7
+ ROOT = Pathname.new(__FILE__).parent.parent.parent
8
+
9
+ # Namespace module for corpus testing
10
+ #
11
+ # rubocop:disable MethodLength
12
+ module Corpus
13
+ TMP = ROOT.join('tmp').freeze
14
+ EXCLUDE_GLOB_FORMAT = '{%s}'.freeze
15
+ RUBY_GLOB_PATTERN = '**/*.rb'.freeze
16
+
17
+ # Not in the docs. Number from chatting with their support.
18
+ # 2 processors allocated per container, 4 processes works well.
19
+ CIRCLE_CI_CONTAINER_PROCESSES = 4
20
+
21
+ private_constant(*constants(false))
22
+
23
+ # Project under corpus test
24
+ # rubocop:disable ClassLength
25
+ class Project
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
+
34
+ include Adamantium, Anima.new(
35
+ :expected_errors,
36
+ :mutation_coverage,
37
+ :mutation_generation,
38
+ :name,
39
+ :namespace,
40
+ :repo_uri,
41
+ :repo_ref
42
+ )
43
+
44
+ # Verify mutation coverage
45
+ #
46
+ # @return [self]
47
+ # if successful
48
+ #
49
+ # @raise [Exception]
50
+ def verify_mutation_coverage
51
+ checkout
52
+ Dir.chdir(repo_path) do
53
+ Bundler.with_clean_env do
54
+ install_mutest
55
+ system(
56
+ %W[
57
+ bundle exec mutest
58
+ --use rspec
59
+ --include lib
60
+ --require #{name}
61
+ #{namespace}*
62
+ ]
63
+ )
64
+ end
65
+ end
66
+ end
67
+
68
+ # Verify mutation generation
69
+ #
70
+ # @return [self]
71
+ # if successful
72
+ #
73
+ # @raise [Exception]
74
+ # otherwise
75
+ def verify_mutation_generation
76
+ checkout
77
+ start = Time.now
78
+
79
+ options = {
80
+ finish: method(:finish),
81
+ start: method(:start),
82
+ in_processes: parallel_processes
83
+ }
84
+
85
+ total = Parallel.map(effective_ruby_paths, options, &method(:count_mutations_and_check_errors))
86
+ .inject(DEFAULT_MUTATION_COUNT, :+)
87
+
88
+ took = Time.now - start
89
+ puts format(MUTATION_GENERATION_MESSAGE, total, took, total / took)
90
+ self
91
+ end
92
+
93
+ # Checkout repository
94
+ #
95
+ # @return [self]
96
+ def checkout
97
+ return self if noinstall?
98
+ TMP.mkdir unless TMP.directory?
99
+
100
+ if repo_path.exist?
101
+ Dir.chdir(repo_path) do
102
+ system(%w[git fetch origin])
103
+ system(%w[git reset --hard])
104
+ system(%w[git clean -f -d -x])
105
+ end
106
+ else
107
+ system(%W[git clone #{repo_uri} #{repo_path}])
108
+ end
109
+
110
+ Dir.chdir(repo_path) do
111
+ system(%W[git checkout #{repo_ref}])
112
+ system(%w[git reset --hard])
113
+ system(%w[git clean -f -d -x])
114
+ end
115
+
116
+ self
117
+ end
118
+ memoize :checkout
119
+
120
+ private
121
+
122
+ # Count mutations and check error results against whitelist
123
+ #
124
+ # @param path [Pathname] path responsible for exception
125
+ #
126
+ # @return [Fixnum] mutations generated
127
+ def count_mutations_and_check_errors(path)
128
+ relative_path = path.relative_path_from(repo_path)
129
+
130
+ count = count_mutations(path)
131
+
132
+ expected_errors.assert_success(relative_path)
133
+
134
+ count
135
+ rescue Exception => exception # rubocop:disable Lint/RescueException
136
+ expected_errors.assert_error(relative_path, exception)
137
+
138
+ DEFAULT_MUTATION_COUNT
139
+ end
140
+
141
+ # Count mutations generated for provided source file
142
+ #
143
+ # @param path [Pathname] path to a source file
144
+ #
145
+ # @raise [Exception] any error specified by integrations.yml
146
+ #
147
+ # @return [Fixnum] number of mutations generated
148
+ def count_mutations(path)
149
+ node = Parser::CurrentRuby.parse(path.read)
150
+
151
+ return DEFAULT_MUTATION_COUNT unless node
152
+
153
+ Mutest::Mutator.mutate(node).length
154
+ end
155
+
156
+ # Install mutest
157
+ #
158
+ # @return [undefined]
159
+ def install_mutest
160
+ return if noinstall?
161
+ relative = ROOT.relative_path_from(repo_path)
162
+ repo_path.join('Gemfile').open('a') do |file|
163
+ file << "gem 'mutest', path: '#{relative}'\n"
164
+ file << "gem 'mutest-rspec', path: '#{relative}'\n"
165
+ file << "eval_gemfile File.expand_path('#{relative.join('Gemfile.shared')}')\n"
166
+ end
167
+ lockfile = repo_path.join('Gemfile.lock')
168
+ lockfile.delete if lockfile.exist?
169
+ system(%w[bundle])
170
+ end
171
+
172
+ # The effective ruby file paths
173
+ #
174
+ # @return [Array<Pathname>]
175
+ def effective_ruby_paths
176
+ Pathname
177
+ .glob(repo_path.join(RUBY_GLOB_PATTERN))
178
+ .sort_by(&:size)
179
+ .reverse
180
+ end
181
+
182
+ # Number of parallel processes to use
183
+ #
184
+ # @return [Fixnum]
185
+ def parallel_processes
186
+ if ENV.key?('CI')
187
+ CIRCLE_CI_CONTAINER_PROCESSES
188
+ else
189
+ Parallel.processor_count
190
+ end
191
+ end
192
+
193
+ # Repository path
194
+ #
195
+ # @return [Pathname]
196
+ def repo_path
197
+ TMP.join(name)
198
+ end
199
+
200
+ # Test if installation should be skipped
201
+ #
202
+ # @return [Boolean]
203
+ def noinstall?
204
+ ENV.key?('NOINSTALL')
205
+ end
206
+
207
+ # Print start progress
208
+ #
209
+ # @param [Pathname] path
210
+ # @param [Fixnum] _index
211
+ #
212
+ # @return [undefined]
213
+ #
214
+ def start(path, _index)
215
+ MUTEX.synchronize do
216
+ puts START_MESSAGE % path
217
+ end
218
+ end
219
+
220
+ # Print finish progress
221
+ #
222
+ # @param [Pathname] path
223
+ # @param [Fixnum] _index
224
+ # @param [Fixnum] count
225
+ #
226
+ # @return [undefined]
227
+ #
228
+ def finish(path, _index, count)
229
+ MUTEX.synchronize do
230
+ puts format(FINISH_MESSAGE, count, path)
231
+ end
232
+ end
233
+
234
+ # Helper method to execute system commands
235
+ #
236
+ # @param [Array<String>] arguments
237
+ #
238
+ def system(arguments)
239
+ return if Kernel.system(*arguments)
240
+
241
+ if block_given?
242
+ yield
243
+ else
244
+ fail "System command failed!: #{arguments.join(' ')}"
245
+ end
246
+ end
247
+
248
+ # Mapping of files which we expect to cause errors during mutation generation
249
+ class ErrorWhitelist
250
+ class UnnecessaryExpectation < StandardError
251
+ MESSAGE = 'Expected to encounter %s while mutating "%s"'.freeze
252
+
253
+ def initialize(*error_info)
254
+ super(MESSAGE % error_info)
255
+ end
256
+ end # UnnecessaryExpectation
257
+
258
+ include Concord.new(:map), Adamantium
259
+
260
+ # Assert that we expect to encounter the provided exception for this path
261
+ #
262
+ # @param path [Pathname]
263
+ # @param exception [Exception]
264
+ #
265
+ # @raise provided exception if we are not expecting this error
266
+ #
267
+ # This method is reraising exceptions but rubocop can't tell
268
+ # rubocop:disable Style/SignalException
269
+ #
270
+ # @return [undefined]
271
+ def assert_error(path, exception)
272
+ original_error = exception.cause || exception
273
+
274
+ raise exception unless map.fetch(original_error.inspect, []).include?(path)
275
+ end
276
+
277
+ # Assert that we expect to not encounter an error for the specified path
278
+ #
279
+ # @param path [Pathname]
280
+ #
281
+ # @raise [UnnecessaryExpectation] if we are expecting an exception for this path
282
+ #
283
+ # @return [undefined]
284
+ def assert_success(path)
285
+ map.each do |error, paths|
286
+ fail UnnecessaryExpectation.new(error, path) if paths.include?(path)
287
+ end
288
+ end
289
+
290
+ # Return representation as hash
291
+ #
292
+ # @note this method is necessary for morpher loader to be invertible
293
+ #
294
+ # @return [Hash{Pathname => String}]
295
+ def to_h
296
+ map
297
+ end
298
+ end # ErrorWhitelist
299
+
300
+ LOADER =
301
+ Morpher.build do
302
+ s(:block,
303
+ s(:guard, s(:primitive, Array)),
304
+ s(:map,
305
+ s(:block,
306
+ s(:guard, s(:primitive, Hash)),
307
+ s(:hash_transform,
308
+ s(:key_symbolize, :repo_uri, s(:guard, s(:primitive, String))),
309
+ s(:key_symbolize, :repo_ref, s(:guard, s(:primitive, String))),
310
+ s(:key_symbolize, :name, s(:guard, s(:primitive, String))),
311
+ s(:key_symbolize, :namespace, s(:guard, s(:primitive, String))),
312
+ s(:key_symbolize, :mutation_coverage,
313
+ s(:guard, s(:or, s(:primitive, TrueClass), s(:primitive, FalseClass)))),
314
+ s(:key_symbolize, :mutation_generation,
315
+ s(:guard, s(:or, s(:primitive, TrueClass), s(:primitive, FalseClass)))),
316
+ s(:key_symbolize, :expected_errors,
317
+ s(:block,
318
+ s(:guard, s(:primitive, Hash)),
319
+ s(:custom,
320
+ [
321
+ ->(hash) { hash.map { |key, values| [key, values.map(&Pathname.method(:new))] }.to_h },
322
+ ->(hash) { hash.map { |key, values| [key, values.map(&:to_s)] }.to_h }
323
+ ]),
324
+ s(:load_attribute_hash, s(:param, ErrorWhitelist))))),
325
+ s(:anima_load, Project))))
326
+ end
327
+
328
+ ALL = LOADER.call(YAML.load_file(ROOT.join('spec', 'integrations.yml')))
329
+ end # Project
330
+ end # Corpus
331
+ end # MutestSpec
@@ -0,0 +1,107 @@
1
+ require 'mutest/actor'
2
+
3
+ # A fake actor used from specs
4
+ module FakeActor
5
+ class Expectation
6
+ include Concord::Public.new(:name, :message, :block)
7
+ include Equalizer.new(:name, :message)
8
+
9
+ def self.new(_name, _message, _block = nil)
10
+ super
11
+ end
12
+
13
+ def verify(other)
14
+ fail "Got:\n#{other.inspect}\nExpected:\n#{inspect}" unless eql?(other)
15
+ block.call(other.message) if block
16
+ end
17
+ end # Expectation
18
+
19
+ class MessageSequence
20
+ include Adamantium::Flat, Concord::Public.new(:messages)
21
+
22
+ def self.new
23
+ super([])
24
+ end
25
+
26
+ def add(name, *message_arguments, &block)
27
+ messages << Expectation.new(name, Mutest::Actor::Message.new(*message_arguments), block)
28
+ self
29
+ end
30
+
31
+ def sending(expectation)
32
+ fail "Unexpected send: #{expectation.inspect}" if messages.empty?
33
+ expected = messages.shift
34
+ expected.verify(expectation)
35
+ self
36
+ end
37
+
38
+ def receiving(name)
39
+ fail "No message to read for #{name.inspect}" if messages.empty?
40
+ expected = messages.shift
41
+ fail "Unexpected message #{expected.inspect} for #{name.inspect}" unless expected.name.eql?(name)
42
+ expected.message
43
+ end
44
+
45
+ def consumed?
46
+ messages.empty?
47
+ end
48
+ end # MessageSequence
49
+
50
+ class Env
51
+ include Concord.new(:messages, :mailbox_names)
52
+
53
+ def spawn
54
+ mailbox = mailbox(next_name)
55
+ yield mailbox if block_given?
56
+ mailbox.sender
57
+ end
58
+
59
+ def mailbox(name)
60
+ Mailbox.new(name, @messages)
61
+ end
62
+
63
+ def new_mailbox
64
+ mailbox(:current)
65
+ end
66
+
67
+ private
68
+
69
+ def next_name
70
+ @mailbox_names.shift.tap do |name|
71
+ name or fail 'Tried to spawn actor when no name available'
72
+ end
73
+ end
74
+ end # Env
75
+
76
+ class Mailbox
77
+ include Concord.new(:name, :messages)
78
+
79
+ def receiver
80
+ Receiver.new(name, messages)
81
+ end
82
+
83
+ def sender
84
+ Sender.new(name, messages)
85
+ end
86
+
87
+ def bind(sender)
88
+ Mutest::Actor::Binding.new(self, sender)
89
+ end
90
+ end # Mailbox
91
+
92
+ class Sender
93
+ include Concord.new(:name, :messages)
94
+
95
+ def call(message)
96
+ messages.sending(Expectation.new(name, message))
97
+ end
98
+ end # Sender
99
+
100
+ class Receiver
101
+ include Concord::Public.new(:name, :messages)
102
+
103
+ def call
104
+ messages.receiving(name)
105
+ end
106
+ end # Receiver
107
+ end # FakeActor
@@ -0,0 +1,60 @@
1
+ module MutestSpec
2
+ class FileState
3
+ DEFAULTS = IceNine.deep_freeze(
4
+ file: false,
5
+ contents: nil,
6
+ requires: []
7
+ )
8
+
9
+ include Adamantium, Anima.new(*DEFAULTS.keys)
10
+
11
+ def self.new(attributes = DEFAULTS)
12
+ super(DEFAULTS.merge(attributes))
13
+ end
14
+
15
+ DOES_NOT_EXIST = new
16
+
17
+ alias_method :file?, :file
18
+ end # FileState
19
+
20
+ class FakePathname
21
+ include Adamantium, Concord.new(:file_system, :pathname)
22
+
23
+ def join(*arguments)
24
+ self.class.new(
25
+ file_system,
26
+ pathname.join(*arguments)
27
+ )
28
+ end
29
+
30
+ def read
31
+ state.contents
32
+ end
33
+
34
+ def to_s
35
+ pathname.to_s
36
+ end
37
+
38
+ def file?
39
+ state.file?
40
+ end
41
+
42
+ private
43
+
44
+ def state
45
+ file_system.state(pathname.to_s)
46
+ end
47
+ end # FakePathname
48
+
49
+ class FileSystem
50
+ include Adamantium, Concord.new(:file_states)
51
+
52
+ def state(filename)
53
+ file_states.fetch(filename, FileState::DOES_NOT_EXIST)
54
+ end
55
+
56
+ def path(filename)
57
+ FakePathname.new(self, Pathname.new(filename))
58
+ end
59
+ end # FileSystem
60
+ end # MutestSpec