def test_opaque_not_byte_aligned_dynamic() -> None: with pytest.raises( RecordFluxError, match= r'^<stdin>:44:3: model: error: opaque field "O2" not aligned to' r" 8 bit boundary [(]L1 -> O1 -> L2 -> O2[)]", ): o2 = Field(ID("O2", location=Location((44, 3)))) Message( "P.M", [ Link(INITIAL, Field("L1")), Link( Field("L1"), Field("O1"), length=Variable("L1"), condition=Equal(Mod(Variable("L1"), Number(8)), Number(0)), ), Link(Field("O1"), Field("L2")), Link(Field("L2"), o2, length=Number(128)), Link(o2, FINAL), ], { Field("L1"): MODULAR_INTEGER, Field("L2"): ModularInteger("P.T", Number(4)), Field("O1"): Opaque(), o2: Opaque(), }, )
def test_prefixed_message() -> None: assert_equal( UnprovenMessage( "P.M", [ Link(INITIAL, Field("F1")), Link( Field("F1"), Field("F2"), LessEqual(Variable("F1"), Number(100)), first=First("F1"), ), Link( Field("F1"), Field("F3"), GreaterEqual(Variable("F1"), Number(200)), first=First("F1"), ), Link(Field("F2"), FINAL), Link(Field("F3"), Field("F4"), length=Variable("F3")), Link(Field("F4"), FINAL), ], { Field("F1"): deepcopy(MODULAR_INTEGER), Field("F2"): deepcopy(MODULAR_INTEGER), Field("F3"): deepcopy(RANGE_INTEGER), Field("F4"): Opaque(), }, ).prefixed("X_"), UnprovenMessage( "P.M", [ Link(INITIAL, Field("X_F1")), Link( Field("X_F1"), Field("X_F2"), LessEqual(Variable("X_F1"), Number(100)), first=First("X_F1"), ), Link( Field("X_F1"), Field("X_F3"), GreaterEqual(Variable("X_F1"), Number(200)), first=First("X_F1"), ), Link(Field("X_F2"), FINAL), Link(Field("X_F3"), Field("X_F4"), length=Variable("X_F3")), Link(Field("X_F4"), FINAL), ], { Field("X_F1"): deepcopy(MODULAR_INTEGER), Field("X_F2"): deepcopy(MODULAR_INTEGER), Field("X_F3"): deepcopy(RANGE_INTEGER), Field("X_F4"): Opaque(), }, ), )
def test_merge_message_recursive() -> None: assert_equal( deepcopy(M_DBL_REF).merged(), UnprovenMessage( "P.Dbl_Ref", [ Link(INITIAL, Field("SR_NR_F1"), length=Number(16)), Link( Field("SR_NR_F3"), Field("NR_F1"), Equal(Variable("SR_NR_F3"), Variable("P.ONE")), length=Number(16), ), Link(Field("SR_NR_F4"), Field("NR_F1"), length=Number(16)), Link(Field("NR_F3"), FINAL, Equal(Variable("NR_F3"), Variable("P.ONE"))), Link(Field("NR_F4"), FINAL), Link(Field("SR_NR_F1"), Field("SR_NR_F2")), Link( Field("SR_NR_F2"), Field("SR_NR_F3"), LessEqual(Variable("SR_NR_F2"), Number(100)), first=First("SR_NR_F2"), ), Link( Field("SR_NR_F2"), Field("SR_NR_F4"), GreaterEqual(Variable("SR_NR_F2"), Number(200)), first=First("SR_NR_F2"), ), Link(Field("NR_F1"), Field("NR_F2")), Link( Field("NR_F2"), Field("NR_F3"), LessEqual(Variable("NR_F2"), Number(100)), first=First("NR_F2"), ), Link( Field("NR_F2"), Field("NR_F4"), GreaterEqual(Variable("NR_F2"), Number(200)), first=First("NR_F2"), ), ], { Field("SR_NR_F1"): Opaque(), Field("SR_NR_F2"): deepcopy(MODULAR_INTEGER), Field("SR_NR_F3"): deepcopy(ENUMERATION), Field("SR_NR_F4"): deepcopy(RANGE_INTEGER), Field("NR_F1"): Opaque(), Field("NR_F2"): deepcopy(MODULAR_INTEGER), Field("NR_F3"): deepcopy(ENUMERATION), Field("NR_F4"): deepcopy(RANGE_INTEGER), }, ), )
def test_value_clear() -> None: ov = OpaqueValue(Opaque()) assert not ov.initialized ov.assign(b"") assert ov.initialized ov.clear() assert not ov.initialized
def test_type_derivation_refinements() -> None: message_foo = Message( "Test.Foo", [Link(INITIAL, Field("Baz"), length=Number(48)), Link(Field("Baz"), FINAL)], {Field("Baz"): Opaque()}, ) message_bar = DerivedMessage("Test.Bar", message_foo) assert_refinements_string( """ package Test is type Foo is message null then Baz with Length => 48; Baz : Opaque; end message; for Foo use (Baz => Foo); type Bar is new Foo; for Bar use (Baz => Bar); end Test; """, [ Refinement("Test", message_foo, Field("Baz"), message_foo), Refinement("Test", message_bar, Field("Baz"), message_bar), ], )
def __init__(self, model: Message, refinements: Sequence[Refinement] = None) -> None: super().__init__(model) self._refinements = refinements or [] self._fields: Dict[str, MessageValue.Field] = { f.name: self.Field( TypeValue.construct( self._type.types[f], imported=self._type.types[f].package != model.package)) for f in self._type.fields } self.__type_literals: Mapping[Name, Expr] = {} self._last_field: str = self._next_field(INITIAL.name) for t in [ f.typeval.literals for f in self._fields.values() if isinstance(f.typeval, EnumValue) ]: self.__type_literals = {**self.__type_literals, **t} initial = self.Field(OpaqueValue(Opaque())) initial.first = Number(0) initial.typeval.assign(bytes()) self._fields[INITIAL.name] = initial self._simplified_mapping: Mapping[Name, Expr] = {} self._preset_fields(INITIAL.name) self.accessible_fields: List[str] self._update_accessible_fields()
def test_exclusive_with_length_invalid() -> None: f1 = Field(ID("F1", Location((98, 10)))) structure = [ Link(INITIAL, f1, length=Number(32)), Link(f1, FINAL, condition=Equal(Length("F1"), Number(32), Location((10, 2)))), Link(f1, Field("F2"), condition=Equal(Length("F1"), Number(32), Location((12, 4)))), Link(Field("F2"), FINAL), ] types = { Field("F1"): Opaque(), Field("F2"): RANGE_INTEGER, } assert_message_model_error( structure, types, r"^" r'<stdin>:98:10: model: error: conflicting conditions for field "F1"\n' r"<stdin>:10:2: model: info: condition 0 [(]F1 -> Final[)]: F1\'Length = 32\n" r"<stdin>:12:4: model: info: condition 1 [(]F1 -> F2[)]: F1\'Length = 32" r"$", )
def test_merge_message_simple_derived() -> None: assert_equal( deepcopy(M_SMPL_REF_DERI).merged(), UnprovenDerivedMessage( "P.Smpl_Ref_Deri", M_SMPL_REF, [ Link(INITIAL, Field("NR_F1"), length=Number(16)), Link(Field("NR_F3"), FINAL, Equal(Variable("NR_F3"), Variable("P.ONE"))), Link(Field("NR_F4"), FINAL), Link(Field("NR_F1"), Field("NR_F2")), Link( Field("NR_F2"), Field("NR_F3"), LessEqual(Variable("NR_F2"), Number(100)), first=First("NR_F2"), ), Link( Field("NR_F2"), Field("NR_F4"), GreaterEqual(Variable("NR_F2"), Number(200)), first=First("NR_F2"), ), ], { Field("NR_F1"): Opaque(), Field("NR_F2"): deepcopy(MODULAR_INTEGER), Field("NR_F3"): deepcopy(ENUMERATION), Field("NR_F4"): deepcopy(RANGE_INTEGER), }, ), )
def test_field_set() -> None: f = MessageValue.Field(OpaqueValue(Opaque())) assert not f.set f.typeval.parse(b"\x01") assert not f.set f.first = Number(1) assert f.set
def test_valid_use_message_length() -> None: structure = [ Link(INITIAL, Field("Verify_Data"), length=Length("Message")), Link(Field("Verify_Data"), FINAL), ] types = {Field("Verify_Data"): Opaque()} Message("P.M", structure, types)
def test_message_in_message() -> None: length = ModularInteger("Message_In_Message.Length", Pow(Number(2), Number(16))) length_value = Message( "Message_In_Message.Length_Value", [ Link(INITIAL, Field("Length")), Link(Field("Length"), Field("Value"), length=Mul(Number(8), Variable("Length"))), Link(Field("Value"), FINAL), ], {Field("Length"): length, Field("Value"): Opaque()}, ) derived_length_value = DerivedMessage("Message_In_Message.Derived_Length_Value", length_value) message = Message( "Message_In_Message.Message", [ Link(INITIAL, Field("Foo_Length")), Link(Field("Foo_Value"), Field("Bar_Length")), Link(Field("Bar_Value"), FINAL), Link( Field("Foo_Length"), Field("Foo_Value"), length=Mul(Variable("Foo_Length"), Number(8)), ), Link( Field("Bar_Length"), Field("Bar_Value"), length=Mul(Variable("Bar_Length"), Number(8)), ), ], { Field("Foo_Length"): length, Field("Foo_Value"): Opaque(), Field("Bar_Length"): length, Field("Bar_Value"): Opaque(), }, ) derived_message = DerivedMessage("Message_In_Message.Derived_Message", message) assert_messages_files( [f"{TESTDIR}/message_in_message.rflx"], [length_value, derived_length_value, message, derived_message], )
def test_valid_length_reference() -> None: structure = [ Link(INITIAL, Field("F1")), Link(Field("F1"), Field("F2"), length=Mul(Number(8), Variable("F1"))), Link(Field("F2"), FINAL), ] types = { Field("F1"): MODULAR_INTEGER, Field("F2"): Opaque(), } Message("P.M", structure, types)
def test_opaque_valid_byte_aligned_dynamic_cond() -> None: Message( "P.M", [ Link(INITIAL, Field("L")), Link( Field("L"), Field("O1"), length=Variable("L"), condition=Equal(Mod(Variable("L"), Number(8)), Number(0)), ), Link(Field("O1"), Field("O2"), length=Number(128)), Link(Field("O2"), FINAL), ], { Field("L"): MODULAR_INTEGER, Field("O1"): Opaque(), Field("O2"): Opaque() }, )
def test_valid_use_message_first_last() -> None: structure = [ Link( INITIAL, Field("Verify_Data"), length=Add(Sub(Last("Message"), First("Message")), Number(1)), ), Link(Field("Verify_Data"), FINAL), ] types = {Field("Verify_Data"): Opaque()} Message("P.M", structure, types)
def test_invalid_length_forward_reference() -> None: structure = [ Link(INITIAL, Field("F1")), Link(Field("F1"), Field("F2"), length=Variable("F2")), Link(Field("F2"), FINAL), ] types = { Field("F1"): MODULAR_INTEGER, Field("F2"): Opaque(), } assert_message_model_error( structure, types, '^model: error: subsequent field "F2" referenced$')
def test_payload_no_length() -> None: structure = [ Link(INITIAL, Field("F1")), Link(Field("F1"), Field("F2")), Link(Field("F2"), FINAL), ] types = { Field("F1"): MODULAR_INTEGER, Field("F2"): Opaque(), } assert_message_model_error( structure, types, r'^model: error: unconstrained field "F2" without length expression$')
def test_opaque_length_not_multiple_of_8() -> None: with pytest.raises( RecordFluxError, match=r'^<stdin>:44:3: model: error: length of opaque field "O"' " not multiple of 8 bit [(]O[)]", ): o = Field(ID("O", location=Location((44, 3)))) Message( "P.M", [Link(INITIAL, o, length=Number(68)), Link(o, FINAL)], {o: Opaque()}, )
def test_opaque_valid_byte_aligned_dynamic_mul() -> None: Message( "P.M", [ Link(INITIAL, Field("L")), Link(Field("L"), Field("O1"), length=Mul(Number(8), Variable("L"))), Link(Field("O1"), FINAL), ], { Field("L"): MODULAR_INTEGER, Field("O1"): Opaque() }, )
def test_invalid_negative_field_length_modular() -> None: structure = [ Link(INITIAL, Field("F1")), Link(Field("F1"), Field("F2"), length=Sub(Variable("F1"), Number(2))), Link(Field("F2"), FINAL), ] types = { Field("F1"): MODULAR_INTEGER, Field("F2"): Opaque(), } assert_message_model_error( structure, types, r'^model: error: negative length for field "F2" [(]F1 -> F2[)]$', )
def test_value_opaque() -> None: # pylint: disable=pointless-statement # pylint: disable=protected-access opaquevalue = OpaqueValue(Opaque()) assert not opaquevalue.initialized with pytest.raises(NotInitializedError, match="value not initialized"): opaquevalue.value opaquevalue.assign(b"\x01\x02") assert opaquevalue.initialized assert opaquevalue.value == b"\x01\x02" k = opaquevalue.size assert isinstance(k, Number) assert k.value == 16 assert str(opaquevalue.bitstring) == "0000000100000010" opaquevalue.parse(Bitstring("1111")) assert opaquevalue._value == b"\x0f"
def test_opaque_equal_scalar() -> None: structure = [ Link(INITIAL, Field("Length")), Link(Field("Length"), Field("Data"), length=Variable("Length")), Link(Field("Data"), FINAL, condition=Equal(Variable("Data"), Number(42))), ] types = {Field("Length"): RANGE_INTEGER, Field("Data"): Opaque()} assert_message_model_error( structure, types, r"^" r'model: error: invalid relation " = " between Opaque and Number' r"$", )
def test_message_invalid_relation_to_aggregate() -> None: structure = [ Link(INITIAL, Field("F1"), length=Number(16)), Link( Field("F1"), FINAL, LessEqual(Variable("F1"), Aggregate(Number(1), Number(2)), Location((100, 20))), ), ] types = {Field("F1"): Opaque()} assert_message_model_error( structure, types, r'^<stdin>:100:20: model: error: invalid relation " <= " between Opaque and Aggregate$', )
def test_invalid_negative_field_length_range_integer() -> None: o = Field(ID("O", location=Location((44, 3)))) structure = [ Link(INITIAL, Field("L")), Link( Field("L"), o, length=Mul(Number(8), Sub(Variable("L"), Number(50))), ), Link(o, FINAL), ] types = {Field("L"): RANGE_INTEGER, o: Opaque()} assert_message_model_error( structure, types, r'^<stdin>:44:3: model: error: negative length for field "O" [(]L -> O[)]$', )
def test_aggregate_inequal_valid_length() -> None: structure = [ Link(INITIAL, Field("Magic"), length=Number(40)), Link( Field("Magic"), FINAL, condition=NotEqual( Variable("Magic"), Aggregate(Number(1), Number(2), Number(3), Number(4), Number(4)), ), ), ] types = { Field("Magic"): Opaque(), } Message("P.M", structure, types)
def test_opaque_length_valid_multiple_of_8_dynamic_cond() -> None: Message( "P.M", [ Link(INITIAL, Field("L")), Link( Field("L"), Field("O"), length=Variable("L"), condition=Equal(Mod(Variable("L"), Number(8)), Number(0)), ), Link(Field("O"), FINAL), ], { Field("L"): MODULAR_INTEGER, Field("O"): Opaque() }, )
def test_tlv_valid_enum() -> None: structure = [ Link(INITIAL, Field("L")), Link(Field("L"), Field("T")), Link( Field("T"), Field("V"), length=Mul(Number(8), Variable("L")), condition=And(NotEqual(Variable("T"), Variable("TWO")), LessEqual(Variable("L"), Number(8192))), ), Link(Field("V"), FINAL), ] types = { Field("L"): RANGE_INTEGER, Field("T"): ENUMERATION, Field("V"): Opaque(), } Message("P.M", structure, types)
def test_opaque_not_byte_aligned() -> None: with pytest.raises( RecordFluxError, match=r'^<stdin>:44:3: model: error: opaque field "O" not aligned to' r" 8 bit boundary [(]P -> O[)]", ): o = Field(ID("O", location=Location((44, 3)))) Message( "P.M", [ Link(INITIAL, Field("P")), Link(Field("P"), o, length=Number(128)), Link(o, FINAL) ], { Field("P"): ModularInteger("P.T", Number(4)), o: Opaque() }, )
def test_opaque_length_not_multiple_of_8_dynamic() -> None: with pytest.raises( RecordFluxError, match= r'^<stdin>:44:3: model: error: length of opaque field "O" not multiple of 8 bit' " [(]L -> O[)]", ): o = Field(ID("O", location=Location((44, 3)))) Message( "P.M", [ Link(INITIAL, Field("L")), Link(Field("L"), o, length=Variable("L")), Link(o, FINAL) ], { Field("L"): MODULAR_INTEGER, o: Opaque() }, )
def test_exclusive_with_length_valid() -> None: structure = [ Link(INITIAL, Field("F1"), length=Number(32)), Link( Field("F1"), FINAL, condition=And(Equal(Length("F1"), Number(32)), Less(Variable("F1"), Number(50))), ), Link( Field("F1"), Field("F2"), condition=And(Equal(Length("F1"), Number(32)), Greater(Variable("F1"), Number(80))), ), Link(Field("F2"), FINAL), ] types = { Field("F1"): Opaque(), Field("F2"): MODULAR_INTEGER, } Message("P.M", structure, types)
def test_aggregate_equal_invalid_length_field() -> None: length = Field(ID("Length", Location((2, 5)))) magic = Field(ID("Magic", Location((3, 5)))) structure = [ Link(INITIAL, length), Link(length, magic, length=Mul(Number(8), Variable("Length"), location=Location((6, 5)))), Link( magic, FINAL, condition=Equal(Variable("Magic"), Aggregate(Number(1), Number(2)), location=Location((10, 5))), ), ] types = { Field("Length"): RangeInteger("P.Length_Type", Number(10), Number(100), Number(8), Location((5, 10))), Field(ID("Magic", Location((17, 3)))): Opaque(), } assert_message_model_error( structure, types, r"^" r'<stdin>:10:5: model: error: contradicting condition in "P.M"\n' r'<stdin>:2:5: model: info: on path: "Length"\n' r'<stdin>:3:5: model: info: on path: "Magic"\n' r'<stdin>:6:5: model: info: unsatisfied "Magic\'Length = 8 [*] Length"\n' r'<stdin>:10:5: model: info: unsatisfied "2 [*] 8 = Magic\'Length"\n' r'<stdin>:5:10: model: info: unsatisfied "Length >= 10"' r"$", )