def test_not_equal__with_field(self):
        for field in self.FIELDS:
            other2 = Field(field.name, "XXX")
            self.assertNotEqual(field.format, other2.format)
            self.assertNotEqual(field, other2)

            other3 = Field("xxx", field.format)
            self.assertNotEqual(field.name, other3.name)
            self.assertNotEqual(field, other3)
 def test_to_string_conversion(self):
     test_data = [
         (Field(), "{}"),
         (Field("name"), "{name}"),
         (Field(format="type"), "{:type}"),
         (Field("name", "type"), "{name:type}"),
     ]
     for field, expected_text in test_data:
         text = str(field)
         self.assertEqual(text, expected_text)
    def test_not_equal__with_string(self):
        for field in self.FIELDS:
            other2 = Field(field.name, "XXX")
            other2_text = str(other2)
            self.assertNotEqual(field.format, other2.format)
            self.assertNotEqual(field, other2_text)

            other3 = Field("xxx", field.format)
            other3_text = str(other3)
            self.assertNotEqual(field.name, other3.name)
            self.assertNotEqual(field, other3_text)
 def test_format_spec__is_lazy_evaluated(self):
     fields = [
         Field(),
         Field("name"),
         Field("name", "type"),
         Field(format="type")
     ]
     for field in fields:
         self.assertIsNone(field._format_spec)
         if field.format:
             _ = field.format_spec.type
             self.assertIsNotNone(field.format_spec)
         else:
             self.assertIsNone(field.format_spec)
    def test_set_format_invalidates_format_spec(self):
        field = Field(format="Number")
        self.assertEqual(field.format, "Number")
        self.assertEqual(field.format_spec.type, "Number")
        self.assertEqual(field.format_spec.align, None)

        field.set_format("<ManyNumbers")
        self.assertEqual(field.format, "<ManyNumbers")
        self.assertEqual(field.format_spec.type, "ManyNumbers")
        self.assertEqual(field.format_spec.align, '<')
    def test_extract_fields__with_many_fields(self):
        MANY_FIELDS_DATA = [
            ("{}xxx{name2}", [Field(), Field("name2")]),
            ("{name1}yyy{:type2}", [Field("name1"),
                                    Field(format="type2")]),
            ("{:type1}xxx{name2}{name3:type3}",
             [Field(format="type1"),
              Field("name2"),
              Field("name3", "type3")]),
        ]
        prefix = "XXX ___"
        suffix = "XXX {{escaped_field}} {{escaped_field:xxx_type}} XXX"

        for field_text, expected_fields in MANY_FIELDS_DATA:
            fields = list(FieldParser.extract_fields(field_text))
            self.assertEqual(len(fields), len(expected_fields))
            self.assertSequenceEqual(fields, expected_fields)

            field_text2 = prefix + field_text + suffix
            fields2 = list(FieldParser.extract_fields(field_text2))
            self.assertEqual(len(fields2), len(expected_fields))
            self.assertSequenceEqual(fields2, expected_fields)
class TestFieldParser(TestCase):
    INVALID_FIELDS = ["", "{", "}", "xxx", "name:type", ":type"]
    VALID_FIELD_DATA = [("{}", Field()), ("{name}", Field("name")),
                        ("{:type}", Field(format="type")),
                        ("{name:type}", Field("name", "type"))]

    #def assertFieldEqual(self, actual, expected):
    #    message = "FAILED: %s == %s" %  (actual, expected)
    #    self.assertIsInstance(actual, Field)
    #    self.assertIsInstance(expected, Field)
    #    self.assertEqual(actual, expected, message)
    #    # self.assertEqual(actual.name,   expected.name, message)
    #    # self.assertEqual(actual.format, expected.format, message)

    def test_parse__raises_error_with_missing_or_partial_braces(self):
        for field_text in self.INVALID_FIELDS:
            with self.assertRaises(ValueError):
                FieldParser.parse(field_text)

    def test_parse__with_valid_fields(self):
        for field_text, expected_field in self.VALID_FIELD_DATA:
            field = FieldParser.parse(field_text)
            self.assertEqual(field, expected_field)

    def test_extract_fields__without_field(self):
        prefix = "XXX ___"
        suffix = "XXX {{escaped_field}} {{escaped_field:xxx_type}} XXX"
        field_texts = [prefix, suffix, prefix + suffix, suffix + prefix]

        for field_text in field_texts:
            fields = list(FieldParser.extract_fields(field_text))
            self.assertEqual(len(fields), 0)

    def test_extract_fields__with_one_field(self):
        prefix = "XXX ___"
        suffix = "XXX {{escaped_field}} {{escaped_field:xxx_type}} XXX"

        for field_text, expected_field in self.VALID_FIELD_DATA:
            fields = list(FieldParser.extract_fields(field_text))
            self.assertEqual(len(fields), 1)
            self.assertSequenceEqual(fields, [expected_field])

            field_text2 = prefix + field_text + suffix
            fields2 = list(FieldParser.extract_fields(field_text2))
            self.assertEqual(len(fields2), 1)
            self.assertSequenceEqual(fields, fields2)

    def test_extract_fields__with_many_fields(self):
        MANY_FIELDS_DATA = [
            ("{}xxx{name2}", [Field(), Field("name2")]),
            ("{name1}yyy{:type2}", [Field("name1"),
                                    Field(format="type2")]),
            ("{:type1}xxx{name2}{name3:type3}",
             [Field(format="type1"),
              Field("name2"),
              Field("name3", "type3")]),
        ]
        prefix = "XXX ___"
        suffix = "XXX {{escaped_field}} {{escaped_field:xxx_type}} XXX"

        for field_text, expected_fields in MANY_FIELDS_DATA:
            fields = list(FieldParser.extract_fields(field_text))
            self.assertEqual(len(fields), len(expected_fields))
            self.assertSequenceEqual(fields, expected_fields)

            field_text2 = prefix + field_text + suffix
            fields2 = list(FieldParser.extract_fields(field_text2))
            self.assertEqual(len(fields2), len(expected_fields))
            self.assertSequenceEqual(fields2, expected_fields)

    def test_extract_types(self):
        MANY_TYPES_DATA = [
            ("{}xxx{name2}", []),
            ("{name1}yyy{:type2}", ["type2"]),
            ("{:type1}xxx{name2}{name3:type3}", ["type1", "type3"]),
        ]

        for field_text, expected_types in MANY_TYPES_DATA:
            type_names = list(FieldParser.extract_types(field_text))
            self.assertEqual(len(type_names), len(expected_types))
            self.assertSequenceEqual(type_names, expected_types)
class TestField(TestCase):
    EMPTY_FORMAT_FIELDS = [
        Field(),  #< Empty field.
        Field("name"),  #< Named field without format.
        Field("name", ""),  #< Named field with format=empty-string.
        Field(format=""),  #< Field with format=empty-string.
    ]
    NONEMPTY_FORMAT_FIELDS = [
        Field(format="Number"),  #< Typed field without name".
        Field("name", "Number"),  #< Named and typed field".
    ]
    INVALID_FORMAT_FIELDS = [
        Field(format="<"),  #< Align without type.
        Field(format="_<"),  #< Fill and align without type.
        Field(format="_<10"),  #< Fill, align and width without type.
        Field(format="_<098"),  #< Fill, align, zero and width without type.
    ]
    FIELDS = EMPTY_FORMAT_FIELDS + NONEMPTY_FORMAT_FIELDS + INVALID_FORMAT_FIELDS

    def test_is_typed__returns_true_for_nonempty_format(self):
        fields = self.NONEMPTY_FORMAT_FIELDS + self.INVALID_FORMAT_FIELDS
        for field in fields:
            self.assertTrue(field.has_format, "Field: %s" % field)

    def test_is_typed__returns_false_for_empty_format(self):
        fields = self.EMPTY_FORMAT_FIELDS
        for field in fields:
            self.assertFalse(field.has_format, "Field: %s" % field)

    def test_format_spec__returns_none_if_format_is_empty(self):
        for field in self.EMPTY_FORMAT_FIELDS:
            self.assertIsNone(field.format_spec, "Field: %s" % field)

    def test_format_spec__if_format_is_nonempty_and_valid(self):
        for field in self.NONEMPTY_FORMAT_FIELDS:
            self.assertIsNotNone(field.format_spec)
            self.assertIsInstance(field.format_spec, FormatSpec)

    def test_format_spec__raises_error_if_nonempty_format_is_invalid(self):
        for field in self.INVALID_FORMAT_FIELDS:
            with self.assertRaises(ValueError):
                field.format_spec

    def test_format_spec__is_lazy_evaluated(self):
        fields = [
            Field(),
            Field("name"),
            Field("name", "type"),
            Field(format="type")
        ]
        for field in fields:
            self.assertIsNone(field._format_spec)
            if field.format:
                _ = field.format_spec.type
                self.assertIsNotNone(field.format_spec)
            else:
                self.assertIsNone(field.format_spec)

    def test_set_format_invalidates_format_spec(self):
        field = Field(format="Number")
        self.assertEqual(field.format, "Number")
        self.assertEqual(field.format_spec.type, "Number")
        self.assertEqual(field.format_spec.align, None)

        field.set_format("<ManyNumbers")
        self.assertEqual(field.format, "<ManyNumbers")
        self.assertEqual(field.format_spec.type, "ManyNumbers")
        self.assertEqual(field.format_spec.align, '<')

    def test_to_string_conversion(self):
        test_data = [
            (Field(), "{}"),
            (Field("name"), "{name}"),
            (Field(format="type"), "{:type}"),
            (Field("name", "type"), "{name:type}"),
        ]
        for field, expected_text in test_data:
            text = str(field)
            self.assertEqual(text, expected_text)

    def test_equal__with_field(self):
        for field in self.FIELDS:
            other = field
            self.assertEqual(field, other)

    def test_equal__with_string(self):
        for field in self.FIELDS:
            other = str(field)
            self.assertEqual(field, other)

    def test_equal__with_unsupported(self):
        UNSUPPORTED_TYPES = [None, make_format_spec(), True, False, 10]
        field = Field()
        for other in UNSUPPORTED_TYPES:
            with self.assertRaises(ValueError):
                field == other

    def test_not_equal__with_field(self):
        for field in self.FIELDS:
            other2 = Field(field.name, "XXX")
            self.assertNotEqual(field.format, other2.format)
            self.assertNotEqual(field, other2)

            other3 = Field("xxx", field.format)
            self.assertNotEqual(field.name, other3.name)
            self.assertNotEqual(field, other3)

    def test_not_equal__with_string(self):
        for field in self.FIELDS:
            other2 = Field(field.name, "XXX")
            other2_text = str(other2)
            self.assertNotEqual(field.format, other2.format)
            self.assertNotEqual(field, other2_text)

            other3 = Field("xxx", field.format)
            other3_text = str(other3)
            self.assertNotEqual(field.name, other3.name)
            self.assertNotEqual(field, other3_text)

    def test_not_equal__with_unsupported(self):
        UNSUPPORTED_TYPES = [None, make_format_spec(), True, False, 10]
        field = Field()
        for other in UNSUPPORTED_TYPES:
            with self.assertRaises(ValueError):
                field != other
 def test_not_equal__with_unsupported(self):
     UNSUPPORTED_TYPES = [None, make_format_spec(), True, False, 10]
     field = Field()
     for other in UNSUPPORTED_TYPES:
         with self.assertRaises(ValueError):
             field != other