coverband 4.2.0 → 4.2.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +29 -9
- data/.travis.yml +10 -1
- data/Gemfile +3 -1
- data/Gemfile.rails4 +1 -0
- data/README.md +40 -15
- data/Rakefile +14 -3
- data/changes.md +47 -12
- data/coverband.gemspec +3 -1
- data/lib/coverband/adapters/base.rb +60 -36
- data/lib/coverband/adapters/file_store.rb +8 -8
- data/lib/coverband/adapters/redis_store.rb +18 -10
- data/lib/coverband/at_exit.rb +2 -11
- data/lib/coverband/collectors/coverage.rb +32 -36
- data/lib/coverband/collectors/delta.rb +34 -28
- data/lib/coverband/configuration.rb +76 -32
- data/lib/coverband/integrations/background.rb +8 -4
- data/lib/coverband/integrations/{middleware.rb → background_middleware.rb} +2 -6
- data/lib/coverband/integrations/bundler.rb +8 -0
- data/lib/coverband/integrations/report_middleware.rb +15 -0
- data/lib/coverband/integrations/resque.rb +3 -5
- data/lib/coverband/reporters/base.rb +39 -14
- data/lib/coverband/reporters/html_report.rb +21 -27
- data/lib/coverband/reporters/web.rb +13 -21
- data/lib/coverband/utils/file_list.rb +16 -5
- data/lib/coverband/utils/file_path_helper.rb +14 -3
- data/lib/coverband/utils/html_formatter.rb +25 -8
- data/lib/coverband/utils/lines_classifier.rb +5 -0
- data/lib/coverband/utils/railtie.rb +11 -12
- data/lib/coverband/utils/result.rb +1 -37
- data/lib/coverband/utils/results.rb +51 -0
- data/lib/coverband/utils/source_file.rb +31 -6
- data/lib/coverband/utils/tasks.rb +9 -10
- data/lib/coverband/version.rb +1 -1
- data/lib/coverband.rb +32 -21
- data/public/application.js +27 -0
- data/test/benchmarks/benchmark.rake +144 -26
- data/test/coverband/adapters/base_test.rb +73 -42
- data/test/coverband/adapters/file_store_test.rb +48 -37
- data/test/coverband/adapters/redis_store_test.rb +41 -10
- data/test/coverband/at_exit_test.rb +0 -2
- data/test/coverband/collectors/coverage_test.rb +57 -9
- data/test/coverband/collectors/delta_test.rb +36 -6
- data/test/coverband/configuration_test.rb +47 -7
- data/test/coverband/coverband_test.rb +14 -2
- data/test/coverband/integrations/background_middleware_test.rb +44 -0
- data/test/coverband/integrations/background_test.rb +1 -3
- data/test/coverband/integrations/report_middleware_test.rb +44 -0
- data/test/coverband/integrations/resque_worker_test.rb +4 -3
- data/test/coverband/integrations/test_resque_job.rb +3 -1
- data/test/coverband/reporters/base_test.rb +4 -4
- data/test/coverband/reporters/console_test.rb +1 -2
- data/test/coverband/reporters/html_test.rb +58 -19
- data/test/coverband/reporters/web_test.rb +0 -10
- data/test/coverband/utils/file_groups_test.rb +11 -5
- data/test/coverband/utils/file_list_test.rb +5 -5
- data/test/coverband/utils/html_formatter_test.rb +43 -0
- data/test/coverband/utils/result_test.rb +6 -47
- data/test/coverband/utils/results_test.rb +54 -0
- data/test/coverband/utils/s3_report_test.rb +2 -0
- data/test/coverband/utils/source_file_test.rb +50 -0
- data/test/dog.rb.erb +12 -0
- data/test/forked/rails_full_stack_test.rb +106 -0
- data/test/forked/rails_rake_full_stack_test.rb +40 -0
- data/test/integration/full_stack_test.rb +17 -15
- data/test/rails4_dummy/Rakefile +6 -0
- data/test/rails4_dummy/config/application.rb +8 -9
- data/test/rails4_dummy/config/coverband.rb +5 -3
- data/test/rails5_dummy/Rakefile +6 -0
- data/test/rails5_dummy/config/application.rb +6 -10
- data/test/rails5_dummy/config/coverband.rb +4 -2
- data/test/rails_test_helper.rb +22 -5
- data/test/test_helper.rb +42 -4
- data/test/unique_files.rb +17 -9
- data/views/file_list.erb +2 -2
- data/views/gem_list.erb +10 -1
- data/views/layout.erb +10 -3
- data/views/source_file.erb +13 -4
- data/views/source_file_loader.erb +1 -1
- metadata +52 -9
- data/test/coverband/integrations/middleware_test.rb +0 -96
- data/test/integration/rails_full_stack_test.rb +0 -95
|
@@ -9,36 +9,61 @@ module Coverband
|
|
|
9
9
|
class Base
|
|
10
10
|
class << self
|
|
11
11
|
include Coverband::Utils::FilePathHelper
|
|
12
|
+
|
|
13
|
+
DATA_KEY = 'data'
|
|
14
|
+
|
|
12
15
|
def report(store, _options = {})
|
|
13
16
|
all_roots = Coverband.configuration.all_root_paths
|
|
14
17
|
scov_style_report = get_current_scov_data_imp(store, all_roots)
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
# These are extremelhy verbose but useful during coverband development, not generally for users
|
|
20
|
+
# if Coverband.configuration.verbose
|
|
21
|
+
# # msg = "report:\n #{scov_style_report.inspect}"
|
|
22
|
+
# # Coverband.configuration.logger.debug msg
|
|
23
|
+
# end
|
|
20
24
|
scov_style_report
|
|
21
25
|
end
|
|
22
26
|
|
|
27
|
+
###
|
|
28
|
+
# Add back files that exist in the project but have no Coverage
|
|
29
|
+
# This makes it easy to find and delete files with no references
|
|
30
|
+
###
|
|
31
|
+
def fix_reports(reports)
|
|
32
|
+
# list all files, even if not tracked by Coverband (0% coverage)
|
|
33
|
+
tracked_glob = "#{Coverband.configuration.current_root}/{app,lib,config}/**/*.{rb}"
|
|
34
|
+
filtered_report_files = {}
|
|
35
|
+
|
|
36
|
+
reports.each_pair do |report_name, report_data|
|
|
37
|
+
filtered_report_files[report_name] = {}
|
|
38
|
+
report_files = Coverband::Utils::Result.add_not_loaded_files(report_data, tracked_glob)
|
|
39
|
+
|
|
40
|
+
# apply coverband filters
|
|
41
|
+
report_files.each_pair do |file, data|
|
|
42
|
+
next if Coverband.configuration.ignore.any? { |i| file.match(i) }
|
|
43
|
+
|
|
44
|
+
filtered_report_files[report_name][file] = data
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
filtered_report_files
|
|
48
|
+
end
|
|
49
|
+
|
|
23
50
|
protected
|
|
24
51
|
|
|
25
52
|
def fix_file_names(report_hash, roots)
|
|
26
|
-
if Coverband.configuration.verbose
|
|
27
|
-
Coverband.configuration.logger.info "fixing root: #{roots.join(', ')}"
|
|
28
|
-
end
|
|
53
|
+
Coverband.configuration.logger.info "fixing root: #{roots.join(', ')}" if Coverband.configuration.verbose
|
|
29
54
|
|
|
30
55
|
# normalize names across servers
|
|
31
56
|
report_hash.each_with_object({}) do |(name, report), fixed_report|
|
|
32
57
|
fixed_report[name] = {}
|
|
33
58
|
report.each_pair do |key, vals|
|
|
34
59
|
filename = relative_path_to_full(key, roots)
|
|
35
|
-
fixed_report[name][filename] = if fixed_report[name].key?(filename) && fixed_report[name][filename][
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
60
|
+
fixed_report[name][filename] = if fixed_report[name].key?(filename) && fixed_report[name][filename][DATA_KEY] && vals[DATA_KEY]
|
|
61
|
+
merged_data = merge_arrays(fixed_report[name][filename][DATA_KEY], vals[DATA_KEY])
|
|
62
|
+
vals[DATA_KEY] = merged_data
|
|
63
|
+
vals
|
|
64
|
+
else
|
|
65
|
+
vals
|
|
66
|
+
end
|
|
42
67
|
end
|
|
43
68
|
end
|
|
44
69
|
end
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
module Coverband
|
|
4
4
|
module Reporters
|
|
5
5
|
class HTMLReport < Base
|
|
6
|
-
attr_accessor :filtered_report_files, :open_report, :
|
|
6
|
+
attr_accessor :filtered_report_files, :open_report, :static, :notice,
|
|
7
7
|
:base_path, :filename
|
|
8
8
|
|
|
9
9
|
def initialize(store, options = {})
|
|
10
10
|
coverband_reports = Coverband::Reporters::Base.report(store, options)
|
|
11
11
|
self.open_report = options.fetch(:open_report) { true }
|
|
12
|
-
self.
|
|
12
|
+
self.static = options.fetch(:static) { true }
|
|
13
13
|
# TODO: refactor notice out to top level of web only
|
|
14
14
|
self.notice = options.fetch(:notice) { nil }
|
|
15
15
|
self.base_path = options.fetch(:base_path) { nil }
|
|
@@ -25,40 +25,34 @@ module Coverband
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def report
|
|
28
|
-
if
|
|
29
|
-
|
|
30
|
-
base_path: base_path,
|
|
31
|
-
notice: notice).format_html!
|
|
28
|
+
if static?
|
|
29
|
+
report_static_site
|
|
32
30
|
else
|
|
33
|
-
|
|
34
|
-
if open_report
|
|
35
|
-
`open #{Coverband.configuration.root}/coverage/index.html`
|
|
36
|
-
else
|
|
37
|
-
Coverband.configuration.logger.info 'report is ready and viewable: open coverage/index.html'
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
Coverband::Utils::S3Report.instance.persist! if Coverband.configuration.s3_bucket
|
|
31
|
+
report_dynamic_html
|
|
41
32
|
end
|
|
42
33
|
end
|
|
43
34
|
|
|
44
35
|
private
|
|
45
36
|
|
|
46
|
-
def
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
filtered_report_files = {}
|
|
37
|
+
def static?
|
|
38
|
+
static
|
|
39
|
+
end
|
|
50
40
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
41
|
+
def report_static_site
|
|
42
|
+
Coverband::Utils::HTMLFormatter.new(filtered_report_files).format_static_html!
|
|
43
|
+
if open_report
|
|
44
|
+
`open #{Coverband.configuration.root}/coverage/index.html`
|
|
45
|
+
else
|
|
46
|
+
Coverband.configuration.logger.info 'report is ready and viewable: open coverage/index.html'
|
|
47
|
+
end
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
next if Coverband.configuration.ignore.any? { |i| file.match(i) }
|
|
49
|
+
Coverband::Utils::S3Report.instance.persist! if Coverband.configuration.s3_bucket
|
|
50
|
+
end
|
|
58
51
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
def report_dynamic_html
|
|
53
|
+
Coverband::Utils::HTMLFormatter.new(filtered_report_files,
|
|
54
|
+
base_path: base_path,
|
|
55
|
+
notice: notice).format_dynamic_html!
|
|
62
56
|
end
|
|
63
57
|
end
|
|
64
58
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
begin
|
|
4
4
|
require 'rack'
|
|
5
5
|
rescue LoadError
|
|
6
|
+
puts 'error loading Coverband web reporter as Rack is not available'
|
|
6
7
|
end
|
|
7
8
|
|
|
8
9
|
module Coverband
|
|
@@ -17,19 +18,26 @@ module Coverband
|
|
|
17
18
|
urls: [/.*\.css/, /.*\.js/, /.*\.gif/, /.*\.png/])
|
|
18
19
|
end
|
|
19
20
|
|
|
21
|
+
def check_auth
|
|
22
|
+
return true unless Coverband.configuration.password
|
|
23
|
+
|
|
24
|
+
auth_header = request.get_header('HTTP_AUTHORIZATION')
|
|
25
|
+
return unless auth_header
|
|
26
|
+
|
|
27
|
+
Coverband.configuration.password == Base64.decode64(auth_header.split[1]).split(':')[1]
|
|
28
|
+
end
|
|
29
|
+
|
|
20
30
|
def call(env)
|
|
21
31
|
@request = Rack::Request.new(env)
|
|
22
32
|
|
|
33
|
+
return [401, { 'www-authenticate' => 'Basic realm=""' }, ['']] unless check_auth
|
|
34
|
+
|
|
23
35
|
if request.post?
|
|
24
36
|
case request.path_info
|
|
25
37
|
when %r{\/clear_file}
|
|
26
38
|
clear_file
|
|
27
39
|
when %r{\/clear}
|
|
28
40
|
clear
|
|
29
|
-
when %r{\/collect_coverage}
|
|
30
|
-
collect_coverage
|
|
31
|
-
when %r{\/reload_files}
|
|
32
|
-
reload_files
|
|
33
41
|
else
|
|
34
42
|
[404, { 'Content-Type' => 'text/html' }, ['404 error!']]
|
|
35
43
|
end
|
|
@@ -55,7 +63,7 @@ module Coverband
|
|
|
55
63
|
notice = "<strong>Notice:</strong> #{Rack::Utils.escape_html(request.params['notice'])}<br/>"
|
|
56
64
|
notice = request.params['notice'] ? notice : ''
|
|
57
65
|
Coverband::Reporters::HTMLReport.new(Coverband.configuration.store,
|
|
58
|
-
|
|
66
|
+
static: false,
|
|
59
67
|
base_path: base_path,
|
|
60
68
|
notice: notice,
|
|
61
69
|
open_report: false).report
|
|
@@ -77,12 +85,6 @@ module Coverband
|
|
|
77
85
|
open_report: false).file_details
|
|
78
86
|
end
|
|
79
87
|
|
|
80
|
-
def collect_coverage
|
|
81
|
-
Coverband.report_coverage(true)
|
|
82
|
-
notice = 'coverband coverage collected'
|
|
83
|
-
[301, { 'Location' => "#{base_path}?notice=#{notice}" }, []]
|
|
84
|
-
end
|
|
85
|
-
|
|
86
88
|
def clear
|
|
87
89
|
if Coverband.configuration.web_enable_clear
|
|
88
90
|
Coverband.configuration.store.clear!
|
|
@@ -104,16 +106,6 @@ module Coverband
|
|
|
104
106
|
[301, { 'Location' => "#{base_path}?notice=#{notice}" }, []]
|
|
105
107
|
end
|
|
106
108
|
|
|
107
|
-
def reload_files
|
|
108
|
-
Coverband.configuration&.safe_reload_files&.each do |safe_file|
|
|
109
|
-
load safe_file
|
|
110
|
-
end
|
|
111
|
-
# force reload
|
|
112
|
-
Coverband.configure
|
|
113
|
-
notice = 'coverband files reloaded'
|
|
114
|
-
[301, { 'Location' => "#{base_path}?notice=#{notice}" }, []]
|
|
115
|
-
end
|
|
116
|
-
|
|
117
109
|
private
|
|
118
110
|
|
|
119
111
|
# This method should get the root mounted endpoint
|
|
@@ -13,24 +13,28 @@ module Coverband
|
|
|
13
13
|
# Returns the count of lines that have coverage
|
|
14
14
|
def covered_lines
|
|
15
15
|
return 0.0 if empty?
|
|
16
|
+
|
|
16
17
|
map { |f| f.covered_lines.count }.inject(:+)
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
# Returns the count of lines that have been missed
|
|
20
21
|
def missed_lines
|
|
21
22
|
return 0.0 if empty?
|
|
23
|
+
|
|
22
24
|
map { |f| f.missed_lines.count }.inject(:+)
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
# Returns the count of lines that are not relevant for coverage
|
|
26
28
|
def never_lines
|
|
27
29
|
return 0.0 if empty?
|
|
30
|
+
|
|
28
31
|
map { |f| f.never_lines.count }.inject(:+)
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
# Returns the count of skipped lines
|
|
32
35
|
def skipped_lines
|
|
33
36
|
return 0.0 if empty?
|
|
37
|
+
|
|
34
38
|
map { |f| f.skipped_lines.count }.inject(:+)
|
|
35
39
|
end
|
|
36
40
|
|
|
@@ -40,11 +44,6 @@ module Coverband
|
|
|
40
44
|
map(&:covered_percent)
|
|
41
45
|
end
|
|
42
46
|
|
|
43
|
-
# Finds the least covered file and returns that file's name
|
|
44
|
-
def least_covered_file
|
|
45
|
-
sort_by(&:covered_percent).first.filename
|
|
46
|
-
end
|
|
47
|
-
|
|
48
47
|
# Returns the overall amount of relevant lines of code across all files in this list
|
|
49
48
|
def lines_of_code
|
|
50
49
|
covered_lines + missed_lines
|
|
@@ -54,15 +53,27 @@ module Coverband
|
|
|
54
53
|
# @return [Float]
|
|
55
54
|
def covered_percent
|
|
56
55
|
return 100.0 if empty? || lines_of_code.zero?
|
|
56
|
+
|
|
57
57
|
Float(covered_lines * 100.0 / lines_of_code)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
+
# Computes the coverage based upon lines covered and lines missed, formatted
|
|
61
|
+
# @return [Float]
|
|
62
|
+
def formatted_covered_percent
|
|
63
|
+
covered_percent.round(2)
|
|
64
|
+
end
|
|
65
|
+
|
|
60
66
|
# Computes the strength (hits / line) based upon lines covered and lines missed
|
|
61
67
|
# @return [Float]
|
|
62
68
|
def covered_strength
|
|
63
69
|
return 0.0 if empty? || lines_of_code.zero?
|
|
70
|
+
|
|
64
71
|
Float(map { |f| f.covered_strength * f.lines_of_code }.inject(:+) / lines_of_code)
|
|
65
72
|
end
|
|
73
|
+
|
|
74
|
+
def first_seen_at
|
|
75
|
+
map(&:first_updated_at).reject { |el| el.is_a?(String) }.min
|
|
76
|
+
end
|
|
66
77
|
end
|
|
67
78
|
end
|
|
68
79
|
end
|
|
@@ -6,16 +6,25 @@
|
|
|
6
6
|
module Coverband
|
|
7
7
|
module Utils
|
|
8
8
|
module FilePathHelper
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
@@path_cache = {}
|
|
12
|
+
|
|
9
13
|
###
|
|
10
14
|
# Takes a full path and converts to a relative path
|
|
11
15
|
###
|
|
12
16
|
def full_path_to_relative(full_path)
|
|
17
|
+
return @@path_cache[full_path] if @@path_cache.key?(full_path)
|
|
18
|
+
|
|
13
19
|
relative_filename = full_path
|
|
14
|
-
Coverband.configuration.
|
|
15
|
-
relative_filename = relative_filename.
|
|
20
|
+
Coverband.configuration.all_root_patterns.each do |root|
|
|
21
|
+
relative_filename = relative_filename.sub(root, './')
|
|
16
22
|
# once we have a relative path break out of the loop
|
|
17
23
|
break if relative_filename.start_with? './'
|
|
18
24
|
end
|
|
25
|
+
|
|
26
|
+
@@path_cache[full_path] = relative_filename
|
|
27
|
+
|
|
19
28
|
relative_filename
|
|
20
29
|
end
|
|
21
30
|
|
|
@@ -40,7 +49,9 @@ module Coverband
|
|
|
40
49
|
relative_filename = relative_path
|
|
41
50
|
local_filename = relative_filename
|
|
42
51
|
roots.each do |root|
|
|
43
|
-
relative_filename = relative_filename.
|
|
52
|
+
relative_filename = relative_filename.sub(/^#{root}/, './')
|
|
53
|
+
# once we have a relative path break out of the loop
|
|
54
|
+
break if relative_filename.start_with? './'
|
|
44
55
|
end
|
|
45
56
|
# the filename for our reports is expected to be a full path.
|
|
46
57
|
# roots.last should be roots << current_root}/
|
|
@@ -21,11 +21,11 @@ module Coverband
|
|
|
21
21
|
@coverage_result = Coverband::Utils::Results.new(report) if report
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def
|
|
24
|
+
def format_static_html!
|
|
25
25
|
format(@coverage_result)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def
|
|
28
|
+
def format_dynamic_html!
|
|
29
29
|
format_html(@coverage_result)
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -35,8 +35,12 @@ module Coverband
|
|
|
35
35
|
|
|
36
36
|
def format_source_file!(filename)
|
|
37
37
|
source_file = @coverage_result.file_from_path_with_type(filename)
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
|
|
39
|
+
if source_file
|
|
40
|
+
formatted_source_file(@coverage_result, source_file)
|
|
41
|
+
else
|
|
42
|
+
'File No Longer Available'
|
|
43
|
+
end
|
|
40
44
|
end
|
|
41
45
|
|
|
42
46
|
private
|
|
@@ -70,16 +74,25 @@ module Coverband
|
|
|
70
74
|
|
|
71
75
|
def asset_output_path
|
|
72
76
|
return @asset_output_path if defined?(@asset_output_path) && @asset_output_path
|
|
77
|
+
|
|
73
78
|
@asset_output_path = File.join(output_path)
|
|
74
79
|
FileUtils.mkdir_p(@asset_output_path)
|
|
75
80
|
@asset_output_path
|
|
76
81
|
end
|
|
77
82
|
|
|
83
|
+
def served_html?
|
|
84
|
+
!static_html?
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def static_html?
|
|
88
|
+
base_path.nil?
|
|
89
|
+
end
|
|
90
|
+
|
|
78
91
|
def assets_path(name)
|
|
79
|
-
if
|
|
80
|
-
File.join(base_path, name)
|
|
81
|
-
else
|
|
92
|
+
if static_html?
|
|
82
93
|
File.join(name)
|
|
94
|
+
else
|
|
95
|
+
File.join(base_path, name)
|
|
83
96
|
end
|
|
84
97
|
end
|
|
85
98
|
|
|
@@ -157,7 +170,11 @@ module Coverband
|
|
|
157
170
|
end
|
|
158
171
|
|
|
159
172
|
def timeago(time)
|
|
160
|
-
|
|
173
|
+
if time
|
|
174
|
+
"<abbr class=\"timeago\" title=\"#{time.iso8601}\">#{time.iso8601}</abbr>"
|
|
175
|
+
else
|
|
176
|
+
'Not Available'
|
|
177
|
+
end
|
|
161
178
|
end
|
|
162
179
|
|
|
163
180
|
def shortened_filename(source_file)
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
####
|
|
4
|
+
#
|
|
5
|
+
# NOTE: with Ruby 2.6.0 and beyond we can replace this classifier with
|
|
6
|
+
# ::Coverage.line_stub
|
|
7
|
+
# https://ruby-doc.org/stdlib-2.6.1/libdoc/coverage/rdoc/Coverage.html#method-c-line_stub
|
|
8
|
+
#
|
|
4
9
|
# Thanks for all the help SimpleCov https://github.com/colszowka/simplecov-html
|
|
5
10
|
# initial version pulled into Coverband from Simplecov 12/04/2018
|
|
6
11
|
#
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
Coverband.eager_loading_coverage!
|
|
4
3
|
module Coverband
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Coverband.report_coverage(true)
|
|
12
|
-
Coverband.configuration.logger&.debug('Coverband: reported after_initialize')
|
|
4
|
+
module RailsEagerLoad
|
|
5
|
+
def eager_load!
|
|
6
|
+
Coverband.eager_loading_coverage!
|
|
7
|
+
super
|
|
8
|
+
ensure
|
|
9
|
+
Coverband.report_coverage
|
|
13
10
|
Coverband.runtime_coverage!
|
|
14
11
|
end
|
|
12
|
+
end
|
|
13
|
+
Rails::Engine.prepend(RailsEagerLoad)
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Coverband
|
|
15
|
+
class Railtie < Rails::Railtie
|
|
16
|
+
initializer 'coverband.configure' do |app|
|
|
17
|
+
app.middleware.use Coverband::BackgroundMiddleware
|
|
19
18
|
end
|
|
20
19
|
|
|
21
20
|
rake_tasks do
|
|
@@ -22,11 +22,8 @@ module Coverband
|
|
|
22
22
|
alias source_files files
|
|
23
23
|
# Explicitly set the Time this result has been created
|
|
24
24
|
attr_writer :created_at
|
|
25
|
-
# Explicitly set the command name that was used for this coverage result.
|
|
26
|
-
# Defaults to Coverband.command_name
|
|
27
|
-
attr_writer :command_name
|
|
28
25
|
|
|
29
|
-
def_delegators :files, :covered_percent, :covered_percentages, :
|
|
26
|
+
def_delegators :files, :covered_percent, :covered_percentages, :covered_strength, :covered_lines, :missed_lines
|
|
30
27
|
def_delegator :files, :lines_of_code, :total_lines
|
|
31
28
|
|
|
32
29
|
# Initialize a new Coverband::Result from given Coverage.result (a Hash of filenames each containing an array of
|
|
@@ -37,7 +34,6 @@ module Coverband
|
|
|
37
34
|
@files = Coverband::Utils::FileList.new(@original_result.map do |filename, coverage|
|
|
38
35
|
Coverband::Utils::SourceFile.new(filename, coverage) if File.file?(filename)
|
|
39
36
|
end.compact.sort_by(&:short_name))
|
|
40
|
-
filter!
|
|
41
37
|
end
|
|
42
38
|
|
|
43
39
|
# Returns all filenames for source files contained in this result
|
|
@@ -55,26 +51,6 @@ module Coverband
|
|
|
55
51
|
@created_at ||= Time.now
|
|
56
52
|
end
|
|
57
53
|
|
|
58
|
-
# The command name that launched this result.
|
|
59
|
-
# Delegated to Coverband.command_name if not set manually
|
|
60
|
-
def command_name
|
|
61
|
-
@command_name ||= 'Coverband'
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# Returns a hash representation of this Result that can be used for marshalling it into JSON
|
|
65
|
-
def to_hash
|
|
66
|
-
{ command_name => { 'coverage' => coverage, 'timestamp' => created_at.to_i } }
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# Loads a Coverband::Result#to_hash dump
|
|
70
|
-
def self.from_hash(hash)
|
|
71
|
-
command_name, data = hash.first
|
|
72
|
-
result = new(data['coverage'])
|
|
73
|
-
result.command_name = command_name
|
|
74
|
-
result.created_at = Time.at(data['timestamp'])
|
|
75
|
-
result
|
|
76
|
-
end
|
|
77
|
-
|
|
78
54
|
# Finds files that were to be tracked but were not loaded and initializes
|
|
79
55
|
# the line-by-line coverage to zero (if relevant) or nil (comments / whitespace etc).
|
|
80
56
|
def self.add_not_loaded_files(result, tracked_files)
|
|
@@ -89,18 +65,6 @@ module Coverband
|
|
|
89
65
|
|
|
90
66
|
result
|
|
91
67
|
end
|
|
92
|
-
|
|
93
|
-
private
|
|
94
|
-
|
|
95
|
-
def coverage
|
|
96
|
-
keys = original_result.keys & filenames
|
|
97
|
-
Hash[keys.zip(original_result.values_at(*keys))]
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# Applies all configured Coverband filters on this result's source files
|
|
101
|
-
def filter!
|
|
102
|
-
@files = files
|
|
103
|
-
end
|
|
104
68
|
end
|
|
105
69
|
end
|
|
106
70
|
end
|
|
@@ -20,6 +20,41 @@ module Coverband
|
|
|
20
20
|
get_results(results_type).source_files.find { |file| file.filename == source_file.filename }
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
def runtime_relevant_coverage(source_file)
|
|
24
|
+
return unless eager_loading_coverage && runtime_coverage
|
|
25
|
+
|
|
26
|
+
eager_file = get_eager_file(source_file)
|
|
27
|
+
runtime_file = get_runtime_file(source_file)
|
|
28
|
+
|
|
29
|
+
return 0.0 unless runtime_file
|
|
30
|
+
|
|
31
|
+
return runtime_file.formatted_covered_percent unless eager_file
|
|
32
|
+
|
|
33
|
+
runtime_relavant_lines = eager_file.relevant_lines - eager_file.covered_lines_count
|
|
34
|
+
runtime_file.runtime_relavant_calculations(runtime_relavant_lines) { |file| file.formatted_covered_percent }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def runtime_relavent_lines(source_file)
|
|
38
|
+
return 0 unless runtime_coverage
|
|
39
|
+
|
|
40
|
+
eager_file = get_eager_file(source_file)
|
|
41
|
+
runtime_file = get_runtime_file(source_file)
|
|
42
|
+
|
|
43
|
+
return runtime_file.covered_lines_count unless eager_file
|
|
44
|
+
|
|
45
|
+
eager_file.relevant_lines - eager_file.covered_lines_count
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
###
|
|
49
|
+
# TODO: Groups still have some issues, this should be generic for groups, but right now gem_name
|
|
50
|
+
# is specifically called out, need to revisit all gorups code.
|
|
51
|
+
###
|
|
52
|
+
def group_file_list_with_type(group, file_list, results_type)
|
|
53
|
+
return unless get_results(results_type)
|
|
54
|
+
|
|
55
|
+
get_results(results_type).groups[group].find { |gem_files| gem_files.first.gem_name == file_list.first.gem_name }
|
|
56
|
+
end
|
|
57
|
+
|
|
23
58
|
def file_from_path_with_type(full_path, results_type = :merged)
|
|
24
59
|
return unless get_results(results_type)
|
|
25
60
|
|
|
@@ -44,6 +79,22 @@ module Coverband
|
|
|
44
79
|
|
|
45
80
|
private
|
|
46
81
|
|
|
82
|
+
def get_eager_file(source_file)
|
|
83
|
+
eager_loading_coverage.source_files.find { |file| file.filename == source_file.filename }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def get_runtime_file(source_file)
|
|
87
|
+
runtime_coverage.source_files.find { |file| file.filename == source_file.filename }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def eager_loading_coverage
|
|
91
|
+
get_results(Coverband::EAGER_TYPE)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def runtime_coverage
|
|
95
|
+
get_results(Coverband::RUNTIME_TYPE)
|
|
96
|
+
end
|
|
97
|
+
|
|
47
98
|
###
|
|
48
99
|
# This is a first version of lazy loading the results
|
|
49
100
|
# for the full advantage we need to push lazy loading to the file level
|