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.
- checksums.yaml +4 -4
- data/.buildkite/hooks/pre-command +3 -0
- data/.buildkite/pipeline.yml +51 -0
- data/.gitattributes +1 -0
- data/.gitignore +38 -0
- data/.rspec +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +216 -0
- data/Gemfile.shared +3 -0
- data/LICENSE +21 -0
- data/README.md +8 -0
- data/Rakefile +24 -0
- data/bin/mutest +39 -0
- data/build/Dockerfile +71 -0
- data/build/docker-bootstrap.sh +85 -0
- data/build/docker-exec +29 -0
- data/build/make-docker +3 -0
- data/build/ruby_matrix +1 -0
- data/build/run +5 -0
- data/build/strict-mode.sh +16 -0
- data/circle.yml +7 -0
- data/config/devtools.yml +2 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/reek.yml +137 -0
- data/config/rubocop.yml +395 -0
- data/config/triage.yml +2 -0
- data/config/yardstick.yml +2 -0
- data/lib/mutest.rb +243 -0
- data/lib/mutest/actor.rb +52 -0
- data/lib/mutest/actor/env.rb +28 -0
- data/lib/mutest/actor/mailbox.rb +31 -0
- data/lib/mutest/actor/receiver.rb +39 -0
- data/lib/mutest/actor/sender.rb +22 -0
- data/lib/mutest/ast.rb +44 -0
- data/lib/mutest/ast/meta.rb +7 -0
- data/lib/mutest/ast/meta/const.rb +22 -0
- data/lib/mutest/ast/meta/optarg.rb +24 -0
- data/lib/mutest/ast/meta/resbody.rb +15 -0
- data/lib/mutest/ast/meta/restarg.rb +15 -0
- data/lib/mutest/ast/meta/send.rb +89 -0
- data/lib/mutest/ast/meta/symbol.rb +15 -0
- data/lib/mutest/ast/named_children.rb +86 -0
- data/lib/mutest/ast/node_predicates.rb +17 -0
- data/lib/mutest/ast/nodes.rb +22 -0
- data/lib/mutest/ast/regexp.rb +50 -0
- data/lib/mutest/ast/regexp/transformer.rb +184 -0
- data/lib/mutest/ast/regexp/transformer/alternative.rb +39 -0
- data/lib/mutest/ast/regexp/transformer/character_set.rb +46 -0
- data/lib/mutest/ast/regexp/transformer/direct.rb +101 -0
- data/lib/mutest/ast/regexp/transformer/options_group.rb +65 -0
- data/lib/mutest/ast/regexp/transformer/quantifier.rb +112 -0
- data/lib/mutest/ast/regexp/transformer/recursive.rb +50 -0
- data/lib/mutest/ast/regexp/transformer/root.rb +28 -0
- data/lib/mutest/ast/regexp/transformer/text.rb +55 -0
- data/lib/mutest/ast/sexp.rb +26 -0
- data/lib/mutest/ast/types.rb +140 -0
- data/lib/mutest/cli.rb +196 -0
- data/lib/mutest/color.rb +39 -0
- data/lib/mutest/config.rb +28 -0
- data/lib/mutest/context.rb +98 -0
- data/lib/mutest/diff.rb +111 -0
- data/lib/mutest/env.rb +59 -0
- data/lib/mutest/env/bootstrap.rb +159 -0
- data/lib/mutest/expression.rb +55 -0
- data/lib/mutest/expression/method.rb +54 -0
- data/lib/mutest/expression/methods.rb +58 -0
- data/lib/mutest/expression/namespace.rb +75 -0
- data/lib/mutest/expression/parser.rb +64 -0
- data/lib/mutest/integration.rb +75 -0
- data/lib/mutest/isolation.rb +11 -0
- data/lib/mutest/isolation/fork.rb +72 -0
- data/lib/mutest/isolation/none.rb +23 -0
- data/lib/mutest/loader.rb +27 -0
- data/lib/mutest/matcher.rb +14 -0
- data/lib/mutest/matcher/chain.rb +19 -0
- data/lib/mutest/matcher/compiler.rb +55 -0
- data/lib/mutest/matcher/config.rb +81 -0
- data/lib/mutest/matcher/filter.rb +19 -0
- data/lib/mutest/matcher/method.rb +138 -0
- data/lib/mutest/matcher/method/instance.rb +63 -0
- data/lib/mutest/matcher/method/singleton.rb +88 -0
- data/lib/mutest/matcher/methods.rb +109 -0
- data/lib/mutest/matcher/namespace.rb +41 -0
- data/lib/mutest/matcher/null.rb +17 -0
- data/lib/mutest/matcher/scope.rb +38 -0
- data/lib/mutest/matcher/static.rb +15 -0
- data/lib/mutest/meta.rb +33 -0
- data/lib/mutest/meta/example.rb +32 -0
- data/lib/mutest/meta/example/dsl.rb +107 -0
- data/lib/mutest/meta/example/verification.rb +85 -0
- data/lib/mutest/mutation.rb +101 -0
- data/lib/mutest/mutator.rb +117 -0
- data/lib/mutest/mutator/node.rb +166 -0
- data/lib/mutest/mutator/node/and_asgn.rb +25 -0
- data/lib/mutest/mutator/node/argument.rb +68 -0
- data/lib/mutest/mutator/node/arguments.rb +90 -0
- data/lib/mutest/mutator/node/begin.rb +21 -0
- data/lib/mutest/mutator/node/binary.rb +64 -0
- data/lib/mutest/mutator/node/block.rb +51 -0
- data/lib/mutest/mutator/node/break.rb +21 -0
- data/lib/mutest/mutator/node/case.rb +47 -0
- data/lib/mutest/mutator/node/class.rb +21 -0
- data/lib/mutest/mutator/node/conditional_loop.rb +25 -0
- data/lib/mutest/mutator/node/const.rb +23 -0
- data/lib/mutest/mutator/node/define.rb +79 -0
- data/lib/mutest/mutator/node/defined.rb +24 -0
- data/lib/mutest/mutator/node/dstr.rb +20 -0
- data/lib/mutest/mutator/node/dsym.rb +20 -0
- data/lib/mutest/mutator/node/generic.rb +77 -0
- data/lib/mutest/mutator/node/if.rb +57 -0
- data/lib/mutest/mutator/node/kwbegin.rb +20 -0
- data/lib/mutest/mutator/node/literal.rb +19 -0
- data/lib/mutest/mutator/node/literal/array.rb +37 -0
- data/lib/mutest/mutator/node/literal/boolean.rb +27 -0
- data/lib/mutest/mutator/node/literal/fixnum.rb +36 -0
- data/lib/mutest/mutator/node/literal/float.rb +45 -0
- data/lib/mutest/mutator/node/literal/hash.rb +52 -0
- data/lib/mutest/mutator/node/literal/nil.rb +20 -0
- data/lib/mutest/mutator/node/literal/range.rb +38 -0
- data/lib/mutest/mutator/node/literal/regex.rb +76 -0
- data/lib/mutest/mutator/node/literal/string.rb +21 -0
- data/lib/mutest/mutator/node/literal/symbol.rb +26 -0
- data/lib/mutest/mutator/node/masgn.rb +21 -0
- data/lib/mutest/mutator/node/match_current_line.rb +22 -0
- data/lib/mutest/mutator/node/mlhs.rb +21 -0
- data/lib/mutest/mutator/node/named_value/access.rb +54 -0
- data/lib/mutest/mutator/node/named_value/constant_assignment.rb +42 -0
- data/lib/mutest/mutator/node/named_value/variable_assignment.rb +47 -0
- data/lib/mutest/mutator/node/next.rb +22 -0
- data/lib/mutest/mutator/node/noop.rb +19 -0
- data/lib/mutest/mutator/node/nthref.rb +22 -0
- data/lib/mutest/mutator/node/op_asgn.rb +50 -0
- data/lib/mutest/mutator/node/or_asgn.rb +26 -0
- data/lib/mutest/mutator/node/regexp.rb +33 -0
- data/lib/mutest/mutator/node/regexp/alternation_meta.rb +21 -0
- data/lib/mutest/mutator/node/regexp/capture_group.rb +26 -0
- data/lib/mutest/mutator/node/regexp/character_type.rb +29 -0
- data/lib/mutest/mutator/node/regexp/end_of_line_anchor.rb +21 -0
- data/lib/mutest/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +21 -0
- data/lib/mutest/mutator/node/regexp/one_or_more.rb +29 -0
- data/lib/mutest/mutator/node/regexp/zero_or_more.rb +29 -0
- data/lib/mutest/mutator/node/regopt.rb +28 -0
- data/lib/mutest/mutator/node/resbody.rb +34 -0
- data/lib/mutest/mutator/node/rescue.rb +69 -0
- data/lib/mutest/mutator/node/return.rb +24 -0
- data/lib/mutest/mutator/node/send.rb +270 -0
- data/lib/mutest/mutator/node/send/attribute_assignment.rb +39 -0
- data/lib/mutest/mutator/node/send/binary.rb +45 -0
- data/lib/mutest/mutator/node/send/conditional.rb +21 -0
- data/lib/mutest/mutator/node/send/index.rb +47 -0
- data/lib/mutest/mutator/node/splat.rb +23 -0
- data/lib/mutest/mutator/node/super.rb +24 -0
- data/lib/mutest/mutator/node/when.rb +60 -0
- data/lib/mutest/mutator/node/yield.rb +21 -0
- data/lib/mutest/mutator/node/zsuper.rb +20 -0
- data/lib/mutest/mutator/util.rb +11 -0
- data/lib/mutest/mutator/util/array.rb +42 -0
- data/lib/mutest/mutator/util/symbol.rb +19 -0
- data/lib/mutest/parallel.rb +89 -0
- data/lib/mutest/parallel/master.rb +181 -0
- data/lib/mutest/parallel/source.rb +57 -0
- data/lib/mutest/parallel/worker.rb +76 -0
- data/lib/mutest/parser.rb +22 -0
- data/lib/mutest/registry.rb +43 -0
- data/lib/mutest/reporter.rb +39 -0
- data/lib/mutest/reporter/cli.rb +87 -0
- data/lib/mutest/reporter/cli/format.rb +135 -0
- data/lib/mutest/reporter/cli/printer.rb +124 -0
- data/lib/mutest/reporter/cli/printer/config.rb +24 -0
- data/lib/mutest/reporter/cli/printer/env_progress.rb +76 -0
- data/lib/mutest/reporter/cli/printer/env_result.rb +20 -0
- data/lib/mutest/reporter/cli/printer/mutation_progress_result.rb +31 -0
- data/lib/mutest/reporter/cli/printer/mutation_result.rb +127 -0
- data/lib/mutest/reporter/cli/printer/status.rb +49 -0
- data/lib/mutest/reporter/cli/printer/status_progressive.rb +46 -0
- data/lib/mutest/reporter/cli/printer/subject_progress.rb +65 -0
- data/lib/mutest/reporter/cli/printer/subject_result.rb +23 -0
- data/lib/mutest/reporter/cli/printer/test_result.rb +28 -0
- data/lib/mutest/reporter/cli/tput.rb +43 -0
- data/lib/mutest/reporter/null.rb +14 -0
- data/lib/mutest/reporter/sequence.rb +24 -0
- data/lib/mutest/repository.rb +80 -0
- data/lib/mutest/require_highjack.rb +24 -0
- data/lib/mutest/result.rb +212 -0
- data/lib/mutest/runner.rb +81 -0
- data/lib/mutest/runner/sink.rb +63 -0
- data/lib/mutest/scope.rb +6 -0
- data/lib/mutest/selector.rb +13 -0
- data/lib/mutest/selector/expression.rb +25 -0
- data/lib/mutest/source_file.rb +47 -0
- data/lib/mutest/subject.rb +94 -0
- data/lib/mutest/subject/method.rb +42 -0
- data/lib/mutest/subject/method/instance.rb +43 -0
- data/lib/mutest/subject/method/singleton.rb +19 -0
- data/lib/mutest/test.rb +14 -0
- data/lib/mutest/util.rb +18 -0
- data/lib/mutest/version.rb +4 -0
- data/lib/mutest/warning_filter.rb +58 -0
- data/lib/mutest/zombifier.rb +119 -0
- data/meta/and.rb +13 -0
- data/meta/and_asgn.rb +12 -0
- data/meta/array.rb +28 -0
- data/meta/begin.rb +19 -0
- data/meta/block.rb +104 -0
- data/meta/block_pass.rb +6 -0
- data/meta/blockarg.rb +8 -0
- data/meta/break.rb +8 -0
- data/meta/case.rb +221 -0
- data/meta/casgn.rb +26 -0
- data/meta/cbase.rb +6 -0
- data/meta/class.rb +10 -0
- data/meta/const.rb +15 -0
- data/meta/csend.rb +8 -0
- data/meta/cvar.rb +5 -0
- data/meta/cvasgn.rb +8 -0
- data/meta/date.rb +57 -0
- data/meta/def.rb +260 -0
- data/meta/defined.rb +7 -0
- data/meta/dstr.rb +11 -0
- data/meta/dsym.rb +12 -0
- data/meta/ensure.rb +7 -0
- data/meta/false.rb +6 -0
- data/meta/float.rb +35 -0
- data/meta/gvar.rb +5 -0
- data/meta/gvasgn.rb +8 -0
- data/meta/hash.rb +22 -0
- data/meta/if.rb +75 -0
- data/meta/int.rb +16 -0
- data/meta/ivar.rb +6 -0
- data/meta/ivasgn.rb +21 -0
- data/meta/kwarg.rb +8 -0
- data/meta/kwbegin.rb +7 -0
- data/meta/kwoptarg.rb +11 -0
- data/meta/kwrestarg.rb +17 -0
- data/meta/lvar.rb +14 -0
- data/meta/lvasgn.rb +8 -0
- data/meta/masgn.rb +5 -0
- data/meta/match_current_line.rb +13 -0
- data/meta/next.rb +9 -0
- data/meta/nil.rb +3 -0
- data/meta/nthref.rb +12 -0
- data/meta/op_assgn.rb +39 -0
- data/meta/or.rb +13 -0
- data/meta/or_asgn.rb +48 -0
- data/meta/range.rb +37 -0
- data/meta/redo.rb +3 -0
- data/meta/regexp.rb +84 -0
- data/meta/regexp/character_types.rb +20 -0
- data/meta/regexp/regexp_alternation_meta.rb +11 -0
- data/meta/regexp/regexp_bol_anchor.rb +8 -0
- data/meta/regexp/regexp_bos_anchor.rb +16 -0
- data/meta/regexp/regexp_capture_group.rb +17 -0
- data/meta/regexp/regexp_eol_anchor.rb +8 -0
- data/meta/regexp/regexp_eos_anchor.rb +6 -0
- data/meta/regexp/regexp_eos_ob_eol_anchor.rb +8 -0
- data/meta/regexp/regexp_one_or_more.rb +32 -0
- data/meta/regexp/regexp_root_expression.rb +8 -0
- data/meta/regexp/regexp_zero_or_more.rb +32 -0
- data/meta/regopt.rb +8 -0
- data/meta/rescue.rb +87 -0
- data/meta/restarg.rb +9 -0
- data/meta/return.rb +14 -0
- data/meta/self.rb +5 -0
- data/meta/send.rb +849 -0
- data/meta/str.rb +5 -0
- data/meta/super.rb +25 -0
- data/meta/sym.rb +6 -0
- data/meta/true.rb +6 -0
- data/meta/until.rb +15 -0
- data/meta/while.rb +24 -0
- data/meta/yield.rb +8 -0
- data/mutest-rspec.gemspec +22 -0
- data/mutest.gemspec +45 -0
- data/spec/integration/mutest/corpus_spec.rb +18 -0
- data/spec/integration/mutest/isolation/fork_spec.rb +8 -0
- data/spec/integration/mutest/null_spec.rb +13 -0
- data/spec/integration/mutest/rspec_spec.rb +11 -0
- data/spec/integration/mutest/test_mutator_handles_types_spec.rb +7 -0
- data/spec/integrations.yml +32 -0
- data/spec/rcov.opts +7 -0
- data/spec/shared/framework_integration_behavior.rb +44 -0
- data/spec/shared/method_matcher_behavior.rb +49 -0
- data/spec/spec_helper.rb +70 -0
- data/spec/support/compress_helper.rb +9 -0
- data/spec/support/corpus.rb +331 -0
- data/spec/support/fake_actor.rb +107 -0
- data/spec/support/file_system.rb +60 -0
- data/spec/support/ice_nine_config.rb +8 -0
- data/spec/support/rb_bug.rb +15 -0
- data/spec/support/ruby_vm.rb +82 -0
- data/spec/support/shared_context.rb +125 -0
- data/spec/support/test_app.rb +5 -0
- data/spec/support/warning.rb +73 -0
- data/spec/support/warnings.yml +5 -0
- data/spec/support/xspec.rb +175 -0
- data/spec/unit/mutest/actor/binding_spec.rb +32 -0
- data/spec/unit/mutest/actor/env_spec.rb +29 -0
- data/spec/unit/mutest/actor/mailbox_spec.rb +25 -0
- data/spec/unit/mutest/actor/message_spec.rb +22 -0
- data/spec/unit/mutest/actor/receiver_spec.rb +56 -0
- data/spec/unit/mutest/actor/sender_spec.rb +22 -0
- data/spec/unit/mutest/ast/meta/optarg_spec.rb +21 -0
- data/spec/unit/mutest/ast/meta/send/proc_predicate_spec.rb +28 -0
- data/spec/unit/mutest/ast/meta/send/receiver_possible_top_level_const_predicate_spec.rb +37 -0
- data/spec/unit/mutest/ast/meta/send_spec.rb +42 -0
- data/spec/unit/mutest/ast/named_children_spec.rb +87 -0
- data/spec/unit/mutest/ast/regexp/parse_spec.rb +5 -0
- data/spec/unit/mutest/ast/regexp/supported_predicate_spec.rb +14 -0
- data/spec/unit/mutest/ast/regexp/transformer/lookup_table/table_spec.rb +19 -0
- data/spec/unit/mutest/ast/regexp/transformer/lookup_table_spec.rb +33 -0
- data/spec/unit/mutest/ast/regexp/transformer_spec.rb +19 -0
- data/spec/unit/mutest/ast/regexp_spec.rb +625 -0
- data/spec/unit/mutest/ast/sexp_spec.rb +36 -0
- data/spec/unit/mutest/ast_spec.rb +55 -0
- data/spec/unit/mutest/cli_spec.rb +247 -0
- data/spec/unit/mutest/context_spec.rb +141 -0
- data/spec/unit/mutest/diff_spec.rb +185 -0
- data/spec/unit/mutest/env/bootstrap_spec.rb +188 -0
- data/spec/unit/mutest/env_spec.rb +100 -0
- data/spec/unit/mutest/expression/method_spec.rb +44 -0
- data/spec/unit/mutest/expression/methods_spec.rb +59 -0
- data/spec/unit/mutest/expression/namespace/exact_spec.rb +26 -0
- data/spec/unit/mutest/expression/namespace/recursive_spec.rb +64 -0
- data/spec/unit/mutest/expression/parser_spec.rb +67 -0
- data/spec/unit/mutest/expression_spec.rb +45 -0
- data/spec/unit/mutest/integration/null_spec.rb +28 -0
- data/spec/unit/mutest/integration/rspec_spec.rb +197 -0
- data/spec/unit/mutest/integration_spec.rb +26 -0
- data/spec/unit/mutest/isolation/fork_spec.rb +155 -0
- data/spec/unit/mutest/isolation/none_spec.rb +16 -0
- data/spec/unit/mutest/loader_spec.rb +42 -0
- data/spec/unit/mutest/matcher/chain_spec.rb +24 -0
- data/spec/unit/mutest/matcher/compiler/subject_prefix_spec.rb +24 -0
- data/spec/unit/mutest/matcher/compiler_spec.rb +76 -0
- data/spec/unit/mutest/matcher/config_spec.rb +45 -0
- data/spec/unit/mutest/matcher/filter_spec.rb +20 -0
- data/spec/unit/mutest/matcher/method/instance_spec.rb +125 -0
- data/spec/unit/mutest/matcher/method/singleton_spec.rb +85 -0
- data/spec/unit/mutest/matcher/methods/instance_spec.rb +58 -0
- data/spec/unit/mutest/matcher/methods/singleton_spec.rb +54 -0
- data/spec/unit/mutest/matcher/namespace_spec.rb +35 -0
- data/spec/unit/mutest/matcher/null_spec.rb +10 -0
- data/spec/unit/mutest/matcher/scope_spec.rb +33 -0
- data/spec/unit/mutest/matcher/static_spec.rb +11 -0
- data/spec/unit/mutest/meta/example/dsl_spec.rb +123 -0
- data/spec/unit/mutest/meta/example/verification_spec.rb +120 -0
- data/spec/unit/mutest/meta/example_spec.rb +32 -0
- data/spec/unit/mutest/mutation_spec.rb +129 -0
- data/spec/unit/mutest/mutator/node_spec.rb +43 -0
- data/spec/unit/mutest/mutator_spec.rb +30 -0
- data/spec/unit/mutest/parallel/driver_spec.rb +26 -0
- data/spec/unit/mutest/parallel/master_spec.rb +335 -0
- data/spec/unit/mutest/parallel/source/array_spec.rb +47 -0
- data/spec/unit/mutest/parallel/worker_spec.rb +65 -0
- data/spec/unit/mutest/parallel_spec.rb +16 -0
- data/spec/unit/mutest/parser_spec.rb +24 -0
- data/spec/unit/mutest/registry_spec.rb +45 -0
- data/spec/unit/mutest/reporter/cli/printer/config_spec.rb +29 -0
- data/spec/unit/mutest/reporter/cli/printer/env_progress_spec.rb +74 -0
- data/spec/unit/mutest/reporter/cli/printer/env_result_spec.rb +35 -0
- data/spec/unit/mutest/reporter/cli/printer/mutation_progress_result_spec.rb +23 -0
- data/spec/unit/mutest/reporter/cli/printer/mutation_result_spec.rb +110 -0
- data/spec/unit/mutest/reporter/cli/printer/status_progressive_spec.rb +43 -0
- data/spec/unit/mutest/reporter/cli/printer/status_spec.rb +119 -0
- data/spec/unit/mutest/reporter/cli/printer/subject_progress_spec.rb +34 -0
- data/spec/unit/mutest/reporter/cli/printer/subject_result_spec.rb +37 -0
- data/spec/unit/mutest/reporter/cli/printer/test_result_spec.rb +14 -0
- data/spec/unit/mutest/reporter/cli/printer_spec.rb +161 -0
- data/spec/unit/mutest/reporter/cli/tput_spec.rb +48 -0
- data/spec/unit/mutest/reporter/cli_spec.rb +212 -0
- data/spec/unit/mutest/reporter/null_spec.rb +12 -0
- data/spec/unit/mutest/reporter/sequence_spec.rb +29 -0
- data/spec/unit/mutest/repository/diff_spec.rb +106 -0
- data/spec/unit/mutest/repository/subject_filter_spec.rb +28 -0
- data/spec/unit/mutest/require_highjack_spec.rb +71 -0
- data/spec/unit/mutest/result/class_methods_spec.rb +49 -0
- data/spec/unit/mutest/result/env_spec.rb +82 -0
- data/spec/unit/mutest/result/mutation_spec.rb +37 -0
- data/spec/unit/mutest/result/subject_spec.rb +109 -0
- data/spec/unit/mutest/result_spec.rb +31 -0
- data/spec/unit/mutest/runner/sink_spec.rb +172 -0
- data/spec/unit/mutest/runner_spec.rb +69 -0
- data/spec/unit/mutest/selector/expression_spec.rb +59 -0
- data/spec/unit/mutest/source_file_spec.rb +42 -0
- data/spec/unit/mutest/subject/method/instance/memoized_spec.rb +78 -0
- data/spec/unit/mutest/subject/method/instance_spec.rb +64 -0
- data/spec/unit/mutest/subject/method/singleton_spec.rb +51 -0
- data/spec/unit/mutest/subject_spec.rb +87 -0
- data/spec/unit/mutest/util/one_spec.rb +20 -0
- data/spec/unit/mutest/warning_filter_spec.rb +99 -0
- data/spec/unit/mutest/zombifier_spec.rb +120 -0
- data/spec/unit/mutest_spec.rb +15 -0
- data/test_app/.rspec +1 -0
- data/test_app/Gemfile.rspec3.4 +7 -0
- data/test_app/Gemfile.rspec3.5 +7 -0
- data/test_app/lib/test_app.rb +109 -0
- data/test_app/lib/test_app/literal.rb +40 -0
- data/test_app/spec/spec_helper.rb +9 -0
- data/test_app/spec/unit/test_app/literal_spec.rb +20 -0
- metadata +784 -9
|
@@ -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
|