]> err.no Git - dak/commitdiff
Port old tests to unittest; currently 18 failures.
authorChris Lamb <lamby@debian.org>
Sat, 31 Oct 2009 21:35:19 +0000 (21:35 +0000)
committerChris Lamb <lamby@debian.org>
Sat, 31 Oct 2009 23:01:56 +0000 (23:01 +0000)
Signed-off-by: Chris Lamb <lamby@debian.org>
21 files changed:
dak/test/001/test.py [deleted file]
dak/test/002/test.py [deleted file]
dak/test/003/test.py [deleted file]
dak/test/004/test.py [deleted file]
dak/test/005/test.py [deleted file]
dak/test/006/test.py [deleted file]
tests/fixtures/changes/1.changes [moved from dak/test/002/empty.changes with 100% similarity]
tests/fixtures/changes/2.changes [moved from dak/test/003/krb5_1.2.2-4_m68k.changes with 100% similarity]
tests/fixtures/changes/bogus-post.changes [moved from dak/test/005/bogus-post.changes with 100% similarity]
tests/fixtures/changes/bogus-pre.changes [moved from dak/test/005/bogus-pre.changes with 100% similarity]
tests/fixtures/changes/valid.changes [moved from dak/test/005/valid.changes with 100% similarity]
tests/fixtures/dsc/1.dsc [moved from dak/test/001/1.dsc with 100% similarity]
tests/fixtures/dsc/2.dsc [moved from dak/test/001/2.dsc with 100% similarity]
tests/fixtures/dsc/3.dsc [moved from dak/test/001/3.dsc with 100% similarity]
tests/fixtures/dsc/4.dsc [moved from dak/test/001/4.dsc with 100% similarity]
tests/fixtures/dsc/5.dsc [moved from dak/test/001/5.dsc with 100% similarity]
tests/fixtures/dsc/6.dsc [moved from dak/test/001/6.dsc with 100% similarity]
tests/fixtures/dsc/7.dsc [new file with mode: 0644]
tests/test_extract_component_from_section.py [new file with mode: 0755]
tests/test_fix_maintainer.py [new file with mode: 0755]
tests/test_parse_changes.py [new file with mode: 0755]

diff --git a/dak/test/001/test.py b/dak/test/001/test.py
deleted file mode 100644 (file)
index 8238c20..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/env python
-
-# Check utils.parse_changes()'s .dsc file validation
-# Copyright (C) 2000, 2006  James Troup <james@nocrew.org>
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-################################################################################
-
-import os, sys
-
-sys.path.append(os.path.abspath('../../'))
-
-import utils
-
-################################################################################
-
-def fail(message):
-    sys.stderr.write("%s\n" % (message))
-    sys.exit(1)
-
-################################################################################
-
-def main ():
-    # Valid .dsc
-    utils.parse_changes('1.dsc',1)
-
-    # Missing blank line before signature body
-    try:
-        utils.parse_changes('2.dsc',1)
-    except utils.invalid_dsc_format_exc, line:
-        if line != 14:
-            fail("Incorrect line number ('%s') for test #2." % (line))
-    else:
-        fail("Test #2 wasn't recognised as invalid.")
-
-    # Missing blank line after signature header
-    try:
-        utils.parse_changes('3.dsc',1)
-    except utils.invalid_dsc_format_exc, line:
-        if line != 14:
-            fail("Incorrect line number ('%s') for test #3." % (line))
-    else:
-        fail("Test #3 wasn't recognised as invalid.")
-
-    # No blank lines at all
-    try:
-        utils.parse_changes('4.dsc',1)
-    except utils.invalid_dsc_format_exc, line:
-        if line != 19:
-            fail("Incorrect line number ('%s') for test #4." % (line))
-    else:
-        fail("Test #4 wasn't recognised as invalid.")
-
-    # Extra blank line before signature body
-    try:
-        utils.parse_changes('5.dsc',1)
-    except utils.invalid_dsc_format_exc, line:
-        if line != 15:
-            fail("Incorrect line number ('%s') for test #5." % (line))
-    else:
-        fail("Test #5 wasn't recognised as invalid.")
-
-    # Extra blank line after signature header
-    try:
-        utils.parse_changes('6.dsc',1)
-    except utils.invalid_dsc_format_exc, line:
-        if line != 5:
-            fail("Incorrect line number ('%s') for test #6." % (line))
-    else:
-        fail("Test #6 wasn't recognised as invalid.")
-
-    # Valid .dsc ; ignoring errors
-    utils.parse_changes('1.dsc', 0)
-
-    # Invalid .dsc ; ignoring errors
-    utils.parse_changes('2.dsc', 0)
-
-################################################################################
-
-if __name__ == '__main__':
-    main()
diff --git a/dak/test/002/test.py b/dak/test/002/test.py
deleted file mode 100644 (file)
index 919a70a..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env python
-
-# Check utils.parse_changes()'s for handling empty files
-# Copyright (C) 2000, 2006  James Troup <james@nocrew.org>
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-################################################################################
-
-import os, sys
-
-sys.path.append(os.path.abspath('../../'))
-
-import utils
-
-################################################################################
-
-def fail(message):
-    sys.stderr.write("%s\n" % (message))
-    sys.exit(1)
-
-################################################################################
-
-def main ():
-    # Empty .changes file; should raise a 'parse error' exception.
-    try:
-        utils.parse_changes('empty.changes', 0)
-    except utils.changes_parse_error_exc, line:
-        if line != "[Empty changes file]":
-            fail("Returned exception with unexcpected error message `%s'." % (line))
-    else:
-        fail("Didn't raise a 'parse error' exception for a zero-length .changes file.")
-
-################################################################################
-
-if __name__ == '__main__':
-    main()
diff --git a/dak/test/003/test.py b/dak/test/003/test.py
deleted file mode 100755 (executable)
index ce07c11..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-
-# Check utils.parse_changes()'s for handling of multi-line fields
-# Copyright (C) 2000, 2006  James Troup <james@nocrew.org>
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-################################################################################
-
-# The deal here is that for the first 6 months of dak's
-# implementation it has been misparsing multi-line fields in .changes
-# files; specifically multi-line fields where there _is_ data on the
-# first line. So, for example:
-
-# Foo: bar baz
-#  bat bant
-
-# Became "foo: bar bazbat bant" rather than "foo: bar baz\nbat bant"
-
-################################################################################
-
-import os, sys
-
-sys.path.append(os.path.abspath('../../'))
-
-import utils
-
-################################################################################
-
-def fail(message):
-    sys.stderr.write("%s\n" % (message))
-    sys.exit(1)
-
-################################################################################
-
-def main ():
-    # Valid .changes file with a multi-line Binary: field
-    try:
-        changes = utils.parse_changes('krb5_1.2.2-4_m68k.changes', 0)
-    except utils.changes_parse_error_exc, line:
-        fail("parse_changes() returned an exception with error message `%s'." % (line))
-
-    o = changes.get("binary", "")
-    if o != "":
-        del changes["binary"]
-    changes["binary"] = {}
-    for j in o.split():
-        changes["binary"][j] = 1
-
-    if not changes["binary"].has_key("krb5-ftpd"):
-        fail("parse_changes() is broken; 'krb5-ftpd' is not in the Binary: dictionary.")
-
-################################################################################
-
-if __name__ == '__main__':
-    main()
diff --git a/dak/test/004/test.py b/dak/test/004/test.py
deleted file mode 100755 (executable)
index 4aa6b48..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/usr/bin/env python
-
-# Check utils.extract_component_from_section()
-# Copyright (C) 2000, 2006  James Troup <james@nocrew.org>
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-################################################################################
-
-import os, sys
-
-sys.path.append(os.path.abspath('../../'))
-
-import utils
-
-################################################################################
-
-def fail(message):
-    sys.stderr.write("%s\n" % (message))
-    sys.exit(1)
-
-################################################################################
-
-# prefix: non-US
-# component: main, contrib, non-free
-# section: games, admin, libs, [...]
-
-# [1] Order is as above.
-# [2] Prefix is optional for the default archive, but mandatory when
-#     uploads are going anywhere else.
-# [3] Default component is main and may be omitted.
-# [4] Section is optional.
-# [5] Prefix is case insensitive
-# [6] Everything else is case sensitive.
-
-def test(input, output):
-    result = utils.extract_component_from_section(input)
-    if result != output:
-        fail ("%s -> %r [should have been %r]" % (input, result, output))
-
-def main ():
-    # Err, whoops?  should probably be "utils", "main"...
-    input = "main/utils"; output = ("main/utils", "main")
-    test (input, output)
-
-
-    # Validate #3
-    input = "utils"; output = ("utils", "main")
-    test (input, output)
-
-    input = "non-free/libs"; output = ("non-free/libs", "non-free")
-    test (input, output)
-
-    input = "contrib/net"; output = ("contrib/net", "contrib")
-    test (input, output)
-
-
-    # Validate #3 with a prefix
-    input = "non-US"; output = ("non-US", "non-US/main")
-    test (input, output)
-
-
-    # Validate #4
-    input = "main"; output = ("main", "main")
-    test (input, output)
-
-    input = "contrib"; output = ("contrib", "contrib")
-    test (input, output)
-
-    input = "non-free"; output = ("non-free", "non-free")
-    test (input, output)
-
-
-    # Validate #4 with a prefix
-    input = "non-US/main"; output = ("non-US/main", "non-US/main")
-    test (input, output)
-
-    input = "non-US/contrib"; output = ("non-US/contrib", "non-US/contrib")
-    test (input, output)
-
-    input = "non-US/non-free"; output = ("non-US/non-free", "non-US/non-free")
-    test (input, output)
-
-
-    # Validate #5
-    input = "non-us"; output = ("non-us", "non-US/main")
-    test (input, output)
-
-    input = "non-us/contrib"; output = ("non-us/contrib", "non-US/contrib")
-    test (input, output)
-
-
-    # Validate #6 (section)
-    input = "utIls"; output = ("utIls", "main")
-    test (input, output)
-
-    # Others..
-    input = "non-US/libs"; output = ("non-US/libs", "non-US/main")
-    test (input, output)
-    input = "non-US/main/libs"; output = ("non-US/main/libs", "non-US/main")
-    test (input, output)
-    input = "non-US/contrib/libs"; output = ("non-US/contrib/libs", "non-US/contrib")
-    test (input, output)
-    input = "non-US/non-free/libs"; output = ("non-US/non-free/libs", "non-US/non-free")
-    test (input, output)
-
-################################################################################
-
-if __name__ == '__main__':
-    main()
diff --git a/dak/test/005/test.py b/dak/test/005/test.py
deleted file mode 100755 (executable)
index b5d3bbc..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python
-
-# Check utils.parse_changes() correctly ignores data outside the signed area
-# Copyright (C) 2004, 2006  James Troup <james@nocrew.org>
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-################################################################################
-
-import os, sys
-
-sys.path.append(os.path.abspath('../../'))
-
-import utils
-
-################################################################################
-
-def fail(message):
-    sys.stderr.write("%s\n" % (message))
-    sys.exit(1)
-
-################################################################################
-
-def main ():
-    for file in [ "valid", "bogus-pre", "bogus-post" ]:
-        for strict_whitespace in [ 0, 1 ]:
-            try:
-                changes = utils.parse_changes("%s.changes" % (file), strict_whitespace)
-            except utils.changes_parse_error_exc, line:
-                fail("%s[%s]: parse_changes() returned an exception with error message `%s'." % (file, strict_whitespace, line))
-            oh_dear = changes.get("you")
-            if oh_dear:
-                fail("%s[%s]: parsed and accepted unsigned data!" % (file, strict_whitespace))
-
-################################################################################
-
-if __name__ == '__main__':
-    main()
diff --git a/dak/test/006/test.py b/dak/test/006/test.py
deleted file mode 100755 (executable)
index 51a3317..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Test textutils.fix_maintainer()
-# Copyright (C) 2004, 2006  James Troup <james@nocrew.org>
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-################################################################################
-
-import os, sys
-
-sys.path.append(os.path.abspath('../../'))
-
-import textutils
-
-################################################################################
-
-def fail(message):
-    sys.stderr.write("%s\n" % (message))
-    sys.exit(1)
-
-################################################################################
-
-def check_valid(s, xa, xb, xc, xd):
-    (a, b, c, d) = textutils.fix_maintainer(s)
-    if a != xa:
-        fail("rfc822_maint: %s (returned) != %s (expected [From: '%s']" % (a, xa, s))
-    if b != xb:
-        fail("rfc2047_maint: %s (returned) != %s (expected [From: '%s']" % (b, xb, s))
-    if c != xc:
-        fail("name: %s (returned) != %s (expected [From: '%s']" % (c, xc, s))
-    if d != xd:
-        fail("email: %s (returned) != %s (expected [From: '%s']" % (d, xd, s))
-
-def check_invalid(s):
-    try:
-        textutils.fix_maintainer(s)
-        fail("%s was parsed successfully but is expected to be invalid." % (s))
-    except utils.ParseMaintError, unused:
-        pass
-
-def main ():
-    # Check Valid UTF-8 maintainer field
-    s = "Noèl Köthe <noel@debian.org>"
-    xa = "Noèl Köthe <noel@debian.org>"
-    xb = "=?utf-8?b?Tm/DqGwgS8O2dGhl?= <noel@debian.org>"
-    xc = "Noèl Köthe"
-    xd = "noel@debian.org"
-    check_valid(s, xa, xb, xc, xd)
-
-    # Check valid ISO-8859-1 maintainer field
-    s = "Noèl Köthe <noel@debian.org>"
-    xa = "Noèl Köthe <noel@debian.org>"
-    xb = "=?iso-8859-1?q?No=E8l_K=F6the?= <noel@debian.org>"
-    xc = "Noèl Köthe"
-    xd = "noel@debian.org"
-    check_valid(s, xa, xb, xc, xd)
-
-    # Check valid ASCII maintainer field
-    s = "James Troup <james@nocrew.org>"
-    xa = "James Troup <james@nocrew.org>"
-    xb = "James Troup <james@nocrew.org>"
-    xc = "James Troup"
-    xd = "james@nocrew.org"
-    check_valid(s, xa, xb, xc, xd)
-
-    # Check "Debian vs RFC822" fixup of names with '.' or ',' in them
-    s = "James J. Troup <james@nocrew.org>"
-    xa = "james@nocrew.org (James J. Troup)"
-    xb = "james@nocrew.org (James J. Troup)"
-    xc = "James J. Troup"
-    xd = "james@nocrew.org"
-    check_valid(s, xa, xb, xc, xd)
-    s = "James J, Troup <james@nocrew.org>"
-    xa = "james@nocrew.org (James J, Troup)"
-    xb = "james@nocrew.org (James J, Troup)"
-    xc = "James J, Troup"
-    xd = "james@nocrew.org"
-    check_valid(s, xa, xb, xc, xd)
-
-    # Check just-email form
-    s = "james@nocrew.org"
-    xa = " <james@nocrew.org>"
-    xb = " <james@nocrew.org>"
-    xc = ""
-    xd = "james@nocrew.org"
-    check_valid(s, xa, xb, xc, xd)
-
-    # Check bracketed just-email form
-    s = "<james@nocrew.org>"
-    xa = " <james@nocrew.org>"
-    xb = " <james@nocrew.org>"
-    xc = ""
-    xd = "james@nocrew.org"
-    check_valid(s, xa, xb, xc, xd)
-
-    # Check Krazy quoted-string local part email address
-    s = "Cris van Pelt <\"Cris van Pelt\"@tribe.eu.org>"
-    xa = "Cris van Pelt <\"Cris van Pelt\"@tribe.eu.org>"
-    xb = "Cris van Pelt <\"Cris van Pelt\"@tribe.eu.org>"
-    xc = "Cris van Pelt"
-    xd = "\"Cris van Pelt\"@tribe.eu.org"
-    check_valid(s, xa, xb, xc, xd)
-
-    # Check empty string
-    s = xa = xb = xc = xd = ""
-    check_valid(s, xa, xb, xc, xd)
-
-    # Check for missing email address
-    check_invalid("James Troup")
-    # Check for invalid email address
-    check_invalid("James Troup <james@nocrew.org")
-
-################################################################################
-
-if __name__ == '__main__':
-    main()
similarity index 100%
rename from dak/test/001/1.dsc
rename to tests/fixtures/dsc/1.dsc
similarity index 100%
rename from dak/test/001/2.dsc
rename to tests/fixtures/dsc/2.dsc
similarity index 100%
rename from dak/test/001/3.dsc
rename to tests/fixtures/dsc/3.dsc
similarity index 100%
rename from dak/test/001/4.dsc
rename to tests/fixtures/dsc/4.dsc
similarity index 100%
rename from dak/test/001/5.dsc
rename to tests/fixtures/dsc/5.dsc
similarity index 100%
rename from dak/test/001/6.dsc
rename to tests/fixtures/dsc/6.dsc
diff --git a/tests/fixtures/dsc/7.dsc b/tests/fixtures/dsc/7.dsc
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_extract_component_from_section.py b/tests/test_extract_component_from_section.py
new file mode 100755 (executable)
index 0000000..3493f41
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+from base_test import DakTestCase
+
+import unittest
+
+from daklib.utils import extract_component_from_section
+
+class ExtractComponentTestCase(DakTestCase):
+    """
+    prefix: non-US
+    component: main, contrib, non-free
+    section: games, admin, libs, [...]
+
+    [1] Order is as above.
+    [2] Prefix is optional for the default archive, but mandatory when
+        uploads are going anywhere else.
+    [3] Default component is main and may be omitted.
+    [4] Section is optional.
+    [5] Prefix is case insensitive
+    [6] Everything else is case sensitive.
+    """
+
+    def assertExtract(self, input, output):
+        self.assertEqual(
+            extract_component_from_section(input)[1],
+            output,
+        )
+
+    def test_1(self):
+        # Validate #3
+        self.assertExtract('utils', 'main')
+
+    def test_2(self):
+        # Err, whoops?  should probably be 'utils', 'main'...
+        self.assertExtract('main/utils', 'main')
+
+    def test_3(self):
+        self.assertExtract('non-free/libs', 'non-free')
+
+    def test_4(self):
+        self.assertExtract('contrib/net', 'contrib')
+
+    def test_5(self):
+        # Validate #4
+        self.assertExtract('main', 'main')
+
+    def test_6(self):
+        self.assertExtract('contrib', 'contrib')
+
+    def test_7(self):
+        self.assertExtract('non-free', 'non-free')
+
+    def test_8(self):
+        # Validate #6 (section)
+        self.assertExtract('utIls', 'main')
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_fix_maintainer.py b/tests/test_fix_maintainer.py
new file mode 100755 (executable)
index 0000000..203fbfc
--- /dev/null
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from base_test import DakTestCase
+
+import unittest
+
+from daklib.textutils import fix_maintainer
+from daklib.dak_exceptions import ParseMaintError
+
+class FixMaintainerTestCase(DakTestCase):
+    def assertValid(self, input, a, b, c, d):
+        a_, b_, c_, d_ = fix_maintainer(input)
+
+        self.assertEqual(a, a_)
+        self.assertEqual(b, b_)
+        self.assertEqual(c, c_)
+        self.assertEqual(d, d_)
+
+    def assertNotValid(self, input):
+        self.assertRaises(ParseMaintError, lambda: fix_maintainer(input))
+
+    def testUTF8Maintainer(self):
+        # Check Valid UTF-8 maintainer field
+        self.assertValid(
+            "Noèl Köthe <noel@debian.org>",
+            "Noèl Köthe <noel@debian.org>",
+            "=?utf-8?b?Tm/DqGwgS8O2dGhl?= <noel@debian.org>",
+            "Noèl Köthe",
+            "noel@debian.org",
+        )
+
+    def testASCII(self):
+        # Check valid ASCII maintainer field
+        self.assertValid(
+            "James Troup <james@nocrew.org>",
+            "James Troup <james@nocrew.org>",
+            "James Troup <james@nocrew.org>",
+            "James Troup",
+            "james@nocrew.org",
+        )
+
+    def testRFC822(self):
+        # Check "Debian vs RFC822" fixup of names with '.' or ',' in them
+        self.assertValid(
+            "James J. Troup <james@nocrew.org>",
+            "james@nocrew.org (James J. Troup)",
+            "james@nocrew.org (James J. Troup)",
+            "James J. Troup",
+            "james@nocrew.org",
+        )
+
+    def testSimple(self):
+        self.assertValid(
+            "James J, Troup <james@nocrew.org>",
+            "james@nocrew.org (James J, Troup)",
+            "james@nocrew.org (James J, Troup)",
+            "James J, Troup",
+            "james@nocrew.org",
+        )
+
+    def testJustEmail(self):
+        # Check just-email form
+        self.assertValid(
+            "james@nocrew.org",
+            " <james@nocrew.org>",
+            " <james@nocrew.org>",
+            "",
+            "james@nocrew.org",
+        )
+
+    def testBracketedEmail(self):
+        # Check bracketed just-email form
+        self.assertValid(
+            "<james@nocrew.org>",
+            " <james@nocrew.org>",
+            " <james@nocrew.org>",
+            "",
+            "james@nocrew.org",
+        )
+
+    def testKrazy(self):
+        # Check Krazy quoted-string local part email address
+        self.assertValid(
+            "Cris van Pelt <\"Cris van Pelt\"@tribe.eu.org>",
+            "Cris van Pelt <\"Cris van Pelt\"@tribe.eu.org>",
+            "Cris van Pelt <\"Cris van Pelt\"@tribe.eu.org>",
+            "Cris van Pelt",
+            "\"Cris van Pelt\"@tribe.eu.org",
+        )
+
+    def testEmptyString(self):
+        # Check empty string
+        self.assertValid("", "", "", "", "")
+
+    def testMissingEmailAddress(self):
+        # Check for missing email address
+        self.assertNotValid("James Troup")
+
+    def testInvalidEmail(self):
+        # Check for invalid email address
+        self.assertNotValid("James Troup <james@nocrew.org")
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_parse_changes.py b/tests/test_parse_changes.py
new file mode 100755 (executable)
index 0000000..de0202e
--- /dev/null
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+
+from base_test import DakTestCase, fixture
+
+import unittest
+
+from daklib.utils import parse_changes
+from daklib.dak_exceptions import InvalidDscError, ParseChangesError
+
+class ParseChangesTestCase(DakTestCase):
+    def assertParse(self, filename, *args):
+        return parse_changes(fixture(filename), *args)
+
+    def assertFails(self, filename, line=None, *args):
+        try:
+            self.assertParse(filename, *args)
+            self.fail('%s was not recognised as invalid' % filename)
+        except ParseChangesError:
+            pass
+        except InvalidDscError, actual_line:
+            if line is not None:
+                assertEqual(actual_line, line)
+
+class ParseDscTestCase(ParseChangesTestCase):
+    def test_1(self):
+        self.assertParse('dsc/1.dsc')
+
+    def test_1_ignoreErrors(self):
+        # Valid .dsc ; ignoring errors
+        self.assertParse('dsc/1.dsc', 0)
+
+    def test_2(self):
+        # Missing blank line before signature body
+        self.assertFails('dsc/2.dsc', line=14)
+
+    def test_2_ignoreErrors(self):
+        # Invalid .dsc ; ignoring errors
+        self.assertParse('dsc/2.dsc', 0)
+
+    def test_3(self):
+        # Missing blank line after signature header
+        self.assertFails('dsc/3.dsc', line=14)
+
+    def test_4(self):
+        # No blank lines at all
+        self.assertFails('dsc/4.dsc', line=19)
+
+    def test_5(self):
+        # Extra blank line before signature body
+        self.assertFails('dsc/5.dsc', line=15)
+
+    def test_6(self):
+        # Extra blank line after signature header
+        self.assertFails('dsc/6.dsc', line=5)
+
+class ParseChangesTestCase(ParseChangesTestCase):
+    def test_1(self):
+        # Empty changes
+        self.assertFails('changes/1.changes', line=5)
+
+    def test_2(self):
+        changes = self.assertParse('changes/2.changes', 0)
+
+        binaries = changes['binary']
+
+        self.assert_('krb5-ftpd' in binaries.split())
+
+    def test_3(self):
+        for filename in ('valid', 'bogus-pre', 'bogus-post'):
+            for strict_whitespace in (0, 1):
+                changes = self.assertParse(
+                    'changes/%s.changes' % filename,
+                    strict_whitespace,
+                )
+                self.failIf(changes.get('you'))
+
+if __name__ == '__main__':
+    unittest.main()