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.
@@ -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
- Coverband::Reporters::HTMLReport.new(Coverband.configuration.store,
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).report
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
- Coverband::Utils::HTMLFormatter.new(nil,
151
+ options = {
146
152
  tracker: tracker,
147
153
  notice: notice,
148
- base_path: base_path).format_abstract_tracker!
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
- "Not Available"
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
- %(<a href="##{id source_file}" class="src_link" title="#{shortened_filename source_file}">#{shortened_filename source_file}</a>)
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(src, i, never_loaded ? 0 : coverage[i - 1])
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
@@ -5,5 +5,5 @@
5
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 = "6.0.3.rc.3"
8
+ VERSION = "6.1.0"
9
9
  end
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(&block)
95
- coverage_instance.eager_loading(&block)
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)
@@ -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
 
@@ -16,7 +16,7 @@ $(document).ready(function() {
16
16
  });
17
17
 
18
18
  // Configuration for fancy sortable tables for source file groups
19
- $(".file_list").dataTable({
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
- var current_rows = 0;
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
- // NOTE: we request 250 at a time, but we seem to have some files that we have as a list but 0 coverage,
54
- // so we don't get back 250 per page... to ensure we we need to account for filtered out and empty files
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 < 100 && current_rows < total_rows) {
63
- get_page(page);
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
- // TODO: move source highlighting here
104
- prev_anchor = curr_anchor ? curr_anchor : jQuery.url.attr("anchor");
105
- curr_anchor = this.href.split("#")[1];
106
- window.location.hash = curr_anchor;
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
- if (prev_anchor && prev_anchor != curr_anchor) {
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
- ")</a></li>"
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
- window.location.href =
202
- window.location.href.split("#")[0] +
203
- $(this)
204
- .attr("href")
205
- .replace("#", "#_");
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
- console.log("I need to fix deep links to source, the click call wont work anymore");
223
- // $("a.src_link[href=#" + anchor + "]").click();
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
 
@@ -88,7 +88,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&amp;").replace(/<
88
88
  xhrError: "This content failed to load.",
89
89
  imgError: "This image failed to load.",
90
90
 
91
- // accessbility
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,"&amp;").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 intedned as a selector (e.g. '#container')
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,"&amp;").replace(/<
145
145
  $prev,
146
146
  $close,
147
147
  $groupControls,
148
- $events = $('<a/>'), // $({}) would be prefered, but there is an issue with jQuery 1.4.2
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
- assert_equal(
69
- {
70
- "first_updated_at" => yesterday.to_i,
71
- "last_updated_at" => today.to_i,
72
- "file_hash" => "abcd",
73
- "data" => [1, 2, 2]
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 controller routes" do
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|