simplecov 0.10.0 → 0.11.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 (75) hide show
  1. checksums.yaml +7 -7
  2. data/.rspec +3 -1
  3. data/.rubocop.yml +6 -5
  4. data/CHANGELOG.md +16 -2
  5. data/Gemfile +14 -14
  6. data/README.md +28 -12
  7. data/Rakefile +5 -8
  8. data/features/config_formatters.feature +1 -1
  9. data/features/config_tracked_files.feature +29 -0
  10. data/features/step_definitions/transformers.rb +1 -1
  11. data/features/support/env.rb +6 -3
  12. data/lib/simplecov.rb +19 -2
  13. data/lib/simplecov/configuration.rb +24 -4
  14. data/lib/simplecov/defaults.rb +28 -5
  15. data/lib/simplecov/file_list.rb +11 -0
  16. data/lib/simplecov/filter.rb +1 -1
  17. data/lib/simplecov/formatter/multi_formatter.rb +17 -13
  18. data/lib/simplecov/result.rb +1 -1
  19. data/lib/simplecov/source_file.rb +6 -3
  20. data/lib/simplecov/version.rb +1 -1
  21. data/spec/1_8_fallbacks_spec.rb +29 -0
  22. data/spec/command_guesser_spec.rb +46 -0
  23. data/spec/deleted_source_spec.rb +12 -0
  24. data/{test → spec}/faked_project/Gemfile +0 -0
  25. data/{test → spec}/faked_project/Rakefile +0 -0
  26. data/{test → spec}/faked_project/cucumber.yml +0 -0
  27. data/{test → spec}/faked_project/features/step_definitions/my_steps.rb +0 -0
  28. data/{test → spec}/faked_project/features/support/env.rb +0 -0
  29. data/{test → spec}/faked_project/features/test_stuff.feature +0 -0
  30. data/{test → spec}/faked_project/lib/faked_project.rb +1 -1
  31. data/{test → spec}/faked_project/lib/faked_project/framework_specific.rb +0 -0
  32. data/{test → spec}/faked_project/lib/faked_project/meta_magic.rb +0 -0
  33. data/{test → spec}/faked_project/lib/faked_project/some_class.rb +0 -0
  34. data/spec/faked_project/lib/faked_project/untested_class.rb +11 -0
  35. data/{test → spec}/faked_project/spec/faked_spec.rb +0 -0
  36. data/{test → spec}/faked_project/spec/forking_spec.rb +0 -0
  37. data/{test → spec}/faked_project/spec/meta_magic_spec.rb +0 -0
  38. data/{test → spec}/faked_project/spec/some_class_spec.rb +0 -0
  39. data/{test → spec}/faked_project/spec/spec_helper.rb +0 -0
  40. data/{test → spec}/faked_project/test/faked_test.rb +0 -0
  41. data/{test → spec}/faked_project/test/meta_magic_test.rb +0 -0
  42. data/{test → spec}/faked_project/test/some_class_test.rb +0 -0
  43. data/{test → spec}/faked_project/test/test_helper.rb +0 -0
  44. data/spec/file_list_spec.rb +48 -0
  45. data/spec/filters_spec.rb +96 -0
  46. data/{test → spec}/fixtures/app/controllers/sample_controller.rb +0 -0
  47. data/{test → spec}/fixtures/app/models/user.rb +0 -0
  48. data/{test → spec}/fixtures/deleted_source_sample.rb +0 -0
  49. data/{test → spec}/fixtures/frameworks/rspec_bad.rb +0 -0
  50. data/{test → spec}/fixtures/frameworks/rspec_good.rb +0 -0
  51. data/{test → spec}/fixtures/frameworks/testunit_bad.rb +0 -0
  52. data/{test → spec}/fixtures/frameworks/testunit_good.rb +0 -0
  53. data/{test → spec}/fixtures/iso-8859.rb +0 -0
  54. data/{test → spec}/fixtures/resultset1.rb +0 -0
  55. data/{test → spec}/fixtures/resultset2.rb +0 -0
  56. data/{test → spec}/fixtures/sample.rb +0 -0
  57. data/{test → spec}/fixtures/utf-8.rb +0 -0
  58. data/{test → spec}/helper.rb +3 -7
  59. data/spec/merge_helpers_spec.rb +108 -0
  60. data/spec/result_spec.rb +207 -0
  61. data/spec/return_codes_spec.rb +37 -0
  62. data/spec/source_file_line_spec.rb +153 -0
  63. data/spec/source_file_spec.rb +75 -0
  64. metadata +163 -149
  65. data/test/shoulda_macros.rb +0 -19
  66. data/test/test_1_8_fallbacks.rb +0 -31
  67. data/test/test_command_guesser.rb +0 -19
  68. data/test/test_deleted_source.rb +0 -14
  69. data/test/test_file_list.rb +0 -23
  70. data/test/test_filters.rb +0 -94
  71. data/test/test_merge_helpers.rb +0 -112
  72. data/test/test_result.rb +0 -175
  73. data/test/test_return_codes.rb +0 -41
  74. data/test/test_source_file.rb +0 -73
  75. data/test/test_source_file_line.rb +0 -106
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
- ---
2
- SHA512:
3
- metadata.gz: 48711e9d1476719d339f0086b8f35b64be59364bbbf5c0d3c767c56a7857dd1afa576b05278a1c74aa8a346d97817676eef1d48f3f10ec1e8b4e452fc4445f56
4
- data.tar.gz: 88dad87cce15389b66baa7d2bb73f675fe168e2dd4168fef863310b053cf989a10a1fdced39b2d10616e8187c48d342236da8e0e17e915d34b4588da949737a2
5
- SHA1:
6
- metadata.gz: ce56b638173500ad25afd14ce524ff192753fc7e
7
- data.tar.gz: 5279e97dae54994a96c976917ce820c5af60cbcb
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bcd3fcd0c8e30121cc9f50e81b8b756f1153e8a3
4
+ data.tar.gz: 58d53aacce8c59039020aa58c651c6c66b04c414
5
+ SHA512:
6
+ metadata.gz: 8edc40314d68f3964d6cdba4d99a9afb07f15e7bafdc5ecccdeda85ce2d662ff5016ccc0b5e78edf5668ca40c92bf168d2f3b031ca08b541a18f15d717354f69
7
+ data.tar.gz: 60b3f714f8701072f44186639a4915aae3b8fdd8341e31ad41b2bde07961917052c012106fccad8b2a54ced75be9f84f7f1f743b3ef64a7b7bd0671c906eea83
data/.rspec CHANGED
@@ -1 +1,3 @@
1
- --require rspec/legacy_formatters
1
+ --color
2
+ --order random
3
+ --warning
@@ -1,13 +1,13 @@
1
1
  AllCops:
2
2
  Exclude:
3
- - 'test/fixtures/iso-8859.rb'
3
+ - 'spec/fixtures/iso-8859.rb'
4
4
  - 'tmp/**/*'
5
5
  - 'vendor/bundle/**/*'
6
6
 
7
7
  Lint/AmbiguousRegexpLiteral:
8
8
  Exclude:
9
9
  - 'features/**/*_steps.rb'
10
- - 'test/**/*_steps.rb'
10
+ - 'spec/**/*_steps.rb'
11
11
  - 'tmp/**/*_steps.rb'
12
12
 
13
13
  Metrics/AbcSize:
@@ -55,15 +55,16 @@ Style/SpaceInsideHashLiteralBraces:
55
55
 
56
56
  Style/SpecialGlobalVars:
57
57
  Exclude:
58
- - 'test/test_deleted_source.rb'
59
- - 'test/test_return_codes.rb'
58
+ - 'spec/deleted_source_spec.rb'
59
+ - 'spec/return_codes_spec.rb'
60
+ - 'lib/simplecov/defaults.rb'
60
61
 
61
62
  Style/StringLiterals:
62
63
  EnforcedStyle: double_quotes
63
64
 
64
65
  Style/FileName:
65
66
  Exclude:
66
- - 'test/fixtures/utf-8.rb'
67
+ - 'spec/fixtures/utf-8.rb'
67
68
 
68
69
  Style/TrailingComma:
69
70
  EnforcedStyleForMultiline: 'comma'
@@ -1,11 +1,25 @@
1
- Unreleased ([changes](https://github.com/colszowka/simplecov/compare/v0.10.0...master))
1
+ Unreleased ([changes](https://github.com/colszowka/simplecov/compare/v0.11.0...master))
2
2
  =================
3
3
 
4
4
  ## Enhancements
5
5
 
6
6
  ## Bugfixes
7
7
 
8
- 0.10.0 2015-04-18 ([changes](https://github.com/colszowka/simplecov/compare/v0.9.2...0.10.0))
8
+ 0.11.0 2015-11-29 ([changes](https://github.com/colszowka/simplecov/compare/v0.10.0...v0.10.11))
9
+ =================
10
+
11
+ ## Enhancements
12
+
13
+ * Added `SimpleCov.minimum_coverage_by_file` for per-file coverage thresholds. See [#392](https://github.com/colszowka/simplecov/pull/392) (thanks @ptashman)
14
+ * Added `track_files` configuration option to specify a glob to always include in coverage results, whether or not those files are required. See [#422](https://github.com/colszowka/simplecov/pull/422) (thanks @hugopeixoto)
15
+ * Speed up `root_filter` by an order of magnitude. See [#396](https://github.com/colszowka/simplecov/pull/396) (thanks @raszi)
16
+
17
+ ## Bugfixes
18
+
19
+ * Fix warning about global variable `$ERROR_INFO`. See [#400](https://github.com/colszowka/simplecov/pull/400) (thanks @amatsuda)
20
+ * Actually recurse upward looking for `.simplecov`, as claimed by the documentation, rather than only the working directory. See [#423](https://github.com/colszowka/simplecov/pull/423) (thanks @alexdowad)
21
+
22
+ 0.10.0 2015-04-18 ([changes](https://github.com/colszowka/simplecov/compare/v0.9.2...v0.10.0))
9
23
  =================
10
24
 
11
25
  ## Enhancements
data/Gemfile CHANGED
@@ -9,26 +9,26 @@ source "https://rubygems.org"
9
9
  gem "rake", ">= 10.3"
10
10
 
11
11
  group :test do
12
+ gem "rspec", ">= 3.2"
12
13
  # Older versions of some gems required for Ruby 1.8.7 support
13
14
  platform :ruby_18 do
14
15
  gem "activesupport", "~> 3.2.21"
15
- gem "shoulda-matchers", "~> 2.0.0"
16
16
  gem "i18n", "~> 0.6.11"
17
17
  end
18
- gem "rubocop", ">= 0.30", :platforms => [:ruby_19, :ruby_20, :ruby_21, :ruby_22]
19
- gem "minitest", ">= 5.5"
20
- gem "rspec", ">= 3.0"
21
- gem "rspec-legacy_formatters", ">= 1.0"
22
- gem "shoulda", ">= 3.5"
23
- end
18
+ platform :jruby, :ruby_19, :ruby_20, :ruby_21, :ruby_22 do
19
+ gem "aruba", "~> 0.7.4"
20
+ gem "capybara", "~> 2.4"
21
+
22
+ # Hack until Capybara fixes its gemspec. 3.0 removed 1.9 support.
23
+ # See https://github.com/jnicklas/capybara/issues/1615
24
+ gem "mime-types", "~> 2.0.0"
24
25
 
25
- platform :jruby, :ruby_19, :ruby_20, :ruby_21, :ruby_22 do
26
- gem "aruba", "~> 0.6"
27
- gem "capybara", "~> 2.0.0"
28
- gem "cucumber", "~> 2.0"
29
- gem "phantomjs", "~> 1.9"
30
- gem "poltergeist", "~> 1.1"
31
- gem "test-unit", "~> 3.0"
26
+ gem "cucumber", "~> 2.0"
27
+ gem "phantomjs", "~> 1.9"
28
+ gem "poltergeist", "~> 1.1"
29
+ gem "rubocop", ">= 0.30"
30
+ gem "test-unit", "~> 3.0"
31
+ end
32
32
  end
33
33
 
34
34
  gemspec
data/README.md CHANGED
@@ -145,8 +145,8 @@ to use SimpleCov with them. Here's an overview of the known ones:
145
145
  <td>
146
146
  As of 0.8.0, SimpleCov should correctly recognize parallel_tests and
147
147
  supplement your test suite names with their corresponding test env
148
- numbers. Locking of the resultset cache should ensure no race conditions
149
- occur when results are merged.
148
+ numbers. SimpleCov locks the resultset cache while merging, ensuring no
149
+ race conditions occur when results are merged.
150
150
  </td>
151
151
  <td>
152
152
  <a href="https://github.com/colszowka/simplecov/issues/64">#64</a> &amp;
@@ -391,17 +391,17 @@ There are two things to note here though:
391
391
 
392
392
  ### Test suite names
393
393
 
394
- SimpleCov tries to guess the name of the currently running test suite based upon the shell command the tests are running
395
- on. This should work fine for Unit Tests, RSpec, and Cucumber. If it fails, it will use the shell command
396
- that invoked the test suite as a command name.
394
+ SimpleCov tries to guess the name of the currently running test suite based upon the shell command the tests
395
+ are running on. This should work fine for Unit Tests, RSpec, and Cucumber. If it fails, it will use the shell
396
+ command that invoked the test suite as a command name.
397
397
 
398
- If you have some non-standard setup and still want nicely labeled test suites, you have to give Simplecov a cue as to what the
399
- name of the currently running test suite is. You can do so by specifying `SimpleCov.command_name` in one test file that is
400
- part of your specific suite.
398
+ If you have some non-standard setup and still want nicely labeled test suites, you have to give Simplecov a
399
+ cue as to what the name of the currently running test suite is. You can do so by specifying
400
+ `SimpleCov.command_name` in one test file that is part of your specific suite.
401
401
 
402
402
  To customize the suite names on a Rails app (yeah, sorry for being Rails-biased, but everyone knows what
403
- the structure of those projects is. You can apply this accordingly to the RSpecs in your Outlook-WebDAV-Calendar-Sync gem),
404
- you could do something like this:
403
+ the structure of those projects is. You can apply this accordingly to the RSpecs in your
404
+ Outlook-WebDAV-Calendar-Sync gem), you could do something like this:
405
405
 
406
406
  ```ruby
407
407
  # test/unit/some_test.rb
@@ -417,8 +417,8 @@ SimpleCov.command_name "test:integration"
417
417
  SimpleCov.command_name "features"
418
418
  ```
419
419
 
420
- Note that this only has to be invoked ONCE PER TEST SUITE, so even if you have 200 unit test files, specifying it in
421
- some_test.rb is enough.
420
+ Note that this only has to be invoked ONCE PER TEST SUITE, so even if you have 200 unit test files,
421
+ specifying it in `some_test.rb` is enough.
422
422
 
423
423
  Last but not least **if multiple suites resolve to the same `command_name`** be aware that the coverage results **will
424
424
  clobber each other instead of being merged**. SimpleCov is smart enough to detect unique names for the most common
@@ -431,6 +431,14 @@ If you are relying on the default `command_name` then SimpleCov will attempt to
431
431
  parallel test runner does not set one or both of these then *you must* set a `command_name` and ensure that it is unique
432
432
  per process (eg. `command_name "Unit Tests PID #{$$}"`).
433
433
 
434
+ If you are using parallel_tests, you must incorporate `TEST_ENV_NUMBER` into the command name yourself, in
435
+ order for SimpleCov to merge the results correctly. For example:
436
+
437
+ ```ruby
438
+ # spec/spec_helper.rb
439
+ SimpleCov.command_name "features" + (ENV['TEST_ENV_NUMBER'] || '')
440
+ ```
441
+
434
442
  [simplecov-html] prints the used test suites in the footer of the generated coverage report.
435
443
 
436
444
  ### Timeout for merge
@@ -539,6 +547,14 @@ You can define the minimum coverage percentage expected. SimpleCov will return n
539
547
  SimpleCov.minimum_coverage 90
540
548
  ```
541
549
 
550
+ ### Minimum coverage by file
551
+
552
+ You can define the minimum coverage by file percentage expected. SimpleCov will return non-zero if unmet. This is useful to help ensure coverage is relatively consistent, rather than being skewed by particularly good or bad areas of the code.
553
+
554
+ ```ruby
555
+ SimpleCov.minimum_coverage_by_file 80
556
+ ```
557
+
542
558
  ### Maximum coverage drop
543
559
 
544
560
  You can define the maximum coverage drop percentage at once. SimpleCov will return non-zero if exceeded.
data/Rakefile CHANGED
@@ -12,12 +12,9 @@ end
12
12
  # Enforce proper permissions on each build
13
13
  Rake::Task[:build].prerequisites.unshift :fix_permissions
14
14
 
15
- require "rake/testtask"
16
- Rake::TestTask.new(:test) do |test|
17
- test.libs << "lib" << "test"
18
- test.test_files = FileList["test/test_*.rb"]
19
- test.verbose = true
20
- test.warning = true
15
+ require "rspec/core/rake_task"
16
+ RSpec::Core::RakeTask.new(:spec) do |spec|
17
+ spec.pattern = FileList["spec/*_spec.rb"]
21
18
  end
22
19
 
23
20
  begin
@@ -33,7 +30,7 @@ end
33
30
  if RUBY_VERSION >= "1.9"
34
31
  require "cucumber/rake/task"
35
32
  Cucumber::Rake::Task.new
36
- task :default => [:test, :cucumber, :rubocop]
33
+ task :default => [:spec, :cucumber, :rubocop]
37
34
  else
38
- task :default => [:test]
35
+ task :default => [:spec]
39
36
  end
@@ -30,7 +30,7 @@ Feature:
30
30
  Given SimpleCov for Test/Unit is configured with:
31
31
  """
32
32
  require 'simplecov'
33
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
33
+ SimpleCov.formatters = [
34
34
  SimpleCov::Formatter::SimpleFormatter,
35
35
  Class.new do
36
36
  def format(result)
@@ -0,0 +1,29 @@
1
+ @test_unit
2
+ Feature:
3
+
4
+ Using the setting `tracked_files` should add files that were not
5
+ required to the report.
6
+
7
+ Scenario:
8
+ Given SimpleCov for Test/Unit is configured with:
9
+ """
10
+ require 'simplecov'
11
+ SimpleCov.start do
12
+ track_files "lib/**/*.rb"
13
+ end
14
+ """
15
+
16
+ When I open the coverage report generated with `bundle exec rake test`
17
+ Then I should see the groups:
18
+ | name | coverage | files |
19
+ | All Files | 76.81% | 7 |
20
+
21
+ And I should see the source files:
22
+ | name | coverage |
23
+ | lib/faked_project.rb | 100.0 % |
24
+ | lib/faked_project/untested_class.rb | 0.0 % |
25
+ | lib/faked_project/some_class.rb | 80.0 % |
26
+ | lib/faked_project/framework_specific.rb | 75.0 % |
27
+ | lib/faked_project/meta_magic.rb | 100.0 % |
28
+ | test/meta_magic_test.rb | 100.0 % |
29
+ | test/some_class_test.rb | 100.0 % |
@@ -8,6 +8,6 @@
8
8
  #
9
9
  Transform "bundle exec rspec spec" do |_|
10
10
  files = nil # Avoid shadowing
11
- in_current_dir { files = Dir["spec/**/*_spec.rb"] }
11
+ in_current_directory { files = Dir["spec/**/*_spec.rb"] }
12
12
  "bundle exec rspec #{files.sort.join(' ')}"
13
13
  end
@@ -8,7 +8,6 @@ Bundler.setup
8
8
  require "aruba/cucumber"
9
9
  require "aruba/jruby" if RUBY_ENGINE == "jruby"
10
10
  require "capybara/cucumber"
11
- require "minitest/autorun"
12
11
  require "phantomjs/poltergeist"
13
12
 
14
13
  # Fake rack app for capybara that just returns the latest coverage report from aruba temp project dir
@@ -24,6 +23,10 @@ Capybara.app = lambda { |env|
24
23
 
25
24
  Capybara.default_driver = Capybara.javascript_driver = :poltergeist
26
25
 
26
+ Capybara.configure do |config|
27
+ config.ignore_hidden_elements = false
28
+ end
29
+
27
30
  Before do
28
31
  # JRuby takes it's time... See https://github.com/cucumber/aruba/issues/134
29
32
  @aruba_timeout_seconds = RUBY_ENGINE == "jruby" ? 60 : 20
@@ -31,9 +34,9 @@ Before do
31
34
  this_dir = File.dirname(__FILE__)
32
35
 
33
36
  # Clean up and create blank state for fake project
34
- in_current_dir do
37
+ in_current_directory do
35
38
  FileUtils.rm_rf "project"
36
- FileUtils.cp_r File.join(this_dir, "../../test/faked_project/"), "project"
39
+ FileUtils.cp_r File.join(this_dir, "../../spec/faked_project/"), "project"
37
40
  end
38
41
 
39
42
  step 'I cd to "project"'
@@ -48,12 +48,29 @@ module SimpleCov
48
48
  end
49
49
  end
50
50
 
51
+ #
52
+ # Finds files that were to be tracked but were not loaded and initializes
53
+ # their coverage to zero.
54
+ #
55
+ def add_not_loaded_files(result)
56
+ if @track_files_glob
57
+ result = result.dup
58
+ Dir[@track_files_glob].each do |file|
59
+ absolute = File.expand_path(file)
60
+
61
+ result[absolute] ||= [0] * File.foreach(absolute).count
62
+ end
63
+ end
64
+
65
+ result
66
+ end
67
+
51
68
  #
52
69
  # Returns the result for the current coverage run, merging it across test suites
53
70
  # from cache using SimpleCov::ResultMerger if use_merging is activated (default)
54
71
  #
55
72
  def result
56
- @result ||= SimpleCov::Result.new(Coverage.result) if running
73
+ @result ||= SimpleCov::Result.new(add_not_loaded_files(Coverage.result)) if running
57
74
  # If we're using merging of results, store the current result
58
75
  # first, then merge the results and return those
59
76
  if use_merging
@@ -109,7 +126,7 @@ module SimpleCov
109
126
  end
110
127
 
111
128
  def load_adapter(name)
112
- warn "method load_adapter is deprecated. use load_profile instead"
129
+ warn "#{Kernel.caller.first}: [DEPRECATION] #load_adapter is deprecated. Use #load_profile instead."
113
130
  load_profile(name)
114
131
  end
115
132
 
@@ -7,7 +7,7 @@ require "simplecov/formatter/multi_formatter"
7
7
  # SimpleCov documentation for further info.
8
8
  #
9
9
  module SimpleCov
10
- module Configuration
10
+ module Configuration # rubocop:disable ModuleLength
11
11
  attr_writer :filters, :groups, :formatter
12
12
 
13
13
  #
@@ -42,6 +42,15 @@ module SimpleCov
42
42
  coverage_path
43
43
  end
44
44
 
45
+ #
46
+ # Coverage results will always include files matched by this glob, whether
47
+ # or not they were explicitly required. Without this, un-required files
48
+ # will not be present in the final report.
49
+ #
50
+ def track_files(glob)
51
+ @track_files_glob = glob
52
+ end
53
+
45
54
  #
46
55
  # Returns the list of configured filters. Add filters using SimpleCov.add_filter.
47
56
  #
@@ -80,7 +89,7 @@ module SimpleCov
80
89
  # Sets the configured formatters.
81
90
  #
82
91
  def formatters=(formatters)
83
- @formatter = SimpleCov::Formatter::MultiFormatter[*formatters]
92
+ @formatter = SimpleCov::Formatter::MultiFormatter.new(formatters)
84
93
  end
85
94
 
86
95
  #
@@ -122,7 +131,7 @@ module SimpleCov
122
131
  end
123
132
 
124
133
  def adapters
125
- warn "method adapters is deprecated. use profiles instead"
134
+ warn "#{Kernel.caller.first}: [DEPRECATION] #adapters is deprecated. Use #profiles instead."
126
135
  profiles
127
136
  end
128
137
 
@@ -166,7 +175,7 @@ module SimpleCov
166
175
  def project_name(new_name = nil)
167
176
  return @project_name if defined?(@project_name) && @project_name && new_name.nil?
168
177
  @project_name = new_name if new_name.is_a?(String)
169
- @project_name ||= File.basename(root.split("/").last).capitalize.gsub("_", " ")
178
+ @project_name ||= File.basename(root.split("/").last).capitalize.tr("_", " ")
170
179
  end
171
180
 
172
181
  #
@@ -215,6 +224,17 @@ module SimpleCov
215
224
  @maximum_coverage_drop ||= (coverage_drop || 100).to_f.round(2)
216
225
  end
217
226
 
227
+ #
228
+ # Defines the minimum coverage per file required for the testsuite to pass.
229
+ # SimpleCov will return non-zero if the current coverage of the least covered file
230
+ # is below this threshold.
231
+ #
232
+ # Default is 0% (disabled)
233
+ #
234
+ def minimum_coverage_by_file(coverage = nil)
235
+ @minimum_coverage_by_file ||= (coverage || 0).to_f.round(2)
236
+ end
237
+
218
238
  #
219
239
  # Refuses any coverage drop. That is, coverage is only allowed to increase.
220
240
  # SimpleCov will return non-zero if the coverage decreases.
@@ -1,10 +1,12 @@
1
1
  # Load default formatter gem
2
2
  require "simplecov-html"
3
+ require "pathname"
3
4
 
4
5
  SimpleCov.profiles.define "root_filter" do
5
6
  # Exclude all files outside of simplecov root
7
+ root_filter = /\A#{Regexp.escape(SimpleCov.root)}/io
6
8
  add_filter do |src|
7
- !(src.filename =~ /^#{Regexp.escape(SimpleCov.root)}/i)
9
+ !(src.filename =~ root_filter)
8
10
  end
9
11
  end
10
12
 
@@ -30,6 +32,8 @@ SimpleCov.profiles.define "rails" do
30
32
  add_group "Mailers", "app/mailers"
31
33
  add_group "Helpers", "app/helpers"
32
34
  add_group "Libraries", "lib"
35
+
36
+ track_files "{app,lib}/**/*.rb"
33
37
  end
34
38
 
35
39
  # Default configuration
@@ -47,11 +51,11 @@ at_exit do
47
51
  # If we are in a different process than called start, don't interfere.
48
52
  next if SimpleCov.pid != Process.pid
49
53
 
50
- if $ERROR_INFO # was an exception thrown?
54
+ if $! # was an exception thrown?
51
55
  # if it was a SystemExit, use the accompanying status
52
56
  # otherwise set a non-zero status representing termination by some other exception
53
57
  # (see github issue 41)
54
- @exit_status = $ERROR_INFO.is_a?(SystemExit) ? $ERROR_INFO.status : SimpleCov::ExitCodes::EXCEPTION
58
+ @exit_status = $!.is_a?(SystemExit) ? $!.status : SimpleCov::ExitCodes::EXCEPTION
55
59
  else
56
60
  # Store the exit status of the test run since it goes away after calling the at_exit proc...
57
61
  @exit_status = SimpleCov::ExitCodes::SUCCESS
@@ -61,11 +65,15 @@ at_exit do
61
65
 
62
66
  if SimpleCov.result? # Result has been computed
63
67
  covered_percent = SimpleCov.result.covered_percent.round(2)
68
+ covered_percentages = SimpleCov.result.covered_percentages.map { |p| p.round(2) }
64
69
 
65
70
  if @exit_status == SimpleCov::ExitCodes::SUCCESS # No other errors
66
71
  if covered_percent < SimpleCov.minimum_coverage # rubocop:disable Metrics/BlockNesting
67
72
  $stderr.printf("Coverage (%.2f%%) is below the expected minimum coverage (%.2f%%).\n", covered_percent, SimpleCov.minimum_coverage)
68
73
  @exit_status = SimpleCov::ExitCodes::MINIMUM_COVERAGE
74
+ elsif covered_percentages.any? { |p| p < SimpleCov.minimum_coverage_by_file } # rubocop:disable Metrics/BlockNesting
75
+ $stderr.printf("File (%s) is only (%.2f%%) covered. This is below the expected minimum coverage per file of (%.2f%%).\n", SimpleCov.result.least_covered_file, covered_percentages.min, SimpleCov.minimum_coverage_by_file)
76
+ @exit_status = SimpleCov::ExitCodes::MINIMUM_COVERAGE
69
77
  elsif (last_run = SimpleCov::LastRun.read) # rubocop:disable Metrics/BlockNesting
70
78
  diff = last_run["result"]["covered_percent"] - covered_percent
71
79
  if diff > SimpleCov.maximum_coverage_drop # rubocop:disable Metrics/BlockNesting
@@ -92,5 +100,20 @@ if home_dir
92
100
  end
93
101
 
94
102
  # Autoload config from .simplecov if present
95
- config_path = File.join(SimpleCov.root, ".simplecov")
96
- load config_path if File.exist?(config_path)
103
+ # Recurse upwards until we find .simplecov or reach the root directory
104
+
105
+ config_path = Pathname.new(SimpleCov.root)
106
+ loop do
107
+ filename = config_path.join(".simplecov")
108
+ if filename.exist?
109
+ begin
110
+ load filename
111
+ rescue LoadError, StandardError
112
+ $stderr.puts "Warning: Error occurred while trying to load #{filename}. " \
113
+ "Error message: #{$!.message}"
114
+ end
115
+ break
116
+ end
117
+ config_path, = config_path.split
118
+ break if config_path.root?
119
+ end