Просмотр исходного кода

libdpkg: Add initial C unit test suite

Guillem Jover лет назад: 17
Родитель
Сommit
1e7843c247
14 измененных файлов с 702 добавлено и 0 удалено
  1. 14 0
      ChangeLog
  2. 1 0
      configure.ac
  3. 1 0
      debian/changelog
  4. 2 0
      lib/Makefile.am
  5. 70 0
      lib/dpkg-test.h
  6. 7 0
      lib/test/.gitignore
  7. 29 0
      lib/test/Makefile.am
  8. 38 0
      lib/test/t-macros.c
  9. 78 0
      lib/test/t-path.c
  10. 44 0
      lib/test/t-pkginfo.c
  11. 58 0
      lib/test/t-string.c
  12. 45 0
      lib/test/t-test.c
  13. 160 0
      lib/test/t-varbuf.c
  14. 155 0
      lib/test/t-version.c

+ 14 - 0
ChangeLog

@@ -1,3 +1,17 @@
+2009-01-22  Guillem Jover  <guillem@debian.org>
+
+	* configure.ac (AC_CONFIG_FILES): Add 'lib/test/Makefile'.
+	* lib/Makefile.am (SUBDIRS): New variable.
+	* lib/dpkg-test.h: New file.
+	* lib/test/Makefile.am: Likewise.
+	* lib/test/t-macros.c: Likewise.
+	* lib/test/t-path.c: Likewise.
+	* lib/test/t-pkginfo.c: Likewise.
+	* lib/test/t-string.c: Likewise.
+	* lib/test/t-test.c: Likewise.
+	* lib/test/t-varbuf.c: Likewise.
+	* lib/test/t-version.c: Likewise.
+
 2009-01-20  Guillem Jover  <guillem@debian.org>
 
 	* lib/dpkg-db.h (varbufaddbuf): Rename argument l to size.

+ 1 - 0
configure.ac

@@ -110,6 +110,7 @@ AC_CONFIG_FILES([ Makefile
 		  dselect/po/Makefile.in
 		  libcompat/Makefile
 		  lib/Makefile
+		  lib/test/Makefile
 		  man/Makefile
 		  origins/Makefile
 		  po/Makefile.in

+ 1 - 0
debian/changelog

@@ -52,6 +52,7 @@ dpkg (1.15.0) UNRELEASED; urgency=low
     name or a uid. Closes: #368000
   * Add new option --procsched to start-stop-daemon to be able to set the
     process scheduling policy and priority. Closes: #175740
+  * Add initial C unit test suite for libdpkg.
 
   [ Raphael Hertzog ]
   * Enhance dpkg-shlibdeps's error message when a library can't be found to

+ 2 - 0
lib/Makefile.am

@@ -1,5 +1,7 @@
 ## Process this file with automake to produce Makefile.in
 
+SUBDIRS = test
+
 localedir = $(datadir)/locale
 pkgconfdir = $(sysconfdir)/@PACKAGE@
 INCLUDES = \

+ 70 - 0
lib/dpkg-test.h

@@ -0,0 +1,70 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * dpkg-test.h - private test suite support
+ *
+ * Copyright © 2009 Guillem Jover <guillem@debian.org>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DPKG_TEST_H
+#define DPKG_TEST_H
+
+#include <config.h>
+#include <compat.h>
+
+#ifndef TEST_MAIN_PROVIDED
+#include <dpkg.h>
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+/* XXX: Using assert is problematic with NDEBUG. */
+
+#define test_pass(a)			assert((a))
+#define test_fail(a)			assert(!(a))
+#define test_str(a, op, b)		assert(strcmp((a), (b)) op 0)
+#define test_mem(a, op, b, size)	assert(memcmp((a), (b), (size)) op 0)
+
+#ifndef TEST_MAIN_PROVIDED
+static void test(void);
+
+const char thisname[] = "test";
+
+int
+main(int argc, char **argv)
+{
+	jmp_buf ejbuf;
+
+	/* Initialize environment. */
+	if (setjmp(ejbuf)) {
+		error_unwind(ehflag_bombout);
+		return 2;
+	}
+	push_error_handler(&ejbuf, print_error_fatal, NULL);
+
+	test();
+
+	/* Shutdown. */
+	set_error_display(NULL, NULL);
+	error_unwind(ehflag_normaltidy);
+
+	return 0;
+}
+#endif
+
+#endif
+

+ 7 - 0
lib/test/.gitignore

@@ -0,0 +1,7 @@
+t-macros
+t-path
+t-pkginfo
+t-string
+t-test
+t-varbuf
+t-version

+ 29 - 0
lib/test/Makefile.am

@@ -0,0 +1,29 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = \
+	-idirafter $(top_srcdir)/libcompat \
+	-I$(top_srcdir)/lib
+
+
+# The tests are sorted in order of increasing complexity.
+check_PROGRAMS = \
+	t-test \
+	t-macros \
+	t-string \
+	t-path \
+	t-varbuf \
+	t-version \
+	t-pkginfo
+
+CHECK_LDADD = ../libdpkg.a
+
+t_macros_LDADD = $(CHECK_LDADD)
+t_path_LDADD = $(CHECK_LDADD)
+t_pkginfo_LDADD = $(CHECK_LDADD)
+t_string_LDADD = $(CHECK_LDADD)
+t_test_LDADD = $(CHECK_LDADD)
+t_varbuf_LDADD = $(CHECK_LDADD)
+t_version_LDADD = $(CHECK_LDADD)
+
+TESTS = $(check_PROGRAMS)
+

+ 38 - 0
lib/test/t-macros.c

@@ -0,0 +1,38 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * t-macros.c - test C support macros
+ *
+ * Copyright © 2009 Guillem Jover <guillem@debian.org>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <dpkg-test.h>
+#include <dpkg-priv.h>
+
+static void
+test(void)
+{
+	test_pass(min(10, 30) == 10);
+	test_pass(min(30, 10) == 10);
+	test_pass(min(0, 10) == 0);
+	test_pass(min(-10, 0) == -10);
+
+	test_pass(max(10, 30) == 30);
+	test_pass(max(30, 10) == 30);
+	test_pass(max(0, 10) == 10);
+	test_pass(max(-10, 0) == 0);
+}
+

+ 78 - 0
lib/test/t-path.c

@@ -0,0 +1,78 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * t-path.c - test path handling code
+ *
+ * Copyright © 2009 Guillem Jover <guillem@debian.org>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <dpkg-test.h>
+#include <dpkg-priv.h>
+
+#include <stdlib.h>
+
+/* Use the test_trim_eq_ref macro to avoid leaking the string and to get
+ * meaningful line numbers from assert. */
+#define test_trim_eq_ref(p, ref) \
+do { \
+	char *t = strdup((p)); \
+	rtrim_slash_slashdot(t); \
+	test_str(t, ==, (ref)); \
+	free(t); \
+} while (0)
+
+static void
+test_path_rtrim(void)
+{
+	test_trim_eq_ref("./././.", ".");
+	test_trim_eq_ref("./././", ".");
+	test_trim_eq_ref("./.", ".");
+	test_trim_eq_ref("./", ".");
+	test_trim_eq_ref("/./././.", "/");
+	test_trim_eq_ref("/./", "/");
+	test_trim_eq_ref("/.", "/");
+	test_trim_eq_ref("/", "/");
+	test_trim_eq_ref("", "");
+	test_trim_eq_ref("/./../.", "/./..");
+	test_trim_eq_ref("/foo/bar/./", "/foo/bar");
+	test_trim_eq_ref("./foo/bar/./", "./foo/bar");
+	test_trim_eq_ref("/./foo/bar/./", "/./foo/bar");
+}
+
+static void
+test_path_skip(void)
+{
+	test_str(skip_slash_dotslash("./././."), ==, ".");
+	test_str(skip_slash_dotslash("./././"), ==, "");
+	test_str(skip_slash_dotslash("./."), ==, ".");
+	test_str(skip_slash_dotslash("./"), ==, "");
+	test_str(skip_slash_dotslash("/./././."), ==, ".");
+	test_str(skip_slash_dotslash("/./"), ==, "");
+	test_str(skip_slash_dotslash("/."), ==, ".");
+	test_str(skip_slash_dotslash("/"), ==, "");
+	test_str(skip_slash_dotslash("/./../."), ==, "../.");
+	test_str(skip_slash_dotslash("/foo/bar/./"), ==, "foo/bar/./");
+	test_str(skip_slash_dotslash("./foo/bar/./"), ==, "foo/bar/./");
+	test_str(skip_slash_dotslash("/./foo/bar/./"), ==, "foo/bar/./");
+}
+
+static void
+test(void)
+{
+	test_path_rtrim();
+	test_path_skip();
+}
+

+ 44 - 0
lib/test/t-pkginfo.c

@@ -0,0 +1,44 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * t-pkginfo.c - test pkginfo handling
+ *
+ * Copyright © 2009 Guillem Jover <guillem@debian.org>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <dpkg-test.h>
+#include <dpkg-db.h>
+
+static void
+test_pkginfo_informative(void)
+{
+	struct pkginfo pkg;
+
+	blankpackage(&pkg);
+	pkg.want = want_purge;
+	test_pass(informative(&pkg, &pkg.installed));
+
+	/* FIXME: Complete. */
+}
+
+static void
+test(void)
+{
+	test_pkginfo_informative();
+
+	/* FIXME: Complete. */
+}
+

+ 58 - 0
lib/test/t-string.c

@@ -0,0 +1,58 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * t-string.c - test string handling
+ *
+ * Copyright © 2009 Guillem Jover <guillem@debian.org>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <dpkg-test.h>
+#include <dpkg-priv.h>
+
+#include <string.h>
+
+static void
+test_str_escape_fmt(void)
+{
+	char buf[1024], *q;
+
+	memset(buf, sizeof(buf), 'a');
+	q = str_escape_fmt(buf, "");
+	strcpy(q, " end");
+	test_str(buf, ==, " end");
+
+	memset(buf, sizeof(buf), 'a');
+	q = str_escape_fmt(buf, "%");
+	strcpy(q, " end");
+	test_str(buf, ==, "%% end");
+
+	memset(buf, sizeof(buf), 'a');
+	q = str_escape_fmt(buf, "%%%");
+	strcpy(q, " end");
+	test_str(buf, ==, "%%%%%% end");
+
+	memset(buf, sizeof(buf), 'a');
+	q = str_escape_fmt(buf, "%b%b%c%c%%");
+	strcpy(q, " end");
+	test_str(buf, ==, "%%b%%b%%c%%c%%%% end");
+}
+
+static void
+test(void)
+{
+	test_str_escape_fmt();
+}
+

+ 45 - 0
lib/test/t-test.c

@@ -0,0 +1,45 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * t-test.c - test suite self tests
+ *
+ * Copyright © 2009 Guillem Jover <guillem@debian.org>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <dpkg-test.h>
+
+static void
+test(void)
+{
+	test_pass(1);
+	test_fail(0);
+
+	test_str("aaa", ==, "aaa");
+	test_str("aaa", <, "bbb");
+	test_str("ccc", >, "bbb");
+	test_str("ccc", !=, "bbb");
+
+	test_mem("aaa", ==, "aaa", 3);
+	test_mem("aaa", <, "bbb", 3);
+	test_mem("ccc", >, "bbb", 3);
+	test_mem("ccc", !=, "bbb", 3);
+
+	test_mem("abcd", ==, "abcd", 4);
+	test_mem("abcd", ==, "abcd", 5);
+	test_mem("ababcd", ==, "ababff", 4);
+	test_mem("ababcd", !=, "ababff", 6);
+}
+

+ 160 - 0
lib/test/t-varbuf.c

@@ -0,0 +1,160 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * t-verbuf.c - test varbuf implementation
+ *
+ * Copyright © 2009 Guillem Jover <guillem@debian.org>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <dpkg-test.h>
+#include <dpkg-db.h>
+
+static void
+test_varbuf_init(void)
+{
+	struct varbuf vb;
+
+	varbufinit(&vb, 0);
+	test_pass(vb.used == 0);
+	test_pass(vb.size == 0);
+	test_pass(vb.buf == NULL);
+
+	varbuffree(&vb);
+	test_pass(vb.used == 0);
+	test_pass(vb.size == 0);
+	test_pass(vb.buf == NULL);
+}
+
+static void
+test_varbuf_prealloc(void)
+{
+	struct varbuf vb;
+
+	varbufinit(&vb, 10);
+	test_pass(vb.used == 0);
+	test_pass(vb.size >= 10);
+	test_pass(vb.buf != NULL);
+
+	varbuffree(&vb);
+	test_pass(vb.used == 0);
+	test_pass(vb.size == 0);
+	test_pass(vb.buf == NULL);
+}
+
+static void
+test_varbuf_addbuf(void)
+{
+	struct varbuf vb;
+
+	varbufinit(&vb, 5);
+
+	varbufaddbuf(&vb, "1234567890", 10);
+	test_pass(vb.used == 10);
+	test_pass(vb.size >= vb.used);
+	test_mem(vb.buf, ==, "1234567890", 10);
+
+	varbufaddbuf(&vb, "abcde", 5);
+	test_pass(vb.used == 15);
+	test_pass(vb.size >= vb.used);
+	test_mem(vb.buf, ==, "1234567890abcde", 15);
+
+	varbuffree(&vb);
+}
+
+static void
+test_varbuf_addc(void)
+{
+	struct varbuf vb;
+
+	varbufinit(&vb, 1);
+
+	varbufaddc(&vb, 'a');
+	test_pass(vb.used == 1);
+	test_pass(vb.size >= vb.used);
+	test_pass(vb.buf[0] == 'a');
+
+	varbufaddc(&vb, 'b');
+	test_pass(vb.used == 2);
+	test_pass(vb.size >= vb.used);
+	test_mem(vb.buf, ==, "ab", 2);
+
+	varbufaddc(&vb, 'c');
+	test_pass(vb.used == 3);
+	test_pass(vb.size >= vb.used);
+	test_mem(vb.buf, ==, "abc", 3);
+
+	varbufaddc(&vb, 'd');
+	test_pass(vb.used == 4);
+	test_pass(vb.size >= vb.used);
+	test_mem(vb.buf, ==, "abcd", 4);
+
+	varbuffree(&vb);
+}
+
+static void
+test_varbuf_dupc(void)
+{
+	struct varbuf vb;
+
+	varbufinit(&vb, 5);
+
+	varbufdupc(&vb, 'z', 10);
+	test_pass(vb.used == 10);
+	test_pass(vb.size >= vb.used);
+	test_mem(vb.buf, ==, "zzzzzzzzzz", 10);
+
+	varbufdupc(&vb, 'y', 5);
+	test_pass(vb.used == 15);
+	test_pass(vb.size >= vb.used);
+	test_mem(vb.buf, ==, "zzzzzzzzzzyyyyy", 15);
+
+	varbuffree(&vb);
+}
+
+static void
+test_varbuf_reset(void)
+{
+	struct varbuf vb;
+
+	varbufinit(&vb, 10);
+
+	varbufaddbuf(&vb, "1234567890", 10);
+
+	varbufreset(&vb);
+	test_pass(vb.used == 0);
+	test_pass(vb.size >= vb.used);
+
+	varbufaddbuf(&vb, "abcdefghijklmno", 15);
+	test_pass(vb.used == 15);
+	test_pass(vb.size >= vb.used);
+	test_mem(vb.buf, ==, "abcdefghijklmno", 15);
+
+	varbuffree(&vb);
+}
+
+static void
+test(void)
+{
+	test_varbuf_init();
+	test_varbuf_prealloc();
+	test_varbuf_addbuf();
+	test_varbuf_addc();
+	test_varbuf_dupc();
+	test_varbuf_reset();
+
+	/* FIXME: Complete. */
+}
+

+ 155 - 0
lib/test/t-version.c

@@ -0,0 +1,155 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * t-version.c - test version handling
+ *
+ * Copyright © 2009 Guillem Jover <guillem@debian.org>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <dpkg-test.h>
+#include <dpkg-db.h>
+
+#define version(epoch, version, revision) \
+	(struct versionrevision) { (epoch), (version), (revision) }
+
+static void
+test_version_compare(void)
+{
+	struct versionrevision a, b;
+
+	blankversion(&a);
+	blankversion(&b);
+	test_fail(epochsdiffer(&a, &b));
+
+	a.epoch = 1;
+	b.epoch = 2;
+	test_pass(epochsdiffer(&a, &b));
+
+	/* Test for version equality. */
+	a = b = version(0, "0", "0");
+	test_pass(versioncompare(&a, &b) == 0);
+
+	a = version(0, "0", "00");
+	b = version(0, "00", "0");
+	test_pass(versioncompare(&a, &b) == 0);
+
+	a = b = version(1, "2", "3");
+	test_pass(versioncompare(&a, &b) == 0);
+
+	/* Test for epoch difference. */
+	a = version(0, "0", "0");
+	b = version(1, "0", "0");
+	test_pass(versioncompare(&a, &b) < 0);
+	test_pass(versioncompare(&b, &a) > 0);
+
+	/* FIXME: Complete. */
+}
+
+static void
+test_version_parse(void)
+{
+	struct versionrevision a, b;
+
+	/* Test 0 versions. */
+	blankversion(&a);
+	b = version(0, "0", "");
+
+	test_pass(parseversion(&a, "0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	test_pass(parseversion(&a, "0:0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	test_pass(parseversion(&a, "0:0-") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	b = version(0, "0", "0");
+	test_pass(parseversion(&a, "0:0-0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	b = version(0, "0.0", "0.0");
+	test_pass(parseversion(&a, "0:0.0-0.0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	/* Test epoched versions. */
+	b = version(1, "0", "");
+	test_pass(parseversion(&a, "1:0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	b = version(5, "1", "");
+	test_pass(parseversion(&a, "5:1") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	/* Test multiple dashes. */
+	b = version(0, "0-0", "0");
+	test_pass(parseversion(&a, "0:0-0-0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	b = version(0, "0-0-0", "0");
+	test_pass(parseversion(&a, "0:0-0-0-0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	/* Test multiple colons. */
+	b = version(0, "0:0", "0");
+	test_pass(parseversion(&a, "0:0:0-0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	b = version(0, "0:0:0", "0");
+	test_pass(parseversion(&a, "0:0:0:0-0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	/* Test multiple dashes and colons. */
+	b = version(0, "0:0-0", "0");
+	test_pass(parseversion(&a, "0:0:0-0-0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	b = version(0, "0-0:0", "0");
+	test_pass(parseversion(&a, "0:0-0:0-0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	/* Test valid characters in upstream version. */
+	b = version(0, "azAZ09.-+~:", "0");
+	test_pass(parseversion(&a, "0:azAZ09.-+~:-0") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	/* Test valid characters in revision. */
+	b = version(0, "0", "azAZ09.+~");
+	test_pass(parseversion(&a, "0:0-azAZ09.+~") == NULL);
+	test_pass(versioncompare(&a, &b) == 0);
+
+	/* Test invalid characters in epoch. */
+	test_fail(parseversion(&a, "a:0-0") == NULL);
+	test_fail(parseversion(&a, "A:0-0") == NULL);
+
+	/* FIXME: parseversion() should validate input! */
+#if 0
+	/* Test invalid characters in upstream version. */
+	test_fail(parseversion(&a, "0:!#@$%&/|\\<>()[]{};,=*^'-0") == NULL);
+
+	/* Test invalid characters in revision. */
+	test_fail(parseversion(&a, "0:0-!#@$%&/|\\<>()[]{};,=*^'") == NULL);
+#endif
+
+	/* FIXME: Complete. */
+}
+
+static void
+test(void)
+{
+	test_version_compare();
+	test_version_parse();
+}
+