Пример #1
0
def test_message_multiple_duplicate_links() -> None:
    t = ModularInteger("P.T", Number(2))
    x = Field(ID("X", location=Location((1, 5))))
    y = Field(ID("Y", location=Location((2, 5))))

    structure = [
        Link(INITIAL, x),
        Link(x, y),
        Link(x, FINAL, location=Location((3, 16))),
        Link(x, FINAL, location=Location((4, 18))),
        Link(y, FINAL, location=Location((5, 20))),
        Link(y, FINAL, location=Location((6, 22))),
    ]

    types = {Field("X"): t, Field("Y"): t}

    assert_message_model_error(
        structure,
        types,
        f'^<stdin>:1:5: model: error: duplicate link from "X" to "{FINAL.name}"\n'
        f"<stdin>:3:16: model: info: duplicate link\n"
        f"<stdin>:4:18: model: info: duplicate link\n"
        f'<stdin>:2:5: model: error: duplicate link from "Y" to "{FINAL.name}"\n'
        f"<stdin>:5:20: model: info: duplicate link\n"
        f"<stdin>:6:22: model: info: duplicate link",
    )
Пример #2
0
def test_merge_message_error_name_conflict() -> None:
    m2_f2 = Field(ID("F2", Location((10, 5))))

    m2 = UnprovenMessage(
        "P.M2",
        [Link(INITIAL, m2_f2), Link(m2_f2, FINAL)],
        {Field("F2"): MODULAR_INTEGER},
        Location((15, 3)),
    )

    m1_f1 = Field(ID("F1", Location((20, 8))))
    m1_f1_f2 = Field(ID("F1_F2", Location((30, 5))))

    m1 = UnprovenMessage(
        "P.M1",
        [Link(INITIAL, m1_f1),
         Link(m1_f1, m1_f1_f2),
         Link(m1_f1_f2, FINAL)],
        {
            Field("F1"): m2,
            Field("F1_F2"): MODULAR_INTEGER
        },
        Location((2, 9)),
    )

    assert_type_error(
        m1.merged(),
        r"^"
        r'<stdin>:30:5: model: error: name conflict for "F1_F2" in "P.M1"\n'
        r'<stdin>:15:3: model: info: when merging message "P.M2"\n'
        r'<stdin>:20:8: model: info: into field "F1"$',
    )
Пример #3
0
 def __init__(self,
              identifier: StrID,
              generic_package: StrID,
              associations: Sequence[StrID] = None) -> None:
     self.identifier = ID(identifier)
     self.generic_package = ID(generic_package)
     self.associations = list(map(ID, associations or []))
Пример #4
0
 def __init__(self,
              name: StrID,
              type_name: StrID,
              default: Expr = None) -> None:
     self.name = ID(name)
     self.type_name = ID(type_name)
     self.default = default
Пример #5
0
 def __init__(self,
              name: StrID,
              generic_name: StrID,
              associations: Sequence[StrID] = None) -> None:
     self.name = ID(name)
     self.generic_name = ID(generic_name)
     self.associations = list(map(str, associations or []))
Пример #6
0
 def __init__(self,
              identifier: StrID,
              type_identifier: StrID,
              type_: rty.Type = rty.Undefined()):
     super().__init__()
     self._identifier = ID(identifier)
     self._type_identifier = ID(type_identifier)
     self.type_ = type_
Пример #7
0
def create_sequence_instantiation(
    sequence_type: model.Sequence,
    prefix: str = "",
    flat: bool = False,
) -> Tuple[List[ContextItem], GenericPackageInstantiation]:
    element_type = sequence_type.element_type
    element_type_package = element_type.package.name

    sequence_context: List[ContextItem] = []
    sequence_package: GenericPackageInstantiation
    if isinstance(element_type, model.Message):
        element_type_identifier = ID(
            element_type.identifier.flat if flat else prefix * element_type.identifier
        )
        sequence_context = [
            WithClause(prefix * const.MESSAGE_SEQUENCE_PACKAGE),
            *([] if flat else [WithClause(element_type_identifier)]),
        ]
        sequence_package = GenericPackageInstantiation(
            ID(sequence_type.identifier.flat if flat else prefix * sequence_type.identifier),
            prefix * const.MESSAGE_SEQUENCE_PACKAGE,
            [
                element_type_identifier * "Context",
                element_type_identifier * "Initialize",
                element_type_identifier * "Take_Buffer",
                element_type_identifier * "Copy",
                element_type_identifier * "Has_Buffer",
                element_type_identifier * "Size",
                element_type_identifier * "Message_Last",
                element_type_identifier * "Initialized",
                element_type_identifier * "Structural_Valid_Message",
            ],
        )
    elif isinstance(element_type, model.Scalar):
        element_type_identifier = prefix * element_type.identifier
        sequence_context = [
            WithClause(prefix * const.SCALAR_SEQUENCE_PACKAGE),
            *(
                [WithClause(prefix * element_type_package)]
                if element_type_package != sequence_type.package
                else []
            ),
        ]
        sequence_package = GenericPackageInstantiation(
            ID(sequence_type.identifier.flat if flat else prefix * sequence_type.identifier),
            prefix * const.SCALAR_SEQUENCE_PACKAGE,
            [
                element_type_identifier,
                str(element_type.size),
                prefix * element_type_package * f"Valid_{element_type.name}",
                prefix * element_type_package * "To_Actual",
                prefix * element_type_package * "To_Base_Integer",
            ],
        )
    else:
        assert False, 'unexpected element type "{type(element_type)}"'

    return (sequence_context, sequence_package)
Пример #8
0
def test_refinement_invalid_field_type() -> None:
    x = Field(ID("X", Location((20, 10))))

    message = Message("P.M",
                      [Link(INITIAL, x), Link(x, FINAL)], {x: MODULAR_INTEGER})

    assert_type_error(
        Refinement("P", message, Field(ID("X", Location((33, 22)))), message),
        r'^<stdin>:33:22: model: error: invalid type of field "X" in refinement of "P.M"\n'
        r"<stdin>:20:10: model: info: expected field of type Opaque",
    )
Пример #9
0
def test_invalid_enumeration_type_duplicate_elements() -> None:
    assert_type_error(
        Enumeration(
            "P.T",
            [(ID("Foo", Location((3, 27))), Number(1)),
             (ID("Foo", Location((3, 32))), Number(2))],
            Number(1),
            False,
        ),
        r'<stdin>:3:32: model: error: duplicate literal "Foo"\n'
        r"<stdin>:3:27: model: info: previous occurrence",
    )
Пример #10
0
def test_in_ipv4_parsing_udp_in_ipv4_in_ethernet(ethernet_frame_value: pyrflx.MessageValue) -> None:
    with open(CAPTURED_DIR / "ethernet_ipv4_udp.raw", "rb") as file:
        msg_as_bytes: bytes = file.read()
    ethernet_frame_value.parse(msg_as_bytes)
    nested_ipv4 = ethernet_frame_value.get("Payload")
    assert isinstance(nested_ipv4, pyrflx.MessageValue)
    assert nested_ipv4.valid_message
    assert nested_ipv4.identifier == ID("IPv4") * "Packet"
    nested_udp = nested_ipv4.get("Payload")
    assert isinstance(nested_udp, pyrflx.MessageValue)
    assert nested_udp.valid_message
    assert nested_udp.identifier == ID("UDP") * "Datagram"
Пример #11
0
def test_attribute() -> None:
    assert isinstance(Size("X"), Attribute)
    assert isinstance(Length("X"), Attribute)
    assert isinstance(First("X"), Attribute)
    assert isinstance(Last("X"), Attribute)
    assert isinstance(Range("X"), Attribute)
    assert isinstance(Old("X"), Attribute)
    assert isinstance(Result("X"), Attribute)
    assert isinstance(Constrained("X"), Attribute)
    assert First("X") == First(Variable("X"))
    assert First("X") == First(ID("X"))
    assert First("X") == First(Variable(ID("X")))
Пример #12
0
 def __init__(
     self,
     message: StrID,
     field: StrID,
     value: Expr,
     type_: rty.Type = rty.Undefined(),
     location: Location = None,
 ) -> None:
     super().__init__(message, type_, location)
     self.message = ID(message)
     self.field = ID(field)
     self.value = value
Пример #13
0
def test_ipv4_parsing_udp_in_ipv4_in_ethernet(frame: MessageValue) -> None:
    with open("tests/ethernet_ipv4_udp.raw", "rb") as file:
        msg_as_bytes: bytes = file.read()
    frame.parse(msg_as_bytes)
    nested_ipv4 = frame.get("Payload")
    assert isinstance(nested_ipv4, MessageValue)
    assert nested_ipv4.valid_message
    assert nested_ipv4.identifier == ID("IPv4.Packet")
    nested_udp = nested_ipv4.get("Payload")
    assert isinstance(nested_udp, MessageValue)
    assert nested_udp.valid_message
    assert nested_udp.identifier == ID("UDP.Datagram")
Пример #14
0
def test_name_conflict_types() -> None:
    assert_model_error(
        [
            ModularInteger(ID("P::T"), Number(256), location=Location((10, 20))),
            RangeInteger(
                ID("P::T"), Number(1), Number(100), Number(8), location=Location((11, 30))
            ),
        ],
        r"^"
        r'<stdin>:11:30: model: error: name conflict for type "P::T"\n'
        r'<stdin>:10:20: model: info: previous occurrence of "P::T"'
        r"$",
    )
Пример #15
0
def test_no_valid_path() -> None:
    f1 = Field(ID("F1", Location((10, 5))))
    f2 = Field(ID("F2", Location((11, 6))))
    f3 = Field(ID("F3", Location((12, 7))))
    structure = [
        Link(INITIAL, f1),
        Link(f1,
             f2,
             condition=LessEqual(Variable("F1"), Number(80), Location(
                 (20, 2)))),
        Link(f1,
             f3,
             condition=Greater(Variable("F1"), Number(80), Location((21, 3)))),
        Link(f2,
             f3,
             condition=Greater(Variable("F1"), Number(80), Location((22, 4)))),
        Link(f3,
             FINAL,
             condition=LessEqual(Variable("F1"), Number(80), Location(
                 (23, 5)))),
    ]
    types = {
        Field("F1"): RANGE_INTEGER,
        Field("F2"): RANGE_INTEGER,
        Field("F3"): RANGE_INTEGER,
    }
    assert_message_model_error(
        structure,
        types,
        r"^"
        r'<stdin>:11:6: model: error: unreachable field "F2" in "P.M"\n'
        r"<stdin>:11:6: model: info: path 0 [(]F1 -> F2[)]:\n"
        r'<stdin>:20:2: model: info: unsatisfied "F1 <= 80"\n'
        r'<stdin>:11:6: model: info: unsatisfied "F1 > 80"\n'
        r'<stdin>:12:7: model: error: unreachable field "F3" in "P.M"\n'
        r"<stdin>:12:7: model: info: path 0 [(]F1 -> F2 -> F3[)]:\n"
        r'<stdin>:20:2: model: info: unsatisfied "F1 <= 80"\n'
        r'<stdin>:22:4: model: info: unsatisfied "F1 > 80"\n'
        r"<stdin>:12:7: model: info: path 1 [(]F1 -> F3[)]:\n"
        r'<stdin>:21:3: model: info: unsatisfied "F1 > 80"\n'
        r'<stdin>:12:7: model: info: unsatisfied "F1 <= 80"\n'
        r'model: error: unreachable field "Final" in "P.M"\n'
        r"model: info: path 0 [(]F1 -> F2 -> F3 -> Final[)]:\n"
        r'<stdin>:20:2: model: info: unsatisfied "F1 <= 80"\n'
        r'<stdin>:22:4: model: info: unsatisfied "F1 > 80"\n'
        r"model: info: path 1 [(]F1 -> F3 -> Final[)]:\n"
        r'<stdin>:21:3: model: info: unsatisfied "F1 > 80"\n'
        r'<stdin>:23:5: model: info: unsatisfied "F1 <= 80"',
    )
Пример #16
0
def test_field_locations() -> None:
    f2 = Field(ID("F2", Location((2, 2))))
    f3 = Field(ID("F3", Location((3, 2))))

    message = UnprovenMessage(
        "P.M",
        [Link(INITIAL, f2), Link(f2, f3),
         Link(f3, FINAL)],
        {
            Field("F2"): MODULAR_INTEGER,
            Field("F3"): MODULAR_INTEGER
        },
        Location((17, 9)),
    )
    assert message.fields == (f2, f3)
Пример #17
0
 def __init__(self,
              identifier: StrID,
              type_: rty.Type = rty.Undefined(),
              location: Location = None):
     self.identifier = ID(identifier)
     self.type_ = type_
     self.location = location
Пример #18
0
def test_named_aggregate_substituted() -> None:
    assert_equal(
        NamedAggregate(("First", First("X"))).substituted(
            lambda x: Number(42) if x == NamedAggregate(("First", First("X"))) else x
        ),
        Number(42),
    )
    assert_equal(
        NamedAggregate(("First", First("X"))).substituted(
            lambda x: Number(42) if x == First("X") else x
        ),
        NamedAggregate(("First", Number(42))),
    )
    assert_equal(
        NamedAggregate(("First", First("X"))).substituted(
            lambda x: Variable(f"P_{x}")
            if isinstance(x, Variable)
            else (
                NamedAggregate(*[*x.elements, (ID("Last"), Last("Y"))])
                if isinstance(x, NamedAggregate)
                else x
            )
        ),
        NamedAggregate(("First", First("P_X")), ("Last", Last("P_Y"))),
    )
Пример #19
0
 def __init__(self,
              identifiers: Sequence[StrID],
              type_name: StrID,
              default: Expr = None) -> None:
     self.identifiers = list(map(ID, identifiers))
     self.type_name = ID(type_name)
     self.default = default
Пример #20
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(),
            },
        )
Пример #21
0
def test_conflicting_literal_builtin_type() -> None:
    assert_model_error(
        [
            Enumeration(
                "P.T",
                [
                    (ID("E1", Location((3, 27))), Number(1)),
                    (ID("Boolean", Location((3, 31))), Number(2)),
                ],
                Number(8),
                False,
            ),
        ],
        r'<stdin>:3:31: model: error: literal conflicts with type "Boolean"\n'
        r"__BUILTINS__:0:0: model: info: conflicting type declaration",
    )
Пример #22
0
def test_aggregate_equal_array_invalid_length() -> None:
    magic = Field(ID("Magic", Location((3, 5))))
    structure = [
        Link(INITIAL, magic, length=Number(40, location=Location((19, 17)))),
        Link(
            magic,
            FINAL,
            condition=NotEqual(Variable("Magic"),
                               Aggregate(Number(1), Number(2)),
                               Location((17, 3))),
        ),
    ]
    types = {
        Field("Magic"):
        Array(
            "P.Arr",
            ModularInteger("P.Modular",
                           Number(128),
                           location=Location((66, 3)))),
    }
    assert_message_model_error(
        structure,
        types,
        r"^"
        r'<stdin>:17:3: model: error: contradicting condition in "P.M"\n'
        r'<stdin>:3:5: model: info: on path: "Magic"\n'
        r'<stdin>:17:3: model: info: unsatisfied "2 [*] Modular\'Length = Magic\'Length"\n'
        r'<stdin>:66:3: model: info: unsatisfied "Modular\'Length = 7"\n'
        r'<stdin>:19:17: model: info: unsatisfied "Magic\'Length = 40"',
    )
Пример #23
0
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"$",
    )
Пример #24
0
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"$",
    )
Пример #25
0
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"',
    )
Пример #26
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")
                    ),
                ]
            },
        )
    )
Пример #27
0
 def _create_init_proc(self, slots: Sequence[NumberedSlotInfo]) -> UnitPart:
     proc = ProcedureSpecification(
         "Initialize",
         [OutParameter(["S"], "Slots"),
          Parameter(["M"], "Memory")])
     return UnitPart(
         [
             SubprogramDeclaration(
                 proc,
                 [Postcondition(Call("Initialized", [Variable("S")]))]),
         ],
         [
             SubprogramBody(
                 proc,
                 declarations=[],
                 statements=([
                     Assignment(
                         "S" * self._slot_name(slot.slot_id),
                         UnrestrictedAccess(
                             Variable(ID(f"M.Slot_{slot.slot_id}"))),
                     ) for slot in slots
                 ] if slots else [NullStatement()]),
                 aspects=[SparkMode(off=True)],
             )
         ],
     )
Пример #28
0
    def check_type(self, declaration_type: rty.Type,
                   typify_variable: Callable[[Expr], Expr]) -> RecordFluxError:
        self.type_ = declaration_type
        expression = self.expression.substituted(typify_variable)
        assert isinstance(expression, Selected)
        self.expression = expression

        error = self.expression.prefix.check_type_instance(rty.Message)
        if error.errors:
            return error

        assert isinstance(self.expression.prefix.type_, rty.Message)

        error = RecordFluxError()
        for r in self.expression.prefix.type_.refinements:
            if ID(r.field) == self.expression.selector and r.sdu.is_compatible(
                    declaration_type):
                break
        else:
            error.extend([
                (
                    f'invalid renaming to "{self.identifier}"',
                    Subsystem.MODEL,
                    Severity.ERROR,
                    self.location,
                ),
                (
                    f'refinement for message "{self.expression.prefix.type_.identifier}"'
                    " would make operation legal",
                    Subsystem.MODEL,
                    Severity.INFO,
                    self.location,
                ),
            ], )
        return error + self.expression.check_type(rty.OPAQUE)
Пример #29
0
 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],
     )
Пример #30
0
def full_base_type_name(scalar_type: Scalar) -> ID:
    if scalar_type.package == BUILTINS_PACKAGE:
        return const.BUILTIN_TYPES_PACKAGE * scalar_type.name + "_Base"

    if isinstance(scalar_type, ModularInteger):
        return scalar_type.identifier

    return ID(f"{scalar_type.full_name}_Base")