tests: Test some corner cases of upkg_decode_index.
authorNick Bowler <nbowler@draconx.ca>
Fri, 4 May 2012 00:24:48 +0000 (20:24 -0400)
committerNick Bowler <nbowler@draconx.ca>
Fri, 4 May 2012 00:50:28 +0000 (20:50 -0400)
It turns out that upkg_decode_index does not fail when there is not
a complete index encoding in the available data.  Add a test case (which
currently does not pass) to verify that the function fails in that
situation.

.gitignore
Makefile.am
test/.gitignore [new file with mode: 0644]
test/decodeindex.c [new file with mode: 0644]
tests/.gitignore [new file with mode: 0644]
tests/libupkg-index-decode.sh [new file with mode: 0644]

index 4bc00768d3e999c16be1b5938aa6fbee8661a227..d0c38772e14b4a8470d9546300dbfa15de7bea76 100644 (file)
@@ -26,3 +26,4 @@ lib
 warn-on-use.h
 arg-nonnull.h
 c++defs.h
+/test-suite.log
index f5c126c96f46026257bd262839f679f5d96eab3c..eb605df6ffd6d46e98a9deaabe4e5ee558fd95da 100644 (file)
@@ -4,8 +4,11 @@
 # This is free software: you are free to do what the fuck you want to.
 # There is NO WARRANTY, to the extent permitted by law.
 
+AUTOMAKE_OPTIONS = parallel-tests color-tests
 ACLOCAL_AMFLAGS = -I m4
 
+AM_CPPFLAGS = -I$(top_srcdir)/src
+
 EXTRA_DIST = m4/gnulib-cache.m4
 
 dist_man_MANS = doc/man/upkg.1
@@ -18,3 +21,13 @@ SUBDIRS += libltdl
 endif
 
 SUBDIRS += src
+
+check_PROGRAMS = test/decodeindex
+test_decodeindex_LDADD = src/libupkg.la lib/libgnu.la
+
+TESTS_ENVIRONMENT = SHELL='$(SHELL)' EXEEXT='$(EXEEXT)'
+TEST_EXTENSIONS = .sh
+SH_LOG_COMPILER = $(SHELL)
+
+TESTS = tests/libupkg-index-decode.sh
+EXTRA_DIST += $(TESTS)
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644 (file)
index 0000000..cd79e46
--- /dev/null
@@ -0,0 +1 @@
+decodeindex
diff --git a/test/decodeindex.c b/test/decodeindex.c
new file mode 100644 (file)
index 0000000..bbe15f4
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Tool for decoding compact index values for testing.
+ * Copyright © 2012 Nick Bowler
+ *
+ * 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 3 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <getopt.h>
+
+#include <upkg.h>
+
+#define PROGNAME "decodeindex"
+static const char *progname = PROGNAME;
+static const unsigned char sopts[] = "VH";
+static const struct option lopts[] = {
+       { "version", 0, NULL, 'V' },
+       { "help",    0, NULL, 'H' },
+       { 0 }
+};
+
+/*
+ * Decode a hexadecimal string into a sequence of bytes.  If there are an
+ * odd number of nibbles, treat the first character as the least significant
+ * nibble of the first byte.  The result is written to the buffer specified by
+ * buf.  At most n bytes are written to the buffer.
+ *
+ * Returns the number of bytes that would be written provided that n was large
+ * enough, or (size_t)-1 if the input is not valid.
+ */
+static size_t decode_hex(const char *hex, unsigned char *buf, size_t n)
+{
+       size_t len, count = 0;
+       char tmp[] = "00";
+
+       for (len = 0; hex[len]; len++) {
+               if (!isxdigit(hex[len]))
+                       return -1;
+       }
+
+       if (!len)
+               return 0;
+
+       switch (len % 2) {
+               while (len > 0) {
+                       case 0: tmp[0] = *hex++; len--;
+                       case 1: tmp[1] = *hex++; len--;
+
+                       if (count < n)
+                               buf[count] = strtoul(tmp, NULL, 16);
+                       count++;
+               }
+       }
+
+       return count;
+}
+
+static void print_usage(FILE *f)
+{
+       fprintf(f, "Usage: %s [options] index [index ...]\n", progname);
+}
+
+static void print_version(void)
+{
+       printf("%s (%s) %s\n", PROGNAME, PACKAGE_NAME, PACKAGE_VERSION);
+       puts("Copyright (C) 2012 Nick Bowler.");
+       puts("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.");
+       puts("This is free software: you are free to change and redistribute it.");
+       puts("There is NO WARRANTY, to the extent permitted by law.");
+}
+
+static void print_bytes(FILE *f, int indent, void *buf, size_t n)
+{
+       fprintf(f, "%*s", indent, "");
+       for (size_t i = 0; i < n; i++)
+               fprintf(f, "%*s%.2hhx", i != 0, "", ((unsigned char *)buf)[i]);
+       putc('\n', f);
+}
+
+static int print_index(const char *hex)
+{
+       unsigned char buf[32];
+       long index = 0;
+       size_t n, rc;
+       int ret = -1;
+
+       n = decode_hex(hex, buf, sizeof buf);
+       if (n == -1) {
+               fprintf(stderr, "%s: invalid hex sequence: %s\n",
+                               progname, hex);
+               goto out;
+       } else if (n == 0) {
+               fprintf(stderr, "%s: empty argument\n", progname);
+               goto out;
+       } else if (n > sizeof buf) {
+               fprintf(stderr, "%s: hex sequence too long: %s\n",
+                               progname, hex);
+               goto out;
+       }
+               
+       rc = upkg_decode_index(&index, buf, n);
+       if (rc == 0) {
+               fprintf(stderr, "%s: invalid index encoding:\n", progname);
+               print_bytes(stderr, 4, buf, n);
+               goto out;
+       } else if (rc < n) {
+               fprintf(stderr, "%s: trailing bytes in argument:\n", progname);
+               print_bytes(stderr, 4, buf+rc, n-rc);
+               /* Non-fatal */
+       }
+
+       ret = 0;
+out:
+       printf("%ld\n", index);
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       int opt, ret = EXIT_SUCCESS;
+
+       if (argc > 0)
+               progname = argv[0];
+
+       while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
+               switch (opt) {
+               case 'V':
+                       print_version();
+                       return EXIT_SUCCESS;
+               case 'H':
+                       print_usage(stdout);
+                       return EXIT_SUCCESS;
+               default:
+                       print_usage(stderr);
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (!argv[optind]) {
+               print_usage(stderr);
+               return EXIT_FAILURE;
+       }
+
+       for (int i = optind; i < argc; i++) {
+               if (print_index(argv[i]) != 0) {
+                       ret = EXIT_FAILURE;
+               }
+       }
+
+       return ret;
+}
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644 (file)
index 0000000..397b4a7
--- /dev/null
@@ -0,0 +1 @@
+*.log
diff --git a/tests/libupkg-index-decode.sh b/tests/libupkg-index-decode.sh
new file mode 100644 (file)
index 0000000..b82bbc9
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/sh
+#
+# Check various corner cases of upkg_decode_index.
+# Copyright © 2012 Nick Bowler
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+decodeindex=test/decodeindex$EXEEXT
+scriptname=$0
+
+test_index() {
+       decode_cmd=`exec 3>&1
+               { $decodeindex "$1" 3>&-
+                       echo decode_status=$? >&3
+               } | { read val 3>&-
+                       echo decode_val=$val >&3
+               }`
+       eval "$decode_cmd"
+
+       case $# in
+       2)
+               (exit $decode_status) || return 1
+               if test x"$decode_val" != x"$2"; then
+                       printf '%s: result (%d) does not match expected (%d)\n' \
+                               "$scriptname" "$decode_val" "$2"
+                       return 1
+               fi
+               ;;
+       1)
+               if (exit $decode_status); then
+                       printf '%s: false positive on (%s), got (%d)\n' \
+                               "$scriptname" "$1" "$decode_val"
+                       return 1
+               fi
+               ;;
+       esac
+}
+
+test_index 00 0
+test_index 4000 0
+test_index 408000 0
+test_index 40808000 0
+test_index 4080808000 0
+
+# False positives
+test_index ''
+test_index 40
+test_index 4080
+test_index 408080
+test_index 40808080
+test_index 4080808080
+test_index 408080808000