diff options
Diffstat (limited to 'lib/dpkg/t')
45 files changed, 5257 insertions, 0 deletions
diff --git a/lib/dpkg/t/b-fsys-hash.c b/lib/dpkg/t/b-fsys-hash.c new file mode 100644 index 0000000..7ae8f9c --- /dev/null +++ b/lib/dpkg/t/b-fsys-hash.c @@ -0,0 +1,81 @@ +/* + * libdpkg - Debian packaging suite library routines + * b-fsys-hash.c - test fsys database load and hash performance + * + * Copyright © 2009-2019 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <stdlib.h> +#include <stdio.h> + +#include <dpkg/i18n.h> +#include <dpkg/dpkg.h> +#include <dpkg/dpkg-db.h> + +#include <dpkg/perf.h> + +#include <dpkg/db-fsys.h> + +static const char *admindir; + +int +main(int argc, const char *const *argv) +{ + struct perf_slot ps; + + push_error_context(); + setvbuf(stdout, NULL, _IONBF, 0); + + admindir = dpkg_db_set_dir(admindir); + + perf_ts_mark_print("init"); + + perf_ts_slot_start(&ps); + fsys_hash_init(); + perf_ts_slot_stop(&ps); + + perf_ts_slot_print(&ps, "fsys_hash_init"); + + perf_ts_slot_start(&ps); + modstatdb_open(msdbrw_readonly | msdbrw_available_readonly); + perf_ts_slot_stop(&ps); + + perf_ts_slot_print(&ps, "modstatdb_init"); + + perf_ts_slot_start(&ps); + ensure_allinstfiles_available_quiet(); + perf_ts_slot_stop(&ps); + + perf_ts_slot_print(&ps, "load .list"); + + if (test_is_verbose()) { + pkg_hash_report(stdout); + fsys_hash_report(stdout); + } + + modstatdb_shutdown(); + pop_error_context(ehflag_normaltidy); + + perf_ts_mark_print("shutdown"); + + return 0; +} diff --git a/lib/dpkg/t/b-pkg-hash.c b/lib/dpkg/t/b-pkg-hash.c new file mode 100644 index 0000000..26cdc12 --- /dev/null +++ b/lib/dpkg/t/b-pkg-hash.c @@ -0,0 +1,65 @@ +/* + * libdpkg - Debian packaging suite library routines + * b-pkg-hash.c - test pkg database load and hash performance + * + * Copyright © 2009-2019 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <stdlib.h> +#include <stdio.h> + +#include <dpkg/i18n.h> +#include <dpkg/dpkg.h> +#include <dpkg/dpkg-db.h> + +#include <dpkg/perf.h> + +static const char *admindir; + +int +main(int argc, const char *const *argv) +{ + struct perf_slot ps; + + push_error_context(); + setvbuf(stdout, NULL, _IONBF, 0); + + admindir = dpkg_db_set_dir(admindir); + + perf_ts_mark_print("init"); + + perf_ts_slot_start(&ps); + modstatdb_open(msdbrw_readonly | msdbrw_available_readonly); + perf_ts_slot_stop(&ps); + + perf_ts_slot_print(&ps, "modstatdb_init"); + + if (test_is_verbose()) + pkg_hash_report(stdout); + + modstatdb_shutdown(); + pop_error_context(ehflag_normaltidy); + + perf_ts_mark_print("shutdown"); + + return 0; +} diff --git a/lib/dpkg/t/c-tarextract.c b/lib/dpkg/t/c-tarextract.c new file mode 100644 index 0000000..882253d --- /dev/null +++ b/lib/dpkg/t/c-tarextract.c @@ -0,0 +1,151 @@ +/* + * libdpkg - Debian packaging suite library routines + * c-tarextract.c - test tar extractor + * + * Copyright © 2014 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <sys/types.h> +#if HAVE_SYS_SYSMACROS_H +#include <sys/sysmacros.h> /* Needed on AIX for major()/minor(). */ +#endif + +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <dpkg/ehandle.h> +#include <dpkg/fdio.h> +#include <dpkg/buffer.h> +#include <dpkg/tarfn.h> + +struct tar_context { + int tar_fd; +}; + +static int +tar_read(struct tar_archive *tar, char *buffer, int size) +{ + struct tar_context *tc = tar->ctx; + + return fd_read(tc->tar_fd, buffer, size); +} + +static int +tar_object_skip(struct tar_archive *tar, struct tar_entry *te) +{ + struct tar_context *tc = tar->ctx; + off_t size; + + size = (te->size + TARBLKSZ - 1) / TARBLKSZ * TARBLKSZ; + if (size == 0) + return 0; + + return fd_skip(tc->tar_fd, size, NULL); +} + +static int +tar_object(struct tar_archive *tar, struct tar_entry *te) +{ + printf("%s mode=%o time=%jd.%.9d uid=%d gid=%d", te->name, + te->stat.mode, te->mtime, 0, te->stat.uid, te->stat.gid); + if (te->stat.uname) + printf(" uname=%s", te->stat.uname); + if (te->stat.gname) + printf(" gname=%s", te->stat.gname); + + switch (te->type) { + case TAR_FILETYPE_FILE0: + case TAR_FILETYPE_FILE: + tar_object_skip(tar, te); + printf(" type=file size=%jd", (intmax_t)te->size); + break; + case TAR_FILETYPE_HARDLINK: + printf(" type=hardlink linkto=%s size=%jd", + te->linkname, (intmax_t)te->size); + break; + case TAR_FILETYPE_SYMLINK: + printf(" type=symlink linkto=%s size=%jd", + te->linkname, (intmax_t)te->size); + break; + case TAR_FILETYPE_DIR: + printf(" type=dir"); + break; + case TAR_FILETYPE_CHARDEV: + case TAR_FILETYPE_BLOCKDEV: + printf(" type=device id=%d.%d", major(te->dev), minor(te->dev)); + break; + case TAR_FILETYPE_FIFO: + printf(" type=fifo"); + break; + default: + ohshit("unexpected tar entry type '%c'", te->type); + } + + printf("\n"); + + return 0; +} + +struct tar_operations tar_ops = { + .read = tar_read, + .extract_file = tar_object, + .link = tar_object, + .symlink = tar_object, + .mkdir = tar_object, + .mknod = tar_object, +}; + +int +main(int argc, char **argv) +{ + struct tar_archive tar; + struct tar_context tar_ctx; + const char *tar_name = argv[1]; + + setvbuf(stdout, NULL, _IOLBF, 0); + + push_error_context(); + + if (tar_name) { + tar_ctx.tar_fd = open(tar_name, O_RDONLY); + if (tar_ctx.tar_fd < 0) + ohshite("cannot open file '%s'", tar_name); + } else { + tar_ctx.tar_fd = STDIN_FILENO; + } + + tar.err = DPKG_ERROR_OBJECT; + tar.ctx = &tar_ctx; + tar.ops = &tar_ops; + + if (tar_extractor(&tar)) + ohshite("extracting tar"); + + dpkg_error_destroy(&tar.err); + + if (tar_name) + close(tar_ctx.tar_fd); + + pop_error_context(ehflag_normaltidy); + + return 0; +} diff --git a/lib/dpkg/t/c-treewalk.c b/lib/dpkg/t/c-treewalk.c new file mode 100644 index 0000000..4cd2b8c --- /dev/null +++ b/lib/dpkg/t/c-treewalk.c @@ -0,0 +1,132 @@ +/* + * libdpkg - Debian packaging suite library routines + * c-treewalk.c - test tree walk implementation + * + * Copyright © 2013-2016 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include <dpkg/ehandle.h> +#include <dpkg/treewalk.h> + +static int +treenode_type(struct treenode *node) +{ + switch (treenode_get_mode(node) & S_IFMT) { + case S_IFREG: + return 'f'; + case S_IFDIR: + return 'd'; + case S_IFLNK: + return 'l'; + case S_IFIFO: + return 'p'; + case S_IFBLK: + return 'b'; + case S_IFCHR: + return 'c'; + case S_IFSOCK: + return 's'; + default: + return '?'; + } +} + +static int +treenode_visit_meta(struct treenode *node) +{ + printf("T=%c N=%s V=%s R=%s\n", + treenode_type(node), treenode_get_name(node), + treenode_get_virtname(node), treenode_get_pathname(node)); + + return 0; +} + +static int +treenode_visit_virt(struct treenode *node) +{ + printf("%s\n", treenode_get_virtname(node)); + + return 0; +} + +static int +treenode_visit_path(struct treenode *node) +{ + printf("%s\n", treenode_get_pathname(node)); + + return 0; +} + +static const char *skipname; + +static bool +treenode_skip(struct treenode *node) +{ + const char *absname = treenode_get_pathname(node); + + if (strcmp(absname, skipname) == 0) + return true; + + return false; +} + +static void +test_treewalk_list(const char *rootdir) +{ + const char *visitname = getenv("TREEWALK_VISIT"); + struct treewalk_funcs funcs = { NULL }; + + if (visitname == NULL || strcmp(visitname, "meta") == 0) + funcs.visit = treenode_visit_meta; + else if (strcmp(visitname, "virt") == 0) + funcs.visit = treenode_visit_virt; + else if (strcmp(visitname, "path") == 0) + funcs.visit = treenode_visit_path; + else + ohshit("unknown treewalk visit name"); + + skipname = getenv("TREEWALK_SKIP"); + if (skipname) + funcs.skip = treenode_skip; + + treewalk(rootdir, 0, &funcs); +} + +int +main(int argc, char **argv) +{ + const char *rootdir = argv[1]; + + setvbuf(stdout, NULL, _IOLBF, 0); + + push_error_context(); + + if (rootdir == NULL) + ohshit("missing treewalk root dir"); + + test_treewalk_list(rootdir); + + pop_error_context(ehflag_normaltidy); + + return 0; +} diff --git a/lib/dpkg/t/c-trigdeferred.c b/lib/dpkg/t/c-trigdeferred.c new file mode 100644 index 0000000..5c21ea3 --- /dev/null +++ b/lib/dpkg/t/c-trigdeferred.c @@ -0,0 +1,96 @@ +/* + * libdpkg - Debian packaging suite library routines + * c-trigdeferred.c - test triggered deferred file parser + * + * Copyright © 2016 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include <dpkg/dpkg-db.h> +#include <dpkg/ehandle.h> +#include <dpkg/trigdeferred.h> + +static void +test_tdm_begin(const char *trig) +{ + printf("<T='%s'", trig); +} + +static void +test_tdm_package(const char *awname) +{ + printf(" P='%s'", awname); +} + +static void +test_tdm_end(void) +{ + printf(" E>\n"); +} + +static const struct trigdefmeths test_tdm = { + .trig_begin = test_tdm_begin, + .package = test_tdm_package, + .trig_end = test_tdm_end, +}; + +static int +test_trigdeferred_parser(const char *admindir) +{ + enum trigdef_update_flags tduf; + enum trigdef_update_status tdus; + + dpkg_db_set_dir(admindir); + + trigdef_set_methods(&test_tdm); + + tduf = TDUF_NO_LOCK | TDUF_WRITE_IF_EMPTY | TDUF_WRITE_IF_ENOENT; + tdus = trigdef_update_start(tduf); + if (tdus < TDUS_OK) + return -tdus + TDUS_OK; + + trigdef_parse(); + + trigdef_process_done(); + + return 0; +} + +int +main(int argc, char **argv) +{ + const char *admindir = argv[1]; + int ret; + + setvbuf(stdout, NULL, _IOLBF, 0); + + push_error_context(); + + if (admindir == NULL) + ohshit("missing triggers deferred admindir"); + + ret = test_trigdeferred_parser(admindir); + + pop_error_context(ehflag_normaltidy); + + return ret; +} diff --git a/lib/dpkg/t/data/meminfo-no-data b/lib/dpkg/t/data/meminfo-no-data new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/dpkg/t/data/meminfo-no-data diff --git a/lib/dpkg/t/data/meminfo-no-info b/lib/dpkg/t/data/meminfo-no-info new file mode 100644 index 0000000..e54196b --- /dev/null +++ b/lib/dpkg/t/data/meminfo-no-info @@ -0,0 +1,52 @@ +MemTotal: 3951508 kB +MemFree: 130976 kB +MemAvailable: 10584 kB +Buffers: 2448 kB +SwapCached: 12936 kB +Active: 3111920 kB +Inactive: 610376 kB +Active(anon): 3102668 kB +Inactive(anon): 606952 kB +Active(file): 9252 kB +Inactive(file): 3424 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 4194300 kB +SwapFree: 3777400 kB +Zswap: 0 kB +Zswapped: 0 kB +Dirty: 0 kB +Writeback: 0 kB +AnonPages: 12960 kB +Mapped: 6700 kB +Shmem: 3684416 kB +KReclaimable: 27616 kB +Slab: 54652 kB +SReclaimable: 27616 kB +SUnreclaim: 27036 kB +KernelStack: 2496 kB +PageTables: 1516 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 6170052 kB +Committed_AS: 4212940 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 16116 kB +VmallocChunk: 0 kB +Percpu: 2288 kB +HardwareCorrupted: 0 kB +AnonHugePages: 0 kB +ShmemHugePages: 0 kB +ShmemPmdMapped: 0 kB +FileHugePages: 0 kB +FilePmdMapped: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +Hugetlb: 0 kB +DirectMap4k: 110452 kB +DirectMap2M: 5132288 kB +DirectMap1G: 5242880 kB diff --git a/lib/dpkg/t/data/meminfo-no-unit b/lib/dpkg/t/data/meminfo-no-unit new file mode 100644 index 0000000..4db2d9c --- /dev/null +++ b/lib/dpkg/t/data/meminfo-no-unit @@ -0,0 +1,53 @@ +MemTotal: 3951508 +MemFree: 130976 +MemAvailable: 10584 +Buffers: 2448 +Cached: 3694676 +SwapCached: 12936 +Active: 3111920 +Inactive: 610376 +Active(anon): 3102668 +Inactive(anon): 606952 +Active(file): 9252 +Inactive(file): 3424 +Unevictable: 0 +Mlocked: 0 +SwapTotal: 4194300 +SwapFree: 3777400 +Zswap: 0 +Zswapped: 0 +Dirty: 0 +Writeback: 0 +AnonPages: 12960 +Mapped: 6700 +Shmem: 3684416 +KReclaimable: 27616 +Slab: 54652 +SReclaimable: 27616 +SUnreclaim: 27036 +KernelStack: 2496 +PageTables: 1516 +NFS_Unstable: 0 +Bounce: 0 +WritebackTmp: 0 +CommitLimit: 6170052 +Committed_AS: 4212940 +VmallocTotal: 34359738367 +VmallocUsed: 16116 +VmallocChunk: 0 +Percpu: 2288 +HardwareCorrupted: 0 +AnonHugePages: 0 +ShmemHugePages: 0 +ShmemPmdMapped: 0 +FileHugePages: 0 +FilePmdMapped: 0 +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 +Hugetlb: 0 +DirectMap4k: 110452 +DirectMap2M: 5132288 +DirectMap1G: 5242880 diff --git a/lib/dpkg/t/data/meminfo-ok b/lib/dpkg/t/data/meminfo-ok new file mode 100644 index 0000000..d4fdf0b --- /dev/null +++ b/lib/dpkg/t/data/meminfo-ok @@ -0,0 +1,53 @@ +MemTotal: 3951508 kB +MemFree: 130976 kB +MemAvailable: 10584 kB +Buffers: 2448 kB +Cached: 3694676 kB +SwapCached: 12936 kB +Active: 3111920 kB +Inactive: 610376 kB +Active(anon): 3102668 kB +Inactive(anon): 606952 kB +Active(file): 9252 kB +Inactive(file): 3424 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 4194300 kB +SwapFree: 3777400 kB +Zswap: 0 kB +Zswapped: 0 kB +Dirty: 0 kB +Writeback: 0 kB +AnonPages: 12960 kB +Mapped: 6700 kB +Shmem: 3684416 kB +KReclaimable: 27616 kB +Slab: 54652 kB +SReclaimable: 27616 kB +SUnreclaim: 27036 kB +KernelStack: 2496 kB +PageTables: 1516 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 6170052 kB +Committed_AS: 4212940 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 16116 kB +VmallocChunk: 0 kB +Percpu: 2288 kB +HardwareCorrupted: 0 kB +AnonHugePages: 0 kB +ShmemHugePages: 0 kB +ShmemPmdMapped: 0 kB +FileHugePages: 0 kB +FilePmdMapped: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +Hugetlb: 0 kB +DirectMap4k: 110452 kB +DirectMap2M: 5132288 kB +DirectMap1G: 5242880 kB diff --git a/lib/dpkg/t/t-ar.c b/lib/dpkg/t/t-ar.c new file mode 100644 index 0000000..88e9387 --- /dev/null +++ b/lib/dpkg/t/t-ar.c @@ -0,0 +1,61 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-ar.c - test ar implementation + * + * Copyright © 2010 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <string.h> + +#include <dpkg/test.h> +#include <dpkg/ar.h> + +static void +test_ar_normalize_name(void) +{ + struct dpkg_ar_hdr arh; + + memccpy(arh.ar_name, "member-name/ ", '\0', sizeof(arh.ar_name)); + dpkg_ar_normalize_name(&arh); + test_str(arh.ar_name, ==, "member-name"); + + memccpy(arh.ar_name, "member-name ", '\0', sizeof(arh.ar_name)); + dpkg_ar_normalize_name(&arh); + test_str(arh.ar_name, ==, "member-name"); +} + +static void +test_ar_member_is_illegal(void) +{ + struct dpkg_ar_hdr arh; + + memset(&arh, ' ', sizeof(arh)); + test_pass(dpkg_ar_member_is_illegal(&arh)); + + memcpy(arh.ar_fmag, DPKG_AR_FMAG, sizeof(arh.ar_fmag)); + test_fail(dpkg_ar_member_is_illegal(&arh)); +} + +TEST_ENTRY(test) +{ + test_plan(4); + + test_ar_normalize_name(); + test_ar_member_is_illegal(); +} diff --git a/lib/dpkg/t/t-arch.c b/lib/dpkg/t/t-arch.c new file mode 100644 index 0000000..430980e --- /dev/null +++ b/lib/dpkg/t/t-arch.c @@ -0,0 +1,225 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-arch.c - test dpkg_arch implementation + * + * Copyright © 2011 Linaro Limited + * Copyright © 2011 Raphaël Hertzog <hertzog@debian.org> + * Copyright © 2011-2014 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/varbuf.h> +#include <dpkg/arch.h> + +static void +test_dpkg_arch_name_is_illegal(void) +{ + /* Test invalid architecture names. */ + test_fail(dpkg_arch_name_is_illegal("") == NULL); + test_fail(dpkg_arch_name_is_illegal("-i386") == NULL); + test_fail(dpkg_arch_name_is_illegal(" i386") == NULL); + test_fail(dpkg_arch_name_is_illegal(":any") == NULL); + test_fail(dpkg_arch_name_is_illegal("amd64_test") == NULL); + test_fail(dpkg_arch_name_is_illegal("i386:test") == NULL); + test_fail(dpkg_arch_name_is_illegal("i386 amd64") == NULL); + test_fail(dpkg_arch_name_is_illegal("i386,amd64") == NULL); + test_fail(dpkg_arch_name_is_illegal("i386|amd64") == NULL); + + /* Test valid architecture names. */ + test_pass(dpkg_arch_name_is_illegal("i386") == NULL); + test_pass(dpkg_arch_name_is_illegal("amd64") == NULL); + test_pass(dpkg_arch_name_is_illegal("hurd-i386") == NULL); + test_pass(dpkg_arch_name_is_illegal("kfreebsd-i386") == NULL); + test_pass(dpkg_arch_name_is_illegal("kfreebsd-amd64") == NULL); + test_pass(dpkg_arch_name_is_illegal("ia64") == NULL); + test_pass(dpkg_arch_name_is_illegal("alpha") == NULL); + test_pass(dpkg_arch_name_is_illegal("armel") == NULL); + test_pass(dpkg_arch_name_is_illegal("hppa") == NULL); + test_pass(dpkg_arch_name_is_illegal("mips") == NULL); + test_pass(dpkg_arch_name_is_illegal("mipsel") == NULL); + test_pass(dpkg_arch_name_is_illegal("powerpc") == NULL); + test_pass(dpkg_arch_name_is_illegal("s390") == NULL); + test_pass(dpkg_arch_name_is_illegal("sparc") == NULL); +} + +static void +test_dpkg_arch_get_list(void) +{ + struct dpkg_arch *arch; + int count = 1; + + /* Must never return NULL. */ + arch = dpkg_arch_get_list(); + test_alloc(arch); + + while ((arch = arch->next)) + count++; + + /* The default list should contain 3 architectures. */ + test_pass(count == 3); +} + +static void +test_dpkg_arch_find(void) +{ + struct dpkg_arch *arch; + + /* Test existence and initial values of default architectures. */ + arch = dpkg_arch_find("all"); + test_pass(arch->type == DPKG_ARCH_ALL); + test_pass(dpkg_arch_get(DPKG_ARCH_ALL) == arch); + arch = dpkg_arch_find(ARCHITECTURE); + test_pass(arch->type == DPKG_ARCH_NATIVE); + test_pass(dpkg_arch_get(DPKG_ARCH_NATIVE) == arch); + arch = dpkg_arch_find("any"); + test_pass(arch->type == DPKG_ARCH_WILDCARD); + test_pass(dpkg_arch_get(DPKG_ARCH_WILDCARD) == arch); + + /* Test missing architecture. */ + arch = dpkg_arch_find(NULL); + test_pass(arch->type == DPKG_ARCH_NONE); + test_pass(dpkg_arch_get(DPKG_ARCH_NONE) == arch); + test_str(arch->name, ==, ""); + + /* Test empty architectures. */ + arch = dpkg_arch_find(""); + test_pass(arch->type == DPKG_ARCH_EMPTY); + test_pass(dpkg_arch_get(DPKG_ARCH_EMPTY) == arch); + test_str(arch->name, ==, ""); + + /* Test for an unknown type. */ + test_pass(dpkg_arch_get(1000) == NULL); + + /* New valid architectures are marked unknown. */ + arch = dpkg_arch_find("foobar"); + test_pass(arch->type == DPKG_ARCH_UNKNOWN); + test_str(arch->name, ==, "foobar"); + + /* New illegal architectures are marked illegal. */ + arch = dpkg_arch_find("a:b"); + test_pass(arch->type == DPKG_ARCH_ILLEGAL); + test_str(arch->name, ==, "a:b"); +} + +static void +test_dpkg_arch_reset_list(void) +{ + dpkg_arch_reset_list(); + + test_dpkg_arch_get_list(); +} + +static void +test_dpkg_arch_modify(void) +{ + struct dpkg_arch *arch; + + dpkg_arch_reset_list(); + + /* Insert a new unknown arch. */ + arch = dpkg_arch_find("foo"); + test_pass(arch->type == DPKG_ARCH_UNKNOWN); + test_str(arch->name, ==, "foo"); + + /* Check that existing unknown arch gets tagged. */ + arch = dpkg_arch_add("foo"); + test_pass(arch->type == DPKG_ARCH_FOREIGN); + test_str(arch->name, ==, "foo"); + + /* Check that new unknown arch gets tagged. */ + arch = dpkg_arch_add("quux"); + test_pass(arch->type == DPKG_ARCH_FOREIGN); + test_str(arch->name, ==, "quux"); + + /* Unmark foreign architectures. */ + + arch = dpkg_arch_find("foo"); + dpkg_arch_unmark(arch); + test_pass(arch->type == DPKG_ARCH_UNKNOWN); + + arch = dpkg_arch_find("bar"); + dpkg_arch_unmark(arch); + test_pass(arch->type == DPKG_ARCH_UNKNOWN); + + arch = dpkg_arch_find("quux"); + dpkg_arch_unmark(arch); + test_pass(arch->type == DPKG_ARCH_UNKNOWN); +} + +static void +test_dpkg_arch_varbuf_archqual(void) +{ + struct varbuf vb = VARBUF_INIT; + + varbuf_add_archqual(&vb, dpkg_arch_get(DPKG_ARCH_NONE)); + varbuf_end_str(&vb); + test_str(vb.buf, ==, ""); + varbuf_reset(&vb); + + varbuf_add_archqual(&vb, dpkg_arch_get(DPKG_ARCH_EMPTY)); + varbuf_end_str(&vb); + test_str(vb.buf, ==, ""); + varbuf_reset(&vb); + + varbuf_add_archqual(&vb, dpkg_arch_get(DPKG_ARCH_ALL)); + varbuf_end_str(&vb); + test_str(vb.buf, ==, ":all"); + varbuf_reset(&vb); + + varbuf_add_archqual(&vb, dpkg_arch_get(DPKG_ARCH_WILDCARD)); + varbuf_end_str(&vb); + test_str(vb.buf, ==, ":any"); + varbuf_reset(&vb); + + varbuf_destroy(&vb); +} + +static void +test_dpkg_arch_describe(void) +{ + struct dpkg_arch *arch; + + arch = dpkg_arch_get(DPKG_ARCH_NONE); + test_str(dpkg_arch_describe(arch), ==, "<none>"); + + arch = dpkg_arch_get(DPKG_ARCH_EMPTY); + test_str(dpkg_arch_describe(arch), ==, "<empty>"); + + arch = dpkg_arch_get(DPKG_ARCH_ALL); + test_str(dpkg_arch_describe(arch), ==, "all"); + + arch = dpkg_arch_get(DPKG_ARCH_WILDCARD); + test_str(dpkg_arch_describe(arch), ==, "any"); + + arch = dpkg_arch_get(DPKG_ARCH_NATIVE); + test_str(dpkg_arch_describe(arch), ==, ARCHITECTURE); +} + +TEST_ENTRY(test) +{ + test_plan(60); + + test_dpkg_arch_name_is_illegal(); + test_dpkg_arch_get_list(); + test_dpkg_arch_find(); + test_dpkg_arch_reset_list(); + test_dpkg_arch_modify(); + test_dpkg_arch_varbuf_archqual(); + test_dpkg_arch_describe(); +} diff --git a/lib/dpkg/t/t-buffer.c b/lib/dpkg/t/t-buffer.c new file mode 100644 index 0000000..fa939e5 --- /dev/null +++ b/lib/dpkg/t/t-buffer.c @@ -0,0 +1,82 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-buffer.c - test buffer handling + * + * Copyright © 2009-2011 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/buffer.h> +#include <dpkg/dpkg.h> + +#include <sys/types.h> + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +static const char str_empty[] = ""; +static const char ref_hash_empty[] = "d41d8cd98f00b204e9800998ecf8427e"; +static const char str_test[] = "this is a test string\n"; +static const char ref_hash_test[] = "475aae3b885d70a9130eec23ab33f2b9"; + +static void +test_buffer_hash(void) +{ + char hash[MD5HASHLEN + 1]; + + buffer_md5(str_empty, hash, strlen(str_empty)); + test_str(hash, ==, ref_hash_empty); + + buffer_md5(str_test, hash, strlen(str_test)); + test_str(hash, ==, ref_hash_test); +} + +static void +test_fdio_hash(void) +{ + char hash[MD5HASHLEN + 1]; + char *test_file; + int fd; + + test_file = test_alloc(strdup("test.XXXXXX")); + fd = mkstemp(test_file); + test_pass(fd >= 0); + + test_pass(fd_md5(fd, hash, -1, NULL) >= 0); + test_str(hash, ==, ref_hash_empty); + + test_pass(write(fd, str_test, strlen(str_test)) == (ssize_t)strlen(str_test)); + test_pass(lseek(fd, 0, SEEK_SET) == 0); + + test_pass(fd_md5(fd, hash, -1, NULL) >= 0); + test_str(hash, ==, ref_hash_test); + + test_pass(unlink(test_file) == 0); + + free(test_file); +} + +TEST_ENTRY(test) +{ + test_plan(10); + + test_buffer_hash(); + test_fdio_hash(); +} diff --git a/lib/dpkg/t/t-c-ctype.c b/lib/dpkg/t/t-c-ctype.c new file mode 100644 index 0000000..2da0553 --- /dev/null +++ b/lib/dpkg/t/t-c-ctype.c @@ -0,0 +1,106 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-c-ctype.c - test C locale ctype functions + * + * Copyright © 2009-2014 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/c-ctype.h> + +static void +test_ctype(void) +{ + int c; + + for (c = -1; c < 256; c++) { + /* Test blank. */ + if (c == '\t' || c == ' ') + test_pass(c_isblank(c)); + else + test_fail(c_isblank(c)); + + /* Test white. */ + if (c == '\t' || c == ' ' || c == '\n') + test_pass(c_iswhite(c)); + else + test_fail(c_iswhite(c)); + + /* Test space. */ + if (c == '\t' || c == '\v' || c == '\f' || + c == '\r' || c == '\n' || c == ' ') + test_pass(c_isspace(c)); + else + test_fail(c_isspace(c)); + + /* Test digit. */ + if (c >= '0' && c <= '9') + test_pass(c_isdigit(c)); + else + test_fail(c_isdigit(c)); + + /* Test lower case. */ + if (c >= 'a' && c <= 'z') + test_pass(c_islower(c)); + else + test_fail(c_islower(c)); + + /* Test upper case. */ + if (c >= 'A' && c <= 'Z') + test_pass(c_isupper(c)); + else + test_fail(c_isupper(c)); + + /* Test alpha. */ + if (c_islower(c) || c_isupper(c)) + test_pass(c_isalpha(c)); + else + test_fail(c_isalpha(c)); + + /* Test alphanumeric. */ + if (c_isdigit(c) || c_isalpha(c)) + test_pass(c_isalnum(c)); + else + test_fail(c_isalnum(c)); + } +} + +static void +test_casing(void) +{ + test_pass(c_tolower('A') == 'a'); + test_pass(c_tolower('Z') == 'z'); + + test_pass(c_tolower('a') == 'a'); + test_pass(c_tolower('z') == 'z'); + + test_pass(c_tolower('0') == '0'); + test_pass(c_tolower('9') == '9'); + + /* Test if we can handle the value for EOF. */ + test_pass(c_tolower(-1) == -1); +} + +TEST_ENTRY(test) +{ + test_plan(2063); + + test_ctype(); + test_casing(); +} diff --git a/lib/dpkg/t/t-command.c b/lib/dpkg/t/t-command.c new file mode 100644 index 0000000..33e002e --- /dev/null +++ b/lib/dpkg/t/t-command.c @@ -0,0 +1,225 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-command.c - test command implementation + * + * Copyright © 2010-2012 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> + +#include <dpkg/test.h> +#include <dpkg/subproc.h> +#include <dpkg/command.h> +#include <dpkg/dpkg.h> + +static void +test_command_init(void) +{ + struct command cmd; + + command_init(&cmd, "/absolute/path/to/progname", NULL); + test_str(cmd.filename, ==, "/absolute/path/to/progname"); + test_str(cmd.name, ==, "progname"); + test_pass(cmd.argc == 0); + test_pass(cmd.argv[0] == NULL); + + command_destroy(&cmd); + test_pass(cmd.filename == NULL); + test_pass(cmd.name == NULL); + test_pass(cmd.argc == 0); + test_pass(cmd.argv == NULL); + + command_init(&cmd, "progname", NULL); + test_str(cmd.filename, ==, "progname"); + test_str(cmd.name, ==, "progname"); + test_pass(cmd.argc == 0); + test_pass(cmd.argv[0] == NULL); + + command_destroy(&cmd); + + command_init(&cmd, "progname", "description"); + test_str(cmd.filename, ==, "progname"); + test_str(cmd.name, ==, "description"); + test_pass(cmd.argc == 0); + test_pass(cmd.argv[0] == NULL); + + command_destroy(&cmd); +} + +static void +test_command_grow_argv(void) +{ + struct command cmd; + int argv_size, i; + + command_init(&cmd, "test", NULL); + + argv_size = cmd.argv_size + 4; + for (i = 0; i < argv_size; i++) + command_add_arg(&cmd, "arg"); + + test_pass(cmd.argc == argv_size); + test_pass(cmd.argv_size >= argv_size); + test_str(cmd.argv[0], ==, "arg"); + test_str(cmd.argv[argv_size - 1], ==, "arg"); + test_pass(cmd.argv[argv_size] == NULL); + + command_destroy(&cmd); +} + +static void +test_command_add_arg(void) +{ + struct command cmd; + + command_init(&cmd, "test", NULL); + + command_add_arg(&cmd, "arg 0"); + test_pass(cmd.argc == 1); + test_str(cmd.argv[0], ==, "arg 0"); + test_pass(cmd.argv[1] == NULL); + + command_add_arg(&cmd, "arg 1"); + test_pass(cmd.argc == 2); + test_str(cmd.argv[0], ==, "arg 0"); + test_str(cmd.argv[1], ==, "arg 1"); + test_pass(cmd.argv[2] == NULL); + + command_add_arg(&cmd, "arg 2"); + test_pass(cmd.argc == 3); + test_str(cmd.argv[0], ==, "arg 0"); + test_str(cmd.argv[1], ==, "arg 1"); + test_str(cmd.argv[2], ==, "arg 2"); + test_pass(cmd.argv[3] == NULL); + + command_destroy(&cmd); +} + +static void +test_command_add_argl(void) +{ + struct command cmd; + const char *args[] = { + "arg 1", + "arg 2", + "arg 3", + NULL, + }; + + command_init(&cmd, "test", NULL); + + command_add_arg(&cmd, "arg 0"); + + command_add_argl(&cmd, args); + test_pass(cmd.argc == 4); + test_str(cmd.argv[0], ==, "arg 0"); + test_str(cmd.argv[1], ==, "arg 1"); + test_str(cmd.argv[2], ==, "arg 2"); + test_str(cmd.argv[3], ==, "arg 3"); + test_pass(cmd.argv[4] == NULL); + + command_destroy(&cmd); +} + +static void +test_command_add_args(void) +{ + struct command cmd; + + command_init(&cmd, "test", NULL); + + command_add_arg(&cmd, "arg 0"); + + command_add_args(&cmd, "arg 1", "arg 2", "arg 3", NULL); + test_pass(cmd.argc == 4); + test_str(cmd.argv[0], ==, "arg 0"); + test_str(cmd.argv[1], ==, "arg 1"); + test_str(cmd.argv[2], ==, "arg 2"); + test_str(cmd.argv[3], ==, "arg 3"); + test_pass(cmd.argv[4] == NULL); + + command_destroy(&cmd); +} + +static void +test_command_exec(void) +{ + struct command cmd; + pid_t pid; + int ret; + + command_init(&cmd, "true", "exec test"); + + command_add_arg(&cmd, "true"); + command_add_arg(&cmd, "arg 0"); + command_add_arg(&cmd, "arg 1"); + + pid = subproc_fork(); + + if (pid == 0) + command_exec(&cmd); + + ret = subproc_reap(pid, "command exec test", 0); + test_pass(ret == 0); + + command_destroy(&cmd); +} + +static void +test_command_shell(void) +{ + pid_t pid; + int ret; + + pid = subproc_fork(); + if (pid == 0) + command_shell("true", "command shell pass test"); + ret = subproc_reap(pid, "command shell pass test", 0); + test_pass(ret == 0); + + pid = subproc_fork(); + if (pid == 0) + command_shell("false", "command shell fail test"); + ret = subproc_reap(pid, "command shell fail test", SUBPROC_RETERROR); + test_fail(ret == 0); + + unsetenv("SHELL"); + pid = subproc_fork(); + if (pid == 0) + command_shell("true", "command default shell test"); + ret = subproc_reap(pid, "command default shell test", 0); + test_pass(ret == 0); +} + +TEST_ENTRY(test) +{ + test_plan(49); + + test_command_init(); + test_command_grow_argv(); + test_command_add_arg(); + test_command_add_argl(); + test_command_add_args(); + test_command_exec(); + test_command_shell(); +} diff --git a/lib/dpkg/t/t-deb-version.c b/lib/dpkg/t/t-deb-version.c new file mode 100644 index 0000000..38b4608 --- /dev/null +++ b/lib/dpkg/t/t-deb-version.c @@ -0,0 +1,90 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-deb-version.c - test deb version handling + * + * Copyright © 2012 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <limits.h> +#include <stdio.h> + +#include <dpkg/test.h> +#include <dpkg/deb-version.h> + +static void +test_deb_version_parse(void) +{ + struct deb_version v; + char *vs; + + /* Test valid versions. */ + test_pass(deb_version_parse(&v, "0.0") == NULL); + test_pass(v.major == 0 && v.minor == 0); + + test_pass(deb_version_parse(&v, "1.1") == NULL); + test_pass(v.major == 1 && v.minor == 1); + + test_pass(deb_version_parse(&v, "1.001") == NULL); + test_pass(v.major == 1 && v.minor == 1); + + test_pass(deb_version_parse(&v, "1.0010") == NULL); + test_pass(v.major == 1 && v.minor == 10); + + test_pass(deb_version_parse(&v, "0.939000") == NULL); + test_pass(v.major == 0 && v.minor == 939000); + + test_pass(deb_version_parse(&v, "1.1\n") == NULL); + test_pass(v.major == 1 && v.minor == 1); + + /* Test invalid versions. */ + test_fail(deb_version_parse(&v, "0") == NULL); + test_fail(deb_version_parse(&v, "a") == NULL); + test_fail(deb_version_parse(&v, "a.b") == NULL); + test_fail(deb_version_parse(&v, "a~b") == NULL); + test_fail(deb_version_parse(&v, " 1.1") == NULL); + test_fail(deb_version_parse(&v, "2 .2") == NULL); + test_fail(deb_version_parse(&v, "3. 3") == NULL); + test_fail(deb_version_parse(&v, "4.4 ") == NULL); + test_fail(deb_version_parse(&v, " 5.5 ") == NULL); + + /* Test integer limits. */ + if (asprintf(&vs, "%d.0", INT_MAX) < 0) + test_bail("cannot allocate memory for asprintf()"); + test_pass(deb_version_parse(&v, vs) == NULL); + free(vs); + + if (asprintf(&vs, "%d.0", INT_MAX - 1) < 0) + test_bail("cannot allocate memory for asprintf()"); + test_pass(deb_version_parse(&v, vs) == NULL); + free(vs); + + if (asprintf(&vs, "%u.0", 1U + (unsigned int)INT_MAX) < 0) + test_bail("cannot allocate memory for asprintf()"); + test_fail(deb_version_parse(&v, vs) == NULL); + free(vs); + + /* TODO: Complete. */ +} + +TEST_ENTRY(test) +{ + test_plan(24); + + test_deb_version_parse(); +} diff --git a/lib/dpkg/t/t-ehandle.c b/lib/dpkg/t/t-ehandle.c new file mode 100644 index 0000000..979d2b7 --- /dev/null +++ b/lib/dpkg/t/t-ehandle.c @@ -0,0 +1,128 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-ehandle.c - test error handling implementation + * + * Copyright © 2016 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <stdbool.h> +#include <fcntl.h> +#include <unistd.h> + +#include <dpkg/test.h> +#include <dpkg/ehandle.h> + +jmp_buf global_handler_jump; + +static void +printer_empty(const char *msg, const void *data) +{ +} + +static void +handler_func(void) +{ + longjmp(global_handler_jump, 1); +} + +static void +test_error_handler_func(void) +{ + bool pass; + + if (setjmp(global_handler_jump)) { + pass = true; + pop_error_context(ehflag_normaltidy); + } else { + pass = false; + push_error_context_func(handler_func, printer_empty, "test func"); + ohshit("test func error"); + test_bail("ohshit() is not supposed to return"); + } + test_pass(pass); +} + +static void +test_error_handler_jump(void) +{ + jmp_buf handler_jump; + bool pass; + + if (setjmp(handler_jump)) { + pass = true; + pop_error_context(ehflag_normaltidy); + } else { + pass = false; + push_error_context_jump(&handler_jump, printer_empty, "test jump"); + ohshit("test jump error"); + test_bail("ohshit() is not supposed to return"); + } + test_pass(pass); +} + +static void +cleanup_error(int argc, void **argv) +{ + ohshit("cleanup error"); +} + +static void +test_cleanup_error(void) +{ + jmp_buf handler_jump; + bool pass; + + if (setjmp(handler_jump)) { + /* The ohshit() is not supposed to get us here, as it should + * be caught by the internal recursive error context. */ + pass = false; + + pop_cleanup(ehflag_normaltidy); + pop_error_context(ehflag_normaltidy); + } else { + push_error_context_jump(&handler_jump, printer_empty, "test cleanup"); + push_cleanup(cleanup_error, ~ehflag_normaltidy, 0); + pop_error_context(ehflag_bombout); + + /* We should have recovered from the cleanup handler failing, + * and arrived here correctly. */ + pass = true; + } + + test_pass(pass); +} + +TEST_ENTRY(test) +{ + test_plan(3); + + if (!test_is_verbose()) { + int fd; + + /* Shut up stderr, we do not want the error output. */ + fd = open("/dev/null", O_RDWR); + if (fd < 0) + test_bail("cannot open /dev/null"); + dup2(fd, 2); + } + + test_error_handler_func(); + test_error_handler_jump(); + test_cleanup_error(); +} diff --git a/lib/dpkg/t/t-error.c b/lib/dpkg/t/t-error.c new file mode 100644 index 0000000..e93459e --- /dev/null +++ b/lib/dpkg/t/t-error.c @@ -0,0 +1,87 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-error.c - test error message reporting + * + * Copyright © 2014 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <errno.h> +#include <string.h> +#include <stdio.h> + +#include <dpkg/test.h> +#include <dpkg/error.h> + +static void +test_dpkg_error_put(void) +{ + struct dpkg_error err = DPKG_ERROR_INIT; + char *errstr_ref = NULL; + + test_pass(err.type == DPKG_MSG_NONE); + test_pass(err.str == NULL); + + test_pass(dpkg_put_warn(NULL, "void error") < 0); + test_pass(dpkg_put_error(NULL, "void error") < 0); + test_pass(dpkg_put_errno(NULL, "void error") < 0); + + test_pass(dpkg_put_warn(&err, "test warning %d", 10) < 0); + test_pass(err.syserrno == 0); + test_str(err.str, ==, "test warning 10"); + test_warn(err); + + test_pass(dpkg_put_error(&err, "test error %d", 20) < 0); + test_pass(err.syserrno == 0); + test_str(err.str, ==, "test error 20"); + test_error(err); + + errno = ENOENT; + if (asprintf(&errstr_ref, "test errno 30 (%s)", strerror(errno)) < 0) + test_bail("cannot allocate string"); + test_pass(dpkg_put_errno(&err, "test errno %d", 30) < 0); + test_str(err.str, ==, errstr_ref); + test_pass(err.syserrno == ENOENT); + test_error(err); + free(errstr_ref); + errno = 0; +} + +static void +test_dpkg_error_destroy(void) +{ + struct dpkg_error err = DPKG_ERROR_INIT; + + errno = ENOENT; + test_pass(dpkg_put_errno(&err, "test destroy") < 0); + test_pass(err.syserrno == ENOENT); + test_pass(err.type == DPKG_MSG_ERROR); + test_pass(err.str != NULL); + dpkg_error_destroy(&err); + test_pass(err.type == DPKG_MSG_NONE); + test_pass(err.syserrno == 0); + test_pass(err.str == NULL); +} + +TEST_ENTRY(test) +{ + test_plan(24); + + test_dpkg_error_put(); + test_dpkg_error_destroy(); +} diff --git a/lib/dpkg/t/t-file.c b/lib/dpkg/t/t-file.c new file mode 100644 index 0000000..0004df4 --- /dev/null +++ b/lib/dpkg/t/t-file.c @@ -0,0 +1,106 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-file.c - test file functions + * + * Copyright © 2018 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/dpkg.h> +#include <dpkg/file.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +static const char ref_data[] = + "this is a test string\n" + "within a test file\n" + "containing multiple lines\n" +; + +static void +test_file_slurp(void) +{ + struct varbuf vb = VARBUF_INIT; + struct dpkg_error err = DPKG_ERROR_INIT; + char *test_file; + char *test_dir; + int fd; + + test_pass(file_slurp("/nonexistent", &vb, &err) < 0); + test_pass(vb.used == 0); + test_pass(vb.buf == NULL); + test_pass(err.syserrno == ENOENT); + test_error(err); + varbuf_destroy(&vb); + + test_dir = test_alloc(strdup("test.XXXXXX")); + test_pass(mkdtemp(test_dir) != NULL); + test_pass(file_slurp(test_dir, &vb, &err) < 0); + test_pass(vb.used == 0); + test_pass(vb.buf == NULL); + test_pass(err.syserrno == 0); + test_error(err); + varbuf_destroy(&vb); + test_pass(rmdir(test_dir) == 0); + + test_file = test_alloc(strdup("test.XXXXXX")); + fd = mkstemp(test_file); + test_pass(fd >= 0); + + test_pass(file_slurp(test_file, &vb, &err) == 0); + test_pass(vb.used == 0); + test_pass(vb.buf == NULL); + test_pass(err.syserrno == 0); + test_pass(err.type == DPKG_MSG_NONE); + varbuf_destroy(&vb); + + test_pass(write(fd, ref_data, strlen(ref_data)) == (ssize_t)strlen(ref_data)); + test_pass(lseek(fd, 0, SEEK_SET) == 0); + + test_pass(file_slurp(test_file, &vb, &err) == 0); + test_pass(vb.used == strlen(ref_data)); + test_mem(vb.buf, ==, ref_data, min(vb.used, strlen(ref_data))); + test_pass(err.syserrno == 0); + test_pass(err.type == DPKG_MSG_NONE); + varbuf_destroy(&vb); + + test_fail(file_is_exec(test_dir)); + test_fail(file_is_exec(test_file)); + test_pass(chmod(test_file, 0755) == 0); + test_pass(file_is_exec(test_file)); + test_pass(chmod(test_file, 0750) == 0); + test_pass(file_is_exec(test_file)); + + test_pass(unlink(test_file) == 0); + free(test_file); + free(test_dir); +} + +TEST_ENTRY(test) +{ + test_plan(32); + + test_file_slurp(); +} diff --git a/lib/dpkg/t/t-fsys-dir.c b/lib/dpkg/t/t-fsys-dir.c new file mode 100644 index 0000000..32f4aab --- /dev/null +++ b/lib/dpkg/t/t-fsys-dir.c @@ -0,0 +1,91 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-fsys-dir.c - test filesystem handling + * + * Copyright © 2018 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <stdlib.h> + +#include <dpkg/test.h> +#include <dpkg/fsys.h> + +static void +test_fsys_dir(void) +{ + const char *newdir; + char *dir; + + test_str(dpkg_fsys_get_dir(), ==, ""); + + newdir = dpkg_fsys_set_dir("/testdir//./"); + test_str(newdir, ==, "/testdir"); + test_str(dpkg_fsys_get_dir(), ==, "/testdir"); + + newdir = dpkg_fsys_set_dir("/testdir"); + test_str(newdir, ==, "/testdir"); + test_str(dpkg_fsys_get_dir(), ==, "/testdir"); + + newdir = dpkg_fsys_set_dir(newdir); + test_str(newdir, ==, "/testdir"); + test_str(dpkg_fsys_get_dir(), ==, "/testdir"); + + dir = dpkg_fsys_get_path("testfile"); + test_str(dir, ==, "/testdir/testfile"); + free(dir); + + dir = dpkg_fsys_get_path("/testfile"); + test_str(dir, ==, "/testdir/testfile"); + free(dir); + + setenv("DPKG_ROOT", "/testenvdir//./", 1); + dpkg_fsys_set_dir(NULL); + test_str(dpkg_fsys_get_dir(), ==, "/testenvdir"); + + setenv("DPKG_ROOT", "/testenvdir", 1); + dpkg_fsys_set_dir(NULL); + test_str(dpkg_fsys_get_dir(), ==, "/testenvdir"); + + dir = dpkg_fsys_get_path("testfile"); + test_str(dir, ==, "/testenvdir/testfile"); + free(dir); + + dir = dpkg_fsys_get_path("/testfile"); + test_str(dir, ==, "/testenvdir/testfile"); + free(dir); + + unsetenv("DPKG_ROOT"); + dpkg_fsys_set_dir(NULL); + test_str(dpkg_fsys_get_dir(), ==, ""); + + dir = dpkg_fsys_get_path("testfile"); + test_str(dir, ==, "/testfile"); + free(dir); + + dir = dpkg_fsys_get_path("/testfile"); + test_str(dir, ==, "/testfile"); + free(dir); +} + +TEST_ENTRY(test) +{ + test_plan(16); + + test_fsys_dir(); +} diff --git a/lib/dpkg/t/t-fsys-hash.c b/lib/dpkg/t/t-fsys-hash.c new file mode 100644 index 0000000..7739328 --- /dev/null +++ b/lib/dpkg/t/t-fsys-hash.c @@ -0,0 +1,108 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-fsys-hash.c - test fsys-hash implementation + * + * Copyright © 2018 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/dpkg.h> +#include <dpkg/fsys.h> + +static void +test_fsys_nodes(void) +{ + struct fsys_namenode *fnn; + struct fsys_hash_iter *iter; + const char *name; + + test_pass(fsys_hash_entries() == 0); + + fsys_hash_init(); + + fnn = fsys_hash_find_node("/nonexistent", FHFF_NONE); + test_pass(fnn == NULL); + test_pass(fsys_hash_entries() == 0); + + name = "/test/path/aa"; + fnn = fsys_hash_find_node(name, FHFF_NOCOPY); + test_pass(fnn != NULL); + test_pass(fsys_hash_entries() == 1); + test_pass(fnn->name == name); + test_str(fnn->name, ==, "/test/path/aa"); + test_pass(fnn->flags == 0); + test_pass(fnn->oldhash == NULL); + test_pass(fnn->newhash == NULL); + + fnn = fsys_hash_find_node("//./test/path/bb", 0); + test_pass(fnn != NULL); + test_pass(fsys_hash_entries() == 2); + test_str(fnn->name, ==, "/test/path/bb"); + test_pass(fnn->flags == 0); + test_pass(fnn->oldhash == NULL); + test_pass(fnn->newhash == NULL); + + fnn = fsys_hash_find_node("/test/path/cc", 0); + test_pass(fnn != NULL); + test_pass(fsys_hash_entries() == 3); + test_str(fnn->name, ==, "/test/path/cc"); + test_pass(fnn->flags == 0); + test_pass(fnn->oldhash == NULL); + test_pass(fnn->newhash == NULL); + + iter = fsys_hash_iter_new(); + while ((fnn = fsys_hash_iter_next(iter))) { + if (strcmp(fnn->name, "/test/path/aa") == 0) + test_str(fnn->name, ==, "/test/path/aa"); + else if (strcmp(fnn->name, "/test/path/bb") == 0) + test_str(fnn->name, ==, "/test/path/bb"); + else if (strcmp(fnn->name, "/test/path/cc") == 0) + test_str(fnn->name, ==, "/test/path/cc"); + else + test_fail("unknown fsys_namenode"); + } + fsys_hash_iter_free(iter); + + fsys_hash_init(); + test_pass(fsys_hash_entries() == 3); + fnn = fsys_hash_find_node("/test/path/aa", FHFF_NONE); + test_pass(fnn != NULL); + fnn = fsys_hash_find_node("/test/path/bb", FHFF_NONE); + test_pass(fnn != NULL); + fnn = fsys_hash_find_node("/test/path/cc", FHFF_NONE); + test_pass(fnn != NULL); + test_pass(fsys_hash_entries() == 3); + + fsys_hash_reset(); + test_pass(fsys_hash_entries() == 0); + fnn = fsys_hash_find_node("/test/path/aa", FHFF_NONE); + test_pass(fnn == NULL); + fnn = fsys_hash_find_node("/test/path/bb", FHFF_NONE); + test_pass(fnn == NULL); + fnn = fsys_hash_find_node("/test/path/cc", FHFF_NONE); + test_pass(fnn == NULL); + test_pass(fsys_hash_entries() == 0); +} + +TEST_ENTRY(test) +{ + test_plan(35); + + test_fsys_nodes(); +} diff --git a/lib/dpkg/t/t-headers-cpp.cc b/lib/dpkg/t/t-headers-cpp.cc new file mode 100644 index 0000000..b5becf9 --- /dev/null +++ b/lib/dpkg/t/t-headers-cpp.cc @@ -0,0 +1,82 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-headers-cpp.cc - test C++ inclusion of headers + * + * Copyright © 2018 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <cstdbool> + +#include <dpkg/ar.h> +#include <dpkg/arch.h> +#include <dpkg/atomic-file.h> +#include <dpkg/buffer.h> +#include <dpkg/c-ctype.h> +#include <dpkg/color.h> +#include <dpkg/command.h> +#include <dpkg/compress.h> +#include <dpkg/db-ctrl.h> +#include <dpkg/db-fsys.h> +#include <dpkg/deb-version.h> +#include <dpkg/debug.h> +#include <dpkg/dir.h> +#include <dpkg/dlist.h> +#include <dpkg/dpkg-db.h> +#include <dpkg/dpkg.h> +#include <dpkg/ehandle.h> +#include <dpkg/error.h> +#include <dpkg/fdio.h> +#include <dpkg/file.h> +#include <dpkg/fsys.h> +#include <dpkg/glob.h> +#include <dpkg/i18n.h> +#include <dpkg/macros.h> +#include <dpkg/namevalue.h> +#include <dpkg/options.h> +#include <dpkg/pager.h> +#include <dpkg/parsedump.h> +#include <dpkg/path.h> +#include <dpkg/pkg-array.h> +#include <dpkg/pkg-files.h> +#include <dpkg/pkg-format.h> +#include <dpkg/pkg-list.h> +#include <dpkg/pkg-queue.h> +#include <dpkg/pkg-show.h> +#include <dpkg/pkg-spec.h> +#include <dpkg/pkg.h> +#include <dpkg/progname.h> +#include <dpkg/program.h> +#include <dpkg/progress.h> +#include <dpkg/report.h> +#include <dpkg/string.h> +#include <dpkg/subproc.h> +#include <dpkg/tarfn.h> +#include <dpkg/test.h> +#include <dpkg/treewalk.h> +#include <dpkg/trigdeferred.h> +#include <dpkg/triglib.h> +#include <dpkg/varbuf.h> +#include <dpkg/version.h> + +TEST_ENTRY(test) +{ + test_plan(1); + + test_pass(true); +} diff --git a/lib/dpkg/t/t-macros.c b/lib/dpkg/t/t-macros.c new file mode 100644 index 0000000..9f4eaa1 --- /dev/null +++ b/lib/dpkg/t/t-macros.c @@ -0,0 +1,45 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-macros.c - test C support macros + * + * Copyright © 2009,2012 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/macros.h> + +TEST_ENTRY(test) +{ + test_plan(12); + + 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); + + test_pass(clamp(0, 0, 0) == 0); + test_pass(clamp(0, -10, 10) == 0); + test_pass(clamp(20, -10, 10) == 10); + test_pass(clamp(-20, -10, 10) == -10); +} diff --git a/lib/dpkg/t/t-meminfo.c b/lib/dpkg/t/t-meminfo.c new file mode 100644 index 0000000..b231081 --- /dev/null +++ b/lib/dpkg/t/t-meminfo.c @@ -0,0 +1,88 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-meminfo.c - test memory information handling code + * + * Copyright © 2022 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/meminfo.h> + +static char * +test_data_file(const char *filename) +{ + char *pathname; + int rc; + + rc = asprintf(&pathname, "%s/t/data/%s", test_get_srcdir(), filename); + if (rc < 0) + test_bail("cannot allocate data filename"); + + return pathname; +} + +static void +test_meminfo(void) +{ + char *pathname; + uint64_t mem; + int rc; + + mem = 0; + pathname = test_data_file("meminfo-no-file"); + rc = meminfo_get_available_from_file(pathname, &mem); + test_pass(rc == MEMINFO_NO_FILE); + test_pass(mem == 0); + free(pathname); + + mem = 0; + pathname = test_data_file("meminfo-no-data"); + rc = meminfo_get_available_from_file(pathname, &mem); + test_pass(rc == MEMINFO_NO_DATA); + test_pass(mem == 0); + free(pathname); + + mem = 0; + pathname = test_data_file("meminfo-no-unit"); + rc = meminfo_get_available_from_file(pathname, &mem); + test_pass(rc == MEMINFO_NO_UNIT); + test_pass(mem == 0); + free(pathname); + + mem = 0; + pathname = test_data_file("meminfo-no-info"); + rc = meminfo_get_available_from_file(pathname, &mem); + test_pass(rc == MEMINFO_NO_INFO); + test_pass(mem == 0); + free(pathname); + + mem = 0; + pathname = test_data_file("meminfo-ok"); + rc = meminfo_get_available_from_file(pathname, &mem); + test_pass(rc == MEMINFO_OK); + test_pass(mem == 3919974400UL); + free(pathname); +} + +TEST_ENTRY(test) +{ + test_plan(10); + + test_meminfo(); +} diff --git a/lib/dpkg/t/t-mod-db.c b/lib/dpkg/t/t-mod-db.c new file mode 100644 index 0000000..c40d8e8 --- /dev/null +++ b/lib/dpkg/t/t-mod-db.c @@ -0,0 +1,57 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-mod-db.c - test database implementation + * + * Copyright © 2011 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <stdlib.h> + +#include <dpkg/test.h> +#include <dpkg/dpkg-db.h> + +static void +test_db_dir(void) +{ + char *dir; + + test_str(dpkg_db_get_dir(), ==, ADMINDIR); + + dpkg_db_set_dir("testdir"); + test_str(dpkg_db_get_dir(), ==, "testdir"); + + setenv("DPKG_ADMINDIR", "testenvdir", 1); + dpkg_db_set_dir(NULL); + test_str(dpkg_db_get_dir(), ==, "testenvdir"); + + unsetenv("DPKG_ADMINDIR"); + dpkg_db_set_dir(NULL); + test_str(dpkg_db_get_dir(), ==, ADMINDIR); + + dir = dpkg_db_get_path("testfile"); + test_str(dir, ==, ADMINDIR "/testfile"); + free(dir); +} + +TEST_ENTRY(test) +{ + test_plan(5); + + test_db_dir(); +} diff --git a/lib/dpkg/t/t-namevalue.c b/lib/dpkg/t/t-namevalue.c new file mode 100644 index 0000000..c864766 --- /dev/null +++ b/lib/dpkg/t/t-namevalue.c @@ -0,0 +1,48 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-namevalue.c - test name/value implementation + * + * Copyright © 2018 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/namevalue.h> +#include <dpkg/dpkg-db.h> + +static void +test_namevalue(void) +{ + const struct namevalue *nv; + + nv = namevalue_find_by_name(booleaninfos, ""); + test_pass(nv == NULL); + + nv = namevalue_find_by_name(booleaninfos, "no"); + test_pass(nv != NULL); + test_pass(nv->value == false); + test_pass(nv->length == strlen("no")); + test_str(nv->name, ==, "no"); +} + +TEST_ENTRY(test) +{ + test_plan(5); + + test_namevalue(); +} diff --git a/lib/dpkg/t/t-pager.c b/lib/dpkg/t/t-pager.c new file mode 100644 index 0000000..2481e80 --- /dev/null +++ b/lib/dpkg/t/t-pager.c @@ -0,0 +1,75 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-pager.c - test pager implementation + * + * Copyright © 2010-2012 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> + +#include <dpkg/test.h> +#include <dpkg/pager.h> +#include <dpkg/dpkg.h> + +static void +test_dup_file(int fd, const char *filename, int flags) +{ + int newfd; + + newfd = open(filename, flags); + dup2(newfd, fd); + close(newfd); +} + +static void +test_pager_get_exec(void) +{ + const char *pager, *default_pager; + int origfd = dup(STDOUT_FILENO); + + /* Test stdout being a tty. */ + test_todo_block("environment might not expose controlling terminal") { + test_dup_file(STDOUT_FILENO, "/dev/tty", O_WRONLY); + setenv("PAGER", "test-pager", 1); + pager = pager_get_exec(); + unsetenv("PAGER"); + default_pager = pager_get_exec(); + dup2(origfd, STDOUT_FILENO); + test_str(pager, ==, "test-pager"); + test_str(default_pager, ==, DEFAULTPAGER); + } + + /* Test stdout not being a tty. */ + test_dup_file(STDOUT_FILENO, "/dev/null", O_WRONLY); + pager = pager_get_exec(); + dup2(origfd, STDOUT_FILENO); + test_str(pager, ==, CAT); +} + +TEST_ENTRY(test) +{ + test_plan(3); + + test_pager_get_exec(); +} diff --git a/lib/dpkg/t/t-path.c b/lib/dpkg/t/t-path.c new file mode 100644 index 0000000..deb1b72 --- /dev/null +++ b/lib/dpkg/t/t-path.c @@ -0,0 +1,181 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-path.c - test path handling code + * + * Copyright © 2009-2012 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <ctype.h> +#include <stdbool.h> +#include <stdlib.h> + +#include <dpkg/test.h> +#include <dpkg/path.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 = test_alloc(strdup((p))); \ + path_trim_slash_slashdot(t); \ + test_str(t, ==, (ref)); \ + free(t); \ +} while (0) + +static void +test_path_trim(void) +{ + test_trim_eq_ref("/a", "/a"); + 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(path_skip_slash_dotslash("./././."), ==, "."); + test_str(path_skip_slash_dotslash("./././"), ==, ""); + test_str(path_skip_slash_dotslash("./."), ==, "."); + test_str(path_skip_slash_dotslash("./"), ==, ""); + test_str(path_skip_slash_dotslash("/./././."), ==, "."); + test_str(path_skip_slash_dotslash("/./"), ==, ""); + test_str(path_skip_slash_dotslash("/."), ==, "."); + test_str(path_skip_slash_dotslash("/"), ==, ""); + test_str(path_skip_slash_dotslash("/./../."), ==, "../."); + test_str(path_skip_slash_dotslash("/foo/bar/./"), ==, "foo/bar/./"); + test_str(path_skip_slash_dotslash("./foo/bar/./"), ==, "foo/bar/./"); + test_str(path_skip_slash_dotslash("/./foo/bar/./"), ==, "foo/bar/./"); +} + +static void +test_path_basename(void) +{ + test_str(path_basename("./."), ==, "."); + test_str(path_basename("./"), ==, ""); + test_str(path_basename("/."), ==, "."); + test_str(path_basename("/"), ==, ""); + test_str(path_basename("/foo"), ==, "foo"); + test_str(path_basename("/foo/bar"), ==, "bar"); + test_str(path_basename("/foo/bar/"), ==, ""); +} + +static void +test_path_temp(void) +{ + char *template; + + template = path_make_temp_template("test"); + + test_pass(strstr(template, "test") != NULL); + test_pass(strstr(template, "XXXXXX") != NULL); + + free(template); +} + +static bool +string_is_ascii(const char *str) +{ + while (*str) { + if (!isascii(*str)) + return false; + + str++; + } + + return true; +} + +static void +test_path_quote(void) +{ + const char src_7_bit[] = "string with 7-bit chars only"; + const char src_7_bit_trim[] = "string with 7-bit chars"; + const char src_8_bit[] = "text w/ 8-bit chars: \\ \370 \300 \342 end"; + const char src_8_bit_end[] = "text \370"; + const char src_bs_end[] = "text \\"; + char *dst; + size_t len; + + /* Test 0 length. */ + dst = NULL; + path_quote_filename(dst, src_7_bit, 0); + + /* Test no quoting. */ + len = strlen(src_7_bit) + 1; + dst = test_alloc(malloc(len)); + + path_quote_filename(dst, src_7_bit, len); + test_str(dst, ==, src_7_bit); + free(dst); + + /* Test no quoting with limit. */ + len = strlen(src_7_bit_trim) + 1; + dst = test_alloc(malloc(len)); + + path_quote_filename(dst, src_7_bit, len); + test_str(dst, ==, src_7_bit_trim); + free(dst); + + /* Test normal quoting. */ + len = strlen(src_8_bit) * 2 + 1; + dst = test_alloc(malloc(len)); + + path_quote_filename(dst, src_8_bit, len); + test_pass(strstr(dst, "end") != NULL); + test_pass(string_is_ascii(dst)); + free(dst); + + /* Test normal quoting with limit. */ + len = strlen(src_8_bit_end) + 1 + 2; + dst = test_alloc(malloc(len)); + + path_quote_filename(dst, src_8_bit_end, len); + test_str(dst, ==, "text "); + free(dst); + + /* Test backslash quoting with limit. */ + len = strlen(src_bs_end) + 1; + dst = test_alloc(malloc(len)); + + path_quote_filename(dst, src_bs_end, len); + test_str(dst, ==, "text "); + free(dst); +} + +TEST_ENTRY(test) +{ + test_plan(41); + + test_path_trim(); + test_path_skip(); + test_path_basename(); + test_path_temp(); + test_path_quote(); +} diff --git a/lib/dpkg/t/t-pkg-format.c b/lib/dpkg/t/t-pkg-format.c new file mode 100644 index 0000000..a6d33fe --- /dev/null +++ b/lib/dpkg/t/t-pkg-format.c @@ -0,0 +1,141 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-pkg-format.c - test pkg-format implementation + * + * Copyright © 2022 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/dpkg-db.h> +#include <dpkg/pkg.h> +#include <dpkg/pkg-format.h> + +static void +prep_pkg(struct pkgset *set, struct pkginfo *pkg) +{ + pkg_blank(pkg); + + pkgset_blank(set); + pkgset_link_pkg(set, pkg); + + set->name = "test-bin"; + pkg->installed.description = "short synopsis -- some package\n" + " This is the extended description for this package-\n" + " .\n" + " Potentially expanding multiple lines.\n"; + pkg->installed.arch = dpkg_arch_get(DPKG_ARCH_ALL); + pkg->installed.version = DPKG_VERSION_OBJECT(0, "4.5", "2"); +} + +static void +prep_virtpkg(struct pkgset *set, struct pkginfo *pkg) +{ + pkg_blank(pkg); + + pkgset_blank(set); + pkgset_link_pkg(set, pkg); + + set->name = "test-virt"; +} + +static void +test_field(struct pkginfo *pkg, const char *fmt, const char *exp) +{ + struct pkg_format_node *head; + struct varbuf vb = VARBUF_INIT; + + head = pkg_format_parse(fmt, NULL); + test_pass(head); + pkg_format_print(&vb, head, pkg, &pkg->installed); + test_str(vb.buf, ==, exp); + pkg_format_free(head); +} + +static void +test_pkg_format_real_fields(void) +{ + struct pkgset pkgset; + struct pkginfo pkg; + + prep_pkg(&pkgset, &pkg); + + test_field(&pkg, "${Package}_${Version}_${Architecture}", + "test-bin_4.5-2_all"); +} + +static void +test_pkg_format_virtual_fields(void) +{ + struct pkgset pkgset; + struct pkginfo pkg; + + prep_pkg(&pkgset, &pkg); + + test_field(&pkg, "${source:Package}_${source:Version}", + "test-bin_4.5-2"); + + pkg.installed.source = "test-src"; + test_field(&pkg, "${source:Package}_${source:Version}", + "test-src_4.5-2"); + test_field(&pkg, "${source:Upstream-Version}", + "4.5"); + + pkg.installed.source = "test-src (1:3.4-6)"; + test_field(&pkg, "${source:Package}_${source:Version}", + "test-src_1:3.4-6"); + test_field(&pkg, "${source:Upstream-Version}", + "3.4"); + + test_field(&pkg, "${binary:Synopsis}", + "short synopsis -- some package"); + + test_field(&pkg, "${binary:Summary}", + "short synopsis -- some package"); + + prep_virtpkg(&pkgset, &pkg); + test_field(&pkg, "${source:Package}_${source:Version}", + "test-virt_"); + test_field(&pkg, "${source:Upstream-Version}", + ""); +} + +static void +test_pkg_format_virtual_fields_db_fsys(void) +{ + struct pkg_format_node *head; + + head = pkg_format_parse("prefix ${unknown-variable} suffix", NULL); + test_pass(head); + test_fail(pkg_format_needs_db_fsys(head)); + pkg_format_free(head); + + head = pkg_format_parse("prefix ${db-fsys:Files} suffix", NULL); + test_pass(head); + test_pass(pkg_format_needs_db_fsys(head)); + pkg_format_free(head); +} + +TEST_ENTRY(test) +{ + test_plan(24); + + test_pkg_format_real_fields(); + test_pkg_format_virtual_fields(); + test_pkg_format_virtual_fields_db_fsys(); +} diff --git a/lib/dpkg/t/t-pkg-hash.c b/lib/dpkg/t/t-pkg-hash.c new file mode 100644 index 0000000..2c009f8 --- /dev/null +++ b/lib/dpkg/t/t-pkg-hash.c @@ -0,0 +1,179 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-pkg-hash.c - test pkg-hash implementation + * + * Copyright © 2018 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/dpkg.h> +#include <dpkg/dpkg-db.h> +#include <dpkg/pkg.h> + +static void +test_pkg_hash(void) +{ + struct dpkg_arch *arch; + struct pkgset *set; + struct pkginfo *pkg; + struct pkg_hash_iter *iter; + int pkginstance; + + test_pass(pkg_hash_count_set() == 0); + test_pass(pkg_hash_count_pkg() == 0); + + set = pkg_hash_find_set("pkg-aa"); + test_pass(set != NULL); + test_str(set->name, ==, "pkg-aa"); + test_pass(pkg_hash_count_set() == 1); + test_pass(pkg_hash_count_pkg() == 1); + + set = pkg_hash_find_set("pkg-aa"); + test_pass(set != NULL); + test_str(set->name, ==, "pkg-aa"); + test_pass(pkg_hash_count_set() == 1); + test_pass(pkg_hash_count_pkg() == 1); + + set = pkg_hash_find_set("Pkg-AA"); + test_pass(set != NULL); + test_str(set->name, ==, "pkg-aa"); + test_pass(pkg_hash_count_set() == 1); + test_pass(pkg_hash_count_pkg() == 1); + + set = pkg_hash_find_set("pkg-bb"); + pkg_set_status(&set->pkg, PKG_STAT_INSTALLED); + test_pass(set != NULL); + test_str(set->name, ==, "pkg-bb"); + test_pass(pkg_hash_count_set() == 2); + test_pass(pkg_hash_count_pkg() == 2); + + set = pkg_hash_find_set("pkg-cc"); + test_pass(set != NULL); + test_str(set->name, ==, "pkg-cc"); + test_pass(pkg_hash_count_set() == 3); + test_pass(pkg_hash_count_pkg() == 3); + + arch = dpkg_arch_find("arch-xx"); + pkg = pkg_hash_find_pkg("pkg-aa", arch); + pkg_set_status(pkg, PKG_STAT_INSTALLED); + test_pass(pkg != NULL); + test_str(pkg->set->name, ==, "pkg-aa"); + test_str(pkg->installed.arch->name, ==, "arch-xx"); + test_str(pkg->available.arch->name, ==, "arch-xx"); + test_pass(pkg_hash_count_set() == 3); + test_pass(pkg_hash_count_pkg() == 3); + + arch = dpkg_arch_find("arch-yy"); + pkg = pkg_hash_find_pkg("pkg-aa", arch); + test_pass(pkg != NULL); + test_str(pkg->set->name, ==, "pkg-aa"); + test_str(pkg->installed.arch->name, ==, "arch-yy"); + test_str(pkg->available.arch->name, ==, "arch-yy"); + test_pass(pkg_hash_count_set() == 3); + test_pass(pkg_hash_count_pkg() == 4); + + arch = dpkg_arch_find("arch-zz"); + pkg = pkg_hash_find_pkg("pkg-aa", arch); + pkg_set_status(pkg, PKG_STAT_UNPACKED); + test_pass(pkg != NULL); + test_str(pkg->set->name, ==, "pkg-aa"); + test_str(pkg->installed.arch->name, ==, "arch-zz"); + test_str(pkg->available.arch->name, ==, "arch-zz"); + test_pass(pkg_hash_count_set() == 3); + test_pass(pkg_hash_count_pkg() == 5); + + arch = dpkg_arch_find("arch-xx"); + pkg = pkg_hash_find_pkg("pkg-aa", arch); + test_pass(pkg != NULL); + test_str(pkg->set->name, ==, "pkg-aa"); + test_str(pkg->installed.arch->name, ==, "arch-xx"); + test_str(pkg->available.arch->name, ==, "arch-xx"); + test_pass(pkg_hash_count_set() == 3); + test_pass(pkg_hash_count_pkg() == 5); + + set = pkg_hash_find_set("pkg-aa"); + test_str(set->name, ==, "pkg-aa"); + pkg = pkg_hash_get_singleton(set); + test_pass(pkg == NULL); + test_pass(pkg_hash_count_set() == 3); + test_pass(pkg_hash_count_pkg() == 5); + + pkg = pkg_hash_find_singleton("pkg-bb"); + test_pass(pkg != NULL); + test_str(pkg->set->name, ==, "pkg-bb"); + test_pass(pkg_hash_count_set() == 3); + test_pass(pkg_hash_count_pkg() == 5); + + pkg = pkg_hash_find_singleton("pkg-cc"); + test_pass(pkg != NULL); + test_str(pkg->set->name, ==, "pkg-cc"); + test_pass(pkg_hash_count_set() == 3); + test_pass(pkg_hash_count_pkg() == 5); + + iter = pkg_hash_iter_new(); + while ((set = pkg_hash_iter_next_set(iter))) { + if (strcmp(set->name, "pkg-aa") == 0) + test_str(set->name, ==, "pkg-aa"); + else if (strcmp(set->name, "pkg-bb") == 0) + test_str(set->name, ==, "pkg-bb"); + else if (strcmp(set->name, "pkg-cc") == 0) + test_str(set->name, ==, "pkg-cc"); + else + test_fail("unknown fsys_namenode"); + } + pkg_hash_iter_free(iter); + + pkginstance = 0; + iter = pkg_hash_iter_new(); + while ((pkg = pkg_hash_iter_next_pkg(iter))) { + pkginstance++; + if (strcmp(pkg->set->name, "pkg-aa") == 0) { + struct pkgbin *pkgbin = &pkg->installed; + + test_str(pkg->set->name, ==, "pkg-aa"); + if (strcmp(pkgbin->arch->name, "arch-xx") == 0) + test_str(pkgbin->arch->name, ==, "arch-xx"); + else if (strcmp(pkgbin->arch->name, "arch-yy") == 0) + test_str(pkgbin->arch->name, ==, "arch-yy"); + else if (strcmp(pkgbin->arch->name, "arch-zz") == 0) + test_str(pkgbin->arch->name, ==, "arch-zz"); + else + test_fail("unknown pkginfo instance"); + } else if (strcmp(pkg->set->name, "pkg-bb") == 0) { + test_str(pkg->set->name, ==, "pkg-bb"); + } else if (strcmp(pkg->set->name, "pkg-cc") == 0) { + test_str(pkg->set->name, ==, "pkg-cc"); + } else { + test_fail("unknown fsys_namenode"); + } + } + pkg_hash_iter_free(iter); + test_pass(pkginstance == 5); + + pkg_hash_reset(); + test_pass(pkg_hash_count_set() == 0); + test_pass(pkg_hash_count_pkg() == 0); +} + +TEST_ENTRY(test) +{ + test_plan(72); + + test_pkg_hash(); +} diff --git a/lib/dpkg/t/t-pkg-list.c b/lib/dpkg/t/t-pkg-list.c new file mode 100644 index 0000000..722cf2e --- /dev/null +++ b/lib/dpkg/t/t-pkg-list.c @@ -0,0 +1,90 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-pkg-list.c - test pkg-list implementation + * + * Copyright © 2010,2012 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/dpkg-db.h> +#include <dpkg/pkg-list.h> + +static void +test_pkg_list_new(void) +{ + struct pkg_list *l1, *l2, *l3; + struct pkginfo pkg1, pkg2, pkg3; + + l1 = pkg_list_new(&pkg1, NULL); + test_alloc(l1); + test_pass(l1->next == NULL); + test_pass(l1->pkg == &pkg1); + + l2 = pkg_list_new(&pkg2, l1); + test_alloc(l2); + test_pass(l2->next == l1); + test_pass(l2->pkg == &pkg2); + + l3 = pkg_list_new(&pkg3, l2); + test_alloc(l3); + test_pass(l3->next == l2); + test_pass(l3->pkg == &pkg3); + + pkg_list_free(l3); +} + +static void +test_pkg_list_prepend(void) +{ + struct pkg_list *head = NULL, *l1, *l2, *l3; + struct pkginfo pkg1, pkg2, pkg3, pkg4; + + pkg_list_prepend(&head, &pkg1); + test_alloc(head); + test_pass(head->next == NULL); + test_pass(head->pkg == &pkg1); + l1 = head; + + pkg_list_prepend(&head, &pkg2); + test_alloc(head); + test_pass(head->next == l1); + test_pass(head->pkg == &pkg2); + l2 = head; + + pkg_list_prepend(&head, &pkg3); + test_alloc(head); + test_pass(head->next == l2); + test_pass(head->pkg == &pkg3); + l3 = head; + + pkg_list_prepend(&head, &pkg4); + test_alloc(head); + test_pass(head->next == l3); + test_pass(head->pkg == &pkg4); + + pkg_list_free(head); +} + +TEST_ENTRY(test) +{ + test_plan(14); + + test_pkg_list_new(); + test_pkg_list_prepend(); +} diff --git a/lib/dpkg/t/t-pkg-queue.c b/lib/dpkg/t/t-pkg-queue.c new file mode 100644 index 0000000..cf1e327 --- /dev/null +++ b/lib/dpkg/t/t-pkg-queue.c @@ -0,0 +1,116 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-pkg-queue.c - test pkg-queue implementation + * + * Copyright © 2010,2012 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/dpkg-db.h> +#include <dpkg/pkg-queue.h> + +static void +test_pkg_queue_init(void) +{ + struct pkg_queue q = PKG_QUEUE_INIT; + struct pkg_list l; + + test_pass(q.length == 0); + test_pass(q.head == NULL); + test_pass(q.tail == NULL); + + test_pass(pkg_queue_is_empty(&q)); + + q = (struct pkg_queue){ .length = 10, .head = &l, .tail = &l }; + + pkg_queue_init(&q); + test_pass(q.length == 0); + test_pass(q.head == NULL); + test_pass(q.tail == NULL); + + test_pass(pkg_queue_is_empty(&q)); +} + +static void +test_pkg_queue_push_pop(void) +{ + struct pkg_queue q = PKG_QUEUE_INIT; + struct pkg_list *l1, *l2, *l3; + struct pkginfo *pkgp, pkg1, pkg2, pkg3; + + test_pass(pkg_queue_is_empty(&q)); + + /* Test push operations. */ + + l1 = pkg_queue_push(&q, &pkg1); + test_pass(l1 != NULL); + test_pass(q.head == l1); + test_pass(q.tail == l1); + test_pass(q.length == 1); + + l2 = pkg_queue_push(&q, &pkg2); + test_pass(l2 != NULL); + test_pass(q.head == l1); + test_pass(q.tail == l2); + test_pass(q.length == 2); + + l3 = pkg_queue_push(&q, &pkg3); + test_pass(l3 != NULL); + test_pass(q.head == l1); + test_pass(q.tail == l3); + test_pass(q.length == 3); + + /* Test pop operations. */ + + pkgp = pkg_queue_pop(&q); + test_pass(pkgp == &pkg1); + test_pass(q.head == l2); + test_pass(q.tail == l3); + test_pass(q.length == 2); + + pkgp = pkg_queue_pop(&q); + test_pass(pkgp == &pkg2); + test_pass(q.head == l3); + test_pass(q.tail == l3); + test_pass(q.length == 1); + + pkgp = pkg_queue_pop(&q); + test_pass(pkgp == &pkg3); + test_pass(q.head == NULL); + test_pass(q.tail == NULL); + test_pass(q.length == 0); + + test_pass(pkg_queue_is_empty(&q)); + + pkgp = pkg_queue_pop(&q); + test_pass(pkgp == NULL); + test_pass(q.head == NULL); + test_pass(q.tail == NULL); + test_pass(q.length == 0); + + pkg_queue_destroy(&q); +} + +TEST_ENTRY(test) +{ + test_plan(38); + + test_pkg_queue_init(); + test_pkg_queue_push_pop(); +} diff --git a/lib/dpkg/t/t-pkg-show.c b/lib/dpkg/t/t-pkg-show.c new file mode 100644 index 0000000..6bb361d --- /dev/null +++ b/lib/dpkg/t/t-pkg-show.c @@ -0,0 +1,70 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-pkg-show.c - test pkg-show implementation + * + * Copyright © 2018 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/dpkg-db.h> +#include <dpkg/arch.h> + +static void +test_pkg_show_name(void) +{ + struct dpkg_arch *arch; + struct pkginfo *pkg; + const char *pkgname; + + arch = dpkg_arch_find("arch"); + test_pass(arch); + + pkg = pkg_hash_find_pkg("test", arch); + test_pass(pkg); + test_str(pkg->set->name, ==, "test"); + test_pass(pkg->installed.arch->type == DPKG_ARCH_UNKNOWN); + + pkgname = pkg_name(pkg, pnaw_never); + test_pass(pkgname); + test_str(pkgname, ==, "test"); + + pkgname = pkg_name(pkg, pnaw_nonambig); + test_pass(pkgname); + test_str(pkgname, ==, "test:arch"); + + pkgname = pkg_name(pkg, pnaw_always); + test_pass(pkgname); + test_str(pkgname, ==, "test:arch"); + + pkgname = pkg_name(pkg, pnaw_same); + test_pass(pkgname); + test_str(pkgname, ==, "test"); + + pkg->installed.multiarch = PKG_MULTIARCH_SAME; + pkgname = pkg_name(pkg, pnaw_same); + test_pass(pkgname); + test_str(pkgname, ==, "test:arch"); +} + +TEST_ENTRY(test) +{ + test_plan(14); + + test_pkg_show_name(); +} diff --git a/lib/dpkg/t/t-pkginfo.c b/lib/dpkg/t/t-pkginfo.c new file mode 100644 index 0000000..787cefe --- /dev/null +++ b/lib/dpkg/t/t-pkginfo.c @@ -0,0 +1,153 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-pkginfo.c - test pkginfo handling + * + * Copyright © 2009-2010,2012-2014 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/dpkg-db.h> +#include <dpkg/pkg.h> + +static void +test_pkginfo_informative(void) +{ + struct pkginfo pkg; + + pkg_blank(&pkg); + test_fail(pkg_is_informative(&pkg, &pkg.installed)); + + pkg_set_want(&pkg, PKG_WANT_PURGE); + test_pass(pkg_is_informative(&pkg, &pkg.installed)); + + pkg_blank(&pkg); + pkg.installed.description = "test description"; + test_pass(pkg_is_informative(&pkg, &pkg.installed)); + + /* TODO: Complete. */ +} + +static void +test_pkginfo_eflags(void) +{ + struct pkginfo pkg; + + pkg_blank(&pkg); + test_pass(pkg.eflag == PKG_EFLAG_OK); + + pkg_set_eflags(&pkg, PKG_EFLAG_REINSTREQ); + test_pass(pkg.eflag == PKG_EFLAG_REINSTREQ); + + pkg_clear_eflags(&pkg, PKG_EFLAG_REINSTREQ); + test_pass(pkg.eflag == PKG_EFLAG_OK); + + pkg_set_eflags(&pkg, 0x11); + test_pass(pkg.eflag == 0x11); + pkg_reset_eflags(&pkg); + test_pass(pkg.eflag == PKG_EFLAG_OK); +} + +static void +test_pkginfo_instance_tracking(void) +{ + struct pkgset set; + struct pkginfo pkg2, pkg3, pkg4; + + pkgset_blank(&set); + pkg_blank(&pkg2); + pkg_blank(&pkg3); + pkg_blank(&pkg4); + + test_pass(pkgset_installed_instances(&set) == 0); + + /* Link the other instances into the pkgset. */ + pkgset_link_pkg(&set, &pkg4); + pkgset_link_pkg(&set, &pkg3); + pkgset_link_pkg(&set, &pkg2); + + /* Test installation state transitions. */ + pkg_set_status(&pkg4, PKG_STAT_INSTALLED); + test_pass(pkgset_installed_instances(&set) == 1); + + pkg_set_status(&pkg4, PKG_STAT_INSTALLED); + test_pass(pkgset_installed_instances(&set) == 1); + + pkg_set_status(&pkg4, PKG_STAT_TRIGGERSPENDING); + test_pass(pkgset_installed_instances(&set) == 1); + + pkg_set_status(&pkg4, PKG_STAT_TRIGGERSAWAITED); + test_pass(pkgset_installed_instances(&set) == 1); + + pkg_set_status(&pkg4, PKG_STAT_HALFCONFIGURED); + test_pass(pkgset_installed_instances(&set) == 1); + + pkg_set_status(&pkg4, PKG_STAT_UNPACKED); + test_pass(pkgset_installed_instances(&set) == 1); + + pkg_set_status(&pkg4, PKG_STAT_HALFINSTALLED); + test_pass(pkgset_installed_instances(&set) == 1); + + pkg_set_status(&pkg4, PKG_STAT_CONFIGFILES); + test_pass(pkgset_installed_instances(&set) == 1); + + pkg_set_status(&pkg4, PKG_STAT_NOTINSTALLED); + test_pass(pkgset_installed_instances(&set) == 0); + + pkg_set_status(&pkg4, PKG_STAT_NOTINSTALLED); + test_pass(pkgset_installed_instances(&set) == 0); + + /* Toggle installation states on various packages. */ + pkg_set_status(&pkg4, PKG_STAT_INSTALLED); + test_pass(pkgset_installed_instances(&set) == 1); + + pkg_set_status(&pkg2, PKG_STAT_HALFINSTALLED); + test_pass(pkgset_installed_instances(&set) == 2); + + pkg_set_status(&set.pkg, PKG_STAT_CONFIGFILES); + test_pass(pkgset_installed_instances(&set) == 3); + + pkg_set_status(&pkg3, PKG_STAT_NOTINSTALLED); + test_pass(pkgset_installed_instances(&set) == 3); + + pkg_set_status(&pkg3, PKG_STAT_UNPACKED); + test_pass(pkgset_installed_instances(&set) == 4); + + pkg_set_status(&set.pkg, PKG_STAT_NOTINSTALLED); + test_pass(pkgset_installed_instances(&set) == 3); + + pkg_set_status(&pkg2, PKG_STAT_NOTINSTALLED); + test_pass(pkgset_installed_instances(&set) == 2); + + pkg_set_status(&pkg3, PKG_STAT_NOTINSTALLED); + test_pass(pkgset_installed_instances(&set) == 1); + + pkg_set_status(&pkg4, PKG_STAT_NOTINSTALLED); + test_pass(pkgset_installed_instances(&set) == 0); +} + +TEST_ENTRY(test) +{ + test_plan(28); + + test_pkginfo_informative(); + test_pkginfo_eflags(); + test_pkginfo_instance_tracking(); + + /* TODO: Complete. */ +} diff --git a/lib/dpkg/t/t-progname.c b/lib/dpkg/t/t-progname.c new file mode 100644 index 0000000..e90e923 --- /dev/null +++ b/lib/dpkg/t/t-progname.c @@ -0,0 +1,53 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-progname.c - test program name handling + * + * Copyright © 2011 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/progname.h> + +static void +test_progname(void) +{ + const char *progname; + + /* Test initially empty progname. */ + progname = dpkg_get_progname(); + /* Handle libtool executables. */ + if (strncmp(progname, "lt-", 3) == 0) + progname += 3; + test_str(progname, ==, "t-progname"); + + /* Test setting a new progname. */ + dpkg_set_progname("newname"); + test_str(dpkg_get_progname(), ==, "newname"); + + /* Test setting a new progname with path. */ + dpkg_set_progname("path/newprogname"); + test_str(dpkg_get_progname(), ==, "newprogname"); +} + +TEST_ENTRY(test) +{ + test_plan(3); + + test_progname(); +} diff --git a/lib/dpkg/t/t-string.c b/lib/dpkg/t/t-string.c new file mode 100644 index 0000000..7b4350d --- /dev/null +++ b/lib/dpkg/t/t-string.c @@ -0,0 +1,281 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-string.c - test string handling + * + * Copyright © 2009-2011, 2014-2015 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/string.h> + +#include <stdlib.h> +#include <string.h> + +#include <stdio.h> + +static void +test_str_is_set(void) +{ + /* Test if strings are unset. */ + test_pass(str_is_unset(NULL)); + test_pass(str_is_unset("")); + test_fail(str_is_unset("aaa")); + + /* Test if strings are set. */ + test_fail(str_is_set(NULL)); + test_fail(str_is_set("")); + test_pass(str_is_set("ccc")); +} + +static void +test_str_match_end(void) +{ + test_pass(str_match_end("foo bar quux", "quux")); + test_pass(str_match_end("foo bar quux", "bar quux")); + test_pass(str_match_end("foo bar quux", "foo bar quux")); + test_fail(str_match_end("foo bar quux", "foo bar quux zorg")); + test_fail(str_match_end("foo bar quux", "foo bar")); + test_fail(str_match_end("foo bar quux", "foo")); +} + +static void +test_str_fnv_hash(void) +{ + test_pass(str_fnv_hash("") == 0x811c9dc5U); + test_pass(str_fnv_hash("a") == 0xe40c292cUL); + test_pass(str_fnv_hash("b") == 0xe70c2de5UL); + test_pass(str_fnv_hash("c") == 0xe60c2c52UL); + test_pass(str_fnv_hash("d") == 0xe10c2473UL); + test_pass(str_fnv_hash("e") == 0xe00c22e0UL); + test_pass(str_fnv_hash("f") == 0xe30c2799UL); + test_pass(str_fnv_hash("fo") == 0x6222e842UL); + test_pass(str_fnv_hash("foo") == 0xa9f37ed7UL); + test_pass(str_fnv_hash("foob") == 0x3f5076efUL); + test_pass(str_fnv_hash("fooba") == 0x39aaa18aUL); + test_pass(str_fnv_hash("foobar") == 0xbf9cf968UL); + + test_pass(str_fnv_hash("test-string") == 0xd28f6e61UL); + test_pass(str_fnv_hash("Test-string") == 0x00a54b81UL); + test_pass(str_fnv_hash("rest-string") == 0x1cdeebffUL); + test_pass(str_fnv_hash("Rest-string") == 0x20464b9fUL); +} + +static void +test_str_concat(void) +{ + char buf[1024], *str; + + memset(buf, 0, sizeof(buf)); + str = str_concat(buf, NULL); + test_pass(str == buf); + test_str(buf, ==, ""); + + memset(buf, 0, sizeof(buf)); + str = str_concat(buf, "aaa", NULL); + test_str(buf, ==, "aaa"); + test_pass(str == buf + 3); + + memset(buf, 0, sizeof(buf)); + str = str_concat(buf, "zzzz", "yy", "xxxx", NULL); + test_str(buf, ==, "zzzzyyxxxx"); + test_pass(str == buf + 10); + + memset(buf, 0, sizeof(buf)); + str = str_concat(buf, "1234", "", "5678", NULL); + test_str(buf, ==, "12345678"); + test_pass(str == buf + 8); + + memset(buf, ' ', sizeof(buf)); + str = str_concat(buf, "eol", NULL, "bom", NULL); + test_str(buf, ==, "eol"); + test_pass(str == buf + 3); +} + +static void +test_str_fmt(void) +{ + char *str; + + str = str_fmt("%s", "abcde"); + test_str(str, ==, "abcde"); + free(str); + + str = str_fmt("%d", 15); + test_str(str, ==, "15"); + free(str); +} + +static void +test_str_escape_fmt(void) +{ + char buf[1024], *q; + + memset(buf, 'a', sizeof(buf)); + q = str_escape_fmt(buf, "", sizeof(buf)); + strcpy(q, " end"); + test_str(buf, ==, " end"); + + memset(buf, 'a', sizeof(buf)); + q = str_escape_fmt(buf, "%", sizeof(buf)); + strcpy(q, " end"); + test_str(buf, ==, "%% end"); + + memset(buf, 'a', sizeof(buf)); + q = str_escape_fmt(buf, "%%%", sizeof(buf)); + strcpy(q, " end"); + test_str(buf, ==, "%%%%%% end"); + + memset(buf, 'a', sizeof(buf)); + q = str_escape_fmt(buf, "%b%b%c%c%%", sizeof(buf)); + strcpy(q, " end"); + test_str(buf, ==, "%%b%%b%%c%%c%%%% end"); + + /* Test delimited buffer. */ + memset(buf, 'a', sizeof(buf)); + q = str_escape_fmt(buf, NULL, 0); + test_mem(buf, ==, "aaaa", 4); + test_pass(buf == q); + test_pass(strnlen(buf, sizeof(buf)) == sizeof(buf)); + + memset(buf, 'a', sizeof(buf)); + q = str_escape_fmt(buf, "b", 1); + test_str(q, ==, ""); + + memset(buf, 'a', sizeof(buf)); + q = str_escape_fmt(buf, "%%%", 5); + strcpy(q, " end"); + test_str(buf, ==, "%%%% end"); + + memset(buf, 'a', sizeof(buf)); + q = str_escape_fmt(buf, "%%%", 4); + strcpy(q, " end"); + test_str(buf, ==, "%% end"); +} + +static void +test_str_rtrim_spaces(void) +{ + char buf[1024]; + char *str_end; + + strcpy(buf, ""); + str_end = str_rtrim_spaces(buf, buf + strlen(buf)); + test_pass(str_end == buf); + test_str(buf, ==, ""); + + strcpy(buf, " \t\t \r\n "); + str_end = str_rtrim_spaces(buf, buf + strlen(buf)); + test_pass(str_end == buf); + test_str(buf, ==, ""); + + strcpy(buf, "abcd"); + str_end = str_rtrim_spaces(buf, buf + strlen(buf)); + test_pass(str_end == buf + 4); + test_str(buf, ==, "abcd"); + + strcpy(buf, "abcd "); + str_end = str_rtrim_spaces(buf, buf + strlen(buf)); + test_pass(str_end == buf + 4); + test_str(buf, ==, "abcd"); + + strcpy(buf, "abcd\t \t "); + str_end = str_rtrim_spaces(buf, buf + strlen(buf)); + test_pass(str_end == buf + 4); + test_str(buf, ==, "abcd"); + + strcpy(buf, " \t \t abcd"); + str_end = str_rtrim_spaces(buf, buf + strlen(buf)); + test_pass(str_end == buf + 12); + test_str(buf, ==, " \t \t abcd"); +} + +static void +test_str_quote_meta(void) +{ + char *str; + + str = str_quote_meta("foo1 2bar"); + test_str(str, ==, "foo1\\ 2bar"); + free(str); + + str = str_quote_meta("foo1?2bar"); + test_str(str, ==, "foo1\\?2bar"); + free(str); + + str = str_quote_meta("foo1*2bar"); + test_str(str, ==, "foo1\\*2bar"); + free(str); +} + +static void +test_str_strip_quotes(void) +{ + char buf[1024], *str; + + strcpy(buf, "unquoted text"); + str = str_strip_quotes(buf); + test_str(str, ==, "unquoted text"); + + strcpy(buf, "contained 'quoted text'"); + str = str_strip_quotes(buf); + test_str(str, ==, "contained 'quoted text'"); + + strcpy(buf, "contained \"quoted text\""); + str = str_strip_quotes(buf); + test_str(str, ==, "contained \"quoted text\""); + + strcpy(buf, "'unbalanced quotes"); + str = str_strip_quotes(buf); + test_pass(str == NULL); + + strcpy(buf, "\"unbalanced quotes"); + str = str_strip_quotes(buf); + test_pass(str == NULL); + + strcpy(buf, "'mismatched quotes\""); + str = str_strip_quotes(buf); + test_pass(str == NULL); + + strcpy(buf, "\"mismatched quotes'"); + str = str_strip_quotes(buf); + test_pass(str == NULL); + + strcpy(buf, "'completely quoted text'"); + str = str_strip_quotes(buf); + test_str(str, ==, "completely quoted text"); + + strcpy(buf, "\"completely quoted text\""); + str = str_strip_quotes(buf); + test_str(str, ==, "completely quoted text"); +} + +TEST_ENTRY(test) +{ + test_plan(74); + + test_str_is_set(); + test_str_match_end(); + test_str_fnv_hash(); + test_str_concat(); + test_str_fmt(); + test_str_escape_fmt(); + test_str_quote_meta(); + test_str_strip_quotes(); + test_str_rtrim_spaces(); +} diff --git a/lib/dpkg/t/t-subproc.c b/lib/dpkg/t/t-subproc.c new file mode 100644 index 0000000..7ce610b --- /dev/null +++ b/lib/dpkg/t/t-subproc.c @@ -0,0 +1,100 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-subproc.c - test sub-process module + * + * Copyright © 2011 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <sys/types.h> + +#include <fcntl.h> +#include <signal.h> +#include <unistd.h> +#include <stdlib.h> + +#include <dpkg/test.h> +#include <dpkg/subproc.h> + +static void +test_subproc_fork(void) +{ + struct sigaction sa; + pid_t pid; + int ret; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + + /* Test exit(). */ + pid = subproc_fork(); + if (pid == 0) + exit(0); + ret = subproc_reap(pid, "subproc exit pass", SUBPROC_RETERROR); + test_pass(ret == 0); + + pid = subproc_fork(); + if (pid == 0) + exit(128); + ret = subproc_reap(pid, "subproc exit fail", SUBPROC_RETERROR); + test_pass(ret == 128); + + /* Test signals. */ + pid = subproc_fork(); + if (pid == 0) + raise(SIGINT); + ret = subproc_reap(pid, "subproc signal", SUBPROC_WARN); + test_pass(ret == -1); + + pid = subproc_fork(); + if (pid == 0) + raise(SIGTERM); + ret = subproc_reap(pid, "subproc signal", SUBPROC_WARN); + test_pass(ret == -1); + + pid = subproc_fork(); + if (pid == 0) + raise(SIGPIPE); + ret = subproc_reap(pid, "subproc SIGPIPE", + SUBPROC_WARN | SUBPROC_NOPIPE); + test_pass(ret == 0); + + pid = subproc_fork(); + if (pid == 0) + raise(SIGPIPE); + ret = subproc_reap(pid, "subproc SIGPIPE", SUBPROC_WARN); + test_pass(ret == -1); +} + +TEST_ENTRY(test) +{ + int fd; + + test_plan(6); + + /* XXX: Shut up stderr, we don't want the error output. */ + fd = open("/dev/null", O_RDWR); + if (fd < 0) + test_bail("cannot open /dev/null"); + dup2(fd, 2); + + test_subproc_fork(); +} diff --git a/lib/dpkg/t/t-tar.c b/lib/dpkg/t/t-tar.c new file mode 100644 index 0000000..6fa217d --- /dev/null +++ b/lib/dpkg/t/t-tar.c @@ -0,0 +1,148 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-tar.c - test tar implementation + * + * Copyright © 2017 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <errno.h> + +#include <dpkg/test.h> +#include <dpkg/tarfn.h> + +static void +test_tar_atol8(void) +{ + uintmax_t u; + + /* Test valid octal numbers. */ + u = tar_atoul("000000\0\0\0\0\0\0", 12, UINTMAX_MAX); + test_pass(u == 0); + u = tar_atoul("00000000000\0", 12, UINTMAX_MAX); + test_pass(u == 0); + u = tar_atoul("00000000001\0", 12, UINTMAX_MAX); + test_pass(u == 1); + u = tar_atoul("00000000777\0", 12, UINTMAX_MAX); + test_pass(u == 511); + u = tar_atoul("77777777777\0", 12, UINTMAX_MAX); + test_pass(u == 8589934591); + + /* Test legacy formatted octal numbers. */ + u = tar_atoul(" 0\0", 12, UINTMAX_MAX); + test_pass(u == 0); + u = tar_atoul(" 1\0", 12, UINTMAX_MAX); + test_pass(u == 1); + u = tar_atoul(" 777\0", 12, UINTMAX_MAX); + test_pass(u == 511); + + /* Test extended octal numbers not terminated by space or NUL, + * (as is required by POSIX), but accepted by several implementations + * to get one byte larger values. */ + u = tar_atoul("000000000000", 12, UINTMAX_MAX); + test_pass(u == 0); + u = tar_atoul("000000000001", 12, UINTMAX_MAX); + test_pass(u == 1); + u = tar_atoul("000000000777", 12, UINTMAX_MAX); + test_pass(u == 511); + u = tar_atoul("777777777777", 12, UINTMAX_MAX); + test_pass(u == 68719476735); + + /* Test invalid octal numbers. */ + errno = 0; + u = tar_atoul(" ", 12, UINTMAX_MAX); + test_pass(u == 0); + test_pass(errno == EINVAL); + + errno = 0; + u = tar_atoul(" 11111aaa ", 12, UINTMAX_MAX); + test_pass(u == 0); + test_pass(errno == ERANGE); + + errno = 0; + u = tar_atoul(" 8 ", 12, UINTMAX_MAX); + test_pass(u == 0); + test_pass(errno == ERANGE); + + errno = 0; + u = tar_atoul(" 18 ", 12, UINTMAX_MAX); + test_pass(u == 0); + test_pass(errno == ERANGE); + + errno = 0; + u = tar_atoul(" aa ", 12, UINTMAX_MAX); + test_pass(u == 0); + test_pass(errno == ERANGE); +} + +static void +test_tar_atol256(void) +{ + uintmax_t u; + intmax_t i; + + /* Test positive numbers. */ + u = tar_atoul("\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12, UINTMAX_MAX); + test_pass(u == 0); + u = tar_atoul("\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 12, UINTMAX_MAX); + test_pass(u == 1); + u = tar_atoul("\x80\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00", 12, UINTMAX_MAX); + test_pass(u == 8589934592); + u = tar_atoul("\x80\x00\x00\x00\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 12, UINTMAX_MAX); + test_pass(u == INTMAX_MAX); + + /* Test overflow. */ + errno = 0; + u = tar_atoul("\x80\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00", 12, UINTMAX_MAX); + test_pass(u == UINTMAX_MAX); + test_pass(errno == ERANGE); + + errno = 0; + u = tar_atoul("\x80\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12, UINTMAX_MAX); + test_pass(u == UINTMAX_MAX); + test_pass(errno == ERANGE); + + /* Test negative numbers. */ + i = tar_atosl("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 12, INTMAX_MIN, INTMAX_MAX); + test_pass(i == -1); + i = tar_atosl("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE", 12, INTMAX_MIN, INTMAX_MAX); + test_pass(i == -2); + i = tar_atosl("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x00\x00\x00\x00", 12, INTMAX_MIN, INTMAX_MAX); + test_pass(i == -8589934592); + i = tar_atosl("\xFF\xFF\xFF\xFF\x80\x00\x00\x00\x00\x00\x00\x00", 12, INTMAX_MIN, INTMAX_MAX); + test_pass(i == INTMAX_MIN); + + /* Test underflow. */ + errno = 0; + i = tar_atosl("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00", 12, INTMAX_MIN, INTMAX_MAX); + test_pass(i == INTMAX_MIN); + test_pass(errno == ERANGE); + + errno = 0; + i = tar_atosl("\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12, INTMAX_MIN, INTMAX_MAX); + test_pass(i == INTMAX_MIN); + test_pass(errno == ERANGE); +} + +TEST_ENTRY(test) +{ + test_plan(38); + + test_tar_atol8(); + test_tar_atol256(); +} diff --git a/lib/dpkg/t/t-tarextract.t b/lib/dpkg/t/t-tarextract.t new file mode 100755 index 0000000..5499cdc --- /dev/null +++ b/lib/dpkg/t/t-tarextract.t @@ -0,0 +1,159 @@ +#!/usr/bin/perl +# +# Copyright © 2014 Guillem Jover <guillem@debian.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, see <https://www.gnu.org/licenses/>. + +use Test::More; +use Cwd; +use File::Path qw(make_path remove_tree); +use File::Temp qw(tempdir); +use File::Spec; +use File::Find; +use POSIX qw(mkfifo); + +use Dpkg (); +use Dpkg::File; +use Dpkg::IPC; + +use strict; +use warnings; +use version; + +my $srcdir = $ENV{srcdir} || '.'; +my $builddir = $ENV{builddir} || '.'; +my $tmpdir = 't.tmp/t-tarextract'; + +# We require GNU tar >= 1.27 for --owner=NAME:ID and --group=NAME:ID. +my $tar_version = qx($Dpkg::PROGTAR --version 2>/dev/null); +if ($tar_version and $tar_version =~ m/^tar \(GNU tar\) (\d+\.\d+)/ and + qv("v$1") >= qv('v1.27')) +{ + plan tests => 12; +} else { + plan skip_all => 'needs GNU tar >= 1.27'; +} + +# Set a known umask. +umask 0022; + +sub tar_create_tree { + my $type = shift; + + my $long_a = 'a' x 29; + my $long_b = 'b' x 29; + my $long_c = 'c' x 29; + my $long_d = 'd' x 29; + my $long_e = 'e' x 29; + my $long_f = 'f' x 22; + + # Populate tar hierarchy + file_touch('file'); + link 'file', 'hardlink'; + + make_path("$long_a/$long_b/$long_c/$long_d/$long_e/"); + make_path("$long_a/$long_b/$long_c/$long_d/$long_e/$long_f/"); + file_touch("$long_a/$long_b/$long_c/$long_d/$long_e/$long_f/long"); + + # POSIX specifies that symlinks have undefined permissions in their + # mode, so their handling is system dependent. Linux does not honor + # the umask for symlinks, other systems like GNU/Hurd or kFreeBSD do, + # which means we get different results due to this. + my $umask = umask 0; + + symlink "$long_a/$long_b/$long_c/$long_d/$long_e/$long_f/long", + 'symlink-long'; + symlink 'file', 'symlink-a'; + symlink 'hardlink', 'symlink-b'; + symlink 'dangling', 'symlink-c'; + + umask $umask; + + mkdir 'directory'; + mkfifo('fifo', 0770); + + # TODO: Need root. + # system 'mknod', 'chardev', 'c', '1', '3'; + # system 'mknod', 'blockdev', 'b', '0', '0'; +} + +sub test_tar_extractor { + my $stdout; + my $stderr; + + my $expected_tar = <<'TAR'; +. mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir +./fifo mode=10750 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=fifo +./file mode=100644 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=file size=0 +./hardlink mode=100644 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=hardlink linkto=./file size=0 +./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir +./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir +./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir +./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir +./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir +./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee/ffffffffffffffffffffff mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir +./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee/ffffffffffffffffffffff/long mode=100644 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=file size=0 +./directory mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir +./symlink-a mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=file size=0 +./symlink-b mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=hardlink size=0 +./symlink-c mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=dangling size=0 +./symlink-long mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee/ffffffffffffffffffffff/long size=0 +TAR + + make_path($tmpdir); + + my $cwd = getcwd(); + + # Check generated tarballs. + foreach my $type (qw(v7 ustar oldgnu gnu)) { + my $dirtree = "$tmpdir/$type"; + my @paths; + + mkdir $dirtree; + chdir $dirtree; + tar_create_tree($type); + find({ no_chdir => 1, wanted => sub { + return if $type eq 'v7' and length > 99; + return if $type eq 'v7' and -l and length readlink > 99; + return if $type eq 'v7' and not (-f or -l or -d); + return if $type eq 'ustar' and length > 256; + return if $type eq 'ustar' and -l and length readlink > 100; + push @paths, $_; + }, + preprocess => sub { my (@files) = sort @_; @files } }, '.'); + chdir $cwd; + + my $paths_list = join "\0", @paths; + spawn(exec => [ $Dpkg::PROGTAR, '-cf', "$dirtree.tar", + '--format', $type, + '-C', $dirtree, '--mtime=@100000000', + '--owner=user:100', '--group=group:200', + '--null', '--no-unquote', '--no-recursion', '-T-' ], + wait_child => 1, from_string => \$paths_list); + + my $expected = $expected_tar; + $expected =~ s/[ug]name=[^ ]+ //g if $type eq 'v7'; + $expected =~ s/\n^.*fifo.*$//mg if $type eq 'v7'; + $expected =~ s/\n^.*dddd.*$//mg if $type eq 'v7'; + $expected =~ s/\n^.*symlink-long.*$//mg if $type eq 'ustar'; + + spawn(exec => [ "$builddir/t/c-tarextract", "$dirtree.tar" ], + nocheck => 1, to_string => \$stdout, to_error => \$stderr); + ok($? == 0, "tar extractor $type should succeed"); + is($stderr, undef, "tar extractor $type stderr is empty"); + is($stdout, $expected, "tar extractor $type is ok"); + } +} + +test_tar_extractor(); diff --git a/lib/dpkg/t/t-test-skip.c b/lib/dpkg/t/t-test-skip.c new file mode 100644 index 0000000..972cdf1 --- /dev/null +++ b/lib/dpkg/t/t-test-skip.c @@ -0,0 +1,31 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-test-skip.c - test suite self tests, skip all + * + * Copyright © 2014 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> + +TEST_ENTRY(test) +{ + test_skip_all("ignore all tests"); + + test_fail(1); +} diff --git a/lib/dpkg/t/t-test.c b/lib/dpkg/t/t-test.c new file mode 100644 index 0000000..48ce872 --- /dev/null +++ b/lib/dpkg/t/t-test.c @@ -0,0 +1,66 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-test.c - test suite self tests + * + * Copyright © 2009, 2014 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> + +TEST_ENTRY(test) +{ + test_plan(22); + + test_pass(1); + test_fail(0); + + test_skip("ignore test"); + + test_skip_block(1) { + test_pass(0); + test_pass(1); + } + + test_todo(0, "unimplemented test", "failing test"); + + test_todo_block("unimplemented block") { + test_pass(0); + test_fail(1); + } + + 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); + + setenv("srcdir", "aaa", 1); + setenv("builddir", "bbb", 1); + test_str(test_get_srcdir(), ==, "aaa"); + test_str(test_get_builddir(), ==, "bbb"); +} diff --git a/lib/dpkg/t/t-treewalk.t b/lib/dpkg/t/t-treewalk.t new file mode 100755 index 0000000..573103d --- /dev/null +++ b/lib/dpkg/t/t-treewalk.t @@ -0,0 +1,154 @@ +#!/usr/bin/perl +# +# Copyright © 2016 Guillem Jover <guillem@debian.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, see <https://www.gnu.org/licenses/>. + +use strict; +use warnings; +use version; + +use Test::More tests => 6; +use Cwd; +use File::Path qw(make_path remove_tree); +use File::Temp qw(tempdir); +use File::Basename; +use File::Find; + +use Dpkg::File; +use Dpkg::IPC; + +my $srcdir = $ENV{srcdir} || '.'; +my $builddir = $ENV{builddir} || '.'; +my $tmpdir = 't.tmp/t-treewalk'; + +# Set a known umask. +umask 0022; + +# Populate the tree hierarchy. +sub make_tree { + my ($dirtree) = @_; + my $cwd = getcwd(); + + make_path($dirtree); + chdir $dirtree; + + # Deep tree. + make_path('aaaa/aaaa/aaaa/aaaa/'); + file_touch('aaaa/aaaa/aaaa/aaaa/abcde'); + file_touch('aaaa/aaaa/aaaa/aaaa/ddddd'); + file_touch('aaaa/aaaa/aaaa/aaaa/wwwwa'); + file_touch('aaaa/aaaa/aaaa/aaaa/wwwwz'); + file_touch('aaaa/aaaa/aaaa/aaaa/zzzzz'); + + # Shallow tree. + make_path('bbbb/'); + file_touch('bbbb/abcde'); + file_touch('bbbb/ddddd'); + file_touch('bbbb/wwwwa'); + file_touch('bbbb/wwwwz'); + file_touch('bbbb/zzzzz'); + + # Populated tree. + make_path('cccc/aa/aa/aa/'); + make_path('cccc/aa/aa/bb/aa/'); + file_touch('cccc/aa/aa/bb/aa/file-a'); + file_touch('cccc/aa/aa/bb/aa/file-z'); + make_path('cccc/aa/bb/'); + make_path('cccc/bb/aa/'); + make_path('cccc/bb/bb/aa/aa/'); + file_touch('cccc/bb/bb/aa/aa/file-a'); + file_touch('cccc/bb/bb/aa/aa/file-z'); + make_path('cccc/bb/bb/bb/'); + file_touch('cccc/bb/bb/bb/file-w'); + make_path('cccc/cc/aa/'); + make_path('cccc/cc/bb/aa/'); + file_touch('cccc/cc/bb/aa/file-t'); + make_path('cccc/cc/bb/bb/'); + file_touch('cccc/cc/bb/bb/file-x'); + make_path('cccc/cc/cc/'); + make_path('cccc/dd/aa/aa/aa/'); + file_touch('cccc/dd/aa/aa/aa/file-y'); + make_path('cccc/dd/aa/aa/bb/'); + file_touch('cccc/dd/aa/aa/bb/file-o'); + make_path('cccc/dd/aa/bb/aa/'); + file_touch('cccc/dd/aa/bb/aa/file-k'); + make_path('cccc/dd/aa/bb/bb/'); + file_touch('cccc/dd/aa/bb/bb/file-l'); + make_path('cccc/dd/aa/cc/aa/'); + file_touch('cccc/dd/aa/cc/aa/file-s'); + make_path('cccc/dd/aa/cc/bb/'); + file_touch('cccc/dd/aa/cc/bb/file-u'); + + # Tree with symlinks cycles. + make_path('llll/self/'); + file_touch('llll/file'); + symlink '..', 'llll/self/loop'; + make_path('llll/real/'); + file_touch('llll/real/file-r'); + symlink '../virt', 'llll/real/loop'; + make_path('llll/virt/'); + file_touch('llll/virt/file-v'); + symlink '../real', 'llll/virt/loop'; + + chdir $cwd; +} + +sub test_treewalker { + my $stdout; + my $stderr; + my $dirtree = $tmpdir; + + # Check generated tarballs. + foreach my $type (qw(full skip)) { + my @paths; + + make_tree($dirtree); + + find({ no_chdir => 1, wanted => sub { + return if $type eq 'skip' and m{^\Q$dirtree\E/cccc}; + push @paths, s{\./}{}r; + }, + }, $dirtree); + + my $expected; + + foreach my $path (sort @paths) { + lstat $path; + + my $ptype; + if (-f _) { + $ptype = 'f'; + } elsif (-l _) { + $ptype = 'l'; + } elsif (-d _) { + $ptype = 'd'; + } + my $pname = basename($path); + my $pvirt = $path =~ s{\Q$dirtree\E/?}{}r; + + $expected .= "T=$ptype N=$pname V=$pvirt R=$path\n"; + } + + $ENV{TREEWALK_SKIP} = $type eq 'skip' ? "$dirtree/cccc" : undef; + + spawn(exec => [ "$builddir/t/c-treewalk", $dirtree ], + nocheck => 1, to_string => \$stdout, to_error => \$stderr); + ok($? == 0, "tree walker $type should succeed"); + is($stderr, undef, "tree walker $type stderr is empty"); + is($stdout, $expected, "tree walker $type is ok"); + } +} + +test_treewalker(); diff --git a/lib/dpkg/t/t-trigdeferred.t b/lib/dpkg/t/t-trigdeferred.t new file mode 100755 index 0000000..bf73541 --- /dev/null +++ b/lib/dpkg/t/t-trigdeferred.t @@ -0,0 +1,116 @@ +#!/usr/bin/perl +# +# Copyright © 2016 Guillem Jover <guillem@debian.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, see <https://www.gnu.org/licenses/>. + +use strict; +use warnings; +use version; + +use Test::More; +use Cwd; +use File::Path qw(make_path remove_tree); +use File::Temp qw(tempdir); +use File::Basename; +use File::Find; + +use Dpkg::File; +use Dpkg::IPC; + +my $srcdir = $ENV{srcdir} || '.'; +my $builddir = $ENV{builddir} || '.'; +my $tmpdir = 't.tmp/t-trigdeferred'; + +my @deferred = ( + { + exitcode => 0, + original => <<'TEXT', + + # Comment + # Another Comment + /root/pathname/file-trigger pkg-a pkg-b pkg-c +named-trigger pkg-1 pkg-2 pkg-3 +parse-trigger pkg:a pkg+b pkg.0 0-pkg +:other-trigger - +TEXT + expected => <<'TEXT', +<T='/root/pathname/file-trigger' P='pkg-a' P='pkg-b' P='pkg-c' E> +<T='named-trigger' P='pkg-1' P='pkg-2' P='pkg-3' E> +<T='parse-trigger' P='pkg:a' P='pkg+b' P='pkg.0' P='0-pkg' E> +<T=':other-trigger' P='-' E> +TEXT + }, { + exitcode => 2, + original => <<"TEXT", +\b # invalid character +TEXT + }, { + exitcode => 2, + original => <<'TEXT', +trigger -pkg +TEXT + }, { + exitcode => 2, + original => <<'TEXT', +trigger +pkg +TEXT + }, { + exitcode => 2, + original => <<'TEXT', +trigger .pkg +TEXT + }, { + exitcode => 2, + original => <<'TEXT', +trigger :pkg +TEXT + }, { + exitcode => 2, + original => 'missing newline', + } +); + +plan tests => scalar(@deferred) * 3; + +# Set a known umask. +umask 0022; + +sub test_trigdeferred { + my $stdout; + my $stderr; + my $admindir = "$tmpdir"; + + # Check triggers deferred file parsing. + make_path("$admindir/triggers"); + + foreach my $test (@deferred) { + file_dump("$admindir/triggers/Unincorp", $test->{original}); + + spawn(exec => [ "$builddir/t/c-trigdeferred", $admindir ], + nocheck => 1, to_string => \$stdout, error_to_string => \$stderr); + my $exitcode = $? >> 8; + + is($exitcode, $test->{exitcode}, 'trigger deferred expected exitcode'); + if ($test->{exitcode} == 0) { + is($stderr, '', 'trigger deferred expected stderr'); + is($stdout, $test->{expected}, 'trigger deferred expected stdout'); + } else { + isnt($stderr, '', 'trigger deferred expected stderr'); + isnt($stdout, undef, 'trigger deferred expected stdout'); + } + } +} + +test_trigdeferred(); diff --git a/lib/dpkg/t/t-trigger.c b/lib/dpkg/t/t-trigger.c new file mode 100644 index 0000000..af78f23 --- /dev/null +++ b/lib/dpkg/t/t-trigger.c @@ -0,0 +1,49 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-trigger.c - test triggers + * + * Copyright © 2012 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/triglib.h> + +static void +test_trig_name_is_illegal(void) +{ + /* Test invalid trigger names. */ + test_fail(trig_name_is_illegal("") == NULL); + test_fail(trig_name_is_illegal("\a") == NULL); + test_fail(trig_name_is_illegal("\t") == NULL); + test_fail(trig_name_is_illegal("\200") == NULL); + test_fail(trig_name_is_illegal("trigger name") == NULL); + + /* Test valid trigger names. */ + test_pass(trig_name_is_illegal("TRIGGER") == NULL); + test_pass(trig_name_is_illegal("trigger") == NULL); + test_pass(trig_name_is_illegal("0123456789") == NULL); + test_pass(trig_name_is_illegal("/file/trigger") == NULL); +} + +TEST_ENTRY(test) +{ + test_plan(9); + + test_trig_name_is_illegal(); +} diff --git a/lib/dpkg/t/t-varbuf.c b/lib/dpkg/t/t-varbuf.c new file mode 100644 index 0000000..ee1fdbc --- /dev/null +++ b/lib/dpkg/t/t-varbuf.c @@ -0,0 +1,475 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-varbuf.c - test varbuf implementation + * + * Copyright © 2009-2011, 2013-2015 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <dpkg/test.h> +#include <dpkg/varbuf.h> + +#include <string.h> +#include <stdint.h> +#include <stdlib.h> + +static void +test_varbuf_init(void) +{ + struct varbuf vb; + + varbuf_init(&vb, 0); + test_pass(vb.used == 0); + test_pass(vb.size == 0); + test_pass(vb.buf == NULL); + + varbuf_destroy(&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; + + varbuf_init(&vb, 10); + test_pass(vb.used == 0); + test_pass(vb.size >= 10); + test_pass(vb.buf != NULL); + + varbuf_destroy(&vb); + test_pass(vb.used == 0); + test_pass(vb.size == 0); + test_pass(vb.buf == NULL); +} + +static void +test_varbuf_new(void) +{ + struct varbuf *vb; + + vb = varbuf_new(0); + test_pass(vb != NULL); + test_pass(vb->used == 0); + test_pass(vb->size == 0); + test_pass(vb->buf == NULL); + varbuf_free(vb); + + vb = varbuf_new(10); + test_pass(vb != NULL); + test_pass(vb->used == 0); + test_pass(vb->size >= 10); + test_pass(vb->buf != NULL); + varbuf_free(vb); +} + +static void +test_varbuf_grow(void) +{ + struct varbuf vb; + jmp_buf grow_jump; + size_t old_size; + bool grow_overflow; + int i; + + varbuf_init(&vb, 10); + + /* Test that we grow when needed. */ + varbuf_grow(&vb, 100); + test_pass(vb.used == 0); + test_pass(vb.size >= 100); + + old_size = vb.size; + + /* Test that we are not leaking. */ + for (i = 0; i < 10; i++) { + varbuf_grow(&vb, 100); + test_pass(vb.used == 0); + test_pass(vb.size >= 100); + test_pass(vb.size == old_size); + } + + /* Test that we grow when needed, with used space. */ + vb.used = 10; + varbuf_grow(&vb, 100); + test_pass(vb.used == 10); + test_pass(vb.size >= 110); + + /* Test that we do not allow allocation overflows. */ + grow_overflow = false; + old_size = vb.size; + test_try(grow_jump) { + varbuf_grow(&vb, SIZE_MAX - vb.size + 2); + } test_catch { + grow_overflow = true; + } test_finally; + test_pass(vb.size == old_size && grow_overflow); + + grow_overflow = false; + old_size = vb.size; + test_try(grow_jump) { + varbuf_grow(&vb, (SIZE_MAX - vb.size - 2) / 2); + } test_catch { + grow_overflow = true; + } test_finally; + test_pass(vb.size == old_size && grow_overflow); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_trunc(void) +{ + struct varbuf vb; + + varbuf_init(&vb, 50); + + /* Test that we truncate (grow). */ + varbuf_trunc(&vb, 20); + test_pass(vb.used == 20); + test_pass(vb.size >= 50); + + /* Test that we truncate (shrink). */ + varbuf_trunc(&vb, 10); + test_pass(vb.used == 10); + test_pass(vb.size >= 50); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_add_buf(void) +{ + struct varbuf vb; + + varbuf_init(&vb, 5); + + varbuf_add_buf(&vb, "1234567890", 10); + test_pass(vb.used == 10); + test_pass(vb.size >= vb.used); + test_mem(vb.buf, ==, "1234567890", 10); + + varbuf_add_buf(&vb, "abcde", 5); + test_pass(vb.used == 15); + test_pass(vb.size >= vb.used); + test_mem(vb.buf, ==, "1234567890abcde", 15); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_add_char(void) +{ + struct varbuf vb; + + varbuf_init(&vb, 1); + + varbuf_add_char(&vb, 'a'); + test_pass(vb.used == 1); + test_pass(vb.size >= vb.used); + test_pass(vb.buf[0] == 'a'); + + varbuf_add_char(&vb, 'b'); + test_pass(vb.used == 2); + test_pass(vb.size >= vb.used); + test_mem(vb.buf, ==, "ab", 2); + + varbuf_add_char(&vb, 'c'); + test_pass(vb.used == 3); + test_pass(vb.size >= vb.used); + test_mem(vb.buf, ==, "abc", 3); + + varbuf_add_char(&vb, 'd'); + test_pass(vb.used == 4); + test_pass(vb.size >= vb.used); + test_mem(vb.buf, ==, "abcd", 4); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_dup_char(void) +{ + struct varbuf vb; + + varbuf_init(&vb, 5); + + varbuf_dup_char(&vb, 'z', 10); + test_pass(vb.used == 10); + test_pass(vb.size >= vb.used); + test_mem(vb.buf, ==, "zzzzzzzzzz", 10); + + varbuf_dup_char(&vb, 'y', 5); + test_pass(vb.used == 15); + test_pass(vb.size >= vb.used); + test_mem(vb.buf, ==, "zzzzzzzzzzyyyyy", 15); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_map_char(void) +{ + struct varbuf vb; + + varbuf_init(&vb, 5); + + varbuf_add_buf(&vb, "1234a5678a9012a", 15); + + varbuf_map_char(&vb, 'a', 'z'); + test_pass(vb.used == 15); + test_pass(vb.size >= vb.used); + test_mem(vb.buf, ==, "1234z5678z9012z", 15); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_add_dir(void) +{ + struct varbuf vb; + + varbuf_init(&vb, 10); + + varbuf_add_dir(&vb, ""); + varbuf_end_str(&vb); + test_str(vb.buf, ==, "/"); + varbuf_add_dir(&vb, ""); + varbuf_end_str(&vb); + test_str(vb.buf, ==, "/"); + varbuf_add_dir(&vb, "aa"); + varbuf_end_str(&vb); + test_str(vb.buf, ==, "/aa/"); + varbuf_add_dir(&vb, ""); + varbuf_end_str(&vb); + test_str(vb.buf, ==, "/aa/"); + + varbuf_reset(&vb); + + varbuf_add_dir(&vb, "/foo/bar"); + varbuf_end_str(&vb); + test_str(vb.buf, ==, "/foo/bar/"); + + varbuf_reset(&vb); + + varbuf_add_dir(&vb, "/foo/bar/"); + varbuf_end_str(&vb); + test_str(vb.buf, ==, "/foo/bar/"); + varbuf_add_dir(&vb, "quux"); + varbuf_end_str(&vb); + test_str(vb.buf, ==, "/foo/bar/quux/"); + varbuf_add_dir(&vb, "zoo"); + varbuf_end_str(&vb); + test_str(vb.buf, ==, "/foo/bar/quux/zoo/"); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_end_str(void) +{ + struct varbuf vb; + + varbuf_init(&vb, 10); + + varbuf_add_buf(&vb, "1234567890X", 11); + test_pass(vb.used == 11); + test_pass(vb.size >= vb.used); + test_mem(vb.buf, ==, "1234567890X", 11); + + varbuf_trunc(&vb, 10); + + varbuf_end_str(&vb); + test_pass(vb.used == 10); + test_pass(vb.size >= vb.used + 1); + test_pass(vb.buf[10] == '\0'); + test_str(vb.buf, ==, "1234567890"); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_get_str(void) +{ + struct varbuf vb; + const char *str; + + varbuf_init(&vb, 10); + + varbuf_add_buf(&vb, "1234567890", 10); + str = varbuf_get_str(&vb); + test_pass(vb.buf == str); + test_pass(vb.used == 10); + test_pass(vb.buf[vb.used] == '\0'); + test_pass(str[vb.used] == '\0'); + test_str(vb.buf, ==, "1234567890"); + test_str(str, ==, "1234567890"); + + varbuf_add_buf(&vb, "abcde", 5); + str = varbuf_get_str(&vb); + test_pass(vb.buf == str); + test_pass(vb.used == 15); + test_pass(vb.buf[vb.used] == '\0'); + test_pass(str[vb.used] == '\0'); + test_str(vb.buf, ==, "1234567890abcde"); + test_str(str, ==, "1234567890abcde"); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_printf(void) +{ + struct varbuf vb; + + varbuf_init(&vb, 5); + + /* Test normal format printing. */ + varbuf_printf(&vb, "format %s number %d", "string", 10); + test_pass(vb.used == strlen("format string number 10")); + test_pass(vb.size >= vb.used); + test_str(vb.buf, ==, "format string number 10"); + + varbuf_reset(&vb); + + /* Test concatenated format printing. */ + varbuf_printf(&vb, "format %s number %d", "string", 10); + varbuf_printf(&vb, " extra %s", "string"); + test_pass(vb.used == strlen("format string number 10 extra string")); + test_pass(vb.size >= vb.used); + test_str(vb.buf, ==, "format string number 10 extra string"); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_reset(void) +{ + struct varbuf vb; + + varbuf_init(&vb, 10); + + varbuf_add_buf(&vb, "1234567890", 10); + + varbuf_reset(&vb); + test_pass(vb.used == 0); + test_pass(vb.size >= vb.used); + + varbuf_add_buf(&vb, "abcdefghijklmno", 15); + test_pass(vb.used == 15); + test_pass(vb.size >= vb.used); + test_mem(vb.buf, ==, "abcdefghijklmno", 15); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_snapshot(void) +{ + struct varbuf vb; + struct varbuf_state vbs; + + varbuf_init(&vb, 0); + + test_pass(vb.used == 0); + varbuf_snapshot(&vb, &vbs); + test_pass(vb.used == 0); + test_pass(vb.used == vbs.used); + test_pass(varbuf_rollback_len(&vbs) == 0); + test_str(varbuf_rollback_start(&vbs), ==, ""); + + varbuf_add_buf(&vb, "1234567890", 10); + varbuf_end_str(&vb); + test_pass(vb.used == 10); + test_pass(varbuf_rollback_len(&vbs) == 10); + test_str(varbuf_rollback_start(&vbs), ==, "1234567890"); + varbuf_rollback(&vbs); + varbuf_end_str(&vb); + test_pass(vb.used == 0); + test_pass(varbuf_rollback_len(&vbs) == 0); + test_str(varbuf_rollback_start(&vbs), ==, ""); + + varbuf_add_buf(&vb, "1234567890", 10); + varbuf_end_str(&vb); + test_pass(vb.used == 10); + test_pass(varbuf_rollback_len(&vbs) == 10); + test_str(varbuf_rollback_start(&vbs), ==, "1234567890"); + varbuf_snapshot(&vb, &vbs); + test_pass(vb.used == 10); + test_pass(varbuf_rollback_len(&vbs) == 0); + test_str(varbuf_rollback_start(&vbs), ==, ""); + + varbuf_add_buf(&vb, "1234567890", 10); + varbuf_end_str(&vb); + test_pass(vb.used == 20); + test_pass(varbuf_rollback_len(&vbs) == 10); + test_str(varbuf_rollback_start(&vbs), ==, "1234567890"); + varbuf_rollback(&vbs); + varbuf_end_str(&vb); + test_pass(vb.used == 10); + test_pass(varbuf_rollback_len(&vbs) == 0); + test_str(varbuf_rollback_start(&vbs), ==, ""); + + varbuf_destroy(&vb); +} + +static void +test_varbuf_detach(void) +{ + struct varbuf vb; + char *str; + + varbuf_init(&vb, 0); + + varbuf_add_buf(&vb, "1234567890", 10); + + str = varbuf_detach(&vb); + + test_mem(str, ==, "1234567890", 10); + test_pass(vb.used == 0); + test_pass(vb.size == 0); + test_pass(vb.buf == NULL); + + free(str); +} + +TEST_ENTRY(test) +{ + test_plan(152); + + test_varbuf_init(); + test_varbuf_prealloc(); + test_varbuf_new(); + test_varbuf_grow(); + test_varbuf_trunc(); + test_varbuf_add_buf(); + test_varbuf_add_char(); + test_varbuf_dup_char(); + test_varbuf_map_char(); + test_varbuf_add_dir(); + test_varbuf_end_str(); + test_varbuf_get_str(); + test_varbuf_printf(); + test_varbuf_reset(); + test_varbuf_snapshot(); + test_varbuf_detach(); + + /* TODO: Complete. */ +} diff --git a/lib/dpkg/t/t-version.c b/lib/dpkg/t/t-version.c new file mode 100644 index 0000000..6a771ca --- /dev/null +++ b/lib/dpkg/t/t-version.c @@ -0,0 +1,308 @@ +/* + * libdpkg - Debian packaging suite library routines + * t-version.c - test version handling + * + * Copyright © 2009-2014 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 of the License, 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 this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <stdlib.h> + +#include <dpkg/test.h> +#include <dpkg/dpkg.h> +#include <dpkg/dpkg-db.h> + +static void +test_version_blank(void) +{ + struct dpkg_version a; + + dpkg_version_blank(&a); + test_pass(a.epoch == 0); + test_pass(a.version == NULL); + test_pass(a.revision == NULL); +} + +static void +test_version_is_informative(void) +{ + struct dpkg_version a; + + dpkg_version_blank(&a); + test_fail(dpkg_version_is_informative(&a)); + + a.epoch = 1; + test_pass(dpkg_version_is_informative(&a)); + + dpkg_version_blank(&a); + a.version = "1"; + test_pass(dpkg_version_is_informative(&a)); + + dpkg_version_blank(&a); + a.revision = "1"; + test_pass(dpkg_version_is_informative(&a)); +} + +static void +test_version_compare(void) +{ + struct dpkg_version a, b; + + dpkg_version_blank(&a); + dpkg_version_blank(&b); + test_pass(dpkg_version_compare(&a, &b) == 0); + + a.epoch = 1; + b.epoch = 2; + test_fail(dpkg_version_compare(&a, &b) == 0); + + a = DPKG_VERSION_OBJECT(0, "1", "1"); + b = DPKG_VERSION_OBJECT(0, "2", "1"); + test_fail(dpkg_version_compare(&a, &b) == 0); + + a = DPKG_VERSION_OBJECT(0, "1", "1"); + b = DPKG_VERSION_OBJECT(0, "1", "2"); + test_fail(dpkg_version_compare(&a, &b) == 0); + + /* Test for version equality. */ + a = b = DPKG_VERSION_OBJECT(0, "0", "0"); + test_pass(dpkg_version_compare(&a, &b) == 0); + + a = DPKG_VERSION_OBJECT(0, "0", "00"); + b = DPKG_VERSION_OBJECT(0, "00", "0"); + test_pass(dpkg_version_compare(&a, &b) == 0); + + a = b = DPKG_VERSION_OBJECT(1, "2", "3"); + test_pass(dpkg_version_compare(&a, &b) == 0); + + /* Test for epoch difference. */ + a = DPKG_VERSION_OBJECT(0, "0", "0"); + b = DPKG_VERSION_OBJECT(1, "0", "0"); + test_pass(dpkg_version_compare(&a, &b) < 0); + test_pass(dpkg_version_compare(&b, &a) > 0); + + /* Test for version component difference. */ + a = DPKG_VERSION_OBJECT(0, "a", "0"); + b = DPKG_VERSION_OBJECT(0, "b", "0"); + test_pass(dpkg_version_compare(&a, &b) < 0); + test_pass(dpkg_version_compare(&b, &a) > 0); + + /* Test for revision component difference. */ + a = DPKG_VERSION_OBJECT(0, "0", "a"); + b = DPKG_VERSION_OBJECT(0, "0", "b"); + test_pass(dpkg_version_compare(&a, &b) < 0); + test_pass(dpkg_version_compare(&b, &a) > 0); + + /* TODO: Complete. */ +} + +static void +test_version_relate(void) +{ + struct dpkg_version a, b; + + dpkg_version_blank(&a); + dpkg_version_blank(&b); + test_pass(dpkg_version_relate(&a, DPKG_RELATION_NONE, &b)); + + a = DPKG_VERSION_OBJECT(0, "1", "1"); + b = DPKG_VERSION_OBJECT(0, "1", "1"); + test_pass(dpkg_version_relate(&a, DPKG_RELATION_EQ, &b)); + test_fail(dpkg_version_relate(&a, DPKG_RELATION_LT, &b)); + test_pass(dpkg_version_relate(&a, DPKG_RELATION_LE, &b)); + test_fail(dpkg_version_relate(&a, DPKG_RELATION_GT, &b)); + test_pass(dpkg_version_relate(&a, DPKG_RELATION_GE, &b)); + + a = DPKG_VERSION_OBJECT(0, "1", "1"); + b = DPKG_VERSION_OBJECT(0, "2", "1"); + test_fail(dpkg_version_relate(&a, DPKG_RELATION_EQ, &b)); + test_pass(dpkg_version_relate(&a, DPKG_RELATION_LT, &b)); + test_pass(dpkg_version_relate(&a, DPKG_RELATION_LE, &b)); + test_fail(dpkg_version_relate(&a, DPKG_RELATION_GT, &b)); + test_fail(dpkg_version_relate(&a, DPKG_RELATION_GE, &b)); + + a = DPKG_VERSION_OBJECT(0, "2", "1"); + b = DPKG_VERSION_OBJECT(0, "1", "1"); + test_fail(dpkg_version_relate(&a, DPKG_RELATION_EQ, &b)); + test_fail(dpkg_version_relate(&a, DPKG_RELATION_LT, &b)); + test_fail(dpkg_version_relate(&a, DPKG_RELATION_LE, &b)); + test_pass(dpkg_version_relate(&a, DPKG_RELATION_GT, &b)); + test_pass(dpkg_version_relate(&a, DPKG_RELATION_GE, &b)); +} + +static void +test_version_parse(void) +{ + struct dpkg_error err; + struct dpkg_version a, b; + const char *p; + char *verstr; + + /* Test 0 versions. */ + dpkg_version_blank(&a); + b = DPKG_VERSION_OBJECT(0, "0", ""); + + test_pass(parseversion(&a, "0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + test_pass(parseversion(&a, "0:0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + b = DPKG_VERSION_OBJECT(0, "0", "0"); + test_pass(parseversion(&a, "0:0-0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + b = DPKG_VERSION_OBJECT(0, "0.0", "0.0"); + test_pass(parseversion(&a, "0:0.0-0.0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + /* Test epoched versions. */ + b = DPKG_VERSION_OBJECT(1, "0", ""); + test_pass(parseversion(&a, "1:0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + b = DPKG_VERSION_OBJECT(5, "1", ""); + test_pass(parseversion(&a, "5:1", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + /* Test multiple hyphens. */ + b = DPKG_VERSION_OBJECT(0, "0-0", "0"); + test_pass(parseversion(&a, "0:0-0-0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + b = DPKG_VERSION_OBJECT(0, "0-0-0", "0"); + test_pass(parseversion(&a, "0:0-0-0-0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + /* Test multiple colons. */ + b = DPKG_VERSION_OBJECT(0, "0:0", "0"); + test_pass(parseversion(&a, "0:0:0-0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + b = DPKG_VERSION_OBJECT(0, "0:0:0", "0"); + test_pass(parseversion(&a, "0:0:0:0-0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + /* Test multiple hyphens and colons. */ + b = DPKG_VERSION_OBJECT(0, "0:0-0", "0"); + test_pass(parseversion(&a, "0:0:0-0-0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + b = DPKG_VERSION_OBJECT(0, "0-0:0", "0"); + test_pass(parseversion(&a, "0:0-0:0-0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + /* Test valid characters in upstream version. */ + b = DPKG_VERSION_OBJECT(0, "09azAZ.-+~:", "0"); + test_pass(parseversion(&a, "0:09azAZ.-+~:-0", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + /* Test valid characters in revision. */ + b = DPKG_VERSION_OBJECT(0, "0", "azAZ09.+~"); + test_pass(parseversion(&a, "0:0-azAZ09.+~", NULL) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + /* Test version with leading and trailing spaces. */ + b = DPKG_VERSION_OBJECT(0, "0", "1"); + test_pass(parseversion(&a, " 0:0-1", &err) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + test_pass(parseversion(&a, "0:0-1 ", &err) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + test_pass(parseversion(&a, " 0:0-1 ", &err) == 0); + test_pass(dpkg_version_compare(&a, &b) == 0); + + /* Test empty version. */ + test_pass(parseversion(&a, "", &err) != 0); + test_error(err); + test_pass(parseversion(&a, " ", &err) != 0); + test_error(err); + + /* Test empty upstream version after epoch. */ + test_fail(parseversion(&a, "0:", &err) == 0); + test_error(err); + + /* Test empty epoch in version. */ + test_fail(parseversion(&a, ":1.0", &err) == 0); + test_error(err); + + /* Test empty revision in version. */ + test_fail(parseversion(&a, "1.0-", &err) == 0); + test_error(err); + + /* Test version with embedded spaces. */ + test_fail(parseversion(&a, "0:0 0-1", &err) == 0); + test_error(err); + + /* Test version with negative epoch. */ + test_fail(parseversion(&a, "-1:0-1", &err) == 0); + test_error(err); + + /* Test version with huge epoch. */ + test_fail(parseversion(&a, "999999999999999999999999:0-1", &err) == 0); + test_error(err); + + /* Test invalid characters in epoch. */ + test_fail(parseversion(&a, "a:0-0", &err) == 0); + test_error(err); + test_fail(parseversion(&a, "A:0-0", &err) == 0); + test_error(err); + + /* Test invalid empty upstream version. */ + test_fail(parseversion(&a, "-0", &err) == 0); + test_error(err); + test_fail(parseversion(&a, "0:-0", &err) == 0); + test_error(err); + + /* Test upstream version not starting with a digit */ + test_fail(parseversion(&a, "0:abc3-0", &err) == 0); + test_warn(err); + + /* Test invalid characters in upstream version. */ + verstr = test_alloc(strdup("0:0a-0")); + for (p = "!#@$%&/|\\<>()[]{};,_=*^'"; *p; p++) { + verstr[3] = *p; + test_fail(parseversion(&a, verstr, &err) == 0); + test_warn(err); + } + free(verstr); + + /* Test invalid characters in revision. */ + test_fail(parseversion(&a, "0:0-0:0", &err) == 0); + test_warn(err); + + verstr = test_alloc(strdup("0:0-0")); + for (p = "!#@$%&/|\\<>()[]{}:;,_=*^'"; *p; p++) { + verstr[4] = *p; + test_fail(parseversion(&a, verstr, &err) == 0); + test_warn(err); + } + free(verstr); + + /* TODO: Complete. */ +} + +TEST_ENTRY(test) +{ + test_plan(196); + + test_version_blank(); + test_version_is_informative(); + test_version_compare(); + test_version_relate(); + test_version_parse(); +} |