mirror of
https://github.com/denoland/deno.git
synced 2025-02-01 12:16:11 -05:00
fix(coverage): better handling of multi-byte characters (#15159)
This commit is contained in:
parent
99bf821727
commit
4854cffcc1
8 changed files with 129 additions and 113 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -838,7 +838,7 @@ dependencies = [
|
|||
"tempfile",
|
||||
"test_util",
|
||||
"text-size",
|
||||
"text_lines",
|
||||
"text_lines 0.6.0",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-lsp",
|
||||
|
@ -881,7 +881,7 @@ dependencies = [
|
|||
"swc_ecma_transforms_typescript",
|
||||
"swc_ecma_utils",
|
||||
"swc_ecma_visit",
|
||||
"text_lines",
|
||||
"text_lines 0.4.1",
|
||||
"url 2.2.2",
|
||||
]
|
||||
|
||||
|
@ -1370,7 +1370,7 @@ dependencies = [
|
|||
"dprint-core",
|
||||
"jsonc-parser",
|
||||
"serde",
|
||||
"text_lines",
|
||||
"text_lines 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1412,7 +1412,7 @@ dependencies = [
|
|||
"swc_common",
|
||||
"swc_ecma_ast",
|
||||
"swc_ecma_parser",
|
||||
"text_lines",
|
||||
"text_lines 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4580,6 +4580,12 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "text_lines"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fd5828de7deaa782e1dd713006ae96b3bee32d3279b79eb67ecf8072c059bcf"
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
|
|
|
@ -94,7 +94,7 @@ serde = { version = "=1.0.139", features = ["derive"] }
|
|||
serde_repr = "=0.1.8"
|
||||
shell-escape = "=0.1.5"
|
||||
text-size = "=1.1.0"
|
||||
text_lines = "=0.4.1"
|
||||
text_lines = "=0.6.0"
|
||||
tokio = { version = "=1.19", features = ["full"] }
|
||||
tokio-util = "=0.7.2"
|
||||
tower-lsp = "=0.17.0"
|
||||
|
|
|
@ -46,9 +46,9 @@ DA:64,0
|
|||
DA:65,0
|
||||
DA:66,0
|
||||
DA:67,0
|
||||
DA:68,1
|
||||
DA:68,0
|
||||
DA:71,0
|
||||
DA:74,1
|
||||
LH:23
|
||||
LH:22
|
||||
LF:38
|
||||
end_of_record
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
cover [WILDCARD]/coverage/complex.ts ... 60.526% (23/38)
|
||||
cover [WILDCARD]/coverage/complex.ts ... 57.895% (22/38)
|
||||
46 | export function unused(
|
||||
47 | foo: string,
|
||||
48 | bar: string,
|
||||
|
@ -15,5 +15,6 @@ cover [WILDCARD]/coverage/complex.ts ... 60.526% (23/38)
|
|||
65 | return (
|
||||
66 | 0
|
||||
67 | );
|
||||
68 | }
|
||||
-----|-----
|
||||
71 | console.log("%s", () => 1);
|
||||
|
|
|
@ -6,10 +6,12 @@ use serde::Serialize;
|
|||
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CoverageRange {
|
||||
/// Start byte index.
|
||||
pub start_offset: usize,
|
||||
/// End byte index.
|
||||
pub end_offset: usize,
|
||||
/// Start character index.
|
||||
#[serde(rename = "startOffset")]
|
||||
pub start_char_offset: usize,
|
||||
/// End character index.
|
||||
#[serde(rename = "endOffset")]
|
||||
pub end_char_offset: usize,
|
||||
pub count: i64,
|
||||
}
|
||||
|
||||
|
|
|
@ -54,15 +54,15 @@ pub fn merge_scripts(
|
|||
let first: &ScriptCoverage = &scripts[0];
|
||||
(first.script_id.clone(), first.url.clone())
|
||||
};
|
||||
let mut range_to_funcs: BTreeMap<Range, Vec<FunctionCoverage>> =
|
||||
let mut range_to_funcs: BTreeMap<CharRange, Vec<FunctionCoverage>> =
|
||||
BTreeMap::new();
|
||||
for script_cov in scripts {
|
||||
for func_cov in script_cov.functions {
|
||||
let root_range = {
|
||||
let root_range_cov: &CoverageRange = &func_cov.ranges[0];
|
||||
Range {
|
||||
start: root_range_cov.start_offset,
|
||||
end: root_range_cov.end_offset,
|
||||
CharRange {
|
||||
start: root_range_cov.start_char_offset,
|
||||
end: root_range_cov.end_char_offset,
|
||||
}
|
||||
};
|
||||
range_to_funcs
|
||||
|
@ -85,12 +85,12 @@ pub fn merge_scripts(
|
|||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
|
||||
struct Range {
|
||||
struct CharRange {
|
||||
start: usize,
|
||||
end: usize,
|
||||
}
|
||||
|
||||
impl Ord for Range {
|
||||
impl Ord for CharRange {
|
||||
fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
|
||||
if self.start != other.start {
|
||||
self.start.cmp(&other.start)
|
||||
|
@ -100,7 +100,7 @@ impl Ord for Range {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Range {
|
||||
impl PartialOrd for CharRange {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
|
||||
if self.start != other.start {
|
||||
self.start.partial_cmp(&other.start)
|
||||
|
@ -249,7 +249,7 @@ fn merge_range_tree_children<'a>(
|
|||
Vec::with_capacity(parent_trees.len());
|
||||
let mut wrapped_children: Vec<Vec<&'a mut RangeTree<'a>>> =
|
||||
Vec::with_capacity(parent_trees.len());
|
||||
let mut open_range: Option<Range> = None;
|
||||
let mut open_range: Option<CharRange> = None;
|
||||
|
||||
for _parent_tree in parent_trees.iter() {
|
||||
flat_children.push(Vec::new());
|
||||
|
@ -318,7 +318,7 @@ fn merge_range_tree_children<'a>(
|
|||
.push(tree);
|
||||
}
|
||||
start_event_queue.set_pending_offset(open_range_end);
|
||||
open_range = Some(Range {
|
||||
open_range = Some(CharRange {
|
||||
start: event.offset,
|
||||
end: open_range_end,
|
||||
});
|
||||
|
@ -452,8 +452,8 @@ mod tests {
|
|||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 1,
|
||||
}],
|
||||
}],
|
||||
|
@ -467,8 +467,8 @@ mod tests {
|
|||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 2,
|
||||
}],
|
||||
}],
|
||||
|
@ -483,8 +483,8 @@ mod tests {
|
|||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 3,
|
||||
}],
|
||||
}],
|
||||
|
@ -506,13 +506,13 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 10,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 3,
|
||||
end_offset: 6,
|
||||
start_char_offset: 3,
|
||||
end_char_offset: 6,
|
||||
count: 1,
|
||||
},
|
||||
],
|
||||
|
@ -528,13 +528,13 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 20,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 3,
|
||||
end_offset: 6,
|
||||
start_char_offset: 3,
|
||||
end_char_offset: 6,
|
||||
count: 2,
|
||||
},
|
||||
],
|
||||
|
@ -551,13 +551,13 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 30,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 3,
|
||||
end_offset: 6,
|
||||
start_char_offset: 3,
|
||||
end_char_offset: 6,
|
||||
count: 3,
|
||||
},
|
||||
],
|
||||
|
@ -580,13 +580,13 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 10,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 2,
|
||||
end_offset: 5,
|
||||
start_char_offset: 2,
|
||||
end_char_offset: 5,
|
||||
count: 1,
|
||||
},
|
||||
],
|
||||
|
@ -602,13 +602,13 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 20,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 4,
|
||||
end_offset: 7,
|
||||
start_char_offset: 4,
|
||||
end_char_offset: 7,
|
||||
count: 2,
|
||||
},
|
||||
],
|
||||
|
@ -625,23 +625,23 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 30,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 2,
|
||||
end_offset: 5,
|
||||
start_char_offset: 2,
|
||||
end_char_offset: 5,
|
||||
count: 21,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 4,
|
||||
end_offset: 5,
|
||||
start_char_offset: 4,
|
||||
end_char_offset: 5,
|
||||
count: 3,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 5,
|
||||
end_offset: 7,
|
||||
start_char_offset: 5,
|
||||
end_char_offset: 7,
|
||||
count: 12,
|
||||
},
|
||||
],
|
||||
|
@ -664,23 +664,23 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 1,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 8,
|
||||
start_char_offset: 1,
|
||||
end_char_offset: 8,
|
||||
count: 6,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 5,
|
||||
start_char_offset: 1,
|
||||
end_char_offset: 5,
|
||||
count: 5,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 5,
|
||||
end_offset: 8,
|
||||
start_char_offset: 5,
|
||||
end_char_offset: 8,
|
||||
count: 7,
|
||||
},
|
||||
],
|
||||
|
@ -696,23 +696,23 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 4,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 8,
|
||||
start_char_offset: 1,
|
||||
end_char_offset: 8,
|
||||
count: 8,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 5,
|
||||
start_char_offset: 1,
|
||||
end_char_offset: 5,
|
||||
count: 9,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 5,
|
||||
end_offset: 8,
|
||||
start_char_offset: 5,
|
||||
end_char_offset: 8,
|
||||
count: 7,
|
||||
},
|
||||
],
|
||||
|
@ -729,13 +729,13 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 5,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 8,
|
||||
start_char_offset: 1,
|
||||
end_char_offset: 8,
|
||||
count: 14,
|
||||
},
|
||||
],
|
||||
|
@ -758,13 +758,13 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 7,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 7,
|
||||
count: 10,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 4,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 4,
|
||||
count: 1,
|
||||
},
|
||||
],
|
||||
|
@ -780,18 +780,18 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 7,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 7,
|
||||
count: 20,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 6,
|
||||
start_char_offset: 1,
|
||||
end_char_offset: 6,
|
||||
count: 11,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 2,
|
||||
end_offset: 5,
|
||||
start_char_offset: 2,
|
||||
end_char_offset: 5,
|
||||
count: 2,
|
||||
},
|
||||
],
|
||||
|
@ -808,23 +808,23 @@ mod tests {
|
|||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 7,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 7,
|
||||
count: 30,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 6,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 6,
|
||||
count: 21,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 5,
|
||||
start_char_offset: 1,
|
||||
end_char_offset: 5,
|
||||
count: 12,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 2,
|
||||
end_offset: 4,
|
||||
start_char_offset: 2,
|
||||
end_char_offset: 4,
|
||||
count: 3,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -202,16 +202,18 @@ fn generate_coverage_report(
|
|||
continue;
|
||||
}
|
||||
|
||||
let source_line_index =
|
||||
text_lines.line_index(function.ranges[0].start_offset);
|
||||
let dest_line_index = text_lines.line_index(
|
||||
text_lines
|
||||
.byte_index_from_char_index(function.ranges[0].start_char_offset),
|
||||
);
|
||||
let line_index = if let Some(source_map) = maybe_source_map.as_ref() {
|
||||
source_map
|
||||
.tokens()
|
||||
.find(|token| token.get_dst_line() as usize == source_line_index)
|
||||
.find(|token| token.get_dst_line() as usize == dest_line_index)
|
||||
.map(|token| token.get_src_line() as usize)
|
||||
.unwrap_or(0)
|
||||
} else {
|
||||
source_line_index
|
||||
dest_line_index
|
||||
};
|
||||
|
||||
coverage_report.named_functions.push(FunctionCoverageItem {
|
||||
|
@ -224,7 +226,9 @@ fn generate_coverage_report(
|
|||
for (block_number, function) in script_coverage.functions.iter().enumerate() {
|
||||
let block_hits = function.ranges[0].count;
|
||||
for (branch_number, range) in function.ranges[1..].iter().enumerate() {
|
||||
let source_line_index = text_lines.line_index(range.start_offset);
|
||||
let source_line_index = text_lines.line_index(
|
||||
text_lines.byte_index_from_char_index(range.start_char_offset),
|
||||
);
|
||||
let line_index = if let Some(source_map) = maybe_source_map.as_ref() {
|
||||
source_map
|
||||
.tokens()
|
||||
|
@ -264,11 +268,14 @@ fn generate_coverage_report(
|
|||
// parts of a line in color (word diff style) instead of the entire line.
|
||||
let mut line_counts = Vec::with_capacity(text_lines.lines_count());
|
||||
for line_index in 0..text_lines.lines_count() {
|
||||
let line_start_offset = text_lines.line_start(line_index);
|
||||
let line_end_offset = text_lines.line_end(line_index);
|
||||
let line_start_byte_offset = text_lines.line_start(line_index);
|
||||
let line_start_char_offset = text_lines.char_index(line_start_byte_offset);
|
||||
let line_end_byte_offset = text_lines.line_end(line_index);
|
||||
let line_end_char_offset = text_lines.char_index(line_end_byte_offset);
|
||||
let ignore = comment_ranges.iter().any(|range| {
|
||||
range.start <= line_start_offset && range.end >= line_end_offset
|
||||
}) || script_source[line_start_offset..line_end_offset]
|
||||
range.start <= line_start_byte_offset && range.end >= line_end_byte_offset
|
||||
}) || script_source
|
||||
[line_start_byte_offset..line_end_byte_offset]
|
||||
.trim()
|
||||
.is_empty();
|
||||
let mut count = 0;
|
||||
|
@ -280,8 +287,8 @@ fn generate_coverage_report(
|
|||
// as long as the code has been evaluated.
|
||||
for function in &script_coverage.functions {
|
||||
for range in &function.ranges {
|
||||
if range.start_offset <= line_start_offset
|
||||
&& range.end_offset >= line_end_offset
|
||||
if range.start_char_offset <= line_start_char_offset
|
||||
&& range.end_char_offset >= line_end_char_offset
|
||||
{
|
||||
count += range.count;
|
||||
}
|
||||
|
@ -295,8 +302,8 @@ fn generate_coverage_report(
|
|||
continue;
|
||||
}
|
||||
|
||||
let overlaps = range.start_offset < line_end_offset
|
||||
&& range.end_offset > line_start_offset;
|
||||
let overlaps = range.start_char_offset < line_end_char_offset
|
||||
&& range.end_char_offset > line_start_char_offset;
|
||||
if overlaps {
|
||||
count = 0;
|
||||
}
|
||||
|
|
|
@ -134,8 +134,8 @@ impl<'rt> RangeTree<'rt> {
|
|||
while let Some((cur, parent_count)) = stack.pop() {
|
||||
let count: i64 = parent_count + cur.delta;
|
||||
ranges.push(CoverageRange {
|
||||
start_offset: cur.start,
|
||||
end_offset: cur.end,
|
||||
start_char_offset: cur.start,
|
||||
end_char_offset: cur.end,
|
||||
count,
|
||||
});
|
||||
for child in cur.children.iter().rev() {
|
||||
|
@ -165,14 +165,14 @@ impl<'rt> RangeTree<'rt> {
|
|||
) -> Option<&'a mut RangeTree<'a>> {
|
||||
let has_range: bool = match ranges.peek() {
|
||||
None => false,
|
||||
Some(range) => range.start_offset < parent_end,
|
||||
Some(range) => range.start_char_offset < parent_end,
|
||||
};
|
||||
if !has_range {
|
||||
return None;
|
||||
}
|
||||
let range = ranges.next().unwrap();
|
||||
let start: usize = range.start_offset;
|
||||
let end: usize = range.end_offset;
|
||||
let start: usize = range.start_char_offset;
|
||||
let end: usize = range.end_char_offset;
|
||||
let count: i64 = range.count;
|
||||
let delta: i64 = count - parent_count;
|
||||
let mut children: Vec<&mut RangeTree> = Vec::new();
|
||||
|
@ -193,8 +193,8 @@ mod tests {
|
|||
fn from_sorted_ranges_empty() {
|
||||
let rta = RangeTreeArena::new();
|
||||
let inputs: Vec<CoverageRange> = vec![CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
start_char_offset: 0,
|
||||
end_char_offset: 9,
|
||||
count: 1,
|
||||
}];
|
||||
let actual: Option<&mut RangeTree> =
|
||||
|
|
Loading…
Add table
Reference in a new issue