mirror of
https://github.com/denoland/deno.git
synced 2024-11-26 16:09:27 -05:00
fix(coverage): merge duplicate reports (#8942)
Merging multiple runs isn't quite right because we rely on a 0 count to signal that a block hasn't been called. Other tools like c8 expect this to be true as-well so we need to do our best to merge coverage files rather than duplicating them.
This commit is contained in:
parent
3e5a3daf59
commit
4ca77ad84c
5 changed files with 85 additions and 27 deletions
|
@ -3330,6 +3330,12 @@ itest!(deno_test_run_run_coverage {
|
||||||
exit_code: 0,
|
exit_code: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itest!(deno_test_run_combined_coverage {
|
||||||
|
args: "test --allow-all --coverage --unstable test_run_run_coverage.ts test_run_test_coverage.ts",
|
||||||
|
output: "test_run_combined_coverage.out",
|
||||||
|
exit_code: 0,
|
||||||
|
});
|
||||||
|
|
||||||
itest!(deno_lint {
|
itest!(deno_lint {
|
||||||
args: "lint --unstable lint/file1.js lint/file2.ts lint/ignored_file.ts",
|
args: "lint --unstable lint/file1.js lint/file2.ts lint/ignored_file.ts",
|
||||||
output: "lint/expected.out",
|
output: "lint/expected.out",
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import { returnsFoo2 } from "./subdir/mod1.ts";
|
import { returnsHi } from "./subdir/mod1.ts";
|
||||||
|
|
||||||
returnsFoo2();
|
returnsHi();
|
||||||
|
|
31
cli/tests/test_run_combined_coverage.out
Normal file
31
cli/tests/test_run_combined_coverage.out
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
Check [WILDCARD]/tests/$deno$test.ts
|
||||||
|
running 2 tests
|
||||||
|
test spawn test ... Check [WILDCARD]/tests/run_coverage.ts
|
||||||
|
ok ([WILDCARD])
|
||||||
|
test spawn test ... Check [WILDCARD]/tests/$deno$test.ts
|
||||||
|
running 1 tests
|
||||||
|
test returnsFooSuccess ... ok ([WILDCARD])
|
||||||
|
|
||||||
|
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])
|
||||||
|
|
||||||
|
ok ([WILDCARD])
|
||||||
|
|
||||||
|
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])
|
||||||
|
|
||||||
|
cover [WILDCARD]/tests/run_coverage.ts ... 100.000% (3/3)
|
||||||
|
cover [WILDCARD]/tests/subdir/mod1.ts ... 57.143% (8/14)
|
||||||
|
8 | export function printHello3() {
|
||||||
|
9 | printHello2();
|
||||||
|
10 | }
|
||||||
|
11 | export function throwsError() {
|
||||||
|
12 | throw Error("exception from mod1");
|
||||||
|
13 | }
|
||||||
|
cover [WILDCARD]/tests/subdir/print_hello.ts ... 25.000% (1/4)
|
||||||
|
1 | export function printHello() {
|
||||||
|
2 | console.log("Hello");
|
||||||
|
3 | }
|
||||||
|
cover [WILDCARD]/tests/subdir/subdir2/mod2.ts ... 62.500% (5/8)
|
||||||
|
5 | export function printHello2() {
|
||||||
|
6 | printHello();
|
||||||
|
7 | }
|
||||||
|
cover [WILDCARD]/tests/test_coverage.ts ... 100.000% (5/5)
|
|
@ -1,16 +1,15 @@
|
||||||
Check [WILDCARD]/$deno$test.ts
|
Check [WILDCARD]/tests/$deno$test.ts
|
||||||
running 1 tests
|
running 1 tests
|
||||||
test spawn test ... Check [WILDCARD]/run_coverage.ts
|
test spawn test ... Check [WILDCARD]/tests/run_coverage.ts
|
||||||
ok ([WILDCARD])
|
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/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)
|
||||||
2 | export function returnsHi() {
|
5 | export function returnsFoo2() {
|
||||||
3 | return "Hi";
|
6 | return returnsFoo();
|
||||||
4 | }
|
7 | }
|
||||||
-----|-----
|
|
||||||
8 | export function printHello3() {
|
8 | export function printHello3() {
|
||||||
9 | printHello2();
|
9 | printHello2();
|
||||||
10 | }
|
10 | }
|
||||||
|
@ -21,7 +20,10 @@ cover [WILDCARD]/tests/subdir/print_hello.ts ... 25.000% (1/4)
|
||||||
1 | export function printHello() {
|
1 | export function printHello() {
|
||||||
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 ... 25.000% (2/8)
|
||||||
|
2 | export function returnsFoo() {
|
||||||
|
3 | return "Foo";
|
||||||
|
4 | }
|
||||||
5 | export function printHello2() {
|
5 | export function printHello2() {
|
||||||
6 | printHello();
|
6 | printHello();
|
||||||
7 | }
|
7 | }
|
||||||
|
|
|
@ -93,7 +93,7 @@ impl CoverageCollector {
|
||||||
|
|
||||||
// TODO(caspervonb) all of these structs can and should be made private, possibly moved to
|
// TODO(caspervonb) all of these structs can and should be made private, possibly moved to
|
||||||
// inspector::protocol.
|
// inspector::protocol.
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CoverageRange {
|
pub struct CoverageRange {
|
||||||
pub start_offset: usize,
|
pub start_offset: usize,
|
||||||
|
@ -101,7 +101,7 @@ pub struct CoverageRange {
|
||||||
pub count: usize,
|
pub count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct FunctionCoverage {
|
pub struct FunctionCoverage {
|
||||||
pub function_name: String,
|
pub function_name: String,
|
||||||
|
@ -109,7 +109,7 @@ pub struct FunctionCoverage {
|
||||||
pub is_block_coverage: bool,
|
pub is_block_coverage: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ScriptCoverage {
|
pub struct ScriptCoverage {
|
||||||
pub script_id: String,
|
pub script_id: String,
|
||||||
|
@ -117,7 +117,7 @@ pub struct ScriptCoverage {
|
||||||
pub functions: Vec<FunctionCoverage>,
|
pub functions: Vec<FunctionCoverage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Coverage {
|
pub struct Coverage {
|
||||||
pub script_coverage: ScriptCoverage,
|
pub script_coverage: ScriptCoverage,
|
||||||
|
@ -237,29 +237,48 @@ fn collect_coverages(dir: &PathBuf) -> Result<Vec<Coverage>, AnyError> {
|
||||||
let entries = fs::read_dir(dir)?;
|
let entries = fs::read_dir(dir)?;
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
let json = fs::read_to_string(entry.unwrap().path())?;
|
let json = fs::read_to_string(entry.unwrap().path())?;
|
||||||
let coverage: Coverage = serde_json::from_str(&json)?;
|
let new_coverage: Coverage = serde_json::from_str(&json)?;
|
||||||
|
|
||||||
coverages.push(coverage);
|
let existing_coverage = coverages
|
||||||
}
|
.iter_mut()
|
||||||
|
.find(|x| x.script_coverage.url == new_coverage.script_coverage.url);
|
||||||
|
|
||||||
// TODO(caspervonb) drain_filter would make this cleaner, its nightly at the moment.
|
if let Some(existing_coverage) = existing_coverage {
|
||||||
if coverages.len() > 1 {
|
for new_function in new_coverage.script_coverage.functions {
|
||||||
coverages.sort_by_key(|k| k.script_coverage.url.clone());
|
let existing_function = existing_coverage
|
||||||
|
.script_coverage
|
||||||
|
.functions
|
||||||
|
.iter_mut()
|
||||||
|
.find(|x| x.function_name == new_function.function_name);
|
||||||
|
|
||||||
for i in (1..coverages.len() - 1).rev() {
|
if let Some(existing_function) = existing_function {
|
||||||
if coverages[i].script_coverage.url
|
for new_range in new_function.ranges {
|
||||||
== coverages[i - 1].script_coverage.url
|
let existing_range =
|
||||||
{
|
existing_function.ranges.iter_mut().find(|x| {
|
||||||
let current = coverages.remove(i);
|
x.start_offset == new_range.start_offset
|
||||||
let previous = &mut coverages[i - 1];
|
&& x.end_offset == new_range.end_offset
|
||||||
|
});
|
||||||
|
|
||||||
for function in current.script_coverage.functions {
|
if let Some(existing_range) = existing_range {
|
||||||
previous.script_coverage.functions.push(function);
|
existing_range.count += new_range.count;
|
||||||
|
} else {
|
||||||
|
existing_function.ranges.push(new_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
existing_coverage
|
||||||
|
.script_coverage
|
||||||
|
.functions
|
||||||
|
.push(new_function);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
coverages.push(new_coverage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
coverages.sort_by_key(|k| k.script_coverage.url.clone());
|
||||||
|
|
||||||
Ok(coverages)
|
Ok(coverages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue