def setUp(self):
     self.validator = Validator()
 def setUp(self):
     self.validator = Validator()
class TestValidator(unittest.TestCase):
    def setUp(self):
        self.validator = Validator()

    def assert_unexpected(self, found, lineno, changelog):
        errors = self.validator.validate(changelog)
        if not errors:
            self.fail("Validator accepted invalid changelog")
        for exobj in errors:
            if isinstance(exobj, Expected):
                if exobj.found != found or exobj.lineno != lineno:
                    raise exobj
                self.assertTrue("unexpected" in str(exobj))
                return
        self.fail("Unexpected %s %s not in errors:\n%s" % (found, lineno,
            "\n".join(str(error) for error in errors)))

    def assert_invalid(self, invalid, missing, lineno, changelog):
        errors = self.validator.validate(changelog)
        if not errors:
            self.fail("Validator accepted invalid changelog")
        for exobj in errors:
            if isinstance(exobj, Invalid):
                if exobj.invalid != invalid or exobj.missing != missing or \
                        exobj.lineno != lineno:
                    raise exobj
                self.assertTrue("Invalid" in str(exobj))
                return
        self.fail("Invalid %s %s %s, not in errors:\n%s" % (invalid, missing,
            lineno, "\n".join(str(error) for error in errors)))

    def test_good_changelog(self):
        self.validator.validate("""\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
- made changes
  some of them were difficult
- made some more changes

* Wed Aug 10 2011 Multiple Part Name <*****@*****.**> - 0.6.0
- transcendent version

* Wed Aug 10 2011 Singlewordname <*****@*****.**> - 0.5.8
- exotic version

* Wed Aug 10 2011 Version with revision <*****@*****.**> - 0.5-1
- initial version
""")

    def test_extra_space_accepted(self):
        self.validator.validate(
"* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1 \n"
"- made changes\n"
"  some of them were difficult  \n"
"- made some more changes\n")

    def test_unexpected_header(self):
        self.assert_unexpected("header", 2, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")

    def test_unexpected_continuation(self):
        self.assert_unexpected("continuation line", 2, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
  made changes
- made some more changes

* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")

    def test_missing_blank(self):
        self.assert_unexpected("header", 3, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
- made changes
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")
        self.assert_unexpected("header", 4, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
- made changes
  some of them were difficult
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")

    def test_missing_body(self):
        self.assert_unexpected("blank", 2, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1

* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")

    def test_unexpected_blank(self):
        self.assert_unexpected("blank", 2, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1

- initial version
""")

    def test_split_body(self):
        self.assert_unexpected("body", 4, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
- made changes

- made some more changes

* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")

    def test_missing_group(self):
        self.assert_invalid("header", None, 1,
            '* Dmitry Rozhkov <*****@*****.**> - 0.6.1')
        self.assert_invalid("header", "author", 1,
            '* Wed Aug 10 2011 <*****@*****.**> - 0.6.1')
        self.assert_invalid("header", "space", 1,
            '* Wed Aug 10 2011 Dmitry Rozhkov<*****@*****.**> - 0.6')
        self.assert_invalid("header", "email", 1,
            '* Wed Aug 10 2011 Dmitry Rozhkov - 0.6.1')
        self.assert_invalid("header", "hyphen", 1,
            '* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> 0.6.1')
        self.assert_invalid("header", "hyphen", 1,
            '* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**>')
        self.assert_invalid("header", "version", 1,
            '* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> -')

    def test_bad_date(self):
        self.assert_invalid("date", None, 1,
            '* Wed Frd 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6')
        self.assert_invalid("date", None, 1,
            '* We Jul 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6')
        self.assert_invalid("date", None, 1,
            '* Jul 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6')
        self.assert_invalid("date", None, 1,
            '* Wed 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6')
        self.assert_invalid("date", None, 1,
            '* Wed Jul 2011 Dmitry Rozhkov <*****@*****.**> - 0.6')
        self.assert_invalid("date", None, 1,
            '* Wed Jul 10 Dmitry Rozhkov <*****@*****.**> - 0.6')
        self.assert_invalid("date", None, 1,
            '* Wed Jul 10 201 Dmitry Rozhkov <*****@*****.**> - 0.6')

    def test_bad_email_ok(self):
        """Email address validation has been relaxed in order to allow
           a variety of anti-spam email obfuscation techniques to work."""
        self.validator.validate(
         '* Wed Aug 10 2011 Dmitry Rozhkov <dmitry[AT]nokia.com> - 1.2')
        self.validator.validate(
         '* Wed Aug 10 2011 Dmitry Rozhkov <dmitry.rozhkov at nokia> - 1.2')

    def test_bad_header(self):
        self.assert_invalid("header", None, 1,
            '* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1 d')

    def test_leading_spaces(self):
        self.assert_unexpected("continuation line", 1,
            ' * Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1')
        self.assert_unexpected("continuation line", 2, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
 - initial version
""")

    def test_unrecoqnized_line(self):
        self.assert_unexpected("garbage", 1,
"""This here is unrecoqnized line
- initial version
""")
class TestValidator(unittest.TestCase):
    def setUp(self):
        self.validator = Validator()

    def assert_unexpected(self, found, lineno, changelog):
        errors = self.validator.validate(changelog)
        if not errors:
            self.fail("Validator accepted invalid changelog")
        for exobj in errors:
            if isinstance(exobj, Expected):
                if exobj.found != found or exobj.lineno != lineno:
                    raise exobj
                self.assertTrue("unexpected" in str(exobj))
                return
        self.fail("Unexpected %s %s not in errors:\n%s" %
                  (found, lineno, "\n".join(str(error) for error in errors)))

    def assert_invalid(self, invalid, missing, lineno, changelog):
        errors = self.validator.validate(changelog)
        if not errors:
            self.fail("Validator accepted invalid changelog")
        for exobj in errors:
            if isinstance(exobj, Invalid):
                if exobj.invalid != invalid or exobj.missing != missing or \
                        exobj.lineno != lineno:
                    raise exobj
                self.assertTrue("Invalid" in str(exobj))
                return
        self.fail("Invalid %s %s %s, not in errors:\n%s" %
                  (invalid, missing, lineno, "\n".join(
                      str(error) for error in errors)))

    def test_good_changelog(self):
        self.validator.validate("""\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
- made changes
  some of them were difficult
- made some more changes

* Wed Aug 10 2011 Multiple Part Name <*****@*****.**> - 0.6.0
- transcendent version

* Wed Aug 10 2011 Singlewordname <*****@*****.**> - 0.5.8
- exotic version

* Wed Aug 10 2011 Version with revision <*****@*****.**> - 0.5-1
- initial version
""")

    def test_extra_space_accepted(self):
        self.validator.validate(
            "* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1 \n"
            "- made changes\n"
            "  some of them were difficult  \n"
            "- made some more changes\n")

    def test_unexpected_header(self):
        self.assert_unexpected(
            "header", 2, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")

    def test_unexpected_continuation(self):
        self.assert_unexpected(
            "continuation line", 2, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
  made changes
- made some more changes

* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")

    def test_missing_blank(self):
        self.assert_unexpected(
            "header", 3, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
- made changes
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")
        self.assert_unexpected(
            "header", 4, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
- made changes
  some of them were difficult
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")

    def test_missing_body(self):
        self.assert_unexpected(
            "blank", 2, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1

* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")

    def test_unexpected_blank(self):
        self.assert_unexpected(
            "blank", 2, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1

- initial version
""")

    def test_split_body(self):
        self.assert_unexpected(
            "body", 4, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
- made changes

- made some more changes

* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.0
- initial version
""")

    def test_missing_group(self):
        self.assert_invalid(
            "header", None, 1,
            '* Dmitry Rozhkov <*****@*****.**> - 0.6.1')
        self.assert_invalid(
            "header", "author", 1,
            '* Wed Aug 10 2011 <*****@*****.**> - 0.6.1')
        self.assert_invalid(
            "header", "space", 1,
            '* Wed Aug 10 2011 Dmitry Rozhkov<*****@*****.**> - 0.6')
        self.assert_invalid("header", "email", 1,
                            '* Wed Aug 10 2011 Dmitry Rozhkov - 0.6.1')
        self.assert_invalid(
            "header", "hyphen", 1,
            '* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> 0.6.1'
        )
        self.assert_invalid(
            "header", "hyphen", 1,
            '* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**>')
        self.assert_invalid(
            "header", "version", 1,
            '* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> -')

    def test_bad_date(self):
        self.assert_invalid(
            "date", None, 1,
            '* Wed Frd 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6'
        )
        self.assert_invalid(
            "date", None, 1,
            '* We Jul 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6')
        self.assert_invalid(
            "date", None, 1,
            '* Jul 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6')
        self.assert_invalid(
            "date", None, 1,
            '* Wed 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6')
        self.assert_invalid(
            "date", None, 1,
            '* Wed Jul 2011 Dmitry Rozhkov <*****@*****.**> - 0.6')
        self.assert_invalid(
            "date", None, 1,
            '* Wed Jul 10 Dmitry Rozhkov <*****@*****.**> - 0.6')
        self.assert_invalid(
            "date", None, 1,
            '* Wed Jul 10 201 Dmitry Rozhkov <*****@*****.**> - 0.6')

    def test_bad_email_ok(self):
        """Email address validation has been relaxed in order to allow
           a variety of anti-spam email obfuscation techniques to work."""
        self.validator.validate(
            '* Wed Aug 10 2011 Dmitry Rozhkov <dmitry[AT]nokia.com> - 1.2')
        self.validator.validate(
            '* Wed Aug 10 2011 Dmitry Rozhkov <dmitry.rozhkov at nokia> - 1.2')

    def test_bad_header(self):
        self.assert_invalid(
            "header", None, 1,
            '* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1 d')

    def test_leading_spaces(self):
        self.assert_unexpected(
            "continuation line", 1,
            ' * Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1')
        self.assert_unexpected(
            "continuation line", 2, """\
* Wed Aug 10 2011 Dmitry Rozhkov <*****@*****.**> - 0.6.1
 - initial version
""")

    def test_unrecoqnized_line(self):
        self.assert_unexpected(
            "garbage", 1, """This here is unrecoqnized line
- initial version
""")