r12468@Kushana: nickm | 2007-03-06 15:24:00 -0500

More unit tests: gcov is fun.


svn:r9748
This commit is contained in:
Nick Mathewson 2007-03-06 20:25:44 +00:00
parent c9e2766e75
commit 5d1bee87ff
8 changed files with 239 additions and 33 deletions

View file

@ -6,6 +6,9 @@ Changes in version 0.2.0.1-alpha - 2007-??-??
o Minor features (logging): o Minor features (logging):
- Always prepend "Bug: " to any log message about a bug. - Always prepend "Bug: " to any log message about a bug.
o Minor features (other):
- More unit tests.
o Removed features: o Removed features:
- Removed support for the old binary "version 0" controller protocol. - Removed support for the old binary "version 0" controller protocol.
This has been deprecated since 0.1.1, and warnings have been issued This has been deprecated since 0.1.1, and warnings have been issued

View file

@ -99,12 +99,16 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
#define ATTR_MALLOC __attribute__((malloc)) #define ATTR_MALLOC __attribute__((malloc))
#define ATTR_NONNULL(x) __attribute__((nonnull x)) #define ATTR_NONNULL(x) __attribute__((nonnull x))
#define PREDICT(exp, val) __builtin_expect((exp), (val)) #define PREDICT(exp, val) __builtin_expect((exp), (val))
#define PREDICT_LIKELY(exp) PREDICT((exp), 1)
#define PREDICT_UNLIKELY(exp) PREDICT((exp), 0)
#else #else
#define ATTR_NORETURN #define ATTR_NORETURN
#define ATTR_PURE #define ATTR_PURE
#define ATTR_MALLOC #define ATTR_MALLOC
#define ATTR_NONNULL(x) #define ATTR_NONNULL(x)
#define PREDICT(exp, val) (exp) #define PREDICT(exp, val) (exp)
#define PREDICT_LIKELY(exp) (exp)
#define PREDICT_UNLIKELY(exp) (exp)
#endif #endif
/* ===== String compatibility */ /* ===== String compatibility */

View file

@ -129,10 +129,10 @@ void _log_fn(int severity, uint32_t domain,
* of the current function name. */ * of the current function name. */
#define log_fn(severity, domain, args...) \ #define log_fn(severity, domain, args...) \
_log_fn(severity, domain, __PRETTY_FUNCTION__, args) _log_fn(severity, domain, __PRETTY_FUNCTION__, args)
#define log_debug(domain, args...) \ #define log_debug(domain, args...) \
do { \ do { \
if (PREDICT(_log_global_min_severity == LOG_DEBUG, 0)) \ if (PREDICT_UNLIKELY(_log_global_min_severity == LOG_DEBUG)) \
_log_fn(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args); \ _log_fn(LOG_DEBUG, domain, __PRETTY_FUNCTION__, args); \
} while (0) } while (0)
#define log_info(domain, args...) \ #define log_info(domain, args...) \
_log_fn(LOG_INFO, domain, __PRETTY_FUNCTION__, args) _log_fn(LOG_INFO, domain, __PRETTY_FUNCTION__, args)

View file

@ -71,21 +71,28 @@ extern int have_failed;
#define test_eq_ptr(expr1, expr2) \ #define test_eq_ptr(expr1, expr2) \
test_eq_type(void*, "%p", expr1, expr2) test_eq_type(void*, "%p", expr1, expr2)
#define test_neq(expr1, expr2) \ #define test_neq_type(tp, fmt, expr1, expr2) \
STMT_BEGIN \ STMT_BEGIN \
long v1=(long)(expr1), v2=(long)(expr2); \ tp v1=(tp)(expr1); \
if (v1!=v2) { printf("."); fflush(stdout); } else { \ tp v2=(tp)(expr2); \
have_failed = 1; \ if (v1!=v2) { printf("."); fflush(stdout); } else { \
printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n"\ have_failed = 1; \
" (%ld == %ld)\n", \ printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n" \
_SHORT_FILE_, \ " ("fmt" == "fmt")\n", \
__LINE__, \ _SHORT_FILE_, \
PRETTY_FUNCTION, \ __LINE__, \
#expr1, #expr2, \ PRETTY_FUNCTION, \
v1, v2); \ #expr1, #expr2, \
return; \ v1, v2); \
return; \
} STMT_END } 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) \ #define test_streq(expr1, expr2) \
STMT_BEGIN \ STMT_BEGIN \
const char *v1=(expr1), *v2=(expr2); \ const char *v1=(expr1), *v2=(expr2); \

View file

@ -115,7 +115,7 @@ _tor_malloc(size_t size DMALLOC_PARAMS)
#endif #endif
result = dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC, 0, 0); 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."); log_err(LD_MM,"Out of memory on malloc(). Dying.");
/* If these functions die within a worker process, they won't call /* 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 * 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; void *result;
result = dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0); 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."); log_err(LD_MM,"Out of memory on realloc(). Dying.");
exit(1); exit(1);
} }
@ -165,7 +165,7 @@ _tor_strdup(const char *s DMALLOC_PARAMS)
tor_assert(s); tor_assert(s);
dup = dmalloc_strdup(file, line, s, 0); 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."); log_err(LD_MM,"Out of memory on strdup(). Dying.");
exit(1); exit(1);
} }
@ -517,7 +517,7 @@ tor_parse_long(const char *s, int base, long min, long max,
CHECK_STRTOX_RESULT(); CHECK_STRTOX_RESULT();
} }
/** As tor_parse_log, but return an unsigned long. */ /** As tor_parse_long, but return an unsigned long. */
unsigned long unsigned long
tor_parse_ulong(const char *s, int base, unsigned long min, tor_parse_ulong(const char *s, int base, unsigned long min,
unsigned long max, int *ok, char **next) 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) base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
{ {
const char *end; const char *end;
int v1,v2; int v1,v2;
if ((srclen % 2) != 0) if ((srclen % 2) != 0)
return -1; 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. /** Return the number of microseconds elapsed between *start and *end.
*/ */
long long
tv_udiff(struct timeval *start, struct timeval *end) tv_udiff(const struct timeval *start, const struct timeval *end)
{ {
long udiff; long udiff;
long secdiff = end->tv_sec - start->tv_sec; 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. /** Return -1 if *a \< *b, 0 if *a==*b, and 1 if *a \> *b.
*/ */
int 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) if (a->tv_sec > b->tv_sec)
return 1; 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. /** Increment *a by the number of seconds and microseconds in *b.
*/ */
void 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_usec += b->tv_usec;
a->tv_sec += b->tv_sec + (a->tv_usec / 1000000); a->tv_sec += b->tv_sec + (a->tv_usec / 1000000);

View file

@ -41,7 +41,7 @@
#ifdef __GNUC__ #ifdef __GNUC__
/** Macro: evaluate the expression x, which we expect to be false. /** Macro: evaluate the expression x, which we expect to be false.
* Used to hint the compiler that a branch won't be taken. */ * 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 #else
#define PREDICT_FALSE(x) !(x) #define PREDICT_FALSE(x) !(x)
#endif #endif
@ -85,14 +85,18 @@ void _tor_free(void *mem);
extern int dmalloc_free(const char *file, const int line, void *pnt, extern int dmalloc_free(const char *file, const int line, void *pnt,
const int func_id); const int func_id);
#define tor_free(p) do { \ #define tor_free(p) do { \
if (PREDICT((p)!=NULL, 1)) { \ if (PREDICT_LIKELY((p)!=NULL)) { \
dmalloc_free(_SHORT_FILE_, __LINE__, (p), 0); \ dmalloc_free(_SHORT_FILE_, __LINE__, (p), 0); \
(p)=NULL; \ (p)=NULL; \
} \ } \
} while (0) } while (0)
#else #else
#define tor_free(p) do { if (PREDICT((p)!=NULL,1)) { free(p); (p)=NULL;} } \ #define tor_free(p) do { \
while (0) if (PREDICT_LIKELY((p)!=NULL)) { \
free(p); \
(p)=NULL; \
} \
} while (0)
#endif #endif
#define tor_malloc(size) _tor_malloc(size DMALLOC_ARGS) #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); int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen);
/* Time helpers */ /* 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_addms(struct timeval *a, long ms);
void tv_add(struct timeval *a, struct timeval *b); void tv_add(struct timeval *a, const struct timeval *b);
int tv_cmp(struct timeval *a, struct timeval *b); int tv_cmp(const struct timeval *a, const struct timeval *b);
time_t tor_timegm(struct tm *tm); time_t tor_timegm(struct tm *tm);
#define RFC1123_TIME_LEN 29 #define RFC1123_TIME_LEN 29
void format_rfc1123_time(char *buf, time_t t); void format_rfc1123_time(char *buf, time_t t);

View file

@ -4178,7 +4178,7 @@ static int need_to_update_have_min_dir_info = 1;
int int
router_have_minimum_dir_info(void) 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(); update_router_have_minimum_dir_info();
need_to_update_have_min_dir_info = 0; need_to_update_have_min_dir_info = 0;
} }

View file

@ -535,6 +535,12 @@ test_crypto(void)
test_eq(i,0); test_eq(i,0);
test_memeq(data2, "\xf0\xd6\x78\xaf\xfc\x00\x01\x00",8); 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(data1);
tor_free(data2); tor_free(data2);
tor_free(data3); tor_free(data3);
@ -606,6 +612,10 @@ test_util(void)
end.tv_usec = 7000; 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)); test_eq(2000L, tv_udiff(&start, &end));
end.tv_sec = 6; end.tv_sec = 6;
@ -620,6 +630,17 @@ test_util(void)
test_eq(-1005000L, tv_udiff(&start, &end)); 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 /* The test values here are confirmed to be correct on a platform
* with a working timegm. */ * with a working timegm. */
a_time.tm_year = 2003-1900; a_time.tm_year = 2003-1900;
@ -644,6 +665,8 @@ test_util(void)
i = parse_rfc1123_time(timestr, &t_res); i = parse_rfc1123_time(timestr, &t_res);
test_eq(i,0); test_eq(i,0);
test_eq(t_res, (time_t)1091580502UL); 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() */ /* Test tor_strstrip() */
strlcpy(buf, "Testing 1 2 3", sizeof(buf)); strlcpy(buf, "Testing 1 2 3", sizeof(buf));
@ -694,6 +717,11 @@ test_util(void)
/* Test tor_parse_long. */ /* Test tor_parse_long. */
test_eq(10L, tor_parse_long("10",10,0,100,NULL,NULL)); 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(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 tor_parse_uint64. */
test_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp)); 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("abcdef", "dee")>0);
test_assert(strcmpend("ab", "abb")<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]; char tmpbuf[INET_NTOA_BUF_LEN];
struct in_addr in; struct in_addr in;
@ -785,6 +833,58 @@ test_util(void)
test_streq("\"abcd\"", escaped("abcd")); test_streq("\"abcd\"", escaped("abcd"));
test_streq("\"\\\\\\n\\r\\t\\\"\\'\"", escaped("\\\n\r\t\"\'")); test_streq("\"\\\\\\n\\r\\t\\\"\\'\"", escaped("\\\n\r\t\"\'"));
test_streq("\"z\\001abc\\277d\"", escaped("z\001abc\277d")); 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 */ /* Test wrap_string */
{ {
@ -809,6 +909,11 @@ test_util(void)
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl); 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 static void
@ -983,9 +1088,11 @@ test_smartlist(void)
test_streq(cp, "50,a,canal,man,noon,panama,plan,radar"); test_streq(cp, "50,a,canal,man,noon,panama,plan,radar");
tor_free(cp); 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, "noon"));
test_assert(!smartlist_string_isin(sl, "noonoon")); 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, 50));
test_assert(!smartlist_string_num_isin(sl, 60)); test_assert(!smartlist_string_num_isin(sl, 60));
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
@ -1061,6 +1168,85 @@ test_smartlist(void)
smartlist_free(sl); 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 static int
_compare_strings_for_pqueue(const void *s1, const void *s2) _compare_strings_for_pqueue(const void *s1, const void *s2)
{ {
@ -1959,6 +2145,7 @@ main(int c, char**v)
test_control_formats(); test_control_formats();
test_pqueue(); test_pqueue();
test_mmap(); test_mmap();
test_threads();
puts("\n========================= Onion Skins ====================="); puts("\n========================= Onion Skins =====================");
test_onion_handshake(); test_onion_handshake();
puts("\n========================= Directory Formats ==============="); puts("\n========================= Directory Formats ===============");