coverband 6.0.3.rc.2 → 6.0.3.rc.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ed82514a858dae89f9a09ec1e1cfb089a9356a1445c4ce930121bb9d8661fc1
4
- data.tar.gz: 3d51eab417e906fbda76b6b94b7f23e000c0f971b7de2a96c9e3adb6fa26616d
3
+ metadata.gz: cf0b6bab823d8155a5e15d361c3acbbef271f84e79947b9818a650e640a61fc7
4
+ data.tar.gz: 25cd0843b3c1e852794bcc008be165bfcbf7e476f373ab681cbff7861f050904
5
5
  SHA512:
6
- metadata.gz: 1a63814d8eb4133fa82990fc7207ee9dce27b9f3b9f09658f34d1904706ec29d2110d15b11461ebbd4c2f5e5b0b7b1e0d8c6575f8daa7d4a06d2b460f2a0aa44
7
- data.tar.gz: 5fcb0ba39f83744b54d97a68318db91686ea5beb2e15a773802a46446afa9ba5b1f892c22add88c11d26ba33f617ad3a276f95cddad37997e8ea0930970b880f
6
+ metadata.gz: d2ae2023667369ac1e7be83ec41898c6e77662545f6226c02417ef9a43e75a4e2950ad0d775e18c96d800270d81da104162d4414b13768ac98c14bcff431acd1
7
+ data.tar.gz: 64ddff4e59042a6ee22cd4839e6e7ac57dff4cf289b02a8f6801c144aafea7edd417ed918c38309b61173176cb177ce548dbf6302963d4b53464d8901cb05d30
data/coverband.gemspec CHANGED
@@ -34,12 +34,13 @@ Gem::Specification.new do |spec|
34
34
  spec.add_development_dependency "capybara"
35
35
  spec.add_development_dependency "m"
36
36
  spec.add_development_dependency "memory_profiler"
37
- # breaking change in minitest and mocha
37
+ # breaking change in minitest and mocha...
38
+ # note: we are also adding 'spy' as mocha doesn't want us to spy on redis calls...
39
+ # ^^^ probably need a large test cleanup refactor
38
40
  spec.add_development_dependency "minitest", "= 5.18.1"
39
41
  spec.add_development_dependency "minitest-fork_executor"
40
42
  spec.add_development_dependency "minitest-stub-const"
41
43
  spec.add_development_dependency "mocha", "~> 1.7.0"
42
- # spec.add_development_dependency "spy"
43
44
  spec.add_development_dependency "rack"
44
45
  spec.add_development_dependency "rack-test"
45
46
  spec.add_development_dependency "rake"
@@ -51,16 +51,6 @@ module Coverband
51
51
  end
52
52
  end
53
53
 
54
- protected
55
-
56
- def split_coverage(types, coverage_cache, options = {})
57
- if types.is_a?(Array)
58
- coverage_for_types(types, options)
59
- else
60
- super
61
- end
62
- end
63
-
64
54
  private
65
55
 
66
56
  # sleep in between to avoid holding other redis commands..
@@ -99,7 +89,7 @@ module Coverband
99
89
  # used to store data to redis. It is changed only when breaking changes to our
100
90
  # redis format are required.
101
91
  ###
102
- REDIS_STORAGE_FORMAT_VERSION = "coverband_hash_3_3"
92
+ REDIS_STORAGE_FORMAT_VERSION = "coverband_hash_4_0"
103
93
 
104
94
  JSON_PAYLOAD_EXPIRATION = 5 * 60
105
95
 
@@ -117,7 +107,7 @@ module Coverband
117
107
  @relative_file_converter = opts[:relative_file_converter] || Utils::RelativeFileConverter
118
108
 
119
109
  @get_coverage_cache = if opts[:get_coverage_cache]
120
- key_prefix = [REDIS_STORAGE_FORMAT_VERSION, @redis_namespace, "v2"].compact.join(".")
110
+ key_prefix = [REDIS_STORAGE_FORMAT_VERSION, @redis_namespace].compact.join(".")
121
111
  GetCoverageRedisCacheStore.new(redis, key_prefix)
122
112
  else
123
113
  GetCoverageNullCacheStore
@@ -182,18 +172,21 @@ module Coverband
182
172
  @redis.sadd(files_key, keys) if keys.any?
183
173
  end
184
174
 
185
- # TODO: refactor this and the method below and consider removing all the cached results stuff
175
+ # NOTE: This method should be used for full coverage or filename coverage look ups
176
+ # When paging code should use coverage_for_types and pull eager and runtime together as matched pairs
186
177
  def coverage(local_type = nil, opts = {})
187
178
  page_size = opts[:page_size] || 250
188
179
  cached_results = @get_coverage_cache.fetch(local_type || type) do |sleep_time|
189
180
  files_set = if opts[:page]
190
- files_set(local_type).each_slice(page_size).to_a[opts[:page] - 1] || {}
181
+ raise "call coverage_for_types with paging"
191
182
  elsif opts[:filename]
192
- files_set(local_type).select { |filepath| filepath == opts[:filename] } || {}
183
+ type_key_prefix = key_prefix(local_type)
184
+ # NOTE: a better way to extract filename from key would be better
185
+ files_set(local_type).select { |cache_key| cache_key.sub(type_key_prefix, "").match(short_name(opts[:filename])) } || {}
193
186
  else
194
187
  files_set(local_type)
195
188
  end
196
- # use batches with a sleep in between to avoid overloading redis
189
+ # below uses batches with a sleep in between to avoid overloading redis
197
190
  files_set.each_slice(page_size).flat_map do |key_batch|
198
191
  sleep sleep_time
199
192
  @redis.pipelined do |pipeline|
@@ -209,20 +202,25 @@ module Coverband
209
202
  end
210
203
  end
211
204
 
212
- # NOTE: when using paging we need to ensure we have the same set of files per page in runtime and eager
205
+ def split_coverage(types, coverage_cache, options = {})
206
+ if types.is_a?(Array) && !options[:filename] && options[:page]
207
+ data = coverage_for_types(types, options)
208
+ coverage_cache[Coverband::RUNTIME_TYPE] = data[Coverband::RUNTIME_TYPE]
209
+ coverage_cache[Coverband::EAGER_TYPE] = data[Coverband::EAGER_TYPE]
210
+ data
211
+ else
212
+ super
213
+ end
214
+ end
215
+
213
216
  def coverage_for_types(types, opts = {})
214
217
  page_size = opts[:page_size] || 250
215
218
 
216
219
  local_type = Coverband::RUNTIME_TYPE
217
220
  hash_data = {}
218
221
 
219
- runtime_file_set = if opts[:page]
220
- files_set(local_type).each_slice(page_size).to_a[opts[:page] - 1] || {}
221
- elsif opts[:filename]
222
- files_set(local_type).select { |filepath| filepath == opts[:filename] } || {}
223
- else
224
- files_set(local_type)
225
- end
222
+ runtime_file_set = files_set(local_type).each_slice(page_size).to_a[opts[:page] - 1] || []
223
+
226
224
  hash_data[Coverband::RUNTIME_TYPE] = runtime_file_set.each_slice(page_size).flat_map do |key_batch|
227
225
  @redis.pipelined do |pipeline|
228
226
  key_batch.each do |key|
@@ -231,8 +229,14 @@ module Coverband
231
229
  end
232
230
  end
233
231
 
232
+ eager_key_pre = key_prefix(Coverband::EAGER_TYPE)
233
+ runtime_key_pre = key_prefix(Coverband::RUNTIME_TYPE)
234
234
  matched_file_set = files_set(Coverband::EAGER_TYPE)
235
- .select { |filepath| runtime_file_set.include?(filepath) } || {}
235
+ .select { |eager_key, val|
236
+ runtime_file_set.any? { |runtime_key|
237
+ (eager_key.sub(eager_key_pre, "") == runtime_key.sub(runtime_key_pre, ""))
238
+ }
239
+ } || []
236
240
  hash_data[Coverband::EAGER_TYPE] = matched_file_set.each_slice(page_size).flat_map do |key_batch|
237
241
  @redis.pipelined do |pipeline|
238
242
  key_batch.each do |key|
@@ -240,9 +244,20 @@ module Coverband
240
244
  end
241
245
  end
242
246
  end
247
+ hash_data[Coverband::RUNTIME_TYPE] = hash_data[Coverband::RUNTIME_TYPE].each_with_object({}) do |data_from_redis, hash|
248
+ add_coverage_for_file(data_from_redis, hash)
249
+ end
250
+ hash_data[Coverband::EAGER_TYPE] = hash_data[Coverband::EAGER_TYPE].each_with_object({}) do |data_from_redis, hash|
251
+ add_coverage_for_file(data_from_redis, hash)
252
+ end
243
253
  hash_data
244
254
  end
245
255
 
256
+ def short_name(filename)
257
+ filename.sub(/^#{Coverband.configuration.root}/, ".")
258
+ .gsub(%r{^\.\/}, "")
259
+ end
260
+
246
261
  def file_count(local_type = nil)
247
262
  files_set(local_type).count { |filename| !Coverband.configuration.ignore.any? { |i| filename.match(i) } }
248
263
  end
@@ -17,7 +17,7 @@ module Coverband
17
17
  :s3_secret_access_key, :password, :api_key, :service_url, :coverband_timeout, :service_dev_mode,
18
18
  :service_test_mode, :process_type, :track_views, :redis_url,
19
19
  :background_reporting_sleep_seconds, :reporting_wiggle,
20
- :send_deferred_eager_loading_data
20
+ :send_deferred_eager_loading_data, :paged_reporting
21
21
 
22
22
  attr_reader :track_gems, :ignore, :use_oneshot_lines_coverage
23
23
 
@@ -293,6 +293,10 @@ module Coverband
293
293
  @send_deferred_eager_loading_data
294
294
  end
295
295
 
296
+ def paged_reporting
297
+ !!@paged_reporting
298
+ end
299
+
296
300
  def service_disabled_dev_test_env?
297
301
  return false unless service?
298
302
 
@@ -5,13 +5,14 @@
5
5
  module Coverband
6
6
  module Reporters
7
7
  class JSONReport < Base
8
- attr_accessor :filtered_report_files, :options, :page, :as_report, :store, :filename
8
+ attr_accessor :filtered_report_files, :options, :page, :as_report, :store, :filename, :base_path
9
9
 
10
10
  def initialize(store, options = {})
11
11
  self.options = options
12
12
  self.page = options.fetch(:page) { nil }
13
13
  self.filename = options.fetch(:filename) { nil }
14
14
  self.as_report = options.fetch(:as_report) { false }
15
+ self.base_path = options.fetch(:base_path) { "./" }
15
16
  self.store = store
16
17
 
17
18
  coverband_reports = Coverband::Reporters::Base.report(store, options)
@@ -29,6 +30,18 @@ module Coverband
29
30
 
30
31
  private
31
32
 
33
+ def coverage_css_class(covered_percent)
34
+ if covered_percent.nil?
35
+ ""
36
+ elsif covered_percent > 90
37
+ "green"
38
+ elsif covered_percent > 80
39
+ "yellow"
40
+ else
41
+ "red"
42
+ end
43
+ end
44
+
32
45
  def report_as_json
33
46
  result = Coverband::Utils::Results.new(filtered_report_files)
34
47
  source_files = result.source_files
@@ -41,10 +54,16 @@ module Coverband
41
54
  if as_report
42
55
  row_data = []
43
56
  data[:files].each_pair do |key, data|
57
+ source_class = data[:never_loaded] ? "strong red" : "strong"
58
+ data_loader_url = "#{base_path}load_file_details?filename=#{data[:filename]}"
59
+ link = "<a href=\"##{data[:hash]}\" class=\"src_link #{source_class} cboxElement\" title=\"#{key}\" data-loader-url=\"#{data_loader_url}\" onclick=\"src_link_click(this)\">#{key}</a>"
60
+ # Hack to ensure the sorting works on percentage columns, the span is hidden but colors the cell and the text is used for sorting
61
+ covered_percent = "#{data[:covered_percent]} <span class=\"#{coverage_css_class(data[:covered_percent])}\">&nbsp;</span>"
62
+ runtime_percentage = "#{data[:runtime_percentage]}<span class=\"#{coverage_css_class(data[:runtime_percentage])}\">&nbsp;</span>"
44
63
  row_data << [
45
- key,
46
- data[:covered_percent].to_s,
47
- data[:runtime_percentage].to_s,
64
+ link,
65
+ covered_percent,
66
+ runtime_percentage,
48
67
  data[:lines_of_code].to_s,
49
68
  (data[:lines_covered] + data[:lines_missed]).to_s,
50
69
  data[:lines_covered].to_s,
@@ -79,6 +98,8 @@ module Coverband
79
98
  source_files.each_with_object({}) do |source_file, hash|
80
99
  runtime_coverage = result.file_with_type(source_file, Coverband::RUNTIME_TYPE)&.covered_lines_count || 0
81
100
  hash[source_file.short_name] = {
101
+ filename: source_file.filename,
102
+ hash: Digest::SHA1.hexdigest(source_file.filename),
82
103
  never_loaded: source_file.never_loaded,
83
104
  runtime_percentage: result.runtime_relevant_coverage(source_file),
84
105
  lines_of_code: source_file.lines.count,
@@ -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
@@ -125,7 +130,8 @@ module Coverband
125
130
 
126
131
  def report_json
127
132
  report_options = {
128
- as_report: true
133
+ as_report: true,
134
+ base_path: base_path
129
135
  }
130
136
  report_options[:page] = (request.params["page"] || 1).to_i if request.params["page"]
131
137
  Coverband::Reporters::JSONReport.new(
@@ -141,10 +147,12 @@ module Coverband
141
147
  def display_abstract_tracker(tracker)
142
148
  notice = "<strong>Notice:</strong> #{Rack::Utils.escape_html(request.params["notice"])}<br/>"
143
149
  notice = request.params["notice"] ? notice : ""
144
- Coverband::Utils::HTMLFormatter.new(nil,
150
+ options = {
145
151
  tracker: tracker,
146
152
  notice: notice,
147
- base_path: base_path).format_abstract_tracker!
153
+ base_path: base_path
154
+ }
155
+ Coverband::Utils::HTMLFormatter.new(nil, options).format_abstract_tracker!
148
156
  end
149
157
 
150
158
  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\-\_]/, "")
@@ -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
@@ -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.2"
8
+ VERSION = "6.0.3.rc.4"
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
@@ -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,25 @@ $(document).ready(function() {
30
30
  null,
31
31
  null,
32
32
  null
33
- ]
34
- });
33
+ ],
34
+ }
35
35
 
36
- // TODO: add support for searching...
37
- // hmm should I just use manual paging? or load more...
36
+ $(".file_list").dataTable(tableOptions);
37
+
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
+ $(".dataTables_empty").html("loading...");
41
42
  var current_rows = 0;
42
43
  var total_rows = 0;
43
44
  var page = 1;
45
+
46
+ // load and render page content before we start the loop
47
+ // perhaps move this into a datatable ready event
48
+ setTimeout(() => {
49
+ get_page(page);
50
+ }, 1250);
44
51
 
45
- // write a function to get a page of data and add it to the table
46
52
  function get_page(page) {
47
53
  $.ajax({
48
54
  url: `${$(".file_list").data("coverageurl")}/report_json?page=${page}`,
@@ -54,79 +60,51 @@ $(document).ready(function() {
54
60
  // so we don't get back 250 per page... to ensure we we need to account for filtered out and empty files
55
61
  // this 250 at the moment is synced to the 250 in the hash redis store
56
62
  current_rows += 250; //data["aaData"].length;
57
- console.log(current_rows);
58
- console.log(total_rows);
59
63
  $(".file_list.unsorted").dataTable().fnAddData(data["aaData"]);
60
64
  page += 1;
65
+ // allow rendering to complete before we click the anchor
66
+ setTimeout(() => {
67
+ if (window.auto_click_anchor && $(window.auto_click_anchor).length > 0) {
68
+ $(window.auto_click_anchor).click();
69
+ }
70
+ }, 50);
61
71
  // the page less than 100 is to stop infinite loop in case of folks never clearing out old coverage reports
62
72
  if (page < 100 && current_rows < total_rows) {
63
- get_page(page);
73
+ setTimeout(() => {
74
+ get_page(page);
75
+ }, 200);
64
76
  }
65
77
  }
66
78
  });
67
79
  }
68
- get_page(page);
69
80
  }
70
81
 
82
+ src_link_click = (trigger_element) => {
83
+ var loader_url = $(trigger_element).attr("data-loader-url");
84
+ auto_click_anchor = null;
85
+ $(trigger_element).colorbox(jQuery.extend(colorbox_options, { href: loader_url}));
86
+ };
71
87
 
72
- // Syntax highlight all files up front - deactivated
73
- // $('.source_table pre code').each(function(i, e) {hljs.highlightBlock(e, ' ')});
74
-
75
- // Syntax highlight source files on first toggle of the file view popup
76
- $("a.src_link").click(function() {
77
- // Get the source file element that corresponds to the clicked element
78
- var source_table = $($(this).attr("href"));
79
- var loader_url = $(source_table).attr("data-loader-url");
80
-
81
- $(source_table).load(loader_url);
82
-
83
- // If not highlighted yet, do it!
84
- if (!source_table.hasClass("highlighted")) {
85
- source_table.find("pre code").each(function(i, e) {
86
- hljs.highlightBlock(e, " ");
87
- });
88
- source_table.addClass("highlighted");
89
- }
90
- });
91
-
92
- var prev_anchor;
93
- var curr_anchor;
94
-
95
- // Set-up of popup for source file views
96
- $("a.src_link").colorbox({
88
+ var colorbox_options = {
97
89
  transition: "none",
98
- inline: true,
99
90
  opacity: 1,
100
91
  width: "95%",
101
92
  height: "95%",
102
93
  onLoad: function() {
103
- prev_anchor = curr_anchor ? curr_anchor : jQuery.url.attr("anchor");
104
- curr_anchor = this.href.split("#")[1];
105
- window.location.hash = curr_anchor;
94
+ // If not highlighted yet, do it!
95
+ var source_table = $(".shared_source_table");
96
+ if (!source_table.hasClass("highlighted")) {
97
+ source_table.find("pre code").each(function(i, e) {
98
+ hljs.highlightBlock(e, " ");
99
+ });
100
+ source_table.addClass("highlighted");
101
+ }
102
+ window.location.hash = this.href.split("#")[1];
106
103
  },
107
104
  onCleanup: function() {
108
- if (prev_anchor && prev_anchor != curr_anchor) {
109
- $('a[href="#' + prev_anchor + '"]').click();
110
- curr_anchor = prev_anchor;
111
- } else {
112
- $(".group_tabs a:first").click();
113
- prev_anchor = curr_anchor;
114
- curr_anchor = $(".group_tabs a:first").attr("href");
115
- }
116
- window.location.hash = curr_anchor;
105
+ window.location.hash = $(".group_tabs a:first").attr("href");
117
106
  }
118
- });
119
-
120
- window.onpopstate = function(event) {
121
- if (location.hash.substring(0, 2) == "#_") {
122
- $.colorbox.close();
123
- curr_anchor = jQuery.url.attr("anchor");
124
- } else {
125
- if ($("#colorbox").is(":hidden")) {
126
- $('a.src_link[href="' + location.hash + '"]').colorbox({ open: true });
127
- }
128
- }
129
- };
107
+ }
130
108
 
131
109
  // Hide src files and file list container after load
132
110
  $(".source_files").hide();
@@ -145,15 +123,20 @@ $(document).ready(function() {
145
123
  .find(".covered_percent")
146
124
  .first()
147
125
  .html();
126
+ if (covered_percent) {
127
+ covered_percent = "(" + covered_percent + ")";
128
+ } else {
129
+ covered_percent = "";
130
+ }
148
131
 
149
132
  $(".group_tabs").append(
150
133
  '<li><a href="#' +
151
134
  container_id +
152
135
  '">' +
153
136
  group_name +
154
- " (" +
137
+ " " +
155
138
  covered_percent +
156
- ")</a></li>"
139
+ "</a></li>"
157
140
  );
158
141
  });
159
142
 
@@ -185,15 +168,26 @@ $(document).ready(function() {
185
168
  .addClass("active");
186
169
  }
187
170
  $(".file_list_container").hide();
188
- $(".file_list_container" + $(this).attr("href")).show();
189
- window.location.href =
190
- window.location.href.split("#")[0] +
191
- $(this)
192
- .attr("href")
193
- .replace("#", "#_");
194
-
171
+ $(".file_list_container" + $(this).attr("href")).show(function() {
172
+ // If we have an anchor to click, click it
173
+ // allow rendering to complete before we click the anchor
174
+ setTimeout(() => {
175
+ if (window.auto_click_anchor && $(window.auto_click_anchor).length > 0) {
176
+ $(window.auto_click_anchor).click();
177
+ }
178
+ }, 30);
179
+ });
180
+ // Below the #_ is a hack to show we have processed the hash change
181
+ if (!window.auto_click_anchor) {
182
+ window.location.href =
183
+ window.location.href.split("#")[0] +
184
+ $(this)
185
+ .attr("href")
186
+ .replace("#", "#_");
187
+ }
188
+
195
189
  // Force favicon reload - otherwise the location change containing anchor would drop the favicon...
196
- // Works only on firefox, but still... - Anyone know a better solution to force favicon on local file?
190
+ // Works only on firefox, but still... - Anyone know a better solution to force favicon on local relative file path?
197
191
  $('link[rel="shortcut icon"]').remove();
198
192
  $("head").append(
199
193
  '<link rel="shortcut icon" type="image/png" href="' +
@@ -203,17 +197,21 @@ $(document).ready(function() {
203
197
  return false;
204
198
  });
205
199
 
200
+ // The below function handles turning initial anchors in links to navigate to correct tab
206
201
  if (jQuery.url.attr("anchor")) {
207
202
  var anchor = jQuery.url.attr("anchor");
208
- // source file hash
209
203
  if (anchor.length == 40) {
210
- $("a.src_link[href=#" + anchor + "]").click();
204
+ // handles deep links to source files
205
+ window.auto_click_anchor = "a.src_link[href=#" + anchor + "]";
206
+ $(".group_tabs a:first").click();
211
207
  } else {
208
+ // handles a # anchor that needs to be processed into a #_ completed action
212
209
  if ($(".group_tabs a." + anchor.replace("_", "")).length > 0) {
213
210
  $(".group_tabs a." + anchor.replace("_", "")).click();
214
211
  }
215
212
  }
216
213
  } else {
214
+ // No anchor, so click the first navigation tab
217
215
  $(".group_tabs a:first").click();
218
216
  }
219
217
 
@@ -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|
@@ -7,12 +7,14 @@ describe "results" do
7
7
  let(:source_file) { Coverband::Utils::SourceFile.new(source_fixture("app/models/user.rb"), run_lines) }
8
8
  let(:eager_lines) { [nil, 1, 1, 0, nil, nil, 1, 0, nil, nil] }
9
9
  let(:run_lines) { [nil, nil, nil, 1, nil, nil, nil, nil, nil, nil] }
10
+ let(:missing_run_coverage_file) { false }
10
11
  let(:original_result) do
11
12
  orig = {
12
13
  Coverband::MERGED_TYPE => {source_fixture("app/models/user.rb") => eager_lines}
13
14
  }
14
15
  orig[Coverband::EAGER_TYPE] = {source_fixture("app/models/user.rb") => eager_lines} if eager_lines
15
16
  orig[Coverband::RUNTIME_TYPE] = {source_fixture("app/models/user.rb") => run_lines} if run_lines
17
+ orig[Coverband::RUNTIME_TYPE] = {"random.rb" => [nil, 1, nil]} if missing_run_coverage_file
16
18
  orig
17
19
  end
18
20
  subject { Coverband::Utils::Results.new(original_result) }
@@ -27,15 +29,28 @@ describe "results" do
27
29
  end
28
30
  end
29
31
 
30
- describe "runtime relevant lines when no runtime coverage exists" do
32
+ describe "runtime relevant lines when no runtime coverage file matches" do
31
33
  let(:run_lines) { nil }
32
34
 
35
+ it "has correct runtime relevant coverage" do
36
+ assert_equal 0, subject.runtime_relevant_coverage(source_file)
37
+ end
38
+
33
39
  it "has correct runtime relevant lines" do
40
+ assert_equal 0, subject.runtime_relavent_lines(source_file)
41
+ end
42
+ end
43
+
44
+ describe "runtime relevant lines when no runtime coverage exists" do
45
+ let(:run_lines) { nil }
46
+ let(:missing_run_coverage_file) { true }
47
+
48
+ it "has correct runtime relevant coverage" do
34
49
  assert_equal 0.0, subject.runtime_relevant_coverage(source_file)
35
50
  end
36
51
 
37
52
  it "has correct runtime relevant lines" do
38
- assert_equal 2, subject.runtime_relavent_lines(source_file)
53
+ assert_equal 0, subject.runtime_relavent_lines(source_file)
39
54
  end
40
55
  end
41
56
 
data/views/layout.erb CHANGED
@@ -26,9 +26,13 @@
26
26
  </div>
27
27
 
28
28
  <div class="source_files">
29
- <% result.source_files.each do |source_file| %>
30
- <%= formatted_source_file_loader(result, source_file) %>
31
- <% end %>
29
+ <div class="shared_source_table">
30
+ <div class='loader'>
31
+ loading source data...
32
+ <br/>
33
+ <img src="<%= assets_path('loading.gif') %>" alt="loading"/>
34
+ </div>
35
+ </div>
32
36
  </div>
33
37
  </div>
34
38
  </body>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coverband
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.3.rc.2
4
+ version: 6.0.3.rc.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Mayer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-03-05 00:00:00.000000000 Z
12
+ date: 2024-04-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: benchmark-ips
@@ -307,7 +307,6 @@ files:
307
307
  - lib/coverband/reporters/html_report.rb
308
308
  - lib/coverband/reporters/json_report.rb
309
309
  - lib/coverband/reporters/web.rb
310
- - lib/coverband/reporters/web_pager.rb
311
310
  - lib/coverband/utils/absolute_file_converter.rb
312
311
  - lib/coverband/utils/configuration_template.rb
313
312
  - lib/coverband/utils/dead_methods.rb
@@ -490,7 +489,6 @@ files:
490
489
  - views/nav.erb
491
490
  - views/settings.erb
492
491
  - views/source_file.erb
493
- - views/source_file_loader.erb
494
492
  homepage: https://github.com/danmayer/coverband
495
493
  licenses:
496
494
  - MIT
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "base64"
4
- require "coverband"
5
-
6
- begin
7
- require "rack"
8
- rescue LoadError
9
- puts "error loading Coverband web reporter as Rack is not available"
10
- end
11
-
12
- module Coverband
13
- module Reporters
14
- class WebPager < Web
15
- def index
16
- notice = "<strong>Notice:</strong> #{Rack::Utils.escape_html(request.params["notice"])}<br/>"
17
- notice = request.params["notice"] ? notice : ""
18
- # TODO: remove the call to the store render empty table
19
- Coverband::Reporters::HTMLReport.new(Coverband.configuration.store,
20
- page: (request.params["page"] || 1).to_i,
21
- static: false,
22
- base_path: base_path,
23
- notice: notice,
24
- open_report: false).report
25
- end
26
- end
27
- end
28
- end
@@ -1,7 +0,0 @@
1
- <div class="source_table" id="<%= id source_file %>" data-loader-url="<%= base_path %>load_file_details?filename=<%= source_file.filename %>">
2
- <div class='loader'>
3
- loading source data...
4
- <br/>
5
- <img src="<%= assets_path('loading.gif') %>" alt="loading"/>
6
- </div>
7
- </div>