simplecov 0.22.0 → 1.0.0.rc2

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