diff options
-rw-r--r-- | cli/tools/coverage/reporter.rs | 55 | ||||
-rw-r--r-- | tests/integration/coverage_tests.rs | 21 |
2 files changed, 67 insertions, 9 deletions
diff --git a/cli/tools/coverage/reporter.rs b/cli/tools/coverage/reporter.rs index fe44fa4d0..6b0e5c885 100644 --- a/cli/tools/coverage/reporter.rs +++ b/cli/tools/coverage/reporter.rs @@ -475,8 +475,14 @@ impl HtmlCoverageReporter { format!("Coverage report for {node}") }; let title = title.replace(std::path::MAIN_SEPARATOR, "/"); + let breadcrumbs_parts = node + .split(std::path::MAIN_SEPARATOR) + .filter(|s| !s.is_empty()) + .collect::<Vec<_>>(); let head = self.create_html_head(&title); - let header = self.create_html_header(&title, stats); + let breadcrumb_navigation = + self.create_breadcrumbs_navigation(&breadcrumbs_parts, is_dir); + let header = self.create_html_header(&breadcrumb_navigation, stats); let footer = self.create_html_footer(timestamp); format!( "<!doctype html> @@ -513,7 +519,7 @@ impl HtmlCoverageReporter { /// Creates header part of the contents for html report. pub fn create_html_header( &self, - title: &str, + breadcrumb_navigation: &str, stats: &CoverageStats, ) -> String { let CoverageStats { @@ -531,7 +537,7 @@ impl HtmlCoverageReporter { format!( " <div class='pad1'> - <h1>{title}</h1> + <h1>{breadcrumb_navigation}</h1> <div class='clearfix'> <div class='fl pad1y space-right2'> <span class='strong'>{branch_percent:.2}%</span> @@ -681,4 +687,47 @@ impl HtmlCoverageReporter { </table>" ) } + + pub fn create_breadcrumbs_navigation( + &self, + breadcrumbs_parts: &[&str], + is_dir: bool, + ) -> String { + let mut breadcrumbs_html = Vec::new(); + let root_repeats = if is_dir { + breadcrumbs_parts.len() + } else { + breadcrumbs_parts.len() - 1 + }; + + let mut root_url = "../".repeat(root_repeats); + root_url += "index.html"; + breadcrumbs_html.push(format!("<a href='{root_url}'>All files</a>")); + + for (index, breadcrumb) in breadcrumbs_parts.iter().enumerate() { + let mut full_url = "../".repeat(breadcrumbs_parts.len() - (index + 1)); + + if index == breadcrumbs_parts.len() - 1 { + breadcrumbs_html.push(breadcrumb.to_string()); + continue; + } + + if is_dir { + full_url += "index.html"; + } else { + full_url += breadcrumb; + if index != breadcrumbs_parts.len() - 1 { + full_url += "/index.html"; + } + } + + breadcrumbs_html.push(format!("<a href='{full_url}'>{breadcrumb}</a>")) + } + + if breadcrumbs_parts.is_empty() { + return String::from("All files"); + } + + breadcrumbs_html.into_iter().collect::<Vec<_>>().join(" / ") + } } diff --git a/tests/integration/coverage_tests.rs b/tests/integration/coverage_tests.rs index c5f8b1453..9509ddcb7 100644 --- a/tests/integration/coverage_tests.rs +++ b/tests/integration/coverage_tests.rs @@ -516,7 +516,7 @@ fn test_html_reporter() { output.assert_matches_text("HTML coverage report has been generated at [WILDCARD]/cov/html/index.html\n"); let index_html = tempdir.join("html").join("index.html").read_to_string(); - assert_contains!(index_html, "<h1>Coverage report for all files</h1>"); + assert_contains!(index_html, "<h1>All files</h1>"); assert_contains!(index_html, "baz/"); assert_contains!(index_html, "href='baz/index.html'"); assert_contains!(index_html, "foo.ts"); @@ -525,13 +525,19 @@ fn test_html_reporter() { assert_contains!(index_html, "href='bar.ts.html'"); let foo_ts_html = tempdir.join("html").join("foo.ts.html").read_to_string(); - assert_contains!(foo_ts_html, "<h1>Coverage report for foo.ts</h1>"); + assert_contains!( + foo_ts_html, + "<h1><a href='index.html'>All files</a> / foo.ts</h1>" + ); // Check that line count has correct title attribute assert_contains!(foo_ts_html, "<span class='cline-any cline-yes' title='This line is covered 1 time'>x1</span>"); assert_contains!(foo_ts_html, "<span class='cline-any cline-yes' title='This line is covered 3 times'>x3</span>"); let bar_ts_html = tempdir.join("html").join("bar.ts.html").read_to_string(); - assert_contains!(bar_ts_html, "<h1>Coverage report for bar.ts</h1>"); + assert_contains!( + bar_ts_html, + "<h1><a href='index.html'>All files</a> / bar.ts</h1>" + ); // Check <T> in source code is escaped to <T> assert_contains!(bar_ts_html, "<T>"); // Check that line anchors are correctly referenced by line number links @@ -543,7 +549,10 @@ fn test_html_reporter() { .join("baz") .join("index.html") .read_to_string(); - assert_contains!(baz_index_html, "<h1>Coverage report for baz/</h1>"); + assert_contains!( + baz_index_html, + "<h1><a href='../index.html'>All files</a> / baz</h1>" + ); assert_contains!(baz_index_html, "qux.ts"); assert_contains!(baz_index_html, "href='qux.ts.html'"); assert_contains!(baz_index_html, "quux.ts"); @@ -554,7 +563,7 @@ fn test_html_reporter() { .join("baz") .join("qux.ts.html") .read_to_string(); - assert_contains!(baz_qux_ts_html, "<h1>Coverage report for baz/qux.ts</h1>"); + assert_contains!(baz_qux_ts_html, "<h1><a href='../index.html'>All files</a> / <a href='../baz/index.html'>baz</a> / qux.ts</h1>"); let baz_quux_ts_html = tempdir .join("html") @@ -563,7 +572,7 @@ fn test_html_reporter() { .read_to_string(); assert_contains!( baz_quux_ts_html, - "<h1>Coverage report for baz/quux.ts</h1>" + "<h1><a href='../index.html'>All files</a> / <a href='../baz/index.html'>baz</a> / quux.ts</h1>" ); } |