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,28 @@
1
+ module Mutest
2
+ # Standalone configuration of a mutest execution.
3
+ #
4
+ # Does not reference any "external" volatile state. The configuration applied
5
+ # to current environment is being represented by the Mutest::Env object.
6
+ class Config
7
+ include Adamantium::Flat, Anima.new(
8
+ :expression_parser,
9
+ :fail_fast,
10
+ :integration,
11
+ :includes,
12
+ :isolation,
13
+ :jobs,
14
+ :kernel,
15
+ :load_path,
16
+ :matcher,
17
+ :open3,
18
+ :pathname,
19
+ :requires,
20
+ :reporter,
21
+ :zombie
22
+ )
23
+
24
+ %i[fail_fast zombie].each do |name|
25
+ define_method(:"#{name}?") { public_send(name) }
26
+ end
27
+ end # Config
28
+ end # Mutest
@@ -0,0 +1,98 @@
1
+ module Mutest
2
+ # An abstract context where mutations can be applied to.
3
+ class Context
4
+ include Adamantium::Flat, Concord::Public.new(:scope, :source_file)
5
+ extend AST::Sexp
6
+
7
+ NAMESPACE_DELIMITER = '::'.freeze
8
+
9
+ # Return root node for mutation
10
+ #
11
+ # @return [Parser::AST::Node]
12
+ def root(node)
13
+ nesting.reverse.reduce(node) do |current, scope|
14
+ self.class.wrap(scope, current)
15
+ end
16
+ end
17
+
18
+ # Identification string
19
+ #
20
+ # @return [String]
21
+ def identification
22
+ scope.name
23
+ end
24
+
25
+ # Wrap node into ast node
26
+ #
27
+ # @param [Class, Module] scope
28
+ # @param [Parser::AST::Node] node
29
+ #
30
+ # @return [Parser::AST::Class]
31
+ # if scope is of kind Class
32
+ #
33
+ # @return [Parser::AST::Module]
34
+ # if scope is of kind module
35
+ def self.wrap(scope, node)
36
+ name = s(:const, nil, scope.name.split(NAMESPACE_DELIMITER).last.to_sym)
37
+ case scope
38
+ when Class
39
+ s(:class, name, nil, node)
40
+ when Module
41
+ s(:module, name, node)
42
+ end
43
+ end
44
+
45
+ # Nesting of scope
46
+ #
47
+ # @return [Enumerable<Class,Module>]
48
+ def nesting
49
+ const = Object
50
+ name_nesting.map do |name|
51
+ const = const.const_get(name)
52
+ end
53
+ end
54
+ memoize :nesting
55
+
56
+ # Unqualified name of scope
57
+ #
58
+ # @return [String]
59
+ def unqualified_name
60
+ name_nesting.last
61
+ end
62
+
63
+ # Match expressions for scope
64
+ #
65
+ # @return [Enumerable<Expression>]
66
+ def match_expressions
67
+ name_nesting.each_index.reverse_each.map do |index|
68
+ Expression::Namespace::Recursive.new(
69
+ scope_name: name_nesting.take(index.succ).join(NAMESPACE_DELIMITER)
70
+ )
71
+ end
72
+ end
73
+ memoize :match_expressions
74
+
75
+ # Scope wrapped by context
76
+ #
77
+ # @return [Module|Class]
78
+ attr_reader :scope
79
+
80
+ def ignore?(node)
81
+ source_file.ignore?(node)
82
+ end
83
+
84
+ def source_path
85
+ source_file.path
86
+ end
87
+
88
+ private
89
+
90
+ # Nesting of names in scope
91
+ #
92
+ # @return [Array<String>]
93
+ def name_nesting
94
+ scope.name.split(NAMESPACE_DELIMITER)
95
+ end
96
+ memoize :name_nesting
97
+ end # Context
98
+ end # Mutest
@@ -0,0 +1,111 @@
1
+ module Mutest
2
+ # Class to create diffs from source code
3
+ class Diff
4
+ include Adamantium::Flat, Concord.new(:old, :new)
5
+
6
+ ADDITION = '+'.freeze
7
+ DELETION = '-'.freeze
8
+ NEWLINE = "\n".freeze
9
+
10
+ # Unified source diff between old and new
11
+ #
12
+ # @return [String]
13
+ # if there is exactly one diff
14
+ #
15
+ # @return [nil]
16
+ # otherwise
17
+ def diff
18
+ return if diffs.empty?
19
+
20
+ minimized_hunk.diff(:unified) << NEWLINE
21
+ end
22
+ memoize :diff
23
+
24
+ # Colorized unified source diff between old and new
25
+ #
26
+ # @return [String]
27
+ # if there is a diff
28
+ #
29
+ # @return [nil]
30
+ # otherwise
31
+ def colorized_diff
32
+ return unless diff
33
+ diff.lines.map(&self.class.method(:colorize_line)).join
34
+ end
35
+ memoize :colorized_diff
36
+
37
+ # Build new object from source strings
38
+ #
39
+ # @param [String] old
40
+ # @param [String] new
41
+ #
42
+ # @return [Diff]
43
+ def self.build(old, new)
44
+ new(lines(old), lines(new))
45
+ end
46
+
47
+ # Break up source into lines
48
+ #
49
+ # @param [String] source
50
+ #
51
+ # @return [Array<String>]
52
+ def self.lines(source)
53
+ source.lines.map(&:chomp)
54
+ end
55
+ private_class_method :lines
56
+
57
+ private
58
+
59
+ # Diffs between old and new
60
+ #
61
+ # @return [Array<Array>]
62
+ def diffs
63
+ ::Diff::LCS.diff(old, new)
64
+ end
65
+
66
+ # Raw diff-lcs hunks
67
+ #
68
+ # @return [Array<Diff::LCS::Hunk>]
69
+ def hunks
70
+ diffs.map do |diff|
71
+ ::Diff::LCS::Hunk.new(old, new, diff, max_length, 0)
72
+ end
73
+ end
74
+
75
+ # Minimized hunk
76
+ #
77
+ # @return Diff::LCS::Hunk
78
+ def minimized_hunk
79
+ head, *tail = hunks
80
+
81
+ tail.reduce(head) do |left, right|
82
+ right.merge(left)
83
+ right
84
+ end
85
+ end
86
+
87
+ # Max length of source line in new and old
88
+ #
89
+ # @return [Fixnum]
90
+ def max_length
91
+ [old, new].map(&:length).max
92
+ end
93
+
94
+ # Colorized a unified diff line
95
+ #
96
+ # @param [String] line
97
+ #
98
+ # @return [String]
99
+ def self.colorize_line(line)
100
+ case line[0]
101
+ when ADDITION
102
+ Color::GREEN
103
+ when DELETION
104
+ Color::RED
105
+ else
106
+ Color::NONE
107
+ end.format(line)
108
+ end
109
+ private_class_method :colorize_line
110
+ end # Diff
111
+ end # Mutest
data/lib/mutest/env.rb ADDED
@@ -0,0 +1,59 @@
1
+ module Mutest
2
+ # Abstract base class for mutest environments
3
+ class Env
4
+ include Adamantium::Flat, Anima.new(
5
+ :actor_env,
6
+ :config,
7
+ :integration,
8
+ :matchable_scopes,
9
+ :mutations,
10
+ :parser,
11
+ :selector,
12
+ :subjects
13
+ )
14
+
15
+ SEMANTICS_MESSAGE =
16
+ "Fix your lib to follow normal ruby semantics!\n" \
17
+ '{Module,Class}#name should return resolvable constant name as String or nil'.freeze
18
+
19
+ # Kill mutation
20
+ #
21
+ # @param [Mutation] mutation
22
+ #
23
+ # @return [Result::Mutation]
24
+ def kill(mutation)
25
+ test_result = run_mutation_tests(mutation)
26
+ Result::Mutation.new(
27
+ mutation: mutation,
28
+ test_result: test_result
29
+ )
30
+ end
31
+
32
+ private
33
+
34
+ # Kill mutation under isolation with integration
35
+ #
36
+ # @param [Isolation] isolation
37
+ # @param [Integration] integration
38
+ #
39
+ # @return [Result::Test]
40
+ #
41
+ # rubocop:disable MethodLength
42
+ def run_mutation_tests(mutation)
43
+ start = Time.now
44
+ tests = selector.call(mutation.subject)
45
+
46
+ config.isolation.call do
47
+ mutation.insert(config.kernel)
48
+ integration.call(tests)
49
+ end
50
+ rescue Isolation::Error => error
51
+ Result::Test.new(
52
+ output: error.message,
53
+ passed: false,
54
+ runtime: Time.now - start,
55
+ tests: tests
56
+ )
57
+ end
58
+ end # Env
59
+ end # Mutest
@@ -0,0 +1,159 @@
1
+ module Mutest
2
+ class Env
3
+ # Bootstrap environment
4
+ class Bootstrap
5
+ include Adamantium::Flat, Concord::Public.new(:config), Procto.call(:env)
6
+
7
+ SEMANTICS_MESSAGE_FORMAT =
8
+ "%<message>s. Fix your lib to follow normal ruby semantics!\n" \
9
+ '{Module,Class}#name should return resolvable constant name as String or nil'.freeze
10
+
11
+ CLASS_NAME_RAISED_EXCEPTION =
12
+ '%<scope_class>s#name from: %<scope>s raised an error: %<exception>s'.freeze
13
+
14
+ CLASS_NAME_TYPE_MISMATCH_FORMAT =
15
+ '%<scope_class>s#name from: %<scope>s returned %<name>s'.freeze
16
+
17
+ private_constant(*constants(false))
18
+
19
+ # Scopes that are eligible for matching
20
+ #
21
+ # @return [Enumerable<Matcher::Scope>]
22
+ attr_reader :matchable_scopes
23
+
24
+ # Parser for this environment
25
+ #
26
+ # @return [Parser]
27
+ attr_reader :parser
28
+
29
+ # Initialize object
30
+ #
31
+ # @return [Object]
32
+ def initialize(*)
33
+ super
34
+ @parser = Parser.new
35
+ infect
36
+ initialize_matchable_scopes
37
+ end
38
+
39
+ # Print warning message
40
+ #
41
+ # @param [String]
42
+ #
43
+ # @return [self]
44
+ def warn(message)
45
+ config.reporter.warn(message)
46
+ self
47
+ end
48
+
49
+ # Environment after bootstraping
50
+ #
51
+ # @return [Env]
52
+ # rubocop:disable MethodLength
53
+ #
54
+ def env
55
+ subjects = matched_subjects
56
+ Env.new(
57
+ actor_env: Actor::Env.new(Thread),
58
+ config: config,
59
+ integration: integration,
60
+ matchable_scopes: matchable_scopes,
61
+ mutations: subjects.flat_map(&:mutations),
62
+ parser: parser,
63
+ selector: Selector::Expression.new(integration),
64
+ subjects: subjects
65
+ )
66
+ end
67
+
68
+ private
69
+
70
+ # Configured mutest integration
71
+ #
72
+ # @return [Mutest::Integration]
73
+ attr_reader :integration
74
+
75
+ # Scope name from scoping object
76
+ #
77
+ # @param [Class, Module] scope
78
+ #
79
+ # @return [String]
80
+ # if scope has a name and does not raise exceptions obtaining it
81
+ #
82
+ # @return [nil]
83
+ # otherwise
84
+ def scope_name(scope)
85
+ scope.name
86
+ rescue => exception
87
+ semantics_warning(
88
+ CLASS_NAME_RAISED_EXCEPTION,
89
+ exception: exception.inspect,
90
+ scope: scope,
91
+ scope_class: scope.class
92
+ )
93
+ nil
94
+ end
95
+
96
+ # Infect environment
97
+ #
98
+ # @return [undefined]
99
+ def infect
100
+ config.includes.each(&config.load_path.method(:<<))
101
+ config.requires.each(&config.kernel.method(:require))
102
+ @integration = config.integration.new(config).setup
103
+ end
104
+
105
+ # Matched subjects
106
+ #
107
+ # @return [Enumerable<Subject>]
108
+ def matched_subjects
109
+ Matcher::Compiler.call(config.matcher).call(self)
110
+ end
111
+
112
+ # Initialize matchable scopes
113
+ #
114
+ # @return [undefined]
115
+ def initialize_matchable_scopes
116
+ scopes =
117
+ ObjectSpace.each_object(Module).each_with_object([]) do |scope, aggregate|
118
+ expression = expression(scope) || next
119
+ aggregate << Scope.new(scope, expression)
120
+ end
121
+
122
+ @matchable_scopes = scopes.sort_by { |scope| scope.expression.syntax }
123
+ end
124
+
125
+ # Try to turn scope into expression
126
+ #
127
+ # @param [Class, Module] scope
128
+ #
129
+ # @return [Expression]
130
+ # if scope can be represented in an expression
131
+ #
132
+ # @return [nil]
133
+ # otherwise
134
+ def expression(scope)
135
+ name = scope_name(scope) or return
136
+
137
+ unless name.instance_of?(String)
138
+ semantics_warning(
139
+ CLASS_NAME_TYPE_MISMATCH_FORMAT,
140
+ name: name,
141
+ scope_class: scope.class,
142
+ scope: scope
143
+ )
144
+ return
145
+ end
146
+
147
+ config.expression_parser.try_parse(name)
148
+ end
149
+
150
+ # Write a semantics warning
151
+ #
152
+ # @return [undefined]
153
+ def semantics_warning(format, options)
154
+ message = format % options
155
+ warn(format(SEMANTICS_MESSAGE_FORMAT, message: message))
156
+ end
157
+ end # Bootstrap
158
+ end # Env
159
+ end # Mutest