mutiny 0.1.0

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 (100) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +18 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +6 -0
  7. data/Gemfile +5 -0
  8. data/Gemfile.lock +113 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +16 -0
  11. data/RELEASES.md +8 -0
  12. data/Rakefile +23 -0
  13. data/TODO.md +55 -0
  14. data/bin/mutiny +35 -0
  15. data/examples/buggy_calculator/.rspec +2 -0
  16. data/examples/buggy_calculator/lib/calculator/max.rb +9 -0
  17. data/examples/buggy_calculator/lib/calculator.rb +4 -0
  18. data/examples/buggy_calculator/spec/calculator/max_spec.rb +17 -0
  19. data/examples/buggy_calculator/spec/spec_helper.rb +89 -0
  20. data/examples/calculator/.rspec +2 -0
  21. data/examples/calculator/lib/calculator/max.rb +9 -0
  22. data/examples/calculator/lib/calculator/min.rb +9 -0
  23. data/examples/calculator/lib/calculator.rb +5 -0
  24. data/examples/calculator/spec/calculator/max_spec.rb +17 -0
  25. data/examples/calculator/spec/calculator/min_spec.rb +17 -0
  26. data/examples/calculator/spec/spec_helper.rb +89 -0
  27. data/examples/untested_calculator/.rspec +2 -0
  28. data/examples/untested_calculator/lib/calculator/max.rb +9 -0
  29. data/examples/untested_calculator/lib/calculator.rb +4 -0
  30. data/examples/untested_calculator/spec/spec_helper.rb +89 -0
  31. data/lib/mutiny/configuration.rb +25 -0
  32. data/lib/mutiny/integration/rspec/context.rb +26 -0
  33. data/lib/mutiny/integration/rspec/parser.rb +36 -0
  34. data/lib/mutiny/integration/rspec/runner.rb +58 -0
  35. data/lib/mutiny/integration/rspec/test.rb +16 -0
  36. data/lib/mutiny/integration/rspec/test_set.rb +17 -0
  37. data/lib/mutiny/integration/rspec.rb +25 -0
  38. data/lib/mutiny/mode/check.rb +62 -0
  39. data/lib/mutiny/mode/mutate.rb +29 -0
  40. data/lib/mutiny/mode.rb +19 -0
  41. data/lib/mutiny/mutants/mutant.rb +32 -0
  42. data/lib/mutiny/mutants/mutant_set.rb +42 -0
  43. data/lib/mutiny/mutants/mutation/method/binary_arithmetic_operator_replacement.rb +15 -0
  44. data/lib/mutiny/mutants/mutation/method/conditional_operator_deletion.rb +19 -0
  45. data/lib/mutiny/mutants/mutation/method/conditional_operator_insertion.rb +25 -0
  46. data/lib/mutiny/mutants/mutation/method/conditional_operator_replacement.rb +19 -0
  47. data/lib/mutiny/mutants/mutation/method/helpers/infix_operator_replacement.rb +17 -0
  48. data/lib/mutiny/mutants/mutation/method/helpers/operator_replacement.rb +81 -0
  49. data/lib/mutiny/mutants/mutation/method/logical_operator_deletion.rb +19 -0
  50. data/lib/mutiny/mutants/mutation/method/logical_operator_insertion.rb +24 -0
  51. data/lib/mutiny/mutants/mutation/method/logical_operator_replacement.rb +15 -0
  52. data/lib/mutiny/mutants/mutation/method/relational_expression_replacement.rb +19 -0
  53. data/lib/mutiny/mutants/mutation/method/relational_operator_replacement.rb +15 -0
  54. data/lib/mutiny/mutants/mutation/method/shortcut_assignment_operator_replacement.rb +23 -0
  55. data/lib/mutiny/mutants/mutation/method/unary_arithmetic_operator_deletion.rb +29 -0
  56. data/lib/mutiny/mutants/mutation/method/unary_arithmetic_operator_insertion.rb +29 -0
  57. data/lib/mutiny/mutants/mutation.rb +10 -0
  58. data/lib/mutiny/mutants/mutation_set.rb +24 -0
  59. data/lib/mutiny/mutants/ruby.rb +42 -0
  60. data/lib/mutiny/pattern.rb +17 -0
  61. data/lib/mutiny/reporter/stdout.rb +9 -0
  62. data/lib/mutiny/subjects/environment/type.rb +54 -0
  63. data/lib/mutiny/subjects/environment.rb +25 -0
  64. data/lib/mutiny/subjects/subject.rb +32 -0
  65. data/lib/mutiny/subjects/subject_set.rb +17 -0
  66. data/lib/mutiny/subjects.rb +3 -0
  67. data/lib/mutiny/tests/test.rb +12 -0
  68. data/lib/mutiny/tests/test_run.rb +18 -0
  69. data/lib/mutiny/tests/test_set.rb +44 -0
  70. data/lib/mutiny/tests.rb +3 -0
  71. data/lib/mutiny/version.rb +3 -0
  72. data/lib/mutiny.rb +4 -0
  73. data/mutiny.gemspec +32 -0
  74. data/spec/integration/check_spec.rb +39 -0
  75. data/spec/integration/mutate_spec.rb +35 -0
  76. data/spec/spec_helper.rb +38 -0
  77. data/spec/support/aruba.rb +12 -0
  78. data/spec/support/in_example_project.rb +17 -0
  79. data/spec/support/shared_examples/shared_examples_for_an_operator_replacement_mutation.rb +26 -0
  80. data/spec/unit/integration/rspec/parser_spec.rb +23 -0
  81. data/spec/unit/integration/rspec/runner_spec.rb +47 -0
  82. data/spec/unit/mutants/mutant_set_spec.rb +57 -0
  83. data/spec/unit/mutants/mutations/method/binary_operator_replacement_spec.rb +11 -0
  84. data/spec/unit/mutants/mutations/method/conditional_operator_deletion_spec.rb +17 -0
  85. data/spec/unit/mutants/mutations/method/conditional_operator_insertion_spec.rb +17 -0
  86. data/spec/unit/mutants/mutations/method/conditional_operator_replacement_spec.rb +16 -0
  87. data/spec/unit/mutants/mutations/method/logical_operator_deletion_spec.rb +17 -0
  88. data/spec/unit/mutants/mutations/method/logical_operator_insertion_spec.rb +17 -0
  89. data/spec/unit/mutants/mutations/method/logical_operator_replacement_spec.rb +11 -0
  90. data/spec/unit/mutants/mutations/method/relational_expression_replacement_spec.rb +18 -0
  91. data/spec/unit/mutants/mutations/method/relational_operator_replacement_spec.rb +11 -0
  92. data/spec/unit/mutants/mutations/method/shortcut_assignment_operator_replacement_spec.rb +12 -0
  93. data/spec/unit/mutants/mutations/method/unary_arithmetic_operator_deletion_spec.rb +21 -0
  94. data/spec/unit/mutants/mutations/method/unary_arithmetic_operator_insertion_spec.rb +21 -0
  95. data/spec/unit/pattern_spec.rb +28 -0
  96. data/spec/unit/subjects/environment/type_spec.rb +54 -0
  97. data/spec/unit/subjects/environment_spec.rb +71 -0
  98. data/spec/unit/subjects/subject_spec.rb +25 -0
  99. data/spec/unit/subjects/test_set_spec.rb +75 -0
  100. metadata +310 -0
@@ -0,0 +1,24 @@
1
+ require "mutiny/mutants/mutation"
2
+
3
+ module Mutiny
4
+ module Mutants
5
+ class Mutation
6
+ module Method
7
+ class LogicalOperatorInsertion < Mutation
8
+ def pattern
9
+ builder.either!(
10
+ builder.literal!(:int, builder.VAL),
11
+ builder.literal!(:send, nil, builder.VAL)
12
+ )
13
+ end
14
+
15
+ def replacement
16
+ builder.derivation! :& do |root|
17
+ builder.literal!(:send, root, :~)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "helpers/infix_operator_replacement"
2
+
3
+ module Mutiny
4
+ module Mutants
5
+ class Mutation
6
+ module Method
7
+ class LogicalOperatorReplacement < Helpers::InfixOperatorReplacement
8
+ def operator_names
9
+ %i(& | ^)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ require_relative "helpers/infix_operator_replacement"
2
+
3
+ module Mutiny
4
+ module Mutants
5
+ class Mutation
6
+ module Method
7
+ class RelationalExpressionReplacement < Helpers::InfixOperatorReplacement
8
+ def operator_names
9
+ %i(< <= == != >= >)
10
+ end
11
+
12
+ def replacement
13
+ builder.either!(builder.true, builder.false)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "helpers/infix_operator_replacement"
2
+
3
+ module Mutiny
4
+ module Mutants
5
+ class Mutation
6
+ module Method
7
+ class RelationalOperatorReplacement < Helpers::InfixOperatorReplacement
8
+ def operator_names
9
+ %i(< <= == != >= >)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ require_relative "helpers/operator_replacement"
2
+
3
+ module Mutiny
4
+ module Mutants
5
+ class Mutation
6
+ module Method
7
+ class ShortcutAssignmentOperatorReplacement < Helpers::OperatorReplacement
8
+ def infix_operator_root
9
+ :op_asgn
10
+ end
11
+
12
+ def infix_operator_names
13
+ %i(+ - * / % ** & | ^ << >>)
14
+ end
15
+
16
+ def prefix_operator_names
17
+ %i(and_asgn or_asgn)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ require "mutiny/mutants/mutation"
2
+
3
+ module Mutiny
4
+ module Mutants
5
+ class Mutation
6
+ module Method
7
+ class UnaryArithmeticOperatorDeletion < Mutation
8
+ def pattern # rubocop:disable Metrics/AbcSize
9
+ builder.either!(
10
+ builder.literal!(:int, builder.VAL { |val| val.name < 0 }),
11
+ builder.literal!(:float, builder.VAL { |val| val.name < 0 }),
12
+ builder.literal!(:send, builder.VAL, :-@)
13
+ )
14
+ end
15
+
16
+ def replacement
17
+ builder.derivation! :val, :& do |val, root|
18
+ if val.name.is_a?(Numeric)
19
+ builder.literal!(root.name, -val.name)
20
+ else
21
+ val
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ require "mutiny/mutants/mutation"
2
+
3
+ module Mutiny
4
+ module Mutants
5
+ class Mutation
6
+ module Method
7
+ class UnaryArithmeticOperatorInsertion < Mutation
8
+ def pattern # rubocop:disable Metrics/AbcSize
9
+ builder.either!(
10
+ builder.literal!(:int, builder.VAL { |val| val.name > 0 }),
11
+ builder.literal!(:float, builder.VAL { |val| val.name > 0 }),
12
+ builder.literal!(:send, nil, builder.VAL)
13
+ )
14
+ end
15
+
16
+ def replacement
17
+ builder.derivation! :val, :& do |val, root|
18
+ if val.name.is_a?(Numeric)
19
+ builder.literal!(root.name, -val.name)
20
+ else
21
+ builder.literal!(:send, root, :-@)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,10 @@
1
+ require "metamorpher"
2
+
3
+ module Mutiny
4
+ module Mutants
5
+ class Mutation
6
+ include Metamorpher::Mutator
7
+ include Metamorpher::Builders::AST
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ require_relative "mutant_set"
2
+
3
+ module Mutiny
4
+ module Mutants
5
+ class MutationSet
6
+ def initialize(*mutations)
7
+ @mutations = mutations
8
+ end
9
+
10
+ # TODO : would performance improve by iterating over subjects than over operators?
11
+ # Probably could improve (more) if metamorpher also supported composite transformers so that
12
+ # several mutation operators could be matched simulatenously during a single AST traversal
13
+ def mutate(subjects)
14
+ MutantSet.new.tap do |mutants|
15
+ @mutations.each do |mutation|
16
+ subjects.each do |subject|
17
+ mutants.add(subject, mutation.mutate_file(subject.path))
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,42 @@
1
+ require_relative "mutation_set"
2
+ require_relative "mutation/method/binary_arithmetic_operator_replacement"
3
+ require_relative "mutation/method/conditional_operator_deletion"
4
+ require_relative "mutation/method/conditional_operator_insertion"
5
+ require_relative "mutation/method/conditional_operator_replacement"
6
+ require_relative "mutation/method/relational_expression_replacement"
7
+ require_relative "mutation/method/relational_operator_replacement"
8
+ require_relative "mutation/method/logical_operator_deletion"
9
+ require_relative "mutation/method/logical_operator_insertion"
10
+ require_relative "mutation/method/logical_operator_replacement"
11
+ require_relative "mutation/method/shortcut_assignment_operator_replacement"
12
+ require_relative "mutation/method/unary_arithmetic_operator_deletion"
13
+ require_relative "mutation/method/unary_arithmetic_operator_insertion"
14
+
15
+ module Mutiny
16
+ module Mutants
17
+ class Ruby
18
+ def mutants_for(subjects)
19
+ mutations.mutate(subjects)
20
+ end
21
+
22
+ private
23
+
24
+ def mutations # rubocop:disable Metrics/MethodLength
25
+ @operators ||= MutationSet.new(
26
+ Mutation::Method::BinaryArithmeticOperatorReplacement.new,
27
+ Mutation::Method::ConditionalOperatorDeletion.new,
28
+ Mutation::Method::ConditionalOperatorInsertion.new,
29
+ Mutation::Method::ConditionalOperatorReplacement.new,
30
+ Mutation::Method::RelationalExpressionReplacement.new,
31
+ Mutation::Method::RelationalOperatorReplacement.new,
32
+ Mutation::Method::LogicalOperatorDeletion.new,
33
+ Mutation::Method::LogicalOperatorInsertion.new,
34
+ Mutation::Method::LogicalOperatorReplacement.new,
35
+ Mutation::Method::ShortcutAssignmentOperatorReplacement.new,
36
+ Mutation::Method::UnaryArithmeticOperatorDeletion.new,
37
+ Mutation::Method::UnaryArithmeticOperatorInsertion.new
38
+ )
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,17 @@
1
+ module Mutiny
2
+ class Pattern
3
+ attr_reader :raw
4
+
5
+ def initialize(raw)
6
+ @raw = raw
7
+ end
8
+
9
+ def match?(identifier)
10
+ raw == "*" || identifier.start_with?(raw)
11
+ end
12
+
13
+ def to_s
14
+ raw
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ module Mutiny
2
+ module Reporter
3
+ class Stdout
4
+ def report(message)
5
+ puts message
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,54 @@
1
+ module Mutiny
2
+ module Subjects
3
+ class Environment
4
+ class Type
5
+ attr_reader :mod, :configuration
6
+
7
+ def initialize(mod, configuration)
8
+ @mod = mod
9
+ @configuration = configuration
10
+ end
11
+
12
+ def relevant?
13
+ !name.nil? && in_scope? && loadable?
14
+ end
15
+
16
+ def to_subject
17
+ Subject.new(name: name, path: absolute_path, root: load_path)
18
+ end
19
+
20
+ private
21
+
22
+ def name
23
+ mod.name
24
+ end
25
+
26
+ def in_scope?
27
+ configuration.patterns.any? { |pattern| pattern.match?(name) }
28
+ end
29
+
30
+ def loadable?
31
+ !load_path.nil?
32
+ end
33
+
34
+ def load_path
35
+ configuration.load_paths.detect do |load_path|
36
+ source_locations.any? { |locs| locs.start_with?(load_path) }
37
+ end
38
+ end
39
+
40
+ def source_locations
41
+ mod.instance_methods(false)
42
+ .map { |method_name| mod.instance_method(method_name).source_location }
43
+ .reject(&:nil?)
44
+ .map(&:first)
45
+ .uniq
46
+ end
47
+
48
+ def absolute_path
49
+ source_locations.first
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,25 @@
1
+ require_relative "environment/type"
2
+
3
+ module Mutiny
4
+ module Subjects
5
+ class Environment
6
+ attr_reader :configuration
7
+
8
+ def initialize(configuration)
9
+ @configuration = configuration
10
+ configuration.loads.each { |l| $LOAD_PATH << l }
11
+ configuration.requires.each { |r| require r }
12
+ end
13
+
14
+ def subjects
15
+ SubjectSet.new(modules.select(&:relevant?).map(&:to_subject))
16
+ end
17
+
18
+ private
19
+
20
+ def modules
21
+ ObjectSpace.each_object(Module).map { |mod| Type.new(mod, configuration) }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,32 @@
1
+ require 'pathname'
2
+
3
+ module Mutiny
4
+ module Subjects
5
+ class Subject
6
+ attr_reader :name, :path, :root
7
+
8
+ def initialize(name:, path: nil, root: nil)
9
+ @name = name
10
+ @path = path
11
+ @root = root
12
+ end
13
+
14
+ def relative_path
15
+ absolute_path = Pathname.new(path)
16
+ root_path = Pathname.new(root)
17
+
18
+ absolute_path.relative_path_from(root_path).to_s
19
+ end
20
+
21
+ def eql?(other)
22
+ is_a?(other.class) && other.name == name && other.path == path && other.root == root
23
+ end
24
+
25
+ alias_method "==", "eql?"
26
+
27
+ def hash
28
+ [name, path, root].hash
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ module Mutiny
2
+ module Subjects
3
+ class SubjectSet
4
+ def initialize(subjects)
5
+ @subjects = subjects
6
+ end
7
+
8
+ def names
9
+ @names ||= @subjects.map(&:name).sort
10
+ end
11
+
12
+ def each(&block)
13
+ @subjects.each(&block)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ require_relative "subjects/subject"
2
+ require_relative "subjects/subject_set"
3
+ require_relative "subjects/environment"
@@ -0,0 +1,12 @@
1
+ module Mutiny
2
+ module Tests
3
+ class Test
4
+ attr_reader :location, :expression
5
+
6
+ def initialize(location: nil, expression:)
7
+ @location = location
8
+ @expression = expression
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ module Mutiny
2
+ module Tests
3
+ class TestRun
4
+ attr_reader :tests, :failed_tests, :output, :runtime
5
+
6
+ def initialize(tests:, failed_tests:, output:, runtime:)
7
+ @tests = tests
8
+ @failed_tests = failed_tests
9
+ @output = output
10
+ @runtime = runtime
11
+ end
12
+
13
+ def passed?
14
+ failed_tests.empty?
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,44 @@
1
+ require "forwardable"
2
+
3
+ module Mutiny
4
+ module Tests
5
+ class TestSet
6
+ extend Forwardable
7
+ def_delegators :tests, :size, :empty?, :hash
8
+
9
+ def self.empty
10
+ new([])
11
+ end
12
+
13
+ def initialize(tests)
14
+ @tests = tests
15
+ end
16
+
17
+ def locations
18
+ tests.map(&:location)
19
+ end
20
+
21
+ def for(subject_set)
22
+ subset { |test| subject_set.names.include?(test.expression) }
23
+ end
24
+
25
+ def subset(&block)
26
+ self.class.new(tests.select(&block))
27
+ end
28
+
29
+ def take(n)
30
+ self.class.new(tests.take(n))
31
+ end
32
+
33
+ def eql?(other)
34
+ is_a?(other.class) && other.tests == tests
35
+ end
36
+
37
+ alias_method "==", "eql?"
38
+
39
+ protected
40
+
41
+ attr_reader :tests
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ require_relative "tests/test"
2
+ require_relative "tests/test_set"
3
+ require_relative "tests/test_run"
@@ -0,0 +1,3 @@
1
+ module Mutiny
2
+ VERSION = "0.1.0"
3
+ end
data/lib/mutiny.rb ADDED
@@ -0,0 +1,4 @@
1
+ require_relative "mutiny/configuration"
2
+ require_relative "mutiny/subjects"
3
+ require_relative "mutiny/tests"
4
+ require_relative "mutiny/mode"
data/mutiny.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mutiny/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mutiny"
8
+ spec.version = Mutiny::VERSION
9
+ spec.authors = ["Louis Rose"]
10
+ spec.email = ["louis.rose@york.ac.uk"]
11
+ spec.description = %q{A tiny and experimental mutation testing framework for exploring research ideas.}
12
+ spec.summary = %q{A tiny mutation testing framework for Ruby}
13
+ spec.homepage = "https://github.com/mutiny/mutiny"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "parser", "~> 2.2.2"
22
+ spec.add_runtime_dependency "unparser", "~> 0.2.4"
23
+ spec.add_runtime_dependency "gli", "~> 2.13.0"
24
+ spec.add_runtime_dependency "metamorpher", "~> 0.2.2"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.10.2"
27
+ spec.add_development_dependency "rake", "~> 10.4.2"
28
+ spec.add_development_dependency "rspec", "~> 3.2.0"
29
+ spec.add_development_dependency "aruba", "~> 0.6.0"
30
+ spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4.6"
31
+ spec.add_development_dependency "rubocop", "~> 0.31.0"
32
+ end
@@ -0,0 +1,39 @@
1
+ describe "Using Mutiny to check whether mutation testing can be carried out" do
2
+ it "should report success for a valid setup" do
3
+ cd "calculator"
4
+ run "bundle exec mutiny check"
5
+
6
+ expected_output = "Checking...\n" \
7
+ " At least one relevant test found (6 in total)\n" \
8
+ " All relevant tests passed\n" \
9
+ "Looks good!\n"
10
+
11
+ expect(all_output).to eq(expected_output)
12
+ end
13
+
14
+ it "should report failure when there are no relevant tests" do
15
+ cd "untested_calculator"
16
+ run "bundle exec mutiny -r calculator check"
17
+
18
+ expected_output = "Checking...\n" \
19
+ " No relevant tests found (for modules matching '*')\n" \
20
+ "Either your mutiny configuration is wrong, or you're missing some tests!\n"
21
+
22
+ expect(all_output).to eq(expected_output)
23
+ end
24
+
25
+ it "should report warning when there are failing tests" do
26
+ cd "buggy_calculator"
27
+ run "bundle exec mutiny -r calculator check"
28
+
29
+ expected_output = "Checking...\n" \
30
+ " At least one relevant test found (3 in total)\n" \
31
+ " Not all relevant tests passed. The failing tests are:\n" \
32
+ " ./spec/calculator/max_spec.rb:9\n" \
33
+ " ./spec/calculator/max_spec.rb:13\n" \
34
+ "\n" \
35
+ "Looks ok, but note that mutiny is most effective when all tests pass.\n"
36
+
37
+ expect(all_output).to eq(expected_output)
38
+ end
39
+ end
@@ -0,0 +1,35 @@
1
+ describe "Using Mutiny to generate mutants" do
2
+ it "should report statistics of generated mutants" do
3
+ cd "calculator"
4
+ run "bundle exec mutiny mutate"
5
+
6
+ expected_output = "Mutating...\n" \
7
+ "Generated 14 mutants:\n" \
8
+ " * calculator/max.rb - 7 mutants\n" \
9
+ " * calculator/min.rb - 7 mutants\n" \
10
+ "Check the '.mutants' directory to browse the generated mutants.\n"
11
+
12
+ expect(all_output).to eq(expected_output)
13
+ end
14
+
15
+ it "should write mutants to the .mutants directory" do
16
+ cd "calculator"
17
+ run "bundle exec mutiny mutate"
18
+
19
+ check_file_content(".mutants/calculator/min.0.rb", /if true/)
20
+ check_file_content(".mutants/calculator/min.1.rb", /if false/)
21
+ check_file_content(".mutants/calculator/min.2.rb", /if right <= left/)
22
+ check_file_content(".mutants/calculator/min.3.rb", /if right == left/)
23
+ check_file_content(".mutants/calculator/min.4.rb", /if right != left/)
24
+ check_file_content(".mutants/calculator/min.5.rb", /if right >= left/)
25
+ check_file_content(".mutants/calculator/min.6.rb", /if right > left/)
26
+
27
+ check_file_content(".mutants/calculator/max.0.rb", /if true/)
28
+ check_file_content(".mutants/calculator/max.1.rb", /if false/)
29
+ check_file_content(".mutants/calculator/max.2.rb", /if right < left/)
30
+ check_file_content(".mutants/calculator/max.3.rb", /if right <= left/)
31
+ check_file_content(".mutants/calculator/max.4.rb", /if right == left/)
32
+ check_file_content(".mutants/calculator/max.5.rb", /if right != left/)
33
+ check_file_content(".mutants/calculator/max.6.rb", /if right >= left/)
34
+ end
35
+ end
@@ -0,0 +1,38 @@
1
+ require 'rspec/core/sandbox'
2
+ require 'rspec/support/spec/stderr_splitter'
3
+ require 'rspec/support/spec/in_sub_process'
4
+
5
+ require "codeclimate-test-reporter"
6
+ CodeClimate::TestReporter.start
7
+
8
+ Dir["./spec/support/**/*.rb"].each { |f| require f }
9
+
10
+ require "mutiny"
11
+
12
+ # This file was generated by the `rspec --init` command. Conventionally, all
13
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
14
+ # Require this file using `require "spec_helper"` to ensure that it is only
15
+ # loaded once.
16
+ #
17
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
18
+ RSpec.configure do |config|
19
+ config.run_all_when_everything_filtered = true
20
+ config.filter_run :focus
21
+
22
+ # Run specs in random order to surface order dependencies. If you find an
23
+ # order dependency and want to debug it, you can fix the order by providing
24
+ # the seed, which is printed after each run.
25
+ # --seed 1234
26
+ config.order = 'random'
27
+
28
+ # Isolate mutiny-under-test from its own test suite
29
+ config.around(:example) do |example|
30
+ RSpec::Core::Sandbox.sandboxed do
31
+ example.run
32
+ end
33
+ end
34
+
35
+ # Make in_sub_process method available for any tests that need
36
+ # to pollute the Ruby environment (e.g., change the ObjectSpace)
37
+ config.include RSpec::Support::InSubProcess
38
+ end
@@ -0,0 +1,12 @@
1
+ require 'aruba/api'
2
+ require 'aruba/reporting'
3
+
4
+ RSpec.configure do |config|
5
+ config.include Aruba::Api
6
+
7
+ config.before(:each) do
8
+ @dirs = [File.join(Dir.pwd, "examples")]
9
+ restore_env
10
+ set_env "GLI_DEBUG", "true"
11
+ end
12
+ end