ultra-pro-pkg 0.0.1

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 (117) hide show
  1. checksums.yaml +7 -0
  2. data/simplecov-1.0.0/LICENSE +20 -0
  3. data/simplecov-1.0.0/README.md +1524 -0
  4. data/simplecov-1.0.0/doc/alternate-formatters.md +66 -0
  5. data/simplecov-1.0.0/doc/commercial-services.md +25 -0
  6. data/simplecov-1.0.0/doc/editor-integration.md +18 -0
  7. data/simplecov-1.0.0/exe/simplecov +11 -0
  8. data/simplecov-1.0.0/lib/minitest/simplecov_plugin.rb +171 -0
  9. data/simplecov-1.0.0/lib/simplecov/autostart.rb +11 -0
  10. data/simplecov-1.0.0/lib/simplecov/cli/clean.rb +47 -0
  11. data/simplecov-1.0.0/lib/simplecov/cli/coverage.rb +91 -0
  12. data/simplecov-1.0.0/lib/simplecov/cli/diff.rb +151 -0
  13. data/simplecov-1.0.0/lib/simplecov/cli/dotfile.rb +100 -0
  14. data/simplecov-1.0.0/lib/simplecov/cli/merge.rb +116 -0
  15. data/simplecov-1.0.0/lib/simplecov/cli/open.rb +50 -0
  16. data/simplecov-1.0.0/lib/simplecov/cli/report.rb +84 -0
  17. data/simplecov-1.0.0/lib/simplecov/cli/run.rb +36 -0
  18. data/simplecov-1.0.0/lib/simplecov/cli/serve.rb +139 -0
  19. data/simplecov-1.0.0/lib/simplecov/cli/uncovered.rb +107 -0
  20. data/simplecov-1.0.0/lib/simplecov/cli.rb +150 -0
  21. data/simplecov-1.0.0/lib/simplecov/color.rb +74 -0
  22. data/simplecov-1.0.0/lib/simplecov/combine/branches_combiner.rb +54 -0
  23. data/simplecov-1.0.0/lib/simplecov/combine/files_combiner.rb +30 -0
  24. data/simplecov-1.0.0/lib/simplecov/combine/lines_combiner.rb +45 -0
  25. data/simplecov-1.0.0/lib/simplecov/combine/methods_combiner.rb +26 -0
  26. data/simplecov-1.0.0/lib/simplecov/combine/results_combiner.rb +61 -0
  27. data/simplecov-1.0.0/lib/simplecov/combine.rb +30 -0
  28. data/simplecov-1.0.0/lib/simplecov/command_guesser.rb +78 -0
  29. data/simplecov-1.0.0/lib/simplecov/configuration/coverage.rb +171 -0
  30. data/simplecov-1.0.0/lib/simplecov/configuration/coverage_criteria.rb +156 -0
  31. data/simplecov-1.0.0/lib/simplecov/configuration/filters.rb +197 -0
  32. data/simplecov-1.0.0/lib/simplecov/configuration/formatting.rb +119 -0
  33. data/simplecov-1.0.0/lib/simplecov/configuration/ignored_entries.rb +63 -0
  34. data/simplecov-1.0.0/lib/simplecov/configuration/merging.rb +164 -0
  35. data/simplecov-1.0.0/lib/simplecov/configuration/thresholds.rb +174 -0
  36. data/simplecov-1.0.0/lib/simplecov/configuration.rb +184 -0
  37. data/simplecov-1.0.0/lib/simplecov/coverage_statistics.rb +59 -0
  38. data/simplecov-1.0.0/lib/simplecov/coverage_violations.rb +148 -0
  39. data/simplecov-1.0.0/lib/simplecov/defaults.rb +60 -0
  40. data/simplecov-1.0.0/lib/simplecov/deprecation.rb +45 -0
  41. data/simplecov-1.0.0/lib/simplecov/directive.rb +162 -0
  42. data/simplecov-1.0.0/lib/simplecov/exit_codes/exit_code_handling.rb +35 -0
  43. data/simplecov-1.0.0/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +45 -0
  44. data/simplecov-1.0.0/lib/simplecov/exit_codes/maximum_overall_coverage_check.rb +45 -0
  45. data/simplecov-1.0.0/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +44 -0
  46. data/simplecov-1.0.0/lib/simplecov/exit_codes/minimum_coverage_by_group_check.rb +41 -0
  47. data/simplecov-1.0.0/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb +70 -0
  48. data/simplecov-1.0.0/lib/simplecov/exit_codes.rb +18 -0
  49. data/simplecov-1.0.0/lib/simplecov/exit_handling.rb +158 -0
  50. data/simplecov-1.0.0/lib/simplecov/file_list.rb +164 -0
  51. data/simplecov-1.0.0/lib/simplecov/filter.rb +139 -0
  52. data/simplecov-1.0.0/lib/simplecov/formatter/base.rb +101 -0
  53. data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/application.css +1 -0
  54. data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/application.js +18 -0
  55. data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/favicon_green.png +0 -0
  56. data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/favicon_red.png +0 -0
  57. data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/favicon_yellow.png +0 -0
  58. data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter/public/index.html +56 -0
  59. data/simplecov-1.0.0/lib/simplecov/formatter/html_formatter.rb +79 -0
  60. data/simplecov-1.0.0/lib/simplecov/formatter/json_formatter/errors_formatter.rb +84 -0
  61. data/simplecov-1.0.0/lib/simplecov/formatter/json_formatter/result_hash_formatter.rb +128 -0
  62. data/simplecov-1.0.0/lib/simplecov/formatter/json_formatter/source_file_formatter.rb +99 -0
  63. data/simplecov-1.0.0/lib/simplecov/formatter/json_formatter.rb +87 -0
  64. data/simplecov-1.0.0/lib/simplecov/formatter/multi_formatter.rb +31 -0
  65. data/simplecov-1.0.0/lib/simplecov/formatter/simple_formatter.rb +23 -0
  66. data/simplecov-1.0.0/lib/simplecov/formatter.rb +14 -0
  67. data/simplecov-1.0.0/lib/simplecov/last_run.rb +35 -0
  68. data/simplecov-1.0.0/lib/simplecov/lines_classifier.rb +60 -0
  69. data/simplecov-1.0.0/lib/simplecov/load_global_config.rb +13 -0
  70. data/simplecov-1.0.0/lib/simplecov/no_defaults.rb +4 -0
  71. data/simplecov-1.0.0/lib/simplecov/parallel_adapters/base.rb +61 -0
  72. data/simplecov-1.0.0/lib/simplecov/parallel_adapters/generic.rb +44 -0
  73. data/simplecov-1.0.0/lib/simplecov/parallel_adapters/parallel_tests.rb +93 -0
  74. data/simplecov-1.0.0/lib/simplecov/parallel_adapters.rb +83 -0
  75. data/simplecov-1.0.0/lib/simplecov/parallel_coordination.rb +129 -0
  76. data/simplecov-1.0.0/lib/simplecov/process.rb +37 -0
  77. data/simplecov-1.0.0/lib/simplecov/profiles/bundler_filter.rb +5 -0
  78. data/simplecov-1.0.0/lib/simplecov/profiles/hidden_filter.rb +5 -0
  79. data/simplecov-1.0.0/lib/simplecov/profiles/rails.rb +32 -0
  80. data/simplecov-1.0.0/lib/simplecov/profiles/root_filter.rb +11 -0
  81. data/simplecov-1.0.0/lib/simplecov/profiles/strict.rb +32 -0
  82. data/simplecov-1.0.0/lib/simplecov/profiles/test_frameworks.rb +5 -0
  83. data/simplecov-1.0.0/lib/simplecov/profiles.rb +64 -0
  84. data/simplecov-1.0.0/lib/simplecov/result/missing_source_files_reporter.rb +49 -0
  85. data/simplecov-1.0.0/lib/simplecov/result/source_file_builder.rb +51 -0
  86. data/simplecov-1.0.0/lib/simplecov/result.rb +183 -0
  87. data/simplecov-1.0.0/lib/simplecov/result_adapter.rb +92 -0
  88. data/simplecov-1.0.0/lib/simplecov/result_merger/legacy_format_adapter.rb +28 -0
  89. data/simplecov-1.0.0/lib/simplecov/result_merger/resultset_file.rb +38 -0
  90. data/simplecov-1.0.0/lib/simplecov/result_merger/resultset_store.rb +50 -0
  91. data/simplecov-1.0.0/lib/simplecov/result_merger.rb +162 -0
  92. data/simplecov-1.0.0/lib/simplecov/result_processing.rb +179 -0
  93. data/simplecov-1.0.0/lib/simplecov/simulate_coverage.rb +75 -0
  94. data/simplecov-1.0.0/lib/simplecov/source_file/branch.rb +82 -0
  95. data/simplecov-1.0.0/lib/simplecov/source_file/branch_builder.rb +114 -0
  96. data/simplecov-1.0.0/lib/simplecov/source_file/builder_context.rb +28 -0
  97. data/simplecov-1.0.0/lib/simplecov/source_file/line.rb +77 -0
  98. data/simplecov-1.0.0/lib/simplecov/source_file/line_builder.rb +43 -0
  99. data/simplecov-1.0.0/lib/simplecov/source_file/method.rb +52 -0
  100. data/simplecov-1.0.0/lib/simplecov/source_file/method_builder.rb +58 -0
  101. data/simplecov-1.0.0/lib/simplecov/source_file/ruby_data_parser.rb +88 -0
  102. data/simplecov-1.0.0/lib/simplecov/source_file/skip_chunks.rb +75 -0
  103. data/simplecov-1.0.0/lib/simplecov/source_file/source_loader.rb +63 -0
  104. data/simplecov-1.0.0/lib/simplecov/source_file/statistics.rb +57 -0
  105. data/simplecov-1.0.0/lib/simplecov/source_file.rb +189 -0
  106. data/simplecov-1.0.0/lib/simplecov/static_coverage_extractor/method_collector.rb +55 -0
  107. data/simplecov-1.0.0/lib/simplecov/static_coverage_extractor/visitor.rb +171 -0
  108. data/simplecov-1.0.0/lib/simplecov/static_coverage_extractor.rb +110 -0
  109. data/simplecov-1.0.0/lib/simplecov/useless_results_remover.rb +27 -0
  110. data/simplecov-1.0.0/lib/simplecov/version.rb +5 -0
  111. data/simplecov-1.0.0/lib/simplecov-html.rb +4 -0
  112. data/simplecov-1.0.0/lib/simplecov.rb +255 -0
  113. data/simplecov-1.0.0/lib/simplecov_json_formatter.rb +4 -0
  114. data/simplecov-1.0.0/schemas/coverage-v1.0.schema.json +306 -0
  115. data/simplecov-1.0.0/schemas/coverage.schema.json +306 -0
  116. data/ultra-pro-pkg.gemspec +12 -0
  117. metadata +156 -0
@@ -0,0 +1,1524 @@
1
+ SimpleCov [![Gem Version](https://badge.fury.io/rb/simplecov.svg)](https://badge.fury.io/rb/simplecov) [![Build Status](https://github.com/simplecov-ruby/simplecov/actions/workflows/stable.yml/badge.svg?branch=main)][Continuous Integration] [![Lint](https://github.com/simplecov-ruby/simplecov/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/simplecov-ruby/simplecov/actions/workflows/lint.yml) [![Typecheck](https://github.com/simplecov-ruby/simplecov/actions/workflows/typecheck.yml/badge.svg?branch=main)](https://github.com/simplecov-ruby/simplecov/actions/workflows/typecheck.yml) [![Maintainability](https://api.codeclimate.com/v1/badges/c071d197d61953a7e482/maintainability)](https://codeclimate.com/github/simplecov-ruby/simplecov/maintainability)
2
+ =========
3
+
4
+ **Code coverage for Ruby**
5
+
6
+ * [Source Code]
7
+ * [API documentation]
8
+ * [Configuration]
9
+ * [Changelog]
10
+ * [Rubygem]
11
+ * [Continuous Integration]
12
+
13
+ [Coverage]: https://docs.ruby-lang.org/en/master/Coverage.html "API doc for Ruby's Coverage library"
14
+ [Source Code]: https://github.com/simplecov-ruby/simplecov "Source Code @ GitHub"
15
+ [API documentation]: http://rubydoc.info/gems/simplecov/frames "RDoc API Documentation at Rubydoc.info"
16
+ [Configuration]: http://rubydoc.info/gems/simplecov/SimpleCov/Configuration "Configuration options API documentation"
17
+ [Changelog]: https://github.com/simplecov-ruby/simplecov/blob/main/CHANGELOG.md "Project Changelog"
18
+ [Rubygem]: http://rubygems.org/gems/simplecov "SimpleCov @ rubygems.org"
19
+ [Continuous Integration]: https://github.com/simplecov-ruby/simplecov/actions?query=workflow%3Astable "SimpleCov is built around the clock by github.com"
20
+
21
+ SimpleCov is a code coverage analysis tool for Ruby. It uses [Ruby's built-in Coverage][Coverage] library to gather
22
+ coverage data, but makes processing the results much easier by providing a clean API to filter, group, merge, format,
23
+ and display them — a complete coverage suite you can set up in just a couple of lines.
24
+
25
+ SimpleCov tracks covered Ruby code; gathering coverage for templating solutions like ERB, Slim, and Haml is not
26
+ supported (though see [Eval coverage](#eval-coverage) for ERB).
27
+
28
+ In most cases you'll want overall coverage results spanning all of your tests — unit tests, Cucumber features, and so
29
+ on. SimpleCov handles this automatically by caching and merging results as it generates reports, so a report reflects
30
+ coverage across your whole test suite and gives you a truer picture of your blank spots.
31
+
32
+ SimpleCov bundles two formatters that need no extra gems: the default HTML formatter (which renders the browsable
33
+ report) and a JSON formatter. Both were once separate gems (`simplecov-html` and `simplecov_json_formatter`) but are
34
+ now built into SimpleCov and configured automatically when you launch it.
35
+
36
+ ## Getting started
37
+
38
+ 1. Add SimpleCov to your `Gemfile` and `bundle install`:
39
+
40
+ ```ruby
41
+ gem 'simplecov', require: false, group: :test
42
+ ```
43
+
44
+ 2. Load and launch SimpleCov **at the very top** of your test helper — `test/test_helper.rb`, `spec/spec_helper.rb`,
45
+ `rails_helper.rb`, Cucumber's `features/support/env.rb`, or whatever setup file your framework uses. SimpleCov
46
+ doesn't care which framework you run in; it just watches what code executes and reports on it, so the same two lines
47
+ work everywhere:
48
+
49
+ ```ruby
50
+ require 'simplecov'
51
+ SimpleCov.start
52
+
53
+ # Previous content of test helper now starts here
54
+ ```
55
+
56
+ > **Important:** `SimpleCov.start` **must** run **before any of your application code is required** — otherwise
57
+ > SimpleCov (and the underlying Coverage library) can't track those files. This bites hardest with tools that keep
58
+ > your app loaded between runs, like Spring; see the [Spring section](#using-spring-with-simplecov).
59
+
60
+ SimpleCov must run in the process you want to analyze. When you test a server process (e.g. a JSON API) from a
61
+ separate test process (e.g. via Selenium) and want to see all code the `rails server` executes — not just code in
62
+ your test files — require SimpleCov in the server process. For Rails, add this near the top of `bin/rails`, below
63
+ the shebang and after `config/boot` is required:
64
+
65
+ ```ruby
66
+ if ENV['RAILS_ENV'] == 'test'
67
+ require 'simplecov'
68
+ SimpleCov.start 'rails'
69
+ end
70
+ ```
71
+
72
+ 3. Run your full test suite to see your application's coverage.
73
+
74
+ 4. Open the HTML report in your default browser:
75
+
76
+ ```sh
77
+ simplecov open
78
+ ```
79
+
80
+ (The bundled `simplecov` CLI picks the right opener for your platform — `open` on macOS, `xdg-open` on Linux/BSD,
81
+ `start` on Windows. Pass `--report PATH` to open a non-default location. See [Command-line interface](#command-line-interface)
82
+ for the full set of subcommands.)
83
+
84
+ 5. Optionally, keep coverage results out of Git:
85
+
86
+ ```sh
87
+ echo coverage >> .gitignore
88
+ ```
89
+
90
+ For Rails applications, SimpleCov ships a built-in `rails` [profile](#profiles) that sets up groups for your
91
+ Controllers, Models, Helpers, and Libraries:
92
+
93
+ ```ruby
94
+ require 'simplecov'
95
+ SimpleCov.start 'rails'
96
+ ```
97
+
98
+ ## Example output
99
+
100
+ **Coverage results report, fully browsable locally with sorting and much more:**
101
+
102
+ ![SimpleCov coverage report](https://github.com/user-attachments/assets/33275385-e0f3-482d-b63e-2a6cd4965fe0)
103
+
104
+ **Source file coverage details view:**
105
+
106
+ ![SimpleCov source file detail view](https://github.com/user-attachments/assets/abcd93b4-a45d-48bb-a0e4-6129c4429193)
107
+
108
+ ## Configuration
109
+
110
+ [Configuration] settings can be applied in three equivalent formats:
111
+
112
+ * Directly in your start block (the most common way):
113
+
114
+ ```ruby
115
+ SimpleCov.start do
116
+ some_config_option 'foo'
117
+ end
118
+ ```
119
+
120
+ * As direct setters:
121
+
122
+ ```ruby
123
+ SimpleCov.some_config_option 'foo'
124
+ ```
125
+
126
+ * In a `configure` block — useful when you don't want to start coverage immediately, or want to add configuration later:
127
+
128
+ ```ruby
129
+ SimpleCov.configure do
130
+ some_config_option 'foo'
131
+ end
132
+ ```
133
+
134
+ See the [Configuration] API documentation for the full list of options.
135
+
136
+ ### Using `.simplecov` for centralized config
137
+
138
+ If you merge multiple test-suite results (e.g. RSpec and Cucumber) into a single report, you'd otherwise have to repeat
139
+ your filters / groups / profile in every test helper. To avoid that, place a `.simplecov` file at your project root
140
+ with the shared configuration; each test helper then requires SimpleCov and explicitly starts it:
141
+
142
+ ```ruby
143
+ # .simplecov — configuration only
144
+ SimpleCov.load_profile 'rails'
145
+ SimpleCov.skip 'lib/generators'
146
+ SimpleCov.group 'Models', 'app/models'
147
+
148
+ # spec/spec_helper.rb
149
+ require 'simplecov'
150
+ SimpleCov.start
151
+
152
+ # features/support/env.rb
153
+ require 'simplecov'
154
+ SimpleCov.start
155
+ ```
156
+
157
+ This is recommended whenever you merge frameworks that rely on each other, like Cucumber and RSpec.
158
+
159
+ > [!NOTE]
160
+ > Calling `SimpleCov.start` directly from `.simplecov` is deprecated. Tracking still begins for backward
161
+ > compatibility, but a one-time deprecation warning fires; a future release will require the explicit `SimpleCov.start`
162
+ > from a test helper. Migrating prevents a long-standing bug where `.simplecov` auto-loaded in a Rakefile or Rails'
163
+ > `Bundler.require` would leave an empty parent-process report that overwrites the test subprocess's good one. See
164
+ > [#581](https://github.com/simplecov-ruby/simplecov/issues/581).
165
+
166
+ ### Changing the report location
167
+
168
+ By default the report ends up in `SimpleCov.root / SimpleCov.coverage_dir`. For out-of-tree build setups
169
+ (CMake/CTest, Bazel, etc.) — where the build directory is elsewhere on the filesystem and you don't want the report
170
+ under the source root — set `SimpleCov.coverage_path` directly:
171
+
172
+ ```ruby
173
+ SimpleCov.start do
174
+ root '/source/checkout'
175
+ coverage_path '/tmp/build/coverage'
176
+ end
177
+ ```
178
+
179
+ Setting `coverage_path` explicitly pins the destination — subsequent changes to `root` or `coverage_dir` don't move
180
+ it. The directory is created if it doesn't already exist.
181
+
182
+ ### Running coverage only on demand
183
+
184
+ The Ruby STDLIB Coverage library is *very* fast (on a ~10-minute Rails suite the slowdown is only a couple of seconds),
185
+ so SimpleCov's policy is to generate coverage on every run — it costs you almost nothing and you always have the latest
186
+ results. There's therefore no built-in on-demand switch, but you can add one with an `ENV` conditional:
187
+
188
+ ```ruby
189
+ SimpleCov.start if ENV["COVERAGE"]
190
+ ```
191
+
192
+ Then coverage runs only when you ask for it:
193
+
194
+ ```sh
195
+ COVERAGE=true rake test
196
+ ```
197
+
198
+ ### Migrating from the legacy configuration API
199
+
200
+ The configuration API was redesigned to use a smaller set of consistent verbs. The legacy methods continue to work but
201
+ emit deprecation warnings that name their replacement; the table below is the canonical migration map.
202
+
203
+ | Legacy | New | Notes |
204
+ |-------------------------------------|----------------------------------|------------------------------------------------------------------------------------------------------------------------|
205
+ | `add_filter "lib/legacy"` | `skip "lib/legacy"` | Identical matcher grammar (string = path-segment substring; Regexp; block; Array). No behavior change. |
206
+ | `add_group "Models", "app/models"` | `group "Models", "app/models"` | Identical matcher grammar. No behavior change. |
207
+ | `track_files "lib/**/*.rb"` | `cover "lib/**/*.rb"` | `cover` includes unloaded files (the legacy `track_files` behavior) **and** restricts the report to the matching set. To keep the old additive-only behavior, pass every directory you want reported: `cover "lib/**/*.rb", "app/**/*.rb"`. |
208
+ | `use_merging false` | `merging false` | Same value, same behavior. |
209
+ | `enable_for_subprocesses true` | `merge_subprocesses true` | Same value, same behavior. |
210
+ | `enable_coverage_for_eval` | `enable_coverage :eval` | Eval coverage now folds into the same call you use to enable `:line`/`:branch`/`:method`: `enable_coverage :branch, :eval`. |
211
+ | `print_error_status` (reader) | `print_errors` | Reader only. The `print_error_status=` writer still works without a warning, but `print_errors true`/`print_errors false` is the new spelling. |
212
+ | `minimum_coverage_by_file line: 70, 'app/x.rb' => 100` | `coverage(:line) { minimum_per_file 70; minimum_per_file 100, only: 'app/x.rb' }` | The `coverage` block fixes the criterion, so per-path overrides are plain percentages with an `only:` target instead of a hash mixing Symbol / String / Regexp keys. See [Per-criterion thresholds](#per-criterion-thresholds-with-coverage). |
213
+ | `minimum_coverage_by_group 'Models' => { line: 90 }` | `coverage(:line) { minimum_per_group 90, only: 'Models' }` | Same uniform shape as `minimum_per_file`. |
214
+
215
+ Brand-new in the redesigned API (no legacy method to migrate from):
216
+
217
+ | Method | Purpose |
218
+ |-------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
219
+ | `cover "lib/**/*.rb"` | Positive scope (allowlist). Multiple calls union; strings are globs. See above for the relationship with `track_files`. |
220
+ | `no_default_skips` | Clear every previously-installed filter — defaults and anything earlier in the block — so subsequent `skip`s start clean.|
221
+ | `formatter false` / `formatters []` | Opt out of formatting entirely. Workers in big parallel CI runs only need their `.resultset.json` for a final `SimpleCov.collate` step; skipping the formatter saves the per-job HTML / multi-formatter overhead. See [#964](https://github.com/simplecov-ruby/simplecov/issues/964). |
222
+ | `parallel_tests true` / `false` | Force on / off the auto-require of the `parallel_tests` gem. Default (unset) auto-detects from `TEST_ENV_NUMBER` / `PARALLEL_TEST_GROUPS` and silently skips if the gem isn't installed. Set explicitly when you use those env vars for unrelated subprocess coordination. See [#1018](https://github.com/simplecov-ruby/simplecov/issues/1018). |
223
+
224
+ Example before/after:
225
+
226
+ ```ruby
227
+ # Before
228
+ SimpleCov.start do
229
+ add_filter "/test/"
230
+ add_filter %r{\Aconfig/}
231
+ add_group "Models", "app/models"
232
+ track_files "lib/**/*.rb"
233
+ enable_coverage_for_eval
234
+ use_merging true
235
+ enable_for_subprocesses true
236
+ end
237
+
238
+ # After
239
+ SimpleCov.start do
240
+ skip "/test/"
241
+ skip %r{\Aconfig/}
242
+ group "Models", "app/models"
243
+ cover "lib/**/*.rb"
244
+ enable_coverage :eval
245
+ merging true
246
+ merge_subprocesses true
247
+ end
248
+ ```
249
+
250
+ ## Coverage criteria
251
+
252
+ Line coverage is on by default. You can additionally enable branch, method, oneshot-line, and eval coverage, and choose
253
+ which criterion leads the report.
254
+
255
+ ### Disabling line coverage
256
+
257
+ If you want a branch-only or method-only run (e.g. you find the line numbers noisy in CI and only care about whether
258
+ each conditional was exercised), enable the criterion you want and then disable line coverage:
259
+
260
+ ```ruby
261
+ SimpleCov.start do
262
+ enable_coverage :branch
263
+ disable_coverage :line
264
+ end
265
+ ```
266
+
267
+ If you disable every criterion, `SimpleCov.start` raises `SimpleCov::ConfigurationError` — at least one of `:line`,
268
+ `:branch`, or `:method` must remain enabled.
269
+
270
+ ### Branch coverage
271
+
272
+ Branch coverage records whether each branch of a condition executed, not just whether a line ran.
273
+
274
+ ```ruby
275
+ SimpleCov.start do
276
+ enable_coverage :branch
277
+ end
278
+ ```
279
+
280
+ It's handy for one-line conditionals:
281
+
282
+ ```ruby
283
+ number.odd? ? "odd" : "even"
284
+ ```
285
+
286
+ Line coverage always marks this line as executed, but never tells you whether both arms were taken. Guard clauses have
287
+ the same story:
288
+
289
+ ```ruby
290
+ return if number.odd?
291
+
292
+ # more code
293
+ ```
294
+
295
+ If the whole method is covered you still won't know whether the guard ever triggered — line coverage just sees the
296
+ condition evaluated.
297
+
298
+ In the HTML report, lines are annotated as `branch_type: hit_count`:
299
+
300
+ * `then: 2` — the `then` branch (of an `if`) was executed twice
301
+ * `else: 0` — the `else` branch (of an `if` or `case`) was never executed
302
+
303
+ Even if you don't write an `else` branch, it still shows up: a missed implicit `else` means the `if` condition was
304
+ never false, or no `when` of a `case` matched.
305
+
306
+ **Is branch coverage strictly better?** No. Branch coverage only concerns itself with conditionals — coverage of
307
+ sequential code is of no interest to it. A file with no conditional logic has no branch data, and SimpleCov reports its
308
+ 0-of-0 branches as 100% (everything coverable was covered). So look at both metrics together: missing 10% of your lines
309
+ might account for 50% of your branches.
310
+
311
+ #### Ignoring implicit `else` branches
312
+
313
+ Ruby's `Coverage` library reports an `:else` branch for several constructs even when the source has no literal `else`
314
+ keyword — exhaustive `case/in` pattern matches, `case/when` without an `else` arm, `||=` / `&&=`, and `if` / `unless`
315
+ without an `else`. Those synthetic branches show up as missed and depress the branch-coverage percentage despite there
316
+ being no code to test. If your style relies on exhaustive pattern matching (or you just want `||=` to stop tanking
317
+ coverage), opt out:
318
+
319
+ ```ruby
320
+ SimpleCov.start do
321
+ enable_coverage :branch
322
+ ignore_branches :implicit_else
323
+ end
324
+ ```
325
+
326
+ `ignore_branches` is variadic; `:implicit_else` and `:eval_generated` (below) are the supported tokens. Calling it
327
+ before (or without) `enable_coverage :branch` is harmless: the setting is stored and applies once branch coverage is
328
+ enabled. Explicit `else` arms still count.
329
+
330
+ #### Ignoring eval-generated branches and methods
331
+
332
+ Rails' `delegate` (and other macros that call `module_eval(body, __FILE__, __LINE__)`) make Ruby's `Coverage` library
333
+ attribute the eval'd code to the macro's source line. The result is a `delegate :foo, to: :bar` line that surfaces in
334
+ the report as if it had its own `def foo` and an `if` branch — both reported as missed when the delegated method isn't
335
+ called from the suite. Drop those synthetic entries:
336
+
337
+ ```ruby
338
+ SimpleCov.start do
339
+ enable_coverage :branch
340
+ enable_coverage :method
341
+ ignore_branches :eval_generated
342
+ ignore_methods :eval_generated
343
+ end
344
+ ```
345
+
346
+ `ignore_methods` is variadic; `:eval_generated` is the only supported token. Both filters detect eval-generated entries
347
+ by walking the static source with [Prism](https://github.com/ruby/prism) and dropping any Coverage entry whose start
348
+ line lacks a real `def` keyword (for methods) or branch construct (for branches). Prism is bundled with Ruby 3.3+; on
349
+ older Rubies `gem install prism` enables the filter, otherwise it's a silent no-op. Real `def`s and branches that share
350
+ a line with an eval-generated entry are kept (line-presence is the matcher).
351
+
352
+ ### Oneshot lines coverage
353
+
354
+ Oneshot lines coverage is a faster alternative to line coverage.
355
+
356
+ Traditional coverage records *how many times* each line ran. Often it's enough to know *whether* each line ran at
357
+ least once — and the counting just adds overhead. Oneshot coverage records only the first execution of each line; the
358
+ hook for each line fires once, after which the program runs with zero overhead.
359
+
360
+ ```ruby
361
+ SimpleCov.start do
362
+ enable_coverage :oneshot_line
363
+ primary_coverage :oneshot_line
364
+ end
365
+ ```
366
+
367
+ ### Eval coverage
368
+
369
+ You can measure coverage for code evaluated by `Kernel#eval`. Supported in CRuby 3.2+.
370
+
371
+ ```ruby
372
+ SimpleCov.start do
373
+ enable_coverage :eval
374
+ end
375
+ ```
376
+
377
+ This is typically useful for ERB. Set `ERB#filename=` so SimpleCov can trace the original `.erb` source file.
378
+
379
+ ### Primary coverage
380
+
381
+ By default the primary coverage type is `line`. The primary type determines what comes first in all output, and which
382
+ type is checked when you customize exit behavior without naming a type (e.g. `SimpleCov.minimum_coverage 90`). To change
383
+ it:
384
+
385
+ ```ruby
386
+ SimpleCov.start do
387
+ enable_coverage :branch
388
+ primary_coverage :branch
389
+ end
390
+
391
+ # or, outside a block:
392
+ SimpleCov.primary_coverage :branch
393
+ ```
394
+
395
+ Coverage must first be enabled for non-default types.
396
+
397
+ ## Filters
398
+
399
+ Filters remove selected files from your coverage data.
400
+
401
+ ### Default filters
402
+
403
+ `SimpleCov.start` loads four filters out of the box:
404
+
405
+ * **`root_filter`** — drops every file outside of `SimpleCov.root`, so you don't end up with coverage reports for the
406
+ source files of every gem in your bundle. (See [Covering files outside the root](#covering-files-outside-the-root).)
407
+ * **`bundler_filter`** — drops `/vendor/bundle/` (in case a project keeps its gems checked into the repo).
408
+ * **`hidden_filter`** — drops any path that starts with a dot, matching the regex `/\A\..*/`. This is what hides
409
+ `.bundle/`, `.semaphore-cache/`, and similar dotfile directories — but it also hides legitimate top-level directories
410
+ like `.scripts/`. If you keep code in such a directory, remove this filter (see below).
411
+ * **`test_frameworks`** — drops common test directories (`test/`, `spec/`, `features/`, `autotest/`), matching the
412
+ regex `%r{\A(test|features|spec|autotest)/}`. Running the test suite always executes 100% of the test files
413
+ themselves, which inflates the overall percentage and obscures application coverage. Remove this filter if you
414
+ prefer to see test files in the report (e.g. to surface dead helpers).
415
+
416
+ For a clean slate (no defaults at all), `require 'simplecov/no_defaults'` *before* `require 'simplecov'`, or call
417
+ `SimpleCov.clear_filters` from your config block. To drop a specific default while keeping the others, use
418
+ `remove_filter`:
419
+
420
+ ```ruby
421
+ SimpleCov.start do
422
+ remove_filter(/\A\..*/) # restore coverage for .scripts/, .tooling/, etc.
423
+ end
424
+ ```
425
+
426
+ `remove_filter` matches by value, so pass back the same `String` or `Regexp` the default profile used. For filters
427
+ added with a block, pass the same `Proc` object you originally handed to `skip`.
428
+
429
+ ### Defining custom filters
430
+
431
+ Define your own filters to remove configuration files, tests, or anything else you don't need in the report. A filter
432
+ can be a String or Regexp (Regexp-matched against each source file's path), a block, your own Filter class, or an array
433
+ of any of these.
434
+
435
+ #### String filter
436
+
437
+ ```ruby
438
+ SimpleCov.start do
439
+ skip "/test/"
440
+ end
441
+ ```
442
+
443
+ Removes all files whose path matches "/test/".
444
+
445
+ #### Regex filter
446
+
447
+ ```ruby
448
+ SimpleCov.start do
449
+ skip %r{^/test/}
450
+ end
451
+ ```
452
+
453
+ Removes all files whose path starts with /test/.
454
+
455
+ #### Block filter
456
+
457
+ ```ruby
458
+ SimpleCov.start do
459
+ skip do |source_file|
460
+ source_file.lines.count < 5
461
+ end
462
+ end
463
+ ```
464
+
465
+ Block filters receive a `SimpleCov::SourceFile` and return `true` to remove the file or `false` to keep it. (See the
466
+ RDoc for `SimpleCov::SourceFile` for the available methods.) The example above removes files with fewer than 5 lines.
467
+
468
+ #### Custom filter class
469
+
470
+ ```ruby
471
+ class LineFilter < SimpleCov::Filter
472
+ def matches?(source_file)
473
+ source_file.lines.count < filter_argument
474
+ end
475
+ end
476
+
477
+ SimpleCov.skip LineFilter.new(5)
478
+ ```
479
+
480
+ Inherit from `SimpleCov::Filter` and define `matches?(source_file)`; a `true` return removes the file. The
481
+ `filter_argument` is set in the `SimpleCov::Filter` initializer — `5` in this example.
482
+
483
+ #### Array filter
484
+
485
+ ```ruby
486
+ SimpleCov.start do
487
+ proc = Proc.new { |source_file| false }
488
+ skip ["string", /regex/, proc, LineFilter.new(5)]
489
+ end
490
+ ```
491
+
492
+ Pass an array containing any of the other filter types.
493
+
494
+ ### Ignoring/skipping code
495
+
496
+ Disable coverage for a span of code with `# simplecov:disable` and `# simplecov:enable` comments. The available
497
+ categories are `line`, `branch`, and `method`; combine them with commas, and omit them to target all three. Anything
498
+ trailing the directive is treated as a free-form reason and ignored — no separator is required, though `--` or any
499
+ other marker is fine if you prefer one.
500
+
501
+ ```ruby
502
+ # simplecov:disable line
503
+ def skipped_lines
504
+ never_reached
505
+ end
506
+ # simplecov:enable line
507
+
508
+ # simplecov:disable branch, method legacy adapter, scheduled for removal
509
+ class LegacyAdapter
510
+ def call(value)
511
+ value ? :yes : :no
512
+ end
513
+ end
514
+ # simplecov:enable
515
+
516
+ raise "absurd" # simplecov:disable
517
+ ```
518
+
519
+ Inline directives (trailing real code) only affect the line they sit on. Block directives sit on their own line and
520
+ remain in effect until the matching `# simplecov:enable` for the same category — or end of file if never closed.
521
+ Directive markers inside string literals or heredocs are ignored.
522
+
523
+ > [!WARNING]
524
+ > The older `# :nocov:` toggle still works but is **deprecated** and will be removed in a future release. Each file
525
+ > that uses it emits a one-time deprecation warning pointing at the recommended `# simplecov:disable` /
526
+ > `# simplecov:enable` replacement. The configurable token name (`SimpleCov.nocov_token`) is similarly deprecated.
527
+
528
+ > [!NOTE]
529
+ > You shouldn't have to skip private methods that are included in your coverage. If you appropriately test the public
530
+ > interface of your classes and objects, you should automatically get full coverage of your private methods.
531
+
532
+ ### How `cover` and `skip` interact
533
+
534
+ `cover` and `skip` operate on different sides of the same chain. `skip` (and its deprecated `add_filter` alias) drops
535
+ matching files from the report. `cover` declares a positive scope that restricts the final report to files matching at
536
+ least one `cover` matcher.
537
+
538
+ Order: `skip` runs first, then `cover`. A file matched by any `skip` filter is dropped before `cover` is consulted, so
539
+ a file matched by both is dropped, not kept. The two are not commutative.
540
+
541
+ ```ruby
542
+ SimpleCov.start do
543
+ cover "{app,lib}/**/*.rb"
544
+ skip "app/legacy"
545
+ end
546
+ ```
547
+
548
+ That config covers `app/` and `lib/`, then drops `app/legacy/`. With only `cover` and no overlapping `skip`, every
549
+ configured default filter (hidden files, vendored gems, test directories) still applies — `cover` doesn't bypass them.
550
+ Use `no_default_skips` to opt out of the defaults wholesale before adding your own.
551
+
552
+ `cover` also expands string-glob matchers on disk so files that exist but were never `require`'d during the run still
553
+ appear in the report (at 0% coverage). Regexp and Proc cover matchers don't trigger disk discovery — they only filter
554
+ the universe of files that Ruby's `Coverage` library reported.
555
+
556
+ ### Covering files outside the root
557
+
558
+ The `root_filter` drops every file outside of `SimpleCov.root` from the raw coverage data before any other filters or
559
+ groups run, so paths you might want to track (a Rails Engine installed as a gem, sibling directories in a Docker
560
+ layout, etc.) never reach your filter chain. To include them, widen `SimpleCov.root` to a directory that contains both
561
+ the project and the extra paths — `'/'` works when there's no useful common ancestor — and then express the
562
+ inclusion/exclusion as filters or groups:
563
+
564
+ ```ruby
565
+ SimpleCov.root '/'
566
+ SimpleCov.start :rails do
567
+ skip { |src| !src.filename.start_with?(Rails.root.to_s, '/path/to/my_engine') }
568
+ end
569
+ ```
570
+
571
+ ## Groups
572
+
573
+ Separate your source files into groups — for example, a Rails app might list Models, Controllers, Helpers, and Libs
574
+ separately. Group definition works like filters (and also accepts custom filter classes), but a source file ends up in
575
+ a group when the filter *passes* (returns `true`), as opposed to being excluded from results when a filter returns
576
+ `true`.
577
+
578
+ ```ruby
579
+ SimpleCov.start do
580
+ group "Models", "app/models"
581
+ group "Controllers", "app/controllers"
582
+ group "Long files" do |src_file|
583
+ src_file.lines.count > 100
584
+ end
585
+ group "Multiple Files", ["app/models", "app/controllers"] # You can also pass in an array
586
+ group "Short files", LineFilter.new(5) # Using the LineFilter class defined in the Filters section above
587
+ end
588
+ ```
589
+
590
+ ## Profiles
591
+
592
+ By default, SimpleCov's only assumption is that you want coverage for files inside your project root. To avoid
593
+ repetitive configuration, you can use predefined blocks of configuration called 'profiles', or define your own. Pass a
594
+ profile's name as the first argument to `SimpleCov.start`.
595
+
596
+ SimpleCov bundles a `rails` profile that looks roughly like this:
597
+
598
+ ```ruby
599
+ SimpleCov.profiles.define 'rails' do
600
+ skip '/test/'
601
+ skip '/config/'
602
+
603
+ group 'Controllers', 'app/controllers'
604
+ group 'Models', 'app/models'
605
+ group 'Helpers', 'app/helpers'
606
+ group 'Libraries', 'lib'
607
+ end
608
+ ```
609
+
610
+ It's just a `SimpleCov.configure` block. Launch it from your test helper, optionally adding more config:
611
+
612
+ ```ruby
613
+ SimpleCov.start 'rails'
614
+
615
+ # or
616
+
617
+ SimpleCov.start 'rails' do
618
+ # additional config here
619
+ end
620
+ ```
621
+
622
+ ### The `strict` profile
623
+
624
+ For projects that have already reached full coverage (or want to ratchet up to it), the bundled `strict` profile
625
+ enables line, branch, and method coverage and pins each minimum threshold at 100%:
626
+
627
+ ```ruby
628
+ SimpleCov.start 'strict'
629
+ ```
630
+
631
+ That's equivalent to:
632
+
633
+ ```ruby
634
+ SimpleCov.start do
635
+ enable_coverage :branch
636
+ enable_coverage :method
637
+ enable_coverage :eval if Coverage.respond_to?(:supported?) && Coverage.supported?(:eval)
638
+ minimum_coverage line: 100, branch: 100, method: 100
639
+ end
640
+ ```
641
+
642
+ The profile drops the branch / method clauses on engines that don't support those criteria (JRuby), so it still loads
643
+ cleanly there, enforcing line coverage at 100%. `:eval` is included on Ruby 3.2+ (where the runtime supports it), so
644
+ any code reached through `Kernel#eval` — typically ERB templates with `ERB#filename=` set — is held to the same 100%
645
+ bar. On older Rubies, the `:eval` clause is silently skipped.
646
+
647
+ ### Custom profiles
648
+
649
+ Load additional profiles with `SimpleCov.load_profile('xyz')`. This lets you build on an existing profile and reuse
650
+ it across unit tests and Cucumber features:
651
+
652
+ ```ruby
653
+ # lib/simplecov_custom_profile.rb
654
+ require 'simplecov'
655
+ SimpleCov.profiles.define 'myprofile' do
656
+ load_profile 'rails'
657
+ skip 'vendor' # Don't include vendored stuff
658
+ end
659
+
660
+ # features/support/env.rb
661
+ require 'simplecov_custom_profile'
662
+ SimpleCov.start 'myprofile'
663
+
664
+ # test/test_helper.rb
665
+ require 'simplecov_custom_profile'
666
+ SimpleCov.start 'myprofile'
667
+ ```
668
+
669
+ ### Profile plugin gems
670
+
671
+ If `SimpleCov.start "<name>"` doesn't find a profile registered under `<name>`, the bundled profile loader tries to
672
+ autoload one in two steps: first `require "simplecov/profiles/<name>"` (where bundled profiles like `rails` and
673
+ `strict` live), then `require "simplecov-profile-<name>"` (the conventional name for a third-party plugin gem). Either
674
+ require is expected to call `SimpleCov.profiles.define "<name>" do ... end` so the registered block can be applied. If
675
+ both requires fail or neither registers the profile, `SimpleCov.start` raises `SimpleCov::ConfigurationError`.
676
+
677
+ To publish your own profile as a gem, name it `simplecov-profile-<name>` and have its main file call
678
+ `SimpleCov.profiles.define`:
679
+
680
+ ```ruby
681
+ # In a gem named simplecov-profile-myteam
682
+ SimpleCov.profiles.define "myteam" do
683
+ enable_coverage :branch
684
+ cover "{app,lib}/**/*.rb"
685
+ skip "app/legacy"
686
+ end
687
+ ```
688
+
689
+ A user who adds the gem to their Gemfile can then `SimpleCov.start "myteam"` without explicitly requiring it.
690
+
691
+ ## Merging results and parallel tests
692
+
693
+ You normally want coverage analyzed across ALL of your test suites at once. SimpleCov automatically caches results in
694
+ `(coverage_path)/.resultset.json` and merges them with subsequent runs — or overrides them, depending on whether it
695
+ considers a subsequent run a different test suite or the same one. To make that distinction, SimpleCov uses the concept
696
+ of **test suite names**.
697
+
698
+ ### Test suite names
699
+
700
+ SimpleCov guesses the running suite's name from the shell command that started the tests. This works fine for Test::Unit,
701
+ RSpec, and Cucumber; if it fails, it falls back to the invoking shell command as the command name.
702
+
703
+ For a non-standard setup, give SimpleCov a cue with `SimpleCov.command_name` in one test file per suite (you only need
704
+ it once per suite — even with 200 unit test files, setting it in one is enough):
705
+
706
+ ```ruby
707
+ # test/unit/some_test.rb
708
+ SimpleCov.command_name 'test:units'
709
+
710
+ # test/functionals/some_controller_test.rb
711
+ SimpleCov.command_name "test:functionals"
712
+
713
+ # test/integration/some_integration_test.rb
714
+ SimpleCov.command_name "test:integration"
715
+
716
+ # features/support/env.rb
717
+ SimpleCov.command_name "features"
718
+ ```
719
+
720
+ **If multiple suites resolve to the same `command_name`, their results clobber each other instead of merging.**
721
+ SimpleCov detects unique names for the most common setups, but if you have more than one suite that doesn't follow a
722
+ common pattern, ensure each gets a unique `command_name`.
723
+
724
+ When running tests in parallel, each process can clobber the others' results. With the default `command_name`,
725
+ SimpleCov detects and avoids collisions based on `ENV['PARALLEL_TEST_GROUPS']` and `ENV['TEST_ENV_NUMBER']`. If your
726
+ runner sets neither, *you must* set a `command_name` that's unique per process (e.g. `command_name "Unit Tests PID #{$$}"`).
727
+ With parallel_tests specifically, incorporate `TEST_ENV_NUMBER` into the name yourself so results merge correctly:
728
+
729
+ ```ruby
730
+ # spec/spec_helper.rb
731
+ SimpleCov.command_name "features" + (ENV['TEST_ENV_NUMBER'] || '')
732
+ ```
733
+
734
+ The HTML report prints the test suites it used in its footer.
735
+
736
+ ### Merging within one execution environment
737
+
738
+ Results are automatically merged with previous runs in the same execution environment when the report is generated, so
739
+ once coverage is set up for Cucumber and your unit / functional / integration tests, all of those suites feed into one
740
+ report.
741
+
742
+ Cached coverage data eventually goes stale, so result sets older than `SimpleCov.merge_timeout` are dropped from the
743
+ merge. The default is 600 seconds (10 minutes); raise or lower it with `SimpleCov.merge_timeout 3600` (1 hour), or
744
+ `merge_timeout 3600` inside a configure/start block. Deactivate automatic merging entirely with `SimpleCov.merging false`.
745
+
746
+ In a parallel run, the process that writes the final report waits for the other workers to finish and write their
747
+ result sets before merging. It gives up after `SimpleCov.parallel_wait_timeout` seconds (default 60) and reports
748
+ whatever has arrived, skipping the minimum / maximum coverage checks against that partial total. If one worker runs
749
+ much heavier test files and routinely finishes a minute or more after the others, raise it with
750
+ `SimpleCov.parallel_wait_timeout 180` so its coverage is included.
751
+
752
+ ### Merge finalization ownership
753
+
754
+ `SimpleCov.merging true` stores each process' resultset so it can be merged with other suites or workers. By default,
755
+ SimpleCov also owns **finalizing** that merge: waiting for sibling workers, building the merged result, formatting the
756
+ report, enforcing minimum / maximum coverage, and writing `.last_run.json`.
757
+
758
+ Some parallel runners intentionally write each worker's resultset to a separate coverage directory and then run an
759
+ explicit cleanup step with `SimpleCov.collate`. In that setup, workers should still store their resultsets, but the
760
+ cleanup task owns finalization:
761
+
762
+ ```ruby
763
+ # spec/spec_helper.rb
764
+ SimpleCov.start do
765
+ if ENV["TEST_ENV_NUMBER"]
766
+ merging true
767
+ coverage_dir "coverage/turbo_tests/#{ENV["TEST_ENV_NUMBER"]}"
768
+ command_name "rspec-#{ENV["TEST_ENV_NUMBER"]}"
769
+ finalize_merge false
770
+ end
771
+ end
772
+ ```
773
+
774
+ ```ruby
775
+ # Rakefile
776
+ task "coverage:collate" do
777
+ require "simplecov"
778
+
779
+ SimpleCov.collate Dir["coverage/turbo_tests/*/.resultset.json"] do
780
+ coverage(:line) { minimum 100 }
781
+ coverage(:branch) { minimum 100 }
782
+ end
783
+ end
784
+ ```
785
+
786
+ When `finalize_merge false`, the worker writes its `.resultset.json` and exits without waiting for siblings, formatting,
787
+ checking thresholds, or writing `.last_run.json`. The `SimpleCov.collate` process is the finalizer and performs those
788
+ steps for the merged result.
789
+
790
+ For compatibility, SimpleCov infers `finalize_merge false` and prints a configuration warning only when all of these are
791
+ true: a recognized parallel adapter is active, more than one worker is expected, merging is enabled, the coverage
792
+ destination was explicitly changed from the default, and the process has parallel-worker environment variables. Set
793
+ `SimpleCov.finalize_merge false` to keep external collation ownership without the warning, or
794
+ `SimpleCov.finalize_merge true` if the selected worker should own the built-in wait / merge / report flow even with a
795
+ custom coverage destination.
796
+
797
+ ### Merging across execution environments
798
+
799
+ If your tests run in parallel across multiple build machines, download each run's `.resultset.json` and merge them into
800
+ a single result set with `SimpleCov.collate`:
801
+
802
+ ```ruby
803
+ # lib/tasks/coverage_report.rake
804
+ namespace :coverage do
805
+ desc "Collates all result sets generated by the different test runners"
806
+ task :report do
807
+ require 'simplecov'
808
+
809
+ SimpleCov.collate Dir["simplecov-resultset-*/.resultset.json"]
810
+ end
811
+ end
812
+ ```
813
+
814
+ `SimpleCov.collate` also takes an optional profile and an optional configuration block, just like `SimpleCov.start` or
815
+ `SimpleCov.configure`. This means you can configure a separate formatter for the collated output — for instance, use the
816
+ plain `SimpleCov::Formatter::SimpleFormatter` in each worker's `SimpleCov.start` and reserve heavier formatters for the
817
+ final `SimpleCov.collate` run:
818
+
819
+ ```ruby
820
+ # spec/spec_helper.rb
821
+ require 'simplecov'
822
+
823
+ SimpleCov.start 'rails' do
824
+ # Disambiguates individual test runs
825
+ command_name "Job #{ENV["TEST_ENV_NUMBER"]}" if ENV["TEST_ENV_NUMBER"]
826
+
827
+ if ENV['CI']
828
+ formatter SimpleCov::Formatter::SimpleFormatter
829
+ else
830
+ formatter SimpleCov::Formatter::MultiFormatter.new([
831
+ SimpleCov::Formatter::SimpleFormatter,
832
+ SimpleCov::Formatter::HTMLFormatter
833
+ ])
834
+ end
835
+
836
+ cover "{app,lib}/**/*.rb"
837
+ end
838
+ ```
839
+
840
+ ```ruby
841
+ # lib/tasks/coverage_report.rake
842
+ namespace :coverage do
843
+ task :report do
844
+ require 'simplecov'
845
+
846
+ SimpleCov.collate Dir["simplecov-resultset-*/.resultset.json"], 'rails' do
847
+ formatter SimpleCov::Formatter::MultiFormatter.new([
848
+ SimpleCov::Formatter::SimpleFormatter,
849
+ SimpleCov::Formatter::HTMLFormatter
850
+ ])
851
+ end
852
+ end
853
+ end
854
+ ```
855
+
856
+ ### Forked subprocesses
857
+
858
+ `SimpleCov.merge_subprocesses true` lets SimpleCov observe subprocesses started with `Process.fork`. It wraps Ruby's
859
+ `Process.fork` so SimpleCov can see into the child, appending `" (subprocess #{pid})"` to the `command_name`, with
860
+ results that merge back together. Configure the child with `.at_fork`:
861
+
862
+ ```ruby
863
+ SimpleCov.merge_subprocesses true
864
+ SimpleCov.at_fork do |pid|
865
+ # This needs a unique name so it won't be overwritten
866
+ SimpleCov.command_name "#{SimpleCov.command_name} (subprocess: #{pid})"
867
+ # be quiet, the parent process will be in charge of output and checking coverage totals
868
+ SimpleCov.print_errors false
869
+ SimpleCov.formatter SimpleCov::Formatter::SimpleFormatter
870
+ SimpleCov.minimum_coverage 0
871
+ # start
872
+ SimpleCov.start
873
+ end
874
+ ```
875
+
876
+ SimpleCov must already be started before `Process.fork` is called.
877
+
878
+ > [!NOTE]
879
+ > The bundled `rails` profile turns this on automatically, so `ActiveSupport::TestCase.parallelize(workers: ...)`
880
+ > worker forks contribute to the merged report instead of being silently dropped.
881
+
882
+ #### Spawned subprocesses
883
+
884
+ You can also cover a Ruby script you launch with `PTY.spawn`, `Open3.popen`, `Process.spawn`, and the like. Add a
885
+ `.simplecov_spawn.rb` file to your project root:
886
+
887
+ ```ruby
888
+ # .simplecov_spawn.rb
889
+ require 'simplecov' # this will also pick up whatever config is in .simplecov,
890
+ # so ensure it just contains configuration and doesn't call SimpleCov.start.
891
+ SimpleCov.command_name 'spawn' # As this isn't for a test runner directly, the script has no pre-defined base command_name
892
+ SimpleCov.at_fork.call(Process.pid) # Use the per-process setup described above
893
+ SimpleCov.start # only now can we start
894
+ ```
895
+
896
+ Then, instead of spawning your script directly:
897
+
898
+ ```ruby
899
+ PTY.spawn('my_script.rb') do # ...
900
+ ```
901
+
902
+ use `ruby -r` to require the spawn file first:
903
+
904
+ ```ruby
905
+ PTY.spawn('ruby -r./.simplecov_spawn my_script.rb') do # ...
906
+ ```
907
+
908
+ ### Parallel-test-runner adapters
909
+
910
+ SimpleCov coordinates with parallel test runners through a small pluggable adapter interface
911
+ (`SimpleCov::ParallelAdapters`). Two adapters ship out of the box:
912
+
913
+ - **`ParallelTestsAdapter`** — wraps the [grosser/parallel_tests](https://github.com/grosser/parallel_tests) gem and
914
+ uses its `ParallelTests.first_process?` / `ParallelTests.wait_for_other_processes_to_finish` APIs for precise worker
915
+ coordination. Activates only when the native `parallel_tests` pid-file contract is present.
916
+ - **`GenericAdapter`** — catch-all for any runner that follows the `TEST_ENV_NUMBER` / `PARALLEL_TEST_GROUPS` env-var
917
+ convention but doesn't ship a Ruby API (parallel_rspec, knapsack-style splitters, custom CI sharding scripts).
918
+ Activates when `TEST_ENV_NUMBER` is set and no more-specific adapter is.
919
+
920
+ Adapters are tried in registration order; the first whose `active?` returns `true` is chosen. With both built-ins, this
921
+ means parallel_tests users get the precise gem-based path and parallel_rspec (or any env-var-only runner) gets the
922
+ polling-based fallback without any configuration change. See [#1065](https://github.com/simplecov-ruby/simplecov/issues/1065).
923
+
924
+ #### Registering a custom adapter
925
+
926
+ If you use a parallel runner with different env vars or its own synchronization API, define a class that inherits from
927
+ `SimpleCov::ParallelAdapters::Base` and register it:
928
+
929
+ ```ruby
930
+ # In your spec_helper.rb / test_helper.rb (before SimpleCov.start)
931
+ class MyRunnerAdapter < SimpleCov::ParallelAdapters::Base
932
+ def self.active?
933
+ !ENV["MY_RUNNER_PID"].nil?
934
+ end
935
+
936
+ def self.first_worker?
937
+ ENV["MY_RUNNER_PID"].to_i == 1
938
+ end
939
+
940
+ def self.wait_for_siblings
941
+ MyRunner.barrier! # if your runner provides a sync primitive
942
+ end
943
+
944
+ def self.expected_worker_count
945
+ ENV["MY_RUNNER_WORKERS"].to_i
946
+ end
947
+ end
948
+
949
+ SimpleCov::ParallelAdapters.register MyRunnerAdapter
950
+ ```
951
+
952
+ Custom adapters are inserted at the front of the selection chain, so they take precedence over the built-ins. `Base`
953
+ provides safe no-op defaults for any method you don't override (single-process semantics: `active?` returns `false`,
954
+ `first_worker?` returns `true`, etc.).
955
+
956
+ ## Coverage thresholds and exit behavior
957
+
958
+ Define what SimpleCov does when your test suite finishes by customizing the `at_exit` hook. The default is shown below;
959
+ do whatever you like instead:
960
+
961
+ ```ruby
962
+ SimpleCov.at_exit do
963
+ SimpleCov.result.format!
964
+ end
965
+ ```
966
+
967
+ The threshold settings below make SimpleCov exit non-zero when coverage doesn't meet your expectations, so they double
968
+ as CI gates.
969
+
970
+ ### Per-criterion thresholds with `coverage`
971
+
972
+ The `coverage` block configures each criterion (line, branch, method) the same way: because the criterion is fixed by
973
+ the enclosing block, every threshold value is a plain percentage, so line, branch, and method coverage read identically.
974
+ Naming a criterion also enables it (line is enabled by default).
975
+
976
+ ```ruby
977
+ SimpleCov.start do
978
+ coverage :line do
979
+ minimum 90 # suite-wide minimum; SimpleCov exits non-zero if unmet
980
+ minimum_per_file 80 # per-file minimum
981
+ minimum_per_file 100, only: "app/mailers/request_mailer.rb" # per-path override (String path or Regexp)
982
+ minimum_per_group 95, only: "Models" # minimum for a named group
983
+ maximum_drop 5 # exit non-zero if coverage drops more than 5% between runs
984
+ end
985
+
986
+ coverage :branch, minimum: 80 # one-liner form for a single setting
987
+ coverage :method, minimum: 100
988
+ end
989
+ ```
990
+
991
+ | Verb | Effect |
992
+ |------|--------|
993
+ | `minimum N` | Suite-wide minimum for this criterion. |
994
+ | `maximum N` | Suite-wide maximum: fails if coverage rises above N. Pairs with `minimum` to pin coverage so an unexpected jump fails instead of being silently absorbed. |
995
+ | `exact N` | Pins coverage by setting both `minimum` and `maximum` to N. |
996
+ | `maximum_drop N` | Maximum allowed drop between runs (`maximum_drop 0` refuses any drop). |
997
+ | `minimum_per_file N` | Per-file minimum. Add `only: "path"` / `only: %r{regexp}` to override it for matching files (later, more specific overrides win). |
998
+ | `minimum_per_group N, only: "Name"` | Minimum for a named [group](#groups). |
999
+
1000
+ Every verb is also a keyword on the one-liner form (`coverage :branch, minimum: 80, maximum_drop: 5`). Two more options:
1001
+ `coverage :line, oneshot: true` selects the faster [oneshot-lines mode](#oneshot-lines-coverage), and
1002
+ `coverage :branch, primary: true` makes branch the report's leading criterion (the one a bare `minimum_coverage 90`
1003
+ targets). `coverage :eval` enables [eval coverage](#eval-coverage).
1004
+
1005
+ ### Suite-wide shortcuts
1006
+
1007
+ For the common case of a single suite-wide threshold, the flat helpers are convenient sugar over the block above. A bare
1008
+ number targets the primary criterion (line by default); a Hash sets per-criterion values:
1009
+
1010
+ ```ruby
1011
+ SimpleCov.minimum_coverage 90 # primary criterion (line)
1012
+ SimpleCov.minimum_coverage line: 90, branch: 80
1013
+ SimpleCov.maximum_coverage line: 90
1014
+ SimpleCov.maximum_coverage_drop line: 5, branch: 10
1015
+ SimpleCov.expected_coverage 95.42 # pins minimum == maximum
1016
+ SimpleCov.refuse_coverage_drop :line, :branch # maximum drop of 0
1017
+ ```
1018
+
1019
+ `expected_coverage` floors the actual percentage to two decimal places, so an actual of 95.4287 still passes at
1020
+ `expected_coverage 95.42`.
1021
+
1022
+ > [!NOTE]
1023
+ > `minimum_coverage_by_file` and `minimum_coverage_by_group` are **deprecated** in favor of the `coverage` block's
1024
+ > `minimum_per_file` / `minimum_per_group`. They still work but emit a deprecation warning. For example, replace
1025
+ > `minimum_coverage_by_file line: 70, 'app/x.rb' => 100` with:
1026
+ >
1027
+ > ```ruby
1028
+ > coverage :line do
1029
+ > minimum_per_file 70
1030
+ > minimum_per_file 100, only: "app/x.rb"
1031
+ > end
1032
+ > ```
1033
+
1034
+ ## Formatters
1035
+
1036
+ ### Using your own formatter
1037
+
1038
+ ```ruby
1039
+ SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter
1040
+ ```
1041
+
1042
+ `SimpleCov.result.format!` then invokes `SimpleCov::Formatter::YourFormatter.new.format(result)`, where `result` is a
1043
+ `SimpleCov::Result`. Do whatever you wish with it.
1044
+
1045
+ ### Using multiple formatters
1046
+
1047
+ As of SimpleCov 0.9 you can specify multiple result formats. The HTML and JSON formatters are built in; other
1048
+ formatters ship as separate gems you'll need to add and require — for example,
1049
+ [simplecov-cobertura](https://github.com/dashingrocket/simplecov-cobertura) for the Cobertura XML that many CI services
1050
+ consume.
1051
+
1052
+ ```ruby
1053
+ require "simplecov-cobertura"
1054
+
1055
+ SimpleCov.formatters = [
1056
+ SimpleCov::Formatter::HTMLFormatter,
1057
+ SimpleCov::Formatter::CoberturaFormatter,
1058
+ ]
1059
+ ```
1060
+
1061
+ ### JSON formatter
1062
+
1063
+ `SimpleCov::Formatter::JSONFormatter` emits JSON — useful for CI consumption or reporting to external services.
1064
+
1065
+ ```ruby
1066
+ SimpleCov.formatter = SimpleCov::Formatter::JSONFormatter
1067
+ ```
1068
+
1069
+ By default `coverage.json` carries the full source-text array for every file, which makes the payload self-contained
1070
+ but dominates the file size on larger projects. Tools that read the project's source files directly from disk can opt
1071
+ out of that field with:
1072
+
1073
+ ```ruby
1074
+ SimpleCov.start do
1075
+ source_in_json false
1076
+ end
1077
+ ```
1078
+
1079
+ The HTML report's `coverage_data.js` always retains the source array — the client-side viewer renders source from
1080
+ there. The setting only affects the side-file `coverage.json`. When the source is omitted, `meta.commit` (the git
1081
+ commit SHA the report was generated against) lets tools recover the exact source lines from repository history.
1082
+
1083
+ > The JSON formatter was originally a separate gem,
1084
+ > [simplecov_json_formatter](https://github.com/codeclimate-community/simplecov_json_formatter). It is now built in and
1085
+ > loaded by default; existing code that does `require "simplecov_json_formatter"` will continue to work.
1086
+
1087
+ ### JSON Schema for `coverage.json`
1088
+
1089
+ `coverage.json` is a public contract, described by a JSON Schema (2020-12) so downstream tools can validate it,
1090
+ generate types, or pin to a known shape. Every emitted document carries a top-level `$schema` URL pointing at the
1091
+ versioned canonical, plus a human-readable `meta.schema_version` (`"major.minor"`).
1092
+
1093
+ The **versioned canonical** lives at [`schemas/coverage-v1.0.schema.json`](schemas/coverage-v1.0.schema.json) and
1094
+ long-lived integrations should pin to it. Once a SimpleCov release ships with a given versioned schema file, that file
1095
+ is immutable: bug fixes, additions, or shape changes ship as a new versioned file (a minor or major bump), never as a
1096
+ silent rewrite of an already-released one. Schemas may still be corrected in-place between gem releases — i.e., the
1097
+ schema file as it currently exists on `main` may change before the next gem release, but the schema for any published
1098
+ gem version stays frozen. A convenience alias at [`schemas/coverage.schema.json`](schemas/coverage.schema.json) always
1099
+ tracks the latest and may shift when a new SimpleCov release bumps the schema.
1100
+
1101
+ The schema version is independent of the gem version:
1102
+
1103
+ - Additive changes (new fields) bump the **minor** segment. Existing consumers keep working.
1104
+ - Removals or shape changes bump the **major** segment, and ship as a new `schemas/coverage-vX.0.schema.json` file so
1105
+ v1.x consumers stay valid.
1106
+
1107
+ The current version is **1.0**. Top-level structure:
1108
+
1109
+ ```jsonc
1110
+ {
1111
+ "$schema": "https://raw.githubusercontent.com/simplecov-ruby/simplecov/main/schemas/coverage-v1.0.schema.json",
1112
+ "meta": { /* schema_version, simplecov_version, command_name, project_name, timestamp, root, commit, line_coverage, branch_coverage, method_coverage */ },
1113
+ "total": { /* aggregate stats for lines (and branches / methods when enabled) */ },
1114
+ "coverage": { "<project-relative path>": { /* per-file lines, source, branches, methods, etc. */ } },
1115
+ "groups": { "<group name>": { /* per-group stats + files */ } },
1116
+ "errors": { /* minimum_coverage, minimum_coverage_by_file, minimum_coverage_by_group, maximum_coverage, maximum_coverage_drop violations */ }
1117
+ }
1118
+ ```
1119
+
1120
+ The `.resultset.json` file is **not** schema'd — it's SimpleCov-internal and may change shape across releases. Build
1121
+ integrations on top of `coverage.json`.
1122
+
1123
+ ### More formatters, editor integrations, and hosted services
1124
+
1125
+ * [Open Source formatter and integration plugins for SimpleCov](doc/alternate-formatters.md)
1126
+ * [Editor Integration](doc/editor-integration.md)
1127
+ * [Hosted (commercial) services](doc/commercial-services.md)
1128
+
1129
+ ## Output and diagnostics
1130
+
1131
+ ### Errors and exit statuses
1132
+
1133
+ If an error is raised, SimpleCov prints a message to `STDERR` with the exit status, to aid debugging:
1134
+
1135
+ ```
1136
+ SimpleCov failed with exit 1
1137
+ ```
1138
+
1139
+ Disable this message with:
1140
+
1141
+ ```ruby
1142
+ SimpleCov.print_errors false
1143
+ ```
1144
+
1145
+ ### Color output
1146
+
1147
+ When color is enabled, SimpleCov highlights coverage percentages in its `STDERR` diagnostics by band (green for
1148
+ `>= 90%`, yellow for `>= 75%`, red below) and prints the "SimpleCov failed with exit ..." summary in red. By default,
1149
+ color is on only when `STDERR` is a TTY. Two environment variables override that:
1150
+
1151
+ - `NO_COLOR=1` (any non-empty value) disables color even when stderr is a TTY. Honors the
1152
+ [no-color.org](https://no-color.org) convention.
1153
+ - `FORCE_COLOR=1` (any non-empty value) enables color even when stderr is not a TTY. Useful when stderr is piped through
1154
+ a wrapper that itself renders ANSI in a terminal (`parallel_tests --combine-stderr`, log multiplexers, some CI runners).
1155
+
1156
+ `NO_COLOR` wins if both are set.
1157
+
1158
+ For programmatic control, use `SimpleCov.color`. An explicit `true` or `false` wins over the env vars and TTY detection:
1159
+
1160
+ ```ruby
1161
+ SimpleCov.color true # always on
1162
+ SimpleCov.color false # always off
1163
+ SimpleCov.color :auto # default behavior: NO_COLOR/FORCE_COLOR/TTY
1164
+ ```
1165
+
1166
+ ## Command-line interface
1167
+
1168
+ The bundled `simplecov` CLI provides a set of subcommands. The read-only reporting commands consume the JSONFormatter's
1169
+ `coverage.json` output, so you don't need to re-run your suite — any prior run that emitted JSON suffices. Paths default
1170
+ to `SimpleCov.coverage_dir` from your project's `.simplecov` when one is present.
1171
+
1172
+ | Command | Description |
1173
+ |--------------------|---------------------------------------------------------------------|
1174
+ | `run <command…>` | Execute `<command>` with simplecov pre-loaded (no `test_helper` hook needed) |
1175
+ | `coverage <path>` | Print coverage stats for a single file |
1176
+ | `report` | Print the overall summary and per-group totals |
1177
+ | `uncovered` | List the lowest-coverage files |
1178
+ | `merge <files…>` | Merge multiple `.resultset.json` files |
1179
+ | `diff <baseline>` | Show per-file coverage delta vs a baseline |
1180
+ | `open` | Open the HTML report in the default browser |
1181
+ | `serve` | Serve the coverage report over HTTP |
1182
+ | `clean` | Remove the coverage report directory |
1183
+
1184
+ Run `simplecov help` for the full option listing.
1185
+
1186
+ ### `run` — run a suite with coverage
1187
+
1188
+ If your project has no `test_helper.rb` hook that calls `SimpleCov.start` (or you don't want to add one), `simplecov run`
1189
+ execs your test command with simplecov pre-loaded so a report drops into `coverage/` at the end:
1190
+
1191
+ ```sh
1192
+ $ simplecov run bundle exec rspec
1193
+ $ simplecov run -- bundle exec rake test
1194
+ $ simplecov run ruby my_test.rb
1195
+ ```
1196
+
1197
+ Internally this just sets `RUBYOPT=-rsimplecov/autostart` for the child process, so any spawned subprocess (parallel
1198
+ test workers, integration test forks, etc.) also picks up the autostart shim. If your project already has a `.simplecov`
1199
+ config that calls `SimpleCov.start`, the autostart shim defers to it and won't double-start Coverage.
1200
+
1201
+ ### `coverage` — per-file lookup
1202
+
1203
+ For editor / TDD inner-loop integrations and tools that want one file's coverage without re-parsing the full report:
1204
+
1205
+ ```sh
1206
+ $ simplecov coverage app/models/user.rb
1207
+ /abs/path/app/models/user.rb
1208
+ Line: 100.00% (12 / 12)
1209
+ Branch: 100.00% (4 / 4)
1210
+ Method: 100.00% (3 / 3)
1211
+
1212
+ $ simplecov coverage --json app/models/user.rb # raw JSON entry
1213
+ $ simplecov coverage --input path/to/coverage.json … # non-default location
1214
+ ```
1215
+
1216
+ The same lookup is available in Ruby, with paths resolved relative to `SimpleCov.root` (absolute or project-relative):
1217
+
1218
+ ```ruby
1219
+ result = SimpleCov.result # or SimpleCov::Result.from_hash(...).first
1220
+ result.coverage_for("app/models/user.rb")
1221
+ # => {line: <CoverageStatistics>, branch: <CoverageStatistics>, method: <CoverageStatistics>}
1222
+
1223
+ result.source_file_for("app/models/user.rb")
1224
+ # => <SimpleCov::SourceFile>
1225
+ ```
1226
+
1227
+ ### `report` — quick terminal report
1228
+
1229
+ For CI logs, ssh sessions, or any terminal-only workflow, `simplecov report` prints the same totals row the HTML report
1230
+ renders at the top, plus per-group totals:
1231
+
1232
+ ```sh
1233
+ $ simplecov report
1234
+ All Files
1235
+ Line: 99.75% (1638 / 1642)
1236
+ Branch: 98.50% (396 / 402)
1237
+ Method: 99.73% (372 / 373)
1238
+ ```
1239
+
1240
+ Pass `--input PATH` to read a non-default `coverage.json`. `--json` emits the totals as a JSON object keyed by section
1241
+ name (`"All Files"` plus each group), useful when a CI step needs to act on the numbers rather than display them.
1242
+
1243
+ ### `uncovered` — list lowest-coverage files
1244
+
1245
+ `simplecov uncovered` prints the lowest-coverage files (by line coverage, worst-first) so you can find where to add
1246
+ tests next without opening the HTML report:
1247
+
1248
+ ```sh
1249
+ $ simplecov uncovered
1250
+ 50.00% 5/10 lib/foo.rb
1251
+ 80.00% 8/10 lib/bar.rb
1252
+
1253
+ $ simplecov uncovered --threshold 90 --top 5
1254
+ $ simplecov uncovered --criterion branch
1255
+ ```
1256
+
1257
+ `--threshold N` filters to files below N% coverage (default `100`); `--top N` caps the list at N entries (default
1258
+ `10`); `--criterion line|branch|method` chooses which coverage to rank by (default `line`). `--json` emits the rows as
1259
+ a JSON array (empty when nothing is below the threshold), useful for piping into a CI gate.
1260
+
1261
+ ### `merge` — combine resultsets from parallel CI workers
1262
+
1263
+ CI matrices that produce one `.resultset.json` per worker can stitch them together with `simplecov merge` instead of
1264
+ hand-rolling a Rake task in every project:
1265
+
1266
+ ```sh
1267
+ $ simplecov merge worker-*/coverage/.resultset.json --output coverage/.resultset.json
1268
+ ```
1269
+
1270
+ By default `simplecov merge` ignores `merge_timeout`; pass `--honor-timeout` to drop entries older than the configured
1271
+ timeout. Pass `--dry-run` to preview the output path without writing, or `-q` / `--quiet` to suppress the success status
1272
+ line for cleaner CI logs. After merging, run `simplecov report` against the combined data.
1273
+
1274
+ ### `diff` — coverage delta vs a baseline
1275
+
1276
+ `simplecov diff <baseline>` reads two `coverage.json` files (current plus a baseline checked into the repo, or produced
1277
+ by a previous CI run) and prints the files whose coverage moved on any enabled criterion. When branch or method coverage
1278
+ is enabled, those deltas appear alongside the line delta on the same row:
1279
+
1280
+ ```sh
1281
+ $ simplecov diff coverage/baseline.json
1282
+ -20.00% lines -10.00% branches lib/foo.rb
1283
+ + 5.00% lines lib/bar.rb
1284
+ +60.00% lines lib/new.rb (new file)
1285
+ -95.00% lines lib/gone.rb (removed)
1286
+ ```
1287
+
1288
+ Regressions are listed first. Pass `--fail-on-drop` to exit non-zero when any file's line coverage slipped, so this
1289
+ composes with CI as a "coverage of this PR didn't drop" gate even when overall thresholds are still satisfied.
1290
+ `--threshold N` filters out deltas below N% in absolute value, useful when a baseline is noisy. `--json` emits the rows
1291
+ as a JSON array for programmatic consumption:
1292
+
1293
+ ```sh
1294
+ $ simplecov diff --json coverage/baseline.json
1295
+ [
1296
+ {"file":"lib/foo.rb","status":"changed","line_delta":-20.0,"branch_delta":-10.0,"method_delta":0.0},
1297
+ {"file":"lib/bar.rb","status":"changed","line_delta":5.0,"branch_delta":0.0,"method_delta":0.0}
1298
+ ]
1299
+ ```
1300
+
1301
+ Coverage keys with a leading `/` (from `coverage.json` files emitted before the `SourceFile#project_filename` change)
1302
+ are normalized, so a baseline from an older SimpleCov still diffs cleanly against newer reports.
1303
+
1304
+ ### `serve` and `clean`
1305
+
1306
+ `simplecov serve` serves the coverage report over HTTP — handy on a remote box where you can't open files directly.
1307
+ `--port N` binds to a specific port (default: a random open port) and `--host HOST` to a specific host (default
1308
+ `127.0.0.1`).
1309
+
1310
+ `simplecov clean` removes the coverage report directory. `--dry-run` prints what would be removed without deleting
1311
+ anything; `-q` / `--quiet` suppresses status lines.
1312
+
1313
+ ## Compatibility and troubleshooting
1314
+
1315
+ ### Ruby version compatibility
1316
+
1317
+ SimpleCov is built in [Continuous Integration] on Ruby 3.2+ and JRuby 10+. On CRuby, every coverage criterion
1318
+ described above is available on the supported versions, with one exception: [eval coverage](#eval-coverage) requires
1319
+ CRuby 3.2+.
1320
+
1321
+ ### JRuby
1322
+
1323
+ On JRuby, only **line coverage** is available — branch, method, oneshot-line, and eval coverage rely on features of
1324
+ CRuby's `Coverage` library that JRuby doesn't implement. SimpleCov detects this automatically: the bundled `strict`
1325
+ profile, for instance, enforces only line coverage at 100% on JRuby instead of failing to load.
1326
+
1327
+ To get accurate line numbers in coverage results, JRuby needs its full backtrace enabled. Pass `JRUBY_OPTS="--debug"`,
1328
+ or create a `.jrubyrc` with `debug.fullTrace=true`.
1329
+
1330
+ ### Notes on specific frameworks and test utilities
1331
+
1332
+ Some frameworks and tools have quirks worth knowing about when using SimpleCov:
1333
+
1334
+ <table>
1335
+ <tr><th>Framework</th><th>Notes</th><th>Issue</th></tr>
1336
+ <tr>
1337
+ <th>
1338
+ parallel_tests
1339
+ </th>
1340
+ <td>
1341
+ As of 0.8.0, SimpleCov should correctly recognize parallel_tests and
1342
+ supplement your test suite names with their corresponding test env
1343
+ numbers. SimpleCov locks the resultset cache while merging, ensuring no
1344
+ race conditions occur when results are merged.
1345
+ </td>
1346
+ <td>
1347
+ <a href="https://github.com/simplecov-ruby/simplecov/issues/64">#64</a> &amp;
1348
+ <a href="https://github.com/simplecov-ruby/simplecov/pull/185">#185</a>
1349
+ </td>
1350
+ </tr>
1351
+ <tr>
1352
+ <th>
1353
+ knapsack_pro
1354
+ </th>
1355
+ <td>
1356
+ To make SimpleCov work with Knapsack Pro Queue Mode to split tests in parallel on CI jobs you need to provide CI node index number to the <code>SimpleCov.command_name</code> in <code>KnapsackPro::Hooks::Queue.before_queue</code> hook.
1357
+ </td>
1358
+ <td>
1359
+ <a href="https://knapsackpro.com/faq/question/how-to-use-simplecov-in-queue-mode">Tip</a>
1360
+ </td>
1361
+ </tr>
1362
+ <tr>
1363
+ <th>
1364
+ RubyMine
1365
+ </th>
1366
+ <td>
1367
+ The <a href="https://www.jetbrains.com/ruby/">RubyMine IDE</a> has
1368
+ built-in support for SimpleCov's coverage reports, though you might need
1369
+ to explicitly set the output root using `SimpleCov.root('foo/bar/baz')`
1370
+ </td>
1371
+ <td>
1372
+ <a href="https://github.com/simplecov-ruby/simplecov/issues/95">#95</a>
1373
+ </td>
1374
+ </tr>
1375
+ <tr>
1376
+ <th>
1377
+ Spork
1378
+ </th>
1379
+ <td>
1380
+ Because of how Spork works internally (using preforking), there used to
1381
+ be trouble when using SimpleCov with it, but that has apparently been
1382
+ resolved with a specific configuration strategy. See <a
1383
+ href="https://github.com/simplecov-ruby/simplecov/issues/42#issuecomment-4440284">this</a>
1384
+ comment.
1385
+ </td>
1386
+ <td>
1387
+ <a href="https://github.com/simplecov-ruby/simplecov/issues/42#issuecomment-4440284">#42</a>
1388
+ </td>
1389
+ </tr>
1390
+ <tr>
1391
+ <th>
1392
+ Spring
1393
+ </th>
1394
+ <td>
1395
+ <a href="#using-spring-with-simplecov">See section below.</a>
1396
+ </td>
1397
+ <td>
1398
+ <a href="https://github.com/simplecov-ruby/simplecov/issues/381">#381</a>
1399
+ </td>
1400
+ </tr>
1401
+ <tr>
1402
+ <th>
1403
+ Test/Unit
1404
+ </th>
1405
+ <td>
1406
+ Test Unit 2 used to mess with ARGV, leading to a failure to detect the
1407
+ test process name in SimpleCov. <code>test-unit</code> releases 2.4.3+
1408
+ (Dec 11th, 2011) should have this problem resolved.
1409
+ </td>
1410
+ <td>
1411
+ <a href="https://github.com/simplecov-ruby/simplecov/issues/45">#45</a> &amp;
1412
+ <a href="https://github.com/test-unit/test-unit/pull/12">test-unit/test-unit#12</a>
1413
+ </td>
1414
+ </tr>
1415
+ </table>
1416
+
1417
+ ### Using Spring with SimpleCov
1418
+
1419
+ If you use [Spring](https://github.com/rails/spring) to speed up test runs, SimpleCov often misreports coverage with the
1420
+ default config due to an eager-loading issue. There are a few fixes.
1421
+
1422
+ One solution is to [explicitly call eager
1423
+ load](https://github.com/simplecov-ruby/simplecov/issues/381#issuecomment-347651728) in your `test_helper.rb` /
1424
+ `spec_helper.rb` after calling `SimpleCov.start`:
1425
+
1426
+ ```ruby
1427
+ require 'simplecov'
1428
+ SimpleCov.start 'rails'
1429
+ Rails.application.eager_load!
1430
+ ```
1431
+
1432
+ Alternatively, disable Spring while running SimpleCov:
1433
+
1434
+ ```sh
1435
+ DISABLE_SPRING=1 rake test
1436
+ ```
1437
+
1438
+ Or remove `gem 'spring'` from your `Gemfile`.
1439
+
1440
+ ### Different coverage between local and CI
1441
+
1442
+ Rails generates `config/environments/test.rb` with `config.eager_load = ENV["CI"].present?` (Rails 7+), so **CI eagerly
1443
+ loads every file in `app/` while your local run does not**. The two environments then report different file sets and
1444
+ different totals from the same suite. Two ways to make the report deterministic:
1445
+
1446
+ - Set `config.eager_load = true` everywhere in `test.rb` (slower locally, but matches CI — and matches what users
1447
+ actually see in production).
1448
+ - Stick with the `rails` profile, which folds `{app,lib}/**/*.rb` into the report at 0% on every run regardless of
1449
+ `eager_load`. (The profile resolves the glob relative to `SimpleCov.root`, not the test runner's cwd.) Outside the
1450
+ profile, the equivalent is `cover "{app,lib}/**/*.rb"` — see the
1451
+ [legacy-API migration table](#migrating-from-the-legacy-configuration-api) for the relationship with the older
1452
+ `track_files`.
1453
+
1454
+ ### Missing coverage
1455
+
1456
+ The **most common problem is that SimpleCov isn't required and started before everything else**. To track coverage for
1457
+ your whole application, **SimpleCov must come first** so that it (and the underlying Coverage library) can track files
1458
+ as they're loaded and used.
1459
+
1460
+ If coverage is missing for some code, a simple trick is to add a `puts` inside that file and another right after
1461
+ `SimpleCov.start`, then check the order they print in:
1462
+
1463
+ ```ruby
1464
+ # my_code.rb
1465
+ class MyCode
1466
+
1467
+ puts "MyCode is being loaded!"
1468
+
1469
+ def my_method
1470
+ # ...
1471
+ end
1472
+ end
1473
+
1474
+ # spec_helper.rb / rails_helper.rb / test_helper.rb / .simplecov — whatever
1475
+ SimpleCov.start
1476
+ puts "SimpleCov started successfully!"
1477
+ ```
1478
+
1479
+ If you see this order, you're good:
1480
+
1481
+ ```
1482
+ SimpleCov started successfully!
1483
+ MyCode is being loaded!
1484
+ ```
1485
+
1486
+ If `MyCode is being loaded!` prints first, the file was loaded before SimpleCov started — that's your problem.
1487
+
1488
+ ### Upgrading from 0.x
1489
+
1490
+ Four methods that had been deprecated for a decade or more were removed in 1.0. Each had a one-to-one rename:
1491
+
1492
+ | Removed | Use instead |
1493
+ | ---------------------------------------- | ------------------------------------------ |
1494
+ | `SimpleCov::Filter#passes?` | `SimpleCov::Filter#matches?` |
1495
+ | `SimpleCov.adapters` | `SimpleCov.profiles` |
1496
+ | `SimpleCov.load_adapter('rails')` | `SimpleCov.load_profile('rails')` |
1497
+ | `SimpleCov::Formatter::MultiFormatter[]` | `SimpleCov::Formatter::MultiFormatter.new` |
1498
+
1499
+ If a custom filter still defines `passes?`, rename the method to `matches?` — the signature and semantics are identical.
1500
+
1501
+ ## Related projects
1502
+
1503
+ Want to find dead code in production? Try [Coverband](https://github.com/danmayer/coverband).
1504
+
1505
+ ## Contributing
1506
+
1507
+ * [Issue Tracker](https://github.com/simplecov-ruby/simplecov/issues) — for code and bug reports. See
1508
+ [CONTRIBUTING](https://github.com/simplecov-ruby/simplecov/blob/main/CONTRIBUTING.md) for how to contribute, along
1509
+ with common problems to check before creating an issue.
1510
+ * [Mailing List](https://groups.google.com/forum/#!forum/simplecov) — open list for discussion and announcements on
1511
+ Google Groups.
1512
+
1513
+ ## Code of Conduct
1514
+
1515
+ Everyone participating in this project's development, issue trackers, and other channels is expected to follow our
1516
+ [Code of Conduct](./CODE_OF_CONDUCT.md).
1517
+
1518
+ ## Kudos
1519
+
1520
+ Thanks to Aaron Patterson for the original idea for this!
1521
+
1522
+ ## Copyright
1523
+
1524
+ Copyright (c) 2010-2026 Erik Berlin, Benjamin Fleischer, Akira Matsuda, Christoph Olszowka, Tobias Pfeiffer, David Rodríguez, and Xavier Shay. See MIT-LICENSE for details.