Skip to content

Commit c285005

Browse files
committed
Add a new test_utils::test_expected() helper function
This helper function makes it easy to write tests verifying that a patch produces expected results. In a test subdirectory you can now check in a `patch.yaml` file and an `expected.svd`, and then write a 1-line test to call `test_expected()` for this subdirectory. If the patch results do not match the expected contents, the error message will contain a unified diff of the mismatching contents. I included a simple test of the clustering behavior as an example.
1 parent 763135a commit c285005

File tree

7 files changed

+269
-2
lines changed

7 files changed

+269
-2
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,5 @@ itertools = "0.12.0"
5151
phf = { version = "0.11", features = ["macros"] }
5252

5353
[dev-dependencies]
54+
similar = "2.5.0"
5455
tempfile = "3.3"

res/cluster/esp32s3.svd

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?xml version="1.0" encoding="utf-8" standalone="no"?>
2+
<device schemaVersion="1.1"
3+
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
4+
xs:noNamespaceSchemaLocation="CMSIS-SVD_Schema_1_1.xsd">
5+
<name>ESP32S3</name>
6+
<peripherals>
7+
<peripheral>
8+
<name>USB0</name>
9+
<description>USB OTG (On-The-Go)</description>
10+
<groupName>USB</groupName>
11+
<baseAddress>0x60080000</baseAddress>
12+
<addressBlock>
13+
<offset>0x0</offset>
14+
<size>0x2A0</size>
15+
<usage>registers</usage>
16+
</addressBlock>
17+
<registers>
18+
<register>
19+
<name>DIEPCTL0</name>
20+
<addressOffset>0x900</addressOffset>
21+
<size>0x20</size>
22+
<resetValue>0x00008000</resetValue>
23+
<fields>
24+
<field>
25+
<name>D_MPS0</name>
26+
<bitOffset>0</bitOffset>
27+
<bitWidth>2</bitWidth>
28+
<access>read-write</access>
29+
</field>
30+
</fields>
31+
</register>
32+
<register>
33+
<name>DIEPINT0</name>
34+
<addressOffset>0x908</addressOffset>
35+
<size>0x20</size>
36+
<fields>
37+
<field>
38+
<name>D_XFERCOMPL0</name>
39+
<bitOffset>0</bitOffset>
40+
<bitWidth>1</bitWidth>
41+
<access>read-write</access>
42+
</field>
43+
</fields>
44+
</register>
45+
<register>
46+
<name>DIEPCTL1</name>
47+
<addressOffset>0x920</addressOffset>
48+
<size>0x20</size>
49+
<resetValue>0x00008000</resetValue>
50+
<fields>
51+
<field>
52+
<name>D_MPS1</name>
53+
<bitOffset>0</bitOffset>
54+
<bitWidth>11</bitWidth>
55+
<access>read-write</access>
56+
</field>
57+
</fields>
58+
</register>
59+
<register>
60+
<name>DIEPINT1</name>
61+
<addressOffset>0x928</addressOffset>
62+
<size>0x20</size>
63+
<fields>
64+
<field>
65+
<name>D_XFERCOMPL1</name>
66+
<bitOffset>0</bitOffset>
67+
<bitWidth>1</bitWidth>
68+
<access>read-write</access>
69+
</field>
70+
</fields>
71+
</register>
72+
<register>
73+
<name>DIEPCTL2</name>
74+
<addressOffset>0x940</addressOffset>
75+
<size>0x20</size>
76+
<resetValue>0x00008000</resetValue>
77+
<fields>
78+
<field>
79+
<name>D_MPS2</name>
80+
<bitOffset>0</bitOffset>
81+
<bitWidth>11</bitWidth>
82+
<access>read-write</access>
83+
</field>
84+
</fields>
85+
</register>
86+
<register>
87+
<name>DIEPINT2</name>
88+
<addressOffset>0x948</addressOffset>
89+
<size>0x20</size>
90+
<fields>
91+
<field>
92+
<name>D_XFERCOMPL2</name>
93+
<bitOffset>0</bitOffset>
94+
<bitWidth>1</bitWidth>
95+
<access>read-write</access>
96+
</field>
97+
</fields>
98+
</register>
99+
</registers>
100+
</peripheral>
101+
</peripherals>
102+
</device>

res/cluster/expected.svd

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?xml version="1.0" encoding="utf-8" standalone="no"?>
2+
<device schemaVersion="1.1"
3+
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
4+
xs:noNamespaceSchemaLocation="CMSIS-SVD_Schema_1_1.xsd">
5+
<name>ESP32S3</name>
6+
<peripherals>
7+
<peripheral>
8+
<name>USB0</name>
9+
<description>USB OTG (On-The-Go)</description>
10+
<groupName>USB</groupName>
11+
<baseAddress>0x60080000</baseAddress>
12+
<addressBlock>
13+
<offset>0x0</offset>
14+
<size>0x2A0</size>
15+
<usage>registers</usage>
16+
</addressBlock>
17+
<registers>
18+
<cluster>
19+
<name>IN_EP0</name>
20+
<description>Device IN Endpoint 0</description>
21+
<addressOffset>0x900</addressOffset>
22+
<register>
23+
<name>DIEPCTL</name>
24+
<addressOffset>0x0</addressOffset>
25+
<size>0x20</size>
26+
<resetValue>0x00008000</resetValue>
27+
<fields>
28+
<field>
29+
<name>MPS</name>
30+
<bitOffset>0</bitOffset>
31+
<bitWidth>2</bitWidth>
32+
<access>read-write</access>
33+
</field>
34+
</fields>
35+
</register>
36+
<register>
37+
<name>DIEPINT</name>
38+
<addressOffset>0x8</addressOffset>
39+
<size>0x20</size>
40+
<fields>
41+
<field>
42+
<name>XFERCOMPL</name>
43+
<bitOffset>0</bitOffset>
44+
<bitWidth>1</bitWidth>
45+
<access>read-write</access>
46+
</field>
47+
</fields>
48+
</register>
49+
</cluster>
50+
<cluster>
51+
<dim>2</dim>
52+
<dimIncrement>0x20</dimIncrement>
53+
<dimIndex>1-2</dimIndex>
54+
<name>IN_EP%s</name>
55+
<description>Device IN Endpoints 1-6</description>
56+
<addressOffset>0x920</addressOffset>
57+
<register>
58+
<name>DIEPCTL</name>
59+
<addressOffset>0x0</addressOffset>
60+
<size>0x20</size>
61+
<resetValue>0x00008000</resetValue>
62+
<fields>
63+
<field>
64+
<name>MPS</name>
65+
<bitOffset>0</bitOffset>
66+
<bitWidth>11</bitWidth>
67+
<access>read-write</access>
68+
</field>
69+
</fields>
70+
</register>
71+
<register>
72+
<name>DIEPINT</name>
73+
<addressOffset>0x8</addressOffset>
74+
<size>0x20</size>
75+
<fields>
76+
<field>
77+
<name>XFERCOMPL</name>
78+
<bitOffset>0</bitOffset>
79+
<bitWidth>1</bitWidth>
80+
<access>read-write</access>
81+
</field>
82+
</fields>
83+
</register>
84+
</cluster>
85+
</registers>
86+
</peripheral>
87+
</peripherals>
88+
</device>

res/cluster/patch.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
_svd: esp32s3.svd
2+
3+
USB0:
4+
_cluster:
5+
IN_EP0:
6+
description: "Device IN Endpoint 0"
7+
DIEPCTL0:
8+
name: DIEPCTL
9+
_modify:
10+
D_MPS0:
11+
name: MPS
12+
DIEPINT0:
13+
name: DIEPINT
14+
_modify:
15+
D_XFERCOMPL0:
16+
name: XFERCOMPL
17+
IN_EP%s:
18+
description: "Device IN Endpoints 1-6"
19+
DIEPCTL[1-6]:
20+
name: DIEPCTL
21+
_modify:
22+
D_MPS1:
23+
name: MPS
24+
DIEPINT[1-6]:
25+
name: DIEPINT
26+
_modify:
27+
D_XFERCOMPL1:
28+
name: XFERCOMPL

src/patch/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use yaml_rust::{yaml::Hash, Yaml, YamlLoader};
2020
use anyhow::{anyhow, Context, Result};
2121
pub type PatchResult = anyhow::Result<()>;
2222

23-
mod device;
23+
pub(crate) mod device;
2424
use device::DeviceExt;
2525
mod iterators;
2626
mod peripheral;

src/patch/peripheral.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,3 +1498,15 @@ fn collect_in_cluster(
14981498
regs.insert(place, RegisterCluster::Cluster(cluster));
14991499
Ok(())
15001500
}
1501+
1502+
#[cfg(test)]
1503+
mod tests {
1504+
use crate::test_utils;
1505+
use anyhow::Result;
1506+
use std::path::Path;
1507+
1508+
#[test]
1509+
fn cluster() -> Result<()> {
1510+
test_utils::test_expected(Path::new("cluster"))
1511+
}
1512+
}

src/test_utils.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use anyhow::{anyhow, Result};
1+
use crate::patch::device::DeviceExt;
2+
use anyhow::{anyhow, Context, Result};
23
use std::fs::File;
34
use std::io::Read;
45
use std::path::{Path, PathBuf};
@@ -37,6 +38,41 @@ pub fn get_patcher(test_subdir: &Path) -> Result<(Device, Hash)> {
3738
Ok((device, yaml.clone()))
3839
}
3940

41+
/// Execute the test found in the specified res/ subdirectory.
42+
///
43+
/// This runs the patch.yaml file in the specified subdirectory, and checks
44+
/// that the results match the expected contents found in the expected.svd file.
45+
pub fn test_expected(test_subdir: &Path) -> Result<()> {
46+
// Run the patch
47+
let (mut device, yaml) = get_patcher(test_subdir)?;
48+
device
49+
.process(&yaml, &Default::default())
50+
.context("processing patch.yaml")?;
51+
52+
// Load the expected contents
53+
let expected_file = res_dir().join(test_subdir.join("expected.svd"));
54+
let f = File::open(&expected_file)
55+
.with_context(|| format!("opening {}", expected_file.display()))?;
56+
let mut contents = String::new();
57+
(&f).read_to_string(&mut contents)?;
58+
let expected = svd_parser::parse(&contents)
59+
.with_context(|| format!("parsing {}", expected_file.display()))?;
60+
61+
if device != expected {
62+
// Include a diff of the changes in the error
63+
let config = svd_encoder::Config::default();
64+
let dev_text = svd_encoder::encode_with_config(&device, &config)?;
65+
let expected_text = svd_encoder::encode_with_config(&expected, &config)?;
66+
let diff = similar::TextDiff::from_lines(&expected_text, &dev_text);
67+
Err(anyhow!(
68+
"patch did not produce expected results:\n{}",
69+
diff.unified_diff()
70+
))
71+
} else {
72+
Ok(())
73+
}
74+
}
75+
4076
/// Gets the absolute path of relpath from the point of view of frompath.
4177
fn abspath(frompath: &Path, relpath: &Path) -> PathBuf {
4278
normpath::BasePath::new(frompath)

0 commit comments

Comments
 (0)