def test_rejects_wrong_type_for_string_attribute(self): ir = _make_ir_from_emb("[(cpp) namespace: 9]\n") attr = ir.module[0].attribute[0] self.assertEqual([[ error.error("m.emb", attr.value.source_location, "Attribute 'namespace' must have a string value.") ]], attribute_checker.normalize_and_verify(ir))
def test_adds_null_byte_order_attributes(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+1] UInt bar\n" " 1 [+1] UInt baz\n" ' [byte_order: "LittleEndian"]\n' " 2 [+2] UInt:8[] baseball\n" " 4 [+2] UInt:8[] bat\n" ' [byte_order: "LittleEndian"]\n') self.assertEqual([], attribute_checker.normalize_and_verify(ir)) structure = ir.module[0].type[0].structure byte_order_attr = ir_util.get_attribute(structure.field[0].attribute, _BYTE_ORDER) self.assertTrue(byte_order_attr.HasField("string_constant")) self.assertEqual("Null", byte_order_attr.string_constant.text) self.assertEqual(structure.field[0].source_location, byte_order_attr.source_location) byte_order_attr = ir_util.get_attribute(structure.field[1].attribute, _BYTE_ORDER) self.assertTrue(byte_order_attr.HasField("string_constant")) self.assertEqual("LittleEndian", byte_order_attr.string_constant.text) byte_order_attr = ir_util.get_attribute(structure.field[2].attribute, _BYTE_ORDER) self.assertTrue(byte_order_attr.HasField("string_constant")) self.assertEqual("Null", byte_order_attr.string_constant.text) self.assertEqual(structure.field[2].source_location, byte_order_attr.source_location) byte_order_attr = ir_util.get_attribute(structure.field[3].attribute, _BYTE_ORDER) self.assertTrue(byte_order_attr.HasField("string_constant")) self.assertEqual("LittleEndian", byte_order_attr.string_constant.text)
def test_rejects_attribute_missing_required_back_end_specifier(self): ir = _make_ir_from_emb('[namespace: "abc"]\n') attr = ir.module[0].attribute[0] self.assertEqual([[ error.error("m.emb", attr.name.source_location, "Unknown attribute 'namespace' on module 'm.emb'.") ]], attribute_checker.normalize_and_verify(ir))
def test_adds_max_bits_attribute(self): ir = _make_ir_from_emb("enum Foo:\n" " ZERO = 0\n") self.assertEqual([], attribute_checker.normalize_and_verify(ir)) enum = ir.module[0].type[0] max_bits_attr = ir_util.get_attribute(enum.attribute, _MAX_BITS) self.assertTrue(max_bits_attr.expression.HasField("constant")) self.assertEqual("64", max_bits_attr.expression.constant.value)
def test_adds_byte_addressable_unit_to_external(self): external_ir = _make_ir_from_emb("external Foo:\n" " [addressable_unit_size: 8]\n") self.assertEqual([], attribute_checker.normalize_and_verify(external_ir)) self.assertEqual(ir_pb2.TypeDefinition.BYTE, external_ir.module[0].type[0].addressable_unit)
def test_rejects_unknown_attribute(self): ir = _make_ir_from_emb("[gibberish: true]\n") attr = ir.module[0].attribute[0] self.assertEqual([[ error.error("m.emb", attr.name.source_location, "Unknown attribute 'gibberish' on module 'm.emb'.") ]], attribute_checker.normalize_and_verify(ir))
def test_adds_true_is_signed_attribute(self): ir = _make_ir_from_emb("enum Foo:\n" " NEGATIVE_ONE = -1\n") self.assertEqual([], attribute_checker.normalize_and_verify(ir)) enum = ir.module[0].type[0] is_signed_attr = ir_util.get_attribute(enum.attribute, _IS_SIGNED) self.assertTrue(is_signed_attr.expression.HasField("boolean_constant")) self.assertTrue(is_signed_attr.expression.boolean_constant.value)
def test_rejects_emboss_internal_attribute_with_back_end_specifier(self): ir = _make_ir_from_emb('[(cpp) byte_order: "LittleEndian"]\n') attr = ir.module[0].attribute[0] self.assertEqual([[ error.error( "m.emb", attr.name.source_location, "Unknown attribute '(cpp) byte_order' on module 'm.emb'.") ]], attribute_checker.normalize_and_verify(ir))
def test_rejects_duplicate_default_attribute(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' '[$default byte_order: "LittleEndian"]\n') self.assertEqual([[ error.error("m.emb", ir.module[0].attribute[1].source_location, "Duplicate attribute 'byte_order'."), error.note("m.emb", ir.module[0].attribute[0].source_location, "Original attribute"), ]], attribute_checker.normalize_and_verify(ir))
def test_does_not_add_fixed_size_attribute_to_variable_size_struct(self): struct_ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " 0 [+4] UInt n\n" " 4 [+n] UInt:8[] payload\n") self.assertEqual([], attribute_checker.normalize_and_verify(struct_ir)) self.assertIsNone( ir_util.get_attribute(struct_ir.module[0].type[0].attribute, _FIXED_SIZE))
def test_disallows_non_string_text_output_attribute(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+2] UInt bar\n" " [text_output: 0]\n") byte_order = ir.module[0].type[0].structure.field[0].attribute[0] self.assertEqual([[ error.error("m.emb", byte_order.value.source_location, "Attribute 'text_output' must be 'Emit' or 'Skip'.") ]], attribute_checker.normalize_and_verify(ir))
def test_requires_byte_order_on_byte_order_dependent_fields(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+2] UInt uint\n") field = ir.module[0].type[0].structure.field[0] self.assertEqual([[ error.error( "m.emb", field.source_location, "Attribute 'byte_order' required on field which is byte order " "dependent.") ]], attribute_checker.normalize_and_verify(ir))
def test_rejects_requires_using_array(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+4] UInt:8[] array\n" " [requires: this]\n") field_ir = ir.module[0].type[0].structure.field[0] self.assertEqual([[ error.error("m.emb", field_ir.attribute[0].value.source_location, "Attribute 'requires' must have a boolean value.") ]], attribute_checker.normalize_and_verify(ir))
def test_disallows_unknown_default_byte_order(self): ir = _make_ir_from_emb('[$default byte_order: "NoEndian"]\n') default_byte_order = ir.module[0].attribute[0] self.assertEqual([[ error.error( "m.emb", default_byte_order.value.source_location, "Attribute 'byte_order' must be 'BigEndian' or 'LittleEndian' or " "'Null'.") ]], attribute_checker.normalize_and_verify(ir))
def test_adds_byte_order_from_scoped_default(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" ' [$default byte_order: "BigEndian"]\n' " 0 [+2] UInt bar\n") self.assertEqual([], attribute_checker.normalize_and_verify(ir)) byte_order_attr = ir_util.get_attribute( ir.module[0].type[0].structure.field[0].attribute, _BYTE_ORDER) self.assertTrue(byte_order_attr.HasField("string_constant")) self.assertEqual("BigEndian", byte_order_attr.string_constant.text)
def test_rejects_may_be_used_as_integer(self): enum_ir = _make_ir_from_emb("enum Foo:\n" " [may_be_used_as_integer: false]\n" " VALUE = 1\n") enum_type_ir = enum_ir.module[0].type[0] self.assertEqual([[ error.error( "m.emb", enum_type_ir.attribute[0].name.source_location, "Unknown attribute 'may_be_used_as_integer' on enum 'Foo'.") ]], attribute_checker.normalize_and_verify(enum_ir))
def test_rejects_external_with_no_addressable_unit_size_attribute(self): external_ir = _make_ir_from_emb("external Foo:\n" " [is_integer: false]\n") external_type_ir = external_ir.module[0].type[0] self.assertEqual([[ error.error( "m.emb", external_type_ir.source_location, "Expected 'addressable_unit_size' attribute for external type." ) ]], attribute_checker.normalize_and_verify(external_ir))
def test_rejects_external_with_wrong_addressable_unit_size_attribute(self): external_ir = _make_ir_from_emb("external Foo:\n" " [addressable_unit_size: 4]\n") external_type_ir = external_ir.module[0].type[0] self.assertEqual([[ error.error( "m.emb", external_type_ir.source_location, "Only values '1' (bit) and '8' (byte) are allowed for the " "'addressable_unit_size' attribute") ]], attribute_checker.normalize_and_verify(external_ir))
def test_disallows_byte_order_on_virtual_field(self): ir = _make_ir_from_emb("struct Foo:\n" " let x = 10\n" ' [byte_order: "LittleEndian"]\n') byte_order = ir.module[0].type[0].structure.field[0].attribute[0] self.assertEqual([[ error.error( "m.emb", byte_order.name.source_location, "Unknown attribute 'byte_order' on virtual struct field 'x'.") ]], attribute_checker.normalize_and_verify(ir))
def test_disallows_default_byte_order_on_enum(self): ir = _make_ir_from_emb("enum Foo:\n" ' [$default byte_order: "LittleEndian"]\n' " BAR = 1\n") default_byte_order = ir.module[0].type[0].attribute[0] self.assertEqual([[ error.error( "m.emb", default_byte_order.name.source_location, "Attribute 'byte_order' may not be defaulted on enum 'Foo'.") ]], attribute_checker.normalize_and_verify(ir))
def test_rejects_too_large_max_bits(self): ir = _make_ir_from_emb("enum Foo:\n" " [maximum_bits: 65]\n" " ZERO = 0\n") attribute_ir = ir.module[0].type[0].attribute[0] self.assertEqual([[ error.error( "m.emb", attribute_ir.value.source_location, "'maximum_bits' on an 'enum' must be between 1 and 64.") ]], error.filter_errors(attribute_checker.normalize_and_verify(ir)))
def test_rejects_non_constant_attribute(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " [fixed_size_in_bits: field1]\n" " 0 [+2] UInt field1\n") attr = ir.module[0].type[0].attribute[0] self.assertEqual([[ error.error( "m.emb", attr.value.source_location, "Attribute 'fixed_size_in_bits' must have a constant value.") ]], attribute_checker.normalize_and_verify(ir))
def test_rejects_is_integer_with_non_constant_value(self): external_ir = _make_ir_from_emb( "external Foo:\n" " [is_integer: $static_size_in_bits == 1]\n" " [addressable_unit_size: 1]\n") external_type_ir = external_ir.module[0].type[0] self.assertEqual([[ error.error( "m.emb", external_type_ir.attribute[0].value.source_location, "Attribute 'is_integer' must have a constant boolean value.") ]], attribute_checker.normalize_and_verify(external_ir))
def test_accepts_correct_size_attribute_on_struct(self): struct_ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " [fixed_size_in_bits: 64]\n" " 0 [+2] UInt field1\n" " 4 [+4] UInt field3\n") self.assertEqual([], attribute_checker.normalize_and_verify(struct_ir)) size_attr = ir_util.get_attribute( struct_ir.module[0].type[0].attribute, _FIXED_SIZE) self.assertTrue(size_attr.expression) self.assertEqual(64, ir_util.constant_value(size_attr.expression))
def test_disallows_unknown_byte_order(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+2] UInt bar\n" ' [byte_order: "NoEndian"]\n') byte_order = ir.module[0].type[0].structure.field[0].attribute[0] self.assertEqual([[ error.error( "m.emb", byte_order.value.source_location, "Attribute 'byte_order' must be 'BigEndian' or 'LittleEndian' or " "'Null'.") ]], attribute_checker.normalize_and_verify(ir))
def test_disallows_null_byte_order_on_multibyte_array_elements(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+4] UInt:16[] uint\n" ' [byte_order: "Null"]\n') byte_order = ir.module[0].type[0].structure.field[0].attribute[0] self.assertEqual([[ error.error( "m.emb", byte_order.value.source_location, "Attribute 'byte_order' may only be 'Null' for one-byte fields." ) ]], attribute_checker.normalize_and_verify(ir))
def test_adds_fixed_size_attribute_to_struct_with_virtual_field(self): struct_ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " 0 [+2] UInt field1\n" " let field2 = field1\n" " 2 [+2] UInt field3\n") self.assertEqual([], attribute_checker.normalize_and_verify(struct_ir)) size_attr = ir_util.get_attribute( struct_ir.module[0].type[0].attribute, _FIXED_SIZE) self.assertEqual(32, ir_util.constant_value(size_attr.expression)) self.assertEqual(struct_ir.module[0].type[0].source_location, size_attr.source_location)
def test_rejects_requires_on_float(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " 0 [+4] Float float\n" " [requires: false]\n") field_ir = ir.module[0].type[0].structure.field[0] self.assertEqual([[ error.error( "m.emb", field_ir.attribute[0].value.source_location, "Attribute 'requires' is only allowed on integer, " "enumeration, or boolean fields.") ]], error.filter_errors(attribute_checker.normalize_and_verify(ir)))
def test_rejects_requires_on_array(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+4] UInt:8[] array\n" " [requires: false]\n") field_ir = ir.module[0].type[0].structure.field[0] self.assertEqual([[ error.error( "m.emb", field_ir.attribute[0].value.source_location, "Attribute 'requires' is only allowed on integer, " "enumeration, or boolean fields, not arrays."), error.note("m.emb", field_ir.type.source_location, "Field type."), ]], error.filter_errors(attribute_checker.normalize_and_verify(ir)))
def test_rejects_duplicate_attribute(self): ir = _make_ir_from_emb("external Foo:\n" " [is_integer: true]\n" " [is_integer: true]\n") self.assertEqual([[ error.error("m.emb", ir.module[0].type[0].attribute[1].source_location, "Duplicate attribute 'is_integer'."), error.note("m.emb", ir.module[0].type[0].attribute[0].source_location, "Original attribute"), ]], attribute_checker.normalize_and_verify(ir))