Skip to content
This repository was archived by the owner on Nov 1, 2023. It is now read-only.

Commit 04f83e0

Browse files
authored
Add lines key to v1 source coverage JSON (#2718)
1 parent 4dbc9c0 commit 04f83e0

File tree

6 files changed

+112
-7
lines changed

6 files changed

+112
-7
lines changed

src/agent/coverage/src/source.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ use crate::binary::BinaryCoverage;
1515

1616
pub use crate::binary::Count;
1717

18-
#[derive(Clone, Debug, Default)]
18+
#[derive(Clone, Debug, Default, Eq, PartialEq)]
1919
pub struct SourceCoverage {
2020
pub files: BTreeMap<FilePath, FileCoverage>,
2121
}
2222

23-
#[derive(Clone, Debug, Default)]
23+
#[derive(Clone, Debug, Default, Eq, PartialEq)]
2424
pub struct FileCoverage {
2525
pub lines: BTreeMap<Line, Count>,
2626
}

src/agent/onefuzz-file-format/src/coverage/source/v1.rs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,18 @@ use debuggable_module::path::FilePath;
99
use serde::{Deserialize, Serialize};
1010

1111
pub type SourceFile = String;
12-
pub type LineNumber = u32;
1312
pub type HitCount = u32;
13+
pub use line_number::LineNumber;
1414

1515
#[derive(Deserialize, Serialize)]
1616
pub struct SourceCoverageJson {
1717
#[serde(flatten)]
18-
pub modules: BTreeMap<SourceFile, BTreeMap<LineNumber, HitCount>>,
18+
pub files: BTreeMap<SourceFile, FileCoverageJson>,
19+
}
20+
21+
#[derive(Deserialize, Serialize)]
22+
pub struct FileCoverageJson {
23+
pub lines: BTreeMap<LineNumber, HitCount>,
1924
}
2025

2126
impl TryFrom<SourceCoverageJson> for SourceCoverage {
@@ -24,13 +29,13 @@ impl TryFrom<SourceCoverageJson> for SourceCoverage {
2429
fn try_from(json: SourceCoverageJson) -> Result<Self> {
2530
let mut source = SourceCoverage::default();
2631

27-
for (file_path, lines) in json.modules {
32+
for (file_path, file_json) in json.files {
2833
let file_path = FilePath::new(file_path)?;
2934

3035
let mut file = FileCoverage::default();
3136

32-
for (line, count) in lines {
33-
let line = Line::new(line)?;
37+
for (line_number, count) in file_json.lines {
38+
let line = Line::new(line_number.0)?;
3439
let count = Count(count);
3540
file.lines.insert(line, count);
3641
}
@@ -41,3 +46,26 @@ impl TryFrom<SourceCoverageJson> for SourceCoverage {
4146
Ok(source)
4247
}
4348
}
49+
50+
mod line_number {
51+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
52+
53+
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
54+
pub struct LineNumber(#[serde(with = "self")] pub u32);
55+
56+
pub fn serialize<S>(val: &u32, serializer: S) -> Result<S::Ok, S::Error>
57+
where
58+
S: Serializer,
59+
{
60+
let s = format!("{}", val);
61+
serializer.serialize_str(&s)
62+
}
63+
64+
pub fn deserialize<'de, D>(deserializer: D) -> Result<u32, D::Error>
65+
where
66+
D: Deserializer<'de>,
67+
{
68+
let s = String::deserialize(deserializer)?;
69+
s.parse().map_err(serde::de::Error::custom)
70+
}
71+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[
2+
{
3+
"file": "src/bin/main.c",
4+
"locations": [
5+
{ "line": 4, "column": 1, "count": 1 },
6+
{ "line": 9, "column": 2, "count": 0 },
7+
{ "line": 12, "column": 3, "count": 5 }
8+
]
9+
},
10+
{
11+
"file": "src/lib/common.c",
12+
"locations": [
13+
{ "line": 5, "column": null, "count": 0 },
14+
{ "line": 5, "column": null, "count": 1 },
15+
{ "line": 8, "column": null, "count": 0 }
16+
]
17+
}
18+
]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"src/bin/main.c": {
3+
"lines": {
4+
"4": 1,
5+
"9": 0,
6+
"12": 5
7+
}
8+
},
9+
"src/lib/common.c": {
10+
"lines": {
11+
"5": 1,
12+
"8": 0
13+
}
14+
}
15+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
use pretty_assertions::assert_eq;
5+
6+
use anyhow::Result;
7+
use coverage::source::{Count, Line, SourceCoverage};
8+
use debuggable_module::path::FilePath;
9+
use onefuzz_file_format::coverage::source::{v0, v1};
10+
11+
fn expected_source_coverage() -> Result<SourceCoverage> {
12+
let main_path = FilePath::new("src/bin/main.c")?;
13+
let common_path = FilePath::new("src/lib/common.c")?;
14+
15+
let mut source = SourceCoverage::default();
16+
17+
let main = source.files.entry(main_path).or_default();
18+
main.lines.insert(Line::new(4)?, Count(1));
19+
main.lines.insert(Line::new(9)?, Count(0));
20+
main.lines.insert(Line::new(12)?, Count(5));
21+
22+
let common = source.files.entry(common_path).or_default();
23+
common.lines.insert(Line::new(5)?, Count(1));
24+
common.lines.insert(Line::new(8)?, Count(0));
25+
26+
Ok(source)
27+
}
28+
29+
#[test]
30+
fn test_source_coverage_formats() -> Result<()> {
31+
let expected = expected_source_coverage()?;
32+
33+
let v0_text = include_str!("files/source-coverage.v0.json");
34+
let v0_json: v0::SourceCoverageJson = serde_json::from_str(v0_text)?;
35+
let from_v0 = SourceCoverage::try_from(v0_json)?;
36+
assert_eq!(from_v0, expected);
37+
38+
let v1_text = include_str!("files/source-coverage.v1.json");
39+
let v1_json: v1::SourceCoverageJson = serde_json::from_str(v1_text)?;
40+
let from_v1 = SourceCoverage::try_from(v1_json)?;
41+
assert_eq!(from_v1, expected);
42+
43+
Ok(())
44+
}

0 commit comments

Comments
 (0)