1use std::cmp::Ordering;
2use std::hash::Hash;
3use std::str::FromStr;
4
5use super::*;
6
7static LOCK_CONTENTION_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(10);
8
9impl Element {
10 pub fn parent(&self) -> Result<Option<Element>, AutosarDataError> {
33 self.0.read().parent()
34 }
35
36 pub fn named_parent(&self) -> Result<Option<Element>, AutosarDataError> {
65 let mut cur_elem_opt = self.parent()?;
66 while let Some(parent) = cur_elem_opt {
67 if parent.is_identifiable() {
68 return Ok(Some(parent));
69 }
70 cur_elem_opt = parent.parent()?;
71 }
72
73 Ok(None)
74 }
75
76 pub(crate) fn set_parent(&self, new_parent: ElementOrModel) {
77 self.0.write().set_parent(new_parent);
78 }
79
80 pub(crate) fn set_model_recursive(&self, model: &WeakAutosarModel) {
87 for (_, element) in self.elements_dfs() {
88 if let ElementOrModel::Element(_, element_model) = &mut element.0.write().parent {
89 *element_model = model.clone();
90 }
91 }
92 }
93
94 pub(crate) fn detach_recursive(&self) {
99 for (_, element) in self.elements_dfs() {
100 element.0.write().parent = ElementOrModel::None;
101 }
102 }
103
104 #[must_use]
117 pub fn element_name(&self) -> ElementName {
118 self.0.read().elemname
119 }
120
121 #[must_use]
135 pub fn element_type(&self) -> ElementType {
136 self.0.read().elemtype
137 }
138
139 #[must_use]
157 pub fn item_name(&self) -> Option<String> {
158 self.0.read().item_name()
159 }
160
161 pub fn set_item_name(&self, new_name: &str) -> Result<(), AutosarDataError> {
196 if new_name.is_empty() {
198 return Err(AutosarDataError::ItemNameRequired {
199 element: self.element_name(),
200 });
201 }
202 let (model, version) = self.model_and_version()?;
203 self.0.write().set_item_name(new_name, &model, version)
204 }
205
206 #[must_use]
222 pub fn is_identifiable(&self) -> bool {
223 self.0.read().is_identifiable()
224 }
225
226 #[must_use]
242 pub fn is_reference(&self) -> bool {
243 self.elemtype().is_ref()
244 }
245
246 pub fn path(&self) -> Result<String, AutosarDataError> {
269 self.0
272 .try_read_for(LOCK_CONTENTION_TIMEOUT)
273 .ok_or(AutosarDataError::ParentElementLocked)?
274 .path()
275 }
276
277 pub fn package(&self) -> Result<Option<Element>, AutosarDataError> {
306 let mut cur_elem = self.clone();
307 loop {
308 let parent = {
309 let element = cur_elem
310 .0
311 .try_read_for(LOCK_CONTENTION_TIMEOUT)
312 .ok_or(AutosarDataError::ParentElementLocked)?;
313 match &element.parent {
314 ElementOrModel::Element(weak_parent, _) => {
315 let parent = weak_parent.upgrade().ok_or(AutosarDataError::ItemDeleted)?;
316 let parent_name = {
318 let parent_lock = parent
319 .0
320 .try_read_for(LOCK_CONTENTION_TIMEOUT)
321 .ok_or(AutosarDataError::ParentElementLocked)?;
322 parent_lock.element_name()
323 };
324
325 if parent_name == ElementName::ArPackage {
326 return Ok(Some(parent));
327 }
328 parent
329 }
330 ElementOrModel::Model(_) => {
331 return Ok(None);
332 }
333 ElementOrModel::None => return Err(AutosarDataError::ItemDeleted),
334 }
335 };
336 cur_elem = parent;
337 }
338 }
339
340 pub fn model(&self) -> Result<AutosarModel, AutosarDataError> {
362 self.0
363 .try_read_for(LOCK_CONTENTION_TIMEOUT)
364 .ok_or(AutosarDataError::ParentElementLocked)?
365 .model()
366 }
367
368 #[must_use]
382 pub fn content_type(&self) -> ContentType {
383 self.elemtype().content_mode().into()
384 }
385
386 pub fn create_sub_element(&self, element_name: ElementName) -> Result<Element, AutosarDataError> {
414 let version = self.min_version()?;
415 self.0
416 .try_write()
417 .ok_or(AutosarDataError::ParentElementLocked)?
418 .create_sub_element(self.downgrade(), element_name, version)
419 }
420
421 pub fn create_sub_element_at(
452 &self,
453 element_name: ElementName,
454 position: usize,
455 ) -> Result<Element, AutosarDataError> {
456 let version = self.min_version()?;
457 self.0
458 .write()
459 .create_sub_element_at(self.downgrade(), element_name, position, version)
460 }
461
462 pub fn create_named_sub_element(
492 &self,
493 element_name: ElementName,
494 item_name: &str,
495 ) -> Result<Element, AutosarDataError> {
496 let (model, version) = self.model_and_version()?;
497 self.0
498 .write()
499 .create_named_sub_element(self.downgrade(), element_name, item_name, &model, version)
500 }
501
502 pub fn create_named_sub_element_at(
534 &self,
535 element_name: ElementName,
536 item_name: &str,
537 position: usize,
538 ) -> Result<Element, AutosarDataError> {
539 let (model, version) = self.model_and_version()?;
540 self.0
541 .write()
542 .create_named_sub_element_at(self.downgrade(), element_name, item_name, position, &model, version)
543 }
544
545 pub fn create_copied_sub_element(&self, other: &Element) -> Result<Element, AutosarDataError> {
585 if self == other {
586 return Err(AutosarDataError::InvalidSubElement {
588 parent: self.element_name(),
589 element: self.element_name(),
590 });
591 }
592 let (model, version) = self.model_and_version()?;
593 let copy = self
594 .0
595 .write()
596 .create_copied_sub_element(self.downgrade(), other, &model, version);
597 model.resolve_relative_references();
600 copy
601 }
602
603 pub fn create_copied_sub_element_at(&self, other: &Element, position: usize) -> Result<Element, AutosarDataError> {
644 if self == other {
645 return Err(AutosarDataError::InvalidSubElement {
647 parent: self.element_name(),
648 element: self.element_name(),
649 });
650 }
651 let (model, version) = self.model_and_version()?;
652 let copy = self
653 .0
654 .write()
655 .create_copied_sub_element_at(self.downgrade(), other, position, &model, version);
656 model.resolve_relative_references();
659 copy
660 }
661
662 pub fn move_element_here(&self, move_element: &Element) -> Result<Element, AutosarDataError> {
699 if self == move_element {
700 return Err(AutosarDataError::ForbiddenMoveToSubElement);
702 }
703 let model_src = move_element.model()?;
704 let model = self.model()?;
705 let version_src = move_element.min_version()?;
706 let version = self.min_version()?;
707 if version != version_src {
708 return Err(AutosarDataError::VersionMismatch {
709 version_cur: version,
710 version_new: version_src,
711 });
712 }
713 let moved = self
714 .0
715 .write()
716 .move_element_here(self.downgrade(), move_element, &model, &model_src, version);
717 model_src.resolve_relative_references();
720 model.resolve_relative_references();
721 moved
722 }
723
724 pub fn move_element_here_at(&self, move_element: &Element, position: usize) -> Result<Element, AutosarDataError> {
762 if self == move_element {
763 return Err(AutosarDataError::ForbiddenMoveToSubElement);
765 }
766 let model_src = move_element.model()?;
767 let model = self.model()?;
768 let version_src = move_element.min_version()?;
769 let version = self.min_version()?;
770 if version != version_src {
771 return Err(AutosarDataError::VersionMismatch {
772 version_cur: version,
773 version_new: version_src,
774 });
775 }
776 let moved =
777 self.0
778 .write()
779 .move_element_here_at(self.downgrade(), move_element, position, &model, &model_src, version);
780 model_src.resolve_relative_references();
783 model.resolve_relative_references();
784 moved
785 }
786
787 pub fn remove_sub_element(&self, sub_element: Element) -> Result<(), AutosarDataError> {
815 if *self == sub_element {
816 return Err(AutosarDataError::ElementNotFound {
818 target: self.element_name(),
819 parent: self.element_name(),
820 });
821 }
822 let model = self.model()?;
823 let result = self.0.write().remove_sub_element(sub_element, &model);
824 model.resolve_relative_references();
826 result
827 }
828
829 pub fn remove_sub_element_kind(&self, element_name: ElementName) -> Result<(), AutosarDataError> {
859 let Some(sub_element) = self.get_sub_element(element_name) else {
860 return Err(AutosarDataError::ElementNotFound {
861 target: element_name,
862 parent: self.element_name(),
863 });
864 };
865 self.remove_sub_element(sub_element)
866 }
867
868 pub fn set_reference_target(&self, target: &Element) -> Result<(), AutosarDataError> {
903 let result = self.set_reference_target_internal(target, None);
904 if let Ok(model) = self.model() {
906 model.resolve_relative_references();
907 }
908 result
909 }
910
911 pub fn set_relative_reference_target(&self, target: &Element, base_label: &str) -> Result<(), AutosarDataError> {
927 let result = self.set_reference_target_internal(target, Some(base_label));
928 if let Ok(model) = self.model() {
930 model.resolve_relative_references();
931 }
932 result
933 }
934
935 pub(crate) fn resolve_reference_base(&self, label: &str) -> Option<String> {
950 let mut search_package = self.package().ok().flatten()?;
951 let mut label = label.to_owned();
952 let mut relative_parts: Vec<String> = Vec::new();
954 let mut visited: Vec<(Element, String)> = Vec::new();
955
956 loop {
957 let (declaring_package, package_ref, package_ref_base) =
958 Self::find_reference_base_declaration(&search_package, &label)?;
959 if visited.contains(&(declaring_package.clone(), label.clone())) {
960 return None;
962 }
963 visited.push((declaring_package.clone(), label));
964
965 let Some(outer_label) = package_ref_base else {
966 let mut resolved = package_ref;
968 for part in relative_parts.iter().rev() {
969 resolved.push('/');
970 resolved.push_str(part);
971 }
972 return Some(resolved);
973 };
974 relative_parts.push(package_ref);
975 search_package = declaring_package;
978 label = outer_label;
979 }
980 }
981
982 pub(crate) fn resolve_relative_target(&self) -> Option<String> {
989 let reference = self.character_data()?.string_value()?;
990 let base_label = self.attribute_value(AttributeName::Base)?.string_value()?;
991 let base_path = self.resolve_reference_base(&base_label)?;
992 Some(format!("{base_path}/{reference}"))
993 }
994
995 fn find_reference_base_declaration(package: &Element, label: &str) -> Option<(Element, String, Option<String>)> {
1001 let mut current_package = Some(package.clone());
1002 while let Some(package) = current_package {
1003 if let Some(reference_bases) = package.try_get_sub_element(ElementName::ReferenceBases) {
1004 let declarations: Vec<Element> = reference_bases
1005 .0
1006 .try_read_for(LOCK_CONTENTION_TIMEOUT)?
1007 .content
1008 .iter()
1009 .filter_map(|item| match item {
1010 ElementContent::Element(sub_element) => Some(sub_element.clone()),
1011 ElementContent::CharacterData(_) => None,
1012 })
1013 .collect();
1014 for declaration in declarations {
1015 if let Some((declared_label, package_ref, package_ref_base)) = declaration
1016 .0
1017 .try_read_for(LOCK_CONTENTION_TIMEOUT)?
1018 .reference_base_declaration()
1019 && declared_label == label
1020 {
1021 return Some((package, package_ref, package_ref_base));
1022 }
1023 }
1024 }
1025 current_package = package.package().ok().flatten();
1026 }
1027 None
1028 }
1029
1030 fn try_get_sub_element(&self, name: ElementName) -> Option<Element> {
1034 let locked_element = self.0.try_read_for(LOCK_CONTENTION_TIMEOUT)?;
1035 for item in &locked_element.content {
1036 if let ElementContent::Element(sub_element) = item
1037 && sub_element.0.try_read_for(LOCK_CONTENTION_TIMEOUT)?.elemname == name
1038 {
1039 return Some(sub_element.clone());
1040 }
1041 }
1042 None
1043 }
1044
1045 fn set_reference_target_internal(
1046 &self,
1047 target: &Element,
1048 base_label: Option<&str>,
1049 ) -> Result<(), AutosarDataError> {
1050 if !self.is_reference() {
1052 return Err(AutosarDataError::NotReferenceElement);
1053 }
1054
1055 let new_ref = target.path()?;
1057 let Some(enum_item) = EnumItem::from_str(target.element_name().to_str())
1059 .ok()
1060 .or(self.element_type().reference_dest_value(&target.element_type()))
1061 else {
1062 return Err(AutosarDataError::InvalidReference);
1063 };
1064
1065 let model = self.model()?;
1066 let target_string = if let Some(base_label) = base_label {
1068 let base_path = self
1071 .resolve_reference_base(base_label)
1072 .ok_or(AutosarDataError::InvalidReferenceBase)?;
1073 let mut trimmed_target_path = new_ref
1074 .strip_prefix(&base_path)
1075 .ok_or(AutosarDataError::InvalidReferenceBase)?;
1076 if let Some(no_leading_slash) = trimmed_target_path.strip_prefix('/') {
1077 trimmed_target_path = no_leading_slash;
1078 }
1079 trimmed_target_path.to_string()
1080 } else {
1081 new_ref
1082 };
1083
1084 let version = self.min_version()?;
1085
1086 let mut element = self.0.write();
1087 if element
1089 .set_attribute_internal(AttributeName::Dest, CharacterData::Enum(enum_item), version)
1090 .is_err()
1091 {
1092 return Err(AutosarDataError::InvalidReference);
1093 }
1094
1095 let opt_old_ref = element.character_data().and_then(|cdata| cdata.string_value());
1096
1097 if let Some(old_ref) = opt_old_ref {
1099 model.fix_reference_origins(&old_ref, &target_string, base_label, self.downgrade());
1100 } else {
1101 model.add_reference_origin(&target_string, base_label, self.downgrade());
1103 }
1104
1105 element.set_character_data(CharacterData::String(target_string), version)?;
1107 if let Some(base_label) = base_label {
1108 element.set_attribute_internal(
1109 AttributeName::Base,
1110 CharacterData::String(base_label.to_string()),
1111 version,
1112 )?;
1113 } else {
1114 element.remove_attribute(AttributeName::Base);
1116 }
1117
1118 Ok(())
1119 }
1120
1121 pub fn get_reference_target(&self) -> Result<Element, AutosarDataError> {
1160 if self.is_reference() {
1161 if let Some(CharacterData::String(reference)) = self.character_data() {
1162 let model = self.model()?;
1163
1164 let full_path = if self.attribute_value(AttributeName::Base).is_some() {
1165 model
1170 .relative_reference_target(&self.downgrade())
1171 .ok_or(AutosarDataError::InvalidReference)?
1172 } else {
1173 reference
1174 };
1175 let target_elem = model
1176 .get_element_by_path(&full_path)
1177 .ok_or(AutosarDataError::InvalidReference)?;
1178
1179 let dest_value = self
1180 .attribute_value(AttributeName::Dest)
1181 .and_then(|cdata| cdata.enum_value())
1182 .ok_or(AutosarDataError::InvalidReference)?;
1183 if target_elem.element_type().verify_reference_dest(dest_value) {
1184 Ok(target_elem)
1185 } else {
1186 Err(AutosarDataError::InvalidReference)
1187 }
1188 } else {
1189 Err(AutosarDataError::InvalidReference)
1190 }
1191 } else {
1192 Err(AutosarDataError::NotReferenceElement)
1193 }
1194 }
1195
1196 pub fn set_character_data<T: Into<CharacterData>>(&self, value: T) -> Result<(), AutosarDataError> {
1225 let chardata: CharacterData = value.into();
1226 self.set_character_data_internal(chardata)
1227 }
1228
1229 fn set_character_data_internal(&self, mut chardata: CharacterData) -> Result<(), AutosarDataError> {
1231 let elemtype = self.elemtype();
1232 if (elemtype.content_mode() == ContentMode::Characters || elemtype.content_mode() == ContentMode::Mixed)
1233 && let Some(cdata_spec) = elemtype.chardata_spec()
1234 {
1235 let (model, version) = self.model_and_version()?;
1236 let mut compatible_value = CharacterData::check_value(&chardata, cdata_spec, version);
1237 if !compatible_value
1238 && matches!(
1239 cdata_spec,
1240 CharacterDataSpec::Pattern { .. } | CharacterDataSpec::String { .. }
1241 )
1242 {
1243 chardata = CharacterData::String(chardata.to_string());
1244 compatible_value = CharacterData::check_value(&chardata, cdata_spec, version);
1245 }
1246 if compatible_value {
1247 let mut prev_path = None;
1249 if self.element_name() == ElementName::ShortName {
1250 if self.character_data().is_some()
1252 && let Some(parent) = self.parent()?
1253 {
1254 prev_path = Some(parent.path()?);
1255 }
1256 };
1257
1258 let old_refval = if elemtype.is_ref() {
1260 self.character_data().and_then(|cdata| cdata.string_value())
1261 } else {
1262 None
1263 };
1264
1265 {
1267 let mut element = self.0.write();
1268 element.content.clear();
1269 element.content.push(ElementContent::CharacterData(chardata));
1270 }
1271
1272 if let Some(prev_path) = prev_path
1274 && let Some(parent) = self.parent()?
1275 {
1276 let new_path = parent.path()?;
1277 model.fix_element_paths(&PathRemap::single(prev_path, new_path));
1278 }
1280
1281 if elemtype.is_ref()
1283 && let Some(CharacterData::String(refval)) = self.character_data()
1284 {
1285 let base = self
1286 .attribute_value(AttributeName::Base)
1287 .and_then(|cdata| cdata.string_value());
1288 if let Some(old_refval) = old_refval {
1289 model.fix_reference_origins(&old_refval, &refval, base.as_deref(), self.downgrade());
1290 } else {
1291 model.add_reference_origin(&refval, base.as_deref(), self.downgrade());
1292 }
1293 }
1294
1295 model.resolve_relative_references();
1298
1299 Ok(())
1300 } else {
1301 Err(AutosarDataError::InvalidCharacterData {
1302 element: self.element_name(),
1303 value: chardata.to_string(),
1304 })
1305 }
1306 } else {
1307 Err(AutosarDataError::IncorrectContentType {
1308 element: self.element_name(),
1309 })
1310 }
1311 }
1312
1313 pub fn remove_character_data(&self) -> Result<(), AutosarDataError> {
1343 let elemtype = self.elemtype();
1344 if elemtype.content_mode() == ContentMode::Characters {
1345 if self.element_name() == ElementName::ShortName {
1346 Err(AutosarDataError::ShortNameRemovalForbidden)
1347 } else {
1348 if self.character_data().is_some() {
1349 if self.is_reference() {
1350 let model = self.model()?;
1352 if let Some(CharacterData::String(reference)) = self.character_data() {
1353 model.remove_reference_origin(&reference, self.downgrade());
1354 }
1355 }
1356 self.0.write().content.clear();
1357 if let Ok(model) = self.model() {
1360 model.resolve_relative_references();
1361 }
1362 }
1363 Ok(())
1364 }
1365 } else {
1366 Err(AutosarDataError::IncorrectContentType {
1367 element: self.element_name(),
1368 })
1369 }
1370 }
1371
1372 pub fn insert_character_content_item(&self, chardata: &str, position: usize) -> Result<(), AutosarDataError> {
1399 let mut element = self.0.write();
1400 if let ContentMode::Mixed = element.elemtype.content_mode() {
1401 if position <= element.content.len() {
1402 element.content.insert(
1403 position,
1404 ElementContent::CharacterData(CharacterData::String(chardata.to_owned())),
1405 );
1406 Ok(())
1407 } else {
1408 Err(AutosarDataError::InvalidPosition)
1409 }
1410 } else {
1411 Err(AutosarDataError::IncorrectContentType {
1412 element: element.element_name(),
1413 })
1414 }
1415 }
1416
1417 pub fn remove_character_content_item(&self, position: usize) -> Result<(), AutosarDataError> {
1443 let mut element = self.0.write();
1444 if let ContentMode::Mixed = element.elemtype.content_mode() {
1445 if position < element.content.len()
1446 && let ElementContent::CharacterData(_) = element.content[position]
1447 {
1448 element.content.remove(position);
1449 return Ok(());
1450 }
1451 Err(AutosarDataError::InvalidPosition)
1452 } else {
1453 Err(AutosarDataError::IncorrectContentType {
1454 element: element.element_name(),
1455 })
1456 }
1457 }
1458
1459 #[must_use]
1472 pub fn content_item_count(&self) -> usize {
1473 self.0.read().content.len()
1474 }
1475
1476 #[must_use]
1501 pub fn character_data(&self) -> Option<CharacterData> {
1502 self.0.read().character_data()
1503 }
1504
1505 #[must_use]
1526 pub fn content(&self) -> ElementContentIterator {
1527 ElementContentIterator::new(self)
1528 }
1529
1530 #[must_use]
1547 pub fn downgrade(&self) -> WeakElement {
1548 WeakElement(Arc::downgrade(&self.0))
1549 }
1550
1551 #[must_use]
1571 pub fn position(&self) -> Option<usize> {
1572 if let Ok(Some(parent)) = self.parent() {
1573 parent
1574 .0
1575 .read()
1576 .content
1577 .iter()
1578 .position(|ec| matches!(ec, ElementContent::Element(elem) if elem == self))
1579 } else {
1580 None
1581 }
1582 }
1583
1584 #[must_use]
1600 pub fn sub_elements(&self) -> ElementsIterator {
1601 ElementsIterator::new(self.clone())
1602 }
1603
1604 #[must_use]
1623 pub fn get_sub_element(&self, name: ElementName) -> Option<Element> {
1624 let locked_elem = self.0.read();
1625 for item in &locked_elem.content {
1626 if let ElementContent::Element(subelem) = item
1627 && subelem.element_name() == name
1628 {
1629 return Some(subelem.clone());
1630 }
1631 }
1632 None
1633 }
1634
1635 #[must_use]
1654 pub fn get_sub_element_at(&self, position: usize) -> Option<Element> {
1655 let locked_elem = self.0.read();
1656 if let Some(ElementContent::Element(subelem)) = locked_elem.content.get(position) {
1657 return Some(subelem.clone());
1658 }
1659 None
1660 }
1661
1662 pub fn get_or_create_sub_element(&self, name: ElementName) -> Result<Element, AutosarDataError> {
1691 let version = self.min_version()?;
1692 let mut locked_elem = self.0.try_write().ok_or(AutosarDataError::ParentElementLocked)?;
1693 for item in &locked_elem.content {
1694 if let ElementContent::Element(subelem) = item
1695 && subelem.element_name() == name
1696 {
1697 return Ok(subelem.clone());
1698 }
1699 }
1700 locked_elem.create_sub_element(self.downgrade(), name, version)
1701 }
1702 pub fn get_or_create_named_sub_element(
1733 &self,
1734 element_name: ElementName,
1735 item_name: &str,
1736 ) -> Result<Element, AutosarDataError> {
1737 let (model, version) = self.model_and_version()?;
1738 let mut locked_elem = self.0.try_write().ok_or(AutosarDataError::ParentElementLocked)?;
1739 for item in &locked_elem.content {
1740 if let ElementContent::Element(subelem) = item
1741 && subelem.element_name() == element_name
1742 && subelem.item_name().as_deref().unwrap_or("") == item_name
1743 {
1744 return Ok(subelem.clone());
1745 }
1746 }
1747 locked_elem.create_named_sub_element(self.downgrade(), element_name, item_name, &model, version)
1748 }
1749
1750 #[must_use]
1769 pub fn elements_dfs(&self) -> ElementsDfsIterator {
1770 ElementsDfsIterator::new(self, 0)
1771 }
1772
1773 #[must_use]
1797 pub fn elements_dfs_with_max_depth(&self, max_depth: usize) -> ElementsDfsIterator {
1798 ElementsDfsIterator::new(self, max_depth)
1799 }
1800
1801 #[must_use]
1815 pub fn attributes(&self) -> AttributeIterator {
1816 AttributeIterator {
1817 element: self.clone(),
1818 index: 0,
1819 }
1820 }
1821
1822 #[must_use]
1833 pub fn attribute_value(&self, attrname: AttributeName) -> Option<CharacterData> {
1834 self.0.read().attribute_value(attrname)
1835 }
1836
1837 pub fn set_attribute<T: Into<CharacterData>>(
1861 &self,
1862 attrname: AttributeName,
1863 value: T,
1864 ) -> Result<(), AutosarDataError> {
1865 let version = self.min_version()?;
1866 let (old_base, reference_value) = self.base_attribute_info(attrname);
1867
1868 self.0.write().set_attribute_internal(attrname, value.into(), version)?;
1869
1870 self.base_attribute_fixup(attrname, old_base, reference_value);
1871 Ok(())
1872 }
1873
1874 pub fn set_attribute_string(&self, attrname: AttributeName, stringvalue: &str) -> Result<(), AutosarDataError> {
1898 let version = self.min_version()?;
1899 let (old_base, reference_value) = self.base_attribute_info(attrname);
1900
1901 self.0.write().set_attribute_string(attrname, stringvalue, version)?;
1902
1903 self.base_attribute_fixup(attrname, old_base, reference_value);
1905 Ok(())
1906 }
1907
1908 #[must_use]
1923 pub fn remove_attribute(&self, attrname: AttributeName) -> bool {
1924 let (old_base, reference_value) = self.base_attribute_info(attrname);
1925
1926 let removed = self.0.write().remove_attribute(attrname);
1927
1928 if removed {
1929 self.base_attribute_fixup(attrname, old_base, reference_value);
1931 }
1932 removed
1933 }
1934
1935 fn base_attribute_info(&self, attrname: AttributeName) -> (Option<String>, Option<String>) {
1937 if !self.is_reference() || attrname != AttributeName::Base {
1938 return (None, None);
1939 }
1940 let old_base = self
1941 .attribute_value(AttributeName::Base)
1942 .and_then(|cdata| cdata.string_value());
1943 let reference_value = self.character_data().and_then(|cdata| cdata.string_value());
1944 (old_base, reference_value)
1945 }
1946
1947 fn base_attribute_fixup(&self, attrname: AttributeName, old_base: Option<String>, reference_value: Option<String>) {
1949 if attrname != AttributeName::Base {
1950 return;
1951 }
1952 if let Some(reference_value) = reference_value
1953 && let Ok(model) = self.model()
1954 {
1955 let new_base = self
1956 .attribute_value(AttributeName::Base)
1957 .and_then(|cdata| cdata.string_value());
1958 if old_base != new_base {
1959 model.fix_reference_origins(
1960 &reference_value,
1961 &reference_value,
1962 new_base.as_deref(),
1963 self.downgrade(),
1964 );
1965 }
1966 }
1967 if let Ok(model) = self.model() {
1971 model.resolve_relative_references();
1972 }
1973 }
1974
1975 pub fn sort(&self) {
1992 self.0.write().sort();
1993 }
1994
1995 #[must_use]
2009 pub fn serialize(&self) -> String {
2010 let mut outstring = String::new();
2011
2012 self.0.read().serialize_internal(&mut outstring, 0, false, &None, None);
2013
2014 outstring
2015 }
2016
2017 pub(crate) fn elemtype(&self) -> ElementType {
2018 self.0.read().elemtype
2019 }
2020
2021 fn recalc_element_type(&self, target_version: AutosarVersion) -> ElementType {
2024 if let Ok(Some(parent)) = self.parent()
2025 && let Some((etype, ..)) = parent
2026 .element_type()
2027 .find_sub_element(self.element_name(), target_version as u32)
2028 {
2029 return etype;
2030 }
2031
2032 self.element_type()
2033 }
2034
2035 pub(crate) fn check_version_compatibility(
2037 &self,
2038 file: &WeakArxmlFile,
2039 target_version: AutosarVersion,
2040 ) -> (Vec<CompatibilityError>, u32) {
2041 let mut compat_errors = Vec::new();
2042 let mut overall_version_mask = u32::MAX;
2043
2044 let elemtype_new = self.recalc_element_type(target_version);
2046
2047 {
2049 let element = self.0.read();
2050 for attribute in &element.attributes {
2051 if let Some(AttributeSpec {
2053 spec: value_spec,
2054 version: version_mask,
2055 ..
2056 }) = elemtype_new.find_attribute_spec(attribute.attrname)
2057 {
2058 overall_version_mask &= version_mask;
2059 if !target_version.compatible(version_mask) {
2061 compat_errors.push(CompatibilityError::IncompatibleAttribute {
2062 element: self.clone(),
2063 attribute: attribute.attrname,
2064 version_mask,
2065 });
2066 } else {
2067 let (is_compatible, value_version_mask) = attribute
2068 .content
2069 .check_version_compatibility(value_spec, target_version);
2070 if !is_compatible {
2071 compat_errors.push(CompatibilityError::IncompatibleAttributeValue {
2072 element: self.clone(),
2073 attribute: attribute.attrname,
2074 attribute_value: attribute.content.to_string(),
2075 version_mask: value_version_mask,
2076 });
2077 }
2078 overall_version_mask &= value_version_mask;
2079 }
2080 }
2081 }
2082 }
2083
2084 for sub_element in self.sub_elements() {
2086 if sub_element.0.read().is_in_file(file)
2087 && let Some((_, indices)) = elemtype_new
2088 .find_sub_element(sub_element.element_name(), target_version as u32)
2089 .or(elemtype_new.find_sub_element(sub_element.element_name(), u32::MAX))
2090 && let Some(version_mask) = elemtype_new.get_sub_element_version_mask(&indices)
2091 {
2092 overall_version_mask &= version_mask;
2093 if !target_version.compatible(version_mask) {
2094 compat_errors.push(CompatibilityError::IncompatibleElement {
2095 element: sub_element.clone(),
2096 version_mask,
2097 });
2098 } else {
2099 let (mut sub_element_errors, sub_element_mask) =
2100 sub_element.check_version_compatibility(file, target_version);
2101 compat_errors.append(&mut sub_element_errors);
2102 overall_version_mask &= sub_element_mask;
2103 }
2104 }
2105 }
2106
2107 (compat_errors, overall_version_mask)
2108 }
2109
2110 #[must_use]
2133 pub fn list_valid_sub_elements(&self) -> Vec<ValidSubElementInfo> {
2134 let etype = self.0.read().elemtype;
2135 let mut valid_sub_elements = Vec::new();
2136
2137 if let Ok(version) = self.min_version() {
2138 for (element_name, _, version_mask, named_mask) in etype.sub_element_spec_iter() {
2139 if version.compatible(version_mask) {
2140 let is_named = version.compatible(named_mask);
2141 let is_allowed = self.0.read().calc_element_insert_range(element_name, version).is_ok();
2142 valid_sub_elements.push(ValidSubElementInfo {
2143 element_name,
2144 is_named,
2145 is_allowed,
2146 });
2147 }
2148 }
2149 }
2150
2151 valid_sub_elements
2152 }
2153
2154 pub fn file_membership(&self) -> Result<(bool, HashSet<WeakArxmlFile>), AutosarDataError> {
2179 let mut cur_elem_opt = Some(self.clone());
2180 while let Some(cur_elem) = &cur_elem_opt {
2181 let locked_cur_elem = cur_elem
2182 .0
2183 .try_read_for(LOCK_CONTENTION_TIMEOUT)
2184 .ok_or(AutosarDataError::ParentElementLocked)?;
2185 if let Some(files) = locked_cur_elem.file_membership.as_deref() {
2186 return Ok((cur_elem == self, files.clone()));
2187 }
2188 let parent = locked_cur_elem.parent()?;
2189 drop(locked_cur_elem);
2190
2191 cur_elem_opt = parent;
2192 }
2193
2194 Err(AutosarDataError::NoFilesInModel)
2196 }
2197
2198 pub(crate) fn file_membership_local(&self) -> HashSet<WeakArxmlFile> {
2200 self.0.read().file_membership_cloned()
2201 }
2202
2203 pub(crate) fn set_file_membership(&self, file_membership: HashSet<WeakArxmlFile>) {
2211 let parent_splittable = self
2214 .parent()
2215 .ok()
2216 .flatten()
2217 .map_or(u32::MAX, |p| p.element_type().splittable());
2218 if file_membership.is_empty() || parent_splittable != 0 {
2220 self.0.write().set_file_membership(file_membership);
2221 }
2222 }
2223
2224 pub fn add_to_file(&self, file: &ArxmlFile) -> Result<(), AutosarDataError> {
2248 let parent_splittable = self.parent()?.is_none_or(|p| p.element_type().splittable() != 0);
2249 if parent_splittable {
2250 if file.model()? == self.model()? {
2251 let weak_file = file.downgrade();
2252 let (_, current_fileset) = self.file_membership()?;
2254 if !current_fileset.contains(&weak_file) {
2256 let mut updated_fileset = current_fileset;
2257 updated_fileset.insert(weak_file);
2258 self.0.write().set_file_membership(updated_fileset);
2259
2260 if let Some(parent) = self.parent()? {
2262 parent.add_to_file_restricted(file)?;
2263 }
2264 }
2265 Ok(())
2266 } else {
2267 Err(AutosarDataError::InvalidFile)
2269 }
2270 } else {
2271 Err(AutosarDataError::FilesetModificationForbidden)
2272 }
2273 }
2274
2275 pub(crate) fn add_to_file_restricted(&self, file: &ArxmlFile) -> Result<(), AutosarDataError> {
2277 let weak_file = file.downgrade();
2278 let (local, current_fileset) = self.file_membership().unwrap_or((true, HashSet::new()));
2279
2280 if !current_fileset.contains(&weak_file) {
2281 if self.element_type().splittable() != 0 {
2285 for se in self.sub_elements() {
2286 if let Some(mut subelem) = se.0.try_write_for(LOCK_CONTENTION_TIMEOUT)
2287 && subelem.file_membership.is_none()
2288 {
2289 subelem.set_file_membership(current_fileset.clone());
2290 }
2291 }
2292 }
2293
2294 let mut extended_fileset = current_fileset;
2295 extended_fileset.insert(weak_file);
2296 let parent_splittable = self.parent()?.is_none_or(|p| p.element_type().splittable() != 0);
2298 if parent_splittable || local {
2299 self.0.write().set_file_membership(extended_fileset);
2300 }
2301
2302 if let Some(parent) = self.parent()? {
2304 parent.add_to_file_restricted(file)?;
2305 }
2306 }
2307
2308 Ok(())
2309 }
2310
2311 pub fn remove_from_file(&self, file: &ArxmlFile) -> Result<(), AutosarDataError> {
2343 let parent_splittable = self.parent()?.is_none_or(|p| p.element_type().splittable() != 0);
2344 if parent_splittable {
2345 if file.model()? == self.model()? {
2346 let weak_file = file.downgrade();
2347
2348 let (_, current_fileset) = self.file_membership()?;
2350 let mut restricted_fileset = current_fileset;
2351 restricted_fileset.remove(&weak_file);
2352 if restricted_fileset.is_empty() {
2353 let Some(parent) = self.parent()? else {
2355 return Err(AutosarDataError::RootElementRemovalForbidden);
2356 };
2357 parent.remove_sub_element(self.to_owned())
2358 } else {
2359 self.0.write().set_file_membership(restricted_fileset);
2360
2361 let mut to_delete = Vec::new();
2363 for (_, subelem) in self.elements_dfs() {
2364 if subelem.0.read().file_membership.is_some() {
2366 subelem.0.write().remove_file_membership(&weak_file);
2367 if subelem.0.read().file_membership.is_none() {
2370 to_delete.push(subelem);
2371 }
2372 }
2373 }
2374 for delete_elem in to_delete {
2376 if let Ok(Some(parent)) = delete_elem.parent() {
2377 let _ = parent.remove_sub_element(delete_elem);
2378 }
2379 }
2380
2381 Ok(())
2382 }
2383 } else {
2384 Err(AutosarDataError::InvalidFile)
2386 }
2387 } else {
2388 Err(AutosarDataError::FilesetModificationForbidden)
2389 }
2390 }
2391
2392 #[must_use]
2397 pub fn xml_path(&self) -> String {
2398 self.0.read().xml_path()
2399 }
2400
2401 pub fn calc_element_insert_range(
2429 &self,
2430 element_name: ElementName,
2431 version: AutosarVersion,
2432 ) -> Result<(usize, usize), AutosarDataError> {
2433 self.0.read().calc_element_insert_range(element_name, version)
2434 }
2435
2436 #[must_use]
2457 pub fn comment(&self) -> Option<String> {
2458 self.0.read().comment.clone()
2459 }
2460
2461 pub fn set_comment(&self, mut opt_comment: Option<String>) {
2479 if let Some(comment) = &mut opt_comment {
2480 if comment.contains("--") {
2482 *comment = comment.replace("--", "__");
2483 }
2484 }
2485 self.0.write().comment = opt_comment;
2486 }
2487
2488 pub fn min_version(&self) -> Result<AutosarVersion, AutosarDataError> {
2511 let model = self.model()?;
2512 self.min_version_in(&model)
2513 }
2514
2515 pub(crate) fn model_and_version(&self) -> Result<(AutosarModel, AutosarVersion), AutosarDataError> {
2520 let model = self.model()?;
2521 let version = self.min_version_in(&model)?;
2522 Ok((model, version))
2523 }
2524
2525 fn min_version_in(&self, model: &AutosarModel) -> Result<AutosarVersion, AutosarDataError> {
2527 if let Some(version) = model.single_file_version() {
2528 return Ok(version);
2531 }
2532
2533 let mut cur_elem_opt = Some(self.clone());
2536 while let Some(cur_elem) = &cur_elem_opt {
2537 let locked_cur_elem = cur_elem
2538 .0
2539 .try_read_for(LOCK_CONTENTION_TIMEOUT)
2540 .ok_or(AutosarDataError::ParentElementLocked)?;
2541 if let Some(files) = locked_cur_elem.file_membership.as_deref() {
2542 let ver = files
2543 .iter()
2544 .filter_map(WeakArxmlFile::upgrade)
2545 .map(|f| f.version())
2546 .min()
2547 .unwrap_or(AutosarVersion::LATEST);
2548
2549 return Ok(ver);
2550 }
2551 let parent = locked_cur_elem.parent()?;
2554 drop(locked_cur_elem);
2555
2556 cur_elem_opt = parent;
2557 }
2558
2559 Err(AutosarDataError::NoFilesInModel)
2560 }
2561}
2562
2563impl Ord for Element {
2564 fn cmp(&self, other: &Element) -> std::cmp::Ordering {
2590 match self.element_name().to_str().cmp(other.element_name().to_str()) {
2592 Ordering::Equal => {}
2593 other => return other,
2594 }
2595
2596 let index1 = self
2599 .get_sub_element(ElementName::Index)
2600 .and_then(|indexelem| indexelem.character_data())
2601 .and_then(|cdata| cdata.parse_integer::<u64>());
2602 let index2 = other
2603 .get_sub_element(ElementName::Index)
2604 .and_then(|indexelem| indexelem.character_data())
2605 .and_then(|cdata| cdata.parse_integer::<u64>());
2606 match (index1, index2) {
2607 (Some(idx1), Some(idx2)) => {
2608 let result = idx1.cmp(&idx2);
2609 if result != Ordering::Equal {
2610 return result;
2611 }
2612 }
2613 (Some(_), None) => return std::cmp::Ordering::Less,
2614 (None, Some(_)) => return std::cmp::Ordering::Greater,
2615 (None, None) => {}
2616 }
2617
2618 if let (Some(name1), Some(name2)) = (self.item_name(), other.item_name()) {
2620 if let (Some((base1, idx1)), Some((base2, idx2))) =
2623 (decompose_item_name(&name1), decompose_item_name(&name2))
2624 && base1 == base2
2625 {
2626 let result = idx1.cmp(&idx2);
2627 if result != Ordering::Equal {
2628 return result;
2629 }
2630 }
2631 let result = name1.cmp(&name2);
2633 if result != Ordering::Equal {
2634 return result;
2635 }
2636 }
2637
2638 let definition1 = self
2640 .get_sub_element(ElementName::DefinitionRef)
2641 .and_then(|defref| defref.character_data())
2642 .and_then(|cdata| cdata.string_value());
2643 let definition2 = other
2644 .get_sub_element(ElementName::DefinitionRef)
2645 .and_then(|defref| defref.character_data())
2646 .and_then(|cdata| cdata.string_value());
2647 if let (Some(def1), Some(def2)) = (definition1, definition2) {
2648 let result = def1.cmp(&def2);
2649 if result != Ordering::Equal {
2650 return result;
2651 }
2652 }
2653
2654 let dest1 = self
2656 .attribute_value(AttributeName::Dest)
2657 .and_then(|cdata| cdata.enum_value());
2658 let dest2 = other
2659 .attribute_value(AttributeName::Dest)
2660 .and_then(|cdata| cdata.enum_value());
2661 match (dest1, dest2) {
2662 (Some(dest1), Some(dest2)) => {
2663 let result = dest1.to_str().cmp(dest2.to_str());
2664 if result != Ordering::Equal {
2665 return result;
2666 }
2667 }
2668 (Some(_), None) => return std::cmp::Ordering::Less,
2669 (None, Some(_)) => return std::cmp::Ordering::Greater,
2670 (None, None) => {}
2671 }
2672
2673 let locked_self = self.0.read();
2675 let locked_other = other.0.read();
2676 locked_self
2677 .content
2678 .cmp(&locked_other.content)
2679 .then(locked_self.attributes.cmp(&locked_other.attributes))
2680 }
2681}
2682
2683impl PartialOrd for Element {
2684 fn partial_cmp(&self, other: &Element) -> Option<std::cmp::Ordering> {
2685 Some(self.cmp(other))
2686 }
2687}
2688
2689fn decompose_item_name(name: &str) -> Option<(String, u64)> {
2694 let bytestr = name.as_bytes();
2695 let mut pos = bytestr.len();
2696 while pos > 0 && bytestr[pos - 1].is_ascii_digit() {
2697 pos -= 1;
2698 }
2699 if let Ok(index) = name[pos..].parse() {
2700 Some((name[0..pos].to_owned(), index))
2701 } else {
2702 None
2703 }
2704}
2705
2706struct ElementContentFormatter<'a>(&'a SmallVec<[ElementContent; 4]>);
2708impl std::fmt::Debug for ElementContentFormatter<'_> {
2709 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2710 let mut list_fmt = f.debug_list();
2711 for item in self.0.iter() {
2712 match item {
2713 ElementContent::Element(elem) => list_fmt.entry(&elem.element_name()),
2714 ElementContent::CharacterData(cdata) => list_fmt.entry(&cdata),
2715 };
2716 }
2717 list_fmt.finish()
2718 }
2719}
2720
2721struct DebugDisplay<'a>(&'a str);
2723impl std::fmt::Debug for DebugDisplay<'_> {
2724 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2725 f.write_str(self.0)
2726 }
2727}
2728
2729impl std::fmt::Debug for Element {
2731 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2732 let elem = self.0.read();
2733 let mut dbgstruct = f.debug_struct("Element");
2734 if let Some(name) = elem.item_name() {
2735 dbgstruct.field("name", &name);
2736 }
2737 dbgstruct.field("elemname", &elem.elemname);
2738 dbgstruct.field("elemtype", &elem.elemtype);
2739 dbgstruct.field("parent", &elem.parent);
2740 dbgstruct.field("content", &ElementContentFormatter(&elem.content));
2741 dbgstruct.field("attributes", &elem.attributes);
2742 if elem.elemtype.splittable() != 0 {
2745 if elem.file_membership.is_none() {
2746 dbgstruct.field("file_membership", &DebugDisplay("(inherited)"));
2747 } else {
2748 dbgstruct.field("file_membership", &elem.file_membership);
2749 }
2750 }
2751 dbgstruct.finish()
2752 }
2753}
2754
2755impl PartialEq for Element {
2756 fn eq(&self, other: &Self) -> bool {
2757 Arc::as_ptr(&self.0) == Arc::as_ptr(&other.0)
2758 }
2759}
2760
2761impl Eq for Element {}
2762
2763impl Hash for Element {
2764 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2765 state.write_usize(Arc::as_ptr(&self.0) as usize);
2766 }
2767}
2768
2769impl std::fmt::Debug for WeakElement {
2770 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2771 if let Some(elem) = self.upgrade() {
2772 f.write_fmt(format_args!("Element:WeakRef ({})", elem.element_name()))
2774 } else {
2775 f.write_fmt(format_args!("Element:WeakRef {:p} (invalid)", Weak::as_ptr(&self.0)))
2776 }
2777 }
2778}
2779
2780impl WeakElement {
2781 pub fn upgrade(&self) -> Option<Element> {
2783 Weak::upgrade(&self.0).map(Element)
2784 }
2785}
2786
2787impl PartialEq for WeakElement {
2788 fn eq(&self, other: &Self) -> bool {
2789 Weak::as_ptr(&self.0) == Weak::as_ptr(&other.0)
2790 }
2791}
2792
2793impl Eq for WeakElement {}
2794
2795impl Hash for WeakElement {
2796 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2797 state.write_usize(Weak::as_ptr(&self.0) as usize);
2798 }
2799}
2800
2801impl ElementContent {
2802 #[must_use]
2804 pub fn unwrap_element(&self) -> Option<Element> {
2805 if let ElementContent::Element(element) = self {
2806 Some(element.clone())
2807 } else {
2808 None
2809 }
2810 }
2811
2812 #[must_use]
2814 pub fn unwrap_cdata(&self) -> Option<CharacterData> {
2815 if let ElementContent::CharacterData(cdata) = self {
2816 Some(cdata.clone())
2817 } else {
2818 None
2819 }
2820 }
2821}
2822
2823impl std::fmt::Debug for ElementOrModel {
2825 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2826 match self {
2827 ElementOrModel::Element(..) => f.write_str("Element"),
2828 ElementOrModel::Model(_) => f.write_str("Model"),
2829 ElementOrModel::None => f.write_str("None/Invalid"),
2830 }
2831 }
2832}
2833
2834impl std::fmt::Debug for ElementContent {
2836 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2837 match self {
2838 ElementContent::Element(elem) => elem.fmt(f),
2839 ElementContent::CharacterData(cdata) => cdata.fmt(f),
2840 }
2841 }
2842}
2843
2844#[cfg(test)]
2845mod test {
2846 use crate::*;
2847 use std::ffi::OsString;
2848
2849 const BASIC_AUTOSAR_FILE: &str = r#"<?xml version="1.0" encoding="utf-8"?>
2850 <AUTOSAR xsi:schemaLocation="http://autosar.org/schema/r4.0 AUTOSAR_00050.xsd" xmlns="http://autosar.org/schema/r4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2851 <AR-PACKAGES>
2852 <AR-PACKAGE>
2853 <SHORT-NAME>TestPackage</SHORT-NAME>
2854 </AR-PACKAGE>
2855 </AR-PACKAGES>
2856 </AUTOSAR>"#;
2857
2858 #[test]
2859 fn element_creation() {
2860 let model = AutosarModel::new();
2861 model
2862 .load_buffer(BASIC_AUTOSAR_FILE.as_bytes(), OsString::from("test.arxml"), true)
2863 .unwrap();
2864 let el_autosar = model.root_element();
2865 let el_ar_package = model.get_element_by_path("/TestPackage").unwrap();
2866
2867 let el_elements = el_ar_package.create_sub_element(ElementName::Elements).unwrap();
2868 let el_compu_method = el_elements
2869 .create_named_sub_element(ElementName::CompuMethod, "TestCompuMethod")
2870 .unwrap();
2871 el_elements
2872 .create_named_sub_element(ElementName::CompuMethod, "TestCompuMethod2")
2873 .unwrap();
2874 el_elements
2875 .create_named_sub_element(ElementName::CompuMethod, "TestCompuMethod3")
2876 .unwrap();
2877 assert!(
2879 el_elements
2880 .create_named_sub_element(ElementName::CompuMethod, "TestCompuMethod3")
2881 .is_err()
2882 );
2883
2884 let count = el_elements.sub_elements().count();
2885 assert_eq!(count, 3);
2886 assert_eq!(count, el_elements.content_item_count());
2887
2888 let (start_pos, end_pos) = el_elements
2890 .0
2891 .read()
2892 .calc_element_insert_range(ElementName::CompuMethod, AutosarVersion::Autosar_00050)
2893 .unwrap();
2894 assert_eq!(start_pos, 0);
2895 assert_eq!(end_pos, 3); let el_compu_method_test = model.get_element_by_path("/TestPackage/TestCompuMethod").unwrap();
2899 assert_eq!(el_compu_method, el_compu_method_test);
2900
2901 let el_compu_internal_to_phys = el_compu_method
2903 .create_sub_element(ElementName::CompuInternalToPhys)
2904 .unwrap();
2905 let el_compu_scales = el_compu_internal_to_phys
2906 .create_sub_element(ElementName::CompuScales)
2907 .unwrap();
2908 let el_compu_scale = el_compu_scales.create_sub_element(ElementName::CompuScale).unwrap();
2909 el_compu_scale.create_sub_element(ElementName::Desc).unwrap();
2910
2911 let (start_pos, end_pos) = el_compu_scale
2913 .calc_element_insert_range(ElementName::ShortLabel, AutosarVersion::Autosar_00050)
2914 .unwrap();
2915 assert_eq!(start_pos, 0);
2916 assert_eq!(end_pos, 0);
2917
2918 let (start_pos, end_pos) = el_compu_scale
2920 .calc_element_insert_range(ElementName::CompuConst, AutosarVersion::Autosar_00050)
2921 .unwrap();
2922 assert_eq!(start_pos, 1);
2923 assert_eq!(end_pos, 1);
2924
2925 el_compu_scale
2927 .create_sub_element(ElementName::CompuRationalCoeffs)
2928 .unwrap();
2929 let result = el_compu_scale.calc_element_insert_range(ElementName::CompuConst, AutosarVersion::Autosar_00050);
2931 assert!(result.is_err());
2932 let result =
2934 el_compu_scale.calc_element_insert_range(ElementName::CompuRationalCoeffs, AutosarVersion::Autosar_00050);
2935 assert!(result.is_err());
2936
2937 assert!(
2939 el_elements
2940 .create_named_sub_element_at(ElementName::System, "System", 99)
2941 .is_err()
2942 );
2943 assert!(el_autosar.create_sub_element_at(ElementName::AdminData, 99).is_err());
2944
2945 assert!(el_elements.create_sub_element(ElementName::System).is_err());
2947 assert!(el_elements.create_named_sub_element(ElementName::System, "").is_err());
2949 assert!(
2950 el_elements
2951 .create_named_sub_element(ElementName::System, "abc def")
2952 .is_err()
2953 );
2954
2955 assert!(
2957 el_autosar
2958 .create_named_sub_element(ElementName::AdminData, "AdminData")
2959 .is_err()
2960 );
2961
2962 assert!(
2964 el_autosar
2965 .create_named_sub_element(ElementName::Autosar, "Autosar")
2966 .is_err()
2967 );
2968 assert!(
2969 el_autosar
2970 .create_named_sub_element_at(ElementName::Autosar, "Autosar", 0)
2971 .is_err()
2972 );
2973 assert!(el_autosar.create_sub_element(ElementName::Autosar).is_err());
2974 assert!(el_autosar.create_sub_element_at(ElementName::Autosar, 0).is_err());
2975
2976 let el_autosar_locked = el_autosar.0.write();
2978 assert!(
2979 el_elements
2980 .create_named_sub_element(ElementName::System, "System")
2981 .is_err()
2982 );
2983 assert!(
2984 el_elements
2985 .create_named_sub_element_at(ElementName::System, "System", 0)
2986 .is_err()
2987 );
2988 assert!(el_autosar.create_sub_element(ElementName::AdminData).is_err());
2989 assert!(el_autosar.create_sub_element_at(ElementName::AdminData, 0).is_err());
2990 drop(el_autosar_locked);
2991 }
2992
2993 #[test]
2994 fn element_creation_after_nonstrict_load() {
2995 let file_content = r#"<?xml version="1.0" encoding="utf-8"?>
2998 <AUTOSAR xsi:schemaLocation="http://autosar.org/schema/r4.0 AUTOSAR_4-0-1.xsd" xmlns="http://autosar.org/schema/r4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2999 <AR-PACKAGES><AR-PACKAGE><SHORT-NAME>Pkg</SHORT-NAME><ELEMENTS>
3000 <SYSTEM><SHORT-NAME>Sys</SHORT-NAME><PNC-VECTOR-LENGTH>8</PNC-VECTOR-LENGTH></SYSTEM>
3001 </ELEMENTS></AR-PACKAGE></AR-PACKAGES>
3002 </AUTOSAR>"#;
3003 let model = AutosarModel::new();
3004 let (_, warnings) = model
3005 .load_buffer(file_content.as_bytes(), OsString::from("test.arxml"), false)
3006 .unwrap();
3007 assert!(!warnings.is_empty());
3008
3009 let el_system = model.get_element_by_path("/Pkg/Sys").unwrap();
3012 el_system.create_sub_element(ElementName::FibexElements).unwrap();
3013 }
3014
3015 #[test]
3016 fn parent() {
3017 let model = AutosarModel::new();
3018 model.create_file("test.arxml", AutosarVersion::Autosar_00050).unwrap();
3019 let el_autosar = model.root_element();
3020 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
3021 let el_ar_package = el_ar_packages
3022 .create_named_sub_element(ElementName::ArPackage, "Package")
3023 .unwrap();
3024 let el_elements = el_ar_package.create_sub_element(ElementName::Elements).unwrap();
3025 let el_system = el_elements
3026 .create_named_sub_element(ElementName::System, "Sys")
3027 .unwrap();
3028 let el_fibex = el_system.create_sub_element(ElementName::FibexElements).unwrap();
3029 let el_fibex_cond = el_fibex
3030 .create_sub_element(ElementName::FibexElementRefConditional)
3031 .unwrap();
3032
3033 let parent = el_fibex_cond.parent().unwrap().unwrap();
3034 assert_eq!(parent, el_fibex);
3035 let named_parent = el_fibex_cond.named_parent().unwrap().unwrap();
3036 assert_eq!(named_parent, el_system);
3037
3038 let named_parent = el_system.named_parent().unwrap().unwrap();
3039 assert_eq!(named_parent, el_ar_package);
3040
3041 let named_parent = el_autosar.named_parent().unwrap();
3042 assert!(named_parent.is_none());
3043
3044 el_autosar.remove_sub_element(el_ar_packages).unwrap();
3046 assert!(el_ar_package.named_parent().is_err());
3047 }
3048
3049 #[test]
3050 fn package() {
3051 let model = AutosarModel::new();
3052 model.create_file("test.arxml", AutosarVersion::Autosar_00050).unwrap();
3053 let el_autosar = model.root_element();
3054 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
3055 let el_ar_package = el_ar_packages
3056 .create_named_sub_element(ElementName::ArPackage, "Package")
3057 .unwrap();
3058 let el_ar_packages_2 = el_ar_package.create_sub_element(ElementName::ArPackages).unwrap();
3059 let el_ar_package_2 = el_ar_packages_2
3060 .create_named_sub_element(ElementName::ArPackage, "SubPackage")
3061 .unwrap();
3062
3063 assert_eq!(el_ar_package.package().unwrap(), None); assert_eq!(el_ar_packages_2.package().unwrap().unwrap(), el_ar_package);
3065 assert_eq!(el_ar_package_2.package().unwrap().unwrap(), el_ar_package); drop(el_autosar);
3068 drop(model);
3069 assert!(el_ar_package.package().is_err()); }
3071
3072 #[test]
3073 fn element_rename() {
3074 let model = AutosarModel::new();
3075 model.create_file("test.arxml", AutosarVersion::Autosar_00050).unwrap();
3076 let el_autosar = model.root_element();
3077 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
3078 let el_ar_package = el_ar_packages
3079 .create_named_sub_element(ElementName::ArPackage, "Package")
3080 .unwrap();
3081 let el_elements = el_ar_package.create_sub_element(ElementName::Elements).unwrap();
3082 let el_can_cluster = el_elements
3083 .create_named_sub_element_at(ElementName::CanCluster, "CanCluster", 0)
3084 .unwrap();
3085 let el_can_physical_channel = el_can_cluster
3086 .create_sub_element(ElementName::CanClusterVariants)
3087 .and_then(|ccv| ccv.create_sub_element(ElementName::CanClusterConditional))
3088 .and_then(|ccc| ccc.create_sub_element(ElementName::PhysicalChannels))
3089 .and_then(|pc| pc.create_named_sub_element(ElementName::CanPhysicalChannel, "CanPhysicalChannel"))
3090 .unwrap();
3091
3092 let el_can_frame_triggering = el_can_physical_channel
3093 .create_sub_element_at(ElementName::FrameTriggerings, 1)
3094 .and_then(|ft| ft.create_named_sub_element(ElementName::CanFrameTriggering, "CanFrameTriggering"))
3095 .unwrap();
3096
3097 let el_ar_package2 = el_ar_packages
3098 .create_named_sub_element(ElementName::ArPackage, "Package2")
3099 .unwrap();
3100 let el_can_frame = el_ar_package2
3101 .create_sub_element(ElementName::Elements)
3102 .and_then(|e| e.create_named_sub_element(ElementName::CanFrame, "CanFrame"))
3103 .unwrap();
3104 let el_frame_ref = el_can_frame_triggering
3105 .create_sub_element(ElementName::FrameRef)
3106 .unwrap();
3107 let _ = el_frame_ref.set_reference_target(&el_can_frame);
3108
3109 let refstr = el_frame_ref.character_data().unwrap().string_value().unwrap();
3111 assert_eq!(refstr, "/Package2/CanFrame");
3112
3113 let result = el_ar_package.set_item_name("");
3115 assert!(result.is_err());
3116
3117 el_ar_package.set_item_name("NewPackage").unwrap();
3119 el_ar_package.set_item_name("NewPackage").unwrap();
3121
3122 let result = el_ar_package2.set_item_name("NewPackage");
3124 assert!(result.is_err());
3125
3126 el_ar_package2.set_item_name("OtherPackage").unwrap();
3128 let refstr = el_frame_ref.character_data().unwrap().string_value().unwrap();
3129 assert_eq!(refstr, "/OtherPackage/CanFrame");
3130
3131 let el_can_frame2 = el_frame_ref.get_reference_target().unwrap();
3133 assert_eq!(el_can_frame, el_can_frame2);
3134
3135 el_can_frame.set_item_name("CanFrame_renamed").unwrap();
3137 let refstr = el_frame_ref.character_data().unwrap().string_value().unwrap();
3138 assert_eq!(refstr, "/OtherPackage/CanFrame_renamed");
3139
3140 assert!(el_autosar.set_item_name("Autosar").is_err());
3142
3143 let el_autosar_locked = el_autosar.0.write();
3145 assert!(el_ar_package.set_item_name("TestPackage_renamed").is_err());
3147 drop(el_autosar_locked);
3148 drop(model);
3149 assert!(el_ar_package.set_item_name("TestPackage_renamed").is_err());
3151 }
3152
3153 #[test]
3154 fn element_copy() {
3155 let model = AutosarModel::new();
3156 model
3157 .load_buffer(BASIC_AUTOSAR_FILE.as_bytes(), OsString::from("test.arxml"), true)
3158 .unwrap();
3159 model.create_file("test", AutosarVersion::LATEST).unwrap();
3160 let el_ar_package = model.get_element_by_path("/TestPackage").unwrap();
3161 el_ar_package
3162 .set_attribute(AttributeName::Uuid, CharacterData::String("0123456".to_string()))
3163 .unwrap();
3164 let el_elements = el_ar_package.create_sub_element(ElementName::Elements).unwrap();
3165 let el_compu_method = el_elements
3166 .create_named_sub_element(ElementName::CompuMethod, "CompuMethod")
3167 .unwrap();
3168 el_elements
3169 .create_named_sub_element(ElementName::DdsServiceInstanceToMachineMapping, "ApItem")
3170 .unwrap();
3171 el_elements
3172 .create_named_sub_element(ElementName::AclObjectSet, "AclObjectSet")
3173 .and_then(|el| el.create_sub_element(ElementName::DerivedFromBlueprintRefs))
3174 .and_then(|el| el.create_sub_element(ElementName::DerivedFromBlueprintRef))
3175 .and_then(|el| {
3176 el.set_attribute(
3177 AttributeName::Dest,
3178 CharacterData::Enum(EnumItem::AbstractImplementationDataType),
3179 )
3180 })
3181 .unwrap();
3182 el_elements
3183 .create_named_sub_element(ElementName::System, "System")
3184 .and_then(|el| el.create_sub_element(ElementName::FibexElements))
3185 .and_then(|el| el.create_sub_element(ElementName::FibexElementRefConditional))
3186 .and_then(|el| el.create_sub_element(ElementName::FibexElementRef))
3187 .and_then(|el| el.set_character_data("/invalid"))
3188 .unwrap();
3189
3190 let project2 = AutosarModel::new();
3191 project2
3192 .create_file("test.arxml", AutosarVersion::Autosar_00044)
3193 .unwrap();
3194
3195 let result = project2.root_element().create_copied_sub_element(&el_ar_package);
3197 assert!(result.is_err());
3198
3199 let el_ar_packages2 = project2
3203 .root_element()
3204 .create_sub_element(ElementName::ArPackages)
3205 .unwrap();
3206 el_ar_packages2.create_copied_sub_element(&el_ar_package).unwrap();
3207
3208 let el_compu_method_2 = project2.get_element_by_path("/TestPackage/CompuMethod").unwrap();
3210
3211 assert_ne!(el_compu_method, el_compu_method_2);
3213 assert_eq!(el_compu_method.serialize(), el_compu_method_2.serialize());
3215
3216 let result = project2.get_element_by_path("/TestPackage/ApItem");
3218 assert!(result.is_none());
3219
3220 let el_ar_package2 = el_ar_packages2
3222 .create_named_sub_element(ElementName::ArPackage, "Package2")
3223 .unwrap();
3224 let result = el_ar_package2.create_copied_sub_element_at(&el_elements, 0);
3225 assert!(result.is_err()); let el_elements2 = el_ar_package2.create_sub_element(ElementName::Elements).unwrap();
3227 let result = el_elements2.create_copied_sub_element_at(&el_compu_method, 99);
3228 assert!(result.is_err()); let result = el_elements2.create_copied_sub_element_at(&el_compu_method, 0);
3230 assert!(result.is_ok()); let result = el_ar_package2.create_copied_sub_element_at(&el_compu_method, 0);
3234 assert!(result.is_err()); }
3236
3237 #[test]
3238 fn element_copy_loop() {
3239 let model = AutosarModel::new();
3240 model.create_file("test.arxml", AutosarVersion::Autosar_00050).unwrap();
3241 let el_autosar = model.root_element();
3242 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
3243 let el_ar_package = el_ar_packages
3244 .create_named_sub_element(ElementName::ArPackage, "Pkg")
3245 .unwrap();
3246
3247 let result = el_ar_package.create_copied_sub_element(&el_ar_packages);
3248 assert!(result.is_err());
3249
3250 let result = el_ar_package.create_copied_sub_element(&el_ar_package);
3252 assert!(result.is_err());
3253 let result = el_ar_package.create_copied_sub_element_at(&el_ar_package, 0);
3254 assert!(result.is_err());
3255 }
3256
3257 #[test]
3258 fn element_self_reference_loop() {
3259 let model = AutosarModel::new();
3260 model.create_file("test.arxml", AutosarVersion::Autosar_00050).unwrap();
3261 let el_autosar = model.root_element();
3262 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
3263 let el_ar_package = el_ar_packages
3264 .create_named_sub_element(ElementName::ArPackage, "Pkg")
3265 .unwrap();
3266
3267 let result = el_ar_package.remove_sub_element(el_ar_package.clone());
3269 assert!(matches!(result, Err(AutosarDataError::ElementNotFound { .. })));
3270
3271 let result = el_ar_packages.move_element_here(&el_ar_packages.clone());
3273 assert!(matches!(result, Err(AutosarDataError::ForbiddenMoveToSubElement)));
3274 let result = el_ar_packages.move_element_here_at(&el_ar_packages.clone(), 0);
3275 assert!(matches!(result, Err(AutosarDataError::ForbiddenMoveToSubElement)));
3276 }
3277
3278 #[test]
3279 fn element_deletion() {
3280 let model = AutosarModel::new();
3281 model
3282 .load_buffer(BASIC_AUTOSAR_FILE.as_bytes(), OsString::from("test.arxml"), true)
3283 .unwrap();
3284 let el_ar_package = model.get_element_by_path("/TestPackage").unwrap();
3285 let el_short_name = el_ar_package.get_sub_element(ElementName::ShortName).unwrap();
3286 el_ar_package
3287 .create_sub_element(ElementName::Elements)
3288 .and_then(|el| el.create_named_sub_element(ElementName::System, "System"))
3289 .and_then(|el| el.create_sub_element(ElementName::FibexElements))
3290 .and_then(|el| el.create_sub_element(ElementName::FibexElementRefConditional))
3291 .and_then(|el| el.create_sub_element(ElementName::FibexElementRef))
3292 .and_then(|el| el.set_character_data("/invalid"))
3293 .unwrap();
3294
3295 let result = el_ar_package.remove_sub_element(el_short_name);
3297 if let Err(AutosarDataError::ShortNameRemovalForbidden) = result {
3298 } else {
3300 panic!("Removing the SHORT-NAME was not prohibited");
3301 }
3302 let el_ar_package_clone = el_ar_package.clone();
3303 let el_ar_packages = el_ar_package.parent().unwrap().unwrap();
3304 let result = el_ar_packages.remove_sub_element(el_ar_package);
3305 assert_eq!(model.0.read().identifiables.len(), 0);
3307 assert!(result.is_ok());
3308
3309 el_ar_packages
3311 .create_named_sub_element(ElementName::ArPackage, "SecondPackage")
3312 .unwrap();
3313 assert_eq!(el_ar_packages.content_item_count(), 1);
3314 let result = el_ar_packages.remove_sub_element_kind(ElementName::ArPackage);
3315 assert!(result.is_ok());
3316 assert_eq!(el_ar_packages.content_item_count(), 0);
3317 let result = el_ar_packages.remove_sub_element_kind(ElementName::ArPackage);
3318 assert!(result.is_err());
3319
3320 let result = el_ar_package_clone.parent();
3322 assert!(matches!(result, Err(AutosarDataError::ItemDeleted)));
3323 let result = el_ar_package_clone.model();
3324 assert!(matches!(result, Err(AutosarDataError::ItemDeleted)));
3325 assert_eq!(el_ar_package_clone.position(), None);
3326 }
3327
3328 #[test]
3329 fn element_position() {
3330 let model = AutosarModel::new();
3331 model.create_file("test.arxml", AutosarVersion::Autosar_00050).unwrap();
3332 let el_autosar = model.root_element();
3333 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
3334 let el_ar_package1 = el_ar_packages
3335 .create_named_sub_element(ElementName::ArPackage, "Pkg1")
3336 .unwrap();
3337 let el_ar_package2 = el_ar_packages
3338 .create_named_sub_element(ElementName::ArPackage, "Pkg2")
3339 .unwrap();
3340 let el_ar_package3 = el_ar_packages
3341 .create_named_sub_element(ElementName::ArPackage, "Pkg3")
3342 .unwrap();
3343
3344 assert_eq!(el_ar_packages.content_item_count(), 3);
3345 assert_eq!(el_ar_package2.position().unwrap(), 1);
3346 assert_eq!(el_ar_packages.get_sub_element_at(1).unwrap(), el_ar_package2);
3347 assert_eq!(el_ar_package3.position().unwrap(), 2);
3348 assert_eq!(el_ar_packages.get_sub_element_at(2).unwrap(), el_ar_package3);
3349
3350 let nonexistent = el_ar_package1.get_sub_element_at(1);
3352 assert_eq!(nonexistent, None);
3353 }
3354
3355 #[test]
3356 fn element_type() {
3357 let model = AutosarModel::new();
3358 model.create_file("test.arxml", AutosarVersion::Autosar_00050).unwrap();
3359 let el_autosar = model.root_element();
3360
3361 assert_eq!(el_autosar.element_type(), ElementType::ROOT);
3362 }
3363
3364 #[test]
3365 fn content_type() {
3366 let model = AutosarModel::new();
3367 model.create_file("test.arxml", AutosarVersion::Autosar_00050).unwrap();
3368 let el_autosar = model.root_element();
3369 let el_ar_package = el_autosar
3370 .create_sub_element(ElementName::ArPackages)
3371 .and_then(|ar_pkgs| ar_pkgs.create_named_sub_element(ElementName::ArPackage, "Package"))
3372 .unwrap();
3373 let el_short_name = el_ar_package.get_sub_element(ElementName::ShortName).unwrap();
3374
3375 let el_l4 = el_ar_package
3376 .create_sub_element(ElementName::LongName)
3377 .and_then(|ln| ln.create_sub_element(ElementName::L4))
3378 .unwrap();
3379
3380 let el_elements = el_ar_package.create_sub_element(ElementName::Elements).unwrap();
3381 let el_debounce_algo = el_elements
3382 .create_named_sub_element(ElementName::DiagnosticContributionSet, "DCS")
3383 .and_then(|dcs| dcs.create_sub_element(ElementName::CommonProperties))
3384 .and_then(|cp| cp.create_sub_element(ElementName::DiagnosticCommonPropsVariants))
3385 .and_then(|dcpv| dcpv.create_sub_element(ElementName::DiagnosticCommonPropsConditional))
3386 .and_then(|dcpc| dcpc.create_sub_element(ElementName::DebounceAlgorithmPropss))
3387 .and_then(|dap| dap.create_named_sub_element(ElementName::DiagnosticDebounceAlgorithmProps, "ddap"))
3388 .and_then(|ddap| ddap.create_sub_element(ElementName::DebounceAlgorithm))
3389 .unwrap();
3390
3391 assert_eq!(el_autosar.element_type().content_mode(), ContentMode::Sequence);
3392 assert_eq!(el_autosar.content_type(), ContentType::Elements);
3393 assert_eq!(el_elements.element_type().content_mode(), ContentMode::Bag);
3394 assert_eq!(el_elements.content_type(), ContentType::Elements);
3395 assert_eq!(el_debounce_algo.element_type().content_mode(), ContentMode::Choice);
3396 assert_eq!(el_debounce_algo.content_type(), ContentType::Elements);
3397 assert_eq!(el_short_name.element_type().content_mode(), ContentMode::Characters);
3398 assert_eq!(el_short_name.content_type(), ContentType::CharacterData);
3399 assert_eq!(el_l4.element_type().content_mode(), ContentMode::Mixed);
3400 assert_eq!(el_l4.content_type(), ContentType::Mixed);
3401 }
3402
3403 #[test]
3404 fn attributes() {
3405 let model = AutosarModel::new();
3406 model
3407 .load_buffer(BASIC_AUTOSAR_FILE.as_bytes(), OsString::from("test.arxml"), true)
3408 .unwrap();
3409 model.create_file("test", AutosarVersion::LATEST).unwrap();
3410 let el_autosar = model.root_element();
3411 let el_ar_packages = el_autosar.get_sub_element(ElementName::ArPackages).unwrap();
3412
3413 let count = el_autosar.attributes().count();
3414 assert_eq!(count, 3);
3415
3416 el_autosar
3418 .set_attribute(AttributeName::S, CharacterData::String(String::from("something")))
3419 .unwrap();
3420
3421 assert!(
3423 el_autosar
3424 .set_attribute(AttributeName::Dest, CharacterData::String(String::from("something")))
3425 .is_err()
3426 );
3427
3428 let result = el_autosar.remove_attribute(AttributeName::S);
3430 assert!(result);
3431
3432 let result = el_autosar.remove_attribute(AttributeName::xmlns);
3434 assert!(!result);
3435
3436 let result = el_autosar.remove_attribute(AttributeName::Accesskey);
3438 assert!(!result);
3439
3440 el_autosar
3442 .set_attribute_string(AttributeName::T, "2022-01-31T13:00:59Z")
3443 .unwrap();
3444
3445 el_autosar
3447 .set_attribute_string(AttributeName::T, "2022-01-31T14:00:59Z")
3448 .unwrap();
3449
3450 assert!(el_autosar.set_attribute_string(AttributeName::T, "abc").is_err());
3452
3453 assert!(
3455 el_ar_packages
3456 .set_attribute_string(AttributeName::xmlns, "abc")
3457 .is_err()
3458 );
3459
3460 let xmlns = el_autosar
3462 .attribute_value(AttributeName::xmlns)
3463 .map(|cdata| cdata.to_string())
3464 .unwrap();
3465 assert_eq!(xmlns, "http://autosar.org/schema/r4.0".to_string());
3466
3467 let lock = el_autosar.0.write();
3469 assert!(
3470 el_ar_packages
3471 .set_attribute(AttributeName::Uuid, CharacterData::String(String::from("1234")))
3472 .is_err()
3473 );
3474 assert!(
3475 el_ar_packages
3476 .set_attribute_string(AttributeName::Uuid, "1234")
3477 .is_err()
3478 );
3479 drop(lock);
3480 }
3481
3482 #[test]
3483 fn mixed_content() {
3484 let model = AutosarModel::new();
3485 model
3486 .load_buffer(BASIC_AUTOSAR_FILE.as_bytes(), OsString::from("test.arxml"), true)
3487 .unwrap();
3488 let el_ar_package = model.get_element_by_path("/TestPackage").unwrap();
3489 let el_long_name = el_ar_package.create_sub_element(ElementName::LongName).unwrap();
3490 assert_eq!(el_long_name.content_type(), ContentType::Elements);
3491 let el_l_4 = el_long_name.create_sub_element(ElementName::L4).unwrap();
3492 assert_eq!(el_l_4.content_type(), ContentType::Mixed);
3493
3494 el_l_4.create_sub_element(ElementName::E).unwrap();
3495 el_l_4.insert_character_content_item("foo", 1).unwrap();
3496 el_l_4.create_sub_element(ElementName::Sup).unwrap();
3497 el_l_4.insert_character_content_item("bar", 0).unwrap();
3498 assert_eq!(el_l_4.content().count(), 4);
3499
3500 assert!(el_l_4.remove_character_content_item(2).is_ok());
3502 assert_eq!(el_l_4.content().count(), 3);
3503 let item = el_l_4.content().next().unwrap();
3505 if let ElementContent::CharacterData(CharacterData::String(content)) = item {
3506 assert_eq!(content, "bar");
3507 } else {
3508 panic!("unexpected content in <L-4>: {item:?}");
3509 }
3510 }
3511
3512 #[test]
3513 fn move_element_position() {
3514 let model = AutosarModel::new();
3516 model.create_file("test.arxml", AutosarVersion::Autosar_00050).unwrap();
3517 let el_autosar = model.root_element();
3518 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
3519 let pkg1 = el_ar_packages
3520 .create_named_sub_element(ElementName::ArPackage, "Pkg1")
3521 .unwrap();
3522 let pkg2 = el_ar_packages
3523 .create_named_sub_element(ElementName::ArPackage, "Pkg2")
3524 .unwrap();
3525 let pkg3 = el_ar_packages
3526 .create_named_sub_element(ElementName::ArPackage, "Pkg3")
3527 .unwrap();
3528
3529 el_ar_packages.move_element_here(&pkg3).unwrap();
3531
3532 assert!(el_ar_packages.move_element_here_at(&pkg1, 99).is_err());
3534 assert!(el_ar_packages.move_element_here_at(&pkg1, 3).is_err()); el_ar_packages.move_element_here_at(&pkg2, 0).unwrap();
3538 el_ar_packages.move_element_here_at(&pkg1, 2).unwrap();
3540 let mut packages_iter = el_ar_packages.sub_elements();
3542 assert_eq!(packages_iter.next().unwrap(), pkg2);
3543 assert_eq!(packages_iter.next().unwrap(), pkg3);
3544 assert_eq!(packages_iter.next().unwrap(), pkg1);
3545
3546 let el_l_4 = pkg1
3548 .create_sub_element(ElementName::LongName)
3549 .and_then(|el| el.create_sub_element(ElementName::L4))
3550 .unwrap();
3551 el_l_4.create_sub_element(ElementName::E).unwrap();
3552 el_l_4.insert_character_content_item("foo", 1).unwrap();
3553 let el_sup = el_l_4.create_sub_element(ElementName::Sup).unwrap();
3554 el_l_4.insert_character_content_item("bar", 0).unwrap();
3555 el_l_4.move_element_here_at(&el_sup, 0).unwrap();
3556 let mut iter = el_l_4.sub_elements();
3557 assert_eq!(iter.next().unwrap(), el_sup);
3558 }
3559
3560 #[test]
3561 fn move_element_local() {
3562 let model = AutosarModel::new();
3564 model.create_file("test.arxml", AutosarVersion::Autosar_00050).unwrap();
3565 let el_autosar = model.root_element();
3566 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
3567 let el_pkg1 = el_ar_packages
3568 .create_named_sub_element(ElementName::ArPackage, "Pkg1")
3569 .unwrap();
3570 let el_elements1 = el_pkg1.create_sub_element(ElementName::Elements).unwrap();
3571 let el_ecu_instance = el_elements1
3572 .create_named_sub_element(ElementName::EcuInstance, "EcuInstance")
3573 .unwrap();
3574 let el_pkg2 = el_ar_packages
3575 .create_named_sub_element(ElementName::ArPackage, "Pkg2")
3576 .unwrap();
3577 let el_pkg3 = el_ar_packages
3578 .create_named_sub_element(ElementName::ArPackage, "Pkg3")
3579 .unwrap();
3580 let el_fibex_element_ref = el_pkg3
3581 .create_sub_element(ElementName::Elements)
3582 .and_then(|el| el.create_named_sub_element(ElementName::System, "System"))
3583 .and_then(|el| el.create_sub_element(ElementName::FibexElements))
3584 .and_then(|el| el.create_sub_element(ElementName::FibexElementRefConditional))
3585 .and_then(|el| el.create_sub_element(ElementName::FibexElementRef))
3586 .unwrap();
3587 el_fibex_element_ref.set_reference_target(&el_ecu_instance).unwrap();
3588
3589 assert!(el_ar_packages.move_element_here(&el_autosar).is_err());
3591 assert!(el_ar_packages.move_element_here_at(&el_autosar, 0).is_err());
3592
3593 assert!(el_pkg1.move_element_here(&el_ar_packages).is_err());
3595 assert!(el_pkg1.move_element_here_at(&el_ar_packages, 1).is_err());
3596
3597 assert!(model.get_element_by_path("/Pkg1/EcuInstance").is_some());
3599 el_pkg2.move_element_here(&el_elements1).unwrap();
3600 assert_eq!(el_elements1.parent().unwrap().unwrap(), el_pkg2);
3601 assert!(model.get_element_by_path("/Pkg2/EcuInstance").is_some());
3602 assert_eq!(el_fibex_element_ref.get_reference_target().unwrap(), el_ecu_instance);
3603
3604 el_pkg1.move_element_here_at(&el_elements1, 1).unwrap();
3606 assert_eq!(el_elements1.parent().unwrap().unwrap(), el_pkg1);
3607 assert!(model.get_element_by_path("/Pkg1/EcuInstance").is_some());
3608 assert_eq!(el_fibex_element_ref.get_reference_target().unwrap(), el_ecu_instance);
3609
3610 let el_elements2 = el_pkg2.create_sub_element(ElementName::Elements).unwrap();
3612 el_elements2.move_element_here(&el_ecu_instance).unwrap();
3613 assert_eq!(el_ecu_instance.parent().unwrap().unwrap(), el_elements2);
3614 assert!(model.get_element_by_path("/Pkg2/EcuInstance").is_some());
3615 assert_eq!(el_fibex_element_ref.get_reference_target().unwrap(), el_ecu_instance);
3616
3617 el_elements1
3619 .create_named_sub_element(ElementName::EcuInstance, "EcuInstance")
3620 .unwrap();
3621 el_elements1.move_element_here_at(&el_ecu_instance, 0).unwrap();
3622 assert_eq!(el_ecu_instance.parent().unwrap().unwrap(), el_elements1);
3623 assert!(model.get_element_by_path("/Pkg1/EcuInstance_1").is_some());
3624 assert_eq!(el_fibex_element_ref.get_reference_target().unwrap(), el_ecu_instance);
3625 }
3626
3627 #[test]
3628 fn move_element_full() {
3629 let model1 = AutosarModel::new();
3631 model1
3632 .create_file("test1.arxml", AutosarVersion::Autosar_00050)
3633 .unwrap();
3634 let el_autosar = model1.root_element();
3635 let el_ar_packages1 = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
3636 let el_pkg1 = el_ar_packages1
3637 .create_named_sub_element(ElementName::ArPackage, "Pkg1")
3638 .unwrap();
3639 let el_elements1 = el_pkg1.create_sub_element(ElementName::Elements).unwrap();
3640 let el_ecu_instance = el_elements1
3641 .create_named_sub_element(ElementName::EcuInstance, "EcuInstance")
3642 .unwrap();
3643 let el_pkg2 = el_ar_packages1
3644 .create_named_sub_element(ElementName::ArPackage, "Pkg2")
3645 .unwrap();
3646 let el_fibex_element_ref = el_pkg2
3647 .create_sub_element(ElementName::Elements)
3648 .and_then(|el| el.create_named_sub_element(ElementName::System, "System"))
3649 .and_then(|el| el.create_sub_element(ElementName::FibexElements))
3650 .and_then(|el| el.create_sub_element(ElementName::FibexElementRefConditional))
3651 .and_then(|el| el.create_sub_element(ElementName::FibexElementRef))
3652 .unwrap();
3653 el_fibex_element_ref.set_reference_target(&el_ecu_instance).unwrap();
3654
3655 let model2 = AutosarModel::new();
3656 model2
3657 .create_file("test2.arxml", AutosarVersion::Autosar_00050)
3658 .unwrap();
3659 let el_autosar2 = model2.root_element();
3660 let el_ar_packages2 = el_autosar2.create_sub_element(ElementName::ArPackages).unwrap();
3661
3662 el_ar_packages2.move_element_here(&el_pkg1).unwrap();
3664 assert!(model1.get_element_by_path("/Pkg1").is_none());
3665 assert!(model2.get_element_by_path("/Pkg1").is_some());
3666 el_ar_packages2.move_element_here_at(&el_pkg2, 1).unwrap();
3667 assert!(model1.get_element_by_path("/Pkg2").is_none());
3668 assert!(model2.get_element_by_path("/Pkg2").is_some());
3669
3670 el_autosar.remove_sub_element(el_ar_packages1).unwrap();
3672 el_autosar.move_element_here(&el_ar_packages2).unwrap();
3673 assert!(model1.get_element_by_path("/Pkg1/EcuInstance").is_some());
3674 assert!(model1.get_element_by_path("/Pkg2/System").is_some());
3675 assert_eq!(el_fibex_element_ref.get_reference_target().unwrap(), el_ecu_instance);
3676
3677 drop(model2);
3679 assert!(el_autosar2.move_element_here(&el_ar_packages2).is_err());
3680 assert!(el_autosar2.move_element_here_at(&el_ar_packages2, 0).is_err());
3681
3682 let project3 = AutosarModel::new();
3684 project3
3685 .create_file("test2.arxml", AutosarVersion::Autosar_4_3_0)
3686 .unwrap();
3687 let el_autosar3 = project3.root_element();
3688 assert!(el_autosar3.move_element_here(&el_ar_packages2).is_err());
3689 assert!(el_autosar3.move_element_here_at(&el_ar_packages2, 0).is_err());
3690 }
3691
3692 #[test]
3693 fn get_set_reference_target() {
3694 let model = AutosarModel::new();
3695 model.create_file("text.arxml", AutosarVersion::Autosar_00050).unwrap();
3696 let el_autosar = model.root_element();
3697 let el_ar_package = el_autosar
3698 .create_sub_element(ElementName::ArPackages)
3699 .and_then(|arpkgs| arpkgs.create_named_sub_element(ElementName::ArPackage, "Package"))
3700 .unwrap();
3701 let el_elements = el_ar_package.create_sub_element(ElementName::Elements).unwrap();
3702 let el_ecu_instance1 = el_elements
3703 .create_named_sub_element(ElementName::EcuInstance, "EcuInstance1")
3704 .unwrap();
3705 let el_ecu_instance2 = el_elements
3706 .create_named_sub_element(ElementName::EcuInstance, "EcuInstance2")
3707 .unwrap();
3708 let el_req_result = el_elements
3709 .create_named_sub_element(ElementName::DiagnosticRoutine, "DiagRoutine")
3710 .and_then(|dr| dr.create_named_sub_element(ElementName::RequestResult, "RequestResult"))
3711 .unwrap();
3712 let el_fibex_element_ref = el_elements
3713 .create_named_sub_element(ElementName::System, "System")
3714 .and_then(|sys| sys.create_sub_element(ElementName::FibexElements))
3715 .and_then(|fe| fe.create_sub_element(ElementName::FibexElementRefConditional))
3716 .and_then(|ferc| ferc.create_sub_element(ElementName::FibexElementRef))
3717 .unwrap();
3718 let el_physical_request_ref = el_elements
3719 .create_named_sub_element(ElementName::DiagnosticConnection, "DiagnosticConnection")
3720 .and_then(|dc| dc.create_sub_element(ElementName::PhysicalRequestRef))
3721 .unwrap();
3722 let el_connection_ident = el_elements
3723 .create_named_sub_element(ElementName::CanTpConfig, "CanTpConfig")
3724 .and_then(|ctc| ctc.create_sub_element(ElementName::TpConnections))
3725 .and_then(|tc: Element| tc.create_sub_element(ElementName::CanTpConnection))
3726 .and_then(|ctc: Element| ctc.create_named_sub_element(ElementName::Ident, "ConnectionIdent"))
3727 .unwrap();
3728
3729 assert!(el_elements.set_reference_target(&el_ar_package).is_err());
3731 assert!(el_fibex_element_ref.set_reference_target(&el_autosar).is_err());
3733 assert!(el_fibex_element_ref.set_reference_target(&el_ar_package).is_err());
3735 assert!(el_fibex_element_ref.set_reference_target(&el_req_result).is_err());
3737
3738 el_fibex_element_ref.set_reference_target(&el_ecu_instance1).unwrap();
3740 assert_eq!(el_fibex_element_ref.get_reference_target().unwrap(), el_ecu_instance1);
3741 el_fibex_element_ref.set_reference_target(&el_ecu_instance2).unwrap();
3743 assert_eq!(el_fibex_element_ref.get_reference_target().unwrap(), el_ecu_instance2);
3744
3745 let el_reference_bases = el_ar_package.create_sub_element(ElementName::ReferenceBases).unwrap();
3747 let el_reference_base = el_reference_bases
3748 .create_sub_element(ElementName::ReferenceBase)
3749 .unwrap();
3750 el_reference_base
3751 .create_sub_element(ElementName::ShortLabel)
3752 .and_then(|short_label| short_label.set_character_data("default"))
3753 .unwrap();
3754 el_reference_base
3755 .create_sub_element(ElementName::PackageRef)
3756 .and_then(|package_ref| package_ref.set_reference_target(&el_ar_package))
3757 .unwrap();
3758 assert_eq!(
3759 el_reference_base.resolve_reference_base("default").as_deref(),
3760 Some("/Package")
3761 );
3762
3763 el_fibex_element_ref
3764 .set_relative_reference_target(&el_ecu_instance2, "default")
3765 .unwrap();
3766 assert_eq!(
3767 el_fibex_element_ref
3768 .attribute_value(AttributeName::Base)
3769 .and_then(|cdata| cdata.string_value())
3770 .unwrap(),
3771 "default"
3772 );
3773 assert_eq!(
3774 el_fibex_element_ref
3775 .character_data()
3776 .and_then(|cdata| cdata.string_value())
3777 .unwrap(),
3778 "EcuInstance2"
3779 );
3780 assert_eq!(el_fibex_element_ref.get_reference_target().unwrap(), el_ecu_instance2);
3781 assert!(
3782 model
3783 .get_references_to("/Package/EcuInstance2")
3784 .contains(&el_fibex_element_ref.downgrade())
3785 );
3786
3787 el_physical_request_ref
3790 .set_reference_target(&el_connection_ident)
3791 .unwrap();
3792 assert_eq!(
3793 el_physical_request_ref.get_reference_target().unwrap(),
3794 el_connection_ident
3795 );
3796
3797 el_fibex_element_ref
3799 .set_attribute(AttributeName::Dest, CharacterData::Enum(EnumItem::ISignal))
3800 .unwrap();
3801 assert!(el_fibex_element_ref.get_reference_target().is_err());
3802 assert_eq!(model.verify_reference_caches(), Ok(()));
3804 el_fibex_element_ref.0.write().attributes.clear(); assert!(el_fibex_element_ref.get_reference_target().is_err());
3810 el_fibex_element_ref.set_reference_target(&el_ecu_instance2).unwrap();
3811 el_fibex_element_ref
3813 .set_attribute(AttributeName::Dest, CharacterData::Enum(EnumItem::EcuInstance))
3814 .unwrap();
3815 el_fibex_element_ref.set_character_data("/does/not/exist").unwrap();
3816 assert!(el_fibex_element_ref.get_reference_target().is_err());
3817 el_fibex_element_ref.set_character_data("/Package").unwrap();
3819 assert!(el_fibex_element_ref.get_reference_target().is_err());
3820 el_fibex_element_ref.remove_character_data().unwrap();
3822 assert!(el_fibex_element_ref.get_reference_target().is_err());
3823 el_fibex_element_ref.set_reference_target(&el_ecu_instance2).unwrap();
3824 assert!(el_elements.get_reference_target().is_err());
3826 drop(model);
3828 assert!(el_fibex_element_ref.get_reference_target().is_err());
3829 }
3830
3831 #[test]
3832 fn relative_reference_outside_package() {
3833 let model = AutosarModel::new();
3834 model.create_file("test.arxml", AutosarVersion::Autosar_00050).unwrap();
3835 let el_autosar = model.root_element();
3836 let el_ar_package = el_autosar
3837 .create_sub_element(ElementName::ArPackages)
3838 .and_then(|arpkgs| arpkgs.create_named_sub_element(ElementName::ArPackage, "Package"))
3839 .unwrap();
3840
3841 let el_sdx_ref = el_autosar
3843 .create_sub_element(ElementName::AdminData)
3844 .and_then(|admin_data| admin_data.create_sub_element(ElementName::Sdgs))
3845 .and_then(|sdgs| sdgs.create_sub_element(ElementName::Sdg))
3846 .and_then(|sdg| sdg.create_sub_element(ElementName::SdxRef))
3847 .unwrap();
3848 assert!(el_sdx_ref.is_reference());
3849 assert!(el_sdx_ref.package().unwrap().is_none());
3850
3851 let result = el_sdx_ref.set_relative_reference_target(&el_ar_package, "default");
3854 assert!(matches!(result, Err(AutosarDataError::InvalidReferenceBase)));
3855
3856 el_sdx_ref.set_character_data("Package").unwrap();
3858 el_sdx_ref
3859 .set_attribute(AttributeName::Base, CharacterData::String("default".to_string()))
3860 .unwrap();
3861 let result = el_sdx_ref.get_reference_target();
3862 assert!(matches!(result, Err(AutosarDataError::InvalidReference)));
3863 assert_eq!(model.verify_reference_caches(), Ok(()));
3864 }
3865
3866 #[test]
3867 fn modify_character_data() {
3868 let model = AutosarModel::new();
3869 model.create_file("text.arxml", AutosarVersion::Autosar_00050).unwrap();
3870 let el_autosar = model.root_element();
3871 let el_ar_package = el_autosar
3872 .create_sub_element(ElementName::ArPackages)
3873 .and_then(|arpkgs| arpkgs.create_named_sub_element(ElementName::ArPackage, "Package"))
3874 .unwrap();
3875 let el_short_name = el_ar_package.get_sub_element(ElementName::ShortName).unwrap();
3876 let el_elements = el_ar_package.create_sub_element(ElementName::Elements).unwrap();
3877 let el_system = el_elements
3878 .create_named_sub_element(ElementName::System, "System")
3879 .unwrap();
3880 let el_fibex_element_ref = el_system
3881 .create_sub_element(ElementName::FibexElements)
3882 .and_then(|fe| fe.create_sub_element(ElementName::FibexElementRefConditional))
3883 .and_then(|ferc| ferc.create_sub_element(ElementName::FibexElementRef))
3884 .unwrap();
3885 let el_pnc_vector_length = el_system.create_sub_element(ElementName::PncVectorLength).unwrap();
3886
3887 assert!(
3889 el_pnc_vector_length
3890 .set_character_data(CharacterData::String("2".to_string()))
3891 .is_ok()
3892 ); assert!(el_pnc_vector_length.set_character_data("2".to_string()).is_ok()); assert!(el_pnc_vector_length.set_character_data("2").is_ok()); assert!(el_pnc_vector_length.set_character_data(2).is_ok()); assert!(
3899 el_short_name
3900 .set_character_data(CharacterData::String("PackageRenamed".to_string()))
3901 .is_ok()
3902 );
3903 assert_eq!(
3904 el_short_name.character_data().unwrap().string_value().unwrap(),
3905 "PackageRenamed"
3906 );
3907 model.get_element_by_path("/PackageRenamed").unwrap();
3908
3909 assert!(
3911 el_fibex_element_ref
3912 .set_character_data("/PackageRenamed/EcuInstance1")
3913 .is_ok()
3914 );
3915 model
3916 .0
3917 .read()
3918 .reference_origins
3919 .get("/PackageRenamed/EcuInstance1")
3920 .unwrap();
3921
3922 assert!(
3924 el_fibex_element_ref
3925 .set_character_data("/PackageRenamed/EcuInstance2")
3926 .is_ok()
3927 );
3928 model
3929 .0
3930 .read()
3931 .reference_origins
3932 .get("/PackageRenamed/EcuInstance2")
3933 .unwrap();
3934 assert!(
3935 !model
3936 .0
3937 .read()
3938 .reference_origins
3939 .contains_key("/PackageRenamed/EcuInstance1")
3940 );
3941
3942 assert!(el_autosar.set_character_data("text").is_err());
3944
3945 assert!(el_short_name.set_character_data(0).is_err());
3947 assert!(el_short_name.set_character_data("").is_err());
3948
3949 assert!(el_pnc_vector_length.remove_character_data().is_ok());
3951
3952 assert!(el_fibex_element_ref.remove_character_data().is_ok());
3954 assert!(
3955 !model
3956 .0
3957 .read()
3958 .reference_origins
3959 .contains_key("/PackageRenamed/EcuInstance2")
3960 );
3961
3962 assert!(el_fibex_element_ref.remove_character_data().is_ok());
3964
3965 assert!(el_short_name.remove_character_data().is_err());
3967
3968 assert!(el_autosar.remove_character_data().is_err());
3970
3971 assert!(
3973 el_autosar
3974 .0
3975 .write()
3976 .set_character_data(0, AutosarVersion::Autosar_00050)
3977 .is_err()
3978 );
3979 assert!(
3980 el_fibex_element_ref
3981 .0
3982 .write()
3983 .set_character_data(0, AutosarVersion::Autosar_00050)
3984 .is_err()
3985 );
3986
3987 el_fibex_element_ref
3989 .set_character_data("/PackageRenamed/EcuInstance2")
3990 .unwrap();
3991 drop(model);
3992 assert!(
3993 el_fibex_element_ref
3994 .set_character_data("/PackageRenamed/EcuInstance1")
3995 .is_err()
3996 );
3997 assert!(el_fibex_element_ref.remove_character_data().is_err());
3998 }
3999
4000 #[test]
4001 fn mixed_character_content() {
4002 let model = AutosarModel::new();
4003 model.create_file("test", AutosarVersion::Autosar_00050).unwrap();
4004 let el_ar_package = model
4005 .root_element()
4006 .create_sub_element(ElementName::ArPackages)
4007 .and_then(|e| e.create_named_sub_element(ElementName::ArPackage, "Pkg"))
4008 .unwrap();
4009 let el_desc = el_ar_package.create_sub_element(ElementName::Desc).unwrap();
4010 let el_l2 = el_desc.create_sub_element(ElementName::L2).unwrap();
4011
4012 el_l2.insert_character_content_item("descriptive text", 0).unwrap();
4014
4015 el_l2.create_sub_element(ElementName::Br).unwrap();
4017
4018 assert!(el_l2.insert_character_content_item("more text", 99).is_err());
4020
4021 assert!(el_desc.insert_character_content_item("text", 0).is_err());
4023
4024 assert!(el_l2.remove_character_content_item(99).is_err());
4026
4027 assert!(el_desc.remove_character_content_item(0).is_err());
4029
4030 assert!(el_l2.remove_character_content_item(1).is_err());
4032
4033 el_l2.remove_character_content_item(0).unwrap();
4035 }
4036
4037 #[test]
4038 fn get_sub_element() {
4039 let model = AutosarModel::new();
4040 model.create_file("test", AutosarVersion::Autosar_00050).unwrap();
4041 let el_autosar = model.root_element();
4042 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
4043 let el_ar_package = el_ar_packages
4044 .create_named_sub_element(ElementName::ArPackage, "Package")
4045 .unwrap();
4046 let el_desc = el_ar_package.create_sub_element(ElementName::Desc).unwrap();
4047 let el_l2 = el_desc.create_sub_element(ElementName::L2).unwrap();
4048
4049 el_l2.insert_character_content_item("descriptive text", 0).unwrap();
4050 el_l2.create_sub_element(ElementName::Br).unwrap();
4051
4052 assert_eq!(
4053 el_autosar.get_sub_element(ElementName::ArPackages).unwrap(),
4054 el_ar_packages
4055 );
4056 assert!(el_autosar.get_sub_element(ElementName::Abs).is_none());
4057 assert!(el_l2.get_sub_element(ElementName::Br).is_some());
4058 }
4059
4060 #[test]
4061 fn get_or_create() {
4062 let model = AutosarModel::new();
4063 model.create_file("test", AutosarVersion::Autosar_00050).unwrap();
4064 let el_autosar = model.root_element();
4065
4066 assert_eq!(el_autosar.sub_elements().count(), 0);
4067 let el_admin_data = el_autosar.get_or_create_sub_element(ElementName::AdminData).unwrap();
4068 let el_ar_packages = el_autosar.get_or_create_sub_element(ElementName::ArPackages).unwrap();
4069 let el_ar_packages2 = el_autosar.get_or_create_sub_element(ElementName::ArPackages).unwrap();
4070 assert_ne!(el_admin_data, el_ar_packages);
4071 assert_eq!(el_ar_packages, el_ar_packages2);
4072
4073 let el_ar_package = el_ar_packages
4074 .get_or_create_named_sub_element(ElementName::ArPackage, "Pkg")
4075 .unwrap();
4076 let el_ar_package2 = el_ar_packages
4077 .get_or_create_named_sub_element(ElementName::ArPackage, "Pkg2")
4078 .unwrap();
4079 let el_ar_package3 = el_ar_packages
4080 .get_or_create_named_sub_element(ElementName::ArPackage, "Pkg2")
4081 .unwrap();
4082 assert_ne!(el_ar_package, el_ar_package2);
4083 assert_eq!(el_ar_package2, el_ar_package3);
4084 }
4085
4086 #[test]
4087 fn serialize() {
4088 const FILEBUF: &str = r#"<?xml version="1.0" encoding="utf-8"?>
4089<!--comment-->
4090<AUTOSAR xsi:schemaLocation="http://autosar.org/schema/r4.0 AUTOSAR_00050.xsd" xmlns="http://autosar.org/schema/r4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4091 <AR-PACKAGES>
4092 <AR-PACKAGE>
4093 <SHORT-NAME>Pkg</SHORT-NAME>
4094 <DESC>
4095 <L-2 L="EN">Description<BR/>Description</L-2>
4096 </DESC>
4097 </AR-PACKAGE>
4098 </AR-PACKAGES>
4099</AUTOSAR>"#;
4100 let model = AutosarModel::new();
4101 model
4102 .load_buffer(FILEBUF.as_bytes(), OsString::from("test"), true)
4103 .unwrap();
4104 model.files().next().unwrap();
4105 let el_autosar = model.root_element();
4106 el_autosar.set_comment(Some("comment".to_string()));
4107
4108 let mut outstring = String::from(r#"<?xml version="1.0" encoding="utf-8"?>"#);
4109 el_autosar
4110 .0
4111 .read()
4112 .serialize_internal(&mut outstring, 0, false, &None, None);
4113
4114 assert_eq!(FILEBUF, outstring);
4115 }
4116
4117 #[test]
4118 fn list_valid_sub_elements() {
4119 let model = AutosarModel::new();
4120 model.create_file("test.arxml", AutosarVersion::Autosar_4_3_0).unwrap();
4121 let el_autosar = model.root_element();
4122 let el_elements = el_autosar
4123 .create_sub_element(ElementName::ArPackages)
4124 .and_then(|el| el.create_named_sub_element(ElementName::ArPackage, "Package"))
4125 .and_then(|el| el.create_sub_element(ElementName::Elements))
4126 .unwrap();
4127 let result = el_elements.list_valid_sub_elements();
4128 assert!(!result.is_empty());
4129 }
4130
4131 #[test]
4132 fn check_version_compatibility() {
4133 const FILEBUF: &str = r#"<?xml version="1.0" encoding="utf-8"?>
4134<AUTOSAR xsi:schemaLocation="http://autosar.org/schema/r4.0 AUTOSAR_00050.xsd" xmlns="http://autosar.org/schema/r4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4135 <AR-PACKAGES>
4136 <AR-PACKAGE>
4137 <SHORT-NAME>Pkg</SHORT-NAME>
4138 <ELEMENTS>
4139 <ACL-OBJECT-SET UUID="012345">
4140 <SHORT-NAME BLUEPRINT-VALUE="xyz">AclObjectSet</SHORT-NAME>
4141 <DERIVED-FROM-BLUEPRINT-REFS>
4142 <DERIVED-FROM-BLUEPRINT-REF DEST="ABSTRACT-IMPLEMENTATION-DATA-TYPE">/invalid</DERIVED-FROM-BLUEPRINT-REF>
4143 </DERIVED-FROM-BLUEPRINT-REFS>
4144 </ACL-OBJECT-SET>
4145 <ADAPTIVE-APPLICATION-SW-COMPONENT-TYPE>
4146 <SHORT-NAME>AdaptiveApplicationSwComponentType</SHORT-NAME>
4147 </ADAPTIVE-APPLICATION-SW-COMPONENT-TYPE>
4148 </ELEMENTS>
4149 </AR-PACKAGE>
4150 </AR-PACKAGES>
4151</AUTOSAR>"#;
4152 let model = AutosarModel::new();
4153 let (file, _) = model
4154 .load_buffer(FILEBUF.as_bytes(), OsString::from("test"), true)
4155 .unwrap();
4156 model.files().next().unwrap();
4157 let el_autosar = model.root_element();
4158
4159 let (compat_errors, _) =
4160 el_autosar.check_version_compatibility(&file.downgrade(), AutosarVersion::Autosar_4_3_0);
4161 assert_eq!(compat_errors.len(), 3);
4162
4163 for ce in compat_errors {
4164 match ce {
4165 CompatibilityError::IncompatibleElement { element, .. } => {
4166 assert_eq!(element.element_name(), ElementName::AdaptiveApplicationSwComponentType);
4167 }
4168 CompatibilityError::IncompatibleAttribute { element, attribute, .. } => {
4169 assert_eq!(element.element_name(), ElementName::ShortName);
4170 assert_eq!(attribute, AttributeName::BlueprintValue);
4171 }
4172 CompatibilityError::IncompatibleAttributeValue { element, attribute, .. } => {
4173 assert_eq!(element.element_name(), ElementName::DerivedFromBlueprintRef);
4174 assert_eq!(attribute, AttributeName::Dest);
4175 }
4176 }
4177 }
4178
4179 let model = AutosarModel::new();
4181 let file = model.create_file("filename", AutosarVersion::Autosar_00046).unwrap();
4182 model
4183 .root_element()
4184 .create_sub_element(ElementName::ArPackages)
4185 .and_then(|e| e.create_named_sub_element(ElementName::ArPackage, "Pkg"))
4186 .and_then(|e| e.create_sub_element(ElementName::Elements))
4187 .and_then(|e| e.create_named_sub_element(ElementName::CompuMethod, "CompuMethod"))
4188 .and_then(|e| e.create_sub_element(ElementName::CompuInternalToPhys))
4189 .and_then(|e| e.create_sub_element(ElementName::CompuScales))
4190 .and_then(|e| e.create_sub_element(ElementName::CompuScale))
4191 .unwrap();
4192 let (compat_errors, _) = file.check_version_compatibility(AutosarVersion::Autosar_4_3_0);
4193 assert!(compat_errors.is_empty());
4194 }
4195
4196 #[test]
4197 fn find_element_insert_pos() {
4198 let model = AutosarModel::new();
4199 model.create_file("test", AutosarVersion::Autosar_00050).unwrap();
4200 let el_autosar = model.root_element();
4201 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
4202 let el_ar_package = el_ar_packages
4203 .create_named_sub_element(ElementName::ArPackage, "Pkg")
4204 .unwrap();
4205 let el_short_name = el_ar_package.get_sub_element(ElementName::ShortName).unwrap();
4206
4207 assert!(
4209 el_short_name
4210 .0
4211 .read()
4212 .calc_element_insert_range(ElementName::Desc, AutosarVersion::Autosar_00050)
4213 .is_err()
4214 );
4215
4216 assert!(
4218 el_autosar
4219 .0
4220 .read()
4221 .calc_element_insert_range(ElementName::ArPackages, AutosarVersion::Autosar_00050)
4222 .is_err()
4223 );
4224 }
4225
4226 #[test]
4227 fn sort() {
4228 let model = AutosarModel::new();
4229 model.create_file("test", AutosarVersion::Autosar_00050).unwrap();
4230 let el_autosar = model.root_element();
4231 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
4232 let el_ar_package1 = el_ar_packages
4233 .create_named_sub_element(ElementName::ArPackage, "Z")
4234 .unwrap();
4235 let el_ar_package2 = el_ar_packages
4236 .create_named_sub_element(ElementName::ArPackage, "A")
4237 .unwrap();
4238 let el_elements = el_ar_package1.create_sub_element(ElementName::Elements).unwrap();
4239 el_ar_package1.create_sub_element(ElementName::AdminData).unwrap();
4240 let el_emcv = el_elements
4242 .create_named_sub_element(ElementName::EcucModuleConfigurationValues, "Config")
4243 .unwrap();
4244 let el_containers = el_emcv.create_sub_element(ElementName::Containers).unwrap();
4245 let el_ecv = el_containers
4246 .create_named_sub_element(ElementName::EcucContainerValue, "ConfigValues")
4247 .unwrap();
4248 let el_paramvalues = el_ecv.create_sub_element(ElementName::ParameterValues).unwrap();
4249 let el_value1 = el_paramvalues
4251 .create_sub_element(ElementName::EcucNumericalParamValue)
4252 .unwrap();
4253 let el_defref1 = el_value1.create_sub_element(ElementName::DefinitionRef).unwrap();
4254 el_defref1
4255 .set_attribute(AttributeName::Dest, CharacterData::Enum(EnumItem::EcucBooleanParamDef))
4256 .unwrap();
4257 el_defref1.set_character_data("/DefRef_999").unwrap();
4258 let el_value2 = el_paramvalues
4260 .create_sub_element(ElementName::EcucNumericalParamValue)
4261 .unwrap();
4262 let el_defref2 = el_value2.create_sub_element(ElementName::DefinitionRef).unwrap();
4263 el_defref2
4264 .set_attribute(AttributeName::Dest, CharacterData::Enum(EnumItem::EcucBooleanParamDef))
4265 .unwrap();
4266 el_defref2.set_character_data("/DefRef_111").unwrap();
4267 let el_elements2 = el_ar_package2.create_sub_element(ElementName::Elements).unwrap();
4269 let el_system = el_elements2
4270 .create_named_sub_element(ElementName::System, "System")
4271 .unwrap();
4272 let el_fibex_elements = el_system.create_sub_element(ElementName::FibexElements).unwrap();
4273 let el_fibex_element1 = el_fibex_elements
4274 .create_sub_element(ElementName::FibexElementRefConditional)
4275 .unwrap();
4276 let el_fibex_element_ref1 = el_fibex_element1
4277 .create_sub_element(ElementName::FibexElementRef)
4278 .unwrap();
4279 el_fibex_element_ref1
4280 .set_attribute(AttributeName::Dest, CharacterData::Enum(EnumItem::ISignal))
4281 .unwrap();
4282 el_fibex_element_ref1.set_character_data("/ZZZZZ").unwrap();
4283 let el_fibex_element2 = el_fibex_elements
4284 .create_sub_element(ElementName::FibexElementRefConditional)
4285 .unwrap();
4286 let el_fibex_element_ref2 = el_fibex_element2
4287 .create_sub_element(ElementName::FibexElementRef)
4288 .unwrap();
4289 el_fibex_element_ref2
4290 .set_attribute(AttributeName::Dest, CharacterData::Enum(EnumItem::ISignal))
4291 .unwrap();
4292 el_fibex_element_ref2.set_character_data("/AAAAA").unwrap();
4293
4294 model.sort();
4295 let mut iter = el_ar_packages.sub_elements();
4297 let item1 = iter.next().unwrap();
4298 let item2 = iter.next().unwrap();
4299 assert_eq!(item1.item_name().unwrap(), "A");
4300 assert_eq!(item2.item_name().unwrap(), "Z");
4301
4302 let mut iter = el_paramvalues.sub_elements();
4304 let item1 = iter.next().unwrap();
4305 let item2 = iter.next().unwrap();
4306 assert_eq!(item1, el_value2);
4307 assert_eq!(item2, el_value1);
4308
4309 let mut iter = el_fibex_elements.sub_elements();
4311 let item1 = iter.next().unwrap();
4312 let item2 = iter.next().unwrap();
4313 assert_eq!(item1, el_fibex_element2);
4314 assert_eq!(item2, el_fibex_element1);
4315 }
4316
4317 fn helper_create_bsw_subelem(
4318 el_subcontainers: &Element,
4319 short_name: &str,
4320 defref: &str,
4321 ) -> Result<Element, AutosarDataError> {
4322 let e = el_subcontainers.create_named_sub_element(ElementName::EcucContainerValue, short_name)?;
4323 let defrefelem = e.create_sub_element(ElementName::DefinitionRef)?;
4324 defrefelem.set_character_data(defref)?;
4325 Ok(e)
4326 }
4327
4328 fn helper_create_indexed_bsw_subelem(
4329 el_subcontainers: &Element,
4330 short_name: &str,
4331 indexstr: &str,
4332 defref: &str,
4333 ) -> Result<Element, AutosarDataError> {
4334 let e = helper_create_bsw_subelem(el_subcontainers, short_name, defref)?;
4335 let indexelem = e.create_sub_element(ElementName::Index)?;
4336 indexelem.set_character_data(indexstr)?;
4337 Ok(e)
4338 }
4339
4340 #[test]
4341 fn sort_bsw_elements() {
4342 let model = AutosarModel::new();
4343 model.create_file("test", AutosarVersion::LATEST).unwrap();
4344 let el_subcontainers = model
4345 .root_element()
4346 .create_sub_element(ElementName::ArPackages)
4347 .and_then(|ap| ap.create_named_sub_element(ElementName::ArPackage, "Pkg"))
4348 .and_then(|ap| ap.create_sub_element(ElementName::Elements))
4349 .and_then(|elems| elems.create_named_sub_element(ElementName::EcucModuleConfigurationValues, "Config"))
4350 .and_then(|emcv| emcv.create_sub_element(ElementName::Containers))
4351 .and_then(|c| c.create_named_sub_element(ElementName::EcucContainerValue, "ConfigValues"))
4352 .and_then(|ecv| ecv.create_sub_element(ElementName::SubContainers))
4353 .unwrap();
4354 let elem1 =
4355 helper_create_indexed_bsw_subelem(&el_subcontainers, "Aaa", "06", "/Defref/Container/Value").unwrap(); let elem2 =
4357 helper_create_indexed_bsw_subelem(&el_subcontainers, "Bbb", "5", "/Defref/Container/Value").unwrap(); let elem3 =
4359 helper_create_indexed_bsw_subelem(&el_subcontainers, "Bbb2", "5", "/Defref/Container/Value").unwrap(); let elem4 =
4361 helper_create_indexed_bsw_subelem(&el_subcontainers, "Ccc", "0X4", "/Defref/Container/Value").unwrap(); let elem5 = helper_create_bsw_subelem(&el_subcontainers, "Zzz", "/Defref/Container/Value").unwrap();
4363 let elem6 =
4364 helper_create_indexed_bsw_subelem(&el_subcontainers, "Ddd", "0b1", "/Defref/Container/Value").unwrap(); let elem7 =
4366 helper_create_indexed_bsw_subelem(&el_subcontainers, "Eee", "0x3", "/Defref/Container/Value").unwrap(); let elem8 =
4368 helper_create_indexed_bsw_subelem(&el_subcontainers, "Fff", "0B10", "/Defref/Container/Value").unwrap(); let elem9 =
4370 helper_create_indexed_bsw_subelem(&el_subcontainers, "Ggg", "0", "/Defref/Container/Value").unwrap(); let elem10 = helper_create_bsw_subelem(&el_subcontainers, "Mmm_0", "/Defref/Container/Value").unwrap();
4373 let elem11 = helper_create_bsw_subelem(&el_subcontainers, "Mmm_5", "/Defref/Container/Value").unwrap();
4374 let elem12 = helper_create_bsw_subelem(&el_subcontainers, "Mmm_10", "/Defref/Container/Value").unwrap();
4375 let elem13 = helper_create_bsw_subelem(&el_subcontainers, "Mmm_9", "/Defref/Container/Value").unwrap();
4376
4377 el_subcontainers.sort();
4378 assert_eq!(elem1.position().unwrap(), 7);
4379 assert_eq!(elem2.position().unwrap(), 5);
4380 assert_eq!(elem3.position().unwrap(), 6);
4381 assert_eq!(elem4.position().unwrap(), 4);
4382 assert_eq!(elem6.position().unwrap(), 1);
4383 assert_eq!(elem7.position().unwrap(), 3);
4384 assert_eq!(elem8.position().unwrap(), 2);
4385 assert_eq!(elem9.position().unwrap(), 0);
4386 assert_eq!(elem10.position().unwrap(), 8);
4388 assert_eq!(elem11.position().unwrap(), 9);
4389 assert_eq!(elem13.position().unwrap(), 10);
4390 assert_eq!(elem12.position().unwrap(), 11);
4391 assert_eq!(elem5.position().unwrap(), 12);
4392 }
4393
4394 #[test]
4395 fn file_membership() {
4396 let model = AutosarModel::new();
4397 let file1 = model.create_file("test_1", AutosarVersion::Autosar_00050).unwrap();
4398 let file2 = model.create_file("test_2", AutosarVersion::Autosar_00050).unwrap();
4399 let el_autosar = model.root_element();
4400 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
4401 let el_ar_package = el_ar_packages
4402 .create_named_sub_element(ElementName::ArPackage, "Pkg")
4403 .unwrap();
4404 el_ar_package.create_sub_element(ElementName::Elements).unwrap();
4405
4406 let fm: HashSet<WeakArxmlFile> = [file1.downgrade()].iter().cloned().collect();
4407 el_ar_packages.set_file_membership(fm.clone());
4410 let (local, _) = el_ar_package.file_membership().unwrap();
4411 assert!(!local);
4412
4413 el_ar_package.set_file_membership(fm.clone());
4416 let (local, fm2) = el_ar_package.file_membership().unwrap();
4417 assert!(local);
4418 assert_eq!(fm, fm2);
4419 let filetxt1 = file1.serialize().unwrap();
4420 let filetxt2 = file2.serialize().unwrap();
4421 assert_ne!(filetxt1, filetxt2);
4422
4423 let model2 = AutosarModel::new();
4425 let model2_file = model2.create_file("file", AutosarVersion::LATEST).unwrap();
4426 assert!(el_ar_package.add_to_file(&model2_file).is_err());
4427 assert!(el_ar_package.remove_from_file(&model2_file).is_err());
4428
4429 el_ar_package.add_to_file(&file1).unwrap();
4431 let (local, fm3) = el_ar_package.file_membership().unwrap();
4432 assert!(local);
4433 assert_eq!(fm3.len(), 1);
4434
4435 el_ar_package.remove_from_file(&file2).unwrap();
4437 let (local, fm3) = el_ar_package.file_membership().unwrap();
4438 assert!(local);
4439 assert_eq!(fm3.len(), 1);
4440
4441 el_ar_package.add_to_file(&file2).unwrap();
4443 let (local, fm3) = el_ar_package.file_membership().unwrap();
4444 assert!(local);
4445 assert_eq!(fm3.len(), 2);
4446
4447 assert!(el_ar_package.get_sub_element(ElementName::Elements).is_some());
4449 el_ar_package.remove_from_file(&file1).unwrap();
4450 el_ar_package.remove_from_file(&file2).unwrap();
4451 assert!(el_ar_package.get_sub_element(ElementName::Elements).is_none());
4452 assert!(el_ar_package.remove_from_file(&file2).is_err());
4453 }
4454
4455 #[test]
4456 fn remove_from_last_file() {
4457 let model = AutosarModel::new();
4458 let file = model.create_file("test.arxml", AutosarVersion::LATEST).unwrap();
4459 let el_autosar = model.root_element();
4460 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
4461 let el_ar_package = el_ar_packages
4462 .create_named_sub_element(ElementName::ArPackage, "Pkg")
4463 .unwrap();
4464
4465 let result = el_autosar.remove_from_file(&file);
4467 assert!(matches!(result, Err(AutosarDataError::RootElementRemovalForbidden)));
4468 assert_eq!(model.files().count(), 1);
4470 assert!(el_autosar.min_version().is_ok());
4471 assert!(file.serialize().is_ok());
4472
4473 let el_chapter = el_ar_package
4476 .create_sub_element(ElementName::Elements)
4477 .and_then(|elements| elements.create_named_sub_element(ElementName::Documentation, "Doc"))
4478 .and_then(|doc| doc.create_sub_element(ElementName::DocumentationContent))
4479 .and_then(|content| content.create_named_sub_element(ElementName::Chapter, "Chap"))
4480 .unwrap();
4481 let el_short_name = el_chapter.get_sub_element(ElementName::ShortName).unwrap();
4482 let result = el_short_name.remove_from_file(&file);
4483 assert!(matches!(result, Err(AutosarDataError::ShortNameRemovalForbidden)));
4484 assert_eq!(el_chapter.item_name().unwrap(), "Chap");
4486 assert!(!el_short_name.file_membership().unwrap().1.is_empty());
4487
4488 el_ar_package.remove_from_file(&file).unwrap();
4490 assert!(model.get_element_by_path("/Pkg").is_none());
4491 }
4492
4493 #[test]
4494 fn comment() {
4495 let model = AutosarModel::new();
4496 model.create_file("test", AutosarVersion::LATEST).unwrap();
4497 let el_autosar = model.root_element();
4498
4499 assert!(el_autosar.comment().is_none());
4501
4502 el_autosar.set_comment(Some("comment".to_string()));
4504 assert_eq!(el_autosar.comment().unwrap(), "comment");
4505
4506 el_autosar.set_comment(Some("comment--".to_string()));
4508 assert_eq!(el_autosar.comment().unwrap(), "comment__");
4509
4510 el_autosar.set_comment(None);
4512 assert!(el_autosar.comment().is_none());
4513 }
4514
4515 #[test]
4516 fn min_version() {
4517 let model = AutosarModel::new();
4518 let result = model.root_element().min_version();
4519 assert!(result.is_err());
4520
4521 model.create_file("test", AutosarVersion::LATEST).unwrap();
4522 let min_ver = model.root_element().min_version().unwrap();
4523 assert_eq!(min_ver, AutosarVersion::LATEST);
4524
4525 model.create_file("test2", AutosarVersion::Autosar_00042).unwrap();
4526 let min_ver = model.root_element().min_version().unwrap();
4527 assert_eq!(min_ver, AutosarVersion::Autosar_00042);
4528 }
4529
4530 #[test]
4531 fn traits() {
4532 let model = AutosarModel::new();
4533 model.create_file("test", AutosarVersion::LATEST).unwrap();
4534
4535 let el_autosar = model.root_element();
4537 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
4538
4539 let el_autosar_second_ref = el_autosar.clone();
4540 assert_eq!(el_autosar, el_autosar_second_ref);
4541 assert_eq!(format!("{el_autosar:?}"), format!("{el_autosar_second_ref:?}"));
4542 assert_ne!(el_autosar, el_ar_packages);
4543
4544 let weak1 = el_autosar.downgrade();
4545 let weak2 = el_autosar_second_ref.downgrade();
4546 assert_eq!(weak1, weak2);
4547 assert_eq!(format!("{weak1:?}"), format!("{weak2:?}"));
4548
4549 #[allow(clippy::mutable_key_type)]
4550 let mut hs = HashSet::new();
4551 hs.insert(el_autosar);
4552 hs.insert(el_ar_packages);
4553 assert!(!hs.insert(el_autosar_second_ref));
4555 assert_eq!(hs.len(), 2);
4556
4557 let mut hs2 = HashSet::new();
4558 hs2.insert(weak1);
4559 assert!(!hs2.insert(weak2));
4560 assert_eq!(hs2.len(), 1);
4561
4562 let ec_elem = ElementContent::Element(model.root_element());
4564 assert_eq!(format!("{:?}", model.root_element()), format!("{ec_elem:?}"));
4565 assert_eq!(ec_elem.unwrap_element(), Some(model.root_element()));
4566 assert!(ec_elem.unwrap_cdata().is_none());
4567 let cdata = CharacterData::String("test".to_string());
4568 let ec_chars = ElementContent::CharacterData(cdata.clone());
4569 assert_eq!(format!("{cdata:?}"), format!("{ec_chars:?}"));
4570 assert_eq!(ec_chars.unwrap_cdata(), Some(cdata));
4571 assert!(ec_chars.unwrap_element().is_none());
4572 }
4573
4574 #[test]
4575 fn element_order() {
4576 let model = AutosarModel::new();
4577 let _file = model.create_file("test", AutosarVersion::LATEST).unwrap();
4578 let el_autosar = model.root_element();
4579 let el_elements = el_autosar
4580 .create_sub_element(ElementName::ArPackages)
4581 .unwrap()
4582 .create_named_sub_element(ElementName::ArPackage, "pkg")
4583 .unwrap()
4584 .create_sub_element(ElementName::Elements)
4585 .unwrap();
4586 let el_system = el_elements
4587 .create_named_sub_element(ElementName::System, "sys")
4588 .unwrap();
4589 let fibex_elements = el_system.create_sub_element(ElementName::FibexElements).unwrap();
4590
4591 let item1 = el_elements
4592 .create_named_sub_element(ElementName::ApplicationPrimitiveDataType, "adt_2")
4593 .unwrap();
4594 let item2 = el_elements
4595 .create_named_sub_element(ElementName::ApplicationPrimitiveDataType, "adt_10")
4596 .unwrap();
4597 let item3 = el_elements
4598 .create_named_sub_element(ElementName::ApplicationArrayDataType, "adt_12")
4599 .unwrap();
4600 assert!(item1 < item2);
4602 assert!(item3 < item1);
4604
4605 let item4 = fibex_elements
4606 .create_sub_element(ElementName::FibexElementRefConditional)
4607 .unwrap();
4608 let item4_ref = item4.create_sub_element(ElementName::FibexElementRef).unwrap();
4609 item4_ref
4610 .set_attribute(AttributeName::Dest, CharacterData::Enum(EnumItem::ISignal))
4611 .unwrap();
4612 item4_ref.set_character_data("/aaa").unwrap();
4613
4614 let item5 = fibex_elements
4615 .create_sub_element(ElementName::FibexElementRefConditional)
4616 .unwrap();
4617 let item5_ref = item5.create_sub_element(ElementName::FibexElementRef).unwrap();
4618 item5_ref
4619 .set_attribute(AttributeName::Dest, CharacterData::Enum(EnumItem::ISignal))
4620 .unwrap();
4621 item5_ref.set_character_data("/bbb").unwrap();
4622
4623 assert!(item4 < item5);
4625
4626 let item6 = fibex_elements
4627 .create_sub_element(ElementName::FibexElementRefConditional)
4628 .unwrap();
4629 let item6_ref = item6.create_sub_element(ElementName::FibexElementRef).unwrap();
4630 item6_ref
4631 .set_attribute(AttributeName::Dest, CharacterData::Enum(EnumItem::EcuInstance))
4632 .unwrap();
4633
4634 assert!(item6 < item4);
4636
4637 let item7 = fibex_elements
4638 .create_sub_element(ElementName::FibexElementRefConditional)
4639 .unwrap();
4640 item7.create_sub_element(ElementName::FibexElementRef).unwrap();
4641
4642 assert!(item7 > item6);
4644 assert!(item6 < item7);
4645 }
4646
4647 #[test]
4648 fn elements_dfs_with_max_depth() {
4649 const FILEBUF: &[u8] = r#"<?xml version="1.0" encoding="utf-8"?>
4650 <AUTOSAR xsi:schemaLocation="http://autosar.org/schema/r4.0 AUTOSAR_00050.xsd" xmlns="http://autosar.org/schema/r4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4651 <AR-PACKAGES>
4652 <AR-PACKAGE><SHORT-NAME>Pkg_A</SHORT-NAME><ELEMENTS>
4653 <ECUC-MODULE-CONFIGURATION-VALUES><SHORT-NAME>BswModule</SHORT-NAME><CONTAINERS><ECUC-CONTAINER-VALUE>
4654 <SHORT-NAME>BswModuleValues</SHORT-NAME>
4655 <PARAMETER-VALUES>
4656 <ECUC-NUMERICAL-PARAM-VALUE>
4657 <DEFINITION-REF DEST="ECUC-BOOLEAN-PARAM-DEF">/REF_A</DEFINITION-REF>
4658 </ECUC-NUMERICAL-PARAM-VALUE>
4659 <ECUC-NUMERICAL-PARAM-VALUE>
4660 <DEFINITION-REF DEST="ECUC-BOOLEAN-PARAM-DEF">/REF_B</DEFINITION-REF>
4661 </ECUC-NUMERICAL-PARAM-VALUE>
4662 <ECUC-NUMERICAL-PARAM-VALUE>
4663 <DEFINITION-REF DEST="ECUC-BOOLEAN-PARAM-DEF">/REF_C</DEFINITION-REF>
4664 </ECUC-NUMERICAL-PARAM-VALUE>
4665 </PARAMETER-VALUES>
4666 </ECUC-CONTAINER-VALUE></CONTAINERS></ECUC-MODULE-CONFIGURATION-VALUES>
4667 </ELEMENTS></AR-PACKAGE>
4668 <AR-PACKAGE><SHORT-NAME>Pkg_B</SHORT-NAME></AR-PACKAGE>
4669 <AR-PACKAGE><SHORT-NAME>Pkg_C</SHORT-NAME></AR-PACKAGE>
4670 </AR-PACKAGES></AUTOSAR>"#.as_bytes();
4671 let model = AutosarModel::new();
4672 let (_, _) = model.load_buffer(FILEBUF, "test1", true).unwrap();
4673 let root_elem = model.root_element();
4674 let ar_packages_elem = root_elem.get_sub_element(ElementName::ArPackages).unwrap();
4675 let root_all_count = root_elem.elements_dfs().count();
4676 let ar_packages_all_count = ar_packages_elem.elements_dfs().count();
4677 assert_eq!(root_all_count, ar_packages_all_count + 1);
4678
4679 let root_lvl3_count = root_elem.elements_dfs_with_max_depth(3).count();
4680 let ar_packages_lvl2_count = ar_packages_elem.elements_dfs_with_max_depth(2).count();
4681 assert_eq!(root_lvl3_count, ar_packages_lvl2_count + 1);
4682
4683 root_elem
4684 .elements_dfs_with_max_depth(3)
4685 .skip(1)
4686 .zip(ar_packages_elem.elements_dfs_with_max_depth(2))
4687 .for_each(|((_, x), (_, y))| assert_eq!(x, y));
4688
4689 for elem in ar_packages_elem.elements_dfs_with_max_depth(2) {
4690 assert!(elem.0 <= 2);
4691 }
4692 }
4693
4694 #[test]
4695 fn parse_reference_bases() {
4696 const FILEBUF: &[u8] = r#"<?xml version="1.0" encoding="utf-8"?>
4698<AUTOSAR xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://autosar.org/schema/r4.0" xsi:schemaLocation="http://autosar.org/schema/r4.0 AUTOSAR_00048.xsd">
4699 <AR-PACKAGES>
4700 <AR-PACKAGE>
4701 <SHORT-NAME>My</SHORT-NAME>
4702 <AR-PACKAGES>
4703 <AR-PACKAGE>
4704 <SHORT-NAME>Lib</SHORT-NAME>
4705 <AR-PACKAGES>
4706 <AR-PACKAGE>
4707 <SHORT-NAME>Hierarchy</SHORT-NAME>
4708 <AR-PACKAGES>
4709 <AR-PACKAGE>
4710 <SHORT-NAME>Units</SHORT-NAME>
4711 <ELEMENTS>
4712 <UNIT>
4713 <SHORT-NAME>MyUnit</SHORT-NAME>
4714 <FACTOR-SI-TO-UNIT>1</FACTOR-SI-TO-UNIT>
4715 <OFFSET-SI-TO-UNIT>0</OFFSET-SI-TO-UNIT>
4716 </UNIT>
4717 </ELEMENTS>
4718 </AR-PACKAGE>
4719 </AR-PACKAGES>
4720 </AR-PACKAGE>
4721 </AR-PACKAGES>
4722 </AR-PACKAGE>
4723 <AR-PACKAGE>
4724 <SHORT-NAME>SWC</SHORT-NAME>
4725 <REFERENCE-BASES>
4726 <REFERENCE-BASE>
4727 <SHORT-LABEL>Units</SHORT-LABEL>
4728 <PACKAGE-REF DEST="AR-PACKAGE">/My/Lib/Hierarchy/Units</PACKAGE-REF>
4729 </REFERENCE-BASE>
4730 </REFERENCE-BASES>
4731 <AR-PACKAGES>
4732 <AR-PACKAGE>
4733 <SHORT-NAME>ApplicationDataTypes</SHORT-NAME>
4734 <ELEMENTS>
4735 <APPLICATION-PRIMITIVE-DATA-TYPE>
4736 <SHORT-NAME>MyDataType</SHORT-NAME>
4737 <CATEGORY>VALUE</CATEGORY>
4738 <SW-DATA-DEF-PROPS>
4739 <SW-DATA-DEF-PROPS-VARIANTS>
4740 <SW-DATA-DEF-PROPS-CONDITIONAL>
4741 <SW-CALIBRATION-ACCESS>NOT-ACCESSIBLE</SW-CALIBRATION-ACCESS>
4742 <UNIT-REF DEST="UNIT" BASE="Units">MyUnit</UNIT-REF>
4743 </SW-DATA-DEF-PROPS-CONDITIONAL>
4744 </SW-DATA-DEF-PROPS-VARIANTS>
4745 </SW-DATA-DEF-PROPS>
4746 </APPLICATION-PRIMITIVE-DATA-TYPE>
4747 </ELEMENTS>
4748 </AR-PACKAGE>
4749 </AR-PACKAGES>
4750 </AR-PACKAGE>
4751 </AR-PACKAGES>
4752 </AR-PACKAGE>
4753 </AR-PACKAGES>
4754</AUTOSAR>"#.as_bytes();
4755 let model = AutosarModel::new();
4756 let (_, _) = model.load_buffer(FILEBUF, "test1", true).unwrap();
4757
4758 let unit_elem = model.get_element_by_path("/My/Lib/Hierarchy/Units/MyUnit").unwrap();
4759 assert_eq!(unit_elem.element_name(), ElementName::Unit);
4760
4761 let refs_to_unit = model.get_references_to(&unit_elem.path().unwrap());
4763 assert_eq!(refs_to_unit.len(), 1);
4764 let reference_elem = refs_to_unit[0].upgrade().unwrap();
4765 assert_eq!(reference_elem.element_name(), ElementName::UnitRef);
4766 assert!(reference_elem.attribute_value(AttributeName::Base).is_some());
4767
4768 assert_eq!(
4770 reference_elem.resolve_reference_base("Units").as_deref(),
4771 Some("/My/Lib/Hierarchy/Units")
4772 );
4773
4774 let target = reference_elem.get_reference_target().unwrap();
4776 assert_eq!(target, unit_elem);
4777 assert_eq!(model.verify_reference_caches(), Ok(()));
4778 }
4779
4780 #[test]
4781 fn modify_relative_ref() {
4782 const FILEBUF: &[u8] = r#"<?xml version="1.0" encoding="utf-8"?>
4783<AUTOSAR xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://autosar.org/schema/r4.0" xsi:schemaLocation="http://autosar.org/schema/r4.0 AUTOSAR_00048.xsd">
4784 <AR-PACKAGES>
4785 <AR-PACKAGE>
4786 <SHORT-NAME>First</SHORT-NAME>
4787 <AR-PACKAGES>
4788 <AR-PACKAGE>
4789 <SHORT-NAME>Second</SHORT-NAME>
4790 <ELEMENTS>
4791 <ECU-INSTANCE>
4792 <SHORT-NAME>Ecu</SHORT-NAME>
4793 </ECU-INSTANCE>
4794 </ELEMENTS>
4795 </AR-PACKAGE>
4796 </AR-PACKAGES>
4797 </AR-PACKAGE>
4798 <AR-PACKAGE>
4799 <SHORT-NAME>Ref</SHORT-NAME>
4800 <REFERENCE-BASES>
4801 <REFERENCE-BASE>
4802 <SHORT-LABEL>First</SHORT-LABEL>
4803 <PACKAGE-REF DEST="AR-PACKAGE">/First</PACKAGE-REF>
4804 </REFERENCE-BASE>
4805 <REFERENCE-BASE>
4806 <SHORT-LABEL>Second</SHORT-LABEL>
4807 <PACKAGE-REF DEST="AR-PACKAGE">/First/Second</PACKAGE-REF>
4808 </REFERENCE-BASE>
4809 </REFERENCE-BASES>
4810 <ELEMENTS>
4811 <SYSTEM>
4812 <SHORT-NAME>System</SHORT-NAME>
4813 <FIBEX-ELEMENTS>
4814 <FIBEX-ELEMENT-REF-CONDITIONAL>
4815 <FIBEX-ELEMENT-REF DEST="ECU-INSTANCE" BASE="First">Second/Ecu</FIBEX-ELEMENT-REF>
4816 </FIBEX-ELEMENT-REF-CONDITIONAL>
4817 </FIBEX-ELEMENTS>
4818 </SYSTEM>
4819 </ELEMENTS>
4820 </AR-PACKAGE>
4821 </AR-PACKAGES>
4822</AUTOSAR>"#.as_bytes();
4823 let model = AutosarModel::new();
4824 let (_, _) = model.load_buffer(FILEBUF, "test1", true).unwrap();
4825
4826 let ref_elem = model
4827 .get_element_by_path("/Ref/System")
4828 .unwrap()
4829 .get_sub_element(ElementName::FibexElements)
4830 .unwrap()
4831 .get_sub_element(ElementName::FibexElementRefConditional)
4832 .unwrap()
4833 .get_sub_element(ElementName::FibexElementRef)
4834 .unwrap();
4835 let ecu_elem = ref_elem.get_reference_target().unwrap();
4836 assert_eq!(ecu_elem.element_name(), ElementName::EcuInstance);
4837 assert_eq!(model.get_references_to(&ecu_elem.path().unwrap()).len(), 1);
4838
4839 ref_elem.set_relative_reference_target(&ecu_elem, "Second").unwrap();
4840 assert_eq!(ref_elem.character_data().unwrap().string_value().unwrap(), "Ecu");
4841 assert_eq!(model.get_references_to(&ecu_elem.path().unwrap()).len(), 1);
4842 assert_eq!(model.verify_reference_caches(), Ok(()));
4843 }
4844
4845 #[test]
4846 fn create_modify_delete_ref_bases() {
4847 let model = AutosarModel::new();
4848 model.create_file("test", AutosarVersion::LATEST).unwrap();
4849 let el_autosar = model.root_element();
4850 let el_ar_packages = el_autosar.create_sub_element(ElementName::ArPackages).unwrap();
4851 let el_ar_package = el_ar_packages
4852 .create_named_sub_element(ElementName::ArPackage, "Pkg")
4853 .unwrap();
4854 let el_ar_package2 = el_ar_packages
4855 .create_named_sub_element(ElementName::ArPackage, "Pkg2")
4856 .unwrap();
4857 let el_reference_bases = el_ar_package.create_sub_element(ElementName::ReferenceBases).unwrap();
4858 let el_reference_base = el_reference_bases
4859 .create_sub_element(ElementName::ReferenceBase)
4860 .unwrap();
4861 assert_eq!(el_reference_base.resolve_reference_base("Units"), None);
4863 let el_short_label = el_reference_base.create_sub_element(ElementName::ShortLabel).unwrap();
4864 el_short_label.set_character_data("Units").unwrap();
4865 assert_eq!(el_reference_base.resolve_reference_base("Units"), None);
4867 let el_package_ref = el_reference_base.create_sub_element(ElementName::PackageRef).unwrap();
4868 el_package_ref.set_reference_target(&el_ar_package2).unwrap();
4869 assert_eq!(
4871 el_reference_base.resolve_reference_base("Units").as_deref(),
4872 Some("/Pkg2")
4873 );
4874
4875 el_short_label.set_character_data("Modified").unwrap();
4876 assert_eq!(el_reference_base.resolve_reference_base("Units"), None);
4878 assert_eq!(
4879 el_reference_base.resolve_reference_base("Modified").as_deref(),
4880 Some("/Pkg2")
4881 );
4882
4883 el_package_ref.set_reference_target(&el_ar_package).unwrap();
4884 assert_eq!(
4886 el_reference_base.resolve_reference_base("Modified").as_deref(),
4887 Some("/Pkg")
4888 );
4889
4890 el_reference_base.remove_sub_element(el_package_ref).unwrap();
4891 assert_eq!(el_reference_base.resolve_reference_base("Modified"), None);
4893 let el_package_ref = el_reference_base.create_sub_element(ElementName::PackageRef).unwrap();
4895 el_package_ref.set_reference_target(&el_ar_package2).unwrap();
4896 assert_eq!(
4897 el_reference_base.resolve_reference_base("Modified").as_deref(),
4898 Some("/Pkg2")
4899 );
4900 el_reference_base.remove_sub_element(el_short_label).unwrap();
4902 assert_eq!(el_reference_base.resolve_reference_base("Modified"), None);
4904 let el_short_label = el_reference_base.create_sub_element(ElementName::ShortLabel).unwrap();
4905 el_short_label.set_character_data("Units").unwrap();
4906 assert_eq!(
4908 el_reference_base.resolve_reference_base("Units").as_deref(),
4909 Some("/Pkg2")
4910 );
4911
4912 el_reference_bases
4913 .remove_sub_element(el_reference_base.clone())
4914 .unwrap();
4915 assert_eq!(el_reference_base.resolve_reference_base("Units"), None);
4917 assert_eq!(model.verify_reference_caches(), Ok(()));
4918 }
4919
4920 #[test]
4921 fn rename_reference_base() {
4922 let model = AutosarModel::new();
4923 model.create_file("test", AutosarVersion::LATEST).unwrap();
4924
4925 let el_ar_packages = model
4926 .root_element()
4927 .create_sub_element(ElementName::ArPackages)
4928 .unwrap();
4929 let owner1 = el_ar_packages
4930 .create_named_sub_element(ElementName::ArPackage, "Owner1")
4931 .unwrap();
4932 let owner2 = el_ar_packages
4933 .create_named_sub_element(ElementName::ArPackage, "Owner2")
4934 .unwrap();
4935 let target1 = el_ar_packages
4936 .create_named_sub_element(ElementName::ArPackage, "Target1")
4937 .unwrap();
4938 let target2 = el_ar_packages
4939 .create_named_sub_element(ElementName::ArPackage, "Target2")
4940 .unwrap();
4941
4942 let short_label_1 = owner1
4943 .create_sub_element(ElementName::ReferenceBases)
4944 .and_then(|e| e.create_sub_element(ElementName::ReferenceBase))
4945 .and_then(|e| {
4946 e.create_sub_element(ElementName::ShortLabel)
4947 .and_then(|l| l.set_character_data("Shared").map(|_| l))
4948 })
4949 .unwrap();
4950 let owner1_reference_base = owner1
4951 .get_sub_element(ElementName::ReferenceBases)
4952 .and_then(|e| e.get_sub_element(ElementName::ReferenceBase))
4953 .unwrap();
4954 owner1_reference_base
4955 .create_sub_element(ElementName::PackageRef)
4956 .and_then(|p| p.set_reference_target(&target1))
4957 .unwrap();
4958
4959 owner2
4960 .create_sub_element(ElementName::ReferenceBases)
4961 .and_then(|e| e.create_sub_element(ElementName::ReferenceBase))
4962 .and_then(|e| {
4963 e.create_sub_element(ElementName::ShortLabel)
4964 .and_then(|l| l.set_character_data("Shared").map(|_| l))
4965 })
4966 .unwrap();
4967 let owner2_reference_base = owner2
4968 .get_sub_element(ElementName::ReferenceBases)
4969 .and_then(|e| e.get_sub_element(ElementName::ReferenceBase))
4970 .unwrap();
4971 owner2_reference_base
4972 .create_sub_element(ElementName::PackageRef)
4973 .and_then(|p| p.set_reference_target(&target2))
4974 .unwrap();
4975
4976 assert_eq!(
4978 short_label_1.resolve_reference_base("Shared").as_deref(),
4979 Some("/Target1")
4980 );
4981 assert_eq!(
4982 owner2_reference_base.resolve_reference_base("Shared").as_deref(),
4983 Some("/Target2")
4984 );
4985
4986 short_label_1.set_character_data("Renamed").unwrap();
4987
4988 assert_eq!(short_label_1.resolve_reference_base("Shared"), None);
4990 assert_eq!(
4991 short_label_1.resolve_reference_base("Renamed").as_deref(),
4992 Some("/Target1")
4993 );
4994 assert_eq!(
4995 owner2_reference_base.resolve_reference_base("Shared").as_deref(),
4996 Some("/Target2")
4997 );
4998 assert_eq!(owner2_reference_base.resolve_reference_base("Renamed"), None);
4999 assert_eq!(model.verify_reference_caches(), Ok(()));
5000 }
5001
5002 #[test]
5003 fn changing_base_attribute() {
5004 let model = AutosarModel::new();
5005 model.create_file("test", AutosarVersion::LATEST).unwrap();
5006
5007 let el_ar_packages = model
5008 .root_element()
5009 .create_sub_element(ElementName::ArPackages)
5010 .unwrap();
5011 let base_a = el_ar_packages
5012 .create_named_sub_element(ElementName::ArPackage, "BaseA")
5013 .unwrap();
5014 let base_b = el_ar_packages
5015 .create_named_sub_element(ElementName::ArPackage, "BaseB")
5016 .unwrap();
5017 let ref_pkg = el_ar_packages
5018 .create_named_sub_element(ElementName::ArPackage, "RefPkg")
5019 .unwrap();
5020
5021 let ecu_a = base_a
5022 .create_sub_element(ElementName::Elements)
5023 .and_then(|e| e.create_named_sub_element(ElementName::EcuInstance, "Ecu"))
5024 .unwrap();
5025 let _ecu_b = base_b
5026 .create_sub_element(ElementName::Elements)
5027 .and_then(|e| e.create_named_sub_element(ElementName::EcuInstance, "Ecu"))
5028 .unwrap();
5029
5030 let ref_bases = ref_pkg.create_sub_element(ElementName::ReferenceBases).unwrap();
5031 let rb_a = ref_bases.create_sub_element(ElementName::ReferenceBase).unwrap();
5032 rb_a.create_sub_element(ElementName::ShortLabel)
5033 .and_then(|e| e.set_character_data("A"))
5034 .unwrap();
5035 rb_a.create_sub_element(ElementName::PackageRef)
5036 .and_then(|e| e.set_reference_target(&base_a))
5037 .unwrap();
5038
5039 let rb_b = ref_bases.create_sub_element(ElementName::ReferenceBase).unwrap();
5040 rb_b.create_sub_element(ElementName::ShortLabel)
5041 .and_then(|e| e.set_character_data("B"))
5042 .unwrap();
5043 rb_b.create_sub_element(ElementName::PackageRef)
5044 .and_then(|e| e.set_reference_target(&base_b))
5045 .unwrap();
5046
5047 let ref_elem = ref_pkg
5048 .create_sub_element(ElementName::Elements)
5049 .and_then(|e| e.create_named_sub_element(ElementName::System, "Sys"))
5050 .and_then(|e| e.create_sub_element(ElementName::FibexElements))
5051 .and_then(|e| e.create_sub_element(ElementName::FibexElementRefConditional))
5052 .and_then(|e| e.create_sub_element(ElementName::FibexElementRef))
5053 .unwrap();
5054 ref_elem.set_relative_reference_target(&ecu_a, "A").unwrap();
5055
5056 ref_elem.set_attribute_string(AttributeName::Base, "B").unwrap();
5057
5058 assert_eq!(
5061 model.relative_reference_target(&ref_elem.downgrade()).as_deref(),
5062 Some("/BaseB/Ecu")
5063 );
5064 assert_eq!(model.get_references_to("/BaseB/Ecu").len(), 1);
5065 assert!(model.get_references_to("/BaseA/Ecu").is_empty());
5066 assert_eq!(model.verify_reference_caches(), Ok(()));
5067 }
5068
5069 fn create_reference_base(owner_package: &Element, label: &str, target_package: &Element) {
5072 let el_reference_base = owner_package
5073 .get_or_create_sub_element(ElementName::ReferenceBases)
5074 .and_then(|e| e.create_sub_element(ElementName::ReferenceBase))
5075 .unwrap();
5076 el_reference_base
5077 .create_sub_element(ElementName::ShortLabel)
5078 .and_then(|e| e.set_character_data(label))
5079 .unwrap();
5080 el_reference_base
5081 .create_sub_element(ElementName::PackageRef)
5082 .and_then(|e| e.set_reference_target(target_package))
5083 .unwrap();
5084 }
5085
5086 fn build_reference_base_model() -> (AutosarModel, Element, Element) {
5089 let model = AutosarModel::new();
5090 model.create_file("test", AutosarVersion::LATEST).unwrap();
5091 let el_ar_packages = model
5092 .root_element()
5093 .create_sub_element(ElementName::ArPackages)
5094 .unwrap();
5095 let el_target = el_ar_packages
5096 .create_named_sub_element(ElementName::ArPackage, "Target")
5097 .unwrap();
5098 let el_owner = el_ar_packages
5101 .create_named_sub_element(ElementName::ArPackage, "Outer")
5102 .and_then(|e| e.create_sub_element(ElementName::ArPackages))
5103 .and_then(|e| e.create_named_sub_element(ElementName::ArPackage, "Owner"))
5104 .unwrap();
5105 create_reference_base(&el_owner, "BaseA", &el_target);
5106 create_reference_base(&el_owner, "BaseB", &el_target);
5107 let el_inside_owner = el_owner
5109 .create_sub_element(ElementName::Elements)
5110 .and_then(|e| e.create_named_sub_element(ElementName::System, "System"))
5111 .unwrap();
5112
5113 assert_eq!(
5114 el_inside_owner.resolve_reference_base("BaseA").as_deref(),
5115 Some("/Target")
5116 );
5117 assert_eq!(
5118 el_inside_owner.resolve_reference_base("BaseB").as_deref(),
5119 Some("/Target")
5120 );
5121
5122 (model, el_owner, el_inside_owner)
5123 }
5124
5125 #[test]
5126 fn remove_reference_bases_element() {
5127 let (model, el_owner, el_inside_owner) = build_reference_base_model();
5129 let el_reference_bases = el_owner.get_sub_element(ElementName::ReferenceBases).unwrap();
5130 el_owner.remove_sub_element(el_reference_bases).unwrap();
5131 assert_eq!(el_inside_owner.resolve_reference_base("BaseA"), None);
5132 assert_eq!(el_inside_owner.resolve_reference_base("BaseB"), None);
5133 assert_eq!(model.verify_reference_caches(), Ok(()));
5134 }
5135
5136 #[test]
5137 fn remove_reference_base_owner_package() {
5138 let (model, el_owner, el_inside_owner) = build_reference_base_model();
5142 let el_ar_packages = el_owner.parent().unwrap().unwrap();
5143 el_ar_packages.remove_sub_element(el_owner).unwrap();
5144 assert_eq!(el_inside_owner.resolve_reference_base("BaseA"), None);
5145 assert_eq!(model.verify_reference_caches(), Ok(()));
5146 }
5147
5148 #[test]
5149 fn remove_reference_base_ancestor() {
5150 let (model, _el_owner, el_inside_owner) = build_reference_base_model();
5153 let el_ar_packages = model.root_element().get_sub_element(ElementName::ArPackages).unwrap();
5154 model.root_element().remove_sub_element(el_ar_packages).unwrap();
5155 assert_eq!(el_inside_owner.resolve_reference_base("BaseA"), None);
5156 assert_eq!(model.verify_reference_caches(), Ok(()));
5157 }
5158
5159 #[test]
5160 fn remove_reference_base_short_label_character_data() {
5161 let (model, el_owner, el_inside_owner) = build_reference_base_model();
5164 let el_short_label = el_owner
5165 .get_sub_element(ElementName::ReferenceBases)
5166 .and_then(|e| e.get_sub_element(ElementName::ReferenceBase))
5167 .and_then(|e| e.get_sub_element(ElementName::ShortLabel))
5168 .unwrap();
5169 assert_eq!(
5170 el_short_label.character_data().unwrap().string_value().unwrap(),
5171 "BaseA"
5172 );
5173 el_short_label.remove_character_data().unwrap();
5174
5175 assert_eq!(el_inside_owner.resolve_reference_base("BaseA"), None);
5176 assert_eq!(
5177 el_inside_owner.resolve_reference_base("BaseB").as_deref(),
5178 Some("/Target")
5179 );
5180 assert_eq!(model.verify_reference_caches(), Ok(()));
5181 }
5182
5183 #[test]
5184 fn remove_reference_base_package_ref_character_data() {
5185 let (model, el_owner, el_inside_owner) = build_reference_base_model();
5188 let el_package_ref = el_owner
5189 .get_sub_element(ElementName::ReferenceBases)
5190 .and_then(|e| e.get_sub_element(ElementName::ReferenceBase))
5191 .and_then(|e| e.get_sub_element(ElementName::PackageRef))
5192 .unwrap();
5193 assert_eq!(
5194 el_package_ref.character_data().unwrap().string_value().unwrap(),
5195 "/Target"
5196 );
5197 el_package_ref.remove_character_data().unwrap();
5198
5199 assert_eq!(el_inside_owner.resolve_reference_base("BaseA"), None);
5200 assert_eq!(
5201 el_inside_owner.resolve_reference_base("BaseB").as_deref(),
5202 Some("/Target")
5203 );
5204 assert_eq!(model.verify_reference_caches(), Ok(()));
5205 }
5206
5207 fn get_package_ref(owner_package: &Element) -> Element {
5209 owner_package
5210 .get_sub_element(ElementName::ReferenceBases)
5211 .and_then(|e| e.get_sub_element(ElementName::ReferenceBase))
5212 .and_then(|e| e.get_sub_element(ElementName::PackageRef))
5213 .unwrap()
5214 }
5215
5216 fn resolved_reference_base(reference: &Element) -> Option<String> {
5219 let base_label = reference
5220 .attribute_value(AttributeName::Base)
5221 .and_then(|cdata| cdata.string_value())?;
5222 reference.resolve_reference_base(&base_label)
5223 }
5224
5225 fn create_target_package(ar_packages: &Element, name: &str) -> (Element, Element) {
5227 let el_package = ar_packages
5228 .create_named_sub_element(ElementName::ArPackage, name)
5229 .unwrap();
5230 let el_ecu = el_package
5231 .create_sub_element(ElementName::Elements)
5232 .and_then(|e| e.create_named_sub_element(ElementName::EcuInstance, "Ecu"))
5233 .unwrap();
5234 (el_package, el_ecu)
5235 }
5236
5237 fn create_relative_reference(
5239 ar_packages: &Element,
5240 package_name: &str,
5241 target: &Element,
5242 base_label: &str,
5243 ) -> Element {
5244 let el_ref = ar_packages
5245 .create_named_sub_element(ElementName::ArPackage, package_name)
5246 .and_then(|e| e.create_sub_element(ElementName::Elements))
5247 .and_then(|e| e.create_named_sub_element(ElementName::System, "System"))
5248 .and_then(|e| e.create_sub_element(ElementName::FibexElements))
5249 .and_then(|e| e.create_sub_element(ElementName::FibexElementRefConditional))
5250 .and_then(|e| e.create_sub_element(ElementName::FibexElementRef))
5251 .unwrap();
5252 el_ref.set_relative_reference_target(target, base_label).unwrap();
5253 el_ref
5254 }
5255
5256 fn build_relative_reference_model() -> (AutosarModel, Element, Element, Element) {
5262 let model = AutosarModel::new();
5263 model.create_file("test", AutosarVersion::LATEST).unwrap();
5264 let el_ar_packages = model
5265 .root_element()
5266 .create_sub_element(ElementName::ArPackages)
5267 .unwrap();
5268 let (el_target, el_ecu) = create_target_package(&el_ar_packages, "Target");
5269 let el_owner = el_ar_packages
5270 .create_named_sub_element(ElementName::ArPackage, "Owner")
5271 .unwrap();
5272 create_reference_base(&el_owner, "Base", &el_target);
5273 let el_owner_packages = el_owner.create_sub_element(ElementName::ArPackages).unwrap();
5274 let el_ref = create_relative_reference(&el_owner_packages, "Sub", &el_ecu, "Base");
5275
5276 assert_eq!(el_ref.character_data().unwrap().string_value().unwrap(), "Ecu");
5278 assert_eq!(el_ref.get_reference_target().unwrap(), el_ecu);
5279 assert!(model.check_references().is_empty());
5280
5281 (model, el_owner, el_target, el_ref)
5282 }
5283
5284 #[test]
5285 fn rename_reference_base_owner_package() {
5286 let (model, el_owner, _el_target, el_ref) = build_relative_reference_model();
5289 el_owner.set_item_name("Renamed").unwrap();
5290
5291 assert_eq!(resolved_reference_base(&el_ref).as_deref(), Some("/Target"));
5292 assert_eq!(el_ref.get_reference_target().unwrap().path().unwrap(), "/Target/Ecu");
5294 assert!(model.check_references().is_empty());
5295 assert_eq!(model.verify_reference_caches(), Ok(()));
5296 }
5297
5298 #[test]
5299 fn rename_reference_base_target_package() {
5300 let (model, el_owner, el_target, el_ref) = build_relative_reference_model();
5303 el_target.set_item_name("Renamed").unwrap();
5304
5305 let el_package_ref = get_package_ref(&el_owner);
5306 assert_eq!(
5307 el_package_ref.character_data().unwrap().string_value().unwrap(),
5308 "/Renamed"
5309 );
5310 assert_eq!(resolved_reference_base(&el_ref).as_deref(), Some("/Renamed"));
5311 assert_eq!(el_ref.character_data().unwrap().string_value().unwrap(), "Ecu");
5313 assert_eq!(el_ref.get_reference_target().unwrap().path().unwrap(), "/Renamed/Ecu");
5314 assert!(model.check_references().is_empty());
5315 assert_eq!(model.verify_reference_caches(), Ok(()));
5316 }
5317
5318 #[test]
5319 fn rename_reference_base_path_boundary() {
5320 let model = AutosarModel::new();
5322 model.create_file("test", AutosarVersion::LATEST).unwrap();
5323 let el_ar_packages = model
5324 .root_element()
5325 .create_sub_element(ElementName::ArPackages)
5326 .unwrap();
5327 let (el_pkg1, _) = create_target_package(&el_ar_packages, "Pkg1");
5328 let (el_pkg10, _) = create_target_package(&el_ar_packages, "Pkg10");
5329 create_reference_base(&el_pkg1, "Base1", &el_pkg10);
5331 create_reference_base(&el_pkg10, "Base10", &el_pkg1);
5332
5333 el_pkg1.set_item_name("Renamed").unwrap();
5334
5335 assert_eq!(
5338 get_package_ref(&el_pkg1).resolve_reference_base("Base1").as_deref(),
5339 Some("/Pkg10")
5340 );
5341 assert_eq!(get_package_ref(&el_pkg1).resolve_reference_base("Base10"), None);
5342 assert_eq!(
5343 get_package_ref(&el_pkg10).resolve_reference_base("Base10").as_deref(),
5344 Some("/Renamed")
5345 );
5346 assert_eq!(get_package_ref(&el_pkg10).resolve_reference_base("Base1"), None);
5347 assert_eq!(model.verify_reference_caches(), Ok(()));
5348 }
5349
5350 #[test]
5351 fn rename_short_name_of_reference_base_owner() {
5352 let (model, el_owner, el_target, el_ref) = build_relative_reference_model();
5356 el_owner
5357 .get_sub_element(ElementName::ShortName)
5358 .and_then(|e| e.set_character_data("Renamed").ok())
5359 .unwrap();
5360
5361 assert_eq!(resolved_reference_base(&el_ref).as_deref(), Some("/Target"));
5362 assert_eq!(el_ref.get_reference_target().unwrap().path().unwrap(), "/Target/Ecu");
5363
5364 el_target
5368 .get_sub_element(ElementName::ShortName)
5369 .and_then(|e| e.set_character_data("MovedAway").ok())
5370 .unwrap();
5371
5372 assert_eq!(resolved_reference_base(&el_ref).as_deref(), Some("/Target"));
5374 assert!(el_ref.get_reference_target().is_err());
5375 assert_eq!(model.check_references().len(), 2);
5378 assert_eq!(model.verify_reference_caches(), Ok(()));
5379 }
5380
5381 #[test]
5382 fn move_reference_base_owner_package() {
5383 let (model, el_owner, el_target, el_ref) = build_relative_reference_model();
5385 el_target
5386 .create_sub_element(ElementName::ArPackages)
5387 .and_then(|e| e.move_element_here(&el_owner))
5388 .unwrap();
5389
5390 assert_eq!(resolved_reference_base(&el_ref).as_deref(), Some("/Target"));
5391 assert!(model.get_element_by_path("/Target/Owner/Sub/System").is_some());
5393 assert_eq!(el_ref.get_reference_target().unwrap().path().unwrap(), "/Target/Ecu");
5394 assert!(model.check_references().is_empty());
5395 assert_eq!(model.verify_reference_caches(), Ok(()));
5396 }
5397
5398 #[test]
5399 fn move_reference_base_target_package() {
5400 let (model, el_owner, el_target, el_ref) = build_relative_reference_model();
5403 el_owner
5404 .get_sub_element(ElementName::ArPackages)
5405 .unwrap()
5406 .move_element_here(&el_target)
5407 .unwrap();
5408
5409 assert_eq!(
5410 get_package_ref(&el_owner)
5411 .character_data()
5412 .unwrap()
5413 .string_value()
5414 .unwrap(),
5415 "/Owner/Target"
5416 );
5417 assert_eq!(resolved_reference_base(&el_ref).as_deref(), Some("/Owner/Target"));
5418 assert_eq!(
5419 el_ref.get_reference_target().unwrap().path().unwrap(),
5420 "/Owner/Target/Ecu"
5421 );
5422 assert!(model.check_references().is_empty());
5423 assert_eq!(model.verify_reference_caches(), Ok(()));
5424 }
5425
5426 #[test]
5427 fn move_reference_bases_element_to_other_package() {
5428 let (model, el_owner, el_target, el_ref) = build_relative_reference_model();
5432 let el_reference_bases = el_owner.get_sub_element(ElementName::ReferenceBases).unwrap();
5433 el_target.move_element_here(&el_reference_bases).unwrap();
5434
5435 assert_eq!(resolved_reference_base(&el_ref), None);
5437 assert!(el_ref.get_reference_target().is_err());
5438 assert_eq!(model.check_references().len(), 1);
5439 assert_eq!(model.verify_reference_caches(), Ok(()));
5440 }
5441
5442 #[test]
5443 fn move_single_reference_base_to_other_package() {
5444 let (model, el_owner, el_target, el_ref) = build_relative_reference_model();
5447 let el_reference_base = el_owner
5448 .get_sub_element(ElementName::ReferenceBases)
5449 .and_then(|e| e.get_sub_element(ElementName::ReferenceBase))
5450 .unwrap();
5451 el_target
5452 .create_sub_element(ElementName::ReferenceBases)
5453 .and_then(|e| e.move_element_here(&el_reference_base))
5454 .unwrap();
5455
5456 assert_eq!(resolved_reference_base(&el_ref), None);
5457 assert!(el_ref.get_reference_target().is_err());
5458
5459 let el_target_packages = el_target.create_sub_element(ElementName::ArPackages).unwrap();
5461 let el_ecu = model.get_element_by_path("/Target/Ecu").unwrap();
5462 let el_new_ref = create_relative_reference(&el_target_packages, "Consumer", &el_ecu, "Base");
5463 assert_eq!(el_new_ref.get_reference_target().unwrap(), el_ecu);
5464 assert_eq!(model.verify_reference_caches(), Ok(()));
5465 }
5466
5467 #[test]
5468 fn move_unnamed_element_containing_packages() {
5469 let model = AutosarModel::new();
5474 model.create_file("test", AutosarVersion::LATEST).unwrap();
5475 let el_ar_packages = model
5476 .root_element()
5477 .create_sub_element(ElementName::ArPackages)
5478 .unwrap();
5479 let (el_target, el_ecu) = create_target_package(&el_ar_packages, "Target");
5480 let el_dest = el_ar_packages
5481 .create_named_sub_element(ElementName::ArPackage, "Dest")
5482 .unwrap();
5483 let el_holder_packages = el_ar_packages
5484 .create_named_sub_element(ElementName::ArPackage, "Holder")
5485 .and_then(|e| e.create_sub_element(ElementName::ArPackages))
5486 .unwrap();
5487
5488 let el_pkg_a = el_holder_packages
5490 .create_named_sub_element(ElementName::ArPackage, "PkgA")
5491 .unwrap();
5492 create_reference_base(&el_pkg_a, "BaseA", &el_target);
5493 let el_pkg_a_packages = el_pkg_a.create_sub_element(ElementName::ArPackages).unwrap();
5494 let el_ref = create_relative_reference(&el_pkg_a_packages, "PkgA_Sub", &el_ecu, "BaseA");
5495 let el_pkg_b = el_holder_packages
5497 .create_named_sub_element(ElementName::ArPackage, "PkgB")
5498 .unwrap();
5499 create_reference_base(&el_pkg_b, "BaseB", &el_target);
5500
5501 assert_eq!(el_ref.get_reference_target().unwrap(), el_ecu);
5502 assert!(model.get_element_by_path("/Holder/PkgA/PkgA_Sub").is_some());
5503
5504 el_dest.move_element_here(&el_holder_packages).unwrap();
5506
5507 assert!(model.get_element_by_path("/Dest/PkgA").is_some());
5509 assert!(model.get_element_by_path("/Dest/PkgB").is_some());
5510 assert!(model.get_element_by_path("/Dest/PkgA/PkgA_Sub").is_some());
5513 assert!(model.get_element_by_path("/Holder/PkgA").is_none());
5514 assert!(model.get_element_by_path("/Holder/PkgA/PkgA_Sub").is_none());
5515 assert!(model.get_element_by_path("/Holder/PkgB").is_none());
5516
5517 assert_eq!(resolved_reference_base(&el_ref).as_deref(), Some("/Target"));
5520 assert_eq!(
5521 get_package_ref(&el_pkg_b).resolve_reference_base("BaseB").as_deref(),
5522 Some("/Target")
5523 );
5524
5525 assert_eq!(el_ref.get_reference_target().unwrap(), el_ecu);
5527 assert!(model.check_references().is_empty());
5528 assert_eq!(model.verify_reference_caches(), Ok(()));
5529 }
5530
5531 #[test]
5532 fn move_relative_reference_out_of_scope() {
5533 let (model, _el_owner, el_target, el_ref) = build_relative_reference_model();
5536 let el_sub = model.get_element_by_path("/Owner/Sub").unwrap();
5537 el_target
5538 .create_sub_element(ElementName::ArPackages)
5539 .and_then(|e| e.move_element_here(&el_sub))
5540 .unwrap();
5541
5542 assert_eq!(el_ref.character_data().unwrap().string_value().unwrap(), "Ecu");
5543 assert!(el_ref.get_reference_target().is_err());
5544 let broken = model.check_references();
5545 assert_eq!(broken.len(), 1);
5546 assert_eq!(broken[0].upgrade().unwrap(), el_ref);
5547 assert_eq!(model.verify_reference_caches(), Ok(()));
5548 }
5549
5550 #[test]
5551 fn move_relative_reference_into_new_scope() {
5552 let (model, _el_owner, _el_target, el_ref) = build_relative_reference_model();
5555 let el_ar_packages = model.root_element().get_sub_element(ElementName::ArPackages).unwrap();
5556 let (el_other_target, _) = create_target_package(&el_ar_packages, "OtherTarget");
5558 let el_other = el_ar_packages
5559 .create_named_sub_element(ElementName::ArPackage, "Other")
5560 .unwrap();
5561 create_reference_base(&el_other, "Base", &el_other_target);
5562
5563 let el_sub = model.get_element_by_path("/Owner/Sub").unwrap();
5564 el_other
5565 .create_sub_element(ElementName::ArPackages)
5566 .and_then(|e| e.move_element_here(&el_sub))
5567 .unwrap();
5568
5569 assert_eq!(el_ref.character_data().unwrap().string_value().unwrap(), "Ecu");
5570 assert_eq!(
5571 el_ref.get_reference_target().unwrap().path().unwrap(),
5572 "/OtherTarget/Ecu"
5573 );
5574 assert!(model.check_references().is_empty());
5575 assert_eq!(model.verify_reference_caches(), Ok(()));
5576 }
5577
5578 #[test]
5579 fn move_element_full_migrates_reference_bases() {
5580 let (model_src, el_owner, _el_target, el_ref) = build_relative_reference_model();
5583
5584 let model_dest = AutosarModel::new();
5585 model_dest.create_file("dest", AutosarVersion::LATEST).unwrap();
5586 let el_dest_packages = model_dest
5587 .root_element()
5588 .create_sub_element(ElementName::ArPackages)
5589 .unwrap();
5590 create_target_package(&el_dest_packages, "Target");
5593 let el_dest_outer = el_dest_packages
5594 .create_named_sub_element(ElementName::ArPackage, "Outer")
5595 .and_then(|e| e.create_sub_element(ElementName::ArPackages))
5596 .unwrap();
5597
5598 el_dest_outer.move_element_here(&el_owner).unwrap();
5599
5600 assert!(model_src.0.read().relative_references.is_empty());
5601 assert_eq!(resolved_reference_base(&el_ref).as_deref(), Some("/Target"));
5603 assert!(!model_dest.0.read().relative_references.is_empty());
5605 assert_eq!(el_ref.get_reference_target().unwrap().path().unwrap(), "/Target/Ecu");
5606 assert_eq!(model_dest.get_references_to("/Target/Ecu").len(), 1);
5607 assert!(model_dest.check_references().is_empty());
5608 }
5609
5610 #[test]
5611 fn move_element_full_keeps_external_references() {
5612 let model_src = AutosarModel::new();
5615 model_src.create_file("src", AutosarVersion::LATEST).unwrap();
5616 let el_src_packages = model_src
5617 .root_element()
5618 .create_sub_element(ElementName::ArPackages)
5619 .unwrap();
5620 let (_, el_src_ecu) = create_target_package(&el_src_packages, "Target");
5621 let el_ref = el_src_packages
5622 .create_named_sub_element(ElementName::ArPackage, "Sub")
5623 .and_then(|e| e.create_sub_element(ElementName::Elements))
5624 .and_then(|e| e.create_named_sub_element(ElementName::System, "System"))
5625 .and_then(|e| e.create_sub_element(ElementName::FibexElements))
5626 .and_then(|e| e.create_sub_element(ElementName::FibexElementRefConditional))
5627 .and_then(|e| e.create_sub_element(ElementName::FibexElementRef))
5628 .unwrap();
5629 el_ref.set_reference_target(&el_src_ecu).unwrap();
5630
5631 let model_dest = AutosarModel::new();
5632 model_dest.create_file("dest", AutosarVersion::LATEST).unwrap();
5633 let el_dest_packages = model_dest
5634 .root_element()
5635 .create_sub_element(ElementName::ArPackages)
5636 .unwrap();
5637 create_target_package(&el_dest_packages, "Target");
5638
5639 let el_sub = model_src.get_element_by_path("/Sub").unwrap();
5640 el_dest_packages.move_element_here(&el_sub).unwrap();
5641
5642 assert_eq!(el_ref.character_data().unwrap().string_value().unwrap(), "/Target/Ecu");
5644 assert_eq!(model_dest.get_references_to("/Target/Ecu").len(), 1);
5647 assert_eq!(model_src.get_references_to("/Target/Ecu").len(), 0);
5648 assert!(model_dest.check_references().is_empty());
5649 }
5650
5651 #[test]
5652 fn copy_resolves_relative_references() {
5653 let (model, el_owner, _el_target, _el_ref) = build_relative_reference_model();
5656 let el_ar_packages = model.root_element().get_sub_element(ElementName::ArPackages).unwrap();
5657 let el_copy = el_ar_packages.create_copied_sub_element(&el_owner).unwrap();
5658
5659 assert_eq!(el_copy.path().unwrap(), "/Owner_1");
5660
5661 let el_copied_ref = model
5663 .get_element_by_path("/Owner_1/Sub/System")
5664 .and_then(|e| e.get_sub_element(ElementName::FibexElements))
5665 .and_then(|e| e.get_sub_element_at(0))
5666 .and_then(|e| e.get_sub_element(ElementName::FibexElementRef))
5667 .unwrap();
5668 assert_eq!(
5669 el_copied_ref.get_reference_target().unwrap().path().unwrap(),
5670 "/Target/Ecu"
5671 );
5672 assert_eq!(model.verify_reference_caches(), Ok(()));
5673 }
5674
5675 #[test]
5676 fn set_character_data_on_package_ref_retargets_reference_base() {
5677 let (model, el_owner, _el_target, el_ref) = build_relative_reference_model();
5680 let el_ar_packages = model.root_element().get_sub_element(ElementName::ArPackages).unwrap();
5681 create_target_package(&el_ar_packages, "OtherTarget");
5682
5683 assert_eq!(model.get_references_to("/Target/Ecu").len(), 1);
5684
5685 get_package_ref(&el_owner).set_character_data("/OtherTarget").unwrap();
5686
5687 assert_eq!(resolved_reference_base(&el_ref).as_deref(), Some("/OtherTarget"));
5688 assert_eq!(
5689 el_ref.get_reference_target().unwrap().path().unwrap(),
5690 "/OtherTarget/Ecu"
5691 );
5692 assert_eq!(model.get_references_to("/OtherTarget/Ecu").len(), 1);
5695 assert!(model.get_references_to("/Target/Ecu").is_empty());
5696 assert_eq!(model.verify_reference_caches(), Ok(()));
5697 }
5698
5699 #[test]
5700 fn set_base_attribute_on_package_ref_chains_reference_base() {
5701 let (model, el_owner, el_target, _el_ref) = build_relative_reference_model();
5704 let el_inner = el_target
5706 .get_sub_element(ElementName::ArPackages)
5707 .unwrap_or_else(|| el_target.create_sub_element(ElementName::ArPackages).unwrap())
5708 .create_named_sub_element(ElementName::ArPackage, "Inner")
5709 .unwrap();
5710 create_reference_base(&el_owner, "Chained", &el_inner);
5711 let el_owner_package_ref = get_package_ref(&el_owner);
5712 assert_eq!(
5713 el_owner_package_ref.resolve_reference_base("Chained").as_deref(),
5714 Some("/Target/Inner")
5715 );
5716
5717 let el_chained_package_ref = el_owner
5719 .get_sub_element(ElementName::ReferenceBases)
5720 .and_then(|e| e.get_sub_element_at(1))
5721 .and_then(|e| e.get_sub_element(ElementName::PackageRef))
5722 .unwrap();
5723 el_chained_package_ref.set_character_data("Inner").unwrap();
5724 el_chained_package_ref
5725 .set_attribute_string(AttributeName::Base, "Base")
5726 .unwrap();
5727
5728 assert_eq!(
5730 el_owner_package_ref.resolve_reference_base("Chained").as_deref(),
5731 Some("/Target/Inner")
5732 );
5733
5734 assert!(el_chained_package_ref.remove_attribute(AttributeName::Base));
5737 assert_eq!(
5738 el_owner_package_ref.resolve_reference_base("Chained").as_deref(),
5739 Some("Inner")
5740 );
5741 assert_eq!(model.verify_reference_caches(), Ok(()));
5742 }
5743
5744 #[test]
5745 fn set_character_data_on_relative_reference() {
5746 let (model, _el_owner, el_target, el_ref) = build_relative_reference_model();
5750 let el_ecu2 = el_target
5751 .get_sub_element(ElementName::Elements)
5752 .unwrap()
5753 .create_named_sub_element(ElementName::EcuInstance, "Ecu2")
5754 .unwrap();
5755
5756 el_ref.set_character_data("Ecu2").unwrap();
5757
5758 assert_eq!(
5759 el_ref
5760 .attribute_value(AttributeName::Base)
5761 .unwrap()
5762 .string_value()
5763 .unwrap(),
5764 "Base"
5765 );
5766 assert_eq!(el_ref.get_reference_target().unwrap(), el_ecu2);
5767 assert_eq!(
5768 model.relative_reference_target(&el_ref.downgrade()).as_deref(),
5769 Some("/Target/Ecu2")
5770 );
5771 assert_eq!(model.get_references_to("/Target/Ecu2").len(), 1);
5772 assert!(model.get_references_to("/Target/Ecu").is_empty());
5773 assert!(model.check_references().is_empty());
5774 assert_eq!(model.verify_reference_caches(), Ok(()));
5775 }
5776
5777 #[test]
5778 fn set_character_data_incompatible_value() {
5779 let model = AutosarModel::new();
5781 model.create_file("test", AutosarVersion::LATEST).unwrap();
5782 let el_elements = model
5783 .root_element()
5784 .create_sub_element(ElementName::ArPackages)
5785 .and_then(|e| e.create_named_sub_element(ElementName::ArPackage, "Pkg"))
5786 .and_then(|e| e.create_sub_element(ElementName::Elements))
5787 .unwrap();
5788 let el_ecu_instance = el_elements
5789 .create_named_sub_element(ElementName::EcuInstance, "Ecu")
5790 .unwrap();
5791 let el_sleep_mode_supported = el_ecu_instance
5792 .create_sub_element(ElementName::SleepModeSupported)
5793 .unwrap();
5794
5795 assert!(matches!(
5797 el_sleep_mode_supported.set_character_data("nonsense"),
5798 Err(AutosarDataError::InvalidCharacterData {
5799 element: ElementName::SleepModeSupported,
5800 ..
5801 })
5802 ));
5803 assert!(el_sleep_mode_supported.character_data().is_none());
5804
5805 el_sleep_mode_supported.set_character_data(true).unwrap();
5807 assert_eq!(
5808 el_sleep_mode_supported
5809 .character_data()
5810 .unwrap()
5811 .string_value()
5812 .unwrap(),
5813 "true"
5814 );
5815
5816 let el_absolute = el_elements
5819 .create_named_sub_element(ElementName::ISignalIPdu, "Pdu")
5820 .and_then(|e| e.create_sub_element(ElementName::IPduTimingSpecifications))
5821 .and_then(|e| e.create_sub_element(ElementName::IPduTiming))
5822 .and_then(|e| e.create_sub_element(ElementName::TransmissionModeDeclaration))
5823 .and_then(|e| e.create_sub_element(ElementName::TransmissionModeTrueTiming))
5824 .and_then(|e| e.create_sub_element(ElementName::CyclicTiming))
5825 .and_then(|e| e.create_sub_element(ElementName::TimePeriod))
5826 .and_then(|e| e.create_sub_element(ElementName::Tolerance))
5827 .and_then(|e| e.create_sub_element(ElementName::AbsoluteTolerance))
5828 .and_then(|e| e.create_sub_element(ElementName::Absolute))
5829 .unwrap();
5830 assert!(matches!(
5831 el_absolute.set_character_data("not a number"),
5832 Err(AutosarDataError::InvalidCharacterData {
5833 element: ElementName::Absolute,
5834 ..
5835 })
5836 ));
5837 el_absolute.set_character_data(1.5).unwrap();
5838 assert_eq!(el_absolute.character_data(), Some(CharacterData::Float(1.5)));
5839 }
5840
5841 #[test]
5842 fn debug_format_of_elements() {
5843 let model = AutosarModel::new();
5844 model.create_file("test", AutosarVersion::LATEST).unwrap();
5845 let el_ar_package = model
5846 .root_element()
5847 .create_sub_element(ElementName::ArPackages)
5848 .and_then(|e| e.create_named_sub_element(ElementName::ArPackage, "Pkg"))
5849 .unwrap();
5850 let el_short_name = el_ar_package.get_sub_element(ElementName::ShortName).unwrap();
5851
5852 let package_text = format!("{el_ar_package:#?}");
5854 assert!(package_text.contains(r#"name: "Pkg""#));
5855 assert!(package_text.contains("parent: Element"));
5856
5857 let short_name_text = format!("{el_short_name:#?}");
5859 assert!(short_name_text.contains("Pkg"));
5860
5861 assert!(format!("{:#?}", model.root_element()).contains("parent: Model"));
5863
5864 let weak_short_name = el_short_name.downgrade();
5866 model
5867 .root_element()
5868 .get_sub_element(ElementName::ArPackages)
5869 .unwrap()
5870 .remove_sub_element(el_ar_package)
5871 .unwrap();
5872 assert!(format!("{el_short_name:#?}").contains("parent: None/Invalid"));
5873 drop(el_short_name);
5874 assert!(format!("{weak_short_name:#?}").contains("(invalid)"));
5875 }
5876
5877 #[test]
5878 fn reference_base_with_additional_sub_elements() {
5879 let (model, el_owner, _el_target, el_ref) = build_relative_reference_model();
5882 let el_reference_base = el_owner
5883 .get_sub_element(ElementName::ReferenceBases)
5884 .and_then(|e| e.get_sub_element(ElementName::ReferenceBase))
5885 .unwrap();
5886 el_reference_base
5887 .create_sub_element(ElementName::IsDefault)
5888 .and_then(|e| e.set_character_data(true))
5889 .unwrap();
5890 el_reference_base
5891 .create_sub_element(ElementName::IsGlobal)
5892 .and_then(|e| e.set_character_data(false))
5893 .unwrap();
5894
5895 assert_eq!(resolved_reference_base(&el_ref).as_deref(), Some("/Target"));
5896 assert_eq!(el_ref.get_reference_target().unwrap().path().unwrap(), "/Target/Ecu");
5897 assert!(model.check_references().is_empty());
5898 assert_eq!(model.verify_reference_caches(), Ok(()));
5899 }
5900
5901 #[test]
5902 fn copy_drops_incompatible_optional_attribute() {
5903 let model_new = AutosarModel::new();
5906 model_new.create_file("new", AutosarVersion::LATEST).unwrap();
5907 let el_package_new = model_new
5908 .root_element()
5909 .create_sub_element(ElementName::ArPackages)
5910 .and_then(|e| e.create_named_sub_element(ElementName::ArPackage, "Pkg"))
5911 .unwrap();
5912 let el_short_label = el_package_new
5913 .create_sub_element(ElementName::VariationPoint)
5914 .and_then(|e| e.create_sub_element(ElementName::ShortLabel))
5915 .unwrap();
5916 el_short_label.set_character_data("Label").unwrap();
5917 el_short_label
5918 .set_attribute_string(AttributeName::BlueprintValue, "bpv")
5919 .unwrap();
5920
5921 let model_old = AutosarModel::new();
5922 model_old.create_file("old", AutosarVersion::Autosar_4_3_0).unwrap();
5923 let el_copy = model_old
5924 .root_element()
5925 .create_sub_element(ElementName::ArPackages)
5926 .and_then(|e| e.create_copied_sub_element(&el_package_new))
5927 .unwrap();
5928
5929 let el_short_label_copy = el_copy
5930 .get_sub_element(ElementName::VariationPoint)
5931 .and_then(|e| e.get_sub_element(ElementName::ShortLabel))
5932 .unwrap();
5933 assert_eq!(
5934 el_short_label_copy.character_data().unwrap().string_value().unwrap(),
5935 "Label"
5936 );
5937 assert!(
5939 el_short_label_copy
5940 .attribute_value(AttributeName::BlueprintValue)
5941 .is_none()
5942 );
5943 }
5944}