aboutsummaryrefslogtreecommitdiff
path: root/src/test/test_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/test_util.c')
-rw-r--r--src/test/test_util.c1174
1 files changed, 853 insertions, 321 deletions
diff --git a/src/test/test_util.c b/src/test/test_util.c
index dd122b250d..036f739b89 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -9,6 +9,7 @@
#define CONTROL_PRIVATE
#define UTIL_PRIVATE
#include "or.h"
+#include "buffers.h"
#include "config.h"
#include "control.h"
#include "test.h"
@@ -69,7 +70,7 @@ test_util_read_until_eof_impl(const char *fname, size_t file_len,
fd = open(fifo_name, O_RDONLY|O_BINARY);
tt_int_op(fd, OP_GE, 0);
str = read_file_to_str_until_eof(fd, read_limit, &sz);
- tt_assert(str != NULL);
+ tt_ptr_op(str, OP_NE, NULL);
if (read_limit < file_len)
tt_int_op(sz, OP_EQ, read_limit);
@@ -366,7 +367,7 @@ test_util_time(void *arg)
* calculations internally, then catches the overflow. */
#define TV_SEC_MAX TIME_MAX
#define TV_SEC_MIN TIME_MIN
-#endif
+#endif /* defined(_WIN32) */
/* Assume tv_usec is an unsigned integer until proven otherwise */
#define TV_USEC_MAX UINT_MAX
@@ -634,13 +635,16 @@ test_util_time(void *arg)
* time_t */
a_time.tm_year = 2039-1900;
#if SIZEOF_TIME_T == 4
+ setup_full_capture_of_logs(LOG_WARN);
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+ expect_single_log_msg_containing("Result does not fit in tor_timegm");
+ teardown_capture_of_logs();
#elif SIZEOF_TIME_T == 8
t_res = 2178252895UL;
tt_int_op(t_res, OP_EQ, tor_timegm(&a_time));
tor_gmtime_r(&t_res, &b_time);
TM_EQUAL(a_time, b_time);
-#endif
+#endif /* SIZEOF_TIME_T == 4 || ... */
/* Test tor_timegm out of range */
@@ -650,8 +654,7 @@ test_util_time(void *arg)
setup_full_capture_of_logs(LOG_WARN); \
} while (0)
#define CHECK_TIMEGM_WARNING(msg) do { \
- expect_log_msg_containing(msg); \
- tt_int_op(1, OP_EQ, smartlist_len(mock_saved_logs())); \
+ expect_single_log_msg_containing(msg); \
teardown_capture_of_logs(); \
} while (0)
@@ -688,7 +691,7 @@ test_util_time(void *arg)
CAPTURE();
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
CHECK_TIMEGM_ARG_OUT_OF_RANGE();
-#endif
+#endif /* SIZEOF_INT == 4 || SIZEOF_INT == 8 */
#if SIZEOF_INT == 8
a_time.tm_year = -1*(1 << 48);
@@ -700,7 +703,7 @@ test_util_time(void *arg)
* a "correct" retrospective gregorian negative year value,
* which I'm pretty sure is:
* -1*(2^63)/60/60/24*2000/730485 + 1970 = -292277022657
- * 730485 is the number of days in two millenia, including leap days */
+ * 730485 is the number of days in two millennia, including leap days */
a_time.tm_year = -292277022657-1900;
CAPTURE();
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
@@ -710,7 +713,7 @@ test_util_time(void *arg)
CAPTURE();
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
CHECK_TIMEGM_ARG_OUT_OF_RANGE();
-#endif
+#endif /* SIZEOF_INT == 8 */
/* Wrong year >= INT32_MAX - 1900 */
#if SIZEOF_INT == 4 || SIZEOF_INT == 8
@@ -723,7 +726,7 @@ test_util_time(void *arg)
CAPTURE();
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
CHECK_TIMEGM_ARG_OUT_OF_RANGE();
-#endif
+#endif /* SIZEOF_INT == 4 || SIZEOF_INT == 8 */
#if SIZEOF_INT == 8
/* one of the largest tm_year values my 64 bit system supports */
@@ -736,7 +739,7 @@ test_util_time(void *arg)
* a "correct" proleptic gregorian year value,
* which I'm pretty sure is:
* (2^63-1)/60/60/24*2000/730485 + 1970 = 292277026596
- * 730485 is the number of days in two millenia, including leap days */
+ * 730485 is the number of days in two millennia, including leap days */
a_time.tm_year = 292277026596-1900;
CAPTURE();
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
@@ -751,7 +754,7 @@ test_util_time(void *arg)
CAPTURE();
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
CHECK_TIMEGM_ARG_OUT_OF_RANGE();
-#endif
+#endif /* SIZEOF_INT == 8 */
/* month */
a_time.tm_year = 2007-1900; /* restore valid year */
@@ -872,7 +875,7 @@ test_util_time(void *arg)
* a "correct" retrospective gregorian negative year value,
* which I'm pretty sure is:
* -1*(2^63)/60/60/24*2000/730485 + 1970 = -292277022657
- * 730485 is the number of days in two millenia, including leap days
+ * 730485 is the number of days in two millennia, including leap days
* (int64_t)b_time.tm_year == (-292277022657LL-1900LL) without clamping */
t_res = INT64_MIN;
CAPTURE();
@@ -887,7 +890,7 @@ test_util_time(void *arg)
teardown_capture_of_logs();
}
}
-#endif
+#endif /* SIZEOF_TIME_T == 8 */
/* time_t >= INT_MAX yields a year clamped to 2037 or 9999,
* depending on whether the implementation of the system gmtime(_r)
@@ -903,7 +906,7 @@ test_util_time(void *arg)
tt_assert(b_time.tm_year == (2037-1900) ||
b_time.tm_year == (2038-1900));
}
-#endif
+#endif /* SIZEOF_TIME_T == 4 || SIZEOF_TIME_T == 8 */
#if SIZEOF_TIME_T == 8
{
@@ -918,7 +921,7 @@ test_util_time(void *arg)
* a "correct" proleptic gregorian year value,
* which I'm pretty sure is:
* (2^63-1)/60/60/24*2000/730485 + 1970 = 292277026596
- * 730485 is the number of days in two millenia, including leap days
+ * 730485 is the number of days in two millennia, including leap days
* (int64_t)b_time.tm_year == (292277026596L-1900L) without clamping */
t_res = INT64_MAX;
CAPTURE();
@@ -928,7 +931,7 @@ test_util_time(void *arg)
tt_assert(b_time.tm_year == (2037-1900) ||
b_time.tm_year == (9999-1900));
}
-#endif
+#endif /* SIZEOF_TIME_T == 8 */
/* Test {format,parse}_rfc1123_time */
@@ -964,7 +967,9 @@ test_util_time(void *arg)
strlcpy(timestr, "Wed, 17 Feb 2038 06:13:20 GMT", sizeof(timestr));
t_res = 0;
+ CAPTURE();
i = parse_rfc1123_time(timestr, &t_res);
+ CHECK_TIMEGM_WARNING("does not fit in tor_timegm");
tt_int_op(-1,OP_EQ, i);
#elif SIZEOF_TIME_T == 8
tt_str_op("Wed, 17 Feb 2038 06:13:20 GMT",OP_EQ, timestr);
@@ -973,7 +978,7 @@ test_util_time(void *arg)
i = parse_rfc1123_time(timestr, &t_res);
tt_int_op(0,OP_EQ, i);
tt_int_op(t_res,OP_EQ, (time_t)2150000000UL);
-#endif
+#endif /* SIZEOF_TIME_T == 4 || ... */
/* The timezone doesn't matter */
t_res = 0;
@@ -1039,13 +1044,16 @@ test_util_time(void *arg)
/* This value is out of range with 32 bit time_t, but in range for 64 bit
* time_t */
t_res = 0;
- i = parse_iso_time("2038-02-17 06:13:20", &t_res);
#if SIZEOF_TIME_T == 4
+ CAPTURE();
+ i = parse_iso_time("2038-02-17 06:13:20", &t_res);
tt_int_op(-1,OP_EQ, i);
+ CHECK_TIMEGM_WARNING("does not fit in tor_timegm");
#elif SIZEOF_TIME_T == 8
+ i = parse_iso_time("2038-02-17 06:13:20", &t_res);
tt_int_op(0,OP_EQ, i);
tt_int_op(t_res,OP_EQ, (time_t)2150000000UL);
-#endif
+#endif /* SIZEOF_TIME_T == 4 || ... */
tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-zz 99-99x99", &t_res));
tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-32 00:00:00", &t_res));
@@ -1059,6 +1067,23 @@ test_util_time(void *arg)
tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04 00:48:22.100", &t_res));
tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04 00:48:22XYZ", &t_res));
+ /* but... that _is_ acceptable if we aren't being strict. */
+ t_res = 0;
+ i = parse_iso_time_("2004-08-04 00:48:22XYZ", &t_res, 0, 0);
+ tt_int_op(0,OP_EQ, i);
+ tt_int_op(t_res,OP_EQ, (time_t)1091580502UL);
+
+ /* try nospace variant. */
+ t_res = 0;
+ i = parse_iso_time_nospace("2004-08-04T00:48:22", &t_res);
+ tt_int_op(0,OP_EQ, i);
+ tt_int_op(t_res,OP_EQ, (time_t)1091580502UL);
+
+ tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04T00:48:22", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time_nospace("2004-08-04 00:48:22", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04x00:48:22", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time_nospace("2004-08-04x00:48:22", &t_res));
+
/* Test tor_gettimeofday */
end.tv_sec = 4;
@@ -1111,7 +1136,7 @@ test_util_time(void *arg)
/* This SHOULD work on windows too; see bug #18665 */
tt_str_op("2038-02-17 06:13:20",OP_EQ, timestr);
#endif
-#endif
+#endif /* SIZEOF_TIME_T == 4 || ... */
#undef CAPTURE
#undef CHECK_TIMEGM_ARG_OUT_OF_RANGE
@@ -1200,13 +1225,16 @@ test_util_parse_http_time(void *arg)
#if SIZEOF_TIME_T == 4
/* parse_http_time should indicate failure on overflow, but it doesn't yet.
* Hopefully #18480 will improve the failure semantics in this case. */
+ setup_full_capture_of_logs(LOG_WARN);
tt_int_op(0,OP_EQ,parse_http_time("Wed, 17 Feb 2038 06:13:20 GMT", &a_time));
tt_int_op((time_t)-1,OP_EQ, tor_timegm(&a_time));
+ expect_single_log_msg_containing("does not fit in tor_timegm");
+ teardown_capture_of_logs();
#elif SIZEOF_TIME_T == 8
tt_int_op(0,OP_EQ,parse_http_time("Wed, 17 Feb 2038 06:13:20 GMT", &a_time));
tt_int_op((time_t)2150000000UL,OP_EQ, tor_timegm(&a_time));
T("2038-02-17 06:13:20");
-#endif
+#endif /* SIZEOF_TIME_T == 4 || ... */
tt_int_op(-1,OP_EQ, parse_http_time("2004-08-zz 99-99x99 GMT", &a_time));
tt_int_op(-1,OP_EQ, parse_http_time("2011-03-32 00:00:00 GMT", &a_time));
@@ -1219,7 +1247,7 @@ test_util_parse_http_time(void *arg)
#undef T
done:
- ;
+ teardown_capture_of_logs();
}
static void
@@ -1453,7 +1481,7 @@ test_util_config_line_comment_character(void *arg)
tor_free(k); tor_free(v);
test_streq(str, "");
-#endif
+#endif /* 0 */
done:
tor_free(k);
@@ -1584,7 +1612,7 @@ test_util_config_line_escaped_content(void *arg)
str = parse_config_line_from_str_verbose(str, &k, &v, NULL);
tt_ptr_op(str, OP_EQ, NULL);
tor_free(k); tor_free(v);
-#endif
+#endif /* 0 */
str = buf6;
@@ -1656,14 +1684,14 @@ test_util_config_line_crlf(void *arg)
tt_assert(str);
tt_str_op(k,OP_EQ,"Hello");
tt_str_op(v,OP_EQ,"world");
- tt_assert(!err);
+ tt_ptr_op(err, OP_EQ, NULL);
tor_free(k); tor_free(v);
str = parse_config_line_from_str_verbose(str, &k, &v, &err);
tt_assert(str);
tt_str_op(k,OP_EQ,"Hello");
tt_str_op(v,OP_EQ,"nice big world");
- tt_assert(!err);
+ tt_ptr_op(err, OP_EQ, NULL);
tor_free(k); tor_free(v);
tt_str_op(str,OP_EQ, "");
@@ -1768,7 +1796,7 @@ test_util_expand_filename(void *arg)
done:
tor_free(str);
}
-#endif
+#endif /* !defined(_WIN32) */
/** Test tor_escape_str_for_pt_args(). */
static void
@@ -1923,7 +1951,7 @@ test_util_strmisc(void *arg)
tt_assert(!tor_mem_is_zero(buf, 10));
/* Test 'escaped' */
- tt_assert(NULL == escaped(NULL));
+ tt_ptr_op(escaped(NULL), OP_EQ, NULL);
tt_str_op("\"\"",OP_EQ, escaped(""));
tt_str_op("\"abcd\"",OP_EQ, escaped("abcd"));
tt_str_op("\"\\\\ \\n\\r\\t\\\"\\'\"",OP_EQ, escaped("\\ \n\r\t\"'"));
@@ -1981,23 +2009,23 @@ test_util_strmisc(void *arg)
/* Test memmem and memstr */
{
const char *haystack = "abcde";
- tt_assert(!tor_memmem(haystack, 5, "ef", 2));
+ tt_ptr_op(tor_memmem(haystack, 5, "ef", 2), OP_EQ, NULL);
tt_ptr_op(tor_memmem(haystack, 5, "cd", 2),OP_EQ, haystack + 2);
tt_ptr_op(tor_memmem(haystack, 5, "cde", 3),OP_EQ, haystack + 2);
- tt_assert(!tor_memmem(haystack, 4, "cde", 3));
+ tt_ptr_op(tor_memmem(haystack, 4, "cde", 3), OP_EQ, NULL);
haystack = "ababcad";
tt_ptr_op(tor_memmem(haystack, 7, "abc", 3),OP_EQ, haystack + 2);
tt_ptr_op(tor_memmem(haystack, 7, "ad", 2),OP_EQ, haystack + 5);
tt_ptr_op(tor_memmem(haystack, 7, "cad", 3),OP_EQ, haystack + 4);
- tt_assert(!tor_memmem(haystack, 7, "dadad", 5));
- tt_assert(!tor_memmem(haystack, 7, "abcdefghij", 10));
+ tt_ptr_op(tor_memmem(haystack, 7, "dadad", 5), OP_EQ, NULL);
+ tt_ptr_op(tor_memmem(haystack, 7, "abcdefghij", 10), OP_EQ, NULL);
/* memstr */
tt_ptr_op(tor_memstr(haystack, 7, "abc"),OP_EQ, haystack + 2);
tt_ptr_op(tor_memstr(haystack, 7, "cad"),OP_EQ, haystack + 4);
- tt_assert(!tor_memstr(haystack, 6, "cad"));
- tt_assert(!tor_memstr(haystack, 7, "cadd"));
- tt_assert(!tor_memstr(haystack, 7, "fe"));
- tt_assert(!tor_memstr(haystack, 7, "ababcade"));
+ tt_ptr_op(tor_memstr(haystack, 6, "cad"), OP_EQ, NULL);
+ tt_ptr_op(tor_memstr(haystack, 7, "cadd"), OP_EQ, NULL);
+ tt_ptr_op(tor_memstr(haystack, 7, "fe"), OP_EQ, NULL);
+ tt_ptr_op(tor_memstr(haystack, 7, "ababcade"), OP_EQ, NULL);
}
/* Test hex_str */
@@ -2107,10 +2135,13 @@ test_util_parse_integer(void *arg)
/* Base different than 10 */
tt_int_op(2L,OP_EQ, tor_parse_long("10",2,0,100,NULL,NULL));
tt_int_op(0L,OP_EQ, tor_parse_long("2",2,0,100,NULL,NULL));
- tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL));
tt_int_op(68284L,OP_EQ, tor_parse_long("10abc",16,0,70000,NULL,NULL));
tt_int_op(68284L,OP_EQ, tor_parse_long("10ABC",16,0,70000,NULL,NULL));
+ tor_capture_bugs_(2);
+ tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL));
tt_int_op(0,OP_EQ, tor_parse_long("10ABC",-1,0,70000,&i,NULL));
+ tt_int_op(2, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
+ tor_end_capture_bugs_();
tt_int_op(i,OP_EQ, 0);
/* Test parse_ulong */
@@ -2123,7 +2154,10 @@ test_util_parse_integer(void *arg)
tt_int_op(0UL,OP_EQ, tor_parse_ulong("8",8,0,100,NULL,NULL));
tt_int_op(50UL,OP_EQ, tor_parse_ulong("50",10,50,100,NULL,NULL));
tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,NULL,NULL));
+ tor_capture_bugs_(1);
tt_int_op(0UL,OP_EQ, tor_parse_ulong("50",-1,50,100,&i,NULL));
+ tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
+ tor_end_capture_bugs_();
tt_int_op(0,OP_EQ, i);
tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,&i,NULL));
tt_int_op(0,OP_EQ, i);
@@ -2139,8 +2173,11 @@ test_util_parse_integer(void *arg)
tt_assert(U64_LITERAL(0) ==
tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp));
tt_int_op(0,OP_EQ, i);
+ tor_capture_bugs_(1);
tt_assert(U64_LITERAL(0) ==
tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp));
+ tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
+ tor_end_capture_bugs_();
tt_int_op(0,OP_EQ, i);
{
@@ -2152,10 +2189,13 @@ test_util_parse_integer(void *arg)
tt_int_op(1,OP_EQ, i);
tt_assert(DBL_TO_U64(d) == 0);
d = tor_parse_double(" ", 0, (double)UINT64_MAX,&i,NULL);
+ tt_double_op(fabs(d), OP_LT, 1e-10);
tt_int_op(0,OP_EQ, i);
d = tor_parse_double(".0a", 0, (double)UINT64_MAX,&i,NULL);
+ tt_double_op(fabs(d), OP_LT, 1e-10);
tt_int_op(0,OP_EQ, i);
d = tor_parse_double(".0a", 0, (double)UINT64_MAX,&i,&cp);
+ tt_double_op(fabs(d), OP_LT, 1e-10);
tt_int_op(1,OP_EQ, i);
d = tor_parse_double("-.0", 0, (double)UINT64_MAX,&i,NULL);
tt_int_op(1,OP_EQ, i);
@@ -2224,114 +2264,340 @@ test_util_pow2(void *arg)
;
}
-/** Run unit tests for compression functions */
static void
-test_util_gzip(void *arg)
+test_util_compress_impl(compress_method_t method)
{
- char *buf1=NULL, *buf2=NULL, *buf3=NULL, *cp1, *cp2;
- const char *ccp2;
+ char *buf1=NULL, *buf2=NULL, *buf3=NULL;
size_t len1, len2;
- tor_zlib_state_t *state = NULL;
- (void)arg;
- buf1 = tor_strdup("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ");
- tt_assert(detect_compression_method(buf1, strlen(buf1)) == UNKNOWN_METHOD);
-
- tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
- GZIP_METHOD));
- tt_assert(buf2);
- tt_assert(len1 < strlen(buf1));
- tt_assert(detect_compression_method(buf2, len1) == GZIP_METHOD);
+ tt_assert(tor_compress_supports_method(method));
- tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1,
- GZIP_METHOD, 1, LOG_INFO));
- tt_assert(buf3);
- tt_int_op(strlen(buf1) + 1,OP_EQ, len2);
- tt_str_op(buf1,OP_EQ, buf3);
+ if (method != NO_METHOD) {
+ tt_ptr_op(tor_compress_version_str(method), OP_NE, NULL);
+ tt_ptr_op(tor_compress_header_version_str(method), OP_NE, NULL);
+ }
- tor_free(buf2);
- tor_free(buf3);
+ buf1 = tor_strdup("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ");
+ tt_assert(detect_compression_method(buf1, strlen(buf1)) == UNKNOWN_METHOD);
- tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
- ZLIB_METHOD));
- tt_assert(buf2);
- tt_assert(detect_compression_method(buf2, len1) == ZLIB_METHOD);
+ tt_assert(!tor_compress(&buf2, &len1, buf1, strlen(buf1)+1, method));
+ tt_ptr_op(buf2, OP_NE, NULL);
+ if (method == NO_METHOD) {
+ // The identity transform doesn't actually compress, and it isn't
+ // detectable as "the identity transform."
+ tt_int_op(len1, OP_EQ, strlen(buf1)+1);
+ tt_int_op(detect_compression_method(buf2, len1), OP_EQ, UNKNOWN_METHOD);
+ } else {
+ tt_int_op(len1, OP_LT, strlen(buf1));
+ tt_int_op(detect_compression_method(buf2, len1), OP_EQ, method);
+ }
- tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1,
- ZLIB_METHOD, 1, LOG_INFO));
- tt_assert(buf3);
- tt_int_op(strlen(buf1) + 1,OP_EQ, len2);
- tt_str_op(buf1,OP_EQ, buf3);
+ tt_assert(!tor_uncompress(&buf3, &len2, buf2, len1, method, 1, LOG_INFO));
+ tt_ptr_op(buf3, OP_NE, NULL);
+ tt_int_op(strlen(buf1) + 1, OP_EQ, len2);
+ tt_str_op(buf1, OP_EQ, buf3);
+ tt_int_op(buf3[len2], OP_EQ, 0);
/* Check whether we can uncompress concatenated, compressed strings. */
tor_free(buf3);
buf2 = tor_reallocarray(buf2, len1, 2);
memcpy(buf2+len1, buf2, len1);
- tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1*2,
- ZLIB_METHOD, 1, LOG_INFO));
- tt_int_op((strlen(buf1)+1)*2,OP_EQ, len2);
- tt_mem_op(buf3,OP_EQ,
+ tt_assert(!tor_uncompress(&buf3, &len2, buf2, len1*2, method, 1, LOG_INFO));
+ tt_int_op((strlen(buf1)+1)*2, OP_EQ, len2);
+ tt_mem_op(buf3, OP_EQ,
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0",
(strlen(buf1)+1)*2);
+ tt_int_op(buf3[len2], OP_EQ, 0);
+
+ /* Check whether we can uncompress partial strings */
tor_free(buf1);
tor_free(buf2);
tor_free(buf3);
- /* Check whether we can uncompress partial strings. */
- buf1 =
- tor_strdup("String with low redundancy that won't be compressed much.");
- tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
- ZLIB_METHOD));
- tt_assert(len1>16);
- /* when we allow an incomplete string, we should succeed.*/
- tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1-16,
- ZLIB_METHOD, 0, LOG_INFO));
- tt_assert(len2 > 5);
- buf3[len2]='\0';
- tt_assert(!strcmpstart(buf1, buf3));
-
- /* when we demand a complete string, this must fail. */
+ size_t b1len = 1<<10;
+ if (method == ZSTD_METHOD) {
+ // zstd needs a big input before it starts generating output that it
+ // can partially decompress.
+ b1len = 1<<18;
+ }
+ buf1 = tor_malloc(b1len);
+ crypto_rand(buf1, b1len);
+ tt_assert(!tor_compress(&buf2, &len1, buf1, b1len, method));
+ tt_int_op(len1, OP_GT, 16);
+ /* when we allow an incomplete output we should succeed.*/
+ tt_assert(!tor_uncompress(&buf3, &len2, buf2, len1-16,
+ method, 0, LOG_INFO));
+ tt_int_op(len2, OP_GT, 5);
+ tt_int_op(len2, OP_LE, len1);
+ tt_assert(fast_memeq(buf1, buf3, len2));
+ tt_int_op(buf3[len2], OP_EQ, 0);
+
+ /* when we demand a complete output from a real compression method, this
+ * must fail. */
tor_free(buf3);
- tt_assert(tor_gzip_uncompress(&buf3, &len2, buf2, len1-16,
- ZLIB_METHOD, 1, LOG_INFO));
- tt_assert(!buf3);
+ if (method != NO_METHOD) {
+ tt_assert(tor_uncompress(&buf3, &len2, buf2, len1-16,
+ method, 1, LOG_INFO));
+ tt_ptr_op(buf3, OP_EQ, NULL);
+ }
- /* Now, try streaming compression. */
+ done:
tor_free(buf1);
tor_free(buf2);
tor_free(buf3);
- state = tor_zlib_new(1, ZLIB_METHOD, HIGH_COMPRESSION);
+}
+
+static void
+test_util_compress_stream_impl(compress_method_t method,
+ compression_level_t level)
+{
+ char *buf1=NULL, *buf2=NULL, *buf3=NULL, *cp1, *cp2;
+ const char *ccp2;
+ size_t len1, len2;
+
+ tor_compress_state_t *state = NULL;
+ state = tor_compress_new(1, method, level);
tt_assert(state);
cp1 = buf1 = tor_malloc(1024);
len1 = 1024;
ccp2 = "ABCDEFGHIJABCDEFGHIJ";
len2 = 21;
- tt_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 0)
- == TOR_ZLIB_OK);
- tt_int_op(0,OP_EQ, len2); /* Make sure we compressed it all. */
+ tt_int_op(tor_compress_process(state, &cp1, &len1, &ccp2, &len2, 0),
+ OP_EQ, TOR_COMPRESS_OK);
+ tt_int_op(0, OP_EQ, len2); /* Make sure we compressed it all. */
tt_assert(cp1 > buf1);
len2 = 0;
cp2 = cp1;
- tt_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 1)
- == TOR_ZLIB_DONE);
- tt_int_op(0,OP_EQ, len2);
- tt_assert(cp1 > cp2); /* Make sure we really added something. */
+ tt_int_op(tor_compress_process(state, &cp1, &len1, &ccp2, &len2, 1),
+ OP_EQ, TOR_COMPRESS_DONE);
+ tt_int_op(0, OP_EQ, len2);
+ if (method == NO_METHOD) {
+ tt_ptr_op(cp1, OP_EQ, cp2);
+ } else {
+ tt_assert(cp1 > cp2); /* Make sure we really added something. */
+ }
+
+ tt_int_op(tor_compress_state_size(state), OP_GT, 0);
- tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf1, 1024-len1,
- ZLIB_METHOD, 1, LOG_WARN));
+ tt_assert(!tor_uncompress(&buf3, &len2, buf1, 1024-len1,
+ method, 1, LOG_WARN));
/* Make sure it compressed right. */
tt_str_op(buf3, OP_EQ, "ABCDEFGHIJABCDEFGHIJ");
- tt_int_op(21,OP_EQ, len2);
+ tt_int_op(21, OP_EQ, len2);
done:
if (state)
- tor_zlib_free(state);
+ tor_compress_free(state);
+ tor_free(buf1);
tor_free(buf2);
tor_free(buf3);
- tor_free(buf1);
+}
+
+/** Run unit tests for compression functions */
+static void
+test_util_compress(void *arg)
+{
+ const char *methodname = arg;
+ tt_assert(methodname);
+
+ compress_method_t method = compression_method_get_by_name(methodname);
+ tt_int_op(method, OP_NE, UNKNOWN_METHOD);
+
+ if (! tor_compress_supports_method(method)) {
+ tt_skip();
+ }
+
+ compression_level_t levels[] = {
+ BEST_COMPRESSION,
+ HIGH_COMPRESSION,
+ MEDIUM_COMPRESSION,
+ LOW_COMPRESSION
+ };
+
+ test_util_compress_impl(method);
+
+ for (unsigned l = 0; l < ARRAY_LENGTH(levels); ++l) {
+ compression_level_t level = levels[l];
+ test_util_compress_stream_impl(method, level);
+ }
+ done:
+ ;
+}
+
+static void
+test_util_decompress_concatenated_impl(compress_method_t method)
+{
+ char input[4096];
+ char *c1 = NULL, *c2 = NULL, *c3 = NULL;
+ char *result = NULL;
+ size_t sz1, sz2, sz3, szr;
+ int r;
+
+ crypto_rand(input, sizeof(input));
+
+ /* Compress the input in two chunks. */
+ r = tor_compress(&c1, &sz1, input, 2048, method);
+ tt_int_op(r, OP_EQ, 0);
+ r = tor_compress(&c2, &sz2, input+2048, 2048, method);
+ tt_int_op(r, OP_EQ, 0);
+
+ /* concatenate the chunks. */
+ sz3 = sz1 + sz2;
+ c3 = tor_malloc(sz3);
+ memcpy(c3, c1, sz1);
+ memcpy(c3+sz1, c2, sz2);
+
+ /* decompress the concatenated result */
+ r = tor_uncompress(&result, &szr, c3, sz3, method, 0, LOG_WARN);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(szr, OP_EQ, sizeof(input));
+ tt_mem_op(result, OP_EQ, input, sizeof(input));
+
+ done:
+ tor_free(c1);
+ tor_free(c2);
+ tor_free(c3);
+ tor_free(result);
+}
+
+static void
+test_util_decompress_concatenated(void *arg)
+{
+ const char *methodname = arg;
+ tt_assert(methodname);
+
+ compress_method_t method = compression_method_get_by_name(methodname);
+ tt_int_op(method, OP_NE, UNKNOWN_METHOD);
+ if (! tor_compress_supports_method(method)) {
+ tt_skip();
+ }
+
+ test_util_decompress_concatenated_impl(method);
+ done:
+ ;
+}
+
+static void
+test_util_decompress_junk_impl(compress_method_t method)
+{
+ char input[4096];
+ char *result = NULL, *result2 = NULL;
+ size_t szr, szr2, sz;
+ int r;
+
+ /* This shouldn't be a compressed string according to any method. */
+ strlcpy(input, "This shouldn't be a compressed string by any means.",
+ sizeof(input));
+ sz = strlen(input);
+ setup_capture_of_logs(LOG_WARN);
+ r = tor_uncompress(&result, &szr, input, sz, method, 0, LOG_WARN);
+ tt_int_op(r, OP_EQ, -1);
+ tt_ptr_op(result, OP_EQ, NULL);
+ expect_log_msg_containing("Error while uncompressing data: bad input?");
+ mock_clean_saved_logs();
+
+ /* Now try again, with a compressed object that starts out good and turns to
+ junk. */
+ crypto_rand(input, sizeof(input));
+ r = tor_compress(&result, &szr, input, sizeof(input), method);
+ tt_int_op(r, OP_EQ, 0);
+ crypto_rand(result+szr/2, szr-(szr/2)); // trash the 2nd half of the result
+ r = tor_uncompress(&result2, &szr2, result, szr, method, 0, LOG_WARN);
+ tt_int_op(r, OP_EQ, -1);
+ expect_log_msg_containing("Error while uncompressing data: bad input?");
+
+ done:
+ teardown_capture_of_logs();
+ tor_free(result);
+ tor_free(result2);
+}
+
+static void
+test_util_decompress_junk(void *arg)
+{
+ const char *methodname = arg;
+ tt_assert(methodname);
+
+ compress_method_t method = compression_method_get_by_name(methodname);
+ tt_int_op(method, OP_NE, UNKNOWN_METHOD);
+ if (! tor_compress_supports_method(method)) {
+ tt_skip();
+ }
+
+ test_util_decompress_junk_impl(method);
+ done:
+ ;
+}
+
+/* mock replacement for tor_compress_is_compression_bomb that doesn't
+ * believe in compression bombs. */
+static int
+mock_is_never_compression_bomb(size_t in, size_t out)
+{
+ (void)in;
+ (void) out;
+ return 0;
+}
+
+static void
+test_util_decompress_dos_impl(compress_method_t method)
+{
+ char *input;
+ char *result = NULL, *result2 = NULL;
+ size_t szr, szr2;
+ int r;
+
+ const size_t big = 1024*1024;
+ /* one megabyte of 0s. */
+ input = tor_malloc_zero(big);
+
+ /* Compress it into "result": it should fail. */
+ setup_full_capture_of_logs(LOG_WARN);
+ r = tor_compress(&result, &szr, input, big, method);
+ tt_int_op(r, OP_EQ, -1);
+ expect_log_msg_containing(
+ "other Tors would think this was a compression bomb");
+ teardown_capture_of_logs();
+
+ /* Try again, but this time suppress compression-bomb detection */
+ MOCK(tor_compress_is_compression_bomb, mock_is_never_compression_bomb);
+ r = tor_compress(&result, &szr, input, big, method);
+ UNMOCK(tor_compress_is_compression_bomb);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+
+ /* We should refuse to uncomrpess it again, since it looks like a
+ * compression bomb. */
+ setup_capture_of_logs(LOG_WARN);
+ r = tor_uncompress(&result2, &szr2, result, szr, method, 0, LOG_WARN);
+ tt_int_op(r, OP_EQ, -1);
+ expect_log_msg_containing("bomb; abandoning stream");
+
+ done:
+ teardown_capture_of_logs();
+ tor_free(input);
+ tor_free(result);
+ tor_free(result2);
+}
+
+static void
+test_util_decompress_dos(void *arg)
+{
+ const char *methodname = arg;
+ tt_assert(methodname);
+
+ compress_method_t method = compression_method_get_by_name(methodname);
+ tt_int_op(method, OP_NE, UNKNOWN_METHOD);
+ if (! tor_compress_supports_method(method)) {
+ tt_skip();
+ }
+
+ test_util_decompress_dos_impl(method);
+ done:
+ ;
}
static void
@@ -2346,44 +2612,44 @@ test_util_gzip_compression_bomb(void *arg)
char *one_mb = tor_malloc_zero(one_million);
char *result = NULL;
size_t result_len = 0;
- tor_zlib_state_t *state = NULL;
+ tor_compress_state_t *state = NULL;
/* Make sure we can't produce a compression bomb */
setup_full_capture_of_logs(LOG_WARN);
- tt_int_op(-1, OP_EQ, tor_gzip_compress(&result, &result_len,
- one_mb, one_million,
- ZLIB_METHOD));
+ tt_int_op(-1, OP_EQ, tor_compress(&result, &result_len,
+ one_mb, one_million,
+ ZLIB_METHOD));
expect_single_log_msg_containing(
"We compressed something and got an insanely high "
"compression factor; other Tors would think this "
- "was a zlib bomb.");
+ "was a compression bomb.");
teardown_capture_of_logs();
/* Here's a compression bomb that we made manually. */
const char compression_bomb[1039] =
{ 0x78, 0xDA, 0xED, 0xC1, 0x31, 0x01, 0x00, 0x00, 0x00, 0xC2,
0xA0, 0xF5, 0x4F, 0x6D, 0x08, 0x5F, 0xA0 /* .... */ };
- tt_int_op(-1, OP_EQ, tor_gzip_uncompress(&result, &result_len,
- compression_bomb, 1039,
- ZLIB_METHOD, 0, LOG_WARN));
+ tt_int_op(-1, OP_EQ, tor_uncompress(&result, &result_len,
+ compression_bomb, 1039,
+ ZLIB_METHOD, 0, LOG_WARN));
/* Now try streaming that. */
- state = tor_zlib_new(0, ZLIB_METHOD, HIGH_COMPRESSION);
- tor_zlib_output_t r;
+ state = tor_compress_new(0, ZLIB_METHOD, HIGH_COMPRESSION);
+ tor_compress_output_t r;
const char *inp = compression_bomb;
size_t inlen = 1039;
do {
char *outp = one_mb;
size_t outleft = 4096; /* small on purpose */
- r = tor_zlib_process(state, &outp, &outleft, &inp, &inlen, 0);
+ r = tor_compress_process(state, &outp, &outleft, &inp, &inlen, 0);
tt_int_op(inlen, OP_NE, 0);
- } while (r == TOR_ZLIB_BUF_FULL);
+ } while (r == TOR_COMPRESS_BUFFER_FULL);
- tt_int_op(r, OP_EQ, TOR_ZLIB_ERR);
+ tt_int_op(r, OP_EQ, TOR_COMPRESS_ERROR);
done:
tor_free(one_mb);
- tor_zlib_free(state);
+ tor_compress_free(state);
}
/** Run unit tests for mmap() wrapper functionality. */
@@ -2401,7 +2667,7 @@ test_util_mmap(void *arg)
crypto_rand(buf, buflen);
mapping = tor_mmap_file(fname1);
- tt_assert(! mapping);
+ tt_ptr_op(mapping, OP_EQ, NULL);
write_str_to_file(fname1, "Short file.", 1);
@@ -2419,7 +2685,7 @@ test_util_mmap(void *arg)
tt_str_op(mapping->data,OP_EQ, "Short file.");
tt_int_op(0, OP_EQ, tor_munmap_file(mapping));
mapping = NULL;
-#endif
+#endif /* defined(_WIN32) */
/* Now a zero-length file. */
write_str_to_file(fname1, "", 1);
@@ -2430,7 +2696,7 @@ test_util_mmap(void *arg)
/* Make sure that we fail to map a no-longer-existent file. */
mapping = tor_mmap_file(fname1);
- tt_assert(! mapping);
+ tt_ptr_op(mapping, OP_EQ, NULL);
/* Now try a big file that stretches across a few pages and isn't aligned */
write_bytes_to_file(fname2, buf, buflen, 1);
@@ -2748,7 +3014,7 @@ test_util_sscanf(void *arg)
r = tor_sscanf("9223372036854775808. -9223372036854775809.",
"%d. %d.", &int1, &int2);
tt_int_op(r,OP_EQ, 0);
-#endif
+#endif /* SIZEOF_INT == 4 || ... */
#if SIZEOF_LONG == 4
/* %lu */
@@ -2843,7 +3109,7 @@ test_util_sscanf(void *arg)
r = tor_sscanf("9223372036854775808. -9223372036854775809.",
"%ld. %ld.", &lng1, &lng2);
tt_int_op(r,OP_EQ, 0);
-#endif
+#endif /* SIZEOF_LONG == 4 || ... */
r = tor_sscanf("123.456 .000007 -900123123.2000787 00003.2",
"%lf %lf %lf %lf", &d1,&d2,&d3,&d4);
@@ -2870,7 +3136,7 @@ strnlen(const char *s, size_t len)
return len;
return p - s;
}
-#endif
+#endif /* !defined(HAVE_STRNLEN) */
static void
test_util_format_time_interval(void *arg)
@@ -3237,7 +3503,7 @@ test_util_format_time_interval(void *arg)
tt_ci_char_op(label_m[0],OP_EQ, 'm');
/* and 7 or 8 seconds - ignored */
-#endif
+#endif /* SIZEOF_LONG == 4 || SIZEOF_LONG == 8 */
#if SIZEOF_LONG == 8
@@ -3275,7 +3541,7 @@ test_util_format_time_interval(void *arg)
tt_ci_char_op(label_m[0],OP_EQ, 'm');
/* and 7 or 8 seconds - ignored */
-#endif
+#endif /* SIZEOF_LONG == 8 */
done:
;
@@ -3318,7 +3584,7 @@ test_util_path_is_relative(void *arg)
tt_int_op(0,OP_EQ, path_is_relative("\\dir"));
tt_int_op(0,OP_EQ, path_is_relative("a:\\dir"));
tt_int_op(0,OP_EQ, path_is_relative("z:\\dir"));
-#endif
+#endif /* defined(_WIN32) */
done:
;
@@ -3333,6 +3599,13 @@ test_util_memarea(void *arg)
void *malloced_ptr = NULL;
int i;
+#ifdef DISABLE_MEMORY_SENTINELS
+ /* If memory sentinels are disabled, this whole module is just an alias for
+ malloc(), which is free to lay out memory most any way it wants. */
+ if (1)
+ tt_skip();
+#endif /* defined(DISABLE_MEMORY_SENTINELS) */
+
(void)arg;
tt_assert(area);
@@ -3502,8 +3775,8 @@ test_util_strtok(void *arg)
}
tor_snprintf(buf, sizeof(buf), "%s", pad1);
tor_snprintf(buf2, sizeof(buf2), "%s", pad2);
- tt_assert(NULL == tor_strtok_r_impl(buf, " ", &cp1));
- tt_assert(NULL == tor_strtok_r_impl(buf2, ".!..;!", &cp2));
+ tt_ptr_op(tor_strtok_r_impl(buf, " ", &cp1), OP_EQ, NULL);
+ tt_ptr_op(tor_strtok_r_impl(buf2, ".!..;!", &cp2), OP_EQ, NULL);
tor_snprintf(buf, sizeof(buf),
"%sGraved on the dark in gestures of descent%s", pad1, pad1);
@@ -3853,7 +4126,7 @@ test_util_load_win_lib(void *ptr)
if (h)
FreeLibrary(h);
}
-#endif
+#endif /* defined(_WIN32) */
#ifndef _WIN32
static void
@@ -3905,7 +4178,7 @@ test_util_exit_status(void *ptr)
tt_int_op(n,OP_EQ, strlen(hex_errno));
tt_int_op(n,OP_EQ, HEX_ERRNO_SIZE);
-#endif
+#endif /* SIZEOF_INT == 4 || ... */
clear_hex_errno(hex_errno);
n = format_helper_exit_status(0x7F, 0, hex_errno);
@@ -3923,20 +4196,16 @@ test_util_exit_status(void *ptr)
done:
;
}
-#endif
+#endif /* !defined(_WIN32) */
#ifndef _WIN32
-/* Check that fgets with a non-blocking pipe returns partial lines and sets
- * EAGAIN, returns full lines and sets no error, and returns NULL on EOF and
- * sets no error */
static void
-test_util_fgets_eagain(void *ptr)
+test_util_string_from_pipe(void *ptr)
{
int test_pipe[2] = {-1, -1};
- int retval;
+ int retval = 0;
+ enum stream_status status = IO_STREAM_TERM;
ssize_t retlen;
- char *retptr;
- FILE *test_stream = NULL;
char buf[4] = { 0 };
(void)ptr;
@@ -3947,91 +4216,115 @@ test_util_fgets_eagain(void *ptr)
retval = pipe(test_pipe);
tt_int_op(retval, OP_EQ, 0);
- /* Set up the read-end to be non-blocking */
- retval = fcntl(test_pipe[0], F_SETFL, O_NONBLOCK);
- tt_int_op(retval, OP_EQ, 0);
+ /* Send in a string. */
+ retlen = write(test_pipe[1], "ABC", 3);
+ tt_int_op(retlen, OP_EQ, 3);
- /* Open it as a stdio stream */
- test_stream = fdopen(test_pipe[0], "r");
- tt_ptr_op(test_stream, OP_NE, NULL);
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
+ tt_int_op(errno, OP_EQ, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "ABC");
+ errno = 0;
+
+ /* Send in a string that contains a nul. */
+ retlen = write(test_pipe[1], "AB\0", 3);
+ tt_int_op(retlen, OP_EQ, 3);
- /* Send in a partial line */
- retlen = write(test_pipe[1], "A", 1);
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
+ tt_int_op(errno, OP_EQ, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "AB");
+ errno = 0;
+
+ /* Send in a string that contains a nul only. */
+ retlen = write(test_pipe[1], "\0", 1);
tt_int_op(retlen, OP_EQ, 1);
- retptr = fgets(buf, sizeof(buf), test_stream);
- tt_int_op(errno, OP_EQ, EAGAIN);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "A");
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
+ tt_int_op(errno, OP_EQ, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "");
errno = 0;
- /* Send in the rest */
- retlen = write(test_pipe[1], "B\n", 2);
- tt_int_op(retlen, OP_EQ, 2);
- retptr = fgets(buf, sizeof(buf), test_stream);
+ /* Send in a string that contains a trailing newline. */
+ retlen = write(test_pipe[1], "AB\n", 3);
+ tt_int_op(retlen, OP_EQ, 3);
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
tt_int_op(errno, OP_EQ, 0);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "B\n");
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "AB");
errno = 0;
- /* Send in a full line */
- retlen = write(test_pipe[1], "CD\n", 3);
+ /* Send in a string that contains a newline only. */
+ retlen = write(test_pipe[1], "\n", 1);
+ tt_int_op(retlen, OP_EQ, 1);
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
+ tt_int_op(errno, OP_EQ, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "");
+ errno = 0;
+
+ /* Send in a string and check that we nul terminate return values. */
+ retlen = write(test_pipe[1], "AAA", 3);
tt_int_op(retlen, OP_EQ, 3);
- retptr = fgets(buf, sizeof(buf), test_stream);
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
tt_int_op(errno, OP_EQ, 0);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "CD\n");
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "AAA");
+ tt_mem_op(buf, OP_EQ, "AAA\0", sizeof(buf));
errno = 0;
- /* Send in a partial line */
- retlen = write(test_pipe[1], "E", 1);
+ retlen = write(test_pipe[1], "B", 1);
tt_int_op(retlen, OP_EQ, 1);
- retptr = fgets(buf, sizeof(buf), test_stream);
- tt_int_op(errno, OP_EQ, EAGAIN);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "E");
+
+ memset(buf, '\xff', sizeof(buf));
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
+ tt_int_op(errno, OP_EQ, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "B");
+ tt_mem_op(buf, OP_EQ, "B\0\xff\xff", sizeof(buf));
errno = 0;
- /* Send in the rest */
- retlen = write(test_pipe[1], "F\n", 2);
- tt_int_op(retlen, OP_EQ, 2);
- retptr = fgets(buf, sizeof(buf), test_stream);
+ /* Send in multiple lines. */
+ retlen = write(test_pipe[1], "A\nB", 3);
+ tt_int_op(retlen, OP_EQ, 3);
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
tt_int_op(errno, OP_EQ, 0);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "F\n");
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "A\nB");
errno = 0;
- /* Send in a full line and close */
- retlen = write(test_pipe[1], "GH", 2);
+ /* Send in a line and close */
+ retlen = write(test_pipe[1], "AB", 2);
tt_int_op(retlen, OP_EQ, 2);
retval = close(test_pipe[1]);
tt_int_op(retval, OP_EQ, 0);
test_pipe[1] = -1;
- retptr = fgets(buf, sizeof(buf), test_stream);
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
tt_int_op(errno, OP_EQ, 0);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "GH");
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "AB");
errno = 0;
/* Check for EOF */
- retptr = fgets(buf, sizeof(buf), test_stream);
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
tt_int_op(errno, OP_EQ, 0);
- tt_ptr_op(retptr, OP_EQ, NULL);
- retval = feof(test_stream);
- tt_int_op(retval, OP_NE, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_CLOSED);
errno = 0;
- /* Check that buf is unchanged according to C99 and C11 */
- tt_str_op(buf, OP_EQ, "GH");
-
done:
- if (test_stream != NULL)
- fclose(test_stream);
if (test_pipe[0] != -1)
close(test_pipe[0]);
if (test_pipe[1] != -1)
close(test_pipe[1]);
}
-#endif
+
+#endif /* !defined(_WIN32) */
/**
* Test for format_hex_number_sigsafe()
@@ -4227,7 +4520,7 @@ test_util_split_lines(void *ptr)
/* Check we have not got too many lines */
tt_int_op(MAX_SPLIT_LINE_COUNT, OP_GT, j);
/* Check that there actually should be a line here */
- tt_assert(tests[i].split_line[j] != NULL);
+ tt_ptr_op(tests[i].split_line[j], OP_NE, NULL);
log_info(LD_GENERAL, "Line %d of test %d, should be <%s>",
j, i, tests[i].split_line[j]);
/* Check that the line is as expected */
@@ -4343,11 +4636,11 @@ test_util_di_map(void *arg)
char dflt_entry[] = "'You have made a good beginning', but no more";
- tt_int_op(32, ==, sizeof(key1));
- tt_int_op(32, ==, sizeof(key2));
- tt_int_op(32, ==, sizeof(key3));
+ tt_int_op(32, OP_EQ, sizeof(key1));
+ tt_int_op(32, OP_EQ, sizeof(key2));
+ tt_int_op(32, OP_EQ, sizeof(key3));
- tt_ptr_op(dflt_entry, ==, dimap_search(dimap, key1, dflt_entry));
+ tt_ptr_op(dflt_entry, OP_EQ, dimap_search(dimap, key1, dflt_entry));
char *str1 = tor_strdup("You are precisely as big as what you love"
" and precisely as small as what you allow"
@@ -4365,10 +4658,10 @@ test_util_di_map(void *arg)
dimap_add_entry(&dimap, key2, str2);
dimap_add_entry(&dimap, key3, str3);
- tt_ptr_op(str1, ==, dimap_search(dimap, key1, dflt_entry));
- tt_ptr_op(str3, ==, dimap_search(dimap, key3, dflt_entry));
- tt_ptr_op(str2, ==, dimap_search(dimap, key2, dflt_entry));
- tt_ptr_op(dflt_entry, ==, dimap_search(dimap, key4, dflt_entry));
+ tt_ptr_op(str1, OP_EQ, dimap_search(dimap, key1, dflt_entry));
+ tt_ptr_op(str3, OP_EQ, dimap_search(dimap, key3, dflt_entry));
+ tt_ptr_op(str2, OP_EQ, dimap_search(dimap, key2, dflt_entry));
+ tt_ptr_op(dflt_entry, OP_EQ, dimap_search(dimap, key4, dflt_entry));
done:
dimap_free(dimap, tor_free_);
@@ -4835,34 +5128,34 @@ test_util_round_to_next_multiple_of(void *arg)
{
(void)arg;
- tt_u64_op(round_uint64_to_next_multiple_of(0,1), ==, 0);
- tt_u64_op(round_uint64_to_next_multiple_of(0,7), ==, 0);
+ tt_u64_op(round_uint64_to_next_multiple_of(0,1), OP_EQ, 0);
+ tt_u64_op(round_uint64_to_next_multiple_of(0,7), OP_EQ, 0);
- tt_u64_op(round_uint64_to_next_multiple_of(99,1), ==, 99);
- tt_u64_op(round_uint64_to_next_multiple_of(99,7), ==, 105);
- tt_u64_op(round_uint64_to_next_multiple_of(99,9), ==, 99);
+ tt_u64_op(round_uint64_to_next_multiple_of(99,1), OP_EQ, 99);
+ tt_u64_op(round_uint64_to_next_multiple_of(99,7), OP_EQ, 105);
+ tt_u64_op(round_uint64_to_next_multiple_of(99,9), OP_EQ, 99);
- tt_u64_op(round_uint64_to_next_multiple_of(UINT64_MAX,2), ==,
+ tt_u64_op(round_uint64_to_next_multiple_of(UINT64_MAX,2), OP_EQ,
UINT64_MAX);
- tt_int_op(round_uint32_to_next_multiple_of(0,1), ==, 0);
- tt_int_op(round_uint32_to_next_multiple_of(0,7), ==, 0);
+ tt_int_op(round_uint32_to_next_multiple_of(0,1), OP_EQ, 0);
+ tt_int_op(round_uint32_to_next_multiple_of(0,7), OP_EQ, 0);
- tt_int_op(round_uint32_to_next_multiple_of(99,1), ==, 99);
- tt_int_op(round_uint32_to_next_multiple_of(99,7), ==, 105);
- tt_int_op(round_uint32_to_next_multiple_of(99,9), ==, 99);
+ tt_int_op(round_uint32_to_next_multiple_of(99,1), OP_EQ, 99);
+ tt_int_op(round_uint32_to_next_multiple_of(99,7), OP_EQ, 105);
+ tt_int_op(round_uint32_to_next_multiple_of(99,9), OP_EQ, 99);
- tt_int_op(round_uint32_to_next_multiple_of(UINT32_MAX,2), ==,
+ tt_int_op(round_uint32_to_next_multiple_of(UINT32_MAX,2), OP_EQ,
UINT32_MAX);
- tt_uint_op(round_to_next_multiple_of(0,1), ==, 0);
- tt_uint_op(round_to_next_multiple_of(0,7), ==, 0);
+ tt_uint_op(round_to_next_multiple_of(0,1), OP_EQ, 0);
+ tt_uint_op(round_to_next_multiple_of(0,7), OP_EQ, 0);
- tt_uint_op(round_to_next_multiple_of(99,1), ==, 99);
- tt_uint_op(round_to_next_multiple_of(99,7), ==, 105);
- tt_uint_op(round_to_next_multiple_of(99,9), ==, 99);
+ tt_uint_op(round_to_next_multiple_of(99,1), OP_EQ, 99);
+ tt_uint_op(round_to_next_multiple_of(99,7), OP_EQ, 105);
+ tt_uint_op(round_to_next_multiple_of(99,9), OP_EQ, 99);
- tt_uint_op(round_to_next_multiple_of(UINT_MAX,2), ==,
+ tt_uint_op(round_to_next_multiple_of(UINT_MAX,2), OP_EQ,
UINT_MAX);
done:
;
@@ -4883,26 +5176,26 @@ test_util_laplace(void *arg)
const double delta_f = 15.0, epsilon = 0.3; /* b = 15.0 / 0.3 = 50.0 */
(void)arg;
- tt_i64_op(INT64_MIN, ==, sample_laplace_distribution(mu, b, 0.0));
- tt_i64_op(-69, ==, sample_laplace_distribution(mu, b, 0.01));
- tt_i64_op(24, ==, sample_laplace_distribution(mu, b, 0.5));
- tt_i64_op(24, ==, sample_laplace_distribution(mu, b, 0.51));
- tt_i64_op(117, ==, sample_laplace_distribution(mu, b, 0.99));
+ tt_i64_op(INT64_MIN, OP_EQ, sample_laplace_distribution(mu, b, 0.0));
+ tt_i64_op(-69, OP_EQ, sample_laplace_distribution(mu, b, 0.01));
+ tt_i64_op(24, OP_EQ, sample_laplace_distribution(mu, b, 0.5));
+ tt_i64_op(24, OP_EQ, sample_laplace_distribution(mu, b, 0.51));
+ tt_i64_op(117, OP_EQ, sample_laplace_distribution(mu, b, 0.99));
/* >>> laplace.ppf([0.0, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99],
* ... loc = 0, scale = 50)
* array([ -inf, -80.47189562, -34.65735903, 0. ,
* 34.65735903, 80.47189562, 195.60115027])
*/
- tt_i64_op(INT64_MIN + 20, ==,
+ tt_i64_op(INT64_MIN + 20, OP_EQ,
add_laplace_noise(20, 0.0, delta_f, epsilon));
- tt_i64_op(-60, ==, add_laplace_noise(20, 0.1, delta_f, epsilon));
- tt_i64_op(-14, ==, add_laplace_noise(20, 0.25, delta_f, epsilon));
- tt_i64_op(20, ==, add_laplace_noise(20, 0.5, delta_f, epsilon));
- tt_i64_op(54, ==, add_laplace_noise(20, 0.75, delta_f, epsilon));
- tt_i64_op(100, ==, add_laplace_noise(20, 0.9, delta_f, epsilon));
- tt_i64_op(215, ==, add_laplace_noise(20, 0.99, delta_f, epsilon));
+ tt_i64_op(-60, OP_EQ, add_laplace_noise(20, 0.1, delta_f, epsilon));
+ tt_i64_op(-14, OP_EQ, add_laplace_noise(20, 0.25, delta_f, epsilon));
+ tt_i64_op(20, OP_EQ, add_laplace_noise(20, 0.5, delta_f, epsilon));
+ tt_i64_op(54, OP_EQ, add_laplace_noise(20, 0.75, delta_f, epsilon));
+ tt_i64_op(100, OP_EQ, add_laplace_noise(20, 0.9, delta_f, epsilon));
+ tt_i64_op(215, OP_EQ, add_laplace_noise(20, 0.99, delta_f, epsilon));
/* Test extreme values of signal with maximally negative values of noise
* 1.0000000000000002 is the smallest number > 1
@@ -4915,54 +5208,54 @@ test_util_laplace(void *arg)
*/
const double noscale_df = 1.0, noscale_eps = 1.0;
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(0, 0.0, noscale_df, noscale_eps));
/* is it clipped to INT64_MIN? */
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(-1, 0.0, noscale_df, noscale_eps));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(INT64_MIN, 0.0,
noscale_df, noscale_eps));
/* ... even when scaled? */
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(0, 0.0, delta_f, epsilon));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(0, 0.0,
DBL_MAX, 1));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(INT64_MIN, 0.0,
DBL_MAX, 1));
/* does it play nice with INT64_MAX? */
- tt_i64_op((INT64_MIN + INT64_MAX), ==,
+ tt_i64_op((INT64_MIN + INT64_MAX), OP_EQ,
add_laplace_noise(INT64_MAX, 0.0,
noscale_df, noscale_eps));
/* do near-zero fractional values work? */
const double min_dbl_error = 0.0000000000000002;
- tt_i64_op(-35, ==,
+ tt_i64_op(-35, OP_EQ,
add_laplace_noise(0, min_dbl_error,
noscale_df, noscale_eps));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(INT64_MIN, min_dbl_error,
noscale_df, noscale_eps));
- tt_i64_op((-35 + INT64_MAX), ==,
+ tt_i64_op((-35 + INT64_MAX), OP_EQ,
add_laplace_noise(INT64_MAX, min_dbl_error,
noscale_df, noscale_eps));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(0, min_dbl_error,
DBL_MAX, 1));
- tt_i64_op((INT64_MAX + INT64_MIN), ==,
+ tt_i64_op((INT64_MAX + INT64_MIN), OP_EQ,
add_laplace_noise(INT64_MAX, min_dbl_error,
DBL_MAX, 1));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(INT64_MIN, min_dbl_error,
DBL_MAX, 1));
/* does it play nice with INT64_MAX? */
- tt_i64_op((INT64_MAX - 35), ==,
+ tt_i64_op((INT64_MAX - 35), OP_EQ,
add_laplace_noise(INT64_MAX, min_dbl_error,
noscale_df, noscale_eps));
@@ -4977,31 +5270,31 @@ test_util_laplace(void *arg)
const double max_dbl_lt_one = 0.9999999999999998;
/* do near-one fractional values work? */
- tt_i64_op(35, ==,
+ tt_i64_op(35, OP_EQ,
add_laplace_noise(0, max_dbl_lt_one, noscale_df, noscale_eps));
/* is it clipped to INT64_MAX? */
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
add_laplace_noise(INT64_MAX - 35, max_dbl_lt_one,
noscale_df, noscale_eps));
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
add_laplace_noise(INT64_MAX - 34, max_dbl_lt_one,
noscale_df, noscale_eps));
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
add_laplace_noise(INT64_MAX, max_dbl_lt_one,
noscale_df, noscale_eps));
/* ... even when scaled? */
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
add_laplace_noise(INT64_MAX, max_dbl_lt_one,
delta_f, epsilon));
- tt_i64_op((INT64_MIN + INT64_MAX), ==,
+ tt_i64_op((INT64_MIN + INT64_MAX), OP_EQ,
add_laplace_noise(INT64_MIN, max_dbl_lt_one,
DBL_MAX, 1));
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
add_laplace_noise(INT64_MAX, max_dbl_lt_one,
DBL_MAX, 1));
/* does it play nice with INT64_MIN? */
- tt_i64_op((INT64_MIN + 35), ==,
+ tt_i64_op((INT64_MIN + 35), OP_EQ,
add_laplace_noise(INT64_MIN, max_dbl_lt_one,
noscale_df, noscale_eps));
@@ -5014,32 +5307,32 @@ test_util_clamp_double_to_int64(void *arg)
{
(void)arg;
- tt_i64_op(INT64_MIN, ==, clamp_double_to_int64(-INFINITY_DBL));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ, clamp_double_to_int64(-INFINITY_DBL));
+ tt_i64_op(INT64_MIN, OP_EQ,
clamp_double_to_int64(-1.0 * pow(2.0, 64.0) - 1.0));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
clamp_double_to_int64(-1.0 * pow(2.0, 63.0) - 1.0));
- tt_i64_op(((uint64_t) -1) << 53, ==,
+ tt_i64_op(((uint64_t) -1) << 53, OP_EQ,
clamp_double_to_int64(-1.0 * pow(2.0, 53.0)));
- tt_i64_op((((uint64_t) -1) << 53) + 1, ==,
+ tt_i64_op((((uint64_t) -1) << 53) + 1, OP_EQ,
clamp_double_to_int64(-1.0 * pow(2.0, 53.0) + 1.0));
- tt_i64_op(-1, ==, clamp_double_to_int64(-1.0));
- tt_i64_op(0, ==, clamp_double_to_int64(-0.9));
- tt_i64_op(0, ==, clamp_double_to_int64(-0.1));
- tt_i64_op(0, ==, clamp_double_to_int64(0.0));
- tt_i64_op(0, ==, clamp_double_to_int64(NAN_DBL));
- tt_i64_op(0, ==, clamp_double_to_int64(0.1));
- tt_i64_op(0, ==, clamp_double_to_int64(0.9));
- tt_i64_op(1, ==, clamp_double_to_int64(1.0));
- tt_i64_op((((int64_t) 1) << 53) - 1, ==,
+ tt_i64_op(-1, OP_EQ, clamp_double_to_int64(-1.0));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(-0.9));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(-0.1));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(0.0));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(NAN_DBL));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(0.1));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(0.9));
+ tt_i64_op(1, OP_EQ, clamp_double_to_int64(1.0));
+ tt_i64_op((((int64_t) 1) << 53) - 1, OP_EQ,
clamp_double_to_int64(pow(2.0, 53.0) - 1.0));
- tt_i64_op(((int64_t) 1) << 53, ==,
+ tt_i64_op(((int64_t) 1) << 53, OP_EQ,
clamp_double_to_int64(pow(2.0, 53.0)));
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
clamp_double_to_int64(pow(2.0, 63.0)));
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
clamp_double_to_int64(pow(2.0, 64.0)));
- tt_i64_op(INT64_MAX, ==, clamp_double_to_int64(INFINITY_DBL));
+ tt_i64_op(INT64_MAX, OP_EQ, clamp_double_to_int64(INFINITY_DBL));
done:
;
@@ -5053,7 +5346,7 @@ fd_is_cloexec(tor_socket_t fd)
int flags = fcntl(fd, F_GETFD, 0);
return (flags & FD_CLOEXEC) == FD_CLOEXEC;
}
-#endif
+#endif /* defined(FD_CLOEXEC) */
#ifndef _WIN32
#define CAN_CHECK_NONBLOCK
@@ -5063,7 +5356,7 @@ fd_is_nonblocking(tor_socket_t fd)
int flags = fcntl(fd, F_GETFL, 0);
return (flags & O_NONBLOCK) == O_NONBLOCK;
}
-#endif
+#endif /* !defined(_WIN32) */
#define ERRNO_IS_EPROTO(e) (e == SOCK_ERRNO(EPROTONOSUPPORT))
#define SOCK_ERR_IS_EPROTO(s) ERRNO_IS_EPROTO(tor_socket_errno(s))
@@ -5085,7 +5378,8 @@ test_util_socket(void *arg)
fd1 = tor_open_socket_with_extensions(domain, SOCK_STREAM, 0, 0, 0);
int err = tor_socket_errno(fd1);
- if (fd1 < 0 && err == SOCK_ERRNO(EPROTONOSUPPORT)) {
+ if (fd1 < 0 && (err == SOCK_ERRNO(EPROTONOSUPPORT) ||
+ err == SOCK_ERRNO(EAFNOSUPPORT))) {
/* Assume we're on an IPv4-only or IPv6-only system, and give up now. */
goto done;
}
@@ -5106,13 +5400,13 @@ test_util_socket(void *arg)
tt_int_op(fd_is_cloexec(fd2), OP_EQ, 0);
tt_int_op(fd_is_cloexec(fd3), OP_EQ, 1);
tt_int_op(fd_is_cloexec(fd4), OP_EQ, 1);
-#endif
+#endif /* defined(CAN_CHECK_CLOEXEC) */
#ifdef CAN_CHECK_NONBLOCK
tt_int_op(fd_is_nonblocking(fd1), OP_EQ, 0);
tt_int_op(fd_is_nonblocking(fd2), OP_EQ, 1);
tt_int_op(fd_is_nonblocking(fd3), OP_EQ, 0);
tt_int_op(fd_is_nonblocking(fd4), OP_EQ, 1);
-#endif
+#endif /* defined(CAN_CHECK_NONBLOCK) */
tor_assert(tor_close_socket == tor_close_socket__real);
@@ -5168,10 +5462,10 @@ is_there_a_localhost(int family)
return result;
}
-#endif
+#endif /* 0 */
/* Test for socketpair and ersatz_socketpair(). We test them both, since
- * the latter is a tolerably good way to exersize tor_accept_socket(). */
+ * the latter is a tolerably good way to exercise tor_accept_socket(). */
static void
test_util_socketpair(void *arg)
{
@@ -5195,7 +5489,7 @@ test_util_socketpair(void *arg)
* Assume we're on a machine without 127.0.0.1 or ::1 and give up now. */
tt_skip();
}
-#endif
+#endif /* defined(__FreeBSD__) */
tt_int_op(0, OP_EQ, socketpair_result);
tt_assert(SOCKET_OK(fds[0]));
@@ -5248,47 +5542,74 @@ test_util_max_mem(void *arg)
}
static void
+test_util_dest_validation_edgecase(void *arg)
+{
+ (void)arg;
+
+ tt_assert(!string_is_valid_dest(NULL));
+ tt_assert(!string_is_valid_dest(""));
+
+ done:
+ return;
+}
+
+static void
test_util_hostname_validation(void *arg)
{
(void)arg;
// Lets try valid hostnames first.
- tt_assert(string_is_valid_hostname("torproject.org"));
- tt_assert(string_is_valid_hostname("ocw.mit.edu"));
- tt_assert(string_is_valid_hostname("i.4cdn.org"));
- tt_assert(string_is_valid_hostname("stanford.edu"));
- tt_assert(string_is_valid_hostname("multiple-words-with-hypens.jp"));
+ tt_assert(string_is_valid_nonrfc_hostname("torproject.org"));
+ tt_assert(string_is_valid_nonrfc_hostname("ocw.mit.edu"));
+ tt_assert(string_is_valid_nonrfc_hostname("i.4cdn.org"));
+ tt_assert(string_is_valid_nonrfc_hostname("stanford.edu"));
+ tt_assert(string_is_valid_nonrfc_hostname("multiple-words-with-hypens.jp"));
// Subdomain name cannot start with '-' or '_'.
- tt_assert(!string_is_valid_hostname("-torproject.org"));
- tt_assert(!string_is_valid_hostname("subdomain.-domain.org"));
- tt_assert(!string_is_valid_hostname("-subdomain.domain.org"));
- tt_assert(!string_is_valid_hostname("___abc.org"));
+ tt_assert(!string_is_valid_nonrfc_hostname("-torproject.org"));
+ tt_assert(!string_is_valid_nonrfc_hostname("subdomain.-domain.org"));
+ tt_assert(!string_is_valid_nonrfc_hostname("-subdomain.domain.org"));
+ tt_assert(!string_is_valid_nonrfc_hostname("___abc.org"));
// Hostnames cannot contain non-alphanumeric characters.
- tt_assert(!string_is_valid_hostname("%%domain.\\org."));
- tt_assert(!string_is_valid_hostname("***x.net"));
- tt_assert(!string_is_valid_hostname("\xff\xffxyz.org"));
- tt_assert(!string_is_valid_hostname("word1 word2.net"));
+ tt_assert(!string_is_valid_nonrfc_hostname("%%domain.\\org."));
+ tt_assert(!string_is_valid_nonrfc_hostname("***x.net"));
+ tt_assert(!string_is_valid_nonrfc_hostname("\xff\xffxyz.org"));
+ tt_assert(!string_is_valid_nonrfc_hostname("word1 word2.net"));
// Test workaround for nytimes.com stupidity, technically invalid,
// but we allow it since they are big, even though they are failing to
// comply with a ~30 year old standard.
- tt_assert(string_is_valid_hostname("core3_euw1.fabrik.nytimes.com"));
+ tt_assert(string_is_valid_nonrfc_hostname("core3_euw1.fabrik.nytimes.com"));
// Firefox passes FQDNs with trailing '.'s directly to the SOCKS proxy,
// which is redundant since the spec states DOMAINNAME addresses are fully
// qualified. While unusual, this should be tollerated.
- tt_assert(string_is_valid_hostname("core9_euw1.fabrik.nytimes.com."));
- tt_assert(!string_is_valid_hostname("..washingtonpost.is.better.com"));
- tt_assert(!string_is_valid_hostname("so.is..ft.com"));
- tt_assert(!string_is_valid_hostname("..."));
+ tt_assert(string_is_valid_nonrfc_hostname("core9_euw1.fabrik.nytimes.com."));
+ tt_assert(!string_is_valid_nonrfc_hostname(
+ "..washingtonpost.is.better.com"));
+ tt_assert(!string_is_valid_nonrfc_hostname("so.is..ft.com"));
+ tt_assert(!string_is_valid_nonrfc_hostname("..."));
// XXX: do we allow single-label DNS names?
// We shouldn't for SOCKS (spec says "contains a fully-qualified domain name"
// but only test pathologically malformed traling '.' cases for now.
- tt_assert(!string_is_valid_hostname("."));
- tt_assert(!string_is_valid_hostname(".."));
+ tt_assert(!string_is_valid_nonrfc_hostname("."));
+ tt_assert(!string_is_valid_nonrfc_hostname(".."));
+
+ // IP address strings are not hostnames.
+ tt_assert(!string_is_valid_nonrfc_hostname("8.8.8.8"));
+ tt_assert(!string_is_valid_nonrfc_hostname("[2a00:1450:401b:800::200e]"));
+ tt_assert(!string_is_valid_nonrfc_hostname("2a00:1450:401b:800::200e"));
+
+ // We allow alphanumeric TLDs. For discussion, see ticket #25055.
+ tt_assert(string_is_valid_nonrfc_hostname("lucky.13"));
+ tt_assert(string_is_valid_nonrfc_hostname("luck.y13"));
+ tt_assert(string_is_valid_nonrfc_hostname("luck.y13."));
+
+ // We allow punycode TLDs. For examples, see
+ // http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+ tt_assert(string_is_valid_nonrfc_hostname("example.xn--l1acc"));
done:
return;
@@ -5356,7 +5677,7 @@ test_util_get_avail_disk_space(void *arg)
#else
tt_i64_op(val, OP_GT, 0); /* You have some space. */
tt_i64_op(val, OP_LT, ((int64_t)1)<<56); /* You don't have a zebibyte */
-#endif
+#endif /* !defined(HAVE_STATVFS) && !defined(_WIN32) */
done:
;
@@ -5406,25 +5727,25 @@ test_util_pwdb(void *arg)
/* Uncached case. */
/* Let's assume that we exist. */
me = tor_getpwuid(getuid());
- tt_assert(me != NULL);
+ tt_ptr_op(me, OP_NE, NULL);
name = tor_strdup(me->pw_name);
/* Uncached case */
me2 = tor_getpwnam(name);
- tt_assert(me2 != NULL);
+ tt_ptr_op(me2, OP_NE, NULL);
tt_int_op(me2->pw_uid, OP_EQ, getuid());
/* Cached case */
me3 = tor_getpwuid(getuid());
- tt_assert(me3 != NULL);
+ tt_ptr_op(me3, OP_NE, NULL);
tt_str_op(me3->pw_name, OP_EQ, name);
me3 = tor_getpwnam(name);
- tt_assert(me3 != NULL);
+ tt_ptr_op(me3, OP_NE, NULL);
tt_int_op(me3->pw_uid, OP_EQ, getuid());
dir = get_user_homedir(name);
- tt_assert(dir != NULL);
+ tt_ptr_op(dir, OP_NE, NULL);
/* Try failing cases. First find a user that doesn't exist by name */
char randbytes[4];
@@ -5444,7 +5765,7 @@ test_util_pwdb(void *arg)
/* We should do a LOG_ERR */
setup_full_capture_of_logs(LOG_ERR);
dir = get_user_homedir(badname);
- tt_assert(dir == NULL);
+ tt_ptr_op(dir, OP_EQ, NULL);
expect_log_msg_containing("not found");
tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1);
teardown_capture_of_logs();
@@ -5466,33 +5787,33 @@ test_util_pwdb(void *arg)
tor_free(dir);
teardown_capture_of_logs();
}
-#endif
+#endif /* !defined(_WIN32) */
static void
test_util_calloc_check(void *arg)
{
(void) arg;
/* Easy cases that are good. */
- tt_assert(size_mul_check__(0,0));
- tt_assert(size_mul_check__(0,100));
- tt_assert(size_mul_check__(100,0));
- tt_assert(size_mul_check__(100,100));
+ tt_assert(size_mul_check(0,0));
+ tt_assert(size_mul_check(0,100));
+ tt_assert(size_mul_check(100,0));
+ tt_assert(size_mul_check(100,100));
/* Harder cases that are still good. */
- tt_assert(size_mul_check__(SIZE_MAX, 1));
- tt_assert(size_mul_check__(1, SIZE_MAX));
- tt_assert(size_mul_check__(SIZE_MAX / 10, 9));
- tt_assert(size_mul_check__(11, SIZE_MAX / 12));
+ tt_assert(size_mul_check(SIZE_MAX, 1));
+ tt_assert(size_mul_check(1, SIZE_MAX));
+ tt_assert(size_mul_check(SIZE_MAX / 10, 9));
+ tt_assert(size_mul_check(11, SIZE_MAX / 12));
const size_t sqrt_size_max_p1 = ((size_t)1) << (sizeof(size_t) * 4);
- tt_assert(size_mul_check__(sqrt_size_max_p1, sqrt_size_max_p1 - 1));
+ tt_assert(size_mul_check(sqrt_size_max_p1, sqrt_size_max_p1 - 1));
/* Cases that overflow */
- tt_assert(! size_mul_check__(SIZE_MAX, 2));
- tt_assert(! size_mul_check__(2, SIZE_MAX));
- tt_assert(! size_mul_check__(SIZE_MAX / 10, 11));
- tt_assert(! size_mul_check__(11, SIZE_MAX / 10));
- tt_assert(! size_mul_check__(SIZE_MAX / 8, 9));
- tt_assert(! size_mul_check__(sqrt_size_max_p1, sqrt_size_max_p1));
+ tt_assert(! size_mul_check(SIZE_MAX, 2));
+ tt_assert(! size_mul_check(2, SIZE_MAX));
+ tt_assert(! size_mul_check(SIZE_MAX / 10, 11));
+ tt_assert(! size_mul_check(11, SIZE_MAX / 10));
+ tt_assert(! size_mul_check(SIZE_MAX / 8, 9));
+ tt_assert(! size_mul_check(sqrt_size_max_p1, sqrt_size_max_p1));
done:
;
@@ -5507,6 +5828,7 @@ test_util_monotonic_time(void *arg)
monotime_coarse_t mtc1, mtc2;
uint64_t nsec1, nsec2, usec1, msec1;
uint64_t nsecc1, nsecc2, usecc1, msecc1;
+ uint32_t stamp1, stamp2;
monotime_init();
@@ -5518,6 +5840,7 @@ test_util_monotonic_time(void *arg)
nsecc1 = monotime_coarse_absolute_nsec();
usecc1 = monotime_coarse_absolute_usec();
msecc1 = monotime_coarse_absolute_msec();
+ stamp1 = monotime_coarse_to_stamp(&mtc1);
tor_sleep_msec(200);
@@ -5525,6 +5848,7 @@ test_util_monotonic_time(void *arg)
monotime_coarse_get(&mtc2);
nsec2 = monotime_absolute_nsec();
nsecc2 = monotime_coarse_absolute_nsec();
+ stamp2 = monotime_coarse_to_stamp(&mtc2);
/* We need to be a little careful here since we don't know the system load.
*/
@@ -5546,6 +5870,11 @@ test_util_monotonic_time(void *arg)
tt_u64_op(msecc1, OP_LE, nsecc1 / 1000000 + 10);
tt_u64_op(usecc1, OP_LE, nsecc1 / 1000 + 10000);
+ uint64_t coarse_stamp_diff =
+ monotime_coarse_stamp_units_to_approx_msec(stamp2-stamp1);
+ tt_u64_op(coarse_stamp_diff, OP_GE, 120);
+ tt_u64_op(coarse_stamp_diff, OP_LE, 1200);
+
done:
;
}
@@ -5623,12 +5952,194 @@ test_util_monotonic_time_ratchet(void *arg)
;
}
+static void
+test_util_monotonic_time_zero(void *arg)
+{
+ (void) arg;
+ monotime_t t1;
+ monotime_coarse_t ct1;
+ monotime_init();
+ /* Check 1: The current time is not zero. */
+ monotime_get(&t1);
+ monotime_coarse_get(&ct1);
+ tt_assert(!monotime_is_zero(&t1));
+ tt_assert(!monotime_coarse_is_zero(&ct1));
+
+ /* Check 2: The _zero() makes the time zero. */
+ monotime_zero(&t1);
+ monotime_coarse_zero(&ct1);
+ tt_assert(monotime_is_zero(&t1));
+ tt_assert(monotime_coarse_is_zero(&ct1));
+ done:
+ ;
+}
+
+static void
+test_util_monotonic_time_add_msec(void *arg)
+{
+ (void) arg;
+ monotime_t t1, t2;
+ monotime_coarse_t ct1, ct2;
+ monotime_init();
+
+ monotime_get(&t1);
+ monotime_coarse_get(&ct1);
+
+ /* adding zero does nothing */
+ monotime_add_msec(&t2, &t1, 0);
+ monotime_coarse_add_msec(&ct2, &ct1, 0);
+ tt_i64_op(monotime_diff_msec(&t1, &t2), OP_EQ, 0);
+ tt_i64_op(monotime_coarse_diff_msec(&ct1, &ct2), OP_EQ, 0);
+
+ /* Add 1337 msec; see if the diff function agree */
+ monotime_add_msec(&t2, &t1, 1337);
+ monotime_coarse_add_msec(&ct2, &ct1, 1337);
+ tt_i64_op(monotime_diff_msec(&t1, &t2), OP_EQ, 1337);
+ tt_i64_op(monotime_coarse_diff_msec(&ct1, &ct2), OP_EQ, 1337);
+
+ /* Add 1337 msec twice more; make sure that any second rollover issues
+ * worked. */
+ monotime_add_msec(&t2, &t2, 1337);
+ monotime_coarse_add_msec(&ct2, &ct2, 1337);
+ monotime_add_msec(&t2, &t2, 1337);
+ monotime_coarse_add_msec(&ct2, &ct2, 1337);
+ tt_i64_op(monotime_diff_msec(&t1, &t2), OP_EQ, 1337*3);
+ tt_i64_op(monotime_coarse_diff_msec(&ct1, &ct2), OP_EQ, 1337*3);
+
+ done:
+ ;
+}
+
+static void
+test_util_htonll(void *arg)
+{
+ (void)arg;
+#ifdef WORDS_BIGENDIAN
+ const uint64_t res_be = 0x8877665544332211;
+#else
+ const uint64_t res_le = 0x1122334455667788;
+#endif
+
+ tt_u64_op(0, OP_EQ, tor_htonll(0));
+ tt_u64_op(0, OP_EQ, tor_ntohll(0));
+ tt_u64_op(UINT64_MAX, OP_EQ, tor_htonll(UINT64_MAX));
+ tt_u64_op(UINT64_MAX, OP_EQ, tor_ntohll(UINT64_MAX));
+
+#ifdef WORDS_BIGENDIAN
+ tt_u64_op(res_be, OP_EQ, tor_htonll(0x8877665544332211));
+ tt_u64_op(res_be, OP_EQ, tor_ntohll(0x8877665544332211));
+#else
+ tt_u64_op(res_le, OP_EQ, tor_htonll(0x8877665544332211));
+ tt_u64_op(res_le, OP_EQ, tor_ntohll(0x8877665544332211));
+#endif /* defined(WORDS_BIGENDIAN) */
+
+ done:
+ ;
+}
+
+static void
+test_util_get_unquoted_path(void *arg)
+{
+ (void)arg;
+
+ char *r = NULL;
+
+ r = get_unquoted_path("\""); // "
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("\"\"\""); // """
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("\\\""); // \"
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("\\\"\\\""); // \"\"
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("A\\B\\C\""); // A\B\C"
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("\"A\\B\\C"); // "A\B\C
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("\"A\\B\"C\""); // "A\B"C"
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("A\\B\"C"); // A\B"C
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("");
+ tt_str_op(r, OP_EQ, "");
+ tor_free(r);
+
+ r = get_unquoted_path("\"\""); // ""
+ tt_str_op(r, OP_EQ, "");
+ tor_free(r);
+
+ r = get_unquoted_path("A\\B\\C"); // A\B\C
+ tt_str_op(r, OP_EQ, "A\\B\\C"); // A\B\C
+ tor_free(r);
+
+ r = get_unquoted_path("\"A\\B\\C\""); // "A\B\C"
+ tt_str_op(r, OP_EQ, "A\\B\\C"); // A\B\C
+ tor_free(r);
+
+ r = get_unquoted_path("\"\\\""); // "\"
+ tt_str_op(r, OP_EQ, "\\"); // \ /* comment to prevent line continuation */
+ tor_free(r);
+
+ r = get_unquoted_path("\"\\\"\""); // "\""
+ tt_str_op(r, OP_EQ, "\""); // "
+ tor_free(r);
+
+ r = get_unquoted_path("\"A\\B\\C\\\"\""); // "A\B\C\""
+ tt_str_op(r, OP_EQ, "A\\B\\C\""); // A\B\C"
+ tor_free(r);
+
+ r = get_unquoted_path("A\\B\\\"C"); // A\B\"C
+ tt_str_op(r, OP_EQ, "A\\B\"C"); // A\B"C
+ tor_free(r);
+
+ r = get_unquoted_path("\"A\\B\\\"C\""); // "A\B\"C"
+ tt_str_op(r, OP_EQ, "A\\B\"C"); // A\B"C
+
+ done:
+ tor_free(r);
+}
+
#define UTIL_LEGACY(name) \
{ #name, test_util_ ## name , 0, NULL, NULL }
#define UTIL_TEST(name, flags) \
{ #name, test_util_ ## name, flags, NULL, NULL }
+#define COMPRESS(name, identifier) \
+ { "compress/" #name, test_util_compress, 0, &passthrough_setup, \
+ (char*)(identifier) }
+
+#define COMPRESS_CONCAT(name, identifier) \
+ { "compress_concat/" #name, test_util_decompress_concatenated, 0, \
+ &passthrough_setup, \
+ (char*)(identifier) }
+
+#define COMPRESS_JUNK(name, identifier) \
+ { "compress_junk/" #name, test_util_decompress_junk, 0, \
+ &passthrough_setup, \
+ (char*)(identifier) }
+
+#define COMPRESS_DOS(name, identifier) \
+ { "compress_dos/" #name, test_util_decompress_dos, 0, \
+ &passthrough_setup, \
+ (char*)(identifier) }
+
#ifdef _WIN32
#define UTIL_TEST_NO_WIN(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
#define UTIL_TEST_WIN_ONLY(n, f) UTIL_TEST(n, (f))
@@ -5637,7 +6148,7 @@ test_util_monotonic_time_ratchet(void *arg)
#define UTIL_TEST_NO_WIN(n, f) UTIL_TEST(n, (f))
#define UTIL_TEST_WIN_ONLY(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
#define UTIL_LEGACY_NO_WIN(n) UTIL_LEGACY(n)
-#endif
+#endif /* defined(_WIN32) */
struct testcase_t util_tests[] = {
UTIL_LEGACY(time),
@@ -5653,7 +6164,23 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(strmisc),
UTIL_TEST(parse_integer, 0),
UTIL_LEGACY(pow2),
- UTIL_LEGACY(gzip),
+ COMPRESS(zlib, "deflate"),
+ COMPRESS(gzip, "gzip"),
+ COMPRESS(lzma, "x-tor-lzma"),
+ COMPRESS(zstd, "x-zstd"),
+ COMPRESS(none, "identity"),
+ COMPRESS_CONCAT(zlib, "deflate"),
+ COMPRESS_CONCAT(gzip, "gzip"),
+ COMPRESS_CONCAT(lzma, "x-tor-lzma"),
+ COMPRESS_CONCAT(zstd, "x-zstd"),
+ COMPRESS_CONCAT(none, "identity"),
+ COMPRESS_JUNK(zlib, "deflate"),
+ COMPRESS_JUNK(gzip, "gzip"),
+ COMPRESS_JUNK(lzma, "x-tor-lzma"),
+ COMPRESS_DOS(zlib, "deflate"),
+ COMPRESS_DOS(gzip, "gzip"),
+ COMPRESS_DOS(lzma, "x-tor-lzma"),
+ COMPRESS_DOS(zstd, "x-zstd"),
UTIL_TEST(gzip_compression_bomb, TT_FORK),
UTIL_LEGACY(datadir),
UTIL_LEGACY(memarea),
@@ -5677,7 +6204,7 @@ struct testcase_t util_tests[] = {
UTIL_TEST(num_cpus, 0),
UTIL_TEST_WIN_ONLY(load_win_lib, 0),
UTIL_TEST_NO_WIN(exit_status, 0),
- UTIL_TEST_NO_WIN(fgets_eagain, 0),
+ UTIL_TEST_NO_WIN(string_from_pipe, 0),
UTIL_TEST(format_hex_number, 0),
UTIL_TEST(format_dec_number, 0),
UTIL_TEST(join_win_cmdline, 0),
@@ -5708,6 +6235,7 @@ struct testcase_t util_tests[] = {
&passthrough_setup, (void*)"1" },
UTIL_TEST(max_mem, 0),
UTIL_TEST(hostname_validation, 0),
+ UTIL_TEST(dest_validation_edgecase, 0),
UTIL_TEST(ipv4_validation, 0),
UTIL_TEST(writepid, 0),
UTIL_TEST(get_avail_disk_space, 0),
@@ -5716,6 +6244,10 @@ struct testcase_t util_tests[] = {
UTIL_TEST(calloc_check, 0),
UTIL_TEST(monotonic_time, 0),
UTIL_TEST(monotonic_time_ratchet, TT_FORK),
+ UTIL_TEST(monotonic_time_zero, 0),
+ UTIL_TEST(monotonic_time_add_msec, 0),
+ UTIL_TEST(htonll, 0),
+ UTIL_TEST(get_unquoted_path, 0),
END_OF_TESTCASES
};