From 5d1bee87ffe3dcdaa9e7960b0fed836aa1d01b9b Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 6 Mar 2007 20:25:44 +0000 Subject: [PATCH] r12468@Kushana: nickm | 2007-03-06 15:24:00 -0500 More unit tests: gcov is fun. svn:r9748 --- ChangeLog | 3 + src/common/compat.h | 4 + src/common/log.h | 8 +- src/common/test.h | 33 +++++--- src/common/util.c | 15 ++-- src/common/util.h | 18 +++-- src/or/routerlist.c | 2 +- src/or/test.c | 189 +++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 239 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 63396962d5..fbfd3f6871 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,9 @@ Changes in version 0.2.0.1-alpha - 2007-??-?? o Minor features (logging): - Always prepend "Bug: " to any log message about a bug. + o Minor features (other): + - More unit tests. + o Removed features: - Removed support for the old binary "version 0" controller protocol. This has been deprecated since 0.1.1, and warnings have been issued diff --git a/src/common/compat.h b/src/common/compat.h index f578c128f8..07f194282f 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -99,12 +99,16 @@ extern INLINE double U64_TO_DBL(uint64_t x) { #define ATTR_MALLOC __attribute__((malloc)) #define ATTR_NONNULL(x) __attribute__((nonnull x)) #define PREDICT(exp, val) __builtin_expect((exp), (val)) +#define PREDICT_LIKELY(exp) PREDICT((exp), 1) +#define PREDICT_UNLIKELY(exp) PREDICT((exp), 0) #else #define ATTR_NORETURN #define ATTR_PURE #define ATTR_MALLOC #define ATTR_NONNULL(x) #define PREDICT(exp, val) (exp) +#define PREDICT_LIKELY(exp) (exp) +#define PREDICT_UNLIKELY(exp) (exp) #endif /* ===== String compatibility */ diff --git a/src/common/log.h b/src/common/log.h index d01305b90a..af17e2e2c2 100644 --- a/src/common/log.h +++ b/src/common/log.h @@ -129,10 +129,10 @@ void _log_fn(int severity, uint32_t domain, * of the current function name. */ #define log_fn(severity, domain, args...) \ _log_fn(severity, domain, __PRETTY_FUNCTION__, args) -#define log_debug(domain, args...) \ - do { \ - if (PREDICT(_log_global_min_severity == LOG_DEBUG, 0)) \ - _log_fn(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args); \ +#define log_debug(domain, args...) \ + do { \ + if (PREDICT_UNLIKELY(_log_global_min_severity == LOG_DEBUG)) \ + _log_fn(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args); \ } while (0) #define log_info(domain, args...) \ _log_fn(LOG_INFO, domain, __PRETTY_FUNCTION__, args) diff --git a/src/common/test.h b/src/common/test.h index 9edda8d296..41b795a89a 100644 --- a/src/common/test.h +++ b/src/common/test.h @@ -71,21 +71,28 @@ extern int have_failed; #define test_eq_ptr(expr1, expr2) \ test_eq_type(void*, "%p", expr1, expr2) -#define test_neq(expr1, expr2) \ - STMT_BEGIN \ - long v1=(long)(expr1), v2=(long)(expr2); \ - if (v1!=v2) { printf("."); fflush(stdout); } else { \ - have_failed = 1; \ - printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n"\ - " (%ld == %ld)\n", \ - _SHORT_FILE_, \ - __LINE__, \ - PRETTY_FUNCTION, \ - #expr1, #expr2, \ - v1, v2); \ - return; \ +#define test_neq_type(tp, fmt, expr1, expr2) \ + STMT_BEGIN \ + tp v1=(tp)(expr1); \ + tp v2=(tp)(expr2); \ + if (v1!=v2) { printf("."); fflush(stdout); } else { \ + have_failed = 1; \ + printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n" \ + " ("fmt" == "fmt")\n", \ + _SHORT_FILE_, \ + __LINE__, \ + PRETTY_FUNCTION, \ + #expr1, #expr2, \ + v1, v2); \ + return; \ } STMT_END +#define test_neq(expr1, expr2) \ + test_neq_type(long, "%ld", expr1, expr2) + +#define test_neq_ptr(expr1, expr2) \ + test_neq_type(void *, "%p", expr1, expr2) + #define test_streq(expr1, expr2) \ STMT_BEGIN \ const char *v1=(expr1), *v2=(expr2); \ diff --git a/src/common/util.c b/src/common/util.c index 6c1ff3bc3b..d21d0c07d1 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -115,7 +115,7 @@ _tor_malloc(size_t size DMALLOC_PARAMS) #endif result = dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC, 0, 0); - if (PREDICT(result == NULL, 0)) { + if (PREDICT_UNLIKELY(result == NULL)) { log_err(LD_MM,"Out of memory on malloc(). Dying."); /* If these functions die within a worker process, they won't call * spawn_exit, but that's ok, since the parent will run out of memory soon @@ -147,7 +147,7 @@ _tor_realloc(void *ptr, size_t size DMALLOC_PARAMS) void *result; result = dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0); - if (PREDICT(result == NULL, 0)) { + if (PREDICT_UNLIKELY(result == NULL)) { log_err(LD_MM,"Out of memory on realloc(). Dying."); exit(1); } @@ -165,7 +165,7 @@ _tor_strdup(const char *s DMALLOC_PARAMS) tor_assert(s); dup = dmalloc_strdup(file, line, s, 0); - if (PREDICT(dup == NULL, 0)) { + if (PREDICT_UNLIKELY(dup == NULL)) { log_err(LD_MM,"Out of memory on strdup(). Dying."); exit(1); } @@ -517,7 +517,7 @@ tor_parse_long(const char *s, int base, long min, long max, CHECK_STRTOX_RESULT(); } -/** As tor_parse_log, but return an unsigned long. */ +/** As tor_parse_long, but return an unsigned long. */ unsigned long tor_parse_ulong(const char *s, int base, unsigned long min, unsigned long max, int *ok, char **next) @@ -615,6 +615,7 @@ int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen) { const char *end; + int v1,v2; if ((srclen % 2) != 0) return -1; @@ -812,7 +813,7 @@ wrap_string(smartlist_t *out, const char *string, size_t width, /** Return the number of microseconds elapsed between *start and *end. */ long -tv_udiff(struct timeval *start, struct timeval *end) +tv_udiff(const struct timeval *start, const struct timeval *end) { long udiff; long secdiff = end->tv_sec - start->tv_sec; @@ -829,7 +830,7 @@ tv_udiff(struct timeval *start, struct timeval *end) /** Return -1 if *a \< *b, 0 if *a==*b, and 1 if *a \> *b. */ int -tv_cmp(struct timeval *a, struct timeval *b) +tv_cmp(const struct timeval *a, const struct timeval *b) { if (a->tv_sec > b->tv_sec) return 1; @@ -845,7 +846,7 @@ tv_cmp(struct timeval *a, struct timeval *b) /** Increment *a by the number of seconds and microseconds in *b. */ void -tv_add(struct timeval *a, struct timeval *b) +tv_add(struct timeval *a, const struct timeval *b) { a->tv_usec += b->tv_usec; a->tv_sec += b->tv_sec + (a->tv_usec / 1000000); diff --git a/src/common/util.h b/src/common/util.h index 5d9a16030d..9f37e6ad3f 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -41,7 +41,7 @@ #ifdef __GNUC__ /** Macro: evaluate the expression x, which we expect to be false. * Used to hint the compiler that a branch won't be taken. */ -#define PREDICT_FALSE(x) PREDICT((x) == ((typeof(x)) 0), 0) +#define PREDICT_FALSE(x) PREDICT_UNLIKELY((x) == ((typeof(x)) 0)) #else #define PREDICT_FALSE(x) !(x) #endif @@ -85,14 +85,18 @@ void _tor_free(void *mem); extern int dmalloc_free(const char *file, const int line, void *pnt, const int func_id); #define tor_free(p) do { \ - if (PREDICT((p)!=NULL, 1)) { \ + if (PREDICT_LIKELY((p)!=NULL)) { \ dmalloc_free(_SHORT_FILE_, __LINE__, (p), 0); \ (p)=NULL; \ } \ } while (0) #else -#define tor_free(p) do { if (PREDICT((p)!=NULL,1)) { free(p); (p)=NULL;} } \ - while (0) +#define tor_free(p) do { \ + if (PREDICT_LIKELY((p)!=NULL)) { \ + free(p); \ + (p)=NULL; \ + } \ + } while (0) #endif #define tor_malloc(size) _tor_malloc(size DMALLOC_ARGS) @@ -172,10 +176,10 @@ void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen); int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen); /* Time helpers */ -long tv_udiff(struct timeval *start, struct timeval *end); +long tv_udiff(const struct timeval *start, const struct timeval *end); void tv_addms(struct timeval *a, long ms); -void tv_add(struct timeval *a, struct timeval *b); -int tv_cmp(struct timeval *a, struct timeval *b); +void tv_add(struct timeval *a, const struct timeval *b); +int tv_cmp(const struct timeval *a, const struct timeval *b); time_t tor_timegm(struct tm *tm); #define RFC1123_TIME_LEN 29 void format_rfc1123_time(char *buf, time_t t); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index b975594474..3af73a7a4e 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -4178,7 +4178,7 @@ static int need_to_update_have_min_dir_info = 1; int router_have_minimum_dir_info(void) { - if (PREDICT(need_to_update_have_min_dir_info, 0)) { + if (PREDICT_UNLIKELY(need_to_update_have_min_dir_info)) { update_router_have_minimum_dir_info(); need_to_update_have_min_dir_info = 0; } diff --git a/src/or/test.c b/src/or/test.c index ddb31188a2..309d4032a3 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -535,6 +535,12 @@ test_crypto(void) test_eq(i,0); test_memeq(data2, "\xf0\xd6\x78\xaf\xfc\x00\x01\x00",8); + /* now try some failing base16 decodes */ + test_eq(-1, base16_decode(data2, 8, data1, 15)); /* odd input len */ + test_eq(-1, base16_decode(data2, 7, data1, 16)); /* dest too short */ + strlcpy(data1, "f0dz!8affc000100", 1024); + test_eq(-1, base16_decode(data2, 8, data1, 16)); + tor_free(data1); tor_free(data2); tor_free(data3); @@ -606,6 +612,10 @@ test_util(void) end.tv_usec = 7000; + test_assert(tv_cmp(&start, &end)<0); + test_assert(tv_cmp(&end, &start)>0); + test_assert(tv_cmp(&end, &end)==0); + test_eq(2000L, tv_udiff(&start, &end)); end.tv_sec = 6; @@ -620,6 +630,17 @@ test_util(void) test_eq(-1005000L, tv_udiff(&start, &end)); + tv_addms(&end, 5090); + test_eq(end.tv_sec, 9); + test_eq(end.tv_usec, 90000); + + end.tv_usec = 999990; + start.tv_sec = 1; + start.tv_usec = 500; + tv_add(&start, &end); + test_eq(start.tv_sec, 11); + test_eq(start.tv_usec, 490); + /* The test values here are confirmed to be correct on a platform * with a working timegm. */ a_time.tm_year = 2003-1900; @@ -644,6 +665,8 @@ test_util(void) i = parse_rfc1123_time(timestr, &t_res); test_eq(i,0); test_eq(t_res, (time_t)1091580502UL); + test_eq(-1, parse_rfc1123_time("Wed, zz Aug 2004 99-99x99 GMT", &t_res)); + tor_gettimeofday(&start); /* Test tor_strstrip() */ strlcpy(buf, "Testing 1 2 3", sizeof(buf)); @@ -694,6 +717,11 @@ test_util(void) /* Test tor_parse_long. */ test_eq(10L, tor_parse_long("10",10,0,100,NULL,NULL)); test_eq(0L, tor_parse_long("10",10,50,100,NULL,NULL)); + test_eq(-50L, tor_parse_long("-50",10,-100,100,NULL,NULL)); + + /* Test tor_parse_ulong */ + test_eq(10UL, tor_parse_ulong("10",10,0,100,NULL,NULL)); + test_eq(0UL, tor_parse_ulong("10",10,50,100,NULL,NULL)); /* Test tor_parse_uint64. */ test_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp)); @@ -772,6 +800,26 @@ test_util(void) test_assert(strcmpend("abcdef", "dee")>0); test_assert(strcmpend("ab", "abb")<0); + test_assert(strcasecmpend("AbcDEF", "abcdef")==0); + test_assert(strcasecmpend("abcdef", "dEF")==0); + test_assert(strcasecmpend("abcDEf", "deg")<0); + test_assert(strcasecmpend("abcdef", "DEE")>0); + test_assert(strcasecmpend("ab", "abB")<0); + + /* Test mem_is_zero */ + memset(buf,0,128); + buf[128] = 'x'; + test_assert(tor_digest_is_zero(buf)); + test_assert(tor_mem_is_zero(buf, 10)); + test_assert(tor_mem_is_zero(buf, 20)); + test_assert(tor_mem_is_zero(buf, 128)); + test_assert(!tor_mem_is_zero(buf, 129)); + buf[60] = (char)255; + test_assert(!tor_mem_is_zero(buf, 128)); + buf[0] = (char)1; + test_assert(!tor_mem_is_zero(buf, 10)); + + /* Test inet_ntoa */ { char tmpbuf[INET_NTOA_BUF_LEN]; struct in_addr in; @@ -785,6 +833,58 @@ test_util(void) test_streq("\"abcd\"", escaped("abcd")); test_streq("\"\\\\\\n\\r\\t\\\"\\'\"", escaped("\\\n\r\t\"\'")); test_streq("\"z\\001abc\\277d\"", escaped("z\001abc\277d")); + test_assert(NULL == escaped(NULL)); + + /* Test strndup and memdup */ + { + const char *s = "abcdefghijklmnopqrstuvwxyz"; + cp = tor_strndup(s, 30); + test_streq(cp, s); /* same string, */ + test_neq(cp, s); /* but different pointers. */ + tor_free(cp); + + cp = tor_strndup(s, 5); + test_streq(cp, "abcde"); + tor_free(cp); + + s = "a\0b\0c\0d\0e\0"; + cp = tor_memdup(s,10); + test_memeq(cp, s, 10); /* same ram, */ + test_neq(cp, s); /* but different pointers. */ + tor_free(cp); + } + + /* Test str-foo functions */ + cp = tor_strdup("abcdef"); + test_assert(tor_strisnonupper(cp)); + cp[3] = 'D'; + test_assert(!tor_strisnonupper(cp)); + tor_strupper(cp); + test_streq(cp, "ABCDEF"); + test_assert(tor_strisprint(cp)); + cp[3] = 3; + test_assert(!tor_strisprint(cp)); + tor_free(cp); + + /* Test eat_whitespace. */ + { + const char *s = " \n a"; + test_eq_ptr(eat_whitespace(s), s+4); + s = "abcd"; + test_eq_ptr(eat_whitespace(s), s); + s = "#xyz\nab"; + test_eq_ptr(eat_whitespace(s), s+5); + } + + /* Test memmem */ + { + const char *haystack = "abcde"; + tor_assert(!tor_memmem(haystack, 5, "ef", 2)); + test_eq_ptr(tor_memmem(haystack, 5, "cd", 2), haystack + 2); + test_eq_ptr(tor_memmem(haystack, 5, "cde", 3), haystack + 2); + haystack = "ababcad"; + test_eq_ptr(tor_memmem(haystack, 7, "abc", 3), haystack + 2); + } /* Test wrap_string */ { @@ -809,6 +909,11 @@ test_util(void) SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); } + + /* now make sure time works. */ + tor_gettimeofday(&end); + /* We might've timewarped a little. */ + test_assert(tv_udiff(&start, &end) >= -5000); } static void @@ -983,9 +1088,11 @@ test_smartlist(void) test_streq(cp, "50,a,canal,man,noon,panama,plan,radar"); tor_free(cp); - /* Test string_isin. */ + /* Test string_isin and isin_case and num_isin */ test_assert(smartlist_string_isin(sl, "noon")); test_assert(!smartlist_string_isin(sl, "noonoon")); + test_assert(smartlist_string_isin_case(sl, "nOOn")); + test_assert(!smartlist_string_isin_case(sl, "nooNooN")); test_assert(smartlist_string_num_isin(sl, 50)); test_assert(!smartlist_string_num_isin(sl, 60)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); @@ -1061,6 +1168,85 @@ test_smartlist(void) smartlist_free(sl); } +/* stop threads running at once. */ +static tor_mutex_t *_thread_test_mutex = NULL; +/* make sure that threads have to run at the same time. */ +static tor_mutex_t *_thread_test_start1 = NULL; +static tor_mutex_t *_thread_test_start2 = NULL; +static strmap_t *_thread_test_strmap = NULL; + +static void +_thread_test_func(void* _s) +{ + char *s = _s; + int i; + tor_mutex_t *m; + if (!strcmp(s, "thread 1")) + m = _thread_test_start1; + else + m = _thread_test_start2; + tor_mutex_acquire(m); + + for (i=0; i<1000; ++i) { + tor_mutex_acquire(_thread_test_mutex); + strmap_set(_thread_test_strmap, "last to run", + (void*)(int)tor_get_thread_id()); + tor_mutex_release(_thread_test_mutex); + } + strmap_set(_thread_test_strmap, s, (void*)(int)tor_get_thread_id()); + + tor_mutex_release(m); + + spawn_exit(); +} + +static void +test_threads(void) +{ + char *s1, *s2; + int done = 0; +#ifndef TOR_IS_MULTITHREADED + /* Skip this test if we aren't threading. We should be threading most + * everywhere by now. */ + if (1) + return 0; +#endif + _thread_test_mutex = tor_mutex_new(); + _thread_test_start1 = tor_mutex_new(); + _thread_test_start2 = tor_mutex_new(); + _thread_test_strmap = strmap_new(); + s1 = tor_strdup("thread 1"); + s2 = tor_strdup("thread 2"); + tor_mutex_acquire(_thread_test_start1); + tor_mutex_acquire(_thread_test_start2); + spawn_func(_thread_test_func, s1); + spawn_func(_thread_test_func, s2); + tor_mutex_release(_thread_test_start2); + tor_mutex_release(_thread_test_start1); + while (!done) { + tor_mutex_acquire(_thread_test_mutex); + strmap_assert_ok(_thread_test_strmap); + if (strmap_get(_thread_test_strmap, "thread 1") && + strmap_get(_thread_test_strmap, "thread 2")) + done = 1; + tor_mutex_release(_thread_test_mutex); + } + tor_mutex_free(_thread_test_mutex); + + /* different thread IDs. */ + test_neq_ptr(strmap_get(_thread_test_strmap, "thread 1"), + strmap_get(_thread_test_strmap, "thread 2")); + test_assert(strmap_get(_thread_test_strmap, "thread 1") == + strmap_get(_thread_test_strmap, "last to run") || + strmap_get(_thread_test_strmap, "thread 2") == + strmap_get(_thread_test_strmap, "last to run")); + + strmap_free(_thread_test_strmap, NULL); + + tor_free(s1); + tor_free(s2); +} + static int _compare_strings_for_pqueue(const void *s1, const void *s2) { @@ -1959,6 +2145,7 @@ main(int c, char**v) test_control_formats(); test_pqueue(); test_mmap(); + test_threads(); puts("\n========================= Onion Skins ====================="); test_onion_handshake(); puts("\n========================= Directory Formats ===============");