Esempio n. 1
0
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]
    )
Esempio n. 2
0
def test_array_aggregate_invalid_element_type() -> None:
    inner = Message(
        "P.I",
        [Link(INITIAL, Field("F")),
         Link(Field("F"), FINAL)],
        {Field("F"): MODULAR_INTEGER},
    )
    array_type = Array("P.Array", inner)

    f = Field("F")
    with pytest.raises(
            RecordFluxError,
            match=r"^<stdin>:90:10: model: error: invalid array element type"
            ' "P.I" for aggregate comparison$',
    ):
        Message(
            "P.M",
            [
                Link(INITIAL, f, length=Number(18)),
                Link(
                    f,
                    FINAL,
                    condition=Equal(
                        Variable("F"),
                        Aggregate(Number(1), Number(2), Number(64)),
                        Location((90, 10)),
                    ),
                ),
            ],
            {Field("F"): array_type},
        )
Esempio n. 3
0
 def setter_postconditions(
     self, message: Message, field: Field, field_type: Type
 ) -> Sequence[Expr]:
     return [
         *[
             Call("Invalid", [Name("Ctx"), Name(p.affixed_name)])
             for p in message.successors(field)
             if p != FINAL
         ],
         *self.common.valid_path_to_next_field_condition(message, field, field_type),
         *[
             Equal(e, Old(e))
             for e in [
                 Selected("Ctx", "Buffer_First"),
                 Selected("Ctx", "Buffer_Last"),
                 Selected("Ctx", "First"),
                 Call("Predecessor", [Name("Ctx"), Name(field.affixed_name)]),
                 Call("Valid_Next", [Name("Ctx"), Name(field.affixed_name)]),
             ]
             + [
                 Call(f"Get_{p.name}", [Name("Ctx")])
                 for p in message.definite_predecessors(field)
                 if isinstance(message.types[p], Scalar)
             ]
         ],
     ]
Esempio n. 4
0
def test_message_proven() -> None:
    message = Message(
        "P.M",
        [Link(INITIAL, Field("F")),
         Link(Field("F"), FINAL)],
        {Field("F"): MODULAR_INTEGER},
    )
    assert message.proven() == message
Esempio n. 5
0
def context_cursor_unchanged(
    message: model.Message, field: model.Field, predecessors: bool
) -> List[Expr]:
    lower: model.Field
    upper: model.Field
    if predecessors:
        if len(message.predecessors(field)) == 0:
            return []
        lower = message.fields[0]
        upper = message.fields[message.fields.index(field) - 1]
    else:
        if len(message.successors(field)) == 0:
            return []
        lower = message.fields[message.fields.index(field) + 1]
        upper = message.fields[-1]
    return [
        ForAllIn(
            "F",
            ValueRange(
                lower=Variable(lower.affixed_name),
                upper=Variable(upper.affixed_name),
                type_identifier=ID("Field"),
            ),
            Equal(
                Call(
                    "Context_Cursors_Index",
                    [
                        Call(
                            "Context_Cursors",
                            [Variable("Ctx")],
                        ),
                        Variable("F"),
                    ],
                ),
                Call(
                    "Context_Cursors_Index",
                    [
                        Old(
                            Call(
                                "Context_Cursors",
                                [Variable("Ctx")],
                            )
                        ),
                        Variable("F"),
                    ],
                ),
            ),
        )
    ]
Esempio n. 6
0
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),
        ],
    )
Esempio n. 7
0
def test_write_specification_files_missing_deps(tmp_path: Path) -> None:
    s = ModularInteger("P::S", Number(65536))
    t = ModularInteger("P::T", Number(256))
    v = mty.Sequence("P::V", element_type=t)
    m = Message("P::M", [Link(INITIAL, Field("Foo")), Link(Field("Foo"), FINAL)], {Field("Foo"): t})
    Model([s, v, m]).write_specification_files(tmp_path)
    expected_path = tmp_path / Path("p.rflx")
    assert list(tmp_path.glob("*.rflx")) == [expected_path]
    assert expected_path.read_text() == textwrap.dedent(
        """\
        package P is

           type S is mod 65536;

           type T is mod 256;

           type V is sequence of P::T;

           type M is
              message
                 Foo : P::T;
              end message;

        end P;"""
    )
Esempio n. 8
0
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)
Esempio n. 9
0
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)
Esempio n. 10
0
    def _expand_message_links(self, message: Message,
                              messages: Dict[ID, Message]) -> Message:
        """Split disjunctions in link conditions."""
        structure = []
        for link in message.structure:
            conditions = self._expand_expression(link.condition.simplified())

            if len(conditions) == 1:
                structure.append(link)
                continue

            for condition in conditions:
                structure.append(
                    Link(
                        link.source,
                        link.target,
                        condition,
                        link.size,
                        link.first,
                        condition.location,
                    ))

        types = {
            f: self._replace_messages(t, messages)
            for f, t in message.types.items()
        }

        return message.copy(structure=structure, types=types)
Esempio n. 11
0
    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)
Esempio n. 12
0
def test_dot_graph(tmp_path: Path) -> None:
    f_type = ModularInteger("P::T", Pow(Number(2), Number(32)))
    m = Message(
        "P::M",
        structure=[Link(INITIAL, Field("X")),
                   Link(Field("X"), FINAL)],
        types={Field("X"): f_type},
    )
    expected = """
        digraph "P::M" {
            graph [bgcolor="#00000000", pad="0.1", ranksep="0.1 equally", splines=true,
                   truecolor=true];
            edge [color="#6f6f6f", fontcolor="#6f6f6f", fontname="Fira Code", penwidth="2.5"];
            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"];
            X;
            intermediate_0 [color="#6f6f6f", fontcolor="#6f6f6f", fontname="Fira Code", height=0,
                            label="(⊤, 32, ⋆)", penwidth=0, style="", width=0];
            Initial -> intermediate_0 [arrowhead=none];
            intermediate_0 -> X [minlen=1];
            intermediate_1 [color="#6f6f6f", fontcolor="#6f6f6f", fontname="Fira Code", height=0,
                            label="(⊤, 0, ⋆)", penwidth=0, style="", width=0];
            X -> intermediate_1 [arrowhead=none];
            intermediate_1 -> Final [minlen=1];
            Final [fillcolor="#6f6f6f", label="", shape=circle, width="0.5"];
        }
        """

    assert_graph(create_message_graph(m), expected, tmp_path)
Esempio n. 13
0
def test_graph_object() -> None:
    f_type = ModularInteger("P::T", Pow(Number(2), Number(32)))
    m = Message(
        "P::M",
        structure=[Link(INITIAL, Field("X")),
                   Link(Field("X"), FINAL)],
        types={Field("X"): f_type},
    )
    g = create_message_graph(m)
    assert [(e.get_source(), e.get_destination()) for e in g.get_edges()] == [
        ("Initial", "intermediate_0"),
        ("intermediate_0", "X"),
        ("X", "intermediate_1"),
        ("intermediate_1", "Final"),
    ]
    assert [n.get_name() for n in g.get_nodes()] == [
        "graph",
        "edge",
        "node",
        "Initial",
        "X",
        "intermediate_0",
        "intermediate_1",
        "Final",
    ]
Esempio n. 14
0
def valid_path_to_next_field_condition(
    message: model.Message, field: model.Field, prefix: str
) -> Sequence[Expr]:
    return [
        If(
            [
                (
                    l.condition.substituted(substitution(message, public=True, prefix=prefix))
                    .simplified()
                    .ada_expr(),
                    And(
                        Equal(
                            Call(
                                "Predecessor",
                                [Variable("Ctx"), Variable(l.target.affixed_name)],
                            ),
                            Variable(field.affixed_name),
                        ),
                        Call(
                            "Valid_Next",
                            [Variable("Ctx"), Variable(l.target.affixed_name)],
                        )
                        if l.target != model.FINAL
                        else TRUE,
                    ),
                )
            ]
        )
        for l in message.outgoing(field)
        if l.target != model.FINAL
    ]
Esempio n. 15
0
def test_array_aggregate_out_of_range() -> None:
    array_type = Array("P.Array", ModularInteger("P.Element", Number(64)))

    f = Field("F")
    with pytest.raises(
            RecordFluxError,
            match=
            r"^<stdin>:44:3: model: error: aggregate element out of range 0 .. 63",
    ):
        Message(
            "P.M",
            [
                Link(INITIAL, f, length=Number(18)),
                Link(
                    f,
                    FINAL,
                    condition=Equal(
                        Variable("F"),
                        Aggregate(Number(1), Number(2),
                                  Number(64, location=Location((44, 3)))),
                    ),
                ),
            ],
            {Field("F"): array_type},
        )
Esempio n. 16
0
 def valid_path_to_next_field_condition(
     self, message: Message, field: Field, field_type: Type
 ) -> Sequence[Expr]:
     return [
         If(
             [
                 (
                     l.condition,
                     And(
                         Equal(
                             Call("Predecessor", [Name("Ctx"), Name(l.target.affixed_name)],),
                             Name(field.affixed_name),
                         ),
                         Call("Valid_Next", [Name("Ctx"), Name(l.target.affixed_name)])
                         if l.target != FINAL
                         else TRUE,
                     ),
                 )
             ]
         ).simplified(
             {
                 **{
                     Variable(field.name): Call("Convert", [Name("Value")])
                     if isinstance(field_type, Enumeration) and field_type.always_valid
                     else Name("Value")
                 },
                 **self.public_substitution(message),
             }
         )
         for l in message.outgoing(field)
         if l.target != FINAL
     ]
Esempio n. 17
0
def test_dot_graph_with_condition() -> 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))),
        ],
        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, ⋆)"];
            Final [fillcolor="#6f6f6f", label="", shape=circle, width="0.5"];
        }
        """

    assert_graph(Graph(m), expected)
Esempio n. 18
0
def fixture_icmp_checksum_message_first(icmp_message: model.Message) -> pyrflx.MessageValue:
    return pyrflx.MessageValue(
        icmp_message.copy(
            structure=[
                model.Link(
                    l.source,
                    l.target,
                    condition=expr.And(l.condition, expr.ValidChecksum("Checksum")),
                )
                if l.target == model.FINAL
                else l
                for l in icmp_message.structure
            ],
            checksums={
                ID("Checksum"): [
                    expr.ValueRange(
                        expr.First("Message"), expr.Sub(expr.First("Checksum"), expr.Number(1))
                    ),
                    expr.Size("Checksum"),
                    expr.ValueRange(
                        expr.Add(expr.Last("Checksum"), expr.Number(1)), expr.Last("Message")
                    ),
                ]
            },
        )
    )
Esempio n. 19
0
def create_array_message() -> Message:
    length_type = ModularInteger("Arrays.Length", Pow(Number(2), Number(8)))

    modular_type = ModularInteger("Arrays.Modular_Integer",
                                  Pow(Number(2), Number(16)))
    modular_vector_type = Array("Arrays.Modular_Vector", modular_type)

    range_type = RangeInteger("Arrays.Range_Integer", Number(1), Number(100),
                              Number(8))
    range_vector_type = Array("Arrays.Range_Vector", range_type)

    enum_type = Enumeration(
        "Arrays.Enumeration",
        {
            "ZERO": Number(0),
            "ONE": Number(1),
            "TWO": Number(2)
        },
        Number(8),
        False,
    )
    enum_vector_type = Array("Arrays.Enumeration_Vector", enum_type)

    av_enum_type = Enumeration(
        "Arrays.AV_Enumeration",
        {
            "AV_ZERO": Number(0),
            "AV_ONE": Number(1),
            "AV_TWO": Number(2)
        },
        Number(8),
        True,
    )
    av_enum_vector_type = Array("Arrays.AV_Enumeration_Vector", av_enum_type)

    structure = [
        Link(INITIAL, Field("Length")),
        Link(Field("Length"),
             Field("Modular_Vector"),
             length=Mul(Variable("Length"), Number(8))),
        Link(Field("Modular_Vector"), Field("Range_Vector"),
             length=Number(16)),
        Link(Field("Range_Vector"),
             Field("Enumeration_Vector"),
             length=Number(16)),
        Link(Field("Enumeration_Vector"),
             Field("AV_Enumeration_Vector"),
             length=Number(16)),
        Link(Field("AV_Enumeration_Vector"), FINAL),
    ]

    types = {
        Field("Length"): length_type,
        Field("Modular_Vector"): modular_vector_type,
        Field("Range_Vector"): range_vector_type,
        Field("Enumeration_Vector"): enum_vector_type,
        Field("AV_Enumeration_Vector"): av_enum_vector_type,
    }

    return Message("Arrays.Message", structure, types)
Esempio n. 20
0
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)
Esempio n. 21
0
def test_derived_message_incorrect_base_name() -> None:
    with pytest.raises(
            RecordFluxError,
            match=
            '^<stdin>:40:8: model: error: unexpected format of type name "M"$'
    ):
        DerivedMessage("P.M", Message("M", [], {}, location=Location((40, 8))))
Esempio n. 22
0
def test_message_incorrect_name() -> None:
    with pytest.raises(
            RecordFluxError,
            match=
            '^<stdin>:10:8: model: error: unexpected format of type name "M"$'
    ):
        Message("M", [], {}, Location((10, 8)))
Esempio n. 23
0
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(),
            },
        )
Esempio n. 24
0
 def bounded_composite_setter_preconditions(message: Message,
                                            field: Field) -> Sequence[Expr]:
     return [
         Call(
             "Field_Condition",
             [
                 Variable("Ctx"),
                 NamedAggregate(("Fld", Variable(field.affixed_name)))
             ] + ([Variable("Length")]
                  if common.length_dependent_condition(message) else []),
         ),
         GreaterEqual(
             Call("Available_Space",
                  [Variable("Ctx"),
                   Variable(field.affixed_name)]),
             Variable("Length"),
         ),
         LessEqual(
             Add(
                 Call("Field_First",
                      [Variable("Ctx"),
                       Variable(field.affixed_name)]),
                 Variable("Length"),
             ),
             Div(Last(const.TYPES_BIT_INDEX), Number(2)),
         ),
         Or(*[
             And(
                 *[
                     Call("Valid",
                          [Variable("Ctx"),
                           Variable(field.affixed_name)])
                     for field in message.fields
                     if Variable(field.name) in l.condition.variables()
                 ],
                 l.condition.substituted(
                     mapping={
                         Variable(field.name): Call(f"Get_{field.name}",
                                                    [Variable("Ctx")])
                         for field in message.fields
                         if Variable(field.name) in l.condition.variables()
                     }),
             ) for l in message.incoming(field)
             if Last("Message") in l.length
         ]),
         Equal(
             Mod(
                 Call("Field_First",
                      [Variable("Ctx"),
                       Variable(field.affixed_name)]),
                 Size(const.TYPES_BYTE),
             ),
             Number(1),
         ),
         Equal(
             Mod(Variable("Length"), Size(const.TYPES_BYTE)),
             Number(0),
         ),
     ]
Esempio n. 25
0
    def test_message_missing_type(self) -> None:
        structure = [
            Link(INITIAL, Field("X")),
            Link(Field("X"), FINAL),
        ]

        with self.assertRaisesRegex(ModelError, '^missing type for field "X" of "P.M"$'):
            Message("P.M", structure, {})
Esempio n. 26
0
def has_size_dependent_condition(message: model.Message, field: model.Field = None) -> bool:
    field_sizes = {expr.Size(f.name) for f in message.fields}
    links = message.outgoing(field) if field else message.structure
    return any(
        size in field_sizes
        for link in links
        for size in link.condition.findall(lambda x: isinstance(x, expr.Size))
    )
Esempio n. 27
0
def valid_message_condition(message: Message,
                            field: Field = INITIAL,
                            structural: bool = False) -> Expr:
    if not message.outgoing(field):
        return TRUE
    return Or(*[
        l.condition if l.target == FINAL else AndThen(
            Call(
                "Structural_Valid" if structural and isinstance(
                    message.types[l.target], Composite) else "Valid",
                [Variable("Ctx"
                          ), Variable(l.target.affixed_name)],
            ),
            l.condition,
            valid_message_condition(message, l.target, structural),
        ) for l in message.outgoing(field)
    ])
Esempio n. 28
0
def test_invalid_message_field_type() -> None:
    with pytest.raises(AssertionError, match=r"rflx/model.py"):
        Message(
            "P.M",
            [Link(INITIAL, Field("F")),
             Link(Field("F"), FINAL)],
            {Field("F"): NewType("T")},
        )
Esempio n. 29
0
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],
    )
Esempio n. 30
0
def test_tlv_message_with_not_operator_exhausting() -> None:
    message = Message(
        "TLV::Message_With_Not_Operator_Exhausting",
        [
            Link(INITIAL, Field("Tag")),
            Link(
                Field("Tag"),
                Field("Length"),
                Not(Not(Not(NotEqual(Variable("Tag"), Variable("Msg_Data"))))),
            ),
            Link(
                Field("Tag"),
                FINAL,
                reduce(
                    lambda acc, f: f(acc),
                    [Not, Not] * 16,
                    Not(
                        Or(
                            Not(
                                Not(
                                    Equal(Variable("Tag"),
                                          Variable("Msg_Data")))),
                            Not(Equal(Variable("Tag"), Variable("Msg_Error"))),
                        )),
                ),
            ),
            Link(Field("Length"),
                 Field("Value"),
                 size=Mul(Variable("Length"), Number(8))),
            Link(Field("Value"), FINAL),
        ],
        {
            Field("Tag"): TLV_TAG,
            Field("Length"): TLV_LENGTH,
            Field("Value"): OPAQUE
        },
    )

    with pytest.raises(
            FatalError,
            match=re.escape(
                "failed to simplify complex expression `not (not (not (not "
                "(not (not (not (not (not (not (not (not (not (not (not (not "
                "(not (not (not (not (not (not (not (not (not (not (not (not "
                "(not (not (not (not (not (not (not (Tag = TLV::Msg_Data))\n"
                "                                 "
                "or not (Tag = TLV::Msg_Error))))))))))))))))))))))))))))))))))` "
                "after `16` iterations, best effort: "
                "`not (not (not (not (not (not (not (not (not (not (not (not (not "
                "(not (not (not (not (Tag = TLV::Msg_Data\n"
                "                 or Tag /= TLV::Msg_Error)))))))))))))))))`"),
    ):
        model = PyRFLX(model=Model([TLV_TAG, TLV_LENGTH, message]))
        pkg = model.package("TLV")
        msg = pkg.new_message("Message_With_Not_Operator_Exhausting")
        test_bytes = b"\x01\x00\x04\x00\x00\x00\x00"
        msg.parse(test_bytes)