summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2022-07-11 19:02:11 -0400
committerGitHub <noreply@github.com>2022-07-11 19:02:11 -0400
commit82431062fa6dd82679e1903dda4e33103a0299da (patch)
tree1b0c0784bba6d7e767110b352a6616020f962d58
parentb68115db3a7c87518c59e6db7fa0ca2f1e3b4ca7 (diff)
fix(coverage): better handling of multi-byte characters (#15159)
-rw-r--r--Cargo.lock14
-rw-r--r--cli/Cargo.toml2
-rw-r--r--cli/tests/testdata/coverage/complex_expected.lcov4
-rw-r--r--cli/tests/testdata/coverage/complex_expected.out3
-rw-r--r--cli/tools/coverage/json_types.rs10
-rw-r--r--cli/tools/coverage/merge.rs162
-rw-r--r--cli/tools/coverage/mod.rs33
-rw-r--r--cli/tools/coverage/range_tree.rs14
8 files changed, 129 insertions, 113 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 46d6a3633..302fb63d3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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]]
@@ -4581,6 +4581,12 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index f86ec4ea2..83eb7666d 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -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"
diff --git a/cli/tests/testdata/coverage/complex_expected.lcov b/cli/tests/testdata/coverage/complex_expected.lcov
index 1bb79d277..7a3cd8d92 100644
--- a/cli/tests/testdata/coverage/complex_expected.lcov
+++ b/cli/tests/testdata/coverage/complex_expected.lcov
@@ -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
diff --git a/cli/tests/testdata/coverage/complex_expected.out b/cli/tests/testdata/coverage/complex_expected.out
index e318e2067..3f7c89e9b 100644
--- a/cli/tests/testdata/coverage/complex_expected.out
+++ b/cli/tests/testdata/coverage/complex_expected.out
@@ -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);
diff --git a/cli/tools/coverage/json_types.rs b/cli/tools/coverage/json_types.rs
index 1e46cc7fd..6da17d58f 100644
--- a/cli/tools/coverage/json_types.rs
+++ b/cli/tools/coverage/json_types.rs
@@ -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,
}
diff --git a/cli/tools/coverage/merge.rs b/cli/tools/coverage/merge.rs
index b0606e215..08a695e1d 100644
--- a/cli/tools/coverage/merge.rs
+++ b/cli/tools/coverage/merge.rs
@@ -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,
},
],
diff --git a/cli/tools/coverage/mod.rs b/cli/tools/coverage/mod.rs
index 0b1a9bc35..bba7271f5 100644
--- a/cli/tools/coverage/mod.rs
+++ b/cli/tools/coverage/mod.rs
@@ -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;
}
diff --git a/cli/tools/coverage/range_tree.rs b/cli/tools/coverage/range_tree.rs
index 24d0a9ffc..aca8939ee 100644
--- a/cli/tools/coverage/range_tree.rs
+++ b/cli/tools/coverage/range_tree.rs
@@ -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> =