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,8 @@
1
+ require 'ice_nine'
2
+
3
+ module IceNine
4
+ class Freezer
5
+ class RSpec < NoFreeze
6
+ end # RSpec
7
+ end # Freezer
8
+ end # IceNine
@@ -0,0 +1,15 @@
1
+ require 'ffi'
2
+
3
+ # @api private
4
+ module RbBug
5
+ extend FFI::Library
6
+ ffi_lib 'ruby'
7
+ attach_function :rb_bug, %i[string varargs], :void
8
+
9
+ # Call the test bug
10
+ #
11
+ # @return [undefined]
12
+ def self.call
13
+ rb_bug('%s', :string, 'test bug')
14
+ end
15
+ end # RbBug
@@ -0,0 +1,82 @@
1
+ module MutestSpec
2
+ # Not a real VM, just kidding. It connects the require / eval triggers
3
+ # require semantics Zombifier relies on in a way we can avoid having to
4
+ # mock around everywhere to test every detail.
5
+ class RubyVM
6
+ include Concord::Public.new(:expected_events)
7
+
8
+ # An event being observed by the VM handlers
9
+ class EventObservation
10
+ include Concord::Public.new(:type, :payload)
11
+ end # EventObservation
12
+
13
+ # An event being expected, can advance the VM
14
+ class EventExpectation
15
+ include AbstractType, Anima.new(
16
+ :expected_payload,
17
+ :trigger_requires,
18
+ :return_value
19
+ )
20
+
21
+ DEFAULTS = IceNine.deep_freeze(trigger_requires: [])
22
+
23
+ def initialize(attributes)
24
+ super(DEFAULTS.merge(attributes))
25
+ end
26
+
27
+ def handle(vm, observation)
28
+ unless match?(observation)
29
+ fail "Unexpected event observation: #{observation.inspect}, expected #{inspect}"
30
+ end
31
+
32
+ trigger_requires.each(&vm.method(:require))
33
+
34
+ self
35
+ end
36
+
37
+ private
38
+
39
+ def match?(observation)
40
+ observation.type.eql?(self.class) && observation.payload.eql?(expected_payload)
41
+ end
42
+
43
+ # Expectation and advance on require calls
44
+ class Require < self
45
+ end # Require
46
+
47
+ # Expectation and advance on eval calls
48
+ class Eval < self
49
+ end # Eval
50
+ end # EventExpectation
51
+
52
+ # A fake implementation of Kernel#require
53
+ def require(logical_name)
54
+ handle_event(EventObservation.new(EventExpectation::Require, logical_name: logical_name))
55
+ end
56
+
57
+ # A fake implementation of Kernel#eval
58
+ def eval(source, binding, location)
59
+ handle_event(
60
+ EventObservation.new(
61
+ EventExpectation::Eval,
62
+ binding: binding,
63
+ source: source,
64
+ source_location: location
65
+ )
66
+ )
67
+ end
68
+
69
+ # Test if VM events where fully processed
70
+ def done?
71
+ expected_events.empty?
72
+ end
73
+
74
+ private
75
+
76
+ def handle_event(observation)
77
+ fail "Unexpected event: #{observation.type} / #{observation.payload}" if expected_events.empty?
78
+
79
+ expected_events.slice!(0).handle(self, observation).return_value
80
+ end
81
+ end # RubyVM
82
+ end # MutestSpec
@@ -0,0 +1,125 @@
1
+ # rubocop:disable ModuleLength
2
+ module SharedContext
3
+ # Prepend an anonymous module with the new `with` method
4
+ #
5
+ # Using an anonymous module eliminates warnings where `setup_shared_context`
6
+ # is used and one of the shared methods is immediately redefined.
7
+ def with(name, &block)
8
+ new_definition =
9
+ Module.new do
10
+ define_method(name) do
11
+ super().with(instance_eval(&block))
12
+ end
13
+ end
14
+
15
+ prepend(new_definition)
16
+ end
17
+
18
+ def messages(&block)
19
+ let(:message_sequence) do
20
+ FakeActor::MessageSequence.new.tap do |sequence|
21
+ sequence.instance_eval(&block)
22
+ end
23
+ end
24
+ end
25
+
26
+ def it_reports(expected_content)
27
+ it 'writes expected report to output' do
28
+ described_class.call(output, reportable)
29
+ output.rewind
30
+ expect(output.read).to eql(strip_indent(expected_content))
31
+ end
32
+ end
33
+
34
+ # rubocop:disable MethodLength
35
+ # rubocop:disable AbcSize
36
+ def setup_shared_context
37
+ let(:env) { instance_double(Mutest::Env, config: config, subjects: [subject_a], mutations: mutations) }
38
+ let(:job_a) { Mutest::Parallel::Job.new(index: 0, payload: mutation_a) }
39
+ let(:job_b) { Mutest::Parallel::Job.new(index: 1, payload: mutation_b) }
40
+ let(:test_a) { instance_double(Mutest::Test, identification: 'test-a') }
41
+ let(:output) { StringIO.new }
42
+ let(:mutations) { [mutation_a, mutation_b] }
43
+ let(:mutation_a_node) { s(:false) }
44
+ let(:mutation_b_node) { s(:nil) }
45
+ let(:mutation_b) { Mutest::Mutation::Evil.new(subject_a, mutation_b_node) }
46
+ let(:mutation_a) { Mutest::Mutation::Evil.new(subject_a, mutation_a_node) }
47
+ let(:subject_a_node) { s(:true) }
48
+
49
+ let(:status) do
50
+ Mutest::Parallel::Status.new(
51
+ active_jobs: [].to_set,
52
+ payload: env_result,
53
+ done: true
54
+ )
55
+ end
56
+
57
+ let(:config) do
58
+ Mutest::Config::DEFAULT.with(
59
+ jobs: 1,
60
+ reporter: Mutest::Reporter::Null.new
61
+ )
62
+ end
63
+
64
+ let(:subject_a) do
65
+ instance_double(
66
+ Mutest::Subject,
67
+ node: subject_a_node,
68
+ source: Unparser.unparse(subject_a_node),
69
+ identification: 'subject-a'
70
+ )
71
+ end
72
+
73
+ before do
74
+ allow(subject_a).to receive(:mutations).and_return([mutation_a, mutation_b])
75
+ end
76
+
77
+ let(:env_result) do
78
+ Mutest::Result::Env.new(
79
+ env: env,
80
+ runtime: 4.0,
81
+ subject_results: [subject_a_result]
82
+ )
83
+ end
84
+
85
+ let(:mutation_a_result) do
86
+ Mutest::Result::Mutation.new(
87
+ mutation: mutation_a,
88
+ test_result: mutation_a_test_result
89
+ )
90
+ end
91
+
92
+ let(:mutation_b_result) do
93
+ Mutest::Result::Mutation.new(
94
+ mutation: mutation_a,
95
+ test_result: mutation_b_test_result
96
+ )
97
+ end
98
+
99
+ let(:mutation_a_test_result) do
100
+ Mutest::Result::Test.new(
101
+ tests: [test_a],
102
+ passed: false,
103
+ runtime: 1.0,
104
+ output: 'mutation a test result output'
105
+ )
106
+ end
107
+
108
+ let(:mutation_b_test_result) do
109
+ Mutest::Result::Test.new(
110
+ tests: [test_a],
111
+ passed: false,
112
+ runtime: 1.0,
113
+ output: 'mutation b test result output'
114
+ )
115
+ end
116
+
117
+ let(:subject_a_result) do
118
+ Mutest::Result::Subject.new(
119
+ subject: subject_a,
120
+ tests: [test_a],
121
+ mutation_results: [mutation_a_result, mutation_b_result]
122
+ )
123
+ end
124
+ end
125
+ end # SharedContext
@@ -0,0 +1,5 @@
1
+ module TestApp
2
+ def self.root
3
+ File.expand_path('../../../test_app', __FILE__)
4
+ end
5
+ end # TestApp
@@ -0,0 +1,73 @@
1
+ require 'yaml'
2
+ require 'equalizer'
3
+ require 'memoizable'
4
+ require 'ice_nine'
5
+
6
+ module MutestSpec
7
+ class Warning
8
+ # Install our $stderr warning proxy only if the top level program is RSpec
9
+ #
10
+ # Mutest performs certain mutations which emit warnings that will obviously
11
+ # not be on our whitelist. We don't need to have enforce our warning assertions
12
+ # then anyways
13
+ def self.hook_under_rspec
14
+ $stderr = EXTRACTOR if $PROGRAM_NAME.end_with?('/rspec')
15
+ end
16
+
17
+ def self.assert_no_warnings
18
+ return if EXTRACTOR.warnings.empty?
19
+
20
+ fail UnexpectedWarnings, EXTRACTOR.warnings.to_a
21
+ end
22
+
23
+ class UnexpectedWarnings < StandardError
24
+ MSG = 'Unexpected warnings: %s'.freeze
25
+
26
+ def initialize(warnings)
27
+ super(MSG % warnings.join("\n"))
28
+ end
29
+ end # UnexpectedWarnings
30
+
31
+ class Extractor < DelegateClass(IO)
32
+ PATTERN = /\A(?:.+):(?:\d+): warning: (?:.+)\n\z/
33
+
34
+ include Equalizer.new(:whitelist, :seen, :io), Memoizable
35
+
36
+ def initialize(io, whitelist)
37
+ @whitelist = whitelist
38
+ @seen = Set.new
39
+ @io = io
40
+
41
+ super(io)
42
+ end
43
+
44
+ def write(message)
45
+ return super if PATTERN !~ message
46
+
47
+ add(message.chomp)
48
+
49
+ self
50
+ end
51
+
52
+ def warnings
53
+ seen.dup
54
+ end
55
+ memoize :warnings
56
+
57
+ private
58
+
59
+ def add(warning)
60
+ return if whitelist.any?(&warning.public_method(:end_with?))
61
+
62
+ seen << warning
63
+ end
64
+
65
+ attr_reader :whitelist, :seen, :io
66
+ end # Extractor
67
+
68
+ warnings = Pathname.new(__dir__).join('warnings.yml').freeze
69
+ whitelist = IceNine.deep_freeze(YAML.safe_load(warnings.read))
70
+
71
+ EXTRACTOR = Extractor.new(STDERR, whitelist)
72
+ end # Warning
73
+ end # MutestSpec
@@ -0,0 +1,5 @@
1
+ ---
2
+ - 'lib/parser/lexer.rb:10922: warning: assigned but unused variable - testEof'
3
+ - 'lib/parser/source/rewriter.rb:392: warning: assigned but unused variable - begin_pos'
4
+ - 'lib/regexp_parser/scanner.rb:1646: warning: assigned but unused variable - testEof'
5
+ - 'lib/regexp_parser/scanner.rb:1674: warning: assigned but unused variable - testEof'
@@ -0,0 +1,175 @@
1
+ module XSpec
2
+ class MessageReaction
3
+ include Concord.new(:event_list)
4
+
5
+ TERMINATE_EVENTS = IceNine.deep_freeze(%i[return exception].to_set)
6
+ VALID_EVENTS = IceNine.deep_freeze(%i[return exception yields].to_set)
7
+
8
+ private_constant(*constants(false))
9
+
10
+ def call(observation)
11
+ event_list.map do |event, object|
12
+ __send__(event, observation, object)
13
+ end.last
14
+ end
15
+
16
+ # Parse events into reaction
17
+ #
18
+ # @param [Array{Symbol,Object}, Hash{Symbol,Object}]
19
+ #
20
+ # @return [MessageReaction]
21
+ def self.parse(events)
22
+ event_list = events.to_a
23
+ assert_valid(event_list)
24
+ new(event_list)
25
+ end
26
+
27
+ private
28
+
29
+ def return(_, value)
30
+ value
31
+ end
32
+
33
+ def exception(_, exception)
34
+ fail exception
35
+ end
36
+
37
+ def yields(observation, yields)
38
+ block = observation.block or fail 'No block passed where expected'
39
+
40
+ validate_block_arity(observation, yields)
41
+
42
+ block.call(*yields)
43
+ end
44
+
45
+ def validate_block_arity(observation, yields)
46
+ expected = yields.length
47
+ observed = observation.block.arity
48
+
49
+ # block allows anything we can skip the check
50
+ return if observed.equal?(-1)
51
+ fail 'Optargs currently not supported' if observed < -1
52
+ block_arity_mismatch(observation, expected, observed) unless expected.equal?(observed)
53
+ end
54
+
55
+ def block_arity_mismatch(observation, expected, observed)
56
+ fail "block arity mismatch, expected #{expected} observed #{observed}\nobservation:\n#{observation.inspect}"
57
+ end
58
+
59
+ alias_method :yields_return, :yields
60
+
61
+ def self.assert_valid(event_list)
62
+ assert_not_empty(event_list)
63
+ assert_valid_events(event_list)
64
+ assert_total(event_list)
65
+ end
66
+ private_class_method :assert_valid
67
+
68
+ def self.assert_valid_events(event_list)
69
+ event_list.map(&:first).each do |event|
70
+ fail "Invalid event: #{event}" unless VALID_EVENTS.include?(event)
71
+ end
72
+ end
73
+ private_class_method :assert_valid_events
74
+
75
+ def self.assert_not_empty(event_list)
76
+ fail 'no events' if event_list.empty?
77
+ end
78
+ private_class_method :assert_not_empty
79
+
80
+ def self.assert_total(event_list)
81
+ return unless event_list[0..-2].map(&:first).any?(&TERMINATE_EVENTS.method(:include?))
82
+
83
+ fail "Reaction not total: #{event_list}"
84
+ end
85
+ private_class_method :assert_total
86
+ end # MessageReaction
87
+
88
+ class MessageExpectation
89
+ include Anima.new(:receiver, :selector, :arguments, :reaction)
90
+ def self.parse(receiver:, selector:, arguments: [], reaction: nil)
91
+ new(
92
+ receiver: receiver,
93
+ selector: selector,
94
+ arguments: arguments,
95
+ reaction: MessageReaction.parse(reaction || { return: nil })
96
+ )
97
+ end
98
+
99
+ def call(observation)
100
+ Verifier.new(self, observation).call
101
+ end
102
+
103
+ class Verifier
104
+ include Concord.new(:expectation, :observation)
105
+
106
+ VERIFIED_ATTRIBUTES = IceNine.deep_freeze(%i[receiver selector arguments])
107
+
108
+ def call
109
+ VERIFIED_ATTRIBUTES.each(&method(:assert_expected_attribute))
110
+
111
+ expectation.reaction.call(observation)
112
+ end
113
+
114
+ private
115
+
116
+ def assert_expected_attribute(name)
117
+ error("#{name} mismatch") unless observation.public_send(name).eql?(expectation.public_send(name))
118
+ end
119
+
120
+ def error(message)
121
+ fail "#{message},\n observation:\n #{observation.inspect}\n expectation:\n #{expectation.inspect}"
122
+ end
123
+
124
+ def trigger_exception
125
+ exception = expectation.exception
126
+ fail exception if exception
127
+ end
128
+ end # Verifier
129
+ end # MessageExpectation
130
+
131
+ class MessageObservation
132
+ include Anima.new(:receiver, :selector, :arguments, :block)
133
+ end # MessageObservation
134
+
135
+ class ExpectationVerifier
136
+ include Concord.new(:expectations)
137
+
138
+ def call(observation)
139
+ expectation = expectations.shift or fail "No expected message but observed #{observation}"
140
+ expectation.call(observation)
141
+ end
142
+
143
+ def assert_done
144
+ expectations.empty? or fail "unconsumed expectations:\n#{expectations.map(&:inspect).join}"
145
+ end
146
+
147
+ # rubocop:disable MethodLength
148
+ def self.verify(rspec_context, expectations)
149
+ verifier = new(expectations)
150
+
151
+ hooks = expectations
152
+ .map { |expectation| [expectation.receiver, expectation.selector] }
153
+ .to_set
154
+
155
+ hooks.each do |receiver, selector|
156
+ rspec_context.instance_eval do
157
+ allow(receiver).to receive(selector) do |*arguments, &block|
158
+ verifier.call(
159
+ MessageObservation.new(
160
+ receiver: receiver,
161
+ selector: selector,
162
+ arguments: arguments,
163
+ block: block
164
+ )
165
+ )
166
+ end
167
+ end
168
+ end
169
+
170
+ yield
171
+
172
+ verifier.assert_done
173
+ end
174
+ end # ExpectationVerifier
175
+ end # XSpec