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
37use 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 .
610const 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]
6266fn 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]
7478fn 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]
9497fn 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]
117125fn 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]
141149fn 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]
184192fn 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&R` -> `B&R`) .
208+ /// Verifies that XML entities are correctly decoded.
202209#[ test]
203210fn test_xml_entity_decoding ( ) {
204211 let xml = MINIMAL_VALID_XML . replace (
205212 r#"<vendorName>TestVendor</vendorName>"# ,
206- r#"<vendorName>B&R Automation</vendorName>"#
213+ r#"<vendorName>B&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]
216222fn 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]
245251fn 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]
263268fn 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