diff --git a/examples/xml/reference/reference_example.py b/examples/xml/reference/reference_example.py new file mode 100644 index 0000000..47c91f9 --- /dev/null +++ b/examples/xml/reference/reference_example.py @@ -0,0 +1,7 @@ +""" +Application data type examples +""" +import autosar.xml.element as ar_element + +ref = ar_element.ExclusiveAreaRef("/Areas/Area1") +print(str(ref)) diff --git a/src/autosar/xml/element.py b/src/autosar/xml/element.py index ba36d1a..90fb562 100644 --- a/src/autosar/xml/element.py +++ b/src/autosar/xml/element.py @@ -530,9 +530,16 @@ class BaseRef(ARObject, abc.ABC): def __init__(self, value: str, - dest: ar_enum.IdentifiableSubTypes) -> None: + dest: ar_enum.IdentifiableSubTypes = None) -> None: self.value = value self.dest: ar_enum.IdentifiableSubTypes = None + if dest is None: + if len(self._accepted_subtypes()) == 1: + dest = list(self._accepted_subtypes())[0] + else: + msg_part1 = "Value of dest cannot be None. Accepted values are: " + msg_part2 = ",".join([str(x) for x in sorted(list(self._accepted_subtypes()))]) + raise ValueError(msg_part1 + msg_part2) if dest in self._accepted_subtypes(): self.dest = dest else: @@ -999,6 +1006,26 @@ def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: """Acceptable values for dest""" return {ar_enum.IdentifiableSubTypes.SWC_IMPLEMENTATION} + +class ExclusiveAreaRef(BaseRef): + """ + EXCLUSIVE-AREA--SUBTYPES-ENUM + """ + + def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.EXCLUSIVE_AREA} + + +class ExclusiveAreaNestingOrderRef(BaseRef): + """ + AR:EXCLUSIVE-AREA-NESTING-ORDER--SUBTYPES-ENUM + """ + + def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]: + """Acceptable values for dest""" + return {ar_enum.IdentifiableSubTypes.EXCLUSIVE_AREA_NESTING_ORDER} + # --- Documentation Elements @@ -2437,8 +2464,7 @@ def __init__(self, class ImplementationProps(Referrable): """ - Complex type AR:IMPLEMENTATION-PROPS - Type: Abstract + Group AR:IMPLEMENTATION-PROPS """ def __init__(self, @@ -6016,3 +6042,173 @@ def ref(self) -> SwcImplementationRef | None: if ref_str is None: return None return SwcImplementationRef(ref_str) + + +class ExecutableEntityActivationReason(ImplementationProps): + """ + Complex type AR:EXECUTABLE-ENTITY-ACTIVATION-REASON + Tag variants: 'EXECUTABLE-ENTITY-ACTIVATION-REASON' + """ + + def __init__(self, + name: str, + bit_position: int | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.bit_position: int | None = None + self._assign_optional_positive_int("bit_position", bit_position) + + +class ExclusiveAreaRefConditional(ARObject): + """ + Complex type AR:EXCLUSIVE-AREA-REF-CONDITIONAL + Tag variants: 'EXCLUSIVE-AREA-REF-CONDITIONAL' + """ + + def __init__(self, + exclusive_area_ref: ExclusiveAreaRef | str | None = None) -> None: + self.exclusive_area_ref: ExclusiveAreaRef | None = None # .EXCLUSIVE-AREA-REF + self._assign_optional("exclusive_area_ref", exclusive_area_ref, ExclusiveAreaRef) + + +ActivationReasonArgumentType = ExecutableEntityActivationReason | list[ExecutableEntityActivationReason] | None +CanEnterLeaveArgumentType = Union[ExclusiveAreaRefConditional, + list[ExclusiveAreaRefConditional], + ExclusiveAreaRef, + list[ExclusiveAreaRef], + str, + None] + +ExclusiveAreaNestingOrderArgumentType = ExclusiveAreaNestingOrderRef | list[ExclusiveAreaNestingOrderRef] | None +RunsInsidesArgumentType = Union[ExclusiveAreaRefConditional, + list[ExclusiveAreaRefConditional], + ExclusiveAreaRef, + list[ExclusiveAreaRef], + str, + None] + +ExclusiveAreaElementArgumentType = ExclusiveAreaRefConditional | ExclusiveAreaRef | str + + +class ExecutableEntity(Identifiable): + """ + Group AR:EXECUTABLE-ENTITY + """ + + def __init__(self, + name: str, + activation_reasons: ActivationReasonArgumentType = None, + can_enter_leave: CanEnterLeaveArgumentType = None, + exclusive_area_nesting_order: ExclusiveAreaNestingOrderArgumentType = None, + minimum_start_interval: float | None = None, + reentrancy_level: ar_enum.ReentrancyLevel | None = None, + runs_insides: RunsInsidesArgumentType = None, + sw_addr_method: str | SwAddrMethodRef | None = None, + **kwargs) -> None: + super().__init__(name, **kwargs) + self.activation_reasons: list[ExecutableEntityActivationReason] = [] # .ACTIVATION-REASONS + # .CAN-ENTERS or CAN-ENTER-EXCLUSIVE-AREA-REFS depending on schema version + self.can_enter_leave: list[ExclusiveAreaRefConditional] = [] + self.exclusive_area_nesting_order: list[ExclusiveAreaNestingOrderRef] = [] # .EXCLUSIVE-AREA-NESTING-ORDER-REFS + self.minimum_start_interval: float | None = None # .MINIMUM-START-INTERVAL + self.reentrancy_level: ar_enum.ReentrancyLevel | None = None # .REENTRANCY-LEVEL + # .RUNS-INSIDES or .RUNS-INSIDE-EXCLUSIVE-AREA-REFS depending on schema version + self.runs_insides: list[ExclusiveAreaRefConditional] = [] + self.sw_addr_method: str | SwAddrMethodRef | None = None # .SW-ADDR-METHOD-REF + + if activation_reasons is not None: + if isinstance(activation_reasons, list): + for activation_reason in activation_reasons: + self.append_activation_reason(activation_reason) + else: + self.append_activation_reason(activation_reasons) + if can_enter_leave is not None: + if isinstance(can_enter_leave, list): + for elem in can_enter_leave: + self.append_can_enter_leave(elem) + else: + self.append_can_enter_leave(can_enter_leave) + if exclusive_area_nesting_order is not None: + if isinstance(exclusive_area_nesting_order, ExclusiveAreaNestingOrderRef): + self.append_exclusive_area_nesting_order(exclusive_area_nesting_order) + elif isinstance(exclusive_area_nesting_order, list): + for elem in exclusive_area_nesting_order: + self.append_exclusive_area_nesting_order(elem) + self._assign_optional("minimum_start_interval", minimum_start_interval, float) + self._assign_optional("reentrancy_level", reentrancy_level, ar_enum.ReentrancyLevel) + if runs_insides is not None: + if isinstance(runs_insides, list): + for elem in runs_insides: + self.append_runs_insides(elem) + else: + self.append_runs_insides(runs_insides) + self._assign_optional('sw_addr_method', sw_addr_method, SwAddrMethodRef) + + def append_activation_reason(self, activation_reason: ExecutableEntityActivationReason) -> None: + """ + Appends activation_reason to internal list of activation reasons + """ + if isinstance(activation_reason, ExecutableEntityActivationReason): + self.activation_reasons.append(activation_reason) + else: + raise TypeError("activation_reason must be of type ExecutableEntityActivationReason") + + def append_can_enter_leave(self, value: ExclusiveAreaElementArgumentType) -> None: + """ + Tthe executable entity can enter/leave the referenced exclusive area through explicit API calls + """ + if isinstance(value, ExclusiveAreaRefConditional): + self.can_enter_leave.append(value) + elif isinstance(value, (ExclusiveAreaRef, str)): + self.can_enter_leave.append(ExclusiveAreaRefConditional(value)) + else: + raise TypeError("value: Invalid type. Expected one of ExclusiveAreaRefConditional, ExclusiveAreaRef, str.") + + def append_exclusive_area_nesting_order(self, exclusive_area_nesting_order: ExclusiveAreaNestingOrderRef) -> None: + """ + Appends exclusive area reference to internal can_enter_leave list + """ + if isinstance(exclusive_area_nesting_order, ExclusiveAreaNestingOrderRef): + self.exclusive_area_nesting_order.append(exclusive_area_nesting_order) + else: + raise TypeError("exclusive_area_nesting_order must be of type ExclusiveAreaRefConditional") + + def append_runs_insides(self, value: ExclusiveAreaElementArgumentType) -> None: + """ + The executable entity runs completely inside the referenced exclusive area + """ + if isinstance(value, ExclusiveAreaRefConditional): + self.runs_insides.append(value) + elif isinstance(value, (ExclusiveAreaRef, str)): + self.runs_insides.append(ExclusiveAreaRefConditional(value)) + else: + raise TypeError("value: Invalid type. Expected one of ExclusiveAreaRefConditional, ExclusiveAreaRef, str.") + + +class RunnableEntity(ExecutableEntity): + """ + Complex type AR:RUNNABLE-ENTITY + Tag variants: 'RUNNABLE-ENTITY' + Only implements base class features for now. + """ + + def __init__(self, + name: str, + **kwargs) -> None: + super().__init__(name, **kwargs) + + +# --- Future stuff + + +class RModeInAtomicSwcInstanceRef(ARObject): + """ + Complex type AR:R-MODE-IN-ATOMIC-SWC-INSTANCE-REF + Tag variants: 'DISABLED-MODE-IREF' | 'MODE-IREF' + """ + + +class RTEEvent(Identifiable): + """ + Group AR:RTE-EVENT + """ diff --git a/src/autosar/xml/enumeration.py b/src/autosar/xml/enumeration.py index 0a49547..45f4903 100644 --- a/src/autosar/xml/enumeration.py +++ b/src/autosar/xml/enumeration.py @@ -219,28 +219,31 @@ class IdentifiableSubTypes(Enum): DATA_CONSTR = 25 DATA_PROTOTYPE = 26 E2E_PROFILE_COMPATIBILITY_PROPS = 27 - IMPLEMENTATION_DATA_TYPE = 28 - IMPLEMENTATION_DATA_TYPE_ELEMENT = 29 - MODE_DECLARATION = 30 - MODE_DECLARATION_GROUP = 31 - MODE_DECLARATION_GROUP_PROTOTYPE = 32 - MODE_SWITCH_INTERFACE = 33 - NV_DATA_INTERFACE = 34 - P_PORT_PROTOTYPE = 35 - PARAMETER_INTERFACE = 36 - PARAMETER_DATA_PROTOTYPE = 37 - PHYSICAL_DIMENSION = 38 - PORT_PROTOTYPE = 39 - PR_PORT_PROTOTYPE = 40 - R_PORT_PROTOTYPE = 41 - SENDER_RECEIVER_INTERFACE = 42 - SW_ADDR_METHOD = 43 - SW_BASE_TYPE = 44 - SW_COMPONENT_PROTOTYPE = 45 - SWC_IMPLEMENTATION = 46 - SWC_INTERNAL_BEHAVIOR = 47 - UNIT = 48 - VARIABLE_DATA_PROTOTYPE = 49 + EXCLUSIVE_AREA = 28 + EXCLUSIVE_AREA_NESTING_ORDER = 29 + IMPLEMENTATION_DATA_TYPE = 30 + IMPLEMENTATION_DATA_TYPE_ELEMENT = 31 + MODE_DECLARATION = 32 + MODE_DECLARATION_GROUP = 33 + MODE_DECLARATION_GROUP_PROTOTYPE = 34 + MODE_SWITCH_INTERFACE = 35 + NV_DATA_INTERFACE = 36 + P_PORT_PROTOTYPE = 37 + PARAMETER_INTERFACE = 38 + PARAMETER_DATA_PROTOTYPE = 39 + PHYSICAL_DIMENSION = 40 + PORT_PROTOTYPE = 41 + PR_PORT_PROTOTYPE = 42 + R_PORT_PROTOTYPE = 43 + RUNNABLE_ENTITY = 44 + SENDER_RECEIVER_INTERFACE = 45 + SW_ADDR_METHOD = 46 + SW_BASE_TYPE = 47 + SW_COMPONENT_PROTOTYPE = 48 + SWC_IMPLEMENTATION = 49 + SWC_INTERNAL_BEHAVIOR = 50 + UNIT = 51 + VARIABLE_DATA_PROTOTYPE = 52 class IntervalType(Enum): @@ -465,6 +468,16 @@ class PageWide(Enum): PGWIDE = 1 +class ReentrancyLevel(Enum): + """ + AR:REENTRANCY-LEVEL-ENUM--SIMPLE + """ + + MULTICORE_REENTRANT = 0 + NON_REENTRANT = 1 + SINGLE_CORE_REENTRANT = 2 + + class ScaleConstraintValidity(Enum): """ AR:SCALE-CONSTR-VALIDITY-ENUM--SIMPLE @@ -720,6 +733,8 @@ class VersionedTextValue: "CONSTANT-SPECIFICATION": IdentifiableSubTypes.CONSTANT_SPECIFICATION, "DATA-CONSTR": IdentifiableSubTypes.DATA_CONSTR, "E-2-E-PROFILE-COMPATIBILITY-PROPS": IdentifiableSubTypes.E2E_PROFILE_COMPATIBILITY_PROPS, + "EXCLUSIVE-AREA": IdentifiableSubTypes.EXCLUSIVE_AREA, + "EXCLUSIVE-AREA-NESTING-ORDER": IdentifiableSubTypes.EXCLUSIVE_AREA_NESTING_ORDER, "IMPLEMENTATION-DATA-TYPE": IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE, "IMPLEMENTATION-DATA-TYPE-ELEMENT": IdentifiableSubTypes.IMPLEMENTATION_DATA_TYPE_ELEMENT, "MODE-DECLARATION": IdentifiableSubTypes.MODE_DECLARATION, @@ -734,6 +749,7 @@ class VersionedTextValue: "PORT-PROTOTYPE": IdentifiableSubTypes.PORT_PROTOTYPE, "PR-PORT-PROTOTYPE": IdentifiableSubTypes.PR_PORT_PROTOTYPE, "R-PORT-PROTOTYPE": IdentifiableSubTypes.R_PORT_PROTOTYPE, + "RUNNABLE-ENTITY": IdentifiableSubTypes.RUNNABLE_ENTITY, "SENDER-RECEIVER-INTERFACE": IdentifiableSubTypes.SENDER_RECEIVER_INTERFACE, "SW-ADDR-METHOD": IdentifiableSubTypes.SW_ADDR_METHOD, "SW-BASE-TYPE": IdentifiableSubTypes.SW_BASE_TYPE, @@ -911,6 +927,11 @@ class VersionedTextValue: "NO-PGWIDE": PageWide.NO_PGWIDE, "PGWIDE": PageWide.PGWIDE, }, + "ReentrancyLevel": { + "MULTICORE-REENTRANT": ReentrancyLevel.MULTICORE_REENTRANT, + "NON-REENTRANT": ReentrancyLevel.NON_REENTRANT, + "SINGLE-CORE-REENTRANT": ReentrancyLevel.SINGLE_CORE_REENTRANT + }, "ScaleConstraintValidity": { "NOT-AVAILABLE": ScaleConstraintValidity.NOT_AVAILABLE, "NOT-DEFINED": ScaleConstraintValidity.NOT_DEFINED, @@ -1077,28 +1098,31 @@ def xml_to_enum(enum_type_name: str, xml_text: str, schema_version: int = ar_bas "DATA-CONSTR", # 25 "DATA-PROTOTYPE", # 26 "E-2-E-PROFILE-COMPATIBILITY-PROPS", # 27 - "IMPLEMENTATION-DATA-TYPE", # 28 - "IMPLEMENTATION-DATA-TYPE-ELEMENT", # 29 - "MODE-DECLARATION", # 30 - "MODE-DECLARATION-GROUP", # 31 - "MODE-DECLARATION-GROUP-PROTOTYPE", # 32 - "MODE-SWITCH-INTERFACE", # 33 - "NV-DATA-INTERFACE", # 34 - "P-PORT-PROTOTYPE", # 35 - "PARAMETER-INTERFACE", # 36 - "PARAMETER-DATA-PROTOTYPE", # 37 - "PHYSICAL-DIMENSION", # 38 - "PORT-PROTOTYPE", # 39 - "PR-PORT-PROTOTYPE", # 40 - "R-PORT-PROTOTYPE", # 41 - "SENDER-RECEIVER-INTERFACE", # 42 - "SW-ADDR-METHOD", # 43 - "SW-BASE-TYPE", # 44 - "SW-COMPONENT-PROTOTYPE", # 45 - "SWC-IMPLEMENTATION", # 46 - "SWC-INTERNAL-BEHAVIOR", # 47 - "UNIT", # 48 - "VARIABLE-DATA-PROTOTYPE", # 49 + "EXCLUSIVE-AREA", # 28 + "EXCLUSIVE-AREA-NESTING-ORDER", # 29 + "IMPLEMENTATION-DATA-TYPE", # 30 + "IMPLEMENTATION-DATA-TYPE-ELEMENT", # 31 + "MODE-DECLARATION", # 32 + "MODE-DECLARATION-GROUP", # 33 + "MODE-DECLARATION-GROUP-PROTOTYPE", # 34 + "MODE-SWITCH-INTERFACE", # 35 + "NV-DATA-INTERFACE", # 36 + "P-PORT-PROTOTYPE", # 37 + "PARAMETER-INTERFACE", # 38 + "PARAMETER-DATA-PROTOTYPE", # 39 + "PHYSICAL-DIMENSION", # 40 + "PORT-PROTOTYPE", # 41 + "PR-PORT-PROTOTYPE", # 42 + "R-PORT-PROTOTYPE", # 43 + "RUNNABLE-ENTITY", # 44 + "SENDER-RECEIVER-INTERFACE", # 45 + "SW-ADDR-METHOD", # 46 + "SW-BASE-TYPE", # 47 + "SW-COMPONENT-PROTOTYPE", # 48 + "SWC-IMPLEMENTATION", # 49 + "SWC-INTERNAL-BEHAVIOR", # 50 + "UNIT", # 51 + "VARIABLE-DATA-PROTOTYPE", # 52 ], "IntervalType": [ "CLOSED", # 0 @@ -1268,6 +1292,11 @@ def xml_to_enum(enum_type_name: str, xml_text: str, schema_version: int = ar_bas "NO-PGWIDE", # 0 "PGWIDE", # 1 ], + "ReentrancyLevel": [ + "MULTICORE-REENTRANT", # 0 + "NON-REENTRANT", # 1 + "SINGLE-CORE-REENTRANT" # 2 + ], "ScaleConstraintValidity": [ "NOT-AVAILABLE", # 0 "NOT-DEFINED", # 1 diff --git a/src/autosar/xml/reader.py b/src/autosar/xml/reader.py index 0b23fcd..64b1b22 100644 --- a/src/autosar/xml/reader.py +++ b/src/autosar/xml/reader.py @@ -264,7 +264,10 @@ def __init__(self, 'AUTOSAR-VARIABLE-IREF': self._read_variable_in_atomic_swc_type_instance_ref, 'ACCESSED-VARIABLE': self._read_autosar_variable_ref, 'VARIABLE-ACCESS': self._read_variable_access, + 'EXECUTABLE-ENTITY-ACTIVATION-REASON': self._read_executable_entity_activation_reason, + 'EXCLUSIVE-AREA-REF-CONDITIONAL': self._read_exclusive_area_ref_conditional, 'SWC-INTERNAL-BEHAVIOR': self._read_swc_internal_behavior, + 'RUNNABLE-ENTITY': self._read_runnable_entity, } self.switcher_all = {} self.switcher_all.update(self.switcher_collectable) @@ -1657,8 +1660,7 @@ def _read_sw_data_def_props_content(self, child_elements: ChildElementMap, data: data['annotations'] = self._read_annotations(xml_child) xml_child = child_elements.get('SW-ADDR-METHOD-REF') if xml_child is not None: - data['sw_addr_method_ref'] = self._read_sw_addr_method_ref( - xml_child) + data['sw_addr_method_ref'] = self._read_sw_addr_method_ref(xml_child) xml_child = child_elements.get('SW-ALIGNMENT') if xml_child is not None: try: @@ -2527,7 +2529,7 @@ def _read_data_prototype_ref(self, xml_elem: ElementTree.Element ) -> ar_element.DataPrototypeRef: """ - Reads references to References to DATA-PROTOTYPE--SUBTYPES-ENUM + Reads references to DATA-PROTOTYPE--SUBTYPES-ENUM """ data = {} self._read_base_ref_attributes(xml_elem.attrib, data) @@ -2538,7 +2540,7 @@ def _read_port_interface_ref(self, xml_elem: ElementTree.Element ) -> ar_element.PortInterfaceRef: """ - Reads references to References to PORT-INTERFACE--SUBTYPES-ENUM + Reads references to PORT-INTERFACE--SUBTYPES-ENUM """ data = {} self._read_base_ref_attributes(xml_elem.attrib, data) @@ -2549,7 +2551,7 @@ def _read_sw_component_type_ref(self, xml_elem: ElementTree.Element ) -> ar_element.SwComponentTypeRef: """ - Reads references to References to SW-COMPONENT-TYPE--SUBTYPES-ENUM + Reads references to SW-COMPONENT-TYPE--SUBTYPES-ENUM """ data = {} self._read_base_ref_attributes(xml_elem.attrib, data) @@ -2560,7 +2562,7 @@ def _read_sw_component_prototype_ref(self, xml_elem: ElementTree.Element ) -> ar_element.SwComponentPrototypeRef: """ - Reads reference to references to SW-COMPONENT-PROTOTYPE--SUBTYPES-ENUM + Reads reference to SW-COMPONENT-PROTOTYPE--SUBTYPES-ENUM """ data = {} self._read_base_ref_attributes(xml_elem.attrib, data) @@ -2573,7 +2575,7 @@ def _read_swc_internal_behavior_ref(self, xml_elem: ElementTree.Element ) -> ar_element.SwcInternalBehaviorRef: """ - Reads reference to references to SWC-INTERNAL-BEHAVIOR--SUBTYPES-ENUM + Reads reference to SWC-INTERNAL-BEHAVIOR--SUBTYPES-ENUM """ data = {} self._read_base_ref_attributes(xml_elem.attrib, data) @@ -2582,6 +2584,28 @@ def _read_swc_internal_behavior_ref(self, raise ar_exception.ParseError(msg) return ar_element.SwcInternalBehaviorRef(xml_elem.text) + def _read_exclusive_area_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.ExclusiveAreaRef: + """ + Reads references to AR:EXCLUSIVE-AREA--SUBTYPES-ENUM + """ + data = {} + self._read_base_ref_attributes(xml_elem.attrib, data) + dest_enum = ar_enum.xml_to_enum('IdentifiableSubTypes', data['dest'], self.schema_version) + return ar_element.ExclusiveAreaRef(xml_elem.text, dest_enum) + + def _read_exclusive_area_nesting_order_ref(self, + xml_elem: ElementTree.Element + ) -> ar_element.ExclusiveAreaNestingOrderRef: + """ + Reads references to AR:EXCLUSIVE-AREA-NESTING-ORDER--SUBTYPES-ENUM + """ + data = {} + self._read_base_ref_attributes(xml_elem.attrib, data) + dest_enum = ar_enum.xml_to_enum('IdentifiableSubTypes', data['dest'], self.schema_version) + return ar_element.ExclusiveAreaNestingOrderRef(xml_elem.text, dest_enum) + # --- Constant and value specifications def _read_text_value_specification(self, @@ -4345,6 +4369,139 @@ def _read_autosar_variable_ref_group(self, child_elements: ChildElementMap, data if xml_child is not None: data["local_variable_ref"] = self._read_variable_data_prototype_ref(xml_child) + def _read_executable_entity_activation_reason(self, + xml_element: ElementTree.Element + ) -> ar_element.ExecutableEntityActivationReason: + """ + Reads complex type AR:EXECUTABLE-ENTITY-ACTIVATION-REASON + Tag variants: 'EXECUTABLE-ENTITY-ACTIVATION-REASON' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_implementation_props(child_elements, data) + xml_child = child_elements.get("BIT-POSITION") + if xml_child is not None: + data["bit_position"] = ar_element.PositiveIntegerValue(xml_child.text).value + self._report_unprocessed_elements(child_elements) + return ar_element.ExecutableEntityActivationReason(**data) + + def _read_exclusive_area_ref_conditional(self, + xml_element: ElementTree.Element + ) -> ar_element.ExclusiveAreaRefConditional: + """ + Reads complex type AR:EXCLUSIVE-AREA-REF-CONDITIONAL + Tag variants: 'EXCLUSIVE-AREA-REF-CONDITIONAL' + """ + data = {} + child_elements = ChildElementMap(xml_element) + xml_child = child_elements.get("EXCLUSIVE-AREA-REF") + if xml_child is not None: + data["exclusive_area_ref"] = self._read_exclusive_area_ref(xml_child) + child_elements.skip("VARIATION-POINT") # Not supported + self._report_unprocessed_elements(child_elements) + return ar_element.ExclusiveAreaRefConditional(**data) + + def _read_executable_entity(self, child_elements: ChildElementMap, data: dict) -> None: + """ + Reads group AR:EXECUTABLE-ENTITY + """ + xml_child = child_elements.get("ACTIVATION-REASONS") + if xml_child is not None: + activation_reasons = [] + for xml_grand_child in xml_child.findall("./EXECUTABLE-ENTITY-ACTIVATION-REASON"): + activation_reasons.append(self._read_executable_entity_activation_reason(xml_grand_child)) + data["activation_reasons"] = activation_reasons + if not isinstance(self.schema_version, int): + raise RuntimeError("Schema version is not set, unable to proceed") + if self.schema_version < 50: + xml_child = child_elements.get("CAN-ENTER-EXCLUSIVE-AREA-REFS") + if xml_child is not None: + can_enter_leave = [] + for xml_grand_child in xml_child.findall("./CAN-ENTER-EXCLUSIVE-AREA-REF"): + # The class constructor will automatically upgrade these references to + # ExclusiveAreaRefConditional elements. + can_enter_leave.append(self._read_exclusive_area_ref(xml_grand_child)) + data["can_enter_leave"] = can_enter_leave + else: + xml_child = child_elements.get("CAN-ENTERS") + if xml_child is not None: + can_enter_leave = [] + for xml_grand_child in xml_child.findall("./EXCLUSIVE-AREA-REF-CONDITIONAL"): + can_enter_leave.append(self._read_exclusive_area_ref_conditional(xml_grand_child)) + data["can_enter_leave"] = can_enter_leave + xml_child = child_elements.get("EXCLUSIVE-AREA-NESTING-ORDER-REFS") + if xml_child is not None: + exclusive_area_nesting_order = [] + for xml_grand_child in xml_child.findall("./EXCLUSIVE-AREA-NESTING-ORDER-REF"): + exclusive_area_nesting_order.append(self._read_exclusive_area_nesting_order_ref(xml_grand_child)) + data["exclusive_area_nesting_order"] = exclusive_area_nesting_order + xml_child = child_elements.get("MINIMUM-START-INTERVAL") + if xml_child is not None: + data["minimum_start_interval"] = self._read_number(xml_child.text) + xml_child = child_elements.get("REENTRANCY-LEVEL") + if xml_child is not None: + data["reentrancy_level"] = ar_enum.xml_to_enum("ReentrancyLevel", xml_child.text) + if self.schema_version < 50: + xml_child = child_elements.get("RUNS-INSIDE-EXCLUSIVE-AREA-REFS") + if xml_child is not None: + runs_insides = [] + for xml_grand_child in xml_child.findall("./RUNS-INSIDE-EXCLUSIVE-AREA-REF"): + # The class constructor will automatically upgrade these references to + # ExclusiveAreaRefConditional elements. + runs_insides.append(self._read_exclusive_area_ref(xml_grand_child)) + data["runs_insides"] = runs_insides + else: + xml_child = child_elements.get("RUNS-INSIDES") + if xml_child is not None: + runs_insides = [] + for xml_grand_child in xml_child.findall("./EXCLUSIVE-AREA-REF-CONDITIONAL"): + runs_insides.append(self._read_exclusive_area_ref_conditional(xml_grand_child)) + data["runs_insides"] = runs_insides + xml_child = child_elements.get('SW-ADDR-METHOD-REF') + if xml_child is not None: + data['sw_addr_method'] = self._read_sw_addr_method_ref(xml_child) + + def _read_runnable_entity(self, xml_element: ElementTree.Element) -> ar_element.RunnableEntity: + """ + Reads complex type AR:RUNNABLE-ENTITY + Tag variants: 'RUNNABLE-ENTITY' + """ + data = {} + child_elements = ChildElementMap(xml_element) + self._read_referrable(child_elements, data) + self._read_multi_language_referrable(child_elements, data) + self._read_identifiable(child_elements, xml_element.attrib, data) + self._read_executable_entity(child_elements, data) + self._read_runnable_entity_group(child_elements, data) + self._report_unprocessed_elements(child_elements) + return ar_element.RunnableEntity(**data) + + def _read_runnable_entity_group(self, child_elements: ChildElementMap, data: dict) -> None: + """ + Reads group AR:RUNNABLE-ENTITY + These elements will be implemented in the next releae + """ + child_elements.skip("ARGUMENTS") + child_elements.skip("ASYNCHRONOUS-SERVER-CALL-RESULT-POINTS") + child_elements.skip("CAN-BE-INVOKED-CONCURRENTLY") + child_elements.skip("DATA-READ-ACCESSS") + child_elements.skip("DATA-RECEIVE-POINT-BY-ARGUMENTS") + child_elements.skip("DATA-RECEIVE-POINT-BY-VALUES") + child_elements.skip("DATA-SEND-POINTS") + child_elements.skip("DATA-WRITE-ACCESSS") + child_elements.skip("EXTERNAL-TRIGGERING-POINTS") + child_elements.skip("INTERNAL-TRIGGERING-POINTS") + child_elements.skip("MODE-ACCESS-POINTS") + child_elements.skip("MODE-SWITCH-POINTS") + child_elements.skip("PARAMETER-ACCESSS") + child_elements.skip("READ-LOCAL-VARIABLES") + child_elements.skip("SERVER-CALL-POINTS") + child_elements.skip("SYMBOL") + child_elements.skip("WAIT-POINTS") + child_elements.skip("WRITTEN-LOCAL-VARIABLES") + child_elements.skip("VARIATION-POINT") + def _read_swc_internal_behavior(self, xml_element: ElementTree.Element) -> ar_element.SwcInternalBehavior: """ Reads complex type AR:SWC-INTERNAL-BEHAVIOR diff --git a/src/autosar/xml/writer.py b/src/autosar/xml/writer.py index b9294c1..948290a 100644 --- a/src/autosar/xml/writer.py +++ b/src/autosar/xml/writer.py @@ -7,6 +7,7 @@ import sys import math import decimal +import autosar.base as ar_base import autosar.xml.document as ar_document import autosar.xml.element as ar_element import autosar.xml.enumeration as ar_enum @@ -181,8 +182,11 @@ class Writer(_XMLWriter): ARXML writer class """ - def __init__(self) -> None: + def __init__(self, + schema_version: int = ar_base.DEFAULT_SCHEMA_VERSION) -> None: super().__init__(indentation_step=2) + self.schema_version = schema_version + # Elements found in AR:PACKAGE self.switcher_collectable = { # Package @@ -332,6 +336,9 @@ def __init__(self) -> None: 'AutosarVariableRef': self._write_autosar_variable_ref, 'VariableAccess': self._write_variable_access, 'SwcInternalBehavior': self._write_swc_internal_behavior, + 'ExecutableEntityActivationReason': self._write_executable_entity_activation_reason, + 'ExclusiveAreaRefConditional': self._write_exclusive_area_ref_conditional, + 'RunnableEntity': self._write_runnable_entity, } self.switcher_all = {} # All concrete elements (used for unit testing) @@ -439,6 +446,7 @@ def _write_admin_data(self, data: dict) -> None: # AUTOSAR Document def _write_document(self, document: ar_document.Document, skip_root_attr: bool = False): + self.schema_version = document.schema_version self._add_line('') if skip_root_attr: self._add_child("AUTOSAR") @@ -1971,8 +1979,7 @@ def _write_sw_base_type_ref(self, elem: ar_element.SwBaseTypeRef) -> None: def _write_sw_addr_method_ref(self, elem: ar_element.SwAddrMethodRef) -> None: """ - Writes complex type AR:SW-ADDR-METHOD-REF - Type: Concrete + Writes references to AR:SW-ADDR-METHOD--SUBTYPES-ENUM Tag variants: 'SW-ADDR-METHOD-REF' """ assert isinstance(elem, ar_element.SwAddrMethodRef) @@ -2230,6 +2237,28 @@ def _write_sw_component_prototype_ref(self, self._collect_base_ref_attr(elem, attr) self._add_content(tag, elem.value, attr) + def _write_exclusive_area_ref(self, + elem: ar_element.ExclusiveAreaRef, + tag: str) -> None: + """ + Writes references to EXCLUSIVE-AREA--SUBTYPES-ENUM + """ + assert isinstance(elem, ar_element.ExclusiveAreaRef) + attr: TupleList = [] + self._collect_base_ref_attr(elem, attr) + self._add_content(tag, elem.value, attr) + + def _write_exclusive_area_nesting_order_ref(self, + elem: ar_element.ExclusiveAreaNestingOrderRef, + tag: str) -> None: + """ + Writes references to EXCLUSIVE-AREA-NESTING-ORDER--SUBTYPES-ENUM + """ + assert isinstance(elem, ar_element.ExclusiveAreaNestingOrderRef) + attr: TupleList = [] + self._collect_base_ref_attr(elem, attr) + self._add_content(tag, elem.value, attr) + def _write_swc_internal_behavior_ref(self, elem: ar_element.SwcInternalBehaviorRef, tag: str) -> None: @@ -3717,6 +3746,7 @@ def _write_variable_access(self, elem: ar_element.VariableAccess, tag: str) -> N Writes complex type AR:VARIABLE-ACCESS Tag variants: 'REPLACE-WITH' | 'VARIABLE-ACCESS' """ + assert isinstance(elem, ar_element.VariableAccess) self._add_child(tag) self._write_referrable(elem) self._write_multilanguage_referrable(elem) @@ -3727,6 +3757,107 @@ def _write_variable_access(self, elem: ar_element.VariableAccess, tag: str) -> N self._add_content("SCOPE", ar_enum.enum_to_xml(elem.scope)) self._leave_child() + def _write_executable_entity_activation_reason(self, + elem: ar_element.ExecutableEntityActivationReason) -> None: + """ + Writes complex type AR:EXECUTABLE-ENTITY-ACTIVATION-REASON + Tag variants: 'EXECUTABLE-ENTITY-ACTIVATION-REASON' + """ + assert isinstance(elem, ar_element.ExecutableEntityActivationReason) + self._add_child("EXECUTABLE-ENTITY-ACTIVATION-REASON") + self._write_referrable(elem) + self._write_implementation_props(elem) + if elem.bit_position is not None: + self._add_content("BIT-POSITION", str(elem.bit_position)) + self._leave_child() + + def _write_exclusive_area_ref_conditional(self, + elem: ar_element.ExclusiveAreaRefConditional) -> None: + """ + Writes complex type AR:EXCLUSIVE-AREA-REF-CONDITIONAL + Tag variants: 'EXCLUSIVE-AREA-REF-CONDITIONAL' + """ + assert isinstance(elem, ar_element.ExclusiveAreaRefConditional) + tag = "EXCLUSIVE-AREA-REF-CONDITIONAL" + if elem.is_empty: + self._add_content(tag) + else: + self._add_child(tag) + if elem.exclusive_area_ref is not None: + self._write_exclusive_area_ref(elem.exclusive_area_ref, "EXCLUSIVE-AREA-REF") + self._leave_child() + + def _write_executable_entity(self, elem: ar_element.ExecutableEntity) -> None: + """ + Writes group AR:EXECUTABLE-ENTITY + """ + if elem.activation_reasons: + self._add_child("ACTIVATION-REASONS") + for activation_reason in elem.activation_reasons: + self._write_executable_entity_activation_reason(activation_reason) + self._leave_child() + if elem.can_enter_leave: + if not isinstance(self.schema_version, int): + raise RuntimeError("Schema version is not set, unable to proceed") + if self.schema_version < 50: + self._add_child("CAN-ENTER-EXCLUSIVE-AREA-REFS") + for child_elem in elem.can_enter_leave: + self._write_exclusive_area_ref(child_elem.exclusive_area_ref, + "CAN-ENTER-EXCLUSIVE-AREA-REF") + self._leave_child() + else: + self._add_child("CAN-ENTERS") + for child_elem in elem.can_enter_leave: + self._write_exclusive_area_ref_conditional(child_elem) + self._leave_child() + if elem.exclusive_area_nesting_order: + self._add_child("EXCLUSIVE-AREA-NESTING-ORDER-REFS") + for nesting_order_ref in elem.exclusive_area_nesting_order: + self._write_exclusive_area_nesting_order_ref(nesting_order_ref, + "EXCLUSIVE-AREA-NESTING-ORDER-REF") + self._leave_child() + if elem.minimum_start_interval is not None: + self._add_content("MINIMUM-START-INTERVAL", self._format_number(elem.minimum_start_interval)) + if elem.reentrancy_level is not None: + self._add_content("REENTRANCY-LEVEL", ar_enum.enum_to_xml(elem.reentrancy_level)) + if elem.runs_insides: + if not isinstance(self.schema_version, int): + raise RuntimeError("Schema version is not set, unable to proceed") + if self.schema_version < 50: + self._add_child("RUNS-INSIDE-EXCLUSIVE-AREA-REFS") + for child_elem in elem.runs_insides: + self._write_exclusive_area_ref(child_elem.exclusive_area_ref, + "RUNS-INSIDE-EXCLUSIVE-AREA-REF") + self._leave_child() + else: + self._add_child("RUNS-INSIDES") + for child_elem in elem.runs_insides: + self._write_exclusive_area_ref_conditional(child_elem) + self._leave_child() + if elem.sw_addr_method is not None: + self._write_sw_addr_method_ref(elem.sw_addr_method) + + def _write_runnable_entity(self, elem: ar_element.RunnableEntity) -> None: + """ + Writes complex type AR:RUNNABLE-ENTITY + Tag variants: 'RUNNABLE-ENTITY' + + This is in early stage, most will be implemented later + """ + self._add_child("RUNNABLE-ENTITY") + self._write_referrable(elem) + self._write_multilanguage_referrable(elem) + self._write_identifiable(elem) + self._write_executable_entity(elem) + self._leave_child() + + def _write_runnable_entity_group(self, elem: ar_element.RunnableEntity) -> None: + """ + Writes group type AR:RUNNABLE-ENTITY + + This is just a placeholder. Will be implemented later + """ + def _write_swc_internal_behavior(self, elem: ar_element.SwcInternalBehavior) -> None: """ Writes complex type AR:SWC-INTERNAL-BEHAVIOR diff --git a/tests/xml/test_swc_internal_behavior.py b/tests/xml/test_swc_internal_behavior.py index b494b84..b630936 100644 --- a/tests/xml/test_swc_internal_behavior.py +++ b/tests/xml/test_swc_internal_behavior.py @@ -226,5 +226,490 @@ def test_local_variable_ref(self): self.assertIsInstance(elem.local_variable_ref, ar_element.VariableDataPrototypeRef) +class TestExecutableEntityActivationReason(unittest.TestCase): + + def test_read_write_name_only(self): + writer = autosar.xml.Writer() + element = ar_element.ExecutableEntityActivationReason('MyName') + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.ExecutableEntityActivationReason = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ExecutableEntityActivationReason) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + def test_read_write_bit_position(self): + writer = autosar.xml.Writer() + element = ar_element.ExecutableEntityActivationReason('MyName', bit_position=0) + xml = ''' + MyName + 0 +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.ExecutableEntityActivationReason = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ExecutableEntityActivationReason) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.bit_position, 0) + + +class TestExclusiveAreaRefConditional(unittest.TestCase): + + def test_empty(self): + element = ar_element.ExclusiveAreaRefConditional() + writer = autosar.xml.Writer() + xml = writer.write_str_elem(element) + self.assertEqual(xml, '') + reader = autosar.xml.Reader() + elem: ar_element.ExclusiveAreaRefConditional = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ExclusiveAreaRefConditional) + + def test_exclusive_area_ref_from_str(self): + ref_str = "/ExclusiveAreas/AreaName" + element = ar_element.ExclusiveAreaRefConditional(ref_str) + writer = autosar.xml.Writer() + xml = f''' + {ref_str} +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.ExclusiveAreaRefConditional = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(elem.exclusive_area_ref), ref_str) + + +class TestExecutableEntity(unittest.TestCase): + """ + ExecutableEntity is a base class. Use RunnableEntity + for unit testing. + """ + + def test_name_only(self): + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName') + xml = ''' + MyName +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(elem.name, 'MyName') + self.assertEqual(elem.short_name, 'MyName') + + def test_activation_reasons_from_element(self): + writer = autosar.xml.Writer() + reason = ar_element.ExecutableEntityActivationReason("MyReason", 1, symbol="MySymbol") + element = ar_element.RunnableEntity('MyName', activation_reasons=reason) + xml = ''' + MyName + + + MyReason + MySymbol + 1 + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.activation_reasons), 1) + activation_reason = elem.activation_reasons[0] + self.assertIsInstance(activation_reason, ar_element.ExecutableEntityActivationReason) + self.assertEqual(activation_reason.name, 'MyReason') + + def test_activation_reasons_from_list(self): + writer = autosar.xml.Writer() + reasons = [ar_element.ExecutableEntityActivationReason("MyReason1", 0, symbol="MySymbol1"), + ar_element.ExecutableEntityActivationReason("MyReason2", 1, symbol="MySymbol2")] + element = ar_element.RunnableEntity('MyName', activation_reasons=reasons) + xml = ''' + MyName + + + MyReason1 + MySymbol1 + 0 + + + MyReason2 + MySymbol2 + 1 + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.activation_reasons), 2) + activation_reason = elem.activation_reasons[0] + self.assertIsInstance(activation_reason, ar_element.ExecutableEntityActivationReason) + self.assertEqual(activation_reason.name, 'MyReason1') + activation_reason = elem.activation_reasons[1] + self.assertIsInstance(activation_reason, ar_element.ExecutableEntityActivationReason) + self.assertEqual(activation_reason.name, 'MyReason2') + + def test_can_enters_from_element(self): + """ + CAN-ENTERS is used for XML schema version >= 50 + """ + ref_str = "/MyPackage/MySwc/MyExclusiveArea" + writer = autosar.xml.Writer() + exclusive_area_cond = ar_element.ExclusiveAreaRefConditional(ref_str) + element = ar_element.RunnableEntity('MyName', can_enter_leave=exclusive_area_cond) + xml = f''' + MyName + + + {ref_str} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.can_enter_leave), 1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str) + + def test_can_enters_from_list(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveArea1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveArea2" + writer = autosar.xml.Writer() + exclusive_area_cond = [ar_element.ExclusiveAreaRefConditional(ref_str1), + ar_element.ExclusiveAreaRefConditional(ref_str2)] + element = ar_element.RunnableEntity('MyName', can_enter_leave=exclusive_area_cond) + xml = f''' + MyName + + + {ref_str1} + + + {ref_str2} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.can_enter_leave), 2) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[1] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str2) + + def test_can_enter_exclusive_area_from_element(self): + """ + CAN-ENTER-EXCLUSIVE-AREA-REFS is used for XML schema version < 50 + """ + ref_str = "/MyPackage/MySwc/MyExclusiveArea" + writer = autosar.xml.Writer(schema_version=49) + exclusive_area_cond = ar_element.ExclusiveAreaRefConditional(ref_str) + element = ar_element.RunnableEntity('MyName', can_enter_leave=exclusive_area_cond) + xml = f''' + MyName + + {ref_str} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader(schema_version=49) + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.can_enter_leave), 1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str) + + def test_can_enter_exclusive_area_from_list(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveArea1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveArea2" + writer = autosar.xml.Writer(schema_version=49) + exclusive_area_cond = [ar_element.ExclusiveAreaRefConditional(ref_str1), + ar_element.ExclusiveAreaRefConditional(ref_str2)] + element = ar_element.RunnableEntity('MyName', can_enter_leave=exclusive_area_cond) + xml = f''' + MyName + + {ref_str1} + {ref_str2} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader(schema_version=49) + # During XML reading, elements of type ExclusiveAreaRef are automatically wrapped + # inside the newer ExclusiveAreaRefConditional element + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.can_enter_leave), 2) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.can_enter_leave[1] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str2) + + def test_can_enter_create_directly_from_reference_string(self): + ref_str = "/MyPackage/MySwc/MyExclusiveArea" + writer = autosar.xml.Writer() + exclusive_area_cond = ar_element.ExclusiveAreaRefConditional(ref_str) + element = ar_element.RunnableEntity('MyName', can_enter_leave=exclusive_area_cond) + xml = f''' + MyName + + + {ref_str} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + + def test_can_enter_create_from_list_of_reference_strings(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveArea1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveArea2" + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName', can_enter_leave=[ref_str1, ref_str2]) + xml = f''' + MyName + + + {ref_str1} + + + {ref_str2} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + + def test_exclusive_area_nesting_order_refs_from_element(self): + ref_str = "/MyPackage/MySwc/MyExclusiveAreaNestingOrder" + writer = autosar.xml.Writer() + exclusive_area_nesting_order = ar_element.ExclusiveAreaNestingOrderRef(ref_str) + element = ar_element.RunnableEntity('MyName', exclusive_area_nesting_order=exclusive_area_nesting_order) + xml = f''' + MyName + + {ref_str} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.exclusive_area_nesting_order), 1) + nesting_order: ar_element.ExclusiveAreaNestingOrderRef = elem.exclusive_area_nesting_order[0] + self.assertIsInstance(nesting_order, ar_element.ExclusiveAreaNestingOrderRef) + self.assertEqual(str(nesting_order), ref_str) + + def test_exclusive_area_nesting_order_refs_from_list(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveAreaNestingOrder1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveAreaNestingOrder1" + writer = autosar.xml.Writer() + exclusive_area_nesting_order = [ar_element.ExclusiveAreaNestingOrderRef(ref_str1), + ar_element.ExclusiveAreaNestingOrderRef(ref_str1)] + element = ar_element.RunnableEntity('MyName', exclusive_area_nesting_order=exclusive_area_nesting_order) + xml = f''' + MyName + + {ref_str1} + {ref_str2} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.exclusive_area_nesting_order), 2) + nesting_order: ar_element.ExclusiveAreaNestingOrderRef = elem.exclusive_area_nesting_order[0] + self.assertIsInstance(nesting_order, ar_element.ExclusiveAreaNestingOrderRef) + self.assertEqual(str(nesting_order), ref_str1) + nesting_order = elem.exclusive_area_nesting_order[1] + self.assertIsInstance(nesting_order, ar_element.ExclusiveAreaNestingOrderRef) + self.assertEqual(str(nesting_order), ref_str2) + + def test_minimum_start_interval_100ms(self): + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName', minimum_start_interval=0.1) + xml = ''' + MyName + 0.1 +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertAlmostEqual(elem.minimum_start_interval, 0.1) + + def test_minimum_start_interval_2s(self): + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName', minimum_start_interval=2) + xml = ''' + MyName + 2 +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(elem.minimum_start_interval, 2) + + def test_reentrancy_level(self): + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName', + reentrancy_level=ar_enum.ReentrancyLevel.SINGLE_CORE_REENTRANT) + xml = ''' + MyName + SINGLE-CORE-REENTRANT +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(elem.reentrancy_level, ar_enum.ReentrancyLevel.SINGLE_CORE_REENTRANT) + + def test_runs_insides_from_element(self): + """ + RUNS-INSIDES is used for XML schema version >= 50 + """ + ref_str = "/MyPackage/MySwc/MyExclusiveArea" + writer = autosar.xml.Writer() + exclusive_area_cond = ar_element.ExclusiveAreaRefConditional(ref_str) + element = ar_element.RunnableEntity('MyName', runs_insides=exclusive_area_cond) + xml = f''' + MyName + + + {ref_str} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.runs_insides), 1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str) + + def test_runs_insides_from_list(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveArea1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveArea2" + writer = autosar.xml.Writer() + exclusive_area_cond = [ar_element.ExclusiveAreaRefConditional(ref_str1), + ar_element.ExclusiveAreaRefConditional(ref_str2)] + element = ar_element.RunnableEntity('MyName', runs_insides=exclusive_area_cond) + xml = f''' + MyName + + + {ref_str1} + + + {ref_str2} + + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.runs_insides), 2) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[1] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str2) + + def test_runs_inside_exclusive_area_from_element(self): + """ + RUNS-INSIDE-EXCLUSIVE-AREA-REFS is used for XML schema version < 50 + """ + ref_str = "/MyPackage/MySwc/MyExclusiveArea" + writer = autosar.xml.Writer(schema_version=49) + exclusive_area_cond = ar_element.ExclusiveAreaRefConditional(ref_str) + element = ar_element.RunnableEntity('MyName', runs_insides=exclusive_area_cond) + xml = f''' + MyName + + {ref_str} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader(schema_version=49) + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.runs_insides), 1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str) + + def test_run_insides_exclusive_area_from_list(self): + ref_str1 = "/MyPackage/MySwc/MyExclusiveArea1" + ref_str2 = "/MyPackage/MySwc/MyExclusiveArea2" + writer = autosar.xml.Writer(schema_version=49) + exclusive_area_cond = [ar_element.ExclusiveAreaRefConditional(ref_str1), + ar_element.ExclusiveAreaRefConditional(ref_str2)] + element = ar_element.RunnableEntity('MyName', runs_insides=exclusive_area_cond) + xml = f''' + MyName + + {ref_str1} + {ref_str2} + +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader(schema_version=49) + # During XML reading, elements of type ExclusiveAreaRef are automatically wrapped + # inside the newer ExclusiveAreaRefConditional element + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + self.assertEqual(len(elem.runs_insides), 2) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[0] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str1) + conditional: ar_element.ExclusiveAreaRefConditional = elem.runs_insides[1] + self.assertIsInstance(conditional, ar_element.ExclusiveAreaRefConditional) + self.assertEqual(str(conditional.exclusive_area_ref), ref_str2) + + def test_sw_addr_method_from_element(self): + ref_str = '/SwAddrMethods/DEFAULT' + writer = autosar.xml.Writer() + element = ar_element.RunnableEntity('MyName', + sw_addr_method=ar_element.SwAddrMethodRef(ref_str)) + xml = f''' + MyName + {ref_str} +''' + self.assertEqual(writer.write_str_elem(element), xml) + reader = autosar.xml.Reader() + elem: ar_element.RunnableEntity = reader.read_str_elem(xml) + self.assertIsInstance(elem, ar_element.RunnableEntity) + ref = elem.sw_addr_method + self.assertEqual(ref.value, '/SwAddrMethods/DEFAULT') + self.assertEqual(ref.dest, ar_enum.IdentifiableSubTypes.SW_ADDR_METHOD) + + def test_create_sw_addr_method_from_string(self): + ref_str = '/SwAddrMethods/DEFAULT' + element = ar_element.RunnableEntity('MyName', sw_addr_method=ref_str) + ref = element.sw_addr_method + self.assertEqual(ref.value, '/SwAddrMethods/DEFAULT') + self.assertEqual(ref.dest, ar_enum.IdentifiableSubTypes.SW_ADDR_METHOD) + + if __name__ == '__main__': unittest.main()