mutation_tester 1.2.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 (47) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +13 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +83 -0
  5. data/LICENSE.txt +19 -0
  6. data/Rakefile +57 -0
  7. data/docs/ci.md +158 -0
  8. data/docs/execution-runners.md +163 -0
  9. data/docs/json-schema.md +171 -0
  10. data/docs/mutation-types.md +207 -0
  11. data/examples/calculator.rb +35 -0
  12. data/examples/calculator_100_perc_spec.rb +121 -0
  13. data/examples/calculator_minitest.rb +53 -0
  14. data/examples/calculator_spec.rb +105 -0
  15. data/examples/github_actions/ai_mutation_gate.yml +75 -0
  16. data/examples/github_actions/mutation_test.yml +87 -0
  17. data/examples/hooks/pre-push +41 -0
  18. data/examples/run_example.rb +31 -0
  19. data/examples/run_example_minitest.rb +38 -0
  20. data/examples/run_example_parallel_minitest.rb +48 -0
  21. data/examples/run_example_parallel_rspec.rb +48 -0
  22. data/examples/run_example_rspec.rb +38 -0
  23. data/examples/spec_helper.rb +21 -0
  24. data/exe/mutation_test +345 -0
  25. data/lib/mutation_tester/batch_runner.rb +286 -0
  26. data/lib/mutation_tester/configuration.rb +105 -0
  27. data/lib/mutation_tester/core.rb +193 -0
  28. data/lib/mutation_tester/fork_runner/worker.rb +202 -0
  29. data/lib/mutation_tester/fork_runner.rb +382 -0
  30. data/lib/mutation_tester/framework_detector.rb +25 -0
  31. data/lib/mutation_tester/in_memory_loader.rb +25 -0
  32. data/lib/mutation_tester/mutation_runner.rb +644 -0
  33. data/lib/mutation_tester/mutator.rb +874 -0
  34. data/lib/mutation_tester/progress_display.rb +130 -0
  35. data/lib/mutation_tester/railtie.rb +7 -0
  36. data/lib/mutation_tester/rake_task.rb +18 -0
  37. data/lib/mutation_tester/reporters/base_reporter.rb +154 -0
  38. data/lib/mutation_tester/reporters/batch_json_reporter.rb +72 -0
  39. data/lib/mutation_tester/reporters/console_reporter.rb +130 -0
  40. data/lib/mutation_tester/reporters/html_reporter.rb +693 -0
  41. data/lib/mutation_tester/reporters/json_reporter.rb +67 -0
  42. data/lib/mutation_tester/test_command.rb +165 -0
  43. data/lib/mutation_tester/version.rb +3 -0
  44. data/lib/mutation_tester.rb +52 -0
  45. data/lib/tasks/mutation_tester.rake +80 -0
  46. data/readme.md +925 -0
  47. metadata +213 -0
@@ -0,0 +1,105 @@
1
+ require_relative 'calculator'
2
+
3
+ RSpec.describe Calculator do
4
+ subject(:calculator) { described_class.new }
5
+
6
+ describe '#add' do
7
+ it 'adds two numbers' do
8
+ expect(calculator.add(2, 3)).to eq(5)
9
+ end
10
+
11
+ it 'adds negative numbers' do
12
+ expect(calculator.add(-2, -3)).to eq(-5)
13
+ end
14
+ end
15
+
16
+ describe '#subtract' do
17
+ it 'subtracts two numbers' do
18
+ expect(calculator.subtract(5, 3)).to eq(2)
19
+ end
20
+
21
+ it 'handles negative results' do
22
+ expect(calculator.subtract(3, 5)).to eq(-2)
23
+ end
24
+ end
25
+
26
+ describe '#multiply' do
27
+ it 'multiplies two numbers' do
28
+ expect(calculator.multiply(3, 4)).to eq(12)
29
+ end
30
+
31
+ it 'multiplies by zero' do
32
+ expect(calculator.multiply(5, 0)).to eq(0)
33
+ end
34
+ end
35
+
36
+ describe '#divide' do
37
+ it 'divides two numbers' do
38
+ expect(calculator.divide(10, 2)).to eq(5)
39
+ end
40
+
41
+ it 'returns 0 when dividing by zero' do
42
+ expect(calculator.divide(10, 0)).to eq(0)
43
+ end
44
+
45
+ it 'handles integer division' do
46
+ expect(calculator.divide(7, 2)).to eq(3)
47
+ end
48
+ end
49
+
50
+ describe '#is_positive?' do
51
+ it 'returns true for positive numbers' do
52
+ expect(calculator.is_positive?(5)).to be true
53
+ end
54
+
55
+ it 'returns false for negative numbers' do
56
+ expect(calculator.is_positive?(-5)).to be false
57
+ end
58
+
59
+ it 'returns false for zero' do
60
+ expect(calculator.is_positive?(0)).to be false
61
+ end
62
+ end
63
+
64
+ describe '#is_even?' do
65
+ it 'returns true for even numbers' do
66
+ expect(calculator.is_even?(4)).to be true
67
+ end
68
+
69
+ it 'returns false for odd numbers' do
70
+ expect(calculator.is_even?(3)).to be false
71
+ end
72
+
73
+ it 'returns true for zero' do
74
+ expect(calculator.is_even?(0)).to be true
75
+ end
76
+ end
77
+
78
+ describe '#max' do
79
+ it 'returns the larger number when first is larger' do
80
+ expect(calculator.max(5, 3)).to eq(5)
81
+ end
82
+
83
+ it 'returns the larger number when second is larger' do
84
+ expect(calculator.max(3, 5)).to eq(5)
85
+ end
86
+
87
+ it 'returns the number when both are equal' do
88
+ expect(calculator.max(5, 5)).to eq(5)
89
+ end
90
+ end
91
+
92
+ describe '#absolute' do
93
+ it 'returns positive number unchanged' do
94
+ expect(calculator.absolute(5)).to eq(5)
95
+ end
96
+
97
+ it 'returns absolute value of negative number' do
98
+ expect(calculator.absolute(-5)).to eq(5)
99
+ end
100
+
101
+ it 'returns zero for zero' do
102
+ expect(calculator.absolute(0)).to eq(0)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,75 @@
1
+ # AI mutation gate for GitHub Actions (mutation_tester gem). Runs mutation_test
2
+ # --json, publishes the SURVIVING mutants (file/line/original/mutated = test
3
+ # gaps) to the job summary and a survivors.json artifact for an AI agent, then
4
+ # re-fails on a low score. Copy to .github/workflows/, edit "EDIT:" lines. Needs
5
+ # jq (preinstalled on ubuntu runners); see mutation_test.yml for the plain gate.
6
+
7
+ name: AI Mutation Gate
8
+
9
+ on:
10
+ pull_request:
11
+ workflow_dispatch:
12
+
13
+ jobs:
14
+ mutation_gate:
15
+ name: AI mutation gate
16
+ runs-on: ubuntu-latest
17
+ timeout-minutes: 30
18
+ steps:
19
+ - name: Checkout
20
+ uses: actions/checkout@v4
21
+
22
+ - name: Set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: '3.3' # EDIT: match your project's Ruby (floor is 3.0)
26
+ bundler-cache: true
27
+
28
+ - name: Run mutation tests (JSON report on stdout)
29
+ id: mutation
30
+ continue-on-error: true # keep going so the worklist/artifact below still run
31
+ run: |
32
+ # EDIT: replace with YOUR source file and its test file.
33
+ bundle exec mutation_test --json \
34
+ app/models/user.rb spec/models/user_spec.rb > mutation_report.json
35
+
36
+ - name: Summarize surviving mutants (test gaps) in the job summary
37
+ if: always()
38
+ run: |
39
+ score=$(jq -r '.summary.mutation_score // "n/a"' mutation_report.json)
40
+ survivors=$(jq '[.mutations[] | select(.status == "survived")] | length' mutation_report.json)
41
+ {
42
+ echo "## Mutation gate"
43
+ echo "Score: **${score}%** - surviving mutants: **${survivors}**"
44
+ if [ "$survivors" -eq 0 ]; then
45
+ echo "No surviving mutants. No test gaps to close."
46
+ else
47
+ echo "| file | line | from | to |"
48
+ echo "|---|---|---|---|"
49
+ jq -r '.mutations[] | select(.status == "survived")
50
+ | "| \(.file_path) | \(.line) | `\(.original)` | `\(.mutated)` |"' \
51
+ mutation_report.json
52
+ fi
53
+ } >> "$GITHUB_STEP_SUMMARY"
54
+
55
+ - name: Extract survivors as a machine-readable worklist for an AI agent
56
+ if: always()
57
+ run: |
58
+ jq '[.mutations[] | select(.status == "survived")
59
+ | {file: .file_path, line: .line, from: .original, to: .mutated,
60
+ source_line: .source_line, mutated_line: .mutated_line}]' \
61
+ mutation_report.json > survivors.json
62
+ cat survivors.json # feed this worklist to your agent CLI
63
+
64
+ - name: Upload mutation report and survivor worklist
65
+ if: always()
66
+ uses: actions/upload-artifact@v4
67
+ with:
68
+ name: mutation-report
69
+ path: |
70
+ mutation_report.json
71
+ survivors.json
72
+
73
+ - name: Enforce the gate
74
+ if: steps.mutation.outcome == 'failure' # non-zero run = score below threshold
75
+ run: exit 1
@@ -0,0 +1,87 @@
1
+ # Mutation testing in CI with GitHub Actions (mutation_tester gem).
2
+ #
3
+ # Copy this file to .github/workflows/mutation_test.yml in your project and you
4
+ # have mutation testing running in CI in about five minutes. The workflow:
5
+ # 1. checks out your code,
6
+ # 2. installs Ruby and your bundle (with mutation_tester in it),
7
+ # 3. runs mutation_test on your source file and its test file,
8
+ # 4. uploads the HTML/JSON reports as a build artifact (even on failure),
9
+ # 5. fails the job when the mutation score is below your threshold.
10
+ #
11
+ # Prerequisite: add the gem to your project's Gemfile so `bundle exec` finds it:
12
+ # bundle add mutation_tester --group development,test
13
+ # (or add `gem "mutation_tester"` to your development/test group, then bundle install).
14
+ #
15
+ # Then look for the lines marked "EDIT:" and point them at your own files.
16
+
17
+ name: Mutation Testing
18
+
19
+ on:
20
+ push:
21
+ pull_request:
22
+
23
+ jobs:
24
+ mutation_test:
25
+ name: Mutation testing
26
+ runs-on: ubuntu-latest
27
+ # Mutation testing re-runs your suite once per mutant, so give the job more
28
+ # head-room than a normal test run. Tune this to your project's size.
29
+ timeout-minutes: 30
30
+
31
+ steps:
32
+ - name: Checkout
33
+ uses: actions/checkout@v4
34
+
35
+ - name: Set up Ruby
36
+ uses: ruby/setup-ruby@v1
37
+ with:
38
+ # EDIT: match the Ruby version your project uses.
39
+ ruby-version: '3.3'
40
+ # Runs `bundle install` and caches the resolved gems between runs.
41
+ bundler-cache: true
42
+
43
+ - name: Run mutation tests
44
+ # EDIT: replace with YOUR source file and its test file.
45
+ # The CLI exits non-zero when the score is below the threshold, which
46
+ # fails this step (and the job). That is your quality gate: no extra
47
+ # configuration needed.
48
+ run: bundle exec mutation_test app/models/user.rb spec/models/user_spec.rb
49
+ # OPTIONAL - run mutants in parallel to finish faster. This works out of
50
+ # the box (see MUTATION_TESTER_PARALLEL_PROCESSES). Enable it only if
51
+ # your tests do not share database state. Uncomment the two lines below:
52
+ # env:
53
+ # MUTATION_TESTER_PARALLEL_PROCESSES: 4
54
+
55
+ # OPTIONAL - test several source/test pairs in one job. Uncomment and give
56
+ # each pair its own --output-dir so their reports do not overwrite each
57
+ # other. The job stops at the first pair that is below its threshold.
58
+ # - name: Run mutation tests (multiple files)
59
+ # run: |
60
+ # bundle exec mutation_test app/models/user.rb spec/models/user_spec.rb \
61
+ # --output-dir tmp/mutation_reports/user
62
+ # bundle exec mutation_test app/models/order.rb spec/models/order_spec.rb \
63
+ # --output-dir tmp/mutation_reports/order
64
+
65
+ # OPTIONAL - incremental gate for pull requests: mutate only the files
66
+ # changed since the PR base branch and stop at the first surviving mutant.
67
+ # This keeps the job fast on large repos. Two edits are needed:
68
+ # 1. give the Checkout step the full history so git can diff against the
69
+ # base branch:
70
+ # with:
71
+ # fetch-depth: 0
72
+ # 2. replace the "Run mutation tests" step with the incremental run:
73
+ # - name: Run mutation tests (changed files only)
74
+ # if: github.event_name == 'pull_request'
75
+ # run: |
76
+ # bundle exec mutation_test --glob 'lib/**/*.rb' \
77
+ # --since "origin/${{ github.base_ref }}" --fail-fast
78
+
79
+ - name: Upload mutation reports
80
+ # always() uploads the reports even when the gate failed the job, which
81
+ # is exactly when you want to inspect the surviving mutants.
82
+ if: always()
83
+ uses: actions/upload-artifact@v4
84
+ with:
85
+ name: mutation-reports
86
+ # Default output_dir; change it if you pass a custom --output-dir above.
87
+ path: tmp/mutation_reports/
@@ -0,0 +1,41 @@
1
+ #!/bin/sh
2
+ #
3
+ # mutation_tester pre-push hook - block a push when the mutation score of your
4
+ # target file(s) drops below THRESHOLD, so weak tests never reach the remote.
5
+ #
6
+ # Install: cp examples/hooks/pre-push .git/hooks/pre-push && chmod +x .git/hooks/pre-push
7
+ # (lefthook/overcommit users: call this script from your pre-push step)
8
+ # Requires: jq (https://jqlang.github.io/jq/)
9
+ # On a block it prints the surviving mutants (file:line, what changed) = the gaps.
10
+
11
+ set -eu
12
+
13
+ THRESHOLD=90 # EDIT: minimum mutation score (percent) required to allow the push
14
+ report=$(mktemp)
15
+ status=0
16
+
17
+ # EDIT: the "SOURCE TEST" pairs to gate on, one per line. The loop reads this
18
+ # heredoc (not a pipe), so it runs in the current shell and $status survives it.
19
+ while read -r source test; do
20
+ [ -z "$source" ] && continue
21
+
22
+ # --json prints ONLY the JSON to stdout; we do our own jq threshold check, so
23
+ # ignore the CLI's own pass/fail exit here.
24
+ bundle exec mutation_test --json "$source" "$test" >"$report" || true
25
+
26
+ score=$(jq -r '.summary.mutation_score // empty' "$report")
27
+ if [ -z "$score" ] || jq -e --argjson t "$THRESHOLD" '.summary.mutation_score < $t' "$report" >/dev/null; then
28
+ echo "BLOCK: $source scored ${score:-no}% (< ${THRESHOLD}%). Surviving mutants (test gaps):" >&2
29
+ jq -r '.mutations[] | select(.status == "survived")
30
+ | " \(.file_path):\(.line) \(.original) -> \(.mutated)"' "$report" >&2
31
+ status=1
32
+ else
33
+ echo "OK: $source scored ${score}% (>= ${THRESHOLD}%)" >&2
34
+ fi
35
+ done <<'PAIRS'
36
+ app/models/user.rb spec/models/user_spec.rb
37
+ PAIRS
38
+
39
+ rm -f "$report"
40
+ [ "$status" -eq 0 ] || echo "Push blocked by mutation gate. Close the gaps above or lower THRESHOLD." >&2
41
+ exit "$status"
@@ -0,0 +1,31 @@
1
+ require_relative '../lib/mutation_tester'
2
+
3
+ MutationTester.configure do |config|
4
+ config.reporters = %i[console html json]
5
+ config.minimum_score = 90
6
+ config.verbose = true
7
+ config.fail_on_threshold = true
8
+ end
9
+
10
+ source_file = File.expand_path('calculator.rb', __dir__)
11
+ spec_file = File.expand_path('calculator_spec.rb', __dir__)
12
+
13
+ unless File.exist?(source_file)
14
+ puts Rainbow("❌ Source file not found: #{source_file}").red
15
+ exit 1
16
+ end
17
+
18
+ unless File.exist?(spec_file)
19
+ puts Rainbow("❌ Spec file not found: #{spec_file}").red
20
+ exit 1
21
+ end
22
+
23
+ success = MutationTester.run(source_file, spec_file)
24
+
25
+ if success
26
+ puts "\n" + Rainbow('✅ Example completed!').green
27
+ puts Rainbow('Check mutation_reports/mutation_report.html for detailed results').cyan
28
+ else
29
+ puts "\n" + Rainbow('❌ Example failed!').red
30
+ exit 1
31
+ end
@@ -0,0 +1,38 @@
1
+ require_relative '../lib/mutation_tester'
2
+
3
+ puts Rainbow('=' * 80).bright
4
+ puts Rainbow('🧬 Minitest Example (Serial Execution)').cyan.bold
5
+ puts Rainbow('=' * 80).bright
6
+ puts ''
7
+
8
+ MutationTester.configure do |config|
9
+ config.parallel_processes = 1
10
+ config.reporters = %i[console html json]
11
+ config.minimum_score = 90
12
+ config.verbose = true
13
+ config.fail_on_threshold = false
14
+ config.output_dir = 'mutation_reports'
15
+ end
16
+
17
+ source_file = File.expand_path('calculator.rb', __dir__)
18
+ spec_file = File.expand_path('calculator_minitest.rb', __dir__)
19
+
20
+ unless File.exist?(source_file)
21
+ puts Rainbow("❌ Source file not found: #{source_file}").red
22
+ exit 1
23
+ end
24
+
25
+ unless File.exist?(spec_file)
26
+ puts Rainbow("❌ Test file not found: #{spec_file}").red
27
+ exit 1
28
+ end
29
+
30
+ success = MutationTester.run(source_file, spec_file)
31
+
32
+ puts ''
33
+ if success
34
+ puts Rainbow('✅ Minitest example completed successfully!').green.bold
35
+ else
36
+ puts Rainbow('⚠️ Minitest example completed with issues').yellow.bold
37
+ end
38
+ puts Rainbow('📊 Check mutation_reports/mutation_report.html for detailed results').cyan
@@ -0,0 +1,48 @@
1
+ require_relative '../lib/mutation_tester'
2
+ require 'parallel'
3
+
4
+ puts Rainbow('=' * 80).bright
5
+ puts Rainbow('🧬 Minitest Example (Parallel Execution)').cyan.bold
6
+ puts Rainbow('=' * 80).bright
7
+ puts ''
8
+
9
+ num_processors = Parallel.processor_count
10
+ puts Rainbow("💻 Detected #{num_processors} processor(s), using parallel execution").cyan
11
+ puts ''
12
+
13
+ MutationTester.configure do |config|
14
+ config.parallel_processes = [num_processors, 2].max
15
+ config.reporters = %i[console html json]
16
+ config.minimum_score = 90
17
+ config.verbose = true
18
+ config.fail_on_threshold = false
19
+ config.output_dir = 'mutation_reports'
20
+ end
21
+
22
+ source_file = File.expand_path('calculator.rb', __dir__)
23
+ spec_file = File.expand_path('calculator_minitest.rb', __dir__)
24
+
25
+ unless File.exist?(source_file)
26
+ puts Rainbow("❌ Source file not found: #{source_file}").red
27
+ exit 1
28
+ end
29
+
30
+ unless File.exist?(spec_file)
31
+ puts Rainbow("❌ Test file not found: #{spec_file}").red
32
+ exit 1
33
+ end
34
+
35
+ start_time = Time.now
36
+ success = MutationTester.run(source_file, spec_file)
37
+ elapsed_time = Time.now - start_time
38
+
39
+ puts ''
40
+ puts Rainbow("⏱️ Completed in #{elapsed_time.round(2)} seconds").cyan
41
+ puts ''
42
+
43
+ if success
44
+ puts Rainbow('✅ Parallel Minitest example completed successfully!').green.bold
45
+ else
46
+ puts Rainbow('⚠️ Parallel Minitest example completed with issues').yellow.bold
47
+ end
48
+ puts Rainbow('📊 Check mutation_reports/mutation_report.html for detailed results').cyan
@@ -0,0 +1,48 @@
1
+ require_relative '../lib/mutation_tester'
2
+ require 'parallel'
3
+
4
+ puts Rainbow('=' * 80).bright
5
+ puts Rainbow('🧬 RSpec Example (Parallel Execution)').cyan.bold
6
+ puts Rainbow('=' * 80).bright
7
+ puts ''
8
+
9
+ num_processors = Parallel.processor_count
10
+ puts Rainbow("💻 Detected #{num_processors} processor(s), using parallel execution").cyan
11
+ puts ''
12
+
13
+ MutationTester.configure do |config|
14
+ config.parallel_processes = [num_processors, 2].max
15
+ config.reporters = %i[console html json]
16
+ config.minimum_score = 90
17
+ config.verbose = true
18
+ config.fail_on_threshold = false
19
+ config.output_dir = 'mutation_reports'
20
+ end
21
+
22
+ source_file = File.expand_path('calculator.rb', __dir__)
23
+ spec_file = File.expand_path('calculator_spec.rb', __dir__)
24
+
25
+ unless File.exist?(source_file)
26
+ puts Rainbow("❌ Source file not found: #{source_file}").red
27
+ exit 1
28
+ end
29
+
30
+ unless File.exist?(spec_file)
31
+ puts Rainbow("❌ Spec file not found: #{spec_file}").red
32
+ exit 1
33
+ end
34
+
35
+ start_time = Time.now
36
+ success = MutationTester.run(source_file, spec_file)
37
+ elapsed_time = Time.now - start_time
38
+
39
+ puts ''
40
+ puts Rainbow("⏱️ Completed in #{elapsed_time.round(2)} seconds").cyan
41
+ puts ''
42
+
43
+ if success
44
+ puts Rainbow('✅ Parallel RSpec example completed successfully!').green.bold
45
+ else
46
+ puts Rainbow('⚠️ Parallel RSpec example completed with issues').yellow.bold
47
+ end
48
+ puts Rainbow('📊 Check mutation_reports/mutation_report.html for detailed results').cyan
@@ -0,0 +1,38 @@
1
+ require_relative '../lib/mutation_tester'
2
+
3
+ puts Rainbow('=' * 80).bright
4
+ puts Rainbow('🧬 RSpec Example (Serial Execution)').cyan.bold
5
+ puts Rainbow('=' * 80).bright
6
+ puts ''
7
+
8
+ MutationTester.configure do |config|
9
+ config.parallel_processes = 1
10
+ config.reporters = %i[console html json]
11
+ config.minimum_score = 90
12
+ config.verbose = true
13
+ config.fail_on_threshold = false
14
+ config.output_dir = 'mutation_reports'
15
+ end
16
+
17
+ source_file = File.expand_path('calculator.rb', __dir__)
18
+ spec_file = File.expand_path('calculator_spec.rb', __dir__)
19
+
20
+ unless File.exist?(source_file)
21
+ puts Rainbow("❌ Source file not found: #{source_file}").red
22
+ exit 1
23
+ end
24
+
25
+ unless File.exist?(spec_file)
26
+ puts Rainbow("❌ Spec file not found: #{spec_file}").red
27
+ exit 1
28
+ end
29
+
30
+ success = MutationTester.run(source_file, spec_file)
31
+
32
+ puts ''
33
+ if success
34
+ puts Rainbow('✅ RSpec example completed successfully!').green.bold
35
+ else
36
+ puts Rainbow('⚠️ RSpec example completed with issues').yellow.bold
37
+ end
38
+ puts Rainbow('📊 Check mutation_reports/mutation_report.html for detailed results').cyan
@@ -0,0 +1,21 @@
1
+ RSpec.configure do |config|
2
+ config.expect_with :rspec do |expectations|
3
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
4
+ end
5
+
6
+ config.mock_with(:rspec) do |mocks|
7
+ mocks.verify_partial_doubles = true
8
+ end
9
+
10
+ config.shared_context_metadata_behavior = :apply_to_host_groups
11
+ config.filter_run_when_matching(:focus)
12
+ config.example_status_persistence_file_path = 'spec/examples.txt'
13
+ config.disable_monkey_patching!
14
+ config.warnings = false
15
+
16
+ config.default_formatter = 'doc' if config.files_to_run.one?
17
+
18
+ config.profile_examples = 10
19
+ config.order = :random
20
+ Kernel.srand config.seed
21
+ end