mirror of
https://github.com/denoland/deno.git
synced 2025-01-03 12:58:54 -05:00
fix(coverage): use source maps when printing pretty reports (#9278)
This commits makes use of source maps and the original source when printing lacking line coverage in the pretty printer. Only the executable lines are checked as before (as non-executable lines will always be ignored anyways). The lines then mapped to the appropriate source line when a source map is present.
This commit is contained in:
parent
591ed6b3ad
commit
5cf194380b
6 changed files with 125 additions and 67 deletions
|
@ -5,6 +5,6 @@ test branch ... ok ([WILDCARD])
|
||||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])
|
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])
|
||||||
|
|
||||||
cover [WILDCARD]/tests/subdir/branch.ts ... 66.667% (6/9)
|
cover [WILDCARD]/tests/subdir/branch.ts ... 66.667% (6/9)
|
||||||
5 | else {
|
4 | } else {
|
||||||
6 | return false;
|
5 | return false;
|
||||||
7 | }
|
6 | }
|
||||||
|
|
|
@ -4,22 +4,23 @@ test returnsFooSuccess ... ok ([WILDCARD])
|
||||||
|
|
||||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])
|
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])
|
||||||
|
|
||||||
cover [WILDCARD]/cli/tests/subdir/mod1.ts ... 35.714% (5/14)
|
cover [WILDCARD]/tests/subdir/mod1.ts ... 35.714% (5/14)
|
||||||
2 | export function returnsHi() {
|
3 | export function returnsHi(): string {
|
||||||
3 | return "Hi";
|
4 | return "Hi";
|
||||||
4 | }
|
5 | }
|
||||||
-----|-----
|
-----|-----
|
||||||
8 | export function printHello3() {
|
11 | export function printHello3(): void {
|
||||||
9 | printHello2();
|
12 | printHello2();
|
||||||
10 | }
|
|
||||||
11 | export function throwsError() {
|
|
||||||
12 | throw Error("exception from mod1");
|
|
||||||
13 | }
|
13 | }
|
||||||
cover [WILDCARD]/cli/tests/subdir/print_hello.ts ... 25.000% (1/4)
|
-----|-----
|
||||||
1 | export function printHello() {
|
15 | export function throwsError(): void {
|
||||||
2 | console.log("Hello");
|
16 | throw Error("exception from mod1");
|
||||||
|
17 | }
|
||||||
|
cover [WILDCARD]/tests/subdir/print_hello.ts ... 25.000% (1/4)
|
||||||
|
1 | export function printHello(): void {
|
||||||
|
2 | console.log("Hello");
|
||||||
3 | }
|
3 | }
|
||||||
cover [WILDCARD]/cli/tests/subdir/subdir2/mod2.ts ... 62.500% (5/8)
|
cover [WILDCARD]/tests/subdir/subdir2/mod2.ts ... 62.500% (5/8)
|
||||||
5 | export function printHello2() {
|
7 | export function printHello2(): void {
|
||||||
6 | printHello();
|
8 | printHello();
|
||||||
7 | }
|
9 | }
|
||||||
|
|
|
@ -14,18 +14,19 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WIL
|
||||||
|
|
||||||
cover [WILDCARD]/tests/run_coverage.ts ... 100.000% (3/3)
|
cover [WILDCARD]/tests/run_coverage.ts ... 100.000% (3/3)
|
||||||
cover [WILDCARD]/tests/subdir/mod1.ts ... 57.143% (8/14)
|
cover [WILDCARD]/tests/subdir/mod1.ts ... 57.143% (8/14)
|
||||||
8 | export function printHello3() {
|
11 | export function printHello3(): void {
|
||||||
9 | printHello2();
|
12 | printHello2();
|
||||||
10 | }
|
|
||||||
11 | export function throwsError() {
|
|
||||||
12 | throw Error("exception from mod1");
|
|
||||||
13 | }
|
13 | }
|
||||||
|
-----|-----
|
||||||
|
15 | export function throwsError(): void {
|
||||||
|
16 | throw Error("exception from mod1");
|
||||||
|
17 | }
|
||||||
cover [WILDCARD]/tests/subdir/print_hello.ts ... 25.000% (1/4)
|
cover [WILDCARD]/tests/subdir/print_hello.ts ... 25.000% (1/4)
|
||||||
1 | export function printHello() {
|
1 | export function printHello(): void {
|
||||||
2 | console.log("Hello");
|
2 | console.log("Hello");
|
||||||
3 | }
|
3 | }
|
||||||
cover [WILDCARD]/tests/subdir/subdir2/mod2.ts ... 62.500% (5/8)
|
cover [WILDCARD]/tests/subdir/subdir2/mod2.ts ... 62.500% (5/8)
|
||||||
5 | export function printHello2() {
|
7 | export function printHello2(): void {
|
||||||
6 | printHello();
|
8 | printHello();
|
||||||
7 | }
|
9 | }
|
||||||
cover [WILDCARD]/tests/test_coverage.ts ... 100.000% (5/5)
|
cover [WILDCARD]/tests/test_coverage.ts ... 100.000% (5/5)
|
||||||
|
|
|
@ -7,23 +7,26 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WIL
|
||||||
|
|
||||||
cover [WILDCARD]/tests/run_coverage.ts ... 100.000% (3/3)
|
cover [WILDCARD]/tests/run_coverage.ts ... 100.000% (3/3)
|
||||||
cover [WILDCARD]/tests/subdir/mod1.ts ... 35.714% (5/14)
|
cover [WILDCARD]/tests/subdir/mod1.ts ... 35.714% (5/14)
|
||||||
5 | export function returnsFoo2() {
|
7 | export function returnsFoo2(): string {
|
||||||
6 | return returnsFoo();
|
8 | return returnsFoo();
|
||||||
7 | }
|
9 | }
|
||||||
8 | export function printHello3() {
|
-----|-----
|
||||||
9 | printHello2();
|
11 | export function printHello3(): void {
|
||||||
10 | }
|
12 | printHello2();
|
||||||
11 | export function throwsError() {
|
|
||||||
12 | throw Error("exception from mod1");
|
|
||||||
13 | }
|
13 | }
|
||||||
|
-----|-----
|
||||||
|
15 | export function throwsError(): void {
|
||||||
|
16 | throw Error("exception from mod1");
|
||||||
|
17 | }
|
||||||
cover [WILDCARD]/tests/subdir/print_hello.ts ... 25.000% (1/4)
|
cover [WILDCARD]/tests/subdir/print_hello.ts ... 25.000% (1/4)
|
||||||
1 | export function printHello() {
|
1 | export function printHello(): void {
|
||||||
2 | console.log("Hello");
|
2 | console.log("Hello");
|
||||||
3 | }
|
3 | }
|
||||||
cover [WILDCARD]/tests/subdir/subdir2/mod2.ts ... 25.000% (2/8)
|
cover [WILDCARD]/tests/subdir/subdir2/mod2.ts ... 25.000% (2/8)
|
||||||
2 | export function returnsFoo() {
|
3 | export function returnsFoo(): string {
|
||||||
3 | return "Foo";
|
4 | return "Foo";
|
||||||
4 | }
|
5 | }
|
||||||
5 | export function printHello2() {
|
-----|-----
|
||||||
6 | printHello();
|
7 | export function printHello2(): void {
|
||||||
7 | }
|
8 | printHello();
|
||||||
|
9 | }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Check [WILDCARD]/$deno$test.ts
|
Check [WILDCARD]/tests/$deno$test.ts
|
||||||
running 1 tests
|
running 1 tests
|
||||||
test spawn test ... Check [WILDCARD]/$deno$test.ts
|
test spawn test ... Check [WILDCARD]/tests/$deno$test.ts
|
||||||
running 1 tests
|
running 1 tests
|
||||||
test returnsFooSuccess ... ok ([WILDCARD])
|
test returnsFooSuccess ... ok ([WILDCARD])
|
||||||
|
|
||||||
|
@ -10,23 +10,24 @@ ok ([WILDCARD])
|
||||||
|
|
||||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])
|
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])
|
||||||
|
|
||||||
cover [WILDCARD]/subdir/mod1.ts ... 35.714% (5/14)
|
cover [WILDCARD]/tests/subdir/mod1.ts ... 35.714% (5/14)
|
||||||
2 | export function returnsHi() {
|
3 | export function returnsHi(): string {
|
||||||
3 | return "Hi";
|
4 | return "Hi";
|
||||||
4 | }
|
5 | }
|
||||||
-----|-----
|
-----|-----
|
||||||
8 | export function printHello3() {
|
11 | export function printHello3(): void {
|
||||||
9 | printHello2();
|
12 | printHello2();
|
||||||
10 | }
|
|
||||||
11 | export function throwsError() {
|
|
||||||
12 | throw Error("exception from mod1");
|
|
||||||
13 | }
|
13 | }
|
||||||
cover [WILDCARD]/subdir/print_hello.ts ... 25.000% (1/4)
|
-----|-----
|
||||||
1 | export function printHello() {
|
15 | export function throwsError(): void {
|
||||||
2 | console.log("Hello");
|
16 | throw Error("exception from mod1");
|
||||||
|
17 | }
|
||||||
|
cover [WILDCARD]/tests/subdir/print_hello.ts ... 25.000% (1/4)
|
||||||
|
1 | export function printHello(): void {
|
||||||
|
2 | console.log("Hello");
|
||||||
3 | }
|
3 | }
|
||||||
cover [WILDCARD]/subdir/subdir2/mod2.ts ... 62.500% (5/8)
|
cover [WILDCARD]/tests/subdir/subdir2/mod2.ts ... 62.500% (5/8)
|
||||||
5 | export function printHello2() {
|
7 | export function printHello2(): void {
|
||||||
6 | printHello();
|
8 | printHello();
|
||||||
7 | }
|
9 | }
|
||||||
cover [WILDCARD]/test_coverage.ts ... 100.000% (5/5)
|
cover [WILDCARD]/tests/test_coverage.ts ... 100.000% (5/5)
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::colors;
|
||||||
use crate::media_type::MediaType;
|
use crate::media_type::MediaType;
|
||||||
use crate::module_graph::TypeLib;
|
use crate::module_graph::TypeLib;
|
||||||
use crate::program_state::ProgramState;
|
use crate::program_state::ProgramState;
|
||||||
|
use crate::source_maps::SourceMapGetter;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
use deno_core::serde_json::json;
|
use deno_core::serde_json::json;
|
||||||
|
@ -15,6 +16,7 @@ use deno_runtime::inspector::InspectorSession;
|
||||||
use deno_runtime::permissions::Permissions;
|
use deno_runtime::permissions::Permissions;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use sourcemap::SourceMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -130,7 +132,15 @@ impl PrettyCoverageReporter {
|
||||||
&mut self,
|
&mut self,
|
||||||
script_coverage: &ScriptCoverage,
|
script_coverage: &ScriptCoverage,
|
||||||
script_source: &str,
|
script_source: &str,
|
||||||
|
maybe_source_map: Option<Vec<u8>>,
|
||||||
|
maybe_original_source: Option<String>,
|
||||||
) {
|
) {
|
||||||
|
let maybe_source_map = if let Some(source_map) = maybe_source_map {
|
||||||
|
Some(SourceMap::from_slice(&source_map).unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let mut ignored_spans: Vec<Span> = Vec::new();
|
let mut ignored_spans: Vec<Span> = Vec::new();
|
||||||
for item in ast::lex("", script_source, &MediaType::JavaScript) {
|
for item in ast::lex("", script_source, &MediaType::JavaScript) {
|
||||||
if let TokenOrComment::Token(_) = item.inner {
|
if let TokenOrComment::Token(_) = item.inner {
|
||||||
|
@ -221,8 +231,39 @@ impl PrettyCoverageReporter {
|
||||||
println!("{}", colors::red(&line_coverage));
|
println!("{}", colors::red(&line_coverage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let output_lines =
|
||||||
|
if let Some(original_source) = maybe_original_source.as_ref() {
|
||||||
|
original_source.split('\n').collect::<Vec<_>>()
|
||||||
|
} else {
|
||||||
|
lines
|
||||||
|
};
|
||||||
|
|
||||||
|
let output_indices = if let Some(source_map) = maybe_source_map.as_ref() {
|
||||||
|
// The compiled executable source lines have to be mapped to all the original source lines that they
|
||||||
|
// came from; this happens in a couple of emit scenarios, the most common example being function
|
||||||
|
// declarations where the compiled JavaScript code only takes a line but the original
|
||||||
|
// TypeScript source spans 10 lines.
|
||||||
|
let mut indices = uncovered_lines
|
||||||
|
.iter()
|
||||||
|
.map(|i| {
|
||||||
|
source_map
|
||||||
|
.tokens()
|
||||||
|
.filter(move |token| token.get_dst_line() as usize == *i)
|
||||||
|
.map(|token| token.get_src_line() as usize)
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<usize>>();
|
||||||
|
|
||||||
|
indices.sort_unstable();
|
||||||
|
indices.dedup();
|
||||||
|
|
||||||
|
indices
|
||||||
|
} else {
|
||||||
|
uncovered_lines
|
||||||
|
};
|
||||||
|
|
||||||
let mut last_line = None;
|
let mut last_line = None;
|
||||||
for line_index in uncovered_lines {
|
for line_index in output_indices {
|
||||||
const WIDTH: usize = 4;
|
const WIDTH: usize = 4;
|
||||||
const SEPERATOR: &str = "|";
|
const SEPERATOR: &str = "|";
|
||||||
|
|
||||||
|
@ -238,7 +279,7 @@ impl PrettyCoverageReporter {
|
||||||
"{:width$} {} {}",
|
"{:width$} {} {}",
|
||||||
line_index + 1,
|
line_index + 1,
|
||||||
colors::gray(SEPERATOR),
|
colors::gray(SEPERATOR),
|
||||||
colors::red(&lines[line_index]),
|
colors::red(&output_lines[line_index]),
|
||||||
width = WIDTH
|
width = WIDTH
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -354,7 +395,18 @@ pub async fn report_coverages(
|
||||||
let module_source = program_state.load(module_specifier.clone(), None)?;
|
let module_source = program_state.load(module_specifier.clone(), None)?;
|
||||||
let script_source = &module_source.code;
|
let script_source = &module_source.code;
|
||||||
|
|
||||||
coverage_reporter.visit_coverage(&script_coverage, &script_source);
|
let maybe_source_map = program_state.get_source_map(&script_coverage.url);
|
||||||
|
let maybe_cached_source = program_state
|
||||||
|
.file_fetcher
|
||||||
|
.get_source(&module_specifier)
|
||||||
|
.map(|f| f.source);
|
||||||
|
|
||||||
|
coverage_reporter.visit_coverage(
|
||||||
|
&script_coverage,
|
||||||
|
&script_source,
|
||||||
|
maybe_source_map,
|
||||||
|
maybe_cached_source,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue