Skip to content

Commit

Permalink
Improve file handling
Browse files Browse the repository at this point in the history
- element operations require that a file exists
- new files don't automatically contain all existing elements
  • Loading branch information
DanielT committed Sep 3, 2023
1 parent 033a3b8 commit 8c60093
Show file tree
Hide file tree
Showing 9 changed files with 399 additions and 295 deletions.
2 changes: 1 addition & 1 deletion autosar-data-specification/src/specification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23588,7 +23588,7 @@ pub(crate) static DATATYPES: [ElementSpec; 4677] = [
/* 187 */ ElementSpec {sub_elements: (17926, 17927), sub_element_ver: 7, attributes: (0, 0), attributes_ver: 0, character_data: None, mode: ContentMode::Bag, ordered: false, splittable: 524287, ref_by: &[]}, // INTERNAL-BEHAVIORS
/* 188 */ ElementSpec {sub_elements: (16846, 16849), sub_element_ver: 126, attributes: (0, 0), attributes_ver: 0, character_data: None, mode: ContentMode::Bag, ordered: false, splittable: 0, ref_by: &[]}, // BLUEPRINT-POLICYS
/* 189 */ ElementSpec {sub_elements: (0, 0), sub_element_ver: 0, attributes: (0, 2), attributes_ver: 0, character_data: Some(60), mode: ContentMode::Characters, ordered: true, splittable: 0, ref_by: &[]}, // AUTO-COLLECT
/* 190 */ ElementSpec {sub_elements: (16441, 16445), sub_element_ver: 8058, attributes: (3360, 3365), attributes_ver: 387, character_data: None, mode: ContentMode::Sequence, ordered: false, splittable: 0, ref_by: &[]}, // AUTOSAR
/* 190 */ ElementSpec {sub_elements: (16441, 16445), sub_element_ver: 8058, attributes: (3360, 3365), attributes_ver: 387, character_data: None, mode: ContentMode::Sequence, ordered: false, splittable: 4294967295, ref_by: &[]}, // AUTOSAR
/* 191 */ ElementSpec {sub_elements: (17927, 17928), sub_element_ver: 7, attributes: (0, 0), attributes_ver: 0, character_data: None, mode: ContentMode::Bag, ordered: false, splittable: 524287, ref_by: &[]}, // AR-PACKAGES
/* 192 */ ElementSpec {sub_elements: (0, 0), sub_element_ver: 0, attributes: (403, 409), attributes_ver: 8750, character_data: Some(664), mode: ContentMode::Characters, ordered: true, splittable: 0, ref_by: &[]}, // DATA-TYPE-REF, TYPE-TREF
/* 193 */ ElementSpec {sub_elements: (17327, 17329), sub_element_ver: 0, attributes: (0, 2), attributes_ver: 0, character_data: None, mode: ContentMode::Sequence, ordered: false, splittable: 0, ref_by: &[]}, // AUTOSAR-DATA-TYPE-REF-CONDITIONAL
Expand Down
3 changes: 3 additions & 0 deletions autosar-data/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ smallvec = { version = "~1.11.0", features = ["union", "const_generics"]}
parking_lot = "0.12"
rustc-hash = "1.1.0"

[dev-dependencies]
tempfile = "3.8"

[[example]]
name = "demo"
102 changes: 101 additions & 1 deletion autosar-data/src/arxmlfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ impl ArxmlFile {
/// # Possible errors
///
/// [AutosarDataError::ItemDeleted]: The model is no longer valid
/// [AutosarDataError::EmptyFile]: The file is empty and cannot be serialized
///
/// # Example
///
Expand All @@ -186,14 +187,18 @@ impl ArxmlFile {
/// let text = file.serialize();
/// ```
pub fn serialize(&self) -> Result<String, AutosarDataError> {
let model = self.model()?;
if !model.root_element().file_membership()?.1.contains(&self.downgrade()) {
return Err(AutosarDataError::EmptyFile);
}

let mut outstring = String::with_capacity(1024 * 1024);

match self.xml_standalone() {
Some(true) => outstring.push_str("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>"),
Some(false) => outstring.push_str("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>"),
None => outstring.push_str("<?xml version=\"1.0\" encoding=\"utf-8\"?>"),
}
let model = self.model()?;
model.0.lock().set_version(self.0.lock().version);
model
.root_element()
Expand Down Expand Up @@ -428,6 +433,101 @@ mod test {
assert_eq!(file_elem_count, file_elem_count_2);
}

#[test]
fn multiple_files_1() {
// two files are created, both contain AUTOSAR. Then a child element of AUTOSAR is created, which is present in both files
let model = AutosarModel::new();
let file_a = model.create_file("a", AutosarVersion::LATEST).unwrap();
let file_b = model.create_file("b", AutosarVersion::LATEST).unwrap();
let el_a_packages = model
.root_element()
.create_sub_element(ElementName::ArPackages)
.unwrap();
// el_a_packages is part of both file_a and file_b, because both files automatically contain the
// root AUTOSAR element, and AR_PACKAGES inherits this
let (_, fs) = el_a_packages.file_membership().unwrap();
assert!(fs.contains(&file_a.downgrade()));
assert!(fs.contains(&file_b.downgrade()));
}

#[test]
fn multiple_files_2() {
// one file is created, which contains AUTOSAR. Then a child element is created, which is automatically part of this file.
// then a second file is created, but the element is NOT part of the new file
let model = AutosarModel::new();
let file_a = model.create_file("a", AutosarVersion::LATEST).unwrap();
let el_a_packages = model
.root_element()
.create_sub_element(ElementName::ArPackages)
.unwrap();
let file_b = model.create_file("b", AutosarVersion::LATEST).unwrap();
// el_a_packages is only part of file_a
let (_, fs) = el_a_packages.file_membership().unwrap();
assert!(fs.contains(&file_a.downgrade()));
assert!(!fs.contains(&file_b.downgrade()));
}

#[test]
fn multiple_files_3() {
// a file is created with multiple sub elements. A pat of this hierarchy is added to a second file
let model = AutosarModel::new();
let file_a = model.create_file("a", AutosarVersion::LATEST).unwrap();
let el_ar_packages = model
.root_element()
.create_sub_element(ElementName::ArPackages)
.unwrap();
let el_pkg1 = el_ar_packages
.create_named_sub_element(ElementName::ArPackage, "Pkg1")
.unwrap();
let el_pkg2 = el_ar_packages
.create_named_sub_element(ElementName::ArPackage, "Pkg2")
.unwrap();
let file_b = model.create_file("b", AutosarVersion::LATEST).unwrap();
let (_, fs) = el_pkg1.file_membership().unwrap();
assert!(fs.contains(&file_a.downgrade())); // el_pkg1 is part of file_a
assert!(!fs.contains(&file_b.downgrade())); // el_pkg1 is not part of file_b
let (_, fs) = el_pkg2.file_membership().unwrap();
assert!(fs.contains(&file_a.downgrade())); // el_pkg2 is part of file_a
assert!(!fs.contains(&file_b.downgrade())); // el_pkg2 is not part of file_b

// add el_pkg2 to file_b
el_pkg2.add_to_file(&file_b).unwrap();
let (_, fs) = el_pkg1.file_membership().unwrap();
assert!(fs.contains(&file_a.downgrade())); // el_pkg1 is part of file_a
assert!(!fs.contains(&file_b.downgrade())); // el_pkg1 is not part of file_b
let (_, fs) = el_pkg2.file_membership().unwrap();
assert!(fs.contains(&file_a.downgrade())); // el_pkg2 is part of file_a
assert!(fs.contains(&file_b.downgrade())); // el_pkg2 is part of file_b

// el_ar_packages was automatically added to file_b, in order to add el_pkg2
let (_, fs) = el_ar_packages.file_membership().unwrap();
assert!(fs.contains(&file_a.downgrade())); // el_ar_packages is part of file_a
assert!(fs.contains(&file_b.downgrade())); // el_ar_packages is part of file_b

// remove el_pkg2 from file_a
let (_, fs) = el_pkg2.file_membership().unwrap();
assert!(fs.contains(&file_a.downgrade())); // el_pkg2 is part of file_a
assert!(fs.contains(&file_b.downgrade())); // el_pkg2 is part of file_b
el_pkg2.remove_from_file(&file_a).unwrap();
let (_, fs) = el_pkg2.file_membership().unwrap();
assert!(!fs.contains(&file_a.downgrade())); // el_pkg2 is part of file_a
assert!(fs.contains(&file_b.downgrade())); // el_pkg2 is part of file_b

// add_to_file / remove_from_file cannot be called on all elements
let el_elements = el_pkg1.create_sub_element(ElementName::Elements).unwrap();
let result = el_elements.add_to_file(&file_a);
assert!(matches!(result, Err(AutosarDataError::FilesetModificationForbidden)));
let result: Result<(), AutosarDataError> = el_elements.remove_from_file(&file_a);
assert!(matches!(result, Err(AutosarDataError::FilesetModificationForbidden)));

// serializing a single file
let text_before = file_a.serialize().unwrap();
model.remove_file(&file_b);
assert!(model.get_element_by_path("/Pkg2").is_none());
let text_after = file_a.serialize().unwrap();
assert_eq!(text_before, text_after);
}

#[test]
fn traits() {
let model = AutosarModel::new();
Expand Down
Loading

0 comments on commit 8c60093

Please sign in to comment.