coverband 6.0.3.rc.3 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -6
- data/.github/workflows/main.yml +1 -1
- data/README.md +25 -1
- data/changes.md +18 -4
- data/coverband.gemspec +6 -4
- data/lib/coverband/adapters/hash_redis_store.rb +62 -47
- data/lib/coverband/adapters/memcached_store.rb +89 -0
- data/lib/coverband/collectors/route_tracker.rb +9 -6
- data/lib/coverband/configuration.rb +31 -10
- data/lib/coverband/reporters/json_report.rb +21 -9
- data/lib/coverband/reporters/web.rb +12 -4
- data/lib/coverband/utils/html_formatter.rb +5 -11
- data/lib/coverband/utils/results.rb +2 -0
- data/lib/coverband/utils/source_file.rb +17 -2
- data/lib/coverband/version.rb +1 -1
- data/lib/coverband.rb +2 -18
- data/lua/lib/persist-coverage.lua +3 -0
- data/public/application.css +24 -1
- data/public/application.js +73 -87
- data/public/dependencies.js +3 -3
- data/test/coverband/adapters/hash_redis_store_test.rb +16 -14
- data/test/coverband/collectors/route_tracker_test.rb +41 -2
- data/test/coverband/reporters/json_test.rb +1 -1
- data/test/coverband/utils/results_test.rb +17 -2
- data/views/source_file.erb +1 -0
- metadata +12 -13
- data/lib/coverband/reporters/web_pager.rb +0 -28
- data/views/source_file_loader.erb +0 -7
@@ -112,11 +112,16 @@ module Coverband
|
|
112
112
|
def index
|
113
113
|
notice = "<strong>Notice:</strong> #{Rack::Utils.escape_html(request.params["notice"])}<br/>"
|
114
114
|
notice = request.params["notice"] ? notice : ""
|
115
|
-
|
115
|
+
page = (request.params["page"] || 1).to_i
|
116
|
+
options = {
|
116
117
|
static: false,
|
117
118
|
base_path: base_path,
|
118
119
|
notice: notice,
|
119
|
-
open_report: false
|
120
|
+
open_report: false
|
121
|
+
}
|
122
|
+
options[:page] = page if Coverband.configuration.paged_reporting
|
123
|
+
Coverband::Reporters::HTMLReport.new(Coverband.configuration.store,
|
124
|
+
options).report
|
120
125
|
end
|
121
126
|
|
122
127
|
def json
|
@@ -136,16 +141,19 @@ module Coverband
|
|
136
141
|
end
|
137
142
|
|
138
143
|
def settings
|
144
|
+
return "" if Coverband.configuration.hide_settings
|
139
145
|
Coverband::Utils::HTMLFormatter.new(nil, base_path: base_path).format_settings!
|
140
146
|
end
|
141
147
|
|
142
148
|
def display_abstract_tracker(tracker)
|
143
149
|
notice = "<strong>Notice:</strong> #{Rack::Utils.escape_html(request.params["notice"])}<br/>"
|
144
150
|
notice = request.params["notice"] ? notice : ""
|
145
|
-
|
151
|
+
options = {
|
146
152
|
tracker: tracker,
|
147
153
|
notice: notice,
|
148
|
-
base_path: base_path
|
154
|
+
base_path: base_path
|
155
|
+
}
|
156
|
+
Coverband::Utils::HTMLFormatter.new(nil, options).format_abstract_tracker!
|
149
157
|
end
|
150
158
|
|
151
159
|
def view_tracker_data
|
@@ -117,13 +117,6 @@ module Coverband
|
|
117
117
|
puts "Encoding error file:#{source_file.filename} Coverband/ERB error #{e.message}."
|
118
118
|
end
|
119
119
|
|
120
|
-
# Returns the html to ajax load a given source_file
|
121
|
-
def formatted_source_file_loader(result, source_file)
|
122
|
-
template("source_file_loader").result(binding)
|
123
|
-
rescue Encoding::CompatibilityError => e
|
124
|
-
puts "Encoding error file:#{source_file.filename} Coverband/ERB error #{e.message}."
|
125
|
-
end
|
126
|
-
|
127
120
|
# Returns a table containing the given source files
|
128
121
|
def formatted_file_list(title, result, source_files, options = {})
|
129
122
|
title_id = title.gsub(/^[^a-zA-Z]+/, "").gsub(/[^a-zA-Z0-9\-\_]/, "")
|
@@ -162,11 +155,11 @@ module Coverband
|
|
162
155
|
Digest::SHA1.hexdigest(source_file.filename)
|
163
156
|
end
|
164
157
|
|
165
|
-
def timeago(time)
|
166
|
-
if time
|
158
|
+
def timeago(time, err_msg = "Not Available")
|
159
|
+
if time.respond_to?(:iso8601)
|
167
160
|
"<abbr class=\"timeago\" title=\"#{time.iso8601}\">#{time.iso8601}</abbr>"
|
168
161
|
else
|
169
|
-
|
162
|
+
err_msg
|
170
163
|
end
|
171
164
|
end
|
172
165
|
|
@@ -175,7 +168,8 @@ module Coverband
|
|
175
168
|
end
|
176
169
|
|
177
170
|
def link_to_source_file(source_file)
|
178
|
-
|
171
|
+
data_loader_url = "#{base_path}load_file_details?filename=#{source_file.filename}"
|
172
|
+
%(<a href="##{id source_file}" class="src_link" title="#{shortened_filename source_file}" data-loader-url="#{data_loader_url}" onclick="src_link_click(this)">#{shortened_filename source_file}</a>)
|
179
173
|
end
|
180
174
|
end
|
181
175
|
end
|
@@ -44,6 +44,8 @@ module Coverband
|
|
44
44
|
eager_file = get_eager_file(source_file)
|
45
45
|
runtime_file = get_runtime_file(source_file)
|
46
46
|
|
47
|
+
return 0 unless runtime_file
|
48
|
+
|
47
49
|
return runtime_file.covered_lines_count unless eager_file
|
48
50
|
|
49
51
|
eager_file.relevant_lines - eager_file.covered_lines_count
|
@@ -25,13 +25,15 @@ module Coverband
|
|
25
25
|
attr_reader :coverage
|
26
26
|
# Whether this line was skipped
|
27
27
|
attr_reader :skipped
|
28
|
+
# The coverage data posted time for this line: either nil (never), nil (missed) or Time instance (last posted)
|
29
|
+
attr_reader :coverage_posted
|
28
30
|
|
29
31
|
# Lets grab some fancy aliases, shall we?
|
30
32
|
alias source src
|
31
33
|
alias line line_number
|
32
34
|
alias number line_number
|
33
35
|
|
34
|
-
def initialize(src, line_number, coverage)
|
36
|
+
def initialize(src, line_number, coverage, coverage_posted = nil)
|
35
37
|
raise ArgumentError, "Only String accepted for source" unless src.is_a?(String)
|
36
38
|
raise ArgumentError, "Only Integer accepted for line_number" unless line_number.is_a?(Integer)
|
37
39
|
raise ArgumentError, "Only Integer and nil accepted for coverage" unless coverage.is_a?(Integer) || coverage.nil?
|
@@ -40,6 +42,7 @@ module Coverband
|
|
40
42
|
@line_number = line_number
|
41
43
|
@coverage = coverage
|
42
44
|
@skipped = false
|
45
|
+
@coverage_posted = coverage_posted
|
43
46
|
end
|
44
47
|
|
45
48
|
# Returns true if this is a line that should have been covered, but was not
|
@@ -82,6 +85,8 @@ module Coverband
|
|
82
85
|
attr_reader :filename
|
83
86
|
# The array of coverage data received from the Coverage.result
|
84
87
|
attr_reader :coverage
|
88
|
+
# The array of coverage timedata received from the Coverage.result
|
89
|
+
attr_reader :coverage_posted
|
85
90
|
|
86
91
|
# the date this version of the file first started to record coverage
|
87
92
|
attr_reader :first_updated_at
|
@@ -96,6 +101,7 @@ module Coverband
|
|
96
101
|
@runtime_relavant_lines = nil
|
97
102
|
if file_data.is_a?(Hash)
|
98
103
|
@coverage = file_data["data"]
|
104
|
+
@coverage_posted = file_data["timedata"] || [] # NOTE: only implement timedata for HashRedisStore
|
99
105
|
@first_updated_at = @last_updated_at = NOT_AVAILABLE
|
100
106
|
@first_updated_at = Time.at(file_data["first_updated_at"]) if file_data["first_updated_at"]
|
101
107
|
@last_updated_at = Time.at(file_data["last_updated_at"]) if file_data["last_updated_at"]
|
@@ -139,7 +145,12 @@ module Coverband
|
|
139
145
|
coverage_exceeding_source_warn if coverage.size > src.size
|
140
146
|
|
141
147
|
lines = src.map.with_index(1) { |src, i|
|
142
|
-
Coverband::Utils::SourceFile::Line.new(
|
148
|
+
Coverband::Utils::SourceFile::Line.new(
|
149
|
+
src,
|
150
|
+
i,
|
151
|
+
never_loaded ? 0 : coverage[i - 1],
|
152
|
+
(never_loaded || !coverage_posted.is_a?(Array)) ? nil : coverage_posted[i - 1]
|
153
|
+
)
|
143
154
|
}
|
144
155
|
|
145
156
|
process_skipped_lines(lines)
|
@@ -200,6 +211,10 @@ module Coverband
|
|
200
211
|
lines[index]&.coverage
|
201
212
|
end
|
202
213
|
|
214
|
+
def line_coverage_posted(index)
|
215
|
+
lines[index]&.coverage_posted
|
216
|
+
end
|
217
|
+
|
203
218
|
# Returns all lines that should have been, but were not covered
|
204
219
|
# as instances of SimpleCov::SourceFile::Line
|
205
220
|
def missed_lines
|
data/lib/coverband/version.rb
CHANGED
data/lib/coverband.rb
CHANGED
@@ -91,8 +91,8 @@ module Coverband
|
|
91
91
|
coverage_instance.eager_loading!
|
92
92
|
end
|
93
93
|
|
94
|
-
def self.eager_loading_coverage(
|
95
|
-
coverage_instance.eager_loading(
|
94
|
+
def self.eager_loading_coverage(...)
|
95
|
+
coverage_instance.eager_loading(...)
|
96
96
|
end
|
97
97
|
|
98
98
|
def self.runtime_coverage!
|
@@ -130,7 +130,6 @@ module Coverband
|
|
130
130
|
###
|
131
131
|
def initialize
|
132
132
|
require "coverband/reporters/web"
|
133
|
-
require "coverband/reporters/web_pager"
|
134
133
|
require "coverband/utils/html_formatter"
|
135
134
|
require "coverband/utils/result"
|
136
135
|
require "coverband/utils/file_list"
|
@@ -148,19 +147,4 @@ module Coverband
|
|
148
147
|
end
|
149
148
|
end
|
150
149
|
end
|
151
|
-
|
152
|
-
module Reporters
|
153
|
-
class WebPager < Web
|
154
|
-
def initialize
|
155
|
-
require "coverband/reporters/web"
|
156
|
-
require "coverband/reporters/web_pager"
|
157
|
-
super
|
158
|
-
end
|
159
|
-
|
160
|
-
def self.call(env)
|
161
|
-
@app ||= new
|
162
|
-
@app.call(env)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
150
|
end
|
@@ -21,6 +21,9 @@ for _, file_data in ipairs(files_data) do
|
|
21
21
|
redis.call('HSETNX', hash_key, 'first_updated_at', first_updated_at)
|
22
22
|
for line, coverage in pairs(file_data.coverage) do
|
23
23
|
redis.call("HINCRBY", hash_key, line, coverage)
|
24
|
+
if coverage > 0 then
|
25
|
+
redis.call("HSET", hash_key, line .. "_last_posted", ARGV[1])
|
26
|
+
end
|
24
27
|
end
|
25
28
|
if ttl and ttl ~= cjson.null then
|
26
29
|
redis.call("EXPIRE", hash_key, ttl)
|
data/public/application.css
CHANGED
@@ -687,9 +687,17 @@ a.src_link {
|
|
687
687
|
background: url("./magnify.png") no-repeat left 50%;
|
688
688
|
padding-left: 18px; }
|
689
689
|
|
690
|
+
a.src_link.strong {
|
691
|
+
font-weight: bold;
|
692
|
+
}
|
693
|
+
|
690
694
|
.red a.src_link {
|
691
695
|
color: #990000;
|
692
|
-
|
696
|
+
}
|
697
|
+
|
698
|
+
a.src_link.red {
|
699
|
+
color: #990000;
|
700
|
+
}
|
693
701
|
|
694
702
|
tr, td {
|
695
703
|
margin: 0;
|
@@ -817,6 +825,21 @@ td {
|
|
817
825
|
.red {
|
818
826
|
color: #990000; }
|
819
827
|
|
828
|
+
span.red {
|
829
|
+
color: #990000; }
|
830
|
+
|
831
|
+
td:has(> span.red) {
|
832
|
+
color: #990000;
|
833
|
+
}
|
834
|
+
|
835
|
+
td:has(> span.yellow) {
|
836
|
+
color: #ddaa00;
|
837
|
+
}
|
838
|
+
|
839
|
+
td:has(> span.green) {
|
840
|
+
color: #009900;
|
841
|
+
}
|
842
|
+
|
820
843
|
.yellow {
|
821
844
|
color: #ddaa00; }
|
822
845
|
|
data/public/application.js
CHANGED
@@ -16,7 +16,7 @@ $(document).ready(function() {
|
|
16
16
|
});
|
17
17
|
|
18
18
|
// Configuration for fancy sortable tables for source file groups
|
19
|
-
|
19
|
+
var tableOptions = {
|
20
20
|
aaSorting: [[1, "asc"]],
|
21
21
|
bPaginate: false,
|
22
22
|
bJQueryUI: true,
|
@@ -30,19 +30,26 @@ $(document).ready(function() {
|
|
30
30
|
null,
|
31
31
|
null,
|
32
32
|
null
|
33
|
-
]
|
34
|
-
}
|
33
|
+
],
|
34
|
+
}
|
35
|
+
|
36
|
+
$(".file_list").dataTable(tableOptions);
|
35
37
|
|
36
|
-
// TODO: add support for searching
|
37
|
-
// hmm should I just use manual paging? or load more...
|
38
|
+
// TODO: add support for searching on server side
|
38
39
|
// best docs on our version of datatables 1.7 https://datatables.net/beta/1.7/examples/server_side/server_side.html
|
39
|
-
// TODO: fix bug where we hardcoded /coverage we need to pull it from the path it is mounted on
|
40
40
|
if ($(".file_list.unsorted").length == 1) {
|
41
|
-
|
41
|
+
$(".dataTables_empty").html("loading...");
|
42
42
|
var total_rows = 0;
|
43
43
|
var page = 1;
|
44
|
+
var all_data = [];
|
45
|
+
|
46
|
+
// load and render page content before we start the loop
|
47
|
+
// perhaps move this into a datatable ready event
|
48
|
+
$(".dataTables_empty").html("loading...");
|
49
|
+
setTimeout(() => {
|
50
|
+
get_page(page);
|
51
|
+
}, 1200);
|
44
52
|
|
45
|
-
// write a function to get a page of data and add it to the table
|
46
53
|
function get_page(page) {
|
47
54
|
$.ajax({
|
48
55
|
url: `${$(".file_list").data("coverageurl")}/report_json?page=${page}`,
|
@@ -50,96 +57,56 @@ $(document).ready(function() {
|
|
50
57
|
dataType: 'json',
|
51
58
|
success: function(data) {
|
52
59
|
total_rows = data["iTotalRecords"];
|
53
|
-
|
54
|
-
|
55
|
-
// this 250 at the moment is synced to the 250 in the hash redis store
|
56
|
-
current_rows += 250; //data["aaData"].length;
|
57
|
-
console.log(current_rows);
|
58
|
-
console.log(total_rows);
|
59
|
-
$(".file_list.unsorted").dataTable().fnAddData(data["aaData"]);
|
60
|
+
all_data = all_data.concat(data["aaData"]);
|
61
|
+
$(".dataTables_empty").html("loading... on " + all_data.length + " of " + total_rows + " files");
|
60
62
|
page += 1;
|
63
|
+
;
|
61
64
|
// the page less than 100 is to stop infinite loop in case of folks never clearing out old coverage reports
|
62
|
-
if (page <
|
63
|
-
|
65
|
+
if (page < 50 && all_data.length < total_rows) {
|
66
|
+
setTimeout(() => {
|
67
|
+
get_page(page);
|
68
|
+
}, 10);
|
69
|
+
} else {
|
70
|
+
$(".file_list.unsorted").dataTable().fnAddData(all_data);
|
71
|
+
// allow rendering to complete before we click the anchor
|
72
|
+
setTimeout(() => {
|
73
|
+
if (window.auto_click_anchor && $(window.auto_click_anchor).length > 0) {
|
74
|
+
$(window.auto_click_anchor).click();
|
75
|
+
}
|
76
|
+
}, 50)
|
64
77
|
}
|
65
78
|
}
|
66
79
|
});
|
67
80
|
}
|
68
|
-
get_page(page);
|
69
81
|
}
|
70
82
|
|
71
|
-
|
72
|
-
// Syntax highlight all files up front - deactivated
|
73
|
-
// $('.source_table pre code').each(function(i, e) {hljs.highlightBlock(e, ' ')});
|
74
83
|
src_link_click = (trigger_element) => {
|
75
|
-
// Get the source file element that corresponds to the clicked element
|
76
|
-
var source_table = $(".shared_source_table");
|
77
84
|
var loader_url = $(trigger_element).attr("data-loader-url");
|
85
|
+
auto_click_anchor = null;
|
78
86
|
$(trigger_element).colorbox(jQuery.extend(colorbox_options, { href: loader_url}));
|
79
|
-
|
80
|
-
// If not highlighted yet, do it!
|
81
|
-
if (!source_table.hasClass("highlighted")) {
|
82
|
-
source_table.find("pre code").each(function(i, e) {
|
83
|
-
hljs.highlightBlock(e, " ");
|
84
|
-
});
|
85
|
-
source_table.addClass("highlighted");
|
86
|
-
}
|
87
87
|
};
|
88
|
-
window.src_link_click = src_link_click;
|
89
88
|
|
90
|
-
// Syntax highlight source files on first toggle of the file view popup
|
91
|
-
$("a.src_link").click(src_link_click(this));
|
92
|
-
|
93
|
-
var prev_anchor;
|
94
|
-
var curr_anchor;
|
95
89
|
var colorbox_options = {
|
96
|
-
open: true,
|
97
90
|
transition: "none",
|
98
|
-
// inline: true,
|
99
91
|
opacity: 1,
|
100
92
|
width: "95%",
|
101
93
|
height: "95%",
|
102
94
|
onLoad: function() {
|
103
|
-
//
|
104
|
-
|
105
|
-
|
106
|
-
|
95
|
+
// If not highlighted yet, do it!
|
96
|
+
var source_table = $(".shared_source_table");
|
97
|
+
if (!source_table.hasClass("highlighted")) {
|
98
|
+
source_table.find("pre code").each(function(i, e) {
|
99
|
+
hljs.highlightBlock(e, " ");
|
100
|
+
});
|
101
|
+
source_table.addClass("highlighted");
|
102
|
+
}
|
103
|
+
window.location.hash = this.href.split("#")[1];
|
107
104
|
},
|
108
105
|
onCleanup: function() {
|
109
|
-
|
110
|
-
$('a[href="#' + prev_anchor + '"]').click();
|
111
|
-
curr_anchor = prev_anchor;
|
112
|
-
} else {
|
113
|
-
$(".group_tabs a:first").click();
|
114
|
-
prev_anchor = curr_anchor;
|
115
|
-
curr_anchor = $(".group_tabs a:first").attr("href");
|
116
|
-
}
|
117
|
-
window.location.hash = curr_anchor;
|
106
|
+
window.location.hash = $(".group_tabs a:first").attr("href");
|
118
107
|
}
|
119
108
|
}
|
120
109
|
|
121
|
-
src_link_colorbox = (trigger_element) => {
|
122
|
-
$(trigger_element).colorbox(colorbox_options);
|
123
|
-
};
|
124
|
-
window.src_link_colorbox = src_link_colorbox;
|
125
|
-
|
126
|
-
// Set-up of popup for source file views
|
127
|
-
// TODO: drop the static source view even for not paged coverband, then delete all this
|
128
|
-
$("a.src_link").colorbox(colorbox_options);
|
129
|
-
|
130
|
-
window.onpopstate = function(event) {
|
131
|
-
if (location.hash.substring(0, 2) == "#_") {
|
132
|
-
$.colorbox.close();
|
133
|
-
curr_anchor = jQuery.url.attr("anchor");
|
134
|
-
} else {
|
135
|
-
if ($("#colorbox").is(":hidden")) {
|
136
|
-
console.log("pop");
|
137
|
-
// $('a.src_link[href="' + location.hash + '"]').colorbox({ open: true });
|
138
|
-
$('.shared_source_table').colorbox({ open: true });
|
139
|
-
}
|
140
|
-
}
|
141
|
-
};
|
142
|
-
|
143
110
|
// Hide src files and file list container after load
|
144
111
|
$(".source_files").hide();
|
145
112
|
$(".file_list_container").hide();
|
@@ -157,15 +124,20 @@ $(document).ready(function() {
|
|
157
124
|
.find(".covered_percent")
|
158
125
|
.first()
|
159
126
|
.html();
|
127
|
+
if (covered_percent) {
|
128
|
+
covered_percent = "(" + covered_percent + ")";
|
129
|
+
} else {
|
130
|
+
covered_percent = "";
|
131
|
+
}
|
160
132
|
|
161
133
|
$(".group_tabs").append(
|
162
134
|
'<li><a href="#' +
|
163
135
|
container_id +
|
164
136
|
'">' +
|
165
137
|
group_name +
|
166
|
-
"
|
138
|
+
" " +
|
167
139
|
covered_percent +
|
168
|
-
"
|
140
|
+
"</a></li>"
|
169
141
|
);
|
170
142
|
});
|
171
143
|
|
@@ -197,15 +169,26 @@ $(document).ready(function() {
|
|
197
169
|
.addClass("active");
|
198
170
|
}
|
199
171
|
$(".file_list_container").hide();
|
200
|
-
$(".file_list_container" + $(this).attr("href")).show()
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
.
|
205
|
-
|
206
|
-
|
172
|
+
$(".file_list_container" + $(this).attr("href")).show(function() {
|
173
|
+
// If we have an anchor to click, click it
|
174
|
+
// allow rendering to complete before we click the anchor
|
175
|
+
setTimeout(() => {
|
176
|
+
if (window.auto_click_anchor && $(window.auto_click_anchor).length > 0) {
|
177
|
+
$(window.auto_click_anchor).click();
|
178
|
+
}
|
179
|
+
}, 30);
|
180
|
+
});
|
181
|
+
// Below the #_ is a hack to show we have processed the hash change
|
182
|
+
if (!window.auto_click_anchor) {
|
183
|
+
window.location.href =
|
184
|
+
window.location.href.split("#")[0] +
|
185
|
+
$(this)
|
186
|
+
.attr("href")
|
187
|
+
.replace("#", "#_");
|
188
|
+
}
|
189
|
+
|
207
190
|
// Force favicon reload - otherwise the location change containing anchor would drop the favicon...
|
208
|
-
// Works only on firefox, but still... - Anyone know a better solution to force favicon on local file?
|
191
|
+
// Works only on firefox, but still... - Anyone know a better solution to force favicon on local relative file path?
|
209
192
|
$('link[rel="shortcut icon"]').remove();
|
210
193
|
$("head").append(
|
211
194
|
'<link rel="shortcut icon" type="image/png" href="' +
|
@@ -215,18 +198,21 @@ $(document).ready(function() {
|
|
215
198
|
return false;
|
216
199
|
});
|
217
200
|
|
201
|
+
// The below function handles turning initial anchors in links to navigate to correct tab
|
218
202
|
if (jQuery.url.attr("anchor")) {
|
219
203
|
var anchor = jQuery.url.attr("anchor");
|
220
|
-
// source file hash
|
221
204
|
if (anchor.length == 40) {
|
222
|
-
|
223
|
-
|
205
|
+
// handles deep links to source files
|
206
|
+
window.auto_click_anchor = "a.src_link[href=#" + anchor + "]";
|
207
|
+
$(".group_tabs a:first").click();
|
224
208
|
} else {
|
209
|
+
// handles a # anchor that needs to be processed into a #_ completed action
|
225
210
|
if ($(".group_tabs a." + anchor.replace("_", "")).length > 0) {
|
226
211
|
$(".group_tabs a." + anchor.replace("_", "")).click();
|
227
212
|
}
|
228
213
|
}
|
229
214
|
} else {
|
215
|
+
// No anchor, so click the first navigation tab
|
230
216
|
$(".group_tabs a:first").click();
|
231
217
|
}
|
232
218
|
|
data/public/dependencies.js
CHANGED
@@ -88,7 +88,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/<
|
|
88
88
|
xhrError: "This content failed to load.",
|
89
89
|
imgError: "This image failed to load.",
|
90
90
|
|
91
|
-
//
|
91
|
+
// accessibility
|
92
92
|
returnFocus: true,
|
93
93
|
trapFocus: true,
|
94
94
|
|
@@ -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 intended as a selector (e.g. '#container')
|
107
107
|
return $(this).attr('href');
|
108
108
|
},
|
109
109
|
title: function() {
|
@@ -145,7 +145,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/<
|
|
145
145
|
$prev,
|
146
146
|
$close,
|
147
147
|
$groupControls,
|
148
|
-
$events = $('<a/>'), // $({}) would be
|
148
|
+
$events = $('<a/>'), // $({}) would be preferred, but there is an issue with jQuery 1.4.2
|
149
149
|
|
150
150
|
// Variables for cached values or use across multiple functions
|
151
151
|
settings,
|
@@ -57,7 +57,8 @@ class HashRedisStoreTest < Minitest::Test
|
|
57
57
|
"first_updated_at" => yesterday.to_i,
|
58
58
|
"last_updated_at" => yesterday.to_i,
|
59
59
|
"file_hash" => "abcd",
|
60
|
-
"data" => [0, 1, 2]
|
60
|
+
"data" => [0, 1, 2],
|
61
|
+
"timedata" => [nil, Time.at(yesterday.to_i), Time.at(yesterday.to_i)]
|
61
62
|
},
|
62
63
|
@store.coverage["./dog.rb"]
|
63
64
|
)
|
@@ -65,15 +66,12 @@ class HashRedisStoreTest < Minitest::Test
|
|
65
66
|
@store.save_report(
|
66
67
|
"app_path/dog.rb" => [1, 1, 0]
|
67
68
|
)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
},
|
75
|
-
@store.coverage["./dog.rb"]
|
76
|
-
)
|
69
|
+
|
70
|
+
assert_equal("abcd", @store.coverage["./dog.rb"]["file_hash"])
|
71
|
+
assert_equal(today.to_i, @store.coverage["./dog.rb"]["last_updated_at"])
|
72
|
+
assert_equal(yesterday.to_i, @store.coverage["./dog.rb"]["first_updated_at"])
|
73
|
+
assert_equal([1, 2, 2], @store.coverage["./dog.rb"]["data"])
|
74
|
+
assert_equal([Time.at(today.to_i), Time.at(today.to_i), Time.at(yesterday.to_i)], @store.coverage["./dog.rb"]["timedata"])
|
77
75
|
end
|
78
76
|
|
79
77
|
def test_ttl_set
|
@@ -109,7 +107,8 @@ class HashRedisStoreTest < Minitest::Test
|
|
109
107
|
"first_updated_at" => current_time.to_i,
|
110
108
|
"last_updated_at" => current_time.to_i,
|
111
109
|
"file_hash" => "abcd",
|
112
|
-
"data" => [0, nil, 1, 2]
|
110
|
+
"data" => [0, nil, 1, 2],
|
111
|
+
"timedata" => [nil, nil, Time.at(current_time.to_i), Time.at(current_time.to_i)]
|
113
112
|
}, @store.coverage["./dog.rb"]
|
114
113
|
)
|
115
114
|
assert_equal [1, 2, 0, 1, 5], @store.coverage["./cat.rb"]["data"]
|
@@ -213,7 +212,8 @@ class HashRedisStoreTest < Minitest::Test
|
|
213
212
|
"first_updated_at" => yesterday.to_i,
|
214
213
|
"last_updated_at" => yesterday.to_i,
|
215
214
|
"file_hash" => "abcd",
|
216
|
-
"data" => [0, 1, 2]
|
215
|
+
"data" => [0, 1, 2],
|
216
|
+
"timedata" => [nil, Time.at(yesterday.to_i), Time.at(yesterday.to_i)]
|
217
217
|
},
|
218
218
|
@store.coverage["./dog.rb"]
|
219
219
|
)
|
@@ -225,7 +225,8 @@ class HashRedisStoreTest < Minitest::Test
|
|
225
225
|
"first_updated_at" => yesterday.to_i,
|
226
226
|
"last_updated_at" => yesterday.to_i,
|
227
227
|
"file_hash" => "abcd",
|
228
|
-
"data" => [0, 1, 2]
|
228
|
+
"data" => [0, 1, 2],
|
229
|
+
"timedata" => [nil, Time.at(yesterday.to_i), Time.at(yesterday.to_i)]
|
229
230
|
},
|
230
231
|
@store.coverage["./dog.rb"]
|
231
232
|
)
|
@@ -235,7 +236,8 @@ class HashRedisStoreTest < Minitest::Test
|
|
235
236
|
"first_updated_at" => yesterday.to_i,
|
236
237
|
"last_updated_at" => yesterday.to_i,
|
237
238
|
"file_hash" => "abcd",
|
238
|
-
"data" => [0, 2, 4]
|
239
|
+
"data" => [0, 2, 4],
|
240
|
+
"timedata" => [nil, Time.at(yesterday.to_i), Time.at(yesterday.to_i)]
|
239
241
|
},
|
240
242
|
@store.coverage["./dog.rb"]
|
241
243
|
)
|
@@ -33,14 +33,32 @@ class RouterTrackerTest < Minitest::Test
|
|
33
33
|
tracker = Coverband::Collectors::RouteTracker.new(store: store, roots: "dir")
|
34
34
|
|
35
35
|
payload = {
|
36
|
-
request: Payload.new("path", "GET")
|
36
|
+
request: Payload.new("path", "GET"),
|
37
|
+
status: 302,
|
38
|
+
location: "https://coverband.dev/"
|
37
39
|
}
|
38
40
|
tracker.track_key(payload)
|
39
41
|
tracker.save_report
|
40
42
|
assert_equal [route_hash], tracker.logged_keys
|
41
43
|
end
|
42
44
|
|
43
|
-
test "track
|
45
|
+
test "track redirect routes when track_redirect_routes is false" do
|
46
|
+
Coverband.configuration.track_redirect_routes = false
|
47
|
+
|
48
|
+
store = fake_store
|
49
|
+
tracker = Coverband::Collectors::RouteTracker.new(store: store, roots: "dir")
|
50
|
+
|
51
|
+
payload = {
|
52
|
+
request: Payload.new("path", "GET"),
|
53
|
+
status: 302,
|
54
|
+
location: "https://coverband.dev/"
|
55
|
+
}
|
56
|
+
tracker.track_key(payload)
|
57
|
+
tracker.save_report
|
58
|
+
assert_equal [], tracker.logged_keys
|
59
|
+
end
|
60
|
+
|
61
|
+
test "track controller routes in Rails < 6.1" do
|
44
62
|
store = fake_store
|
45
63
|
route_hash = {controller: "some/controller", action: "index", url_path: nil, verb: "GET"}
|
46
64
|
store.raw_store.expects(:hset).with(tracker_key, route_hash.to_s, anything)
|
@@ -57,6 +75,27 @@ class RouterTrackerTest < Minitest::Test
|
|
57
75
|
assert_equal [route_hash], tracker.logged_keys
|
58
76
|
end
|
59
77
|
|
78
|
+
test "track controller routes in Rails >= 6.1" do
|
79
|
+
store = fake_store
|
80
|
+
route_hash = {controller: "some/controller", action: "index", url_path: nil, verb: "GET"}
|
81
|
+
store.raw_store.expects(:hset).with(tracker_key, route_hash.to_s, anything)
|
82
|
+
tracker = Coverband::Collectors::RouteTracker.new(store: store, roots: "dir")
|
83
|
+
payload = {
|
84
|
+
params: {
|
85
|
+
"controller" => "some/controller",
|
86
|
+
"action" => "index"
|
87
|
+
},
|
88
|
+
controller: "SomeController",
|
89
|
+
action: "index",
|
90
|
+
path: "path",
|
91
|
+
method: "GET",
|
92
|
+
request: Payload.new("path", "GET")
|
93
|
+
}
|
94
|
+
tracker.track_key(payload)
|
95
|
+
tracker.save_report
|
96
|
+
assert_equal [route_hash], tracker.logged_keys
|
97
|
+
end
|
98
|
+
|
60
99
|
test "report used routes" do
|
61
100
|
store = fake_store
|
62
101
|
route_hash = {controller: "some/controller", action: "index", url_path: nil, verb: "GET"}
|
@@ -38,7 +38,7 @@ class ReportJSONTest < Minitest::Test
|
|
38
38
|
json = Coverband::Reporters::JSONReport.new(@store).report
|
39
39
|
parsed = JSON.parse(json)
|
40
40
|
|
41
|
-
expected_keys = ["never_loaded", "runtime_percentage", "lines_of_code", "lines_covered", "lines_runtime", "lines_missed", "covered_percent", "covered_strength"]
|
41
|
+
expected_keys = ["filename", "hash", "never_loaded", "runtime_percentage", "lines_of_code", "lines_covered", "lines_runtime", "lines_missed", "covered_percent", "covered_strength"]
|
42
42
|
|
43
43
|
assert_equal parsed["files"].length, 2
|
44
44
|
parsed["files"].keys.each do |file|
|