def test_slice_simplified() -> None: assert_equal( Slice( Variable("Buffer"), First("Buffer"), Add(Last("Buffer"), Add(Number(21), Number(21))), ).simplified(), Slice(Variable("Buffer"), First("Buffer"), Add(Last("Buffer"), Number(42))), )
def test_number_ge() -> None: # pylint: disable=unneeded-not assert not Number(1) >= Number(2) assert Number(2) >= Number(2) assert Number(3) >= Number(2) assert not Variable("X") >= Number(2) assert not Number(2) >= Variable("X")
def setter_postconditions(message: Message, field: Field) -> Sequence[Expr]: return [ *[ Call("Invalid", [Variable("Ctx"), Variable(p.affixed_name)]) for p in message.successors(field) if p != FINAL ], *common.valid_path_to_next_field_condition(message, field), *[ Equal(e, Old(e)) for e in [ Variable("Ctx.Buffer_First"), Variable("Ctx.Buffer_Last"), Variable("Ctx.First"), Call("Predecessor", [Variable("Ctx"), Variable(field.affixed_name)]), Call("Valid_Next", [Variable("Ctx"), Variable(field.affixed_name)]), ] + [ Call(f"Get_{p.name}", [Variable("Ctx")]) for p in message.definite_predecessors(field) if isinstance(message.types[p], Scalar) ] ], ]
def test_number_lt() -> None: # pylint: disable=unneeded-not assert Number(1) < Number(2) assert not Number(2) < Number(2) assert not Number(3) < Number(2) assert not Variable("X") < Number(2) assert not Number(2) < Variable("X")
def invalid_successors_invariant() -> Expr: return AndThen( *[ If( [ ( AndThen( *[ Call( "Invalid", [Indexed(Variable("Cursors"), Variable(p.affixed_name))], ) for p in message.direct_predecessors(f) ] ), Call( "Invalid", [Indexed(Variable("Cursors"), Variable(f.affixed_name))], ), ) ] ) for f in message.fields if f not in message.direct_successors(INITIAL) ] )
def assign(self, value: str, check: bool = True) -> None: prefixed_value = ( ID(value) if value.startswith(str(self._type.package)) or not self.__imported or self.__builtin else self._type.package * value) if Variable(prefixed_value) not in self.literals: raise KeyError(f"{value} is not a valid enum value") r = (And(*self._type.constraints( "__VALUE__", check, not self.__imported)).substituted( mapping={ **self.literals, **{ Variable("__VALUE__"): self._type.literals[prefixed_value.name] }, **{ Length("__VALUE__"): self._type.size }, }).simplified()) assert r == TRUE self._value = ( str(prefixed_value) if self.__imported and not self.__builtin else str(prefixed_value.name), self._type.literals[prefixed_value.name], )
def test_pow_simplified(self) -> None: self.assertEqual(Pow(Variable("X"), Number(1)).simplified(), Pow(Variable("X"), Number(1))) self.assertEqual( Pow(Variable("X"), Add(Number(1), Number(1))).simplified(), Pow(Variable("X"), Number(2)), ) self.assertEqual(Pow(Number(6), Number(2)).simplified(), Number(36))
def test_mod_simplified(self) -> None: self.assertEqual(Mod(Variable("X"), Number(1)).simplified(), Mod(Variable("X"), Number(1))) self.assertEqual( Mod(Variable("X"), Add(Number(1), Number(1))).simplified(), Mod(Variable("X"), Number(2)), ) self.assertEqual(Mod(Number(6), Number(2)).simplified(), Number(0))
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_coverage_2(self) -> None: foo_type = ModularInteger("P.Foo", Pow(Number(2), Number(32))) structure = [ Link(INITIAL, Field("F1")), Link(Field("F1"), Field("F2")), Link(Field("F2"), Field("F4"), Greater(Variable("F1"), Number(100))), Link( Field("F2"), Field("F3"), LessEqual(Variable("F1"), Number(100)), first=Add(Last("F2"), Number(64)), ), Link(Field("F3"), Field("F4")), Link(Field("F4"), FINAL), ] types = { Field("F1"): foo_type, Field("F2"): foo_type, Field("F3"): foo_type, Field("F4"): foo_type, } with mock.patch("rflx.model.Message._Message__verify_conditions", lambda x: None): with self.assertRaisesRegex( ModelError, "^path F1 -> F2 -> F3 -> F4 does not cover whole message"): Message("P.M", structure, types)
def test_dot_graph_with_double_edge() -> None: f_type = ModularInteger("P.T", Pow(Number(2), Number(32))) m = Message( "P.M", structure=[ Link(INITIAL, Field("F1")), Link(Field("F1"), FINAL, Greater(Variable("F1"), Number(100))), Link(Field("F1"), FINAL, Less(Variable("F1"), Number(50))), ], types={Field("F1"): f_type}, ) expected = """ digraph "P.M" { graph [ranksep="0.8 equally", splines=ortho]; edge [color="#6f6f6f", fontcolor="#6f6f6f", fontname="Fira Code"]; node [color="#6f6f6f", fillcolor="#009641", fontcolor="#ffffff", fontname=Arimo, shape=box, style="rounded,filled", width="1.5"]; Initial [fillcolor="#ffffff", label="", shape=circle, width="0.5"]; F1; Initial -> F1 [xlabel="(⊤, 32, ⋆)"]; F1 -> Final [xlabel="(F1 > 100, 0, ⋆)"]; F1 -> Final [xlabel="(F1 < 50, 0, ⋆)"]; Final [fillcolor="#6f6f6f", label="", shape=circle, width="0.5"]; } """ assert_graph(Graph(m), expected)
def constraints(self, name: str, proof: bool = False) -> Expr: if proof: return And( And(*[Equal(Variable(l), v) for l, v in self.literals.items()]), Or(*[Equal(Variable(name), Variable(l)) for l in self.literals.keys()]), ) return TRUE
def field_value(field: Field, field_type: Type) -> Expr: if isinstance(field_type, Enumeration): if public: return Call( target_type, [Call("To_Base", [Call(f"Get_{field.name}", [Variable("Ctx")])])], ) return Call( target_type, [ Selected( Indexed(cursors, Variable(field.affixed_name)), f"Value.{field.name}_Value" ) ], ) if isinstance(field_type, Scalar): if public: return Call(target_type, [Call(f"Get_{field.name}", [Variable("Ctx")])]) return Call( target_type, [ Selected( Indexed(cursors, Variable(field.affixed_name)), f"Value.{field.name}_Value" ) ], ) if isinstance(field_type, Composite): return Variable(field.name) assert False, f'unexpected type "{type(field_type).__name__}"' return UNDEFINED
def create_structural_valid_function() -> UnitPart: specification = FunctionSpecification( "Structural_Valid", "Boolean", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")], ) return UnitPart( [SubprogramDeclaration(specification)], [ ExpressionFunctionDeclaration( specification, And( Or(*[ Equal( Selected( Indexed(Variable("Ctx.Cursors"), Variable("Fld")), "State"), Variable(s), ) for s in ("S_Valid", "S_Structural_Valid") ])), ) ], )
def test_exclusive_conflict() -> None: f1 = Field(ID("F1", Location((8, 4)))) structure = [ Link(INITIAL, f1), Link(f1, FINAL, condition=Greater(Variable("F1"), Number(50), Location((10, 5)))), Link(f1, Field("F2"), condition=Less(Variable("F1"), Number(80), Location((11, 7)))), Link(Field("F2"), FINAL), ] types = { Field("F1"): RANGE_INTEGER, Field("F2"): RANGE_INTEGER, } assert_message_model_error( structure, types, r"^" r'<stdin>:8:4: model: error: conflicting conditions for field "F1"\n' r"<stdin>:10:5: model: info: condition 0 [(]F1 -> Final[)]: F1 > 50\n" r"<stdin>:11:7: model: info: condition 1 [(]F1 -> F2[)]: F1 < 80" r"$", )
def test_conditionally_unreachable_field_outgoing_multi() -> None: f2 = Field(ID("F2", Location((90, 12)))) structure = [ Link(INITIAL, Field("F1")), Link(Field("F1"), f2, LessEqual(Variable("F1"), Number(32), Location((66, 3)))), Link(Field("F1"), Field("F3"), Greater(Variable("F1"), Number(32))), Link( f2, Field("F3"), And( Greater(Variable("F1"), Number(32)), LessEqual(Variable("F1"), Number(48)), location=Location((22, 34)), ), ), Link(f2, FINAL, Greater(Variable("F1"), Number(48))), Link(Field("F3"), FINAL), ] types = { Field("F1"): MODULAR_INTEGER, Field("F2"): MODULAR_INTEGER, Field("F3"): MODULAR_INTEGER, } assert_message_model_error( structure, types, r"^" r'<stdin>:90:12: model: error: unreachable field "F2" in "P.M"\n' r"<stdin>:90:12: model: info: path 0 [(]F1 -> F2[)]:\n" r'<stdin>:66:3: model: info: unsatisfied "F1 <= 32"\n' r'<stdin>:90:12: model: info: unsatisfied "[(]F1 > 32 and F1 <= 48[)] or F1 > 48"', )
def test_no_path_to_final_transitive() -> None: structure = [ Link(INITIAL, Field("F1")), Link(Field("F1"), Field("F2")), Link(Field("F2"), Field("F3"), Greater(Variable("F1"), Number(100))), Link(Field("F3"), FINAL), Link(Field("F2"), Field("F4"), LessEqual(Variable("F1"), Number(100))), Link(Field("F4"), Field("F5")), Link(Field("F5"), Field("F6")), ] types = { Field("F1"): MODULAR_INTEGER, Field("F2"): MODULAR_INTEGER, Field("F3"): MODULAR_INTEGER, Field("F4"): MODULAR_INTEGER, Field("F5"): MODULAR_INTEGER, Field("F6"): MODULAR_INTEGER, } assert_message_model_error( structure, types, r"^" r'model: error: no path to FINAL for field "F4" in "P.M"\n' r'model: error: no path to FINAL for field "F5" in "P.M"\n' r'model: error: no path to FINAL for field "F6" in "P.M"' r"$", )
def test_field_coverage_2(monkeypatch: Any) -> None: structure = [ Link(INITIAL, Field("F1")), Link(Field("F1"), Field("F2")), Link(Field("F2"), Field("F4"), Greater(Variable("F1"), Number(100))), Link( Field("F2"), Field("F3"), LessEqual(Variable("F1"), Number(100)), first=Add(Last("F2"), Number(64)), ), Link(Field("F3"), Field("F4")), Link(Field("F4"), FINAL), ] types = { Field("F1"): MODULAR_INTEGER, Field("F2"): MODULAR_INTEGER, Field("F3"): MODULAR_INTEGER, Field("F4"): MODULAR_INTEGER, } monkeypatch.setattr(Message, "_AbstractMessage__verify_conditions", lambda x: None) assert_message_model_error( structure, types, r"^" r"model: error: path does not cover whole message\n" r'model: info: on path: "F1"\n' r'model: info: on path: "F2"\n' r'model: info: on path: "F3"\n' r'model: info: on path: "F4"' r"$", )
def test_no_contradiction_multi() -> None: structure = [ Link(INITIAL, Field("F0")), Link(Field("F0"), Field("F1"), condition=Equal(Variable("F0"), Number(1))), Link(Field("F0"), Field("F2"), condition=Equal(Variable("F0"), Number(2))), Link(Field("F1"), Field("F3")), Link(Field("F2"), Field("F3")), Link(Field("F3"), Field("F4"), condition=Equal(Variable("F0"), Number(1))), Link(Field("F3"), Field("F5"), condition=Equal(Variable("F0"), Number(2))), Link(Field("F4"), FINAL), Link(Field("F5"), FINAL), ] types = { Field("F0"): RANGE_INTEGER, Field("F1"): RANGE_INTEGER, Field("F2"): RANGE_INTEGER, Field("F3"): RANGE_INTEGER, Field("F4"): RANGE_INTEGER, Field("F5"): RANGE_INTEGER, } Message("P.M", structure, types)
def test_term_simplified(self) -> None: self.assertEqual( Add( Mul(Number(1), Number(6)), Sub(Variable("X"), Number(10)), Add(Number(1), Number(3)) ).simplified(), Variable("X"), )
def test_message_type_message() -> None: simple_structure = [ Link(INITIAL, Field("Bar")), Link(Field("Bar"), Field("Baz")), Link(Field("Baz"), FINAL), ] simple_types = { Field("Bar"): ModularInteger("Message_Type.T", Number(256)), Field("Baz"): ModularInteger("Message_Type.T", Number(256)), } simple_message = Message("Message_Type.Simple_PDU", simple_structure, simple_types) structure = [ Link(INITIAL, Field("Foo")), Link(Field("Foo"), Field("Bar"), LessEqual(Variable("Foo"), Number(30, 16))), Link(Field("Foo"), Field("Baz"), Greater(Variable("Foo"), Number(30, 16))), Link(Field("Bar"), Field("Baz")), Link(Field("Baz"), FINAL), ] types = { **simple_types, **{Field("Foo"): ModularInteger("Message_Type.T", Number(256))}, } message = Message("Message_Type.PDU", structure, types) empty_message = Message("Message_Type.Empty_PDU", [], {}) assert_messages_files( [f"{TESTDIR}/message_type.rflx"], [message, simple_message, empty_message] )
def create_verify_message_procedure( message: Message, context_invariant: Sequence[Expr]) -> UnitPart: specification = ProcedureSpecification( "Verify_Message", [InOutParameter(["Ctx"], "Context")]) return UnitPart( [ SubprogramDeclaration( specification, [ Postcondition( And( Equal( Call("Has_Buffer", [Variable("Ctx")]), Old(Call("Has_Buffer", [Variable("Ctx")])), ), *context_invariant, )), ], ) ], [ SubprogramBody( specification, [], [ CallStatement( "Verify", [Variable("Ctx"), Variable(f.affixed_name)]) for f in message.fields ], ) ], )
def test_ass_expr_findall() -> None: assert_equal( And(Equal(Variable("X"), Number(1)), Variable("Y"), Number(2)).findall( lambda x: isinstance(x, Number) ), [Number(1), Number(2)], )
def create_tlv_message() -> Message: tag_type = Enumeration("TLV.Tag", { "Msg_Data": Number(1), "Msg_Error": Number(3) }, Number(2), False) length_type = ModularInteger("TLV.Length", Pow(Number(2), Number(14))) structure = [ Link(INITIAL, Field("Tag")), Link(Field("Tag"), Field("Length"), Equal(Variable("Tag"), Variable("Msg_Data"))), Link(Field("Tag"), FINAL, Equal(Variable("Tag"), Variable("Msg_Error"))), Link(Field("Length"), Field("Value"), length=Mul(Variable("Length"), Number(8))), Link(Field("Value"), FINAL), ] types = { Field("Tag"): tag_type, Field("Length"): length_type, Field("Value"): Payload() } return Message("TLV.Message", structure, types)
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_type_refinement_spec() -> None: spec = { "Message_Type": Specification( ContextSpec([]), PackageSpec( "Message_Type", [ ModularInteger("__PACKAGE__.T", Number(256)), MessageSpec( "__PACKAGE__.PDU", [ Component( "Foo", "T", [ Then( "Bar", UNDEFINED, UNDEFINED, LessEqual(Variable("Foo"), Number(30, 16)), ), Then( "Baz", UNDEFINED, UNDEFINED, Greater(Variable("Foo"), Number(30, 16)), ), ], ), Component("Bar", "T"), Component("Baz", "T"), ], ), MessageSpec( "__PACKAGE__.Simple_PDU", [Component("Bar", "T"), Component("Baz", "T")], ), MessageSpec("__PACKAGE__.Empty_PDU", []), ], ), ), "Type_Refinement": Specification( ContextSpec(["Message_Type"]), PackageSpec( "Type_Refinement", [ RefinementSpec( "Message_Type.Simple_PDU", "Bar", "Message_Type.PDU", Equal(Variable("Baz"), Number(42)), ), RefinementSpec("Message_Type.PDU", "Bar", "Message_Type.Simple_PDU"), ], ), ), } assert_specifications_files( [f"{TESTDIR}/message_type.rflx", f"{TESTDIR}/type_refinement.rflx"], spec )
def test_value_enum(enum_value: EnumValue) -> None: assert enum_value.literals == { Variable("One"): Number(1), Variable("Test.One"): Number(1), Variable("Two"): Number(2), Variable("Test.Two"): Number(2), } assert not enum_value.initialized
def composite_setter_postconditions(self, message: Message, field: Field) -> Sequence[Expr]: return [ Call("Has_Buffer", [Variable("Ctx")]), *self.setter_postconditions(message, field), Call("Structural_Valid", [Variable("Ctx"), Variable(field.affixed_name)]), ]
def field_length(field: Field) -> Expr: if public: return Call("Field_Length", [Variable("Ctx"), Variable(field.affixed_name)]) return Add( Sub( Selected(Indexed(cursors, Variable(field.affixed_name)), "Last"), Selected(Indexed(cursors, Variable(field.affixed_name)), "First"), ), Number(1), )
def field_value(field: Field) -> Expr: if public: return Call(f"Get_{field.name}", [Variable("Ctx")]) return Selected( Indexed( Variable("Ctx.Cursors" if not embedded else "Cursors"), Variable(field.affixed_name), ), f"Value.{field.name}_Value", )