coverband 5.1.0.rcmailer.1 → 5.2.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/diagram.yml +16 -0
- data/.github/workflows/main.yml +5 -5
- data/Gemfile +2 -5
- data/README.md +33 -1
- data/changes.md +19 -66
- data/coverband.gemspec +16 -4
- data/diagram.svg +1 -0
- data/lib/coverband/adapters/base.rb +8 -7
- data/lib/coverband/adapters/file_store.rb +1 -1
- data/lib/coverband/adapters/hash_redis_store.rb +1 -1
- data/lib/coverband/adapters/null_store.rb +42 -0
- data/lib/coverband/adapters/redis_store.rb +1 -1
- data/lib/coverband/at_exit.rb +3 -0
- data/lib/coverband/collectors/coverage.rb +19 -1
- data/lib/coverband/collectors/view_tracker.rb +27 -20
- data/lib/coverband/collectors/view_tracker_service.rb +3 -3
- data/lib/coverband/configuration.rb +9 -2
- data/lib/coverband/integrations/background.rb +6 -3
- data/lib/coverband/reporters/base.rb +1 -1
- data/lib/coverband/reporters/web.rb +4 -4
- data/lib/coverband/utils/dead_methods.rb +63 -0
- data/lib/coverband/utils/method_definition_scanner.rb +96 -0
- data/lib/coverband/utils/railtie.rb +3 -2
- data/lib/coverband/utils/result.rb +1 -1
- data/lib/coverband/utils/source_file.rb +2 -2
- data/lib/coverband/utils/tasks.rb +17 -3
- data/lib/coverband/version.rb +2 -2
- data/lib/coverband.rb +1 -0
- data/public/dependencies.js +4 -4
- data/roadmap.md +56 -0
- data/test/coverband/adapters/null_store_test.rb +39 -0
- data/test/coverband/configuration_test.rb +5 -5
- data/test/coverband/utils/dead_methods_test.rb +53 -0
- data/test/coverband/utils/method_definition_scanner_test.rb +85 -0
- data/test/fixtures/casting_invitor.rb +60 -0
- data/test/forked/rails_full_stack_test.rb +1 -1
- data/test/integration/full_stack_deferred_eager_test.rb +51 -0
- data/test/test_helper.rb +1 -0
- data/test/unique_files.rb +3 -3
- data/views/file_list.erb +2 -2
- metadata +25 -4
@@ -8,8 +8,8 @@ module Coverband
|
|
8
8
|
class ViewTrackerService < ViewTracker
|
9
9
|
def report_views_tracked
|
10
10
|
reported_time = Time.now.to_i
|
11
|
-
if views_to_record.any?
|
12
|
-
relative_views = views_to_record.map! do |view|
|
11
|
+
if @views_to_record.any?
|
12
|
+
relative_views = @views_to_record.map! do |view|
|
13
13
|
roots.each do |root|
|
14
14
|
view = view.gsub(/#{root}/, "")
|
15
15
|
end
|
@@ -17,7 +17,7 @@ module Coverband
|
|
17
17
|
end
|
18
18
|
save_tracked_views(views: relative_views, reported_time: reported_time)
|
19
19
|
end
|
20
|
-
|
20
|
+
@views_to_record = []
|
21
21
|
rescue => e
|
22
22
|
# we don't want to raise errors if Coverband can't reach the service
|
23
23
|
logger&.error "Coverband: view_tracker failed to store, error #{e.class.name}" if Coverband.configuration.verbose || Coverband.configuration.service_dev_mode
|
@@ -8,7 +8,7 @@ module Coverband
|
|
8
8
|
:background_reporting_enabled,
|
9
9
|
:test_env, :web_enable_clear, :gem_details, :web_debug, :report_on_exit,
|
10
10
|
:simulate_oneshot_lines_coverage,
|
11
|
-
:view_tracker
|
11
|
+
:view_tracker, :defer_eager_loading_data
|
12
12
|
attr_writer :logger, :s3_region, :s3_bucket, :s3_access_key_id,
|
13
13
|
:s3_secret_access_key, :password, :api_key, :service_url, :coverband_timeout, :service_dev_mode,
|
14
14
|
:service_test_mode, :process_type, :track_views, :redis_url,
|
@@ -62,6 +62,7 @@ module Coverband
|
|
62
62
|
@store = nil
|
63
63
|
@background_reporting_enabled = true
|
64
64
|
@background_reporting_sleep_seconds = nil
|
65
|
+
@defer_eager_loading_data = false
|
65
66
|
@test_env = nil
|
66
67
|
@web_enable_clear = false
|
67
68
|
@track_views = true
|
@@ -147,7 +148,9 @@ module Coverband
|
|
147
148
|
end
|
148
149
|
|
149
150
|
def track_views
|
150
|
-
|
151
|
+
return false if service_disabled_dev_test_env?
|
152
|
+
|
153
|
+
@track_views
|
151
154
|
end
|
152
155
|
|
153
156
|
###
|
@@ -241,6 +244,10 @@ module Coverband
|
|
241
244
|
Coverband.coverband_service? || !api_key.nil?
|
242
245
|
end
|
243
246
|
|
247
|
+
def defer_eager_loading_data?
|
248
|
+
@defer_eager_loading_data
|
249
|
+
end
|
250
|
+
|
244
251
|
def service_disabled_dev_test_env?
|
245
252
|
(coverband_env == "test" && !Coverband.configuration.service_test_mode) ||
|
246
253
|
(coverband_env == "development" && !Coverband.configuration.service_dev_mode)
|
@@ -31,15 +31,18 @@ module Coverband
|
|
31
31
|
sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds.to_i
|
32
32
|
@thread = Thread.new {
|
33
33
|
loop do
|
34
|
-
Coverband.report_coverage
|
35
|
-
Coverband.configuration.view_tracker&.report_views_tracked
|
36
34
|
if Coverband.configuration.reporting_wiggle
|
37
35
|
sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds.to_i + rand(Coverband.configuration.reporting_wiggle.to_i)
|
38
36
|
end
|
37
|
+
# NOTE: Normally as processes first start we immediately report, this causes a redis spike on deploys
|
38
|
+
# if deferred is set also sleep frst to spread load
|
39
|
+
sleep(sleep_seconds.to_i) if Coverband.configuration.defer_eager_loading_data?
|
40
|
+
Coverband.report_coverage
|
41
|
+
Coverband.configuration.view_tracker&.report_views_tracked
|
39
42
|
if Coverband.configuration.verbose
|
40
43
|
logger.debug("Coverband: background reporting coverage (#{Coverband.configuration.store.type}). Sleeping #{sleep_seconds}s")
|
41
44
|
end
|
42
|
-
sleep(sleep_seconds.to_i)
|
45
|
+
sleep(sleep_seconds.to_i) unless Coverband.configuration.defer_eager_loading_data?
|
43
46
|
end
|
44
47
|
}
|
45
48
|
end
|
@@ -15,7 +15,7 @@ module Coverband
|
|
15
15
|
scov_style_report = get_current_scov_data_imp(store, all_roots)
|
16
16
|
|
17
17
|
# These are extremelhy verbose but useful during coverband development, not generally for users
|
18
|
-
# Only
|
18
|
+
# Only available by uncommenting this mode is never released
|
19
19
|
# if Coverband.configuration.verbose
|
20
20
|
# # msg = "report:\n #{scov_style_report.inspect}"
|
21
21
|
# # Coverband.configuration.logger.debug msg
|
@@ -124,7 +124,7 @@ module Coverband
|
|
124
124
|
Coverband.configuration.store.clear!
|
125
125
|
notice = "coverband coverage cleared"
|
126
126
|
else
|
127
|
-
notice = "web_enable_clear
|
127
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
128
128
|
end
|
129
129
|
[301, {"Location" => "#{base_path}?notice=#{notice}"}, []]
|
130
130
|
end
|
@@ -135,7 +135,7 @@ module Coverband
|
|
135
135
|
Coverband.configuration.store.clear_file!(filename)
|
136
136
|
notice = "coverage for file #{filename} cleared"
|
137
137
|
else
|
138
|
-
notice = "web_enable_clear
|
138
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
139
139
|
end
|
140
140
|
[301, {"Location" => "#{base_path}?notice=#{notice}"}, []]
|
141
141
|
end
|
@@ -146,7 +146,7 @@ module Coverband
|
|
146
146
|
tracker.reset_recordings
|
147
147
|
notice = "view tracking reset"
|
148
148
|
else
|
149
|
-
notice = "web_enable_clear
|
149
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
150
150
|
end
|
151
151
|
[301, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
|
152
152
|
end
|
@@ -158,7 +158,7 @@ module Coverband
|
|
158
158
|
tracker.clear_file!(filename)
|
159
159
|
notice = "coverage for file #{filename} cleared"
|
160
160
|
else
|
161
|
-
notice = "web_enable_clear
|
161
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
162
162
|
end
|
163
163
|
[301, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
|
164
164
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: ntrue
|
2
|
+
|
3
|
+
require "coverband/utils/method_definition_scanner"
|
4
|
+
|
5
|
+
module Coverband
|
6
|
+
module Utils
|
7
|
+
module ArrayToTableInConsole
|
8
|
+
refine Array do
|
9
|
+
def to_table
|
10
|
+
column_sizes =
|
11
|
+
reduce([]) { |lengths, row|
|
12
|
+
row.each_with_index.map do |iterand, index|
|
13
|
+
[lengths[index] || 0, iterand.to_s.length].max
|
14
|
+
end
|
15
|
+
}
|
16
|
+
puts head =
|
17
|
+
"-" * (column_sizes.inject(&:+) + (3 * column_sizes.count) + 1)
|
18
|
+
each do |row|
|
19
|
+
row = row.fill(nil, row.size..(column_sizes.size - 1))
|
20
|
+
row =
|
21
|
+
row.each_with_index.map { |v, i|
|
22
|
+
v.to_s + " " * (column_sizes[i] - v.to_s.length)
|
23
|
+
}
|
24
|
+
puts "| " + row.join(" | ") + " |"
|
25
|
+
end
|
26
|
+
puts head
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class DeadMethods
|
32
|
+
using ArrayToTableInConsole
|
33
|
+
def self.scan(file_path:, coverage:)
|
34
|
+
MethodDefinitionScanner.scan(file_path).reject do |method_definition|
|
35
|
+
method_definition.body.coverage?(coverage)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.scan_all
|
40
|
+
coverage = Coverband.configuration.store.coverage
|
41
|
+
coverage.flat_map do |file_path, coverage|
|
42
|
+
scan(file_path: file_path, coverage: coverage["data"])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.output_all
|
47
|
+
rows =
|
48
|
+
scan_all.each_with_object(
|
49
|
+
[%w[file class method line_number]]
|
50
|
+
) { |dead_method, rows|
|
51
|
+
rows <<
|
52
|
+
[
|
53
|
+
dead_method.file_path,
|
54
|
+
dead_method.class_name,
|
55
|
+
dead_method.name,
|
56
|
+
dead_method.first_line_number
|
57
|
+
]
|
58
|
+
}
|
59
|
+
rows.to_table
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(RubyVM::AbstractSyntaxTree)
|
4
|
+
module Coverband
|
5
|
+
module Utils
|
6
|
+
class MethodDefinitionScanner
|
7
|
+
attr_reader :path
|
8
|
+
|
9
|
+
def initialize(path)
|
10
|
+
@path = path
|
11
|
+
end
|
12
|
+
|
13
|
+
def scan
|
14
|
+
scan_node(RubyVM::AbstractSyntaxTree.parse_file(path), nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.scan(path)
|
18
|
+
new(path).scan
|
19
|
+
end
|
20
|
+
|
21
|
+
class MethodBody
|
22
|
+
def initialize(method_definition)
|
23
|
+
@method_definition = method_definition
|
24
|
+
end
|
25
|
+
|
26
|
+
def coverage?(file_coverage)
|
27
|
+
body_coverage =
|
28
|
+
file_coverage[(first_line_number - 1)..(last_line_number - 1)]
|
29
|
+
body_coverage.map(&:to_i).any?(&:positive?)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def first_line_number
|
35
|
+
@method_definition.first_line_number + 1
|
36
|
+
end
|
37
|
+
|
38
|
+
def last_line_number
|
39
|
+
@method_definition.last_line_number - 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class MethodDefinition
|
44
|
+
attr_reader :last_line_number,
|
45
|
+
:first_line_number,
|
46
|
+
:name,
|
47
|
+
:class_name,
|
48
|
+
:file_path
|
49
|
+
|
50
|
+
def initialize(
|
51
|
+
first_line_number:,
|
52
|
+
last_line_number:,
|
53
|
+
name:,
|
54
|
+
class_name:,
|
55
|
+
file_path:
|
56
|
+
)
|
57
|
+
@first_line_number = first_line_number
|
58
|
+
@last_line_number = last_line_number
|
59
|
+
@name = name
|
60
|
+
@class_name = class_name
|
61
|
+
@file_path = file_path
|
62
|
+
end
|
63
|
+
|
64
|
+
def body
|
65
|
+
MethodBody.new(self)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def scan_node(node, class_name)
|
72
|
+
definitions = []
|
73
|
+
return definitions unless node.is_a?(RubyVM::AbstractSyntaxTree::Node)
|
74
|
+
current_class = node.type == :CLASS ? node.children.first.children.last : class_name
|
75
|
+
if node.type == :DEFN
|
76
|
+
definitions <<
|
77
|
+
MethodDefinition.new(
|
78
|
+
first_line_number: node.first_lineno,
|
79
|
+
last_line_number: node.last_lineno,
|
80
|
+
name: node.children.first,
|
81
|
+
class_name: current_class,
|
82
|
+
file_path: path
|
83
|
+
)
|
84
|
+
end
|
85
|
+
definitions + scan_children(node, current_class)
|
86
|
+
end
|
87
|
+
|
88
|
+
def scan_children(node, current_class)
|
89
|
+
node.children.flatten.compact.map { |child|
|
90
|
+
scan_node(child, current_class)
|
91
|
+
}.flatten
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -21,7 +21,7 @@ module Coverband
|
|
21
21
|
|
22
22
|
config.after_initialize do
|
23
23
|
unless Coverband.tasks_to_ignore?
|
24
|
-
Coverband.configure
|
24
|
+
Coverband.configure unless Coverband.configured?
|
25
25
|
Coverband.eager_loading_coverage!
|
26
26
|
Coverband.report_coverage
|
27
27
|
Coverband.runtime_coverage!
|
@@ -37,7 +37,7 @@ module Coverband
|
|
37
37
|
|
38
38
|
Coverband.configuration.view_tracker = COVERBAND_VIEW_TRACKER
|
39
39
|
|
40
|
-
ActiveSupport::Notifications.subscribe(/
|
40
|
+
ActiveSupport::Notifications.subscribe(/render_(template|partial|collection).action_view/) do |name, start, finish, id, payload|
|
41
41
|
COVERBAND_VIEW_TRACKER.track_views(name, start, finish, id, payload) unless name.include?("!")
|
42
42
|
end
|
43
43
|
end
|
@@ -50,6 +50,7 @@ module Coverband
|
|
50
50
|
config.before_configuration do
|
51
51
|
unless ENV["COVERBAND_DISABLE_AUTO_START"]
|
52
52
|
begin
|
53
|
+
Coverband.configure unless Coverband.configured?
|
53
54
|
Coverband.start
|
54
55
|
rescue Redis::CannotConnectError => error
|
55
56
|
Coverband.configuration.logger.info "Redis is not available (#{error}), Coverband not configured"
|
@@ -101,7 +101,7 @@ module Coverband
|
|
101
101
|
@last_updated_at = Time.at(file_data["last_updated_at"]) if file_data["last_updated_at"]
|
102
102
|
@never_loaded = file_data["never_loaded"] || false
|
103
103
|
else
|
104
|
-
# TODO: Deprecate this code path this was backwards
|
104
|
+
# TODO: Deprecate this code path this was backwards compatibility from 3-4
|
105
105
|
@coverage = file_data
|
106
106
|
@first_updated_at = NOT_AVAILABLE
|
107
107
|
@last_updated_at = NOT_AVAILABLE
|
@@ -139,7 +139,7 @@ module Coverband
|
|
139
139
|
coverage_exceeding_source_warn if coverage.size > src.size
|
140
140
|
|
141
141
|
lines = src.map.with_index(1) { |src, i|
|
142
|
-
Coverband::Utils::SourceFile::Line.new(src, i, coverage[i - 1])
|
142
|
+
Coverband::Utils::SourceFile::Line.new(src, i, never_loaded ? 0 : coverage[i - 1])
|
143
143
|
}
|
144
144
|
|
145
145
|
process_skipped_lines(lines)
|
@@ -9,11 +9,25 @@ namespace :coverband do
|
|
9
9
|
Coverband::Reporters::ConsoleReport.report(Coverband.configuration.store)
|
10
10
|
end
|
11
11
|
|
12
|
+
if defined?(RubyVM::AbstractSyntaxTree)
|
13
|
+
require "coverband/utils/dead_methods"
|
14
|
+
|
15
|
+
desc "Output all dead methods"
|
16
|
+
task :dead_methods do
|
17
|
+
Coverband::Utils::DeadMethods.output_all
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
12
21
|
desc "report runtime Coverband code coverage"
|
13
22
|
task :coverage_server do
|
14
|
-
|
15
|
-
|
16
|
-
|
23
|
+
if Rake::Task.task_defined?("environment")
|
24
|
+
Rake.application["environment"].invoke
|
25
|
+
end
|
26
|
+
if Coverband.configuration.store.is_a?(Coverband::Adapters::FileStore)
|
27
|
+
Coverband.configuration.store.merge_mode = true
|
28
|
+
end
|
29
|
+
Rack::Server.start app: Coverband::Reporters::Web.new,
|
30
|
+
Port: ENV.fetch("COVERBAND_COVERAGE_PORT", 9022).to_i
|
17
31
|
end
|
18
32
|
|
19
33
|
###
|
data/lib/coverband/version.rb
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
###
|
4
4
|
# ensure we properly do release candidate versioning; https://github.com/danmayer/coverband/issues/288
|
5
|
-
# use format
|
5
|
+
# use format "4.2.1.rc.1" ~> 4.2.1.rc to prerelease versions like v4.2.1.rc.2 and v4.2.1.rc.3
|
6
6
|
###
|
7
7
|
module Coverband
|
8
|
-
VERSION =
|
8
|
+
VERSION = '5.2.0.rc.1'
|
9
9
|
end
|
data/lib/coverband.rb
CHANGED
@@ -13,6 +13,7 @@ require "coverband/adapters/redis_store"
|
|
13
13
|
require "coverband/adapters/hash_redis_store"
|
14
14
|
require "coverband/adapters/file_store"
|
15
15
|
require "coverband/adapters/stdout_store"
|
16
|
+
require "coverband/adapters/null_store"
|
16
17
|
require "coverband/utils/file_hasher"
|
17
18
|
require "coverband/collectors/coverage"
|
18
19
|
require "coverband/collectors/view_tracker"
|
data/public/dependencies.js
CHANGED
@@ -103,7 +103,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/<
|
|
103
103
|
return this.rel;
|
104
104
|
},
|
105
105
|
href: function() {
|
106
|
-
// using this.href would give the absolute url, when the href may have been
|
106
|
+
// using this.href would give the absolute url, when the href may have been intedned as a selector (e.g. '#container')
|
107
107
|
return $(this).attr('href');
|
108
108
|
},
|
109
109
|
title: function() {
|
@@ -397,7 +397,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/<
|
|
397
397
|
loadedHeight = $loaded.outerHeight(true);
|
398
398
|
loadedWidth = $loaded.outerWidth(true);
|
399
399
|
|
400
|
-
// Opens
|
400
|
+
// Opens initial empty Colorbox prior to content being loaded.
|
401
401
|
var initialWidth = setSize(settings.get('initialWidth'), 'x');
|
402
402
|
var initialHeight = setSize(settings.get('initialHeight'), 'y');
|
403
403
|
var maxWidth = settings.get('maxWidth');
|
@@ -983,7 +983,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/<
|
|
983
983
|
return;
|
984
984
|
}
|
985
985
|
|
986
|
-
// A small pause because some browsers will
|
986
|
+
// A small pause because some browsers will occasionally report a
|
987
987
|
// img.width and img.height of zero immediately after the img.onload fires
|
988
988
|
setTimeout(function(){
|
989
989
|
var percent;
|
@@ -1236,7 +1236,7 @@ u;this.oApi._fnAddColumn=y;this.oApi._fnColumnOptions=C;this.oApi._fnAddData=w;t
|
|
1236
1236
|
Q;this.oApi._fnFilterCreateSearch=fa;this.oApi._fnDataToSearch=ga;this.oApi._fnSort=O;this.oApi._fnSortAttachListener=$;this.oApi._fnSortingClasses=W;this.oApi._fnFeatureHtmlPaginate=wa;this.oApi._fnPageChange=Ba;this.oApi._fnFeatureHtmlInfo=va;this.oApi._fnUpdateInfo=Ca;this.oApi._fnFeatureHtmlLength=ra;this.oApi._fnFeatureHtmlProcessing=ta;this.oApi._fnProcessingDisplay=K;this.oApi._fnVisibleToColumnIndex=da;this.oApi._fnColumnIndexToVisible=N;this.oApi._fnNodeToDataIndex=R;this.oApi._fnVisbleColumns=
|
1237
1237
|
T;this.oApi._fnCalculateEnd=F;this.oApi._fnConvertToWidth=Da;this.oApi._fnCalculateColumnWidths=ea;this.oApi._fnScrollingWidthAdjust=ia;this.oApi._fnGetWidestNode=Ea;this.oApi._fnGetMaxLenString=Fa;this.oApi._fnStringToCss=v;this.oApi._fnArrayCmp=La;this.oApi._fnDetectType=Z;this.oApi._fnSettingsFromNode=B;this.oApi._fnGetDataMaster=V;this.oApi._fnGetTrNodes=S;this.oApi._fnGetTdNodes=X;this.oApi._fnEscapeRegex=ha;this.oApi._fnDeleteIndex=ja;this.oApi._fnReOrderIndex=qa;this.oApi._fnColumnOrdering=
|
1238
1238
|
aa;this.oApi._fnLog=J;this.oApi._fnClearTable=ba;this.oApi._fnSaveState=Ga;this.oApi._fnLoadState=Ia;this.oApi._fnCreateCookie=Ha;this.oApi._fnReadCookie=ka;this.oApi._fnGetUniqueThs=ca;this.oApi._fnScrollBarWidth=Ja;this.oApi._fnApplyToChildren=M;this.oApi._fnMap=n;var Ka=this;return this.each(function(){var a=0,b,c,d,f;a=0;for(b=E.length;a<b;a++){if(E[a].nTable==this)if(typeof g=="undefined"||typeof g.bRetrieve!="undefined"&&g.bRetrieve===true)return E[a].oInstance;else if(typeof g.bDestroy!="undefined"&&
|
1239
|
-
g.bDestroy===true){E[a].oInstance.fnDestroy();break}else{J(E[a],0,"Cannot reinitialise DataTable.\n\nTo retrieve the DataTables object for this table, please pass either no arguments to the dataTable() function, or set bRetrieve to true. Alternatively, to
|
1239
|
+
g.bDestroy===true){E[a].oInstance.fnDestroy();break}else{J(E[a],0,"Cannot reinitialise DataTable.\n\nTo retrieve the DataTables object for this table, please pass either no arguments to the dataTable() function, or set bRetrieve to true. Alternatively, to destroy the old table and create a new one, set bDestroy to true (note that a lot of changes to the configuration can be made through the API which is usually much faster).");return}if(E[a].sTableId!==""&&E[a].sTableId==this.getAttribute("id")){E.splice(a,
|
1240
1240
|
1);break}}var e=new l;E.push(e);var i=false,h=false;a=this.getAttribute("id");if(a!==null){e.sTableId=a;e.sInstance=a}else e.sInstance=m._oExternConfig.iNextUnique++;e.oInstance=Ka;e.nTable=this;e.oApi=Ka.oApi;if(typeof g!="undefined"&&g!==null){e.oInit=g;n(e.oFeatures,g,"bPaginate");n(e.oFeatures,g,"bLengthChange");n(e.oFeatures,g,"bFilter");n(e.oFeatures,g,"bSort");n(e.oFeatures,g,"bInfo");n(e.oFeatures,g,"bProcessing");n(e.oFeatures,g,"bAutoWidth");n(e.oFeatures,g,"bSortClasses");n(e.oFeatures,
|
1241
1241
|
g,"bServerSide");n(e.oScroll,g,"sScrollX","sX");n(e.oScroll,g,"sScrollXInner","sXInner");n(e.oScroll,g,"sScrollY","sY");n(e.oScroll,g,"bScrollCollapse","bCollapse");n(e,g,"asStripClasses");n(e,g,"fnRowCallback");n(e,g,"fnHeaderCallback");n(e,g,"fnFooterCallback");n(e,g,"fnInitComplete");n(e,g,"fnServerData");n(e,g,"fnFormatNumber");n(e,g,"aaSorting");n(e,g,"aaSortingFixed");n(e,g,"aLengthMenu");n(e,g,"sPaginationType");n(e,g,"sAjaxSource");n(e,g,"iCookieDuration");n(e,g,"sCookiePrefix");n(e,g,"sDom");
|
1242
1242
|
n(e,g,"oSearch","oPreviousSearch");n(e,g,"aoSearchCols","aoPreSearchCols");n(e,g,"iDisplayLength","_iDisplayLength");n(e,g,"bJQueryUI","bJUI");typeof g.fnDrawCallback=="function"&&e.aoDrawCallback.push({fn:g.fnDrawCallback,sName:"user"});e.oFeatures.bServerSide&&e.oFeatures.bSort&&e.oFeatures.bSortClasses&&e.aoDrawCallback.push({fn:W,sName:"server_side_sort_classes"});if(typeof g.bJQueryUI!="undefined"&&g.bJQueryUI){e.oClasses=m.oJUIClasses;if(typeof g.sDom=="undefined")e.sDom='<"H"lfr>t<"F"ip>'}if(e.oScroll.sX!==
|
data/roadmap.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Future Roadmap
|
2
|
+
|
3
|
+
### Research Alternative Redis formats
|
4
|
+
|
5
|
+
- Look at alternative storage formats for Redis
|
6
|
+
- [redis bitmaps](http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/)
|
7
|
+
- [redis bitfield](https://stackoverflow.com/questions/47100606/optimal-way-to-store-array-of-integers-in-redis-database)
|
8
|
+
- Add support for [zadd](http://redis.io/topics/data-types-intro) so one could determine single call versus multiple calls on a line, letting us determine the most executed code in production.
|
9
|
+
|
10
|
+
### Coverband Future...
|
11
|
+
|
12
|
+
Will be the fully modern release that drops maintenance legacy support in favor of increased performance, ease of use, and maintainability.
|
13
|
+
|
14
|
+
- Release will be aimed as significantly simplifying ease of use
|
15
|
+
- near zero config setup for Rails apps
|
16
|
+
- add built-in support for easy loading via Railties
|
17
|
+
- built in support for activejob, sidekiq, and other common frameworks
|
18
|
+
- reduced configuration options
|
19
|
+
- support oneshot
|
20
|
+
- drop middleware figure out a way to kick off background without middelware
|
21
|
+
- options on reporting
|
22
|
+
- background reporting
|
23
|
+
- or middleware reporting
|
24
|
+
- Support for file versions
|
25
|
+
- md5 or release tags
|
26
|
+
- add coverage timerange support
|
27
|
+
- Drop Simplecov dependency
|
28
|
+
- improved web reporting
|
29
|
+
- lists current config options
|
30
|
+
- eventually allow updating remote config
|
31
|
+
- full theming
|
32
|
+
- list redis data dump for debugging
|
33
|
+
- additional adapters: Memcache, S3, and ActiveRecord
|
34
|
+
- add articles / podcasts like prontos readme https://github.com/prontolabs/pronto
|
35
|
+
- Add detailed Gem usage report, if we collect and send gem usage we can give percentage of gem code used, which should help application developers know when to remove gem dependencies (0%) or perhaps inline single methods for little usage (using <= 5%) for example.
|
36
|
+
- add meta data information first seen last recorded to the coverage report views (probably need to drop simplecov for that).
|
37
|
+
- more details in this issue: https://github.com/danmayer/coverband/issues/118
|
38
|
+
- Make good video on setup, install, usage
|
39
|
+
- See if we can add support for views / templates
|
40
|
+
- using this technique https://github.com/ioquatix/covered
|
41
|
+
- Better default grouping (could use groups features for gems for rails controllers, models, lib, etc)
|
42
|
+
- Improved logging for easier debugging and development
|
43
|
+
- drop the verbose mode and better support standard logger levels
|
44
|
+
- Possibly setup a build assets system
|
45
|
+
- my JS rules expanded the compressed JS at the top of application.js, basically we want to stitch together JS
|
46
|
+
- I guess we could also load multiple JS files as most of the JS is just default compressed JS and a tiny amount of actual app JS.
|
47
|
+
- lazy load for Coverband results
|
48
|
+
- view layer file coverage
|
49
|
+
- move all code to work with relative paths leaving only stdlib Coverage working on full paths
|
50
|
+
- add gem_safe_lists to track only some gems
|
51
|
+
- add gem_details_safe list to report on details on some gems
|
52
|
+
- - display gems that are in loaded with 0 coverage, thanks @kbaum
|
53
|
+
|
54
|
+
# Alpha / Beta / Release Candidates
|
55
|
+
|
56
|
+
### Coverband 5.?.?
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path("../../test_helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
class AdaptersNullStoreTest < Minitest::Test
|
6
|
+
def test_covered_lines_when_no_file
|
7
|
+
@store = Coverband::Adapters::NullStore.new("")
|
8
|
+
expected = {}
|
9
|
+
assert_equal expected, @store.coverage
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "Coverband::Adapters::NullStore" do
|
13
|
+
def setup
|
14
|
+
super
|
15
|
+
@store = Coverband::Adapters::NullStore.new(@test_file_path)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_coverage
|
19
|
+
assert_equal @store.coverage, {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_covered_lines_when_null
|
23
|
+
assert_nil @store.coverage["none.rb"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_covered_files
|
27
|
+
assert_equal @store.covered_files.include?("dog.rb"), false
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_clear
|
31
|
+
assert_nil @store.clear!
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_save_report
|
35
|
+
@store.send(:save_report, "cat.rb" => [0, 1])
|
36
|
+
assert_equal @store.coverage, {}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -10,7 +10,7 @@ class BaseTest < Minitest::Test
|
|
10
10
|
Coverband.configure do |config|
|
11
11
|
config.root = Dir.pwd
|
12
12
|
config.root_paths = ["/app_path/"]
|
13
|
-
config.ignore = ["config/
|
13
|
+
config.ignore = ["config/environments"]
|
14
14
|
config.reporter = "std_out"
|
15
15
|
config.store = Coverband::Adapters::RedisStore.new(Coverband::Test.redis, redis_namespace: "coverband_test")
|
16
16
|
end
|
@@ -18,7 +18,7 @@ class BaseTest < Minitest::Test
|
|
18
18
|
|
19
19
|
test "ignore works with equal" do
|
20
20
|
Coverband::Collectors::Coverage.instance.reset_instance
|
21
|
-
expected = ["vendor/", ".erb$", ".slim$", "/tmp", "internal:prelude", "db/schema.rb", "config/
|
21
|
+
expected = ["vendor/", ".erb$", ".slim$", "/tmp", "internal:prelude", "db/schema.rb", "config/environments"]
|
22
22
|
assert_equal expected, Coverband.configuration.ignore
|
23
23
|
end
|
24
24
|
|
@@ -33,7 +33,7 @@ class BaseTest < Minitest::Test
|
|
33
33
|
"/tmp",
|
34
34
|
"internal:prelude",
|
35
35
|
"db/schema.rb",
|
36
|
-
"config/
|
36
|
+
"config/environments",
|
37
37
|
"config/initializers"]
|
38
38
|
assert_equal expected, Coverband.configuration.ignore
|
39
39
|
end
|
@@ -47,7 +47,7 @@ class BaseTest < Minitest::Test
|
|
47
47
|
Coverband::Collectors::Coverage.instance.reset_instance
|
48
48
|
current_paths = Coverband.configuration.root_paths.dup
|
49
49
|
# verify previous bug fix
|
50
|
-
# it would extend the root_paths instance variable on each
|
50
|
+
# it would extend the root_paths instance variable on each invocation
|
51
51
|
Coverband.configuration.all_root_paths
|
52
52
|
Coverband.configuration.all_root_paths
|
53
53
|
assert_equal current_paths, Coverband.configuration.root_paths
|
@@ -103,7 +103,7 @@ class BaseTest < Minitest::Test
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
|
-
test "store
|
106
|
+
test "store doesn't raises when api key and redis_url" do
|
107
107
|
Coverband::Collectors::Coverage.instance.reset_instance
|
108
108
|
Coverband.configuration.reset
|
109
109
|
Coverband.configure do |config|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path("../../test_helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
if defined?(RubyVM::AbstractSyntaxTree)
|
6
|
+
require "coverband/utils/dead_methods"
|
7
|
+
module Coverband
|
8
|
+
module Utils
|
9
|
+
class DeadMethodsTest < Minitest::Test
|
10
|
+
attr_accessor :coverband
|
11
|
+
|
12
|
+
def setup
|
13
|
+
super
|
14
|
+
@coverband = Coverband::Collectors::Coverage.instance
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_dog_dead_methods
|
18
|
+
file_path = require_unique_file
|
19
|
+
coverage = [nil, nil, 1, 1, 0, nil, nil]
|
20
|
+
dead_methods =
|
21
|
+
DeadMethods.scan(file_path: file_path, coverage: coverage)
|
22
|
+
assert_equal(1, dead_methods.length)
|
23
|
+
dead_method = dead_methods.first
|
24
|
+
assert_equal(4, dead_method.first_line_number)
|
25
|
+
assert_equal(6, dead_method.last_line_number)
|
26
|
+
assert_equal(file_path, dead_method.file_path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_all_dead_methods
|
30
|
+
require_unique_file
|
31
|
+
@coverband.report_coverage
|
32
|
+
dead_methods = DeadMethods.scan_all
|
33
|
+
dead_method = dead_methods.find { |method| method.class_name == :Dog }
|
34
|
+
assert(dead_method)
|
35
|
+
assert_equal(4, dead_method.first_line_number)
|
36
|
+
assert_equal(6, dead_method.last_line_number)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_output_all
|
40
|
+
require_unique_file
|
41
|
+
@coverband.report_coverage
|
42
|
+
DeadMethods.output_all
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_dog_methods_not_dead
|
46
|
+
file = require_unique_file
|
47
|
+
coverage = [nil, nil, 1, 1, 1, nil, nil]
|
48
|
+
assert_empty(DeadMethods.scan(file_path: file, coverage: coverage))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|