def test_unexpected_mathematical_operator() -> None: with pytest.raises(ParseFatalException, match=r"^unexpected mathematical operator"): grammar.parse_mathematical_expression( "", 0, [[Number(1, location=Location((1, 1))), "//", Number(1, location=Location((1, 8)))]], )
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"', )
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"$', )
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_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_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_message_unsupported_expression() -> None: x = Field("X") structure = [ Link(INITIAL, x), Link( x, FINAL, condition=LessEqual( Pow( Number(2), Add(Variable("X", location=Location((10, 23))), Number(1)), location=Location((10, 19)), ), Number(1024), ), ), ] types = {x: MODULAR_INTEGER} assert_message_model_error( structure, types, '^<stdin>:10:19: model: error: unsupported expression in "P.M"\n' '<stdin>:10:23: model: info: variable "X" in exponent', )
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", )
def test_enumeration_invalid_literal() -> None: assert_type_error( Enumeration("P.T", [("A B", Number(1))], Number(8), False, Location(((1, 2)))), r'^<stdin>:1:2: model: error: invalid literal name "A B" in "T"$', ) assert_type_error( Enumeration("P.T", [("A.B", Number(1))], Number(8), False, Location((6, 4))), r'^<stdin>:6:4: model: error: invalid literal name "A.B" in "T"$', )
def test_type_name() -> None: t = ModularInteger("Package.Type_Name", Number(256)) assert t.name == "Type_Name" assert t.package == ID("Package") assert_type_error( ModularInteger("X", Number(256), Location((10, 20))), r'^<stdin>:10:20: model: error: unexpected format of type name "X"$', ) assert_type_error( ModularInteger("X.Y.Z", Number(256), Location((10, 20))), '^<stdin>:10:20: model: error: unexpected format of type name "X.Y.Z"$', )
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", )
def test_conflicting_refinements() -> None: r1 = copy(models.REFINEMENT) r1.location = Location((10, 20)) r2 = copy(models.REFINEMENT) r2.location = Location((10, 30)) assert_model_error( [models.MESSAGE, r1, r2], r"^" r'<stdin>:10:30: model: error: conflicting refinement of "P::M" with "P::M"\n' r"<stdin>:10:20: model: info: previous occurrence of refinement" r"$", )
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"$", )
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)
def test_array_unsupported_element_type() -> None: assert_type_error( Array( "P.A", ModularInteger("P.B", Pow(Number(2), Number(4)), Location((3, 4))), Location((5, 4)), ), r'^<stdin>:5:4: model: error: unsupported element type size of array "A"\n' r'<stdin>:3:4: model: info: type "B" has size 4, must be multiple of 8$', ) assert_type_error( Array("P.A", BOOLEAN, Location((5, 4))), r'^<stdin>:5:4: model: error: unsupported element type size of array "A"\n' r'__BUILTINS__:0:0: model: info: type "Boolean" has size 1, must be multiple of 8$', )
def test_enumeration_invalid_literal_value() -> None: assert_type_error( Enumeration("P.T", [("A", Number(2**63))], Number(64), False, Location((10, 5))), r'^<stdin>:10:5: model: error: enumeration value of "T"' r" outside of permitted range \(0 .. 2\*\*63 - 1\)$", )
def test_range_invalid_size_exceeds_limit() -> None: # ISSUE: Componolit/RecordFlux#238 assert_type_error( RangeInteger("P.T", Number(0), Number(256), Number(128), Location((50, 3))), r'^<stdin>:50:3: model: error: size of "T" exceeds limit \(2\*\*64\)$', )
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_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", )
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}, )
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}, )
def test_name_conflict_sessions() -> None: s1 = copy(models.SESSION) s1.location = Location((10, 20)) s2 = copy(models.SESSION) s2.location = Location((10, 30)) with pytest.raises( RecordFluxError, match=( r"^" r'<stdin>:10:30: model: error: name conflict for session "P::S"\n' r'<stdin>:10:20: model: info: previous occurrence of "P::S"' r"$" ), ): Model([], [s1, s2])
def parse_mathematical_expression(string: str, location: int, tokens: ParseResults) -> Expr: result: List[Expr] = tokens[0] while len(result) > 1: left = result.pop(0) operator = result.pop(0) right = result.pop(0) assert left.location, f'expression "{left}" without location' assert right.location, f'expression "{right}" without location' assert left.location.source == right.location.source, "expression with different source" locn = Location(left.location.start, left.location.source, left.location.end) expression: Expr if operator == "+": expression = Add(left, right) expression.location = locn elif operator == "-": expression = Sub(left, right, locn) elif operator == "*": expression = Mul(left, right) expression.location = locn elif operator == "/": expression = Div(left, right, locn) elif operator == "**": expression = Pow(left, right, locn) else: raise ParseFatalException(string, location, "unexpected mathematical operator") result.insert(0, expression) return result[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))))
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)))
def test_private_type_declaration() -> None: string = "type X is private" expected = decl.TypeDeclaration( model.Private("Package::X", location=Location((1, 1), None, (1, 17))) ) actual = parse_formal_declaration(string) assert actual == expected assert actual.location
def test_message_missing_type() -> None: x = Field(ID("X", Location((5, 6)))) structure = [Link(INITIAL, x), Link(x, FINAL)] assert_message_model_error( structure, {}, '^<stdin>:5:6: model: error: missing type for field "X" in "P.M"$', )
def test_array_invalid_element_type() -> None: assert_type_error( Array("P.A", Array("P.B", MODULAR_INTEGER, Location((3, 4))), Location((5, 4))), r'^<stdin>:5:4: model: error: invalid element type of array "A"\n' r'<stdin>:3:4: model: info: type "B" must be scalar or non-null message$', ) assert_type_error( Array("P.A", Message("P.B", [], {}, Location((3, 4))), Location( (5, 4))), r'^<stdin>:5:4: model: error: invalid element type of array "A"\n' r'<stdin>:3:4: model: info: type "B" must be scalar or non-null message$', ) assert_type_error( Array("P.A", OPAQUE, Location((5, 4))), r'^<stdin>:5:4: model: error: invalid element type of array "A"\n' r'__BUILTINS__:0:0: model: info: type "Opaque" must be scalar or non-null message$', )
def test_parsed_field_locations() -> None: p = Parser() p.parse_string( """ package Test is type T is mod 2**8; type M is message F1 : T; F2 : T; end message; end Test; """ ) m = p.create_model() assert m.messages[0].fields == ( Field(ID("F1", Location((6, 21), end=(6, 22)))), Field(ID("F2", Location((7, 21), end=(7, 22)))), )
def test_message_duplicate_link() -> None: t = ModularInteger("P.T", Number(2)) x = Field(ID("X", location=Location((1, 5)))) structure = [ Link(INITIAL, x), Link(x, FINAL, location=Location((4, 42))), Link(x, FINAL, location=Location((5, 42))), ] types = {Field("X"): t} assert_message_model_error( structure, types, f'^<stdin>:1:5: model: error: duplicate link from "X" to "{FINAL.name}"\n' f"<stdin>:4:42: model: info: duplicate link\n" f"<stdin>:5:42: model: info: duplicate link", )