Skip to content

Commit 22ffac5

Browse files
committed
comments update
1 parent 537e01f commit 22ffac5

File tree

2 files changed

+78
-80
lines changed

2 files changed

+78
-80
lines changed

crates/powerlink-rs-xdc/tests/parsing.rs

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
// crates/powerlink-rs-xdc/tests/parsing.rs
1+
//! Integration tests for full XDC/XDD file parsing and round-trip serialization.
2+
//!
3+
//! These tests validate that real-world (or mock real-world) XML files are
4+
//! parsed correctly into the public `XdcFile` structure and can be serialized
5+
//! back to XML without data loss.
26
37
use powerlink_rs_xdc::{
4-
ParameterAccess, load_xdc_from_str, load_xdd_defaults_from_str, save_xdc_to_string,
8+
load_xdc_from_str, load_xdd_defaults_from_str, save_xdc_to_string, ParameterAccess,
59
};
610
use std::fs;
711
use std::path::PathBuf;
@@ -17,82 +21,81 @@ fn load_test_file(name: &str) -> String {
1721
.unwrap_or_else(|e| panic!("Failed to read test file {:?}: {}", path, e))
1822
}
1923

20-
/// This test validates that the resolver correctly loads data from the
21-
/// <ApplicationProcess> block and applies it to the <ObjectList>
22-
/// by resolving the `uniqueIDRef`.
24+
/// Validates that the resolver correctly loads data from the `<ApplicationProcess>`
25+
/// block and applies it to the `<ObjectList>` via `uniqueIDRef`.
2326
#[test]
2427
fn test_resolve_extended_app_process() {
2528
let xml_content = load_test_file("MyDevice_extended.xdd");
29+
// Load as XDD (use defaults)
2630
let xdc_file = load_xdd_defaults_from_str(&xml_content).expect("Failed to parse extended XDD");
2731

28-
// 1. Find the Object Dictionary
2932
let od = &xdc_file.object_dictionary;
3033

31-
// 2. Find Object 0x2100, which references "ID_Parameter1"
34+
// 1. Find Object 0x2100, which references "ID_Parameter1"
3235
let obj_2100 = od
3336
.objects
3437
.iter()
3538
.find(|o| o.index == 0x2100)
3639
.expect("Failed to find object 0x2100");
3740

38-
// 3. Assert that its attributes were resolved from "ID_Parameter1"
41+
// 2. Assert that its attributes were resolved from "ID_Parameter1"
3942
assert_eq!(obj_2100.name, "ExampleSimpleParameter_U8");
4043
assert_eq!(
4144
obj_2100.access_type,
4245
Some(ParameterAccess::ReadWrite),
4346
"Access type was not resolved from <parameter>"
4447
);
45-
// Assert that the `defaultValue` ("15") was correctly parsed and resolved
46-
// from the <parameter> (as USINT, "0005").
47-
// UPDATED: We now expect the string "15" directly from the XML.
48+
// Assert that the `defaultValue` ("15") was correctly parsed from the <parameter>.
4849
assert_eq!(
4950
obj_2100.data.as_deref(),
5051
Some("15"),
5152
"defaultValue was not resolved from <parameter>"
5253
);
5354

54-
// 4. Find Object 0x2101, which references "ID_Parameter2" (a struct)
55+
// 3. Find Object 0x2101, which references "ID_Parameter2" (a struct)
5556
let obj_2101 = od
5657
.objects
5758
.iter()
5859
.find(|o| o.index == 0x2101)
5960
.expect("Failed to find object 0x2101");
6061

61-
// Assert its attributes were resolved
6262
assert_eq!(obj_2101.name, "ExampleStructure_DOM");
6363
assert_eq!(
6464
obj_2101.access_type,
6565
Some(ParameterAccess::ReadWrite),
6666
"Access type was not resolved from <parameter>"
6767
);
68-
// The parameter itself has no value, so the data should be None
68+
// The parameter itself has no value, so data should be None
6969
assert_eq!(obj_2101.data, None);
7070
}
7171

72-
/// This test validates the full "round-trip" capability.
73-
/// 1. Load XDD (from `defaultValue`)
74-
/// 2. Save to string (as XDC, serializing data as `actualValue`)
75-
/// 3. Load the new string (from `actualValue`)
76-
/// 4. Assert the two resulting structs are identical.
72+
/// Validates the full "round-trip" capability.
73+
///
74+
/// 1. Load an XDD file (parsing `defaultValue`).
75+
/// 2. Serialize it back to a string (generating valid XDC XML).
76+
/// 3. Load that new string back in.
77+
/// 4. Assert the internal structures match.
7778
#[test]
7879
fn test_round_trip_static_xdd() {
79-
// 1. Load the original XDD, parsing `defaultValue`
80+
// 1. Load original XDD
8081
let xdd_content = load_test_file("MyDevice_static.xdd");
8182
let file1 =
8283
load_xdd_defaults_from_str(&xdd_content).expect("Failed to parse original static XDD");
8384

84-
// 2. Save it back to a new XDC-style string
85-
// This converts `file1.data` (from `defaultValue`) into `actualValue` attributes.
85+
// 2. Serialize to string
8686
let xdc_string_new = save_xdc_to_string(&file1).expect("Failed to serialize XDC to string");
8787

88-
// 3. Load the *new* string, parsing `actualValue`
88+
// 3. Load the new string
89+
// Note: `save_xdc_to_string` generally writes values to `actualValue` fields
90+
// if loaded from XDC, or preserves source structure.
91+
// For this test, we use `load_xdc_from_str` to read the result.
8992
let file2 = load_xdc_from_str(&xdc_string_new).expect("Failed to parse newly serialized XDC");
9093

91-
// 4. Detailed Comparisons for Debugging
94+
// 4. Detailed Comparisons
9295
assert_eq!(file1.header, file2.header, "Header mismatch");
9396
assert_eq!(file1.identity, file2.identity, "Identity mismatch");
9497

95-
// Check NetworkManagement specifically
98+
// Check NetworkManagement
9699
if let (Some(nm1), Some(nm2)) = (&file1.network_management, &file2.network_management) {
97100
assert_eq!(
98101
nm1.general_features, nm2.general_features,
@@ -141,7 +144,7 @@ fn test_round_trip_static_xdd() {
141144
assert_eq!(file1, file2, "XdcFile structs mismatch after round-trip");
142145
}
143146

144-
/// This test simply ensures the minimal "dynamic" XDD parses correctly.
147+
/// Validates that the minimal "dynamic" XDD parses correctly.
145148
#[test]
146149
fn test_load_dynamic_xdd() {
147150
let xml_content = load_test_file("MyDevice.xdd");
@@ -162,7 +165,5 @@ fn test_load_dynamic_xdd() {
162165
.expect("Object 0x1F82 not found");
163166

164167
assert_eq!(flags_obj.name, "NMT_FeatureFlags_U32");
165-
// `defaultValue="0x00000045"`
166-
// UPDATED: We now expect the string "0x00000045" directly from the XML.
167168
assert_eq!(flags_obj.data.as_deref(), Some("0x00000045"));
168-
}
169+
}

crates/powerlink-rs-xdc/tests/robustness.rs

Lines changed: 48 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
// crates/powerlink-rs-xdc/tests/robustness.rs
1+
//! Integration tests focused on error handling and edge cases.
2+
//!
3+
//! These tests ensure the parser correctly identifies and reports errors for
4+
//! malformed XML, invalid attributes, missing mandatory elements, and data type
5+
//! mismatches, without panicking.
26
37
use powerlink_rs_xdc::{load_xdc_from_str, to_core_od, XdcError};
48

5-
/// A minimal valid XDC template to be corrupted by tests.
9+
/// A minimal valid XDC template used as a base for creating corrupted test cases.
610
const MINIMAL_VALID_XML: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
711
<ISO15745ProfileContainer xmlns="http://www.ethernet-powerlink.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ethernet-powerlink.org Powerlink_Main.xsd">
812
<ISO15745Profile>
@@ -57,7 +61,7 @@ const MINIMAL_VALID_XML: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
5761
</ISO15745Profile>
5862
</ISO15745ProfileContainer>"#;
5963

60-
/// Test that the parser catches malformed XML syntax (e.g. unclosed tags).
64+
/// Verifies that the parser catches malformed XML syntax (e.g., unclosed tags).
6165
#[test]
6266
fn test_malformed_xml_syntax() {
6367
let xml = r#"<ISO15745ProfileContainer><ProfileHeader> ... missing closing tags"#;
@@ -69,7 +73,7 @@ fn test_malformed_xml_syntax() {
6973
);
7074
}
7175

72-
/// Test that the resolver catches invalid hex strings in the `index` attribute.
76+
/// Verifies that the resolver catches invalid hex strings in the `index` attribute.
7377
#[test]
7478
fn test_invalid_index_hex() {
7579
// Inject an invalid index "ZZZZ"
@@ -88,13 +92,15 @@ fn test_invalid_index_hex() {
8892
);
8993
}
9094

91-
/// Test that the resolver handles missing ApplicationLayers gracefully or returns error.
92-
/// In our implementation, `resolver/mod.rs` explicitly checks for this.
95+
/// Verifies that the resolver requires the `ApplicationLayers` block in the Communication Profile.
9396
#[test]
9497
fn test_missing_application_layers() {
9598
// Remove the ApplicationLayers block
9699
let start = MINIMAL_VALID_XML.find("<ApplicationLayers>").unwrap();
97-
let end = MINIMAL_VALID_XML.find("</ApplicationLayers>").unwrap() + "</ApplicationLayers>".len();
100+
let end = MINIMAL_VALID_XML
101+
.find("</ApplicationLayers>")
102+
.unwrap()
103+
+ "</ApplicationLayers>".len();
98104
let mut xml = MINIMAL_VALID_XML.to_string();
99105
xml.replace_range(start..end, "");
100106

@@ -111,17 +117,19 @@ fn test_missing_application_layers() {
111117
);
112118
}
113119

114-
/// Test that the `converter` (to core OD) handles invalid data values gracefully.
115-
/// e.g. "INVALID" for a Unsigned16.
120+
/// Verifies that the `converter` (to core OD) handles invalid data values gracefully.
121+
///
122+
/// The parser loads the string as-is, but the converter must fail if the string
123+
/// cannot be parsed into the target native type.
116124
#[test]
117125
fn test_data_type_conversion_failure() {
118126
// Inject invalid data "NOT_HEX" for U16 type
119127
let xml = MINIMAL_VALID_XML.replace(r#"actualValue="0x1234""#, r#"actualValue="NOT_HEX""#);
120-
121-
// 1. Load should succeed (the parser stores it as a String, which is valid XML).
128+
129+
// 1. Load should succeed (the parser stores it as a String).
122130
let xdc_file = load_xdc_from_str(&xml).expect("Parser should handle raw strings");
123131

124-
// 2. Conversion to Core OD should FAIL because "NOT_HEX" cannot become U16.
132+
// 2. Conversion to Core OD should FAIL.
125133
let core_result = to_core_od(&xdc_file);
126134

127135
assert!(
@@ -136,31 +144,30 @@ fn test_data_type_conversion_failure() {
136144
);
137145
}
138146

139-
/// Test that the `converter` handles boolean parsing correctly (true/false/1/0).
147+
/// Verifies that the `converter` handles boolean parsing correctly across variants.
140148
#[test]
141149
fn test_boolean_conversion_variants() {
142-
// Prepare an XML with a Boolean object
143150
let base_xml = MINIMAL_VALID_XML.replace(
144151
r#"<defType dataType="0006"><Unsigned16/></defType>"#,
145-
r#"<defType dataType="0001"><Boolean/></defType>"#
152+
r#"<defType dataType="0001"><Boolean/></defType>"#,
146153
).replace(
147154
r#"dataType="0006" actualValue="0x1234""#,
148-
r#"dataType="0001" actualValue="REPLACE_ME""#
155+
r#"dataType="0001" actualValue="REPLACE_ME""#,
149156
);
150157

151-
// Case 1: "true"
158+
// Case 1: "true" -> 1
152159
let xml_true = base_xml.replace("REPLACE_ME", "true");
153160
let file_true = load_xdc_from_str(&xml_true).unwrap();
154161
let od_true = to_core_od(&file_true).unwrap();
155162
let val_true = od_true.read_object(0x1000).unwrap();
156-
// Core OD stores Boolean as u8 (1 or 0)
163+
157164
if let powerlink_rs::od::Object::Variable(powerlink_rs::od::ObjectValue::Boolean(v)) = val_true {
158165
assert_eq!(*v, 1);
159166
} else {
160167
panic!("Expected Boolean(1)");
161168
}
162169

163-
// Case 2: "0"
170+
// Case 2: "0" -> 0
164171
let xml_zero = base_xml.replace("REPLACE_ME", "0");
165172
let file_zero = load_xdc_from_str(&xml_zero).unwrap();
166173
let od_zero = to_core_od(&file_zero).unwrap();
@@ -171,63 +178,62 @@ fn test_boolean_conversion_variants() {
171178
panic!("Expected Boolean(0)");
172179
}
173180

174-
// Case 3: Invalid "yes"
181+
// Case 3: Invalid "yes" -> Error
175182
let xml_invalid = base_xml.replace("REPLACE_ME", "yes");
176183
let file_invalid = load_xdc_from_str(&xml_invalid).unwrap();
177184
let res_invalid = to_core_od(&file_invalid);
178185
assert!(matches!(res_invalid, Err(XdcError::InvalidAttributeFormat { .. })));
179186
}
180187

181-
/// Test resilience against broken `uniqueIDRef` links.
182-
/// The resolver should currently ignore broken links (fail-open) or handle them without panic.
188+
/// Verifies resilience against broken `uniqueIDRef` links.
189+
///
190+
/// The resolver should treat broken links as "no value found" rather than panicking.
183191
#[test]
184192
fn test_broken_parameter_reference() {
185-
// Inject a uniqueIDRef that doesn't exist
186193
let xml = MINIMAL_VALID_XML.replace(
187194
r#"<Object index="1000" name="Device Type" objectType="7" dataType="0006" actualValue="0x1234" />"#,
188195
r#"<Object index="1000" name="Device Type" objectType="7" uniqueIDRef="NON_EXISTENT_ID" />"#
189196
);
190197

191198
let result = load_xdc_from_str(&xml);
192199
assert!(result.is_ok(), "Parser should not panic on broken ref");
193-
200+
194201
let file = result.unwrap();
195202
let obj = &file.object_dictionary.objects[0];
196-
203+
197204
// Since the ref was broken and no direct value provided, data should be None
198205
assert_eq!(obj.data, None);
199206
}
200207

201-
/// Test that XML entities are correctly decoded (e.g., `B&amp;R` -> `B&R`).
208+
/// Verifies that XML entities are correctly decoded.
202209
#[test]
203210
fn test_xml_entity_decoding() {
204211
let xml = MINIMAL_VALID_XML.replace(
205212
r#"<vendorName>TestVendor</vendorName>"#,
206-
r#"<vendorName>B&amp;R Automation</vendorName>"#
213+
r#"<vendorName>B&amp;R Automation</vendorName>"#,
207214
);
208215

209216
let xdc_file = load_xdc_from_str(&xml).expect("Failed to parse XML with entities");
210217
assert_eq!(xdc_file.identity.vendor_name, "B&R Automation");
211218
}
212219

213-
/// Test that numeric values overflow their target types triggers an error.
214-
/// E.g. "256" for Unsigned8.
220+
/// Verifies that numeric values overflowing their target types trigger an error.
215221
#[test]
216222
fn test_numeric_overflow() {
217-
// Set type to Unsigned8 (0005) but value to 256 (too large for u8)
223+
// Set type to Unsigned8 (0005) but value to 256
218224
let base_xml = MINIMAL_VALID_XML.replace(
219225
r#"<defType dataType="0006"><Unsigned16/></defType>"#,
220-
r#"<defType dataType="0005"><Unsigned8/></defType>"#
226+
r#"<defType dataType="0005"><Unsigned8/></defType>"#,
221227
).replace(
222228
r#"dataType="0006" actualValue="0x1234""#,
223-
r#"dataType="0005" actualValue="256""#
229+
r#"dataType="0005" actualValue="256""#,
224230
);
225231

226232
let xdc_file = load_xdc_from_str(&base_xml).expect("Initial parse should succeed");
227-
233+
228234
// Conversion should fail
229235
let core_result = to_core_od(&xdc_file);
230-
236+
231237
assert!(
232238
matches!(
233239
core_result,
@@ -240,13 +246,12 @@ fn test_numeric_overflow() {
240246
);
241247
}
242248

243-
/// Test missing mandatory fields in ProfileHeader.
249+
/// Verifies behavior when mandatory fields in ProfileHeader are missing.
244250
#[test]
245251
fn test_missing_header_fields() {
246-
// Remove ProfileIdentification
247252
let xml = MINIMAL_VALID_XML.replace(
248-
r#"<ProfileIdentification>Test</ProfileIdentification>"#,
249-
""
253+
r#"<ProfileIdentification>Test</ProfileIdentification>"#,
254+
"",
250255
);
251256

252257
let result = load_xdc_from_str(&xml);
@@ -258,27 +263,19 @@ fn test_missing_header_fields() {
258263
);
259264
}
260265

261-
/// Test behavior when an unknown data type ID is used.
266+
/// Verifies behavior when an unknown data type ID is used.
262267
#[test]
263268
fn test_unknown_data_type() {
264269
// Use a made-up data type ID "FFFF"
265-
let xml = MINIMAL_VALID_XML.replace(
266-
r#"dataType="0006""#,
267-
r#"dataType="FFFF""#
268-
);
270+
let xml = MINIMAL_VALID_XML.replace(r#"dataType="0006""#, r#"dataType="FFFF""#);
269271

270272
let xdc_file = load_xdc_from_str(&xml).expect("Parse should succeed");
271-
272-
// Converter attempts to map this.
273-
// Current implementation in converter.rs: map_data_to_value returns Ok(None) for unknown type.
274-
// map_object sees None for a VAR (type 7) and returns XdcError::ValidationError.
273+
274+
// Converter attempts to map this, fails to find logic for "FFFF", returns error.
275275
let core_result = to_core_od(&xdc_file);
276276

277277
assert!(
278-
matches!(
279-
core_result,
280-
Err(XdcError::ValidationError(_))
281-
),
278+
matches!(core_result, Err(XdcError::ValidationError(_))),
282279
"Expected ValidationError for unknown data type, got {:?}",
283280
core_result
284281
);

0 commit comments

Comments
 (0)