simplecov 0.22.0 → 1.0.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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +1058 -508
  4. data/doc/alternate-formatters.md +0 -5
  5. data/doc/commercial-services.md +5 -5
  6. data/exe/simplecov +11 -0
  7. data/lib/minitest/simplecov_plugin.rb +13 -5
  8. data/lib/simplecov/autostart.rb +11 -0
  9. data/lib/simplecov/cli/clean.rb +47 -0
  10. data/lib/simplecov/cli/coverage.rb +91 -0
  11. data/lib/simplecov/cli/diff.rb +151 -0
  12. data/lib/simplecov/cli/dotfile.rb +100 -0
  13. data/lib/simplecov/cli/merge.rb +116 -0
  14. data/lib/simplecov/cli/open.rb +50 -0
  15. data/lib/simplecov/cli/report.rb +84 -0
  16. data/lib/simplecov/cli/run.rb +36 -0
  17. data/lib/simplecov/cli/serve.rb +139 -0
  18. data/lib/simplecov/cli/uncovered.rb +107 -0
  19. data/lib/simplecov/cli.rb +150 -0
  20. data/lib/simplecov/color.rb +74 -0
  21. data/lib/simplecov/combine/branches_combiner.rb +27 -5
  22. data/lib/simplecov/combine/files_combiner.rb +7 -1
  23. data/lib/simplecov/combine/lines_combiner.rb +19 -17
  24. data/lib/simplecov/combine/methods_combiner.rb +26 -0
  25. data/lib/simplecov/combine/results_combiner.rb +5 -4
  26. data/lib/simplecov/command_guesser.rb +46 -32
  27. data/lib/simplecov/configuration/coverage.rb +171 -0
  28. data/lib/simplecov/configuration/coverage_criteria.rb +156 -0
  29. data/lib/simplecov/configuration/filters.rb +197 -0
  30. data/lib/simplecov/configuration/formatting.rb +119 -0
  31. data/lib/simplecov/configuration/ignored_entries.rb +63 -0
  32. data/lib/simplecov/configuration/merging.rb +164 -0
  33. data/lib/simplecov/configuration/thresholds.rb +174 -0
  34. data/lib/simplecov/configuration.rb +91 -407
  35. data/lib/simplecov/coverage_statistics.rb +12 -9
  36. data/lib/simplecov/coverage_violations.rb +148 -0
  37. data/lib/simplecov/defaults.rb +27 -20
  38. data/lib/simplecov/deprecation.rb +45 -0
  39. data/lib/simplecov/directive.rb +162 -0
  40. data/lib/simplecov/exit_codes/exit_code_handling.rb +8 -2
  41. data/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +19 -57
  42. data/lib/simplecov/exit_codes/maximum_overall_coverage_check.rb +45 -0
  43. data/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +17 -27
  44. data/lib/simplecov/exit_codes/minimum_coverage_by_group_check.rb +41 -0
  45. data/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb +38 -21
  46. data/lib/simplecov/exit_codes.rb +3 -0
  47. data/lib/simplecov/exit_handling.rb +158 -0
  48. data/lib/simplecov/file_list.rb +61 -17
  49. data/lib/simplecov/filter.rb +69 -24
  50. data/lib/simplecov/formatter/base.rb +101 -0
  51. data/lib/simplecov/formatter/html_formatter/public/application.css +1 -0
  52. data/lib/simplecov/formatter/html_formatter/public/application.js +18 -0
  53. data/lib/simplecov/formatter/html_formatter/public/favicon_green.png +0 -0
  54. data/lib/simplecov/formatter/html_formatter/public/favicon_red.png +0 -0
  55. data/lib/simplecov/formatter/html_formatter/public/favicon_yellow.png +0 -0
  56. data/lib/simplecov/formatter/html_formatter/public/index.html +56 -0
  57. data/lib/simplecov/formatter/html_formatter.rb +79 -0
  58. data/lib/simplecov/formatter/json_formatter/errors_formatter.rb +84 -0
  59. data/lib/simplecov/formatter/json_formatter/result_hash_formatter.rb +128 -0
  60. data/lib/simplecov/formatter/json_formatter/source_file_formatter.rb +99 -0
  61. data/lib/simplecov/formatter/json_formatter.rb +87 -0
  62. data/lib/simplecov/formatter/multi_formatter.rb +4 -5
  63. data/lib/simplecov/formatter/simple_formatter.rb +9 -11
  64. data/lib/simplecov/formatter.rb +4 -0
  65. data/lib/simplecov/last_run.rb +10 -3
  66. data/lib/simplecov/lines_classifier.rb +25 -13
  67. data/lib/simplecov/load_global_config.rb +9 -4
  68. data/lib/simplecov/parallel_adapters/base.rb +61 -0
  69. data/lib/simplecov/parallel_adapters/generic.rb +44 -0
  70. data/lib/simplecov/parallel_adapters/parallel_tests.rb +93 -0
  71. data/lib/simplecov/parallel_adapters.rb +83 -0
  72. data/lib/simplecov/parallel_coordination.rb +129 -0
  73. data/lib/simplecov/process.rb +31 -13
  74. data/lib/simplecov/profiles/bundler_filter.rb +1 -1
  75. data/lib/simplecov/profiles/hidden_filter.rb +1 -1
  76. data/lib/simplecov/profiles/rails.rb +24 -10
  77. data/lib/simplecov/profiles/root_filter.rb +6 -5
  78. data/lib/simplecov/profiles/strict.rb +32 -0
  79. data/lib/simplecov/profiles/test_frameworks.rb +1 -4
  80. data/lib/simplecov/profiles.rb +32 -3
  81. data/lib/simplecov/result/missing_source_files_reporter.rb +49 -0
  82. data/lib/simplecov/result/source_file_builder.rb +51 -0
  83. data/lib/simplecov/result.rb +108 -19
  84. data/lib/simplecov/result_adapter.rb +70 -8
  85. data/lib/simplecov/result_merger/legacy_format_adapter.rb +28 -0
  86. data/lib/simplecov/result_merger/resultset_file.rb +38 -0
  87. data/lib/simplecov/result_merger/resultset_store.rb +50 -0
  88. data/lib/simplecov/result_merger.rb +59 -91
  89. data/lib/simplecov/result_processing.rb +179 -0
  90. data/lib/simplecov/simulate_coverage.rb +54 -8
  91. data/lib/simplecov/source_file/branch.rb +1 -3
  92. data/lib/simplecov/source_file/branch_builder.rb +114 -0
  93. data/lib/simplecov/source_file/builder_context.rb +28 -0
  94. data/lib/simplecov/source_file/line.rb +7 -2
  95. data/lib/simplecov/source_file/line_builder.rb +43 -0
  96. data/lib/simplecov/source_file/method.rb +52 -0
  97. data/lib/simplecov/source_file/method_builder.rb +58 -0
  98. data/lib/simplecov/source_file/ruby_data_parser.rb +88 -0
  99. data/lib/simplecov/source_file/skip_chunks.rb +75 -0
  100. data/lib/simplecov/source_file/source_loader.rb +63 -0
  101. data/lib/simplecov/source_file/statistics.rb +57 -0
  102. data/lib/simplecov/source_file.rb +66 -232
  103. data/lib/simplecov/static_coverage_extractor/method_collector.rb +55 -0
  104. data/lib/simplecov/static_coverage_extractor/visitor.rb +171 -0
  105. data/lib/simplecov/static_coverage_extractor.rb +110 -0
  106. data/lib/simplecov/useless_results_remover.rb +16 -7
  107. data/lib/simplecov/version.rb +1 -1
  108. data/lib/simplecov-html.rb +4 -0
  109. data/lib/simplecov.rb +156 -371
  110. data/lib/simplecov_json_formatter.rb +4 -0
  111. data/schemas/coverage-v1.0.schema.json +306 -0
  112. data/schemas/coverage.schema.json +306 -0
  113. metadata +90 -57
  114. data/CHANGELOG.md +0 -191
  115. data/lib/simplecov/default_formatter.rb +0 -20
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "prism"
5
+ rescue LoadError
6
+ # Prism isn't available on this Ruby (older than 3.3 without the gem).
7
+ # `StaticCoverageExtractor.available?` will return false and callers
8
+ # fall back to the previous "empty hashes" behavior.
9
+ end
10
+
11
+ module SimpleCov
12
+ # Static enumeration of the branches and methods Ruby's `Coverage` library
13
+ # WOULD have reported if a file had been loaded with `branches: true` /
14
+ # `methods: true`. Used by `SimulateCoverage` to backfill data for files
15
+ # added via `cover` / `track_files` that were never `require`'d during the
16
+ # run — so unloaded files contribute to the branch/method denominators
17
+ # symmetrically with their line coverage, instead of vanishing from the
18
+ # totals (see #1059).
19
+ #
20
+ # Implementation uses Prism (stdlib in Ruby 3.3+, gem on older Rubies).
21
+ # When Prism isn't available, `available?` returns false and SimulateCoverage
22
+ # falls back to the previous behavior — older Rubies keep working, just
23
+ # without the synthesized data.
24
+ #
25
+ # The emitted shape mirrors `Coverage.result[path]` for the same file:
26
+ # branches are nested as `{condition_tuple => {arm_tuple => 0, ...}}` and
27
+ # methods as `{["ClassName", :name, lines/cols] => 0}`. Position info
28
+ # comes from Prism's reported source locations; it doesn't always match
29
+ # `Coverage`'s byte-for-byte (the two parsers report slightly different
30
+ # column conventions for some constructs), but lines are reliable and
31
+ # downstream consumers that key off line numbers (the HTML formatter,
32
+ # SonarQube, etc.) see the data they expect.
33
+ module StaticCoverageExtractor
34
+ module_function
35
+
36
+ # simplecov:disable branch
37
+ # The Prism-unavailable arm of this ternary is unreachable when Prism
38
+ # itself IS loadable — i.e., on every engine that exercises the dogfood
39
+ # report. Asserted-on by callers; tested indirectly via the
40
+ # `available?`-returns-false fallback path in SimulateCoverage's spec.
41
+ def available?
42
+ defined?(::Prism) ? true : false
43
+ end
44
+ # simplecov:enable branch
45
+
46
+ # Parse `source` (a string of Ruby) and return a hash of the form
47
+ # `{"branches" => {...}, "methods" => {...}}` matching the shape that
48
+ # `Coverage.result[path]` produces. Returns nil on parse failure or
49
+ # when Prism isn't available; callers should treat that as "couldn't
50
+ # extract — fall back to empty hashes."
51
+ def call(source)
52
+ # simplecov:disable branch — `then` arm unreachable when Prism IS loadable
53
+ return nil unless available?
54
+
55
+ # simplecov:enable branch
56
+
57
+ result = ::Prism.parse(source)
58
+ return nil if result.failure?
59
+
60
+ visitor = Visitor.new
61
+ visitor.visit(result.value)
62
+ {"branches" => visitor.branches, "methods" => visitor.methods}
63
+ rescue StandardError
64
+ # simplecov:disable line
65
+ # Parser errors beyond the .failure? check, unsupported AST shapes,
66
+ # or anything else: fall back to empty hashes rather than crashing
67
+ # the whole report. Defensive; hard to trigger from a real source
68
+ # input that Prism accepts at parse time.
69
+ nil
70
+ # simplecov:enable line
71
+ end
72
+
73
+ # Summarize a source file's REAL branch and method positions, for the
74
+ # `:eval_generated` filter (SimpleCov.ignore_branches /
75
+ # SimpleCov.ignore_methods, #1046). Returns a hash:
76
+ #
77
+ # {
78
+ # branches: Set[start_line, ...], # e.g., [3, 12, 20]
79
+ # methods: Set[[name, start_line], ...] # e.g., [[:foo, 7], [:bar, 13]]
80
+ # }
81
+ #
82
+ # Branch matching is start_line-only rather than by the full tuple.
83
+ # Static extraction and Coverage can still disagree on a branch's exact
84
+ # column positions (and, for some constructs, its type), so matching on
85
+ # start_line alone is the conservative choice that tolerates those
86
+ # differences. Coincidental line-sharing between a real branch and an
87
+ # eval-generated one will keep both, which is an acceptable
88
+ # false-negative for an opt-in filter. Method matching uses
89
+ # (name, start_line) since a method name is unique at any line.
90
+ #
91
+ # Returns nil when Prism is unavailable or parsing fails, signaling
92
+ # callers to keep every Coverage entry (no false drops).
93
+ def real_source_positions(source)
94
+ extracted = call(source)
95
+ return nil unless extracted
96
+
97
+ {
98
+ branches: extracted["branches"].keys.to_set { |tuple| tuple[2] },
99
+ methods: extracted["methods"].keys.to_set { |tuple| [tuple[1], tuple[2]] }
100
+ }
101
+ end
102
+ end
103
+ end
104
+
105
+ # simplecov:disable branch
106
+ # The `else` arm (Prism missing) is unreachable on engines where the
107
+ # dogfood report runs; the Visitor class only matters when Prism is
108
+ # loadable.
109
+ require_relative "static_coverage_extractor/visitor" if SimpleCov::StaticCoverageExtractor.available?
110
+ # simplecov:enable branch
@@ -1,18 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimpleCov
4
- #
5
- # Select the files that related to working scope directory of SimpleCov
6
- #
4
+ # Drop coverage entries whose paths live outside `SimpleCov.root` so the
5
+ # report only reflects the project's own source. Vendored gems, stdlib
6
+ # files, and anything else that happens to have been touched during the
7
+ # run never make it into the formatted result.
7
8
  module UselessResultsRemover
8
9
  def self.call(coverage_result)
9
- coverage_result.select do |path, _coverage|
10
- path =~ root_regx
11
- end
10
+ coverage_result.select { |path, _coverage| path.match?(root_regex) }
11
+ end
12
+
13
+ # The `/i` flag covers case-insensitive matches on Windows / macOS-HFS+
14
+ # where the on-disk path's case can differ from `SimpleCov.root`'s.
15
+ def self.root_regex
16
+ root = SimpleCov.root
17
+ return @root_regex if root == @root_regex_root
18
+
19
+ @root_regex_root = root
20
+ @root_regex = /\A#{Regexp.escape(root.chomp(File::SEPARATOR) + File::SEPARATOR)}/i
12
21
  end
13
22
 
14
23
  def self.root_regx
15
- @root_regx ||= /\A#{Regexp.escape(SimpleCov.root + File::SEPARATOR)}/i.freeze
24
+ root_regex
16
25
  end
17
26
  end
18
27
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimpleCov
4
- VERSION = "0.22.0"
4
+ VERSION = "1.0.0"
5
5
  end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Backward-compatibility shim: simplecov-html is now part of simplecov.
4
+ require_relative "simplecov/formatter/html_formatter"