diff options
-rw-r--r-- | testapp.c | 47 | ||||
-rw-r--r-- | util.c | 17 | ||||
-rw-r--r-- | util.h | 15 |
3 files changed, 78 insertions, 1 deletions
@@ -22,6 +22,8 @@ #include "cache.h" #include "util.h" +#define TMP_TEMPLATE "/tmp/test_file.XXXXXXX" + enum test_return { TEST_SKIP, TEST_PASS, TEST_FAIL }; static enum test_return cache_create_test(void) @@ -387,6 +389,50 @@ static int connect_server(const char *hostname, in_port_t port) return sock; } +static enum test_return test_vperror(void) { + int rv = 0; + int oldstderr = dup(STDERR_FILENO); + char tmpl[sizeof(TMP_TEMPLATE)+1]; + strncpy(tmpl, TMP_TEMPLATE, sizeof(TMP_TEMPLATE)+1); + + int newfile = mkstemp(tmpl); + assert(newfile > 0); + rv = dup2(newfile, STDERR_FILENO); + assert(rv == STDERR_FILENO); + rv = close(newfile); + assert(rv == 0); + + errno = EIO; + vperror("Old McDonald had a farm. %s", "EI EIO"); + + /* Restore stderr */ + rv = dup2(oldstderr, STDERR_FILENO); + assert(rv == STDERR_FILENO); + + + /* Go read the file */ + char buf[80] = { 0 }; + FILE *efile = fopen(tmpl, "r"); + assert(efile); + char *prv = fgets(buf, sizeof(buf), efile); + assert(prv); + fclose(efile); + + unlink(tmpl); + + char expected[80] = { 0 }; + snprintf(expected, sizeof(expected), + "Old McDonald had a farm. EI EIO: %s\n", strerror(EIO)); + + /* + fprintf(stderr, + "\nExpected: ``%s''" + "\nGot: ``%s''\n", expected, buf); + */ + + return strcmp(expected, buf) == 0 ? TEST_PASS : TEST_FAIL; +} + static enum test_return test_issue_72(void) { in_port_t port; @@ -435,6 +481,7 @@ struct testcase testcases[] = { { "strtoull", test_safe_strtoull }, { "issue_44", test_issue_44 }, { "issue_72", test_issue_72 }, + { "vperror", test_vperror }, { NULL, NULL } }; @@ -1,9 +1,10 @@ -#include <stdlib.h> +#include <stdio.h> #include <assert.h> #include <ctype.h> #include <errno.h> #include <string.h> #include <stdlib.h> +#include <stdarg.h> #include "memcached.h" @@ -88,3 +89,17 @@ bool safe_strtol(const char *str, int32_t *out) { } return false; } + +void vperror(const char *fmt, ...) { + int old_errno = errno; + char buf[80]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + errno = old_errno; + + perror(buf); +} @@ -11,3 +11,18 @@ bool safe_strtoull(const char *str, uint64_t *out); bool safe_strtoll(const char *str, int64_t *out); bool safe_strtoul(const char *str, uint32_t *out); bool safe_strtol(const char *str, int32_t *out); + +#ifdef __GCC +# define __gcc_attribute__ __attribute__ +#else +# define __gcc_attribute__(x) +#endif + +/** + * Vararg variant of perror that makes for more useful error messages + * when reporting with parameters. + * + * @param fmt a printf format + */ +void vperror(const char *fmt, ...) + __gcc_attribute__ ((format (printf, 1, 2))); |