summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/Makefile.am29
-rw-r--r--src/test/Makefile.nmake20
-rw-r--r--src/test/bench.c320
-rw-r--r--src/test/test-child.c43
-rw-r--r--src/test/test.c990
-rw-r--r--src/test/test.h14
-rw-r--r--src/test/test_addr.c212
-rw-r--r--src/test/test_config.c170
-rw-r--r--src/test/test_containers.c30
-rw-r--r--src/test/test_crypto.c244
-rw-r--r--src/test/test_data.c2
-rw-r--r--src/test/test_dir.c169
-rw-r--r--src/test/test_microdesc.c233
-rw-r--r--src/test/test_pt.c143
-rw-r--r--src/test/test_util.c2141
-rw-r--r--src/test/tinytest.c59
-rw-r--r--src/test/tinytest.h18
-rw-r--r--src/test/tinytest_demo.c14
-rw-r--r--src/test/tinytest_macros.h97
19 files changed, 4252 insertions, 696 deletions
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
index 904719d94b..31a464ee7a 100644
--- a/src/test/Makefile.am
+++ b/src/test/Makefile.am
@@ -1,6 +1,6 @@
TESTS = test
-noinst_PROGRAMS = test
+noinst_PROGRAMS = test test-child bench
AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
-DLOCALSTATEDIR="\"$(localstatedir)\"" \
@@ -12,19 +12,38 @@ AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
# matters a lot there, and is quite hard to debug if you forget to do it.
test_SOURCES = \
- test_data.c \
test.c \
test_addr.c \
+ test_containers.c \
test_crypto.c \
+ test_data.c \
test_dir.c \
- test_containers.c \
+ test_microdesc.c \
+ test_pt.c \
test_util.c \
+ test_config.c \
tinytest.c
+bench_SOURCES = \
+ bench.c
+
test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
test_LDADD = ../or/libtor.a ../common/libor.a ../common/libor-crypto.a \
../common/libor-event.a \
- @TOR_ZLIB_LIBS@ -lm @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
+
+bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
+ @TOR_LDFLAGS_libevent@
+bench_LDADD = ../or/libtor.a ../common/libor.a ../common/libor-crypto.a \
+ ../common/libor-event.a \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
+
+noinst_HEADERS = \
+ tinytest.h \
+ tinytest_macros.h \
+ test.h
+
-noinst_HEADERS = tinytest.h tinytest_macros.h test.h
diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake
new file mode 100644
index 0000000000..aec477cf99
--- /dev/null
+++ b/src/test/Makefile.nmake
@@ -0,0 +1,20 @@
+all: test.exe
+
+CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common /I ..\or
+
+LIBS = ..\..\..\build-alpha\lib\libevent.lib \
+ ..\..\..\build-alpha\lib\libcrypto.lib \
+ ..\..\..\build-alpha\lib\libssl.lib \
+ ..\..\..\build-alpha\lib\libz.lib \
+ ..\or\libtor.lib \
+ ws2_32.lib advapi32.lib shell32.lib
+
+TEST_OBJECTS = test.obj test_addr.obj test_containers.obj \
+ test_crypto.obj test_data.obj test_dir.obj test_microdesc.obj \
+ test_pt.obj test_util.obj test_config.obj tinytest.obj
+
+test.exe: $(TEST_OBJECTS)
+ $(CC) $(CFLAGS) $(LIBS) ..\common\*.lib $(TEST_OBJECTS)
+
+clean:
+ del $(TEST_OBJECTS) *.lib test.exe
diff --git a/src/test/bench.c b/src/test/bench.c
new file mode 100644
index 0000000000..3eae532d30
--- /dev/null
+++ b/src/test/bench.c
@@ -0,0 +1,320 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Ordinarily defined in tor_main.c; this bit is just here to provide one
+ * since we're not linking to tor_main.c */
+const char tor_git_revision[] = "";
+
+/**
+ * \file bench.c
+ * \brief Benchmarks for lower level Tor modules.
+ **/
+
+#include "orconfig.h"
+
+#define RELAY_PRIVATE
+
+#include "or.h"
+#include "relay.h"
+
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
+static uint64_t nanostart;
+static inline uint64_t
+timespec_to_nsec(const struct timespec *ts)
+{
+ return ((uint64_t)ts->tv_sec)*1000000000 + ts->tv_nsec;
+}
+
+static void
+reset_perftime(void)
+{
+ struct timespec ts;
+ int r;
+ r = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
+ tor_assert(r == 0);
+ nanostart = timespec_to_nsec(&ts);
+}
+
+static uint64_t
+perftime(void)
+{
+ struct timespec ts;
+ int r;
+ r = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
+ tor_assert(r == 0);
+ return timespec_to_nsec(&ts) - nanostart;
+}
+
+#else
+static struct timeval tv_start = { 0, 0 };
+static void
+reset_perftime(void)
+{
+ tor_gettimeofday(&tv_start);
+}
+static uint64_t
+perftime(void)
+{
+ struct timeval now, out;
+ tor_gettimeofday(&now);
+ timersub(&now, &tv_start, &out);
+ return ((uint64_t)out.tv_sec)*1000000000 + out.tv_usec*1000;
+}
+#endif
+
+#define NANOCOUNT(start,end,iters) \
+ ( ((double)((end)-(start))) / (iters) )
+
+/** Run AES performance benchmarks. */
+static void
+bench_aes(void)
+{
+ int len, i;
+ char *b1, *b2;
+ crypto_cipher_t *c;
+ uint64_t start, end;
+ const int bytes_per_iter = (1<<24);
+ reset_perftime();
+ c = crypto_cipher_new(NULL);
+
+ for (len = 1; len <= 8192; len *= 2) {
+ int iters = bytes_per_iter / len;
+ b1 = tor_malloc_zero(len);
+ b2 = tor_malloc_zero(len);
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ crypto_cipher_encrypt(c, b1, b2, len);
+ }
+ end = perftime();
+ tor_free(b1);
+ tor_free(b2);
+ printf("%d bytes: %.2f nsec per byte\n", len,
+ NANOCOUNT(start, end, iters*len));
+ }
+ crypto_cipher_free(c);
+}
+
+static void
+bench_cell_aes(void)
+{
+ uint64_t start, end;
+ const int len = 509;
+ const int iters = (1<<16);
+ const int max_misalign = 15;
+ char *b = tor_malloc(len+max_misalign);
+ crypto_cipher_t *c;
+ int i, misalign;
+
+ c = crypto_cipher_new(NULL);
+
+ reset_perftime();
+ for (misalign = 0; misalign <= max_misalign; ++misalign) {
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ crypto_cipher_crypt_inplace(c, b+misalign, len);
+ }
+ end = perftime();
+ printf("%d bytes, misaligned by %d: %.2f nsec per byte\n", len, misalign,
+ NANOCOUNT(start, end, iters*len));
+ }
+
+ crypto_cipher_free(c);
+ tor_free(b);
+}
+
+/** Run digestmap_t performance benchmarks. */
+static void
+bench_dmap(void)
+{
+ smartlist_t *sl = smartlist_new();
+ smartlist_t *sl2 = smartlist_new();
+ uint64_t start, end, pt2, pt3, pt4;
+ int iters = 8192;
+ const int elts = 4000;
+ const int fpostests = 100000;
+ char d[20];
+ int i,n=0, fp = 0;
+ digestmap_t *dm = digestmap_new();
+ digestset_t *ds = digestset_new(elts);
+
+ for (i = 0; i < elts; ++i) {
+ crypto_rand(d, 20);
+ smartlist_add(sl, tor_memdup(d, 20));
+ }
+ for (i = 0; i < elts; ++i) {
+ crypto_rand(d, 20);
+ smartlist_add(sl2, tor_memdup(d, 20));
+ }
+ printf("nbits=%d\n", ds->mask+1);
+
+ reset_perftime();
+
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ SMARTLIST_FOREACH(sl, const char *, cp, digestmap_set(dm, cp, (void*)1));
+ }
+ pt2 = perftime();
+ printf("digestmap_set: %.2f ns per element\n",
+ NANOCOUNT(start, pt2, iters*elts));
+
+ for (i = 0; i < iters; ++i) {
+ SMARTLIST_FOREACH(sl, const char *, cp, digestmap_get(dm, cp));
+ SMARTLIST_FOREACH(sl2, const char *, cp, digestmap_get(dm, cp));
+ }
+ pt3 = perftime();
+ printf("digestmap_get: %.2f ns per element\n",
+ NANOCOUNT(pt2, pt3, iters*elts*2));
+
+ for (i = 0; i < iters; ++i) {
+ SMARTLIST_FOREACH(sl, const char *, cp, digestset_add(ds, cp));
+ }
+ pt4 = perftime();
+ printf("digestset_add: %.2f ns per element\n",
+ NANOCOUNT(pt3, pt4, iters*elts));
+
+ for (i = 0; i < iters; ++i) {
+ SMARTLIST_FOREACH(sl, const char *, cp, n += digestset_isin(ds, cp));
+ SMARTLIST_FOREACH(sl2, const char *, cp, n += digestset_isin(ds, cp));
+ }
+ end = perftime();
+ printf("digestset_isin: %.2f ns per element.\n",
+ NANOCOUNT(pt4, end, iters*elts*2));
+ /* We need to use this, or else the whole loop gets optimized out. */
+ printf("Hits == %d\n", n);
+
+ for (i = 0; i < fpostests; ++i) {
+ crypto_rand(d, 20);
+ if (digestset_isin(ds, d)) ++fp;
+ }
+ printf("False positive rate on digestset: %.2f%%\n",
+ (fp/(double)fpostests)*100);
+
+ digestmap_free(dm, NULL);
+ digestset_free(ds);
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ SMARTLIST_FOREACH(sl2, char *, cp, tor_free(cp));
+ smartlist_free(sl);
+ smartlist_free(sl2);
+}
+
+static void
+bench_cell_ops(void)
+{
+ const int iters = 1<<16;
+ int i;
+
+ /* benchmarks for cell ops at relay. */
+ or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ cell_t *cell = tor_malloc(sizeof(cell_t));
+ int outbound;
+ uint64_t start, end;
+
+ crypto_rand((char*)cell->payload, sizeof(cell->payload));
+
+ /* Mock-up or_circuit_t */
+ or_circ->_base.magic = OR_CIRCUIT_MAGIC;
+ or_circ->_base.purpose = CIRCUIT_PURPOSE_OR;
+
+ /* Initialize crypto */
+ or_circ->p_crypto = crypto_cipher_new(NULL);
+ or_circ->n_crypto = crypto_cipher_new(NULL);
+ or_circ->p_digest = crypto_digest_new();
+ or_circ->n_digest = crypto_digest_new();
+
+ reset_perftime();
+
+ for (outbound = 0; outbound <= 1; ++outbound) {
+ cell_direction_t d = outbound ? CELL_DIRECTION_OUT : CELL_DIRECTION_IN;
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ char recognized = 0;
+ crypt_path_t *layer_hint = NULL;
+ relay_crypt(TO_CIRCUIT(or_circ), cell, d, &layer_hint, &recognized);
+ }
+ end = perftime();
+ printf("%sbound cells: %.2f ns per cell. (%.2f ns per byte of payload)\n",
+ outbound?"Out":" In",
+ NANOCOUNT(start,end,iters),
+ NANOCOUNT(start,end,iters*CELL_PAYLOAD_SIZE));
+ }
+
+ crypto_digest_free(or_circ->p_digest);
+ crypto_digest_free(or_circ->n_digest);
+ crypto_cipher_free(or_circ->p_crypto);
+ crypto_cipher_free(or_circ->n_crypto);
+ tor_free(or_circ);
+ tor_free(cell);
+}
+
+typedef void (*bench_fn)(void);
+
+typedef struct benchmark_t {
+ const char *name;
+ bench_fn fn;
+ int enabled;
+} benchmark_t;
+
+#define ENT(s) { #s , bench_##s, 0 }
+
+static struct benchmark_t benchmarks[] = {
+ ENT(dmap),
+ ENT(aes),
+ ENT(cell_aes),
+ ENT(cell_ops),
+ {NULL,NULL,0}
+};
+
+static benchmark_t *
+find_benchmark(const char *name)
+{
+ benchmark_t *b;
+ for (b = benchmarks; b->name; ++b) {
+ if (!strcmp(name, b->name)) {
+ return b;
+ }
+ }
+ return NULL;
+}
+
+/** Main entry point for benchmark code: parse the command line, and run
+ * some benchmarks. */
+int
+main(int argc, const char **argv)
+{
+ int i;
+ int list=0, n_enabled=0;
+ benchmark_t *b;
+
+ tor_threads_init();
+
+ for (i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "--list")) {
+ list = 1;
+ } else {
+ benchmark_t *b = find_benchmark(argv[i]);
+ ++n_enabled;
+ if (b) {
+ b->enabled = 1;
+ } else {
+ printf("No such benchmark as %s\n", argv[i]);
+ }
+ }
+ }
+
+ reset_perftime();
+
+ crypto_seed_rng(1);
+
+ for (b = benchmarks; b->name; ++b) {
+ if (b->enabled || n_enabled == 0) {
+ printf("===== %s =====\n", b->name);
+ if (!list)
+ b->fn();
+ }
+ }
+
+ return 0;
+}
+
diff --git a/src/test/test-child.c b/src/test/test-child.c
new file mode 100644
index 0000000000..c5725f1c5a
--- /dev/null
+++ b/src/test/test-child.c
@@ -0,0 +1,43 @@
+/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include <stdio.h>
+#include "orconfig.h"
+#ifdef _WIN32
+#define WINDOWS_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+/** Trivial test program which prints out its command line arguments so we can
+ * check if tor_spawn_background() works */
+int
+main(int argc, char **argv)
+{
+ int i;
+
+ fprintf(stdout, "OUT\n");
+ fprintf(stderr, "ERR\n");
+ for (i = 1; i < argc; i++)
+ fprintf(stdout, "%s\n", argv[i]);
+ fprintf(stdout, "SLEEPING\n");
+ /* We need to flush stdout so that test_util_spawn_background_partial_read()
+ succeed. Otherwise ReadFile() will get the entire output in one */
+ // XXX: Can we make stdio flush on newline?
+ fflush(stdout);
+#ifdef _WIN32
+ Sleep(1000);
+#else
+ sleep(1);
+#endif
+ fprintf(stdout, "DONE\n");
+#ifdef _WIN32
+ Sleep(1000);
+#else
+ sleep(1);
+#endif
+
+ return 0;
+}
+
diff --git a/src/test/test.c b/src/test/test.c
index b5b744eba7..6bf2d28d90 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Ordinarily defined in tor_main.c; this bit is just here to provide one
@@ -19,7 +19,7 @@ const char tor_git_revision[] = "";
#include <fcntl.h>
#endif
-#ifdef MS_WINDOWS
+#ifdef _WIN32
/* For mkdir() */
#include <direct.h>
#else
@@ -71,6 +71,9 @@ int have_failed = 0;
/** Temporary directory (set up by setup_directory) under which we store all
* our files during testing. */
static char temp_dir[256];
+#ifdef _WIN32
+#define pid_t int
+#endif
static pid_t temp_dir_setup_in_pid = 0;
/** Select and create the temporary directory we'll use to run our unit tests.
@@ -83,12 +86,12 @@ setup_directory(void)
int r;
if (is_setup) return;
-#ifdef MS_WINDOWS
+#ifdef _WIN32
{
char buf[MAX_PATH];
const char *tmp = buf;
/* If this fails, we're probably screwed anyway */
- if (!GetTempPath(sizeof(buf),buf))
+ if (!GetTempPathA(sizeof(buf),buf))
tmp = "c:\\windows\\temp";
tor_snprintf(temp_dir, sizeof(temp_dir),
"%s\\tor_test_%d", tmp, (int)getpid());
@@ -119,56 +122,71 @@ get_fname(const char *name)
return buf;
}
+/* Remove a directory and all of its subdirectories */
+static void
+rm_rf(const char *dir)
+{
+ struct stat st;
+ smartlist_t *elements;
+
+ elements = tor_listdir(dir);
+ if (elements) {
+ SMARTLIST_FOREACH_BEGIN(elements, const char *, cp) {
+ char *tmp = NULL;
+ tor_asprintf(&tmp, "%s"PATH_SEPARATOR"%s", dir, cp);
+ if (0 == stat(tmp,&st) && (st.st_mode & S_IFDIR)) {
+ rm_rf(tmp);
+ } else {
+ if (unlink(tmp)) {
+ fprintf(stderr, "Error removing %s: %s\n", tmp, strerror(errno));
+ }
+ }
+ tor_free(tmp);
+ } SMARTLIST_FOREACH_END(cp);
+ SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
+ smartlist_free(elements);
+ }
+ if (rmdir(dir))
+ fprintf(stderr, "Error removing directory %s: %s\n", dir, strerror(errno));
+}
+
/** Remove all files stored under the temporary directory, and the directory
* itself. Called by atexit(). */
static void
remove_directory(void)
{
- smartlist_t *elements;
if (getpid() != temp_dir_setup_in_pid) {
/* Only clean out the tempdir when the main process is exiting. */
return;
}
- elements = tor_listdir(temp_dir);
- if (elements) {
- SMARTLIST_FOREACH(elements, const char *, cp,
- {
- size_t len = strlen(cp)+strlen(temp_dir)+16;
- char *tmp = tor_malloc(len);
- tor_snprintf(tmp, len, "%s"PATH_SEPARATOR"%s", temp_dir, cp);
- unlink(tmp);
- tor_free(tmp);
- });
- SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
- smartlist_free(elements);
- }
- rmdir(temp_dir);
+
+ rm_rf(temp_dir);
}
/** Define this if unit tests spend too much time generating public keys*/
#undef CACHE_GENERATED_KEYS
-static crypto_pk_env_t *pregen_keys[5] = {NULL, NULL, NULL, NULL, NULL};
+static crypto_pk_t *pregen_keys[5] = {NULL, NULL, NULL, NULL, NULL};
#define N_PREGEN_KEYS ((int)(sizeof(pregen_keys)/sizeof(pregen_keys[0])))
/** Generate and return a new keypair for use in unit tests. If we're using
* the key cache optimization, we might reuse keys: we only guarantee that
* keys made with distinct values for <b>idx</b> are different. The value of
* <b>idx</b> must be at least 0, and less than N_PREGEN_KEYS. */
-crypto_pk_env_t *
+crypto_pk_t *
pk_generate(int idx)
{
#ifdef CACHE_GENERATED_KEYS
tor_assert(idx < N_PREGEN_KEYS);
if (! pregen_keys[idx]) {
- pregen_keys[idx] = crypto_new_pk_env();
+ pregen_keys[idx] = crypto_pk_new();
tor_assert(!crypto_pk_generate_key(pregen_keys[idx]));
}
return crypto_pk_dup_key(pregen_keys[idx]);
#else
- crypto_pk_env_t *result;
+ crypto_pk_t *result;
(void) idx;
- result = crypto_new_pk_env();
+ result = crypto_pk_new();
tor_assert(!crypto_pk_generate_key(result));
return result;
#endif
@@ -181,12 +199,443 @@ free_pregenerated_keys(void)
unsigned idx;
for (idx = 0; idx < N_PREGEN_KEYS; ++idx) {
if (pregen_keys[idx]) {
- crypto_free_pk_env(pregen_keys[idx]);
+ crypto_pk_free(pregen_keys[idx]);
pregen_keys[idx] = NULL;
}
}
}
+typedef struct socks_test_data_t {
+ socks_request_t *req;
+ buf_t *buf;
+} socks_test_data_t;
+
+static void *
+socks_test_setup(const struct testcase_t *testcase)
+{
+ socks_test_data_t *data = tor_malloc(sizeof(socks_test_data_t));
+ (void)testcase;
+ data->buf = buf_new_with_capacity(256);
+ data->req = socks_request_new();
+ config_register_addressmaps(get_options());
+ return data;
+}
+static int
+socks_test_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ socks_test_data_t *data = ptr;
+ (void)testcase;
+ buf_free(data->buf);
+ socks_request_free(data->req);
+ tor_free(data);
+ return 1;
+}
+
+const struct testcase_setup_t socks_setup = {
+ socks_test_setup, socks_test_cleanup
+};
+
+#define SOCKS_TEST_INIT() \
+ socks_test_data_t *testdata = ptr; \
+ buf_t *buf = testdata->buf; \
+ socks_request_t *socks = testdata->req;
+#define ADD_DATA(buf, s) \
+ write_to_buf(s, sizeof(s)-1, buf)
+
+static void
+socks_request_clear(socks_request_t *socks)
+{
+ tor_free(socks->username);
+ tor_free(socks->password);
+ memset(socks, 0, sizeof(socks_request_t));
+}
+
+/** Perform unsupported SOCKS 4 commands */
+static void
+test_socks_4_unsupported_commands(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 4 Send BIND [02] to IP address 2.2.2.2:4369 */
+ ADD_DATA(buf, "\x04\x02\x11\x11\x02\x02\x02\x02\x00");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == -1);
+ test_eq(4, socks->socks_version);
+ test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
+
+ done:
+ ;
+}
+
+/** Perform supported SOCKS 4 commands */
+static void
+test_socks_4_supported_commands(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ test_eq(0, buf_datalen(buf));
+
+ /* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4370 */
+ ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x03\x00");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(4, socks->socks_version);
+ test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
+ test_eq(SOCKS_COMMAND_CONNECT, socks->command);
+ test_streq("2.2.2.3", socks->address);
+ test_eq(4370, socks->port);
+ test_assert(socks->got_auth == 0);
+ test_assert(! socks->username);
+
+ test_eq(0, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4369 with userid*/
+ ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x04me\x00");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(4, socks->socks_version);
+ test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
+ test_eq(SOCKS_COMMAND_CONNECT, socks->command);
+ test_streq("2.2.2.4", socks->address);
+ test_eq(4370, socks->port);
+ test_assert(socks->got_auth == 1);
+ test_assert(socks->username);
+ test_eq(2, socks->usernamelen);
+ test_memeq("me", socks->username, 2);
+
+ test_eq(0, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 4a Send RESOLVE [F0] request for torproject.org */
+ ADD_DATA(buf, "\x04\xF0\x01\x01\x00\x00\x00\x02me\x00torproject.org\x00");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(4, socks->socks_version);
+ test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
+ test_streq("torproject.org", socks->address);
+
+ test_eq(0, buf_datalen(buf));
+
+ done:
+ ;
+}
+
+/** Perform unsupported SOCKS 5 commands */
+static void
+test_socks_5_unsupported_commands(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 5 Send unsupported BIND [02] command */
+ ADD_DATA(buf, "\x05\x02\x00\x01");
+
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), 0);
+ test_eq(0, buf_datalen(buf));
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+ ADD_DATA(buf, "\x05\x02\x00\x01\x02\x02\x02\x01\x01\x01");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), -1);
+ /* XXX: shouldn't tor reply 'command not supported' [07]? */
+
+ buf_clear(buf);
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send unsupported UDP_ASSOCIATE [03] command */
+ ADD_DATA(buf, "\x05\x03\x00\x01\x02");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), 0);
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+ ADD_DATA(buf, "\x05\x03\x00\x01\x02\x02\x02\x01\x01\x01");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), -1);
+ /* XXX: shouldn't tor reply 'command not supported' [07]? */
+
+ done:
+ ;
+}
+
+/** Perform supported SOCKS 5 commands */
+static void
+test_socks_5_supported_commands(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */
+ ADD_DATA(buf, "\x05\x01\x00");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), 0);
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+
+ ADD_DATA(buf, "\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), 1);
+ test_streq("2.2.2.2", socks->address);
+ test_eq(4369, socks->port);
+
+ test_eq(0, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send CONNECT [01] to FQDN torproject.org:4369 */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\x01\x00\x03\x0Etorproject.org\x11\x11");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), 1);
+
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+ test_streq("torproject.org", socks->address);
+ test_eq(4369, socks->port);
+
+ test_eq(0, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send RESOLVE [F0] request for torproject.org:4369 */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\xF0\x00\x03\x0Etorproject.org\x01\x02");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+ test_streq("torproject.org", socks->address);
+
+ test_eq(0, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send RESOLVE_PTR [F1] for IP address 2.2.2.5 */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\xF1\x00\x01\x02\x02\x02\x05\x01\x03");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+ test_streq("2.2.2.5", socks->address);
+
+ test_eq(0, buf_datalen(buf));
+
+ done:
+ ;
+}
+
+/** Perform SOCKS 5 authentication */
+static void
+test_socks_5_no_authenticate(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /*SOCKS 5 No Authentication */
+ ADD_DATA(buf,"\x05\x01\x00");
+ test_assert(!fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks));
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(SOCKS_NO_AUTH, socks->reply[1]);
+
+ test_eq(0, buf_datalen(buf));
+
+ /*SOCKS 5 Send username/password anyway - pretend to be broken */
+ ADD_DATA(buf,"\x01\x02\x01\x01\x02\x01\x01");
+ test_assert(!fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks));
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+
+ test_eq(2, socks->usernamelen);
+ test_eq(2, socks->passwordlen);
+
+ test_memeq("\x01\x01", socks->username, 2);
+ test_memeq("\x01\x01", socks->password, 2);
+
+ done:
+ ;
+}
+
+/** Perform SOCKS 5 authentication */
+static void
+test_socks_5_authenticate(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 5 Negotiate username/password authentication */
+ ADD_DATA(buf, "\x05\x01\x02");
+
+ test_assert(!fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks));
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(SOCKS_USER_PASS, socks->reply[1]);
+ test_eq(5, socks->socks_version);
+
+ test_eq(0, buf_datalen(buf));
+
+ /* SOCKS 5 Send username/password */
+ ADD_DATA(buf, "\x01\x02me\x08mypasswd");
+ test_assert(!fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks));
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+
+ test_eq(2, socks->usernamelen);
+ test_eq(8, socks->passwordlen);
+
+ test_memeq("me", socks->username, 2);
+ test_memeq("mypasswd", socks->password, 8);
+
+ done:
+ ;
+}
+
+/** Perform SOCKS 5 authentication and send data all in one go */
+static void
+test_socks_5_authenticate_with_data(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 5 Negotiate username/password authentication */
+ ADD_DATA(buf, "\x05\x01\x02");
+
+ test_assert(!fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks));
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(SOCKS_USER_PASS, socks->reply[1]);
+ test_eq(5, socks->socks_version);
+
+ test_eq(0, buf_datalen(buf));
+
+ /* SOCKS 5 Send username/password */
+ /* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */
+ ADD_DATA(buf, "\x01\x02me\x03you\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11");
+ test_assert(fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+
+ test_streq("2.2.2.2", socks->address);
+ test_eq(4369, socks->port);
+
+ test_eq(2, socks->usernamelen);
+ test_eq(3, socks->passwordlen);
+ test_memeq("me", socks->username, 2);
+ test_memeq("you", socks->password, 3);
+
+ done:
+ ;
+}
+
+/** Perform SOCKS 5 authentication before method negotiated */
+static void
+test_socks_5_auth_before_negotiation(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 5 Send username/password */
+ ADD_DATA(buf, "\x01\x02me\x02me");
+ test_assert(fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks) == -1);
+ test_eq(0, socks->socks_version);
+ test_eq(0, socks->replylen);
+ test_eq(0, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+
+ done:
+ ;
+}
+
+static void
+test_buffer_copy(void *arg)
+{
+ generic_buffer_t *buf=NULL, *buf2=NULL;
+ const char *s;
+ size_t len;
+ char b[256];
+ int i;
+ (void)arg;
+
+ buf = generic_buffer_new();
+ tt_assert(buf);
+
+ /* Copy an empty buffer. */
+ tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
+ tt_assert(buf2);
+ tt_int_op(0, ==, generic_buffer_len(buf2));
+
+ /* Now try with a short buffer. */
+ s = "And now comes an act of enormous enormance!";
+ len = strlen(s);
+ generic_buffer_add(buf, s, len);
+ tt_int_op(len, ==, generic_buffer_len(buf));
+ /* Add junk to buf2 so we can test replacing.*/
+ generic_buffer_add(buf2, "BLARG", 5);
+ tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
+ tt_int_op(len, ==, generic_buffer_len(buf2));
+ generic_buffer_get(buf2, b, len);
+ test_mem_op(b, ==, s, len);
+ /* Now free buf2 and retry so we can test allocating */
+ generic_buffer_free(buf2);
+ buf2 = NULL;
+ tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
+ tt_int_op(len, ==, generic_buffer_len(buf2));
+ generic_buffer_get(buf2, b, len);
+ test_mem_op(b, ==, s, len);
+ /* Clear buf for next test */
+ generic_buffer_get(buf, b, len);
+ tt_int_op(generic_buffer_len(buf),==,0);
+
+ /* Okay, now let's try a bigger buffer. */
+ s = "Quis autem vel eum iure reprehenderit qui in ea voluptate velit "
+ "esse quam nihil molestiae consequatur, vel illum qui dolorem eum "
+ "fugiat quo voluptas nulla pariatur?";
+ len = strlen(s);
+ for (i = 0; i < 256; ++i) {
+ b[0]=i;
+ generic_buffer_add(buf, b, 1);
+ generic_buffer_add(buf, s, len);
+ }
+ tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
+ tt_int_op(generic_buffer_len(buf2), ==, generic_buffer_len(buf));
+ for (i = 0; i < 256; ++i) {
+ generic_buffer_get(buf2, b, len+1);
+ tt_int_op((unsigned char)b[0],==,i);
+ test_mem_op(b+1, ==, s, len);
+ }
+
+ done:
+ if (buf)
+ generic_buffer_free(buf);
+ if (buf2)
+ generic_buffer_free(buf2);
+}
+
/** Run unit tests for buffers.c */
static void
test_buffers(void)
@@ -365,7 +814,7 @@ static void
test_onion_handshake(void)
{
/* client-side */
- crypto_dh_env_t *c_dh = NULL;
+ crypto_dh_t *c_dh = NULL;
char c_buf[ONIONSKIN_CHALLENGE_LEN];
char c_keys[40];
@@ -374,7 +823,7 @@ test_onion_handshake(void)
char s_keys[40];
/* shared */
- crypto_pk_env_t *pk = NULL;
+ crypto_pk_t *pk = NULL;
pk = pk_generate(0);
@@ -404,7 +853,7 @@ test_onion_handshake(void)
if (c_dh)
crypto_dh_free(c_dh);
if (pk)
- crypto_free_pk_env(pk);
+ crypto_pk_free(pk);
}
static void
@@ -563,9 +1012,10 @@ test_policy_summary_helper(const char *policy_str,
const char *expected_summary)
{
config_line_t line;
- smartlist_t *policy = smartlist_create();
+ smartlist_t *policy = smartlist_new();
char *summary = NULL;
int r;
+ short_policy_t *short_policy = NULL;
line.key = (char*)"foo";
line.value = (char *)policy_str;
@@ -578,10 +1028,14 @@ test_policy_summary_helper(const char *policy_str,
test_assert(summary != NULL);
test_streq(summary, expected_summary);
+ short_policy = parse_short_policy(summary);
+ tt_assert(short_policy);
+
done:
tor_free(summary);
if (policy)
addr_policy_list_free(policy);
+ short_policy_free(short_policy);
}
/** Run unit tests for generating summary lines of exit policies */
@@ -598,7 +1052,7 @@ test_policies(void)
smartlist_t *sm = NULL;
char *policy_str = NULL;
- policy = smartlist_create();
+ policy = smartlist_new();
p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1);
test_assert(p != NULL);
@@ -611,17 +1065,20 @@ test_policies(void)
smartlist_add(policy, p);
+ tor_addr_from_ipv4h(&tar, 0x01020304u);
test_assert(ADDR_POLICY_ACCEPTED ==
- compare_addr_to_addr_policy(0x01020304u, 2, policy));
+ compare_tor_addr_to_addr_policy(&tar, 2, policy));
+ tor_addr_make_unspec(&tar);
test_assert(ADDR_POLICY_PROBABLY_ACCEPTED ==
- compare_addr_to_addr_policy(0, 2, policy));
+ compare_tor_addr_to_addr_policy(&tar, 2, policy));
+ tor_addr_from_ipv4h(&tar, 0xc0a80102);
test_assert(ADDR_POLICY_REJECTED ==
- compare_addr_to_addr_policy(0xc0a80102, 2, policy));
+ compare_tor_addr_to_addr_policy(&tar, 2, policy));
test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, NULL, 1));
test_assert(policy2);
- policy3 = smartlist_create();
+ policy3 = smartlist_new();
p = router_parse_addr_policy_item_from_string("reject *:*",-1);
test_assert(p != NULL);
smartlist_add(policy3, p);
@@ -629,7 +1086,7 @@ test_policies(void)
test_assert(p != NULL);
smartlist_add(policy3, p);
- policy4 = smartlist_create();
+ policy4 = smartlist_new();
p = router_parse_addr_policy_item_from_string("accept *:443",-1);
test_assert(p != NULL);
smartlist_add(policy4, p);
@@ -637,7 +1094,7 @@ test_policies(void)
test_assert(p != NULL);
smartlist_add(policy4, p);
- policy5 = smartlist_create();
+ policy5 = smartlist_new();
p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*",-1);
test_assert(p != NULL);
smartlist_add(policy5, p);
@@ -669,12 +1126,12 @@ test_policies(void)
test_assert(p != NULL);
smartlist_add(policy5, p);
- policy6 = smartlist_create();
+ policy6 = smartlist_new();
p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*",-1);
test_assert(p != NULL);
smartlist_add(policy6, p);
- policy7 = smartlist_create();
+ policy7 = smartlist_new();
p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*",-1);
test_assert(p != NULL);
smartlist_add(policy7, p);
@@ -771,7 +1228,7 @@ test_policies(void)
"reject 1,3,5,7");
/* truncation ports */
- sm = smartlist_create();
+ sm = smartlist_new();
for (i=1; i<2000; i+=2) {
char buf[POLICY_BUF_LEN];
tor_snprintf(buf, sizeof(buf), "reject *:%d", i);
@@ -810,102 +1267,6 @@ test_policies(void)
}
}
-/** Run AES performance benchmarks. */
-static void
-bench_aes(void)
-{
- int len, i;
- char *b1, *b2;
- crypto_cipher_env_t *c;
- struct timeval start, end;
- const int iters = 100000;
- uint64_t nsec;
- c = crypto_new_cipher_env();
- crypto_cipher_generate_key(c);
- crypto_cipher_encrypt_init_cipher(c);
- for (len = 1; len <= 8192; len *= 2) {
- b1 = tor_malloc_zero(len);
- b2 = tor_malloc_zero(len);
- tor_gettimeofday(&start);
- for (i = 0; i < iters; ++i) {
- crypto_cipher_encrypt(c, b1, b2, len);
- }
- tor_gettimeofday(&end);
- tor_free(b1);
- tor_free(b2);
- nsec = (uint64_t) tv_udiff(&start,&end);
- nsec *= 1000;
- nsec /= (iters*len);
- printf("%d bytes: "U64_FORMAT" nsec per byte\n", len,
- U64_PRINTF_ARG(nsec));
- }
- crypto_free_cipher_env(c);
-}
-
-/** Run digestmap_t performance benchmarks. */
-static void
-bench_dmap(void)
-{
- smartlist_t *sl = smartlist_create();
- smartlist_t *sl2 = smartlist_create();
- struct timeval start, end, pt2, pt3, pt4;
- const int iters = 10000;
- const int elts = 4000;
- const int fpostests = 1000000;
- char d[20];
- int i,n=0, fp = 0;
- digestmap_t *dm = digestmap_new();
- digestset_t *ds = digestset_new(elts);
-
- for (i = 0; i < elts; ++i) {
- crypto_rand(d, 20);
- smartlist_add(sl, tor_memdup(d, 20));
- }
- for (i = 0; i < elts; ++i) {
- crypto_rand(d, 20);
- smartlist_add(sl2, tor_memdup(d, 20));
- }
- printf("nbits=%d\n", ds->mask+1);
-
- tor_gettimeofday(&start);
- for (i = 0; i < iters; ++i) {
- SMARTLIST_FOREACH(sl, const char *, cp, digestmap_set(dm, cp, (void*)1));
- }
- tor_gettimeofday(&pt2);
- for (i = 0; i < iters; ++i) {
- SMARTLIST_FOREACH(sl, const char *, cp, digestmap_get(dm, cp));
- SMARTLIST_FOREACH(sl2, const char *, cp, digestmap_get(dm, cp));
- }
- tor_gettimeofday(&pt3);
- for (i = 0; i < iters; ++i) {
- SMARTLIST_FOREACH(sl, const char *, cp, digestset_add(ds, cp));
- }
- tor_gettimeofday(&pt4);
- for (i = 0; i < iters; ++i) {
- SMARTLIST_FOREACH(sl, const char *, cp, n += digestset_isin(ds, cp));
- SMARTLIST_FOREACH(sl2, const char *, cp, n += digestset_isin(ds, cp));
- }
- tor_gettimeofday(&end);
-
- for (i = 0; i < fpostests; ++i) {
- crypto_rand(d, 20);
- if (digestset_isin(ds, d)) ++fp;
- }
-
- printf("%ld\n",(unsigned long)tv_udiff(&start, &pt2));
- printf("%ld\n",(unsigned long)tv_udiff(&pt2, &pt3));
- printf("%ld\n",(unsigned long)tv_udiff(&pt3, &pt4));
- printf("%ld\n",(unsigned long)tv_udiff(&pt4, &end));
- printf("-- %d\n", n);
- printf("++ %f\n", fp/(double)fpostests);
- digestmap_free(dm, NULL);
- digestset_free(ds);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- SMARTLIST_FOREACH(sl2, char *, cp, tor_free(cp));
- smartlist_free(sl);
- smartlist_free(sl2);
-}
-
/** Test encoding and parsing of rendezvous service descriptors. */
static void
test_rend_fns(void)
@@ -914,10 +1275,10 @@ test_rend_fns(void)
char service_id[DIGEST_LEN];
char service_id_base32[REND_SERVICE_ID_LEN_BASE32+1];
const char *next_desc;
- smartlist_t *descs = smartlist_create();
+ smartlist_t *descs = smartlist_new();
char computed_desc_id[DIGEST_LEN];
char parsed_desc_id[DIGEST_LEN];
- crypto_pk_env_t *pk1 = NULL, *pk2 = NULL;
+ crypto_pk_t *pk1 = NULL, *pk2 = NULL;
time_t now;
char *intro_points_encrypted = NULL;
size_t intro_points_size;
@@ -928,10 +1289,10 @@ test_rend_fns(void)
char address3[] = "fooaddress.exit";
char address4[] = "www.torproject.org";
- test_assert(BAD_HOSTNAME == parse_extended_hostname(address1, 1));
- test_assert(ONION_HOSTNAME == parse_extended_hostname(address2, 1));
- test_assert(EXIT_HOSTNAME == parse_extended_hostname(address3, 1));
- test_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4, 1));
+ test_assert(BAD_HOSTNAME == parse_extended_hostname(address1));
+ test_assert(ONION_HOSTNAME == parse_extended_hostname(address2));
+ test_assert(EXIT_HOSTNAME == parse_extended_hostname(address3));
+ test_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4));
pk1 = pk_generate(0);
pk2 = pk_generate(1);
@@ -944,11 +1305,11 @@ test_rend_fns(void)
generated->timestamp = now;
generated->version = 2;
generated->protocols = 42;
- generated->intro_nodes = smartlist_create();
+ generated->intro_nodes = smartlist_new();
for (i = 0; i < 3; i++) {
rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t));
- crypto_pk_env_t *okey = pk_generate(2 + i);
+ crypto_pk_t *okey = pk_generate(2 + i);
intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
intro->extend_info->onion_key = okey;
crypto_pk_get_digest(intro->extend_info->onion_key,
@@ -1015,9 +1376,9 @@ test_rend_fns(void)
if (generated)
rend_service_descriptor_free(generated);
if (pk1)
- crypto_free_pk_env(pk1);
+ crypto_pk_free(pk1);
if (pk2)
- crypto_free_pk_env(pk2);
+ crypto_pk_free(pk2);
tor_free(intro_points_encrypted);
}
@@ -1026,8 +1387,74 @@ static void
test_geoip(void)
{
int i, j;
- time_t now = time(NULL);
+ time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
char *s = NULL;
+ const char *bridge_stats_1 =
+ "bridge-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "bridge-ips zz=24,xy=8\n",
+ *dirreq_stats_1 =
+ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "dirreq-v3-ips ab=8\n"
+ "dirreq-v2-ips \n"
+ "dirreq-v3-reqs ab=8\n"
+ "dirreq-v2-reqs \n"
+ "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
+ "not-modified=0,busy=0\n"
+ "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
+ "busy=0\n"
+ "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ *dirreq_stats_2 =
+ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "dirreq-v3-ips \n"
+ "dirreq-v2-ips \n"
+ "dirreq-v3-reqs \n"
+ "dirreq-v2-reqs \n"
+ "dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
+ "not-modified=0,busy=0\n"
+ "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
+ "busy=0\n"
+ "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ *dirreq_stats_3 =
+ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "dirreq-v3-ips \n"
+ "dirreq-v2-ips \n"
+ "dirreq-v3-reqs \n"
+ "dirreq-v2-reqs \n"
+ "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
+ "not-modified=0,busy=0\n"
+ "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
+ "busy=0\n"
+ "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ *dirreq_stats_4 =
+ "dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "dirreq-v3-ips \n"
+ "dirreq-v2-ips \n"
+ "dirreq-v3-reqs \n"
+ "dirreq-v2-reqs \n"
+ "dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
+ "not-modified=0,busy=0\n"
+ "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
+ "busy=0\n"
+ "dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n"
+ "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ *entry_stats_1 =
+ "entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "entry-ips ab=8\n",
+ *entry_stats_2 =
+ "entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "entry-ips \n";
+ tor_addr_t addr;
/* Populate the DB a bit. Add these in order, since we can't do the final
* 'sort' step. These aren't very good IP addresses, but they're perfectly
@@ -1053,19 +1480,26 @@ test_geoip(void)
test_streq("??", NAMEFOR(2000));
#undef NAMEFOR
- get_options()->BridgeRelay = 1;
- get_options()->BridgeRecordUsageByCountry = 1;
+ get_options_mutable()->BridgeRelay = 1;
+ get_options_mutable()->BridgeRecordUsageByCountry = 1;
/* Put 9 observations in AB... */
- for (i=32; i < 40; ++i)
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, i, now-7200);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, 225, now-7200);
+ for (i=32; i < 40; ++i) {
+ tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200);
+ }
+ tor_addr_from_ipv4h(&addr, (uint32_t) 225);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200);
/* and 3 observations in XY, several times. */
for (j=0; j < 10; ++j)
- for (i=52; i < 55; ++i)
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, i, now-3600);
+ for (i=52; i < 55; ++i) {
+ tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-3600);
+ }
/* and 17 observations in ZZ... */
- for (i=110; i < 127; ++i)
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, i, now);
+ for (i=110; i < 127; ++i) {
+ tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
+ }
s = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
test_assert(s);
test_streq("zz=24,ab=16,xy=8", s);
@@ -1077,6 +1511,122 @@ test_geoip(void)
test_assert(s);
test_streq("zz=24,xy=8", s);
+ /* Start testing bridge statistics by making sure that we don't output
+ * bridge stats without initializing them. */
+ s = geoip_format_bridge_stats(now + 86400);
+ test_assert(!s);
+
+ /* Initialize stats and generate the bridge-stats history string out of
+ * the connecting clients added above. */
+ geoip_bridge_stats_init(now);
+ s = geoip_format_bridge_stats(now + 86400);
+ test_streq(bridge_stats_1, s);
+ tor_free(s);
+
+ /* Stop collecting bridge stats and make sure we don't write a history
+ * string anymore. */
+ geoip_bridge_stats_term();
+ s = geoip_format_bridge_stats(now + 86400);
+ test_assert(!s);
+
+ /* Stop being a bridge and start being a directory mirror that gathers
+ * directory request statistics. */
+ geoip_bridge_stats_term();
+ get_options_mutable()->BridgeRelay = 0;
+ get_options_mutable()->BridgeRecordUsageByCountry = 0;
+ get_options_mutable()->DirReqStatistics = 1;
+
+ /* Start testing dirreq statistics by making sure that we don't collect
+ * dirreq stats without initializing them. */
+ tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
+ s = geoip_format_dirreq_stats(now + 86400);
+ test_assert(!s);
+
+ /* Initialize stats, note one connecting client, and generate the
+ * dirreq-stats history string. */
+ geoip_dirreq_stats_init(now);
+ tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
+ s = geoip_format_dirreq_stats(now + 86400);
+ test_streq(dirreq_stats_1, s);
+ tor_free(s);
+
+ /* Stop collecting stats, add another connecting client, and ensure we
+ * don't generate a history string. */
+ geoip_dirreq_stats_term();
+ tor_addr_from_ipv4h(&addr, (uint32_t) 101);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
+ s = geoip_format_dirreq_stats(now + 86400);
+ test_assert(!s);
+
+ /* Re-start stats, add a connecting client, reset stats, and make sure
+ * that we get an all empty history string. */
+ geoip_dirreq_stats_init(now);
+ tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
+ geoip_reset_dirreq_stats(now);
+ s = geoip_format_dirreq_stats(now + 86400);
+ test_streq(dirreq_stats_2, s);
+ tor_free(s);
+
+ /* Note a successful network status response and make sure that it
+ * appears in the history string. */
+ geoip_note_ns_response(GEOIP_CLIENT_NETWORKSTATUS, GEOIP_SUCCESS);
+ s = geoip_format_dirreq_stats(now + 86400);
+ test_streq(dirreq_stats_3, s);
+ tor_free(s);
+
+ /* Start a tunneled directory request. */
+ geoip_start_dirreq((uint64_t) 1, 1024, GEOIP_CLIENT_NETWORKSTATUS,
+ DIRREQ_TUNNELED);
+ s = geoip_format_dirreq_stats(now + 86400);
+ test_streq(dirreq_stats_4, s);
+
+ /* Stop collecting directory request statistics and start gathering
+ * entry stats. */
+ geoip_dirreq_stats_term();
+ get_options_mutable()->DirReqStatistics = 0;
+ get_options_mutable()->EntryStatistics = 1;
+
+ /* Start testing entry statistics by making sure that we don't collect
+ * anything without initializing entry stats. */
+ tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
+ s = geoip_format_entry_stats(now + 86400);
+ test_assert(!s);
+
+ /* Initialize stats, note one connecting client, and generate the
+ * entry-stats history string. */
+ geoip_entry_stats_init(now);
+ tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
+ s = geoip_format_entry_stats(now + 86400);
+ test_streq(entry_stats_1, s);
+ tor_free(s);
+
+ /* Stop collecting stats, add another connecting client, and ensure we
+ * don't generate a history string. */
+ geoip_entry_stats_term();
+ tor_addr_from_ipv4h(&addr, (uint32_t) 101);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
+ s = geoip_format_entry_stats(now + 86400);
+ test_assert(!s);
+
+ /* Re-start stats, add a connecting client, reset stats, and make sure
+ * that we get an all empty history string. */
+ geoip_entry_stats_init(now);
+ tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
+ geoip_reset_entry_stats(now);
+ s = geoip_format_entry_stats(now + 86400);
+ test_streq(entry_stats_2, s);
+ tor_free(s);
+
+ /* Stop collecting entry statistics. */
+ geoip_entry_stats_term();
+ get_options_mutable()->EntryStatistics = 0;
+
done:
tor_free(s);
}
@@ -1089,7 +1639,8 @@ test_stats(void)
char *s = NULL;
int i;
- /* We shouldn't collect exit stats without initializing them. */
+ /* Start with testing exit port statistics; we shouldn't collect exit
+ * stats without initializing them. */
rep_hist_note_exit_stream_opened(80);
rep_hist_note_exit_bytes(80, 100, 10000);
s = rep_hist_format_exit_stats(now + 86400);
@@ -1134,7 +1685,7 @@ test_stats(void)
test_assert(!s);
/* Re-start stats, add some bytes, reset stats, and see what history we
- * get when observing no streams or bytes at all. */
+ * get when observing no streams or bytes at all. */
rep_hist_exit_stats_init(now);
rep_hist_note_exit_stream_opened(80);
rep_hist_note_exit_bytes(80, 100, 10000);
@@ -1144,6 +1695,96 @@ test_stats(void)
"exit-kibibytes-written other=0\n"
"exit-kibibytes-read other=0\n"
"exit-streams-opened other=0\n", s);
+ tor_free(s);
+
+ /* Continue with testing connection statistics; we shouldn't collect
+ * conn stats without initializing them. */
+ rep_hist_note_or_conn_bytes(1, 20, 400, now);
+ s = rep_hist_format_conn_stats(now + 86400);
+ test_assert(!s);
+
+ /* Initialize stats, note bytes, and generate history string. */
+ rep_hist_conn_stats_init(now);
+ rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
+ rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
+ rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
+ rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
+ s = rep_hist_format_conn_stats(now + 86400);
+ test_streq("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n", s);
+ tor_free(s);
+
+ /* Stop collecting stats, add some bytes, and ensure we don't generate
+ * a history string. */
+ rep_hist_conn_stats_term();
+ rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
+ s = rep_hist_format_conn_stats(now + 86400);
+ test_assert(!s);
+
+ /* Re-start stats, add some bytes, reset stats, and see what history we
+ * get when observing no bytes at all. */
+ rep_hist_conn_stats_init(now);
+ rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
+ rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
+ rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
+ rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
+ rep_hist_reset_conn_stats(now);
+ s = rep_hist_format_conn_stats(now + 86400);
+ test_streq("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n", s);
+ tor_free(s);
+
+ /* Continue with testing buffer statistics; we shouldn't collect buffer
+ * stats without initializing them. */
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ test_assert(!s);
+
+ /* Initialize stats, add statistics for a single circuit, and generate
+ * the history string. */
+ rep_hist_buffer_stats_init(now);
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "cell-processed-cells 20,0,0,0,0,0,0,0,0,0\n"
+ "cell-queued-cells 2.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
+ "0.00,0.00\n"
+ "cell-time-in-queue 2,0,0,0,0,0,0,0,0,0\n"
+ "cell-circuits-per-decile 1\n", s);
+ tor_free(s);
+
+ /* Add nineteen more circuit statistics to the one that's already in the
+ * history to see that the math works correctly. */
+ for (i = 21; i < 30; i++)
+ rep_hist_add_buffer_stats(2.0, 2.0, i);
+ for (i = 20; i < 30; i++)
+ rep_hist_add_buffer_stats(3.5, 3.5, i);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "cell-processed-cells 29,28,27,26,25,24,23,22,21,20\n"
+ "cell-queued-cells 2.75,2.75,2.75,2.75,2.75,2.75,2.75,2.75,"
+ "2.75,2.75\n"
+ "cell-time-in-queue 3,3,3,3,3,3,3,3,3,3\n"
+ "cell-circuits-per-decile 2\n", s);
+ tor_free(s);
+
+ /* Stop collecting stats, add statistics for one circuit, and ensure we
+ * don't generate a history string. */
+ rep_hist_buffer_stats_term();
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ test_assert(!s);
+
+ /* Re-start stats, add statistics for one circuit, reset stats, and make
+ * sure that the history has all zeros. */
+ rep_hist_buffer_stats_init(now);
+ rep_hist_add_buffer_stats(2.0, 2.0, 20);
+ rep_hist_reset_buffer_stats(now);
+ s = rep_hist_format_buffer_stats(now + 86400);
+ test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ "cell-processed-cells 0,0,0,0,0,0,0,0,0,0\n"
+ "cell-queued-cells 0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
+ "0.00,0.00\n"
+ "cell-time-in-queue 0,0,0,0,0,0,0,0,0,0\n"
+ "cell-circuits-per-decile 0\n", s);
done:
tor_free(s);
@@ -1180,12 +1821,13 @@ const struct testcase_setup_t legacy_setup = {
{ #group "_" #name, legacy_test_helper, 0, &legacy_setup, \
test_ ## group ## _ ## name }
#define DISABLED(name) \
- { #name, legacy_test_helper, TT_SKIP, &legacy_setup, name }
+ { #name, legacy_test_helper, TT_SKIP, &legacy_setup, test_ ## name }
#define FORK(name) \
{ #name, legacy_test_helper, TT_FORK, &legacy_setup, test_ ## name }
static struct testcase_t test_array[] = {
ENT(buffers),
+ { "buffer_copy", test_buffer_copy, 0, NULL, NULL },
ENT(onion_handshake),
ENT(circuit_timeout),
ENT(policies),
@@ -1193,8 +1835,23 @@ static struct testcase_t test_array[] = {
ENT(geoip),
FORK(stats),
- DISABLED(bench_aes),
- DISABLED(bench_dmap),
+ END_OF_TESTCASES
+};
+
+#define SOCKSENT(name) \
+ { #name, test_socks_##name, TT_FORK, &socks_setup, NULL }
+
+static struct testcase_t socks_tests[] = {
+ SOCKSENT(4_unsupported_commands),
+ SOCKSENT(4_supported_commands),
+
+ SOCKSENT(5_unsupported_commands),
+ SOCKSENT(5_supported_commands),
+ SOCKSENT(5_no_authenticate),
+ SOCKSENT(5_auth_before_negotiation),
+ SOCKSENT(5_authenticate),
+ SOCKSENT(5_authenticate_with_data),
+
END_OF_TESTCASES
};
@@ -1203,14 +1860,21 @@ extern struct testcase_t crypto_tests[];
extern struct testcase_t container_tests[];
extern struct testcase_t util_tests[];
extern struct testcase_t dir_tests[];
+extern struct testcase_t microdesc_tests[];
+extern struct testcase_t pt_tests[];
+extern struct testcase_t config_tests[];
static struct testgroup_t testgroups[] = {
{ "", test_array },
+ { "socks/", socks_tests },
{ "addr/", addr_tests },
{ "crypto/", crypto_tests },
{ "container/", container_tests },
{ "util/", util_tests },
{ "dir/", dir_tests },
+ { "dir/md/", microdesc_tests },
+ { "pt/", pt_tests },
+ { "config/", config_tests },
END_OF_GROUPS
};
@@ -1259,7 +1923,11 @@ main(int c, const char **v)
}
options->command = CMD_RUN_UNITTESTS;
- crypto_global_init(0, NULL, NULL);
+ if (crypto_global_init(0, NULL, NULL)) {
+ printf("Can't initialize crypto subsystem; exiting.\n");
+ return 1;
+ }
+ crypto_set_tls_dh_prime(NULL);
rep_hist_init();
network_init();
setup_directory();
diff --git a/src/test/test.h b/src/test/test.h
index f7ae46ce6d..0b6e6c60cb 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef _TOR_TEST_H
@@ -34,18 +34,18 @@
#define test_neq_ptr(expr1, expr2) tt_ptr_op((expr1), !=, (expr2))
#define test_streq(expr1, expr2) tt_str_op((expr1), ==, (expr2))
#define test_strneq(expr1, expr2) tt_str_op((expr1), !=, (expr2))
-#define test_streq(expr1, expr2) tt_str_op((expr1), ==, (expr2))
#define test_mem_op(expr1, op, expr2, len) \
tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2, \
const char *, \
- (memcmp(_val1, _val2, len) op 0), \
+ (memcmp(val1_, val2_, len) op 0), \
char *, "%s", \
{ size_t printlen = (len)*2+1; \
- _print = tor_malloc(printlen); \
- base16_encode(_print, printlen, _value, \
+ print_ = tor_malloc(printlen); \
+ base16_encode(print_, printlen, value_, \
(len)); }, \
- { tor_free(_print); } \
+ { tor_free(print_); }, \
+ TT_EXIT_TEST_FUNCTION \
);
#define test_memeq(expr1, expr2, len) test_mem_op((expr1), ==, (expr2), len)
@@ -66,7 +66,7 @@
#define test_memeq_hex(expr1, hex) test_mem_op_hex(expr1, ==, hex)
const char *get_fname(const char *name);
-crypto_pk_env_t *pk_generate(int idx);
+crypto_pk_t *pk_generate(int idx);
void legacy_test_helper(void *data);
extern const struct testcase_setup_t legacy_setup;
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 1dab0e0112..9007a23c5c 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -14,30 +14,30 @@ test_addr_basic(void)
uint16_t u16;
char *cp;
- /* Test parse_addr_port */
+ /* Test addr_port_lookup */
cp = NULL; u32 = 3; u16 = 3;
- test_assert(!parse_addr_port(LOG_WARN, "1.2.3.4", &cp, &u32, &u16));
+ test_assert(!addr_port_lookup(LOG_WARN, "1.2.3.4", &cp, &u32, &u16));
test_streq(cp, "1.2.3.4");
test_eq(u32, 0x01020304u);
test_eq(u16, 0);
tor_free(cp);
- test_assert(!parse_addr_port(LOG_WARN, "4.3.2.1:99", &cp, &u32, &u16));
+ test_assert(!addr_port_lookup(LOG_WARN, "4.3.2.1:99", &cp, &u32, &u16));
test_streq(cp, "4.3.2.1");
test_eq(u32, 0x04030201u);
test_eq(u16, 99);
tor_free(cp);
- test_assert(!parse_addr_port(LOG_WARN, "nonexistent.address:4040",
+ test_assert(!addr_port_lookup(LOG_WARN, "nonexistent.address:4040",
&cp, NULL, &u16));
test_streq(cp, "nonexistent.address");
test_eq(u16, 4040);
tor_free(cp);
- test_assert(!parse_addr_port(LOG_WARN, "localhost:9999", &cp, &u32, &u16));
+ test_assert(!addr_port_lookup(LOG_WARN, "localhost:9999", &cp, &u32, &u16));
test_streq(cp, "localhost");
test_eq(u32, 0x7f000001u);
test_eq(u16, 9999);
tor_free(cp);
u32 = 3;
- test_assert(!parse_addr_port(LOG_WARN, "localhost", NULL, &u32, &u16));
+ test_assert(!addr_port_lookup(LOG_WARN, "localhost", NULL, &u32, &u16));
test_eq(cp, NULL);
test_eq(u32, 0x7f000001u);
test_eq(u16, 0);
@@ -53,9 +53,17 @@ test_addr_basic(void)
char tmpbuf[TOR_ADDR_BUF_LEN];
const char *ip = "176.192.208.224";
struct in_addr in;
- tor_inet_pton(AF_INET, ip, &in);
- tor_inet_ntop(AF_INET, &in, tmpbuf, sizeof(tmpbuf));
+
+ /* good round trip */
+ test_eq(tor_inet_pton(AF_INET, ip, &in), 1);
+ test_eq_ptr(tor_inet_ntop(AF_INET, &in, tmpbuf, sizeof(tmpbuf)), &tmpbuf);
test_streq(tmpbuf, ip);
+
+ /* just enough buffer length */
+ test_streq(tor_inet_ntop(AF_INET, &in, tmpbuf, strlen(ip) + 1), ip);
+
+ /* too short buffer */
+ test_eq_ptr(tor_inet_ntop(AF_INET, &in, tmpbuf, strlen(ip)), NULL);
}
done:
@@ -65,16 +73,18 @@ test_addr_basic(void)
#define _test_op_ip6(a,op,b,e1,e2) \
STMT_BEGIN \
tt_assert_test_fmt_type(a,b,e1" "#op" "e2,struct in6_addr*, \
- (memcmp(_val1->s6_addr, _val2->s6_addr, 16) op 0), \
+ (memcmp(val1_->s6_addr, val2_->s6_addr, 16) op 0), \
char *, "%s", \
{ int i; char *cp; \
- cp = _print = tor_malloc(64); \
+ cp = print_ = tor_malloc(64); \
for (i=0;i<16;++i) { \
- tor_snprintf(cp, 3,"%02x", (unsigned)_value->s6_addr[i]);\
+ tor_snprintf(cp, 3,"%02x", (unsigned)value_->s6_addr[i]);\
cp += 2; \
if (i != 15) *cp++ = ':'; \
} \
- }, { tor_free(_print); } \
+ }, \
+ { tor_free(print_); }, \
+ TT_EXIT_TEST_FUNCTION \
); \
STMT_END
@@ -165,6 +175,7 @@ static void
test_addr_ip6_helpers(void)
{
char buf[TOR_ADDR_BUF_LEN], bug[TOR_ADDR_BUF_LEN];
+ char rbuf[REVERSE_LOOKUP_NAME_BUF_LEN];
struct in6_addr a1, a2;
tor_addr_t t1, t2;
int r, i;
@@ -175,8 +186,30 @@ test_addr_ip6_helpers(void)
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
- // struct in_addr b1, b2;
/* Test tor_inet_ntop and tor_inet_pton: IPv6 */
+ {
+ const char *ip = "2001::1234";
+ const char *ip_ffff = "::ffff:192.168.1.2";
+
+ /* good round trip */
+ test_eq(tor_inet_pton(AF_INET6, ip, &a1), 1);
+ test_eq_ptr(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), &buf);
+ test_streq(buf, ip);
+
+ /* good round trip - ::ffff:0:0 style */
+ test_eq(tor_inet_pton(AF_INET6, ip_ffff, &a2), 1);
+ test_eq_ptr(tor_inet_ntop(AF_INET6, &a2, buf, sizeof(buf)), &buf);
+ test_streq(buf, ip_ffff);
+
+ /* just long enough buffer (remember \0) */
+ test_streq(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)+1), ip);
+ test_streq(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)+1),
+ ip_ffff);
+
+ /* too short buffer (remember \0) */
+ test_eq_ptr(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)), NULL);
+ test_eq_ptr(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)), NULL);
+ }
/* ==== Converting to and from sockaddr_t. */
sin = (struct sockaddr_in *)&sa_storage;
@@ -268,12 +301,23 @@ test_addr_ip6_helpers(void)
test_ntop6_reduces("1000:0001:0000:0007:0000:0000:0000:0000",
"1000:1:0:7::");
+ /* Bad af param */
+ test_eq(tor_inet_pton(AF_UNSPEC, 0, 0), -1);
+
/* === Test pton: invalid in6. */
test_pton6_bad("foobar.");
+ test_pton6_bad("-1::");
+ test_pton6_bad("00001::");
+ test_pton6_bad("10000::");
+ test_pton6_bad("::10000");
test_pton6_bad("55555::");
test_pton6_bad("9:-60::");
+ test_pton6_bad("9:+60::");
+ test_pton6_bad("9|60::");
+ test_pton6_bad("0x60::");
+ test_pton6_bad("::0x60");
+ test_pton6_bad("9:0x60::");
test_pton6_bad("1:2:33333:4:0002:3::");
- //test_pton6_bad("1:2:3333:4:00002:3::");// BAD, but glibc doesn't say so.
test_pton6_bad("1:2:3333:4:fish:3::");
test_pton6_bad("1:2:3:4:5:6:7:8:9");
test_pton6_bad("1:2:3:4:5:6:7");
@@ -281,8 +325,14 @@ test_addr_ip6_helpers(void)
test_pton6_bad("1:2:3:4:5:6:1.2.3");
test_pton6_bad("::1.2.3");
test_pton6_bad("::1.2.3.4.5");
+ test_pton6_bad("::ffff:0xff.0.0.0");
+ test_pton6_bad("::ffff:ff.0.0.0");
+ test_pton6_bad("::ffff:256.0.0.0");
+ test_pton6_bad("::ffff:-1.0.0.0");
test_pton6_bad("99");
test_pton6_bad("");
+ test_pton6_bad(".");
+ test_pton6_bad(":");
test_pton6_bad("1::2::3:4");
test_pton6_bad("a:::b:c");
test_pton6_bad(":::a:b:c");
@@ -291,6 +341,9 @@ test_addr_ip6_helpers(void)
/* test internal checking */
test_external_ip("fbff:ffff::2:7", 0);
test_internal_ip("fc01::2:7", 0);
+ test_internal_ip("fc01::02:7", 0);
+ test_internal_ip("fc01::002:7", 0);
+ test_internal_ip("fc01::0002:7", 0);
test_internal_ip("fdff:ffff::f:f", 0);
test_external_ip("fe00::3:f", 0);
@@ -361,33 +414,67 @@ test_addr_ip6_helpers(void)
test_addr_compare_masked("0::2:2:1", <, "0::8000:2:1", 81);
test_addr_compare_masked("0::2:2:1", ==, "0::8000:2:1", 80);
- /* Test decorated addr_to_string. */
- test_eq(AF_INET6, tor_addr_from_str(&t1, "[123:45:6789::5005:11]"));
+ /* Test undecorated tor_addr_to_str */
+ test_eq(AF_INET6, tor_addr_parse(&t1, "[123:45:6789::5005:11]"));
+ p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
+ test_streq(p1, "123:45:6789::5005:11");
+ test_eq(AF_INET, tor_addr_parse(&t1, "18.0.0.1"));
+ p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
+ test_streq(p1, "18.0.0.1");
+
+ /* Test decorated tor_addr_to_str */
+ test_eq(AF_INET6, tor_addr_parse(&t1, "[123:45:6789::5005:11]"));
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
test_streq(p1, "[123:45:6789::5005:11]");
- test_eq(AF_INET, tor_addr_from_str(&t1, "18.0.0.1"));
+ test_eq(AF_INET, tor_addr_parse(&t1, "18.0.0.1"));
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
test_streq(p1, "18.0.0.1");
- /* Test tor_addr_parse_reverse_lookup_name */
- i = tor_addr_parse_reverse_lookup_name(&t1, "Foobar.baz", AF_UNSPEC, 0);
+ /* Test buffer bounds checking of tor_addr_to_str */
+ test_eq(AF_INET6, tor_addr_parse(&t1, "::")); /* 2 + \0 */
+ test_eq_ptr(tor_addr_to_str(buf, &t1, 2, 0), NULL); /* too short buf */
+ test_streq(tor_addr_to_str(buf, &t1, 3, 0), "::");
+ test_eq_ptr(tor_addr_to_str(buf, &t1, 4, 1), NULL); /* too short buf */
+ test_streq(tor_addr_to_str(buf, &t1, 5, 1), "[::]");
+
+ test_eq(AF_INET6, tor_addr_parse(&t1, "2000::1337")); /* 10 + \0 */
+ test_eq_ptr(tor_addr_to_str(buf, &t1, 10, 0), NULL); /* too short buf */
+ test_streq(tor_addr_to_str(buf, &t1, 11, 0), "2000::1337");
+ test_eq_ptr(tor_addr_to_str(buf, &t1, 12, 1), NULL); /* too short buf */
+ test_streq(tor_addr_to_str(buf, &t1, 13, 1), "[2000::1337]");
+
+ test_eq(AF_INET, tor_addr_parse(&t1, "1.2.3.4")); /* 7 + \0 */
+ test_eq_ptr(tor_addr_to_str(buf, &t1, 7, 0), NULL); /* too short buf */
+ test_streq(tor_addr_to_str(buf, &t1, 8, 0), "1.2.3.4");
+
+ test_eq(AF_INET, tor_addr_parse(&t1, "255.255.255.255")); /* 15 + \0 */
+ test_eq_ptr(tor_addr_to_str(buf, &t1, 15, 0), NULL); /* too short buf */
+ test_streq(tor_addr_to_str(buf, &t1, 16, 0), "255.255.255.255");
+ test_eq_ptr(tor_addr_to_str(buf, &t1, 15, 1), NULL); /* too short buf */
+ test_streq(tor_addr_to_str(buf, &t1, 16, 1), "255.255.255.255");
+
+ t1.family = AF_UNSPEC;
+ test_eq_ptr(tor_addr_to_str(buf, &t1, sizeof(buf), 0), NULL);
+
+ /* Test tor_addr_parse_PTR_name */
+ i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 0);
test_eq(0, i);
- i = tor_addr_parse_reverse_lookup_name(&t1, "Foobar.baz", AF_UNSPEC, 1);
+ i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 1);
test_eq(0, i);
- i = tor_addr_parse_reverse_lookup_name(&t1, "1.0.168.192.in-addr.arpa",
+ i = tor_addr_parse_PTR_name(&t1, "1.0.168.192.in-addr.arpa",
AF_UNSPEC, 1);
test_eq(1, i);
test_eq(tor_addr_family(&t1), AF_INET);
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
test_streq(p1, "192.168.0.1");
- i = tor_addr_parse_reverse_lookup_name(&t1, "192.168.0.99", AF_UNSPEC, 0);
+ i = tor_addr_parse_PTR_name(&t1, "192.168.0.99", AF_UNSPEC, 0);
test_eq(0, i);
- i = tor_addr_parse_reverse_lookup_name(&t1, "192.168.0.99", AF_UNSPEC, 1);
+ i = tor_addr_parse_PTR_name(&t1, "192.168.0.99", AF_UNSPEC, 1);
test_eq(1, i);
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
test_streq(p1, "192.168.0.99");
memset(&t1, 0, sizeof(t1));
- i = tor_addr_parse_reverse_lookup_name(&t1,
+ i = tor_addr_parse_PTR_name(&t1,
"0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
@@ -396,43 +483,91 @@ test_addr_ip6_helpers(void)
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
test_streq(p1, "[9dee:effe:ebe1:beef:fedc:ba98:7654:3210]");
/* Failing cases. */
- i = tor_addr_parse_reverse_lookup_name(&t1,
+ i = tor_addr_parse_PTR_name(&t1,
"6.7.8.9.a.b.c.d.e.f."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_UNSPEC, 0);
test_eq(i, -1);
- i = tor_addr_parse_reverse_lookup_name(&t1,
+ i = tor_addr_parse_PTR_name(&t1,
"6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.f.0."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_UNSPEC, 0);
test_eq(i, -1);
- i = tor_addr_parse_reverse_lookup_name(&t1,
+ i = tor_addr_parse_PTR_name(&t1,
"6.7.8.9.a.b.c.d.e.f.X.0.0.0.0.9."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_UNSPEC, 0);
test_eq(i, -1);
- i = tor_addr_parse_reverse_lookup_name(&t1, "32.1.1.in-addr.arpa",
+ i = tor_addr_parse_PTR_name(&t1, "32.1.1.in-addr.arpa",
AF_UNSPEC, 0);
test_eq(i, -1);
- i = tor_addr_parse_reverse_lookup_name(&t1, ".in-addr.arpa",
+ i = tor_addr_parse_PTR_name(&t1, ".in-addr.arpa",
AF_UNSPEC, 0);
test_eq(i, -1);
- i = tor_addr_parse_reverse_lookup_name(&t1, "1.2.3.4.5.in-addr.arpa",
+ i = tor_addr_parse_PTR_name(&t1, "1.2.3.4.5.in-addr.arpa",
AF_UNSPEC, 0);
test_eq(i, -1);
- i = tor_addr_parse_reverse_lookup_name(&t1, "1.2.3.4.5.in-addr.arpa",
+ i = tor_addr_parse_PTR_name(&t1, "1.2.3.4.5.in-addr.arpa",
AF_INET6, 0);
test_eq(i, -1);
- i = tor_addr_parse_reverse_lookup_name(&t1,
+ i = tor_addr_parse_PTR_name(&t1,
"6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.0."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_INET, 0);
test_eq(i, -1);
+ /* === Test tor_addr_to_PTR_name */
+
+ /* Stage IPv4 addr */
+ memset(&sa_storage, 0, sizeof(sa_storage));
+ sin = (struct sockaddr_in *)&sa_storage;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = htonl(0x7f010203); /* 127.1.2.3 */
+ tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, NULL);
+
+ /* Check IPv4 PTR - too short buffer */
+ test_eq(tor_addr_to_PTR_name(rbuf, 1, &t1), -1);
+ test_eq(tor_addr_to_PTR_name(rbuf,
+ strlen("3.2.1.127.in-addr.arpa") - 1,
+ &t1), -1);
+
+ /* Check IPv4 PTR - valid addr */
+ test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),
+ strlen("3.2.1.127.in-addr.arpa"));
+ test_streq(rbuf, "3.2.1.127.in-addr.arpa");
+
+ /* Invalid addr family */
+ t1.family = AF_UNSPEC;
+ test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1), -1);
+
+ /* Stage IPv6 addr */
+ memset(&sa_storage, 0, sizeof(sa_storage));
+ sin6 = (struct sockaddr_in6 *)&sa_storage;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_addr.s6_addr[0] = 0x80; /* 8000::abcd */
+ sin6->sin6_addr.s6_addr[14] = 0xab;
+ sin6->sin6_addr.s6_addr[15] = 0xcd;
+
+ tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, NULL);
+
+ {
+ const char* addr_PTR = "d.c.b.a.0.0.0.0.0.0.0.0.0.0.0.0."
+ "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.ip6.arpa";
+
+ /* Check IPv6 PTR - too short buffer */
+ test_eq(tor_addr_to_PTR_name(rbuf, 0, &t1), -1);
+ test_eq(tor_addr_to_PTR_name(rbuf, strlen(addr_PTR) - 1, &t1), -1);
+
+ /* Check IPv6 PTR - valid addr */
+ test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),
+ strlen(addr_PTR));
+ test_streq(rbuf, addr_PTR);
+ }
+
/* test tor_addr_parse_mask_ports */
test_addr_mask_ports_parse("[::f]/17:47-95", AF_INET6,
0, 0, 0, 0x0000000f, 17, 47, 95);
@@ -478,12 +613,11 @@ test_addr_ip6_helpers(void)
/* get interface addresses */
r = get_interface_address6(LOG_DEBUG, AF_INET, &t1);
i = get_interface_address6(LOG_DEBUG, AF_INET6, &t2);
-#if 0
- tor_inet_ntop(AF_INET, &t1.sa.sin_addr, buf, sizeof(buf));
- printf("\nv4 address: %s (family=%d)", buf, IN_FAMILY(&t1));
- tor_inet_ntop(AF_INET6, &t2.sa6.sin6_addr, buf, sizeof(buf));
- printf("\nv6 address: %s (family=%d)", buf, IN_FAMILY(&t2));
-#endif
+
+ TT_BLATHER(("v4 address: %s (family=%d)", fmt_addr(&t1),
+ tor_addr_family(&t1)));
+ TT_BLATHER(("v6 address: %s (family=%d)", fmt_addr(&t2),
+ tor_addr_family(&t2)));
done:
;
diff --git a/src/test/test_config.c b/src/test/test_config.c
new file mode 100644
index 0000000000..ff251a24d8
--- /dev/null
+++ b/src/test/test_config.c
@@ -0,0 +1,170 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "or.h"
+#include "config.h"
+#include "connection_edge.h"
+#include "test.h"
+
+static void
+test_config_addressmap(void *arg)
+{
+ char buf[1024];
+ char address[256];
+ time_t expires = TIME_MAX;
+ (void)arg;
+
+ strlcpy(buf, "MapAddress .invalidwildcard.com *.torserver.exit\n" // invalid
+ "MapAddress *invalidasterisk.com *.torserver.exit\n" // invalid
+ "MapAddress *.google.com *.torserver.exit\n"
+ "MapAddress *.yahoo.com *.google.com.torserver.exit\n"
+ "MapAddress *.cn.com www.cnn.com\n"
+ "MapAddress *.cnn.com www.cnn.com\n"
+ "MapAddress ex.com www.cnn.com\n"
+ "MapAddress ey.com *.cnn.com\n"
+ "MapAddress www.torproject.org 1.1.1.1\n"
+ "MapAddress other.torproject.org "
+ "this.torproject.org.otherserver.exit\n"
+ "MapAddress test.torproject.org 2.2.2.2\n"
+ "MapAddress www.google.com 3.3.3.3\n"
+ "MapAddress www.example.org 4.4.4.4\n"
+ "MapAddress 4.4.4.4 7.7.7.7\n"
+ "MapAddress 4.4.4.4 5.5.5.5\n"
+ "MapAddress www.infiniteloop.org 6.6.6.6\n"
+ "MapAddress 6.6.6.6 www.infiniteloop.org\n"
+ , sizeof(buf));
+
+ config_get_lines(buf, &(get_options_mutable()->AddressMap), 0);
+ config_register_addressmaps(get_options());
+
+ /* MapAddress .invalidwildcard.com .torserver.exit - no match */
+ strlcpy(address, "www.invalidwildcard.com", sizeof(address));
+ test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+
+ /* MapAddress *invalidasterisk.com .torserver.exit - no match */
+ strlcpy(address, "www.invalidasterisk.com", sizeof(address));
+ test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+
+ /* Where no mapping for FQDN match on top-level domain */
+ /* MapAddress .google.com .torserver.exit */
+ strlcpy(address, "reader.google.com", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "reader.torserver.exit");
+
+ /* MapAddress *.yahoo.com *.google.com.torserver.exit */
+ strlcpy(address, "reader.yahoo.com", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "reader.google.com.torserver.exit");
+
+ /*MapAddress *.cnn.com www.cnn.com */
+ strlcpy(address, "cnn.com", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "www.cnn.com");
+
+ /* MapAddress .cn.com www.cnn.com */
+ strlcpy(address, "www.cn.com", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "www.cnn.com");
+
+ /* MapAddress ex.com www.cnn.com - no match */
+ strlcpy(address, "www.ex.com", sizeof(address));
+ test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+
+ /* MapAddress ey.com *.cnn.com - invalid expression */
+ strlcpy(address, "ey.com", sizeof(address));
+ test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+
+ /* Where mapping for FQDN match on FQDN */
+ strlcpy(address, "www.google.com", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "3.3.3.3");
+
+ strlcpy(address, "www.torproject.org", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "1.1.1.1");
+
+ strlcpy(address, "other.torproject.org", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "this.torproject.org.otherserver.exit");
+
+ strlcpy(address, "test.torproject.org", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "2.2.2.2");
+
+ /* Test a chain of address mappings and the order in which they were added:
+ "MapAddress www.example.org 4.4.4.4"
+ "MapAddress 4.4.4.4 7.7.7.7"
+ "MapAddress 4.4.4.4 5.5.5.5"
+ */
+ strlcpy(address, "www.example.org", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "5.5.5.5");
+
+ /* Test infinite address mapping results in no change */
+ strlcpy(address, "www.infiniteloop.org", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "www.infiniteloop.org");
+
+ /* Test we don't find false positives */
+ strlcpy(address, "www.example.com", sizeof(address));
+ test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+
+ /* Test top-level-domain matching a bit harder */
+ addressmap_clear_configured();
+ strlcpy(buf, "MapAddress *.com *.torserver.exit\n"
+ "MapAddress *.torproject.org 1.1.1.1\n"
+ "MapAddress *.net 2.2.2.2\n"
+ , sizeof(buf));
+ config_get_lines(buf, &(get_options_mutable()->AddressMap), 0);
+ config_register_addressmaps(get_options());
+
+ strlcpy(address, "www.abc.com", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "www.abc.torserver.exit");
+
+ strlcpy(address, "www.def.com", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "www.def.torserver.exit");
+
+ strlcpy(address, "www.torproject.org", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "1.1.1.1");
+
+ strlcpy(address, "test.torproject.org", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "1.1.1.1");
+
+ strlcpy(address, "torproject.net", sizeof(address));
+ test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ test_streq(address, "2.2.2.2");
+
+ /* We don't support '*' as a mapping directive */
+ addressmap_clear_configured();
+ strlcpy(buf, "MapAddress * *.torserver.exit\n", sizeof(buf));
+ config_get_lines(buf, &(get_options_mutable()->AddressMap), 0);
+ config_register_addressmaps(get_options());
+
+ strlcpy(address, "www.abc.com", sizeof(address));
+ test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+
+ strlcpy(address, "www.def.net", sizeof(address));
+ test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+
+ strlcpy(address, "www.torproject.org", sizeof(address));
+ test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+
+ done:
+ ;
+}
+
+#define CONFIG_TEST(name, flags) \
+ { #name, test_config_ ## name, flags, NULL, NULL }
+
+struct testcase_t config_tests[] = {
+ CONFIG_TEST(addressmap, 0),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index af9fb1c5c9..615c489f41 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -34,7 +34,7 @@ test_container_smartlist_basic(void)
/* XXXX test sort_digests, uniq_strings, uniq_digests */
/* Test smartlist add, del_keeporder, insert, get. */
- sl = smartlist_create();
+ sl = smartlist_new();
smartlist_add(sl, (void*)1);
smartlist_add(sl, (void*)2);
smartlist_add(sl, (void*)3);
@@ -68,7 +68,7 @@ test_container_smartlist_basic(void)
static void
test_container_smartlist_strings(void)
{
- smartlist_t *sl = smartlist_create();
+ smartlist_t *sl = smartlist_new();
char *cp=NULL, *cp_alloc=NULL;
size_t sz;
@@ -298,11 +298,11 @@ test_container_smartlist_strings(void)
static void
test_container_smartlist_overlap(void)
{
- smartlist_t *sl = smartlist_create();
- smartlist_t *ints = smartlist_create();
- smartlist_t *odds = smartlist_create();
- smartlist_t *evens = smartlist_create();
- smartlist_t *primes = smartlist_create();
+ smartlist_t *sl = smartlist_new();
+ smartlist_t *ints = smartlist_new();
+ smartlist_t *odds = smartlist_new();
+ smartlist_t *evens = smartlist_new();
+ smartlist_t *primes = smartlist_new();
int i;
for (i=1; i < 10; i += 2)
smartlist_add(odds, (void*)(uintptr_t)i);
@@ -351,7 +351,7 @@ test_container_smartlist_overlap(void)
static void
test_container_smartlist_digests(void)
{
- smartlist_t *sl = smartlist_create();
+ smartlist_t *sl = smartlist_new();
/* digest_isin. */
smartlist_add(sl, tor_memdup("AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN));
@@ -384,9 +384,9 @@ test_container_smartlist_digests(void)
static void
test_container_smartlist_join(void)
{
- smartlist_t *sl = smartlist_create();
- smartlist_t *sl2 = smartlist_create(), *sl3 = smartlist_create(),
- *sl4 = smartlist_create();
+ smartlist_t *sl = smartlist_new();
+ smartlist_t *sl2 = smartlist_new(), *sl3 = smartlist_new(),
+ *sl4 = smartlist_new();
char *joined=NULL;
/* unique, sorted. */
smartlist_split_string(sl,
@@ -479,7 +479,7 @@ test_container_bitarray(void)
static void
test_container_digestset(void)
{
- smartlist_t *included = smartlist_create();
+ smartlist_t *included = smartlist_new();
char d[DIGEST_LEN];
int i;
int ok = 1;
@@ -532,7 +532,7 @@ _compare_strings_for_pqueue(const void *p1, const void *p2)
static void
test_container_pqueue(void)
{
- smartlist_t *sl = smartlist_create();
+ smartlist_t *sl = smartlist_new();
int (*cmp)(const void *, const void*);
const int offset = STRUCT_OFFSET(pq_entry_t, idx);
#define ENTRY(s) pq_entry_t s = { #s, -1 }
@@ -669,7 +669,7 @@ test_container_strmap(void)
/* Test iterator. */
iter = strmap_iter_init(map);
- found_keys = smartlist_create();
+ found_keys = smartlist_new();
while (!strmap_iter_done(iter)) {
strmap_iter_get(iter,&k,&v);
smartlist_add(found_keys, tor_strdup(k));
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 85a4e929a4..7f4347a41c 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -1,19 +1,20 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define CRYPTO_PRIVATE
#include "or.h"
#include "test.h"
+#include "aes.h"
/** Run unit tests for Diffie-Hellman functionality. */
static void
test_crypto_dh(void)
{
- crypto_dh_env_t *dh1 = crypto_dh_new(DH_TYPE_CIRCUIT);
- crypto_dh_env_t *dh2 = crypto_dh_new(DH_TYPE_CIRCUIT);
+ crypto_dh_t *dh1 = crypto_dh_new(DH_TYPE_CIRCUIT);
+ crypto_dh_t *dh2 = crypto_dh_new(DH_TYPE_CIRCUIT);
char p1[DH_BYTES];
char p2[DH_BYTES];
char s1[DH_BYTES];
@@ -95,13 +96,17 @@ test_crypto_rng(void)
/** Run unit tests for our AES functionality */
static void
-test_crypto_aes(void)
+test_crypto_aes(void *arg)
{
char *data1 = NULL, *data2 = NULL, *data3 = NULL;
- crypto_cipher_env_t *env1 = NULL, *env2 = NULL;
+ crypto_cipher_t *env1 = NULL, *env2 = NULL;
int i, j;
char *mem_op_hex_tmp=NULL;
+ int use_evp = !strcmp(arg,"evp");
+ evaluate_evp_for_aes(use_evp);
+ evaluate_ctr_for_aes();
+
data1 = tor_malloc(1024);
data2 = tor_malloc(1024);
data3 = tor_malloc(1024);
@@ -113,14 +118,10 @@ test_crypto_aes(void)
memset(data2, 0, 1024);
memset(data3, 0, 1024);
- env1 = crypto_new_cipher_env();
+ env1 = crypto_cipher_new(NULL);
test_neq(env1, 0);
- env2 = crypto_new_cipher_env();
+ env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
test_neq(env2, 0);
- j = crypto_cipher_generate_key(env1);
- crypto_cipher_set_key(env2, crypto_cipher_get_key(env1));
- crypto_cipher_encrypt_init_cipher(env1);
- crypto_cipher_decrypt_init_cipher(env2);
/* Try encrypting 512 chars. */
crypto_cipher_encrypt(env1, data2, data1, 512);
@@ -146,14 +147,12 @@ test_crypto_aes(void)
test_memeq(data1, data3, 1024-5);
/* Now make sure that when we encrypt with different chunk sizes, we get
the same results. */
- crypto_free_cipher_env(env2);
+ crypto_cipher_free(env2);
env2 = NULL;
memset(data3, 0, 1024);
- env2 = crypto_new_cipher_env();
+ env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
test_neq(env2, 0);
- crypto_cipher_set_key(env2, crypto_cipher_get_key(env1));
- crypto_cipher_encrypt_init_cipher(env2);
for (j = 0; j < 1024-16; j += 17) {
crypto_cipher_encrypt(env2, data3+j, data1+j, 17);
}
@@ -163,16 +162,15 @@ test_crypto_aes(void)
}
}
test_memeq(data2, data3, 1024-16);
- crypto_free_cipher_env(env1);
+ crypto_cipher_free(env1);
env1 = NULL;
- crypto_free_cipher_env(env2);
+ crypto_cipher_free(env2);
env2 = NULL;
/* NIST test vector for aes. */
- env1 = crypto_new_cipher_env(); /* IV starts at 0 */
- crypto_cipher_set_key(env1, "\x80\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00");
- crypto_cipher_encrypt_init_cipher(env1);
+ /* IV starts at 0 */
+ env1 = crypto_cipher_new("\x80\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00");
crypto_cipher_encrypt(env1, data1,
"\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00", 16);
@@ -180,46 +178,64 @@ test_crypto_aes(void)
/* Now test rollover. All these values are originally from a python
* script. */
- crypto_cipher_set_iv(env1, "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\xff\xff\xff\xff\xff\xff\xff\xff");
+ crypto_cipher_free(env1);
+ env1 = crypto_cipher_new_with_iv(
+ "\x80\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xff\xff\xff\xff\xff\xff\xff\xff");
memset(data2, 0, 1024);
crypto_cipher_encrypt(env1, data1, data2, 32);
test_memeq_hex(data1, "335fe6da56f843199066c14a00a40231"
"cdd0b917dbc7186908a6bfb5ffd574d3");
-
- crypto_cipher_set_iv(env1, "\x00\x00\x00\x00\xff\xff\xff\xff"
- "\xff\xff\xff\xff\xff\xff\xff\xff");
+ crypto_cipher_free(env1);
+ env1 = crypto_cipher_new_with_iv(
+ "\x80\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x00\x00\x00\x00\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff");
memset(data2, 0, 1024);
crypto_cipher_encrypt(env1, data1, data2, 32);
test_memeq_hex(data1, "e627c6423fa2d77832a02b2794094b73"
"3e63c721df790d2c6469cc1953a3ffac");
-
- crypto_cipher_set_iv(env1, "\xff\xff\xff\xff\xff\xff\xff\xff"
- "\xff\xff\xff\xff\xff\xff\xff\xff");
+ crypto_cipher_free(env1);
+ env1 = crypto_cipher_new_with_iv(
+ "\x80\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff");
memset(data2, 0, 1024);
crypto_cipher_encrypt(env1, data1, data2, 32);
test_memeq_hex(data1, "2aed2bff0de54f9328efd070bf48f70a"
"0EDD33D3C621E546455BD8BA1418BEC8");
/* Now check rollover on inplace cipher. */
- crypto_cipher_set_iv(env1, "\xff\xff\xff\xff\xff\xff\xff\xff"
- "\xff\xff\xff\xff\xff\xff\xff\xff");
+ crypto_cipher_free(env1);
+ env1 = crypto_cipher_new_with_iv(
+ "\x80\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff");
crypto_cipher_crypt_inplace(env1, data2, 64);
test_memeq_hex(data2, "2aed2bff0de54f9328efd070bf48f70a"
"0EDD33D3C621E546455BD8BA1418BEC8"
"93e2c5243d6839eac58503919192f7ae"
"1908e67cafa08d508816659c2e693191");
- crypto_cipher_set_iv(env1, "\xff\xff\xff\xff\xff\xff\xff\xff"
- "\xff\xff\xff\xff\xff\xff\xff\xff");
+ crypto_cipher_free(env1);
+ env1 = crypto_cipher_new_with_iv(
+ "\x80\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff");
crypto_cipher_crypt_inplace(env1, data2, 64);
test_assert(tor_mem_is_zero(data2, 64));
done:
tor_free(mem_op_hex_tmp);
if (env1)
- crypto_free_cipher_env(env1);
+ crypto_cipher_free(env1);
if (env2)
- crypto_free_cipher_env(env2);
+ crypto_cipher_free(env2);
tor_free(data1);
tor_free(data2);
tor_free(data3);
@@ -229,7 +245,7 @@ test_crypto_aes(void)
static void
test_crypto_sha(void)
{
- crypto_digest_env_t *d1 = NULL, *d2 = NULL;
+ crypto_digest_t *d1 = NULL, *d2 = NULL;
int i;
char key[160];
char digest[32];
@@ -346,7 +362,7 @@ test_crypto_sha(void)
"bfdc63644f0713938a7f51535c3a35e2");
/* Incremental digest code. */
- d1 = crypto_new_digest_env();
+ d1 = crypto_digest_new();
test_assert(d1);
crypto_digest_add_bytes(d1, "abcdef", 6);
d2 = crypto_digest_dup(d1);
@@ -363,11 +379,11 @@ test_crypto_sha(void)
crypto_digest_get_digest(d1, d_out1, sizeof(d_out1));
crypto_digest(d_out2, "abcdef", 6);
test_memeq(d_out1, d_out2, DIGEST_LEN);
- crypto_free_digest_env(d1);
- crypto_free_digest_env(d2);
+ crypto_digest_free(d1);
+ crypto_digest_free(d2);
/* Incremental digest code with sha256 */
- d1 = crypto_new_digest256_env(DIGEST_SHA256);
+ d1 = crypto_digest256_new(DIGEST_SHA256);
test_assert(d1);
crypto_digest_add_bytes(d1, "abcdef", 6);
d2 = crypto_digest_dup(d1);
@@ -387,9 +403,9 @@ test_crypto_sha(void)
done:
if (d1)
- crypto_free_digest_env(d1);
+ crypto_digest_free(d1);
if (d2)
- crypto_free_digest_env(d2);
+ crypto_digest_free(d2);
tor_free(mem_op_hex_tmp);
}
@@ -397,7 +413,7 @@ test_crypto_sha(void)
static void
test_crypto_pk(void)
{
- crypto_pk_env_t *pk1 = NULL, *pk2 = NULL;
+ crypto_pk_t *pk1 = NULL, *pk2 = NULL;
char *encoded = NULL;
char data1[1024], data2[1024], data3[1024];
size_t size;
@@ -405,7 +421,7 @@ test_crypto_pk(void)
/* Public-key ciphers */
pk1 = pk_generate(0);
- pk2 = crypto_new_pk_env();
+ pk2 = crypto_pk_new();
test_assert(pk1 && pk2);
test_assert(! crypto_pk_write_public_key_to_string(pk1, &encoded, &size));
test_assert(! crypto_pk_read_public_key_from_string(pk2, encoded, size));
@@ -471,7 +487,7 @@ test_crypto_pk(void)
/*XXXX test failed signing*/
/* Try encoding */
- crypto_free_pk_env(pk2);
+ crypto_pk_free(pk2);
pk2 = NULL;
i = crypto_pk_asn1_encode(pk1, data1, 1024);
test_assert(i>0);
@@ -480,14 +496,11 @@ test_crypto_pk(void)
/* Try with hybrid encryption wrappers. */
crypto_rand(data1, 1024);
- for (i = 0; i < 3; ++i) {
+ for (i = 0; i < 2; ++i) {
for (j = 85; j < 140; ++j) {
memset(data2,0,1024);
memset(data3,0,1024);
- if (i == 0 && j < 129)
- continue;
- p = (i==0)?PK_NO_PADDING:
- (i==1)?PK_PKCS1_PADDING:PK_PKCS1_OAEP_PADDING;
+ p = (i==0)?PK_PKCS1_PADDING:PK_PKCS1_OAEP_PADDING;
len = crypto_pk_public_hybrid_encrypt(pk1,data2,sizeof(data2),
data1,j,p,0);
test_assert(len>=0);
@@ -499,7 +512,7 @@ test_crypto_pk(void)
}
/* Try copy_full */
- crypto_free_pk_env(pk2);
+ crypto_pk_free(pk2);
pk2 = crypto_pk_copy_full(pk1);
test_assert(pk2 != NULL);
test_neq_ptr(pk1, pk2);
@@ -507,9 +520,9 @@ test_crypto_pk(void)
done:
if (pk1)
- crypto_free_pk_env(pk1);
+ crypto_pk_free(pk1);
if (pk2)
- crypto_free_pk_env(pk2);
+ crypto_pk_free(pk2);
tor_free(encoded);
}
@@ -670,14 +683,16 @@ test_crypto_s2k(void)
/** Test AES-CTR encryption and decryption with IV. */
static void
-test_crypto_aes_iv(void)
+test_crypto_aes_iv(void *arg)
{
- crypto_cipher_env_t *cipher;
char *plain, *encrypted1, *encrypted2, *decrypted1, *decrypted2;
char plain_1[1], plain_15[15], plain_16[16], plain_17[17];
char key1[16], key2[16];
ssize_t encrypted_size, decrypted_size;
+ int use_evp = !strcmp(arg,"evp");
+ evaluate_evp_for_aes(use_evp);
+
plain = tor_malloc(4095);
encrypted1 = tor_malloc(4095 + 1 + 16);
encrypted2 = tor_malloc(4095 + 1 + 16);
@@ -693,116 +708,79 @@ test_crypto_aes_iv(void)
crypto_rand(plain_17, 17);
key1[0] = key2[0] + 128; /* Make sure that contents are different. */
/* Encrypt and decrypt with the same key. */
- cipher = crypto_create_init_cipher(key1, 1);
- encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 4095,
+ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 4095,
plain, 4095);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
+
test_eq(encrypted_size, 16 + 4095);
- tor_assert(encrypted_size > 0); /* This is obviously true, since 4111 is
+ tt_assert(encrypted_size > 0); /* This is obviously true, since 4111 is
* greater than 0, but its truth is not
* obvious to all analysis tools. */
- cipher = crypto_create_init_cipher(key1, 0);
- decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 4095,
+ decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095,
encrypted1, encrypted_size);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
+
test_eq(decrypted_size, 4095);
- tor_assert(decrypted_size > 0);
+ tt_assert(decrypted_size > 0);
test_memeq(plain, decrypted1, 4095);
/* Encrypt a second time (with a new random initialization vector). */
- cipher = crypto_create_init_cipher(key1, 1);
- encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted2, 16 + 4095,
+ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted2, 16 + 4095,
plain, 4095);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
+
test_eq(encrypted_size, 16 + 4095);
- tor_assert(encrypted_size > 0);
- cipher = crypto_create_init_cipher(key1, 0);
- decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted2, 4095,
+ tt_assert(encrypted_size > 0);
+ decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted2, 4095,
encrypted2, encrypted_size);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
test_eq(decrypted_size, 4095);
- tor_assert(decrypted_size > 0);
+ tt_assert(decrypted_size > 0);
test_memeq(plain, decrypted2, 4095);
test_memneq(encrypted1, encrypted2, encrypted_size);
/* Decrypt with the wrong key. */
- cipher = crypto_create_init_cipher(key2, 0);
- decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted2, 4095,
+ decrypted_size = crypto_cipher_decrypt_with_iv(key2, decrypted2, 4095,
encrypted1, encrypted_size);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
test_memneq(plain, decrypted2, encrypted_size);
/* Alter the initialization vector. */
encrypted1[0] += 42;
- cipher = crypto_create_init_cipher(key1, 0);
- decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 4095,
+ decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095,
encrypted1, encrypted_size);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
test_memneq(plain, decrypted2, 4095);
/* Special length case: 1. */
- cipher = crypto_create_init_cipher(key1, 1);
- encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 1,
+ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 1,
plain_1, 1);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
test_eq(encrypted_size, 16 + 1);
- tor_assert(encrypted_size > 0);
- cipher = crypto_create_init_cipher(key1, 0);
- decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 1,
+ tt_assert(encrypted_size > 0);
+ decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 1,
encrypted1, encrypted_size);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
test_eq(decrypted_size, 1);
- tor_assert(decrypted_size > 0);
+ tt_assert(decrypted_size > 0);
test_memeq(plain_1, decrypted1, 1);
/* Special length case: 15. */
- cipher = crypto_create_init_cipher(key1, 1);
- encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 15,
+ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 15,
plain_15, 15);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
test_eq(encrypted_size, 16 + 15);
- tor_assert(encrypted_size > 0);
- cipher = crypto_create_init_cipher(key1, 0);
- decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 15,
+ tt_assert(encrypted_size > 0);
+ decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 15,
encrypted1, encrypted_size);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
test_eq(decrypted_size, 15);
- tor_assert(decrypted_size > 0);
+ tt_assert(decrypted_size > 0);
test_memeq(plain_15, decrypted1, 15);
/* Special length case: 16. */
- cipher = crypto_create_init_cipher(key1, 1);
- encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 16,
+ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 16,
plain_16, 16);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
test_eq(encrypted_size, 16 + 16);
- tor_assert(encrypted_size > 0);
- cipher = crypto_create_init_cipher(key1, 0);
- decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 16,
+ tt_assert(encrypted_size > 0);
+ decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 16,
encrypted1, encrypted_size);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
test_eq(decrypted_size, 16);
- tor_assert(decrypted_size > 0);
+ tt_assert(decrypted_size > 0);
test_memeq(plain_16, decrypted1, 16);
/* Special length case: 17. */
- cipher = crypto_create_init_cipher(key1, 1);
- encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 17,
+ encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 17,
plain_17, 17);
- crypto_free_cipher_env(cipher);
- cipher = NULL;
test_eq(encrypted_size, 16 + 17);
- tor_assert(encrypted_size > 0);
- cipher = crypto_create_init_cipher(key1, 0);
- decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 17,
+ tt_assert(encrypted_size > 0);
+ decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 17,
encrypted1, encrypted_size);
test_eq(decrypted_size, 17);
- tor_assert(decrypted_size > 0);
+ tt_assert(decrypted_size > 0);
test_memeq(plain_17, decrypted1, 17);
done:
@@ -812,8 +790,6 @@ test_crypto_aes_iv(void)
tor_free(encrypted2);
tor_free(decrypted1);
tor_free(decrypted2);
- if (cipher)
- crypto_free_cipher_env(cipher);
}
/** Test base32 decoding. */
@@ -851,18 +827,36 @@ test_crypto_base32_decode(void)
;
}
+static void *
+pass_data_setup_fn(const struct testcase_t *testcase)
+{
+ return testcase->setup_data;
+}
+static int
+pass_data_cleanup_fn(const struct testcase_t *testcase, void *ptr)
+{
+ (void)ptr;
+ (void)testcase;
+ return 1;
+}
+static const struct testcase_setup_t pass_data = {
+ pass_data_setup_fn, pass_data_cleanup_fn
+};
+
#define CRYPTO_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_crypto_ ## name }
struct testcase_t crypto_tests[] = {
CRYPTO_LEGACY(formats),
CRYPTO_LEGACY(rng),
- CRYPTO_LEGACY(aes),
+ { "aes_AES", test_crypto_aes, TT_FORK, &pass_data, (void*)"aes" },
+ { "aes_EVP", test_crypto_aes, TT_FORK, &pass_data, (void*)"evp" },
CRYPTO_LEGACY(sha),
CRYPTO_LEGACY(pk),
CRYPTO_LEGACY(dh),
CRYPTO_LEGACY(s2k),
- CRYPTO_LEGACY(aes_iv),
+ { "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" },
+ { "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"evp" },
CRYPTO_LEGACY(base32_decode),
END_OF_TESTCASES
};
diff --git a/src/test/test_data.c b/src/test/test_data.c
index fc85857615..de2f9f58eb 100644
--- a/src/test/test_data.c
+++ b/src/test/test_data.c
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** First of 3 example authority certificates for unit testing. */
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 873d761a99..83c612045b 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -1,16 +1,18 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define DIRSERV_PRIVATE
#define DIRVOTE_PRIVATE
#define ROUTER_PRIVATE
+#define HIBERNATE_PRIVATE
#include "or.h"
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
+#include "hibernate.h"
#include "networkstatus.h"
#include "router.h"
#include "routerlist.h"
@@ -74,7 +76,7 @@ test_dir_formats(void)
char *pk1_str = NULL, *pk2_str = NULL, *pk3_str = NULL, *cp;
size_t pk1_str_len, pk2_str_len, pk3_str_len;
routerinfo_t *r1=NULL, *r2=NULL;
- crypto_pk_env_t *pk1 = NULL, *pk2 = NULL, *pk3 = NULL;
+ crypto_pk_t *pk1 = NULL, *pk2 = NULL, *pk3 = NULL;
routerinfo_t *rp1 = NULL;
addr_policy_t *ex1, *ex2;
routerlist_t *dir1 = NULL, *dir2 = NULL;
@@ -85,6 +87,8 @@ test_dir_formats(void)
test_assert(pk1 && pk2 && pk3);
+ hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE);
+
get_platform_str(platform, sizeof(platform));
r1 = tor_malloc_zero(sizeof(routerinfo_t));
r1->address = tor_strdup("18.244.0.1");
@@ -92,6 +96,8 @@ test_dir_formats(void)
r1->cache_info.published_on = 0;
r1->or_port = 9000;
r1->dir_port = 9003;
+ tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::");
+ r1->ipv6_orport = 9999;
r1->onion_pkey = crypto_pk_dup_key(pk1);
r1->identity_pkey = crypto_pk_dup_key(pk2);
r1->bandwidthrate = 1000;
@@ -121,7 +127,7 @@ test_dir_formats(void)
r2->onion_pkey = crypto_pk_dup_key(pk2);
r2->identity_pkey = crypto_pk_dup_key(pk1);
r2->bandwidthrate = r2->bandwidthburst = r2->bandwidthcapacity = 3000;
- r2->exit_policy = smartlist_create();
+ r2->exit_policy = smartlist_new();
smartlist_add(r2->exit_policy, ex2);
smartlist_add(r2->exit_policy, ex1);
r2->nickname = tor_strdup("Fred");
@@ -137,6 +143,7 @@ test_dir_formats(void)
test_assert(router_dump_router_to_string(buf, 2048, r1, pk2)>0);
strlcpy(buf2, "router Magri 18.244.0.1 9000 0 9003\n"
+ "or-address [1:2:3:4::]:9999\n"
"platform Tor "VERSION" on ", sizeof(buf2));
strlcat(buf2, get_uname(), sizeof(buf2));
strlcat(buf2, "\n"
@@ -206,7 +213,7 @@ test_dir_formats(void)
/* Okay, now for the directories. */
{
- fingerprint_list = smartlist_create();
+ fingerprint_list = smartlist_new();
crypto_pk_get_fingerprint(pk2, buf, 1);
add_fingerprint_to_dir("Magri", buf, fingerprint_list);
crypto_pk_get_fingerprint(pk1, buf, 1);
@@ -243,9 +250,9 @@ test_dir_formats(void)
tor_free(pk1_str);
tor_free(pk2_str);
tor_free(pk3_str);
- if (pk1) crypto_free_pk_env(pk1);
- if (pk2) crypto_free_pk_env(pk2);
- if (pk3) crypto_free_pk_env(pk3);
+ if (pk1) crypto_pk_free(pk1);
+ if (pk2) crypto_pk_free(pk2);
+ if (pk3) crypto_pk_free(pk3);
if (rp1) routerinfo_free(rp1);
tor_free(dir1); /* XXXX And more !*/
tor_free(dir2); /* And more !*/
@@ -298,7 +305,7 @@ test_dir_versions(void)
#define tt_versionstatus_op(vs1, op, vs2) \
tt_assert_test_type(vs1,vs2,#vs1" "#op" "#vs2,version_status_t, \
- (_val1 op _val2),"%d")
+ (val1_ op val2_),"%d",TT_EXIT_TEST_FUNCTION)
#define test_v_i_o(val, ver, lst) \
tt_versionstatus_op(val, ==, tor_version_is_obsolete(ver, lst))
@@ -371,7 +378,7 @@ test_dir_versions(void)
static void
test_dir_fp_pairs(void)
{
- smartlist_t *sl = smartlist_create();
+ smartlist_t *sl = smartlist_new();
fp_pair_t *pair;
dir_split_resource_into_fingerprint_pairs(
@@ -399,7 +406,7 @@ test_dir_fp_pairs(void)
static void
test_dir_split_fps(void *testdata)
{
- smartlist_t *sl = smartlist_create();
+ smartlist_t *sl = smartlist_new();
char *mem_op_hex_tmp = NULL;
(void)testdata;
@@ -587,7 +594,7 @@ static void
test_dir_param_voting(void)
{
networkstatus_t vote1, vote2, vote3, vote4;
- smartlist_t *votes = smartlist_create();
+ smartlist_t *votes = smartlist_new();
char *res = NULL;
/* dirvote_compute_params only looks at the net_params field of the votes,
@@ -597,10 +604,10 @@ test_dir_param_voting(void)
memset(&vote2, 0, sizeof(vote2));
memset(&vote3, 0, sizeof(vote3));
memset(&vote4, 0, sizeof(vote4));
- vote1.net_params = smartlist_create();
- vote2.net_params = smartlist_create();
- vote3.net_params = smartlist_create();
- vote4.net_params = smartlist_create();
+ vote1.net_params = smartlist_new();
+ vote2.net_params = smartlist_new();
+ vote3.net_params = smartlist_new();
+ vote4.net_params = smartlist_new();
smartlist_split_string(vote1.net_params,
"ab=90 abcd=20 cw=50 x-yz=-99", NULL, 0, 0);
smartlist_split_string(vote2.net_params,
@@ -616,13 +623,81 @@ test_dir_param_voting(void)
test_eq(0, networkstatus_get_param(&vote4, "foobar", 0, -100, 8));
smartlist_add(votes, &vote1);
+
+ /* Do the first tests without adding all the other votes, for
+ * networks without many dirauths. */
+
+ res = dirvote_compute_params(votes, 11, 6);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-99");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 2);
+ test_streq(res, "");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 1);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-99");
+ tor_free(res);
+
smartlist_add(votes, &vote2);
+
+ res = dirvote_compute_params(votes, 11, 2);
+ test_streq(res, "ab=27 abcd=20 cw=5 x-yz=-99");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 2);
+ test_streq(res, "ab=27 cw=5 x-yz=-99");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 3);
+ test_streq(res, "ab=27 cw=5 x-yz=-99");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 6);
+ test_streq(res, "");
+ tor_free(res);
+
smartlist_add(votes, &vote3);
+
+ res = dirvote_compute_params(votes, 11, 3);
+ test_streq(res, "ab=27 abcd=20 c=60 cw=50 x-yz=-9 zzzzz=101");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 3);
+ test_streq(res, "ab=27 abcd=20 cw=50 x-yz=-9");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 5);
+ test_streq(res, "cw=50 x-yz=-9");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 9);
+ test_streq(res, "cw=50 x-yz=-9");
+ tor_free(res);
+
smartlist_add(votes, &vote4);
- res = dirvote_compute_params(votes);
- test_streq(res,
- "ab=90 abcd=20 c=1 cw=50 x-yz=-9 zzzzz=101");
+ res = dirvote_compute_params(votes, 11, 4);
+ test_streq(res, "ab=90 abcd=20 c=1 cw=50 x-yz=-9 zzzzz=101");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 4);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 5);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tor_free(res);
+
+ /* Test that the special-cased "at least three dirauths voted for
+ * this param" logic works as expected. */
+ res = dirvote_compute_params(votes, 12, 6);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 10);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tor_free(res);
done:
tor_free(res);
@@ -684,7 +759,7 @@ generate_ri_from_rs(const vote_routerstatus_t *vrs)
tor_strdup("123456789012345678901234567890123");
r->cache_info.signed_descriptor_len =
strlen(r->cache_info.signed_descriptor_body);
- r->exit_policy = smartlist_create();
+ r->exit_policy = smartlist_new();
r->cache_info.published_on = ++published + time(NULL);
return r;
}
@@ -697,7 +772,7 @@ get_detached_sigs(networkstatus_t *ns, networkstatus_t *ns2)
char *r;
smartlist_t *sl;
tor_assert(ns && ns->flavor == FLAV_NS);
- sl = smartlist_create();
+ sl = smartlist_new();
smartlist_add(sl,ns);
if (ns2)
smartlist_add(sl,ns2);
@@ -712,8 +787,8 @@ static void
test_dir_v3_networkstatus(void)
{
authority_cert_t *cert1=NULL, *cert2=NULL, *cert3=NULL;
- crypto_pk_env_t *sign_skey_1=NULL, *sign_skey_2=NULL, *sign_skey_3=NULL;
- crypto_pk_env_t *sign_skey_leg1=NULL;
+ crypto_pk_t *sign_skey_1=NULL, *sign_skey_2=NULL, *sign_skey_3=NULL;
+ crypto_pk_t *sign_skey_leg1=NULL;
const char *msg=NULL;
time_t now = time(NULL);
@@ -724,7 +799,7 @@ test_dir_v3_networkstatus(void)
vote_routerstatus_t *vrs;
routerstatus_t *rs;
char *v1_text=NULL, *v2_text=NULL, *v3_text=NULL, *consensus_text=NULL, *cp;
- smartlist_t *votes = smartlist_create();
+ smartlist_t *votes = smartlist_new();
/* For generating the two other consensuses. */
char *detached_text1=NULL, *detached_text2=NULL;
@@ -742,9 +817,9 @@ test_dir_v3_networkstatus(void)
test_assert(cert2);
cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3, NULL);
test_assert(cert3);
- sign_skey_1 = crypto_new_pk_env();
- sign_skey_2 = crypto_new_pk_env();
- sign_skey_3 = crypto_new_pk_env();
+ sign_skey_1 = crypto_pk_new();
+ sign_skey_2 = crypto_pk_new();
+ sign_skey_3 = crypto_pk_new();
sign_skey_leg1 = pk_generate(4);
test_assert(!crypto_pk_read_private_key_from_string(sign_skey_1,
@@ -768,15 +843,15 @@ test_dir_v3_networkstatus(void)
vote->valid_until = now+3000;
vote->vote_seconds = 100;
vote->dist_seconds = 200;
- vote->supported_methods = smartlist_create();
+ vote->supported_methods = smartlist_new();
smartlist_split_string(vote->supported_methods, "1 2 3", NULL, 0, -1);
vote->client_versions = tor_strdup("0.1.2.14,0.1.2.15");
vote->server_versions = tor_strdup("0.1.2.14,0.1.2.15,0.1.2.16");
- vote->known_flags = smartlist_create();
+ vote->known_flags = smartlist_new();
smartlist_split_string(vote->known_flags,
"Authority Exit Fast Guard Running Stable V2Dir Valid",
0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- vote->voters = smartlist_create();
+ vote->voters = smartlist_new();
voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
voter->nickname = tor_strdup("Voter1");
voter->address = tor_strdup("1.2.3.4");
@@ -787,10 +862,10 @@ test_dir_v3_networkstatus(void)
crypto_pk_get_digest(cert1->identity_key, voter->identity_digest);
smartlist_add(vote->voters, voter);
vote->cert = authority_cert_dup(cert1);
- vote->net_params = smartlist_create();
+ vote->net_params = smartlist_new();
smartlist_split_string(vote->net_params, "circuitwindow=101 foo=990",
NULL, 0, 0);
- vote->routerstatus_list = smartlist_create();
+ vote->routerstatus_list = smartlist_new();
/* add the first routerstatus. */
vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
rs = &vrs->status;
@@ -803,7 +878,7 @@ test_dir_v3_networkstatus(void)
rs->or_port = 443;
rs->dir_port = 8000;
/* all flags but running cleared */
- rs->is_running = 1;
+ rs->is_flagged_running = 1;
smartlist_add(vote->routerstatus_list, vrs);
test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
@@ -818,7 +893,7 @@ test_dir_v3_networkstatus(void)
rs->addr = 0x99009901;
rs->or_port = 443;
rs->dir_port = 0;
- rs->is_exit = rs->is_stable = rs->is_fast = rs->is_running =
+ rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running =
rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1;
smartlist_add(vote->routerstatus_list, vrs);
test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
@@ -835,7 +910,8 @@ test_dir_v3_networkstatus(void)
rs->or_port = 400;
rs->dir_port = 9999;
rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
- rs->is_running = rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1;
+ rs->is_flagged_running = rs->is_valid = rs->is_v2_dir =
+ rs->is_possible_guard = 1;
smartlist_add(vote->routerstatus_list, vrs);
test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
@@ -931,7 +1007,7 @@ test_dir_v3_networkstatus(void)
vote->dist_seconds = 300;
authority_cert_free(vote->cert);
vote->cert = authority_cert_dup(cert2);
- vote->net_params = smartlist_create();
+ vote->net_params = smartlist_new();
smartlist_split_string(vote->net_params, "bar=2000000000 circuitwindow=20",
NULL, 0, 0);
tor_free(vote->client_versions);
@@ -972,7 +1048,7 @@ test_dir_v3_networkstatus(void)
vote->dist_seconds = 250;
authority_cert_free(vote->cert);
vote->cert = authority_cert_dup(cert3);
- vote->net_params = smartlist_create();
+ vote->net_params = smartlist_new();
smartlist_split_string(vote->net_params, "circuitwindow=80 foo=660",
NULL, 0, 0);
smartlist_add(vote->supported_methods, tor_strdup("4"));
@@ -1044,7 +1120,7 @@ test_dir_v3_networkstatus(void)
"Running:Stable:V2Dir:Valid");
tor_free(cp);
cp = smartlist_join_strings(con->net_params, ":", 0, NULL);
- test_streq(cp, "bar=2000000000:circuitwindow=80:foo=660");
+ test_streq(cp, "circuitwindow=80:foo=660");
tor_free(cp);
test_eq(4, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/
@@ -1075,7 +1151,8 @@ test_dir_v3_networkstatus(void)
test_assert(!rs->is_fast);
test_assert(!rs->is_possible_guard);
test_assert(!rs->is_stable);
- test_assert(rs->is_running); /* If it wasn't running it wouldn't be here */
+ /* (If it wasn't running it wouldn't be here) */
+ test_assert(rs->is_flagged_running);
test_assert(!rs->is_v2_dir);
test_assert(!rs->is_valid);
test_assert(!rs->is_named);
@@ -1097,7 +1174,7 @@ test_dir_v3_networkstatus(void)
test_assert(rs->is_fast);
test_assert(rs->is_possible_guard);
test_assert(rs->is_stable);
- test_assert(rs->is_running);
+ test_assert(rs->is_flagged_running);
test_assert(rs->is_v2_dir);
test_assert(rs->is_valid);
test_assert(!rs->is_named);
@@ -1167,10 +1244,10 @@ test_dir_v3_networkstatus(void)
/* Extract a detached signature from con3. */
detached_text1 = get_detached_sigs(con3, con_md3);
- tor_assert(detached_text1);
+ tt_assert(detached_text1);
/* Try to parse it. */
dsig1 = networkstatus_parse_detached_signatures(detached_text1, NULL);
- tor_assert(dsig1);
+ tt_assert(dsig1);
/* Are parsed values as expected? */
test_eq(dsig1->valid_after, con3->valid_after);
@@ -1270,13 +1347,13 @@ test_dir_v3_networkstatus(void)
if (con_md)
networkstatus_vote_free(con_md);
if (sign_skey_1)
- crypto_free_pk_env(sign_skey_1);
+ crypto_pk_free(sign_skey_1);
if (sign_skey_2)
- crypto_free_pk_env(sign_skey_2);
+ crypto_pk_free(sign_skey_2);
if (sign_skey_3)
- crypto_free_pk_env(sign_skey_3);
+ crypto_pk_free(sign_skey_3);
if (sign_skey_leg1)
- crypto_free_pk_env(sign_skey_leg1);
+ crypto_pk_free(sign_skey_leg1);
if (cert1)
authority_cert_free(cert1);
if (cert2)
@@ -1305,7 +1382,7 @@ test_dir_v3_networkstatus(void)
}
#define DIR_LEGACY(name) \
- { #name, legacy_test_helper, 0, &legacy_setup, test_dir_ ## name }
+ { #name, legacy_test_helper, TT_FORK, &legacy_setup, test_dir_ ## name }
#define DIR(name) \
{ #name, test_dir_##name, 0, NULL, NULL }
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
new file mode 100644
index 0000000000..89c578f4a7
--- /dev/null
+++ b/src/test/test_microdesc.c
@@ -0,0 +1,233 @@
+/* Copyright (c) 2010-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "or.h"
+
+#include "config.h"
+#include "microdesc.h"
+
+#include "test.h"
+
+#ifdef _WIN32
+/* For mkdir() */
+#include <direct.h>
+#else
+#include <dirent.h>
+#endif
+
+static const char test_md1[] =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMjlHH/daN43cSVRaHBwgUfnszzAhg98EvivJ9Qxfv51mvQUxPjQ07es\n"
+ "gV/3n8fyh3Kqr/ehi9jxkdgSRfSnmF7giaHL1SLZ29kA7KtST+pBvmTpDtHa3ykX\n"
+ "Xorc7hJvIyTZoc1HU+5XSynj3gsBE5IGK1ZRzrNS688LnuZMVp1tAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n";
+
+static const char test_md2[] =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMIixIowh2DyPmDNMDwBX2DHcYcqdcH1zdIQJZkyV6c6rQHnvbcaDoSg\n"
+ "jgFSLJKpnGmh71FVRqep+yVB0zI1JY43kuEnXry2HbZCD9UDo3d3n7t015X5S7ON\n"
+ "bSSYtQGPwOr6Epf96IF6DoQxy4iDnPUAlejuhAG51s1y6/rZQ3zxAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n";
+
+static const char test_md3[] =
+ "@last-listed 2009-06-22\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMH3340d4ENNGrqx7UxT+lB7x6DNUKOdPEOn4teceE11xlMyZ9TPv41c\n"
+ "qj2fRZzfxlc88G/tmiaHshmdtEpklZ740OFqaaJVj4LjPMKFNE+J7Xc1142BE9Ci\n"
+ "KgsbjGYe2RY261aADRWLetJ8T9QDMm+JngL4288hc8pq1uB/3TAbAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "p accept 1-700,800-1000\n"
+ "family nodeX nodeY nodeZ\n";
+
+static void
+test_md_cache(void *data)
+{
+ or_options_t *options = NULL;
+ microdesc_cache_t *mc = NULL ;
+ smartlist_t *added = NULL, *wanted = NULL;
+ microdesc_t *md1, *md2, *md3;
+ char d1[DIGEST256_LEN], d2[DIGEST256_LEN], d3[DIGEST256_LEN];
+ const char *test_md3_noannotation = strchr(test_md3, '\n')+1;
+ time_t time1, time2, time3;
+ char *fn = NULL, *s = NULL;
+ (void)data;
+
+ options = get_options_mutable();
+ tt_assert(options);
+
+ time1 = time(NULL);
+ time2 = time(NULL) - 2*24*60*60;
+ time3 = time(NULL) - 15*24*60*60;
+
+ /* Possibly, turn this into a test setup/cleanup pair */
+ tor_free(options->DataDirectory);
+ options->DataDirectory = tor_strdup(get_fname("md_datadir_test"));
+#ifdef _WIN32
+ tt_int_op(0, ==, mkdir(options->DataDirectory));
+#else
+ tt_int_op(0, ==, mkdir(options->DataDirectory, 0700));
+#endif
+
+ tt_assert(!strcmpstart(test_md3_noannotation, "onion-key"));
+
+ crypto_digest256(d1, test_md1, strlen(test_md1), DIGEST_SHA256);
+ crypto_digest256(d2, test_md2, strlen(test_md1), DIGEST_SHA256);
+ crypto_digest256(d3, test_md3_noannotation, strlen(test_md3_noannotation),
+ DIGEST_SHA256);
+
+ mc = get_microdesc_cache();
+
+ added = microdescs_add_to_cache(mc, test_md1, NULL, SAVED_NOWHERE, 0,
+ time1, NULL);
+ tt_int_op(1, ==, smartlist_len(added));
+ md1 = smartlist_get(added, 0);
+ smartlist_free(added);
+ added = NULL;
+
+ wanted = smartlist_new();
+ added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0,
+ time2, wanted);
+ /* Should fail, since we didn't list test_md2's digest in wanted */
+ tt_int_op(0, ==, smartlist_len(added));
+ smartlist_free(added);
+ added = NULL;
+
+ smartlist_add(wanted, tor_memdup(d2, DIGEST256_LEN));
+ smartlist_add(wanted, tor_memdup(d3, DIGEST256_LEN));
+ added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0,
+ time2, wanted);
+ /* Now it can work. md2 should have been added */
+ tt_int_op(1, ==, smartlist_len(added));
+ md2 = smartlist_get(added, 0);
+ /* And it should have gotten removed from 'wanted' */
+ tt_int_op(smartlist_len(wanted), ==, 1);
+ test_mem_op(smartlist_get(wanted, 0), ==, d3, DIGEST256_LEN);
+ smartlist_free(added);
+ added = NULL;
+
+ added = microdescs_add_to_cache(mc, test_md3, NULL,
+ SAVED_NOWHERE, 0, -1, NULL);
+ /* Must fail, since SAVED_NOWHERE precludes annotations */
+ tt_int_op(0, ==, smartlist_len(added));
+ smartlist_free(added);
+ added = NULL;
+
+ added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL,
+ SAVED_NOWHERE, 0, time3, NULL);
+ /* Now it can work */
+ tt_int_op(1, ==, smartlist_len(added));
+ md3 = smartlist_get(added, 0);
+ smartlist_free(added);
+ added = NULL;
+
+ /* Okay. We added 1...3. Let's poke them to see how they look, and make
+ * sure they're really in the journal. */
+ tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
+ tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
+ tt_ptr_op(md3, ==, microdesc_cache_lookup_by_digest256(mc, d3));
+
+ tt_int_op(md1->last_listed, ==, time1);
+ tt_int_op(md2->last_listed, ==, time2);
+ tt_int_op(md3->last_listed, ==, time3);
+
+ tt_int_op(md1->saved_location, ==, SAVED_IN_JOURNAL);
+ tt_int_op(md2->saved_location, ==, SAVED_IN_JOURNAL);
+ tt_int_op(md3->saved_location, ==, SAVED_IN_JOURNAL);
+
+ tt_int_op(md1->bodylen, ==, strlen(test_md1));
+ tt_int_op(md2->bodylen, ==, strlen(test_md2));
+ tt_int_op(md3->bodylen, ==, strlen(test_md3_noannotation));
+ test_mem_op(md1->body, ==, test_md1, strlen(test_md1));
+ test_mem_op(md2->body, ==, test_md2, strlen(test_md2));
+ test_mem_op(md3->body, ==, test_md3_noannotation,
+ strlen(test_md3_noannotation));
+
+ tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs.new",
+ options->DataDirectory);
+ s = read_file_to_str(fn, RFTS_BIN, NULL);
+ tt_assert(s);
+ test_mem_op(md1->body, ==, s + md1->off, md1->bodylen);
+ test_mem_op(md2->body, ==, s + md2->off, md2->bodylen);
+ test_mem_op(md3->body, ==, s + md3->off, md3->bodylen);
+
+ tt_ptr_op(md1->family, ==, NULL);
+ tt_ptr_op(md3->family, !=, NULL);
+ tt_int_op(smartlist_len(md3->family), ==, 3);
+ tt_str_op(smartlist_get(md3->family, 0), ==, "nodeX");
+
+ /* Now rebuild the cache! */
+ tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);
+
+ tt_int_op(md1->saved_location, ==, SAVED_IN_CACHE);
+ tt_int_op(md2->saved_location, ==, SAVED_IN_CACHE);
+ tt_int_op(md3->saved_location, ==, SAVED_IN_CACHE);
+
+ /* The journal should be empty now */
+ tor_free(s);
+ s = read_file_to_str(fn, RFTS_BIN, NULL);
+ tt_str_op(s, ==, "");
+ tor_free(s);
+ tor_free(fn);
+
+ /* read the cache. */
+ tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
+ options->DataDirectory);
+ s = read_file_to_str(fn, RFTS_BIN, NULL);
+ test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1));
+ test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2));
+ test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation));
+
+ /* Okay, now we are going to forget about the cache entirely, and reload it
+ * from the disk. */
+ microdesc_free_all();
+ mc = get_microdesc_cache();
+ md1 = microdesc_cache_lookup_by_digest256(mc, d1);
+ md2 = microdesc_cache_lookup_by_digest256(mc, d2);
+ md3 = microdesc_cache_lookup_by_digest256(mc, d3);
+ test_assert(md1);
+ test_assert(md2);
+ test_assert(md3);
+ test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1));
+ test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2));
+ test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation));
+
+ tt_int_op(md1->last_listed, ==, time1);
+ tt_int_op(md2->last_listed, ==, time2);
+ tt_int_op(md3->last_listed, ==, time3);
+
+ /* Okay, now we are going to clear out everything older than a week old.
+ * In practice, that means md3 */
+ microdesc_cache_clean(mc, time(NULL)-7*24*60*60, 1/*force*/);
+ tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
+ tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
+ tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3));
+ md3 = NULL; /* it's history now! */
+
+ /* rebuild again, make sure it stays gone. */
+ microdesc_cache_rebuild(mc, 1);
+ tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
+ tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
+ tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3));
+
+ done:
+ if (options)
+ tor_free(options->DataDirectory);
+ microdesc_free_all();
+
+ smartlist_free(added);
+ if (wanted)
+ SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp));
+ smartlist_free(wanted);
+ tor_free(s);
+ tor_free(fn);
+}
+
+struct testcase_t microdesc_tests[] = {
+ { "cache", test_md_cache, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
new file mode 100644
index 0000000000..d3dadb9bfa
--- /dev/null
+++ b/src/test/test_pt.c
@@ -0,0 +1,143 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#define PT_PRIVATE
+#include "or.h"
+#include "transports.h"
+#include "circuitbuild.h"
+#include "test.h"
+
+static void
+reset_mp(managed_proxy_t *mp)
+{
+ mp->conf_state = PT_PROTO_LAUNCHED;
+ SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
+ smartlist_clear(mp->transports);
+}
+
+static void
+test_pt_parsing(void)
+{
+ char line[200];
+
+ managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t));
+ mp->conf_state = PT_PROTO_INFANT;
+ mp->transports = smartlist_new();
+
+ /* incomplete cmethod */
+ strcpy(line,"CMETHOD trebuchet");
+ test_assert(parse_cmethod_line(line, mp) < 0);
+
+ reset_mp(mp);
+
+ /* wrong proxy type */
+ strcpy(line,"CMETHOD trebuchet dog 127.0.0.1:1999");
+ test_assert(parse_cmethod_line(line, mp) < 0);
+
+ reset_mp(mp);
+
+ /* wrong addrport */
+ strcpy(line,"CMETHOD trebuchet socks4 abcd");
+ test_assert(parse_cmethod_line(line, mp) < 0);
+
+ reset_mp(mp);
+
+ /* correct line */
+ strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999");
+ test_assert(parse_cmethod_line(line, mp) == 0);
+ test_assert(smartlist_len(mp->transports));
+
+ reset_mp(mp);
+
+ /* incomplete smethod */
+ strcpy(line,"SMETHOD trebuchet");
+ test_assert(parse_smethod_line(line, mp) < 0);
+
+ reset_mp(mp);
+
+ /* wrong addr type */
+ strcpy(line,"SMETHOD trebuchet abcd");
+ test_assert(parse_smethod_line(line, mp) < 0);
+
+ reset_mp(mp);
+
+ /* cowwect */
+ strcpy(line,"SMETHOD trebuchy 127.0.0.1:1999");
+ test_assert(parse_smethod_line(line, mp) == 0);
+
+ reset_mp(mp);
+
+ /* unsupported version */
+ strcpy(line,"VERSION 666");
+ test_assert(parse_version(line, mp) < 0);
+
+ /* incomplete VERSION */
+ strcpy(line,"VERSION ");
+ test_assert(parse_version(line, mp) < 0);
+
+ /* correct VERSION */
+ strcpy(line,"VERSION 1");
+ test_assert(parse_version(line, mp) == 0);
+
+ done:
+ tor_free(mp);
+}
+
+static void
+test_pt_protocol(void)
+{
+ char line[200];
+
+ managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t));
+ mp->conf_state = PT_PROTO_LAUNCHED;
+ mp->transports = smartlist_new();
+ mp->argv = tor_malloc_zero(sizeof(char*)*2);
+ mp->argv[0] = tor_strdup("<testcase>");
+
+ /* various wrong protocol runs: */
+
+ strcpy(line,"VERSION 1");
+ handle_proxy_line(line, mp);
+ test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
+
+ strcpy(line,"VERSION 1");
+ handle_proxy_line(line, mp);
+ test_assert(mp->conf_state == PT_PROTO_BROKEN);
+
+ reset_mp(mp);
+
+ strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999");
+ handle_proxy_line(line, mp);
+ test_assert(mp->conf_state == PT_PROTO_BROKEN);
+
+ reset_mp(mp);
+
+ /* correct protocol run: */
+ strcpy(line,"VERSION 1");
+ handle_proxy_line(line, mp);
+ test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
+
+ strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999");
+ handle_proxy_line(line, mp);
+ test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
+
+ strcpy(line,"CMETHODS DONE");
+ handle_proxy_line(line, mp);
+ test_assert(mp->conf_state == PT_PROTO_CONFIGURED);
+
+ done:
+ tor_free(mp);
+}
+
+#define PT_LEGACY(name) \
+ { #name, legacy_test_helper, 0, &legacy_setup, test_pt_ ## name }
+
+struct testcase_t pt_tests[] = {
+ PT_LEGACY(parsing),
+ PT_LEGACY(protocol),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 12e3fa9793..4f9eb73e03 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1,11 +1,12 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define CONTROL_PRIVATE
#define MEMPOOL_PRIVATE
+#define UTIL_PRIVATE
#include "or.h"
#include "config.h"
#include "control.h"
@@ -13,6 +14,10 @@
#include "mempool.h"
#include "memarea.h"
+#ifdef _WIN32
+#include <tchar.h>
+#endif
+
/* XXXX this is a minimal wrapper to make the unit tests compile with the
* changed tor_timegm interface. */
static time_t
@@ -31,9 +36,12 @@ test_util_time(void)
{
struct timeval start, end;
struct tm a_time;
- char timestr[RFC1123_TIME_LEN+1];
+ char timestr[128];
time_t t_res;
int i;
+ struct timeval tv;
+
+ /* Test tv_udiff */
start.tv_sec = 5;
start.tv_usec = 5000;
@@ -59,9 +67,7 @@ test_util_time(void)
test_eq(-1005000L, tv_udiff(&start, &end));
- end.tv_usec = 999990;
- start.tv_sec = 1;
- start.tv_usec = 500;
+ /* Test tor_timegm */
/* The test values here are confirmed to be correct on a platform
* with a working timegm. */
@@ -77,6 +83,17 @@ test_util_time(void)
a_time.tm_mon = 1; /* Try a leap year, in feb. */
a_time.tm_mday = 10;
test_eq((time_t) 1076393695UL, tor_timegm(&a_time));
+ a_time.tm_mon = 0;
+ a_time.tm_mday = 10;
+ test_eq((time_t) 1073715295UL, tor_timegm(&a_time));
+ a_time.tm_mon = 12; /* Wrong month, it's 0-based */
+ a_time.tm_mday = 10;
+ test_eq((time_t) -1, tor_timegm(&a_time));
+ a_time.tm_mon = -1; /* Wrong month */
+ a_time.tm_mday = 10;
+ test_eq((time_t) -1, tor_timegm(&a_time));
+
+ /* Test {format,parse}_rfc1123_time */
format_rfc1123_time(timestr, 0);
test_streq("Thu, 01 Jan 1970 00:00:00 GMT", timestr);
@@ -85,9 +102,64 @@ test_util_time(void)
t_res = 0;
i = parse_rfc1123_time(timestr, &t_res);
- test_eq(i,0);
+ test_eq(0,i);
+ test_eq(t_res, (time_t)1091580502UL);
+ /* The timezone doesn't matter */
+ t_res = 0;
+ test_eq(0, parse_rfc1123_time("Wed, 04 Aug 2004 00:48:22 ZUL", &t_res));
test_eq(t_res, (time_t)1091580502UL);
test_eq(-1, parse_rfc1123_time("Wed, zz Aug 2004 99-99x99 GMT", &t_res));
+ test_eq(-1, parse_rfc1123_time("Wed, 32 Mar 2011 00:00:00 GMT", &t_res));
+ test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 24:00:00 GMT", &t_res));
+ test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:60:00 GMT", &t_res));
+ test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:59:62 GMT", &t_res));
+ test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 1969 23:59:59 GMT", &t_res));
+ test_eq(-1, parse_rfc1123_time("Wed, 30 Ene 2011 23:59:59 GMT", &t_res));
+ test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:59:59 GM", &t_res));
+
+#if 0
+ /* This fails, I imagine it's important and should be fixed? */
+ test_eq(-1, parse_rfc1123_time("Wed, 29 Feb 2011 16:00:00 GMT", &t_res));
+ /* Why is this string valid (ie. the test fails because it doesn't
+ return -1)? */
+ test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:59:61 GMT", &t_res));
+#endif
+
+ /* Test parse_iso_time */
+
+ t_res = 0;
+ i = parse_iso_time("", &t_res);
+ test_eq(-1, i);
+ t_res = 0;
+ i = parse_iso_time("2004-08-32 00:48:22", &t_res);
+ test_eq(-1, i);
+ t_res = 0;
+ i = parse_iso_time("1969-08-03 00:48:22", &t_res);
+ test_eq(-1, i);
+
+ t_res = 0;
+ i = parse_iso_time("2004-08-04 00:48:22", &t_res);
+ test_eq(0,i);
+ test_eq(t_res, (time_t)1091580502UL);
+ t_res = 0;
+ i = parse_iso_time("2004-8-4 0:48:22", &t_res);
+ test_eq(0, i);
+ test_eq(t_res, (time_t)1091580502UL);
+ test_eq(-1, parse_iso_time("2004-08-zz 99-99x99 GMT", &t_res));
+ test_eq(-1, parse_iso_time("2011-03-32 00:00:00 GMT", &t_res));
+ test_eq(-1, parse_iso_time("2011-03-30 24:00:00 GMT", &t_res));
+ test_eq(-1, parse_iso_time("2011-03-30 23:60:00 GMT", &t_res));
+ test_eq(-1, parse_iso_time("2011-03-30 23:59:62 GMT", &t_res));
+ test_eq(-1, parse_iso_time("1969-03-30 23:59:59 GMT", &t_res));
+ test_eq(-1, parse_iso_time("2011-00-30 23:59:59 GMT", &t_res));
+ test_eq(-1, parse_iso_time("2011-03-30 23:59", &t_res));
+
+ /* Test tor_gettimeofday */
+
+ end.tv_sec = 4;
+ end.tv_usec = 999990;
+ start.tv_sec = 1;
+ start.tv_usec = 500;
tor_gettimeofday(&start);
/* now make sure time works. */
@@ -95,6 +167,25 @@ test_util_time(void)
/* We might've timewarped a little. */
tt_int_op(tv_udiff(&start, &end), >=, -5000);
+ /* Test format_iso_time */
+
+ tv.tv_sec = (time_t)1326296338;
+ tv.tv_usec = 3060;
+ format_iso_time(timestr, tv.tv_sec);
+ test_streq("2012-01-11 15:38:58", timestr);
+ /* The output of format_local_iso_time will vary by timezone, and setting
+ our timezone for testing purposes would be a nontrivial flaky pain.
+ Skip this test for now.
+ format_local_iso_time(timestr, tv.tv_sec);
+ test_streq("2012-01-11 10:38:58", timestr);
+ */
+ format_iso_time_nospace(timestr, tv.tv_sec);
+ test_streq("2012-01-11T15:38:58", timestr);
+ test_eq(strlen(timestr), ISO_TIME_LEN);
+ format_iso_time_nospace_usec(timestr, &tv);
+ test_streq("2012-01-11T15:38:58.003060", timestr);
+ test_eq(strlen(timestr), ISO_TIME_USEC_LEN);
+
done:
;
}
@@ -306,6 +397,334 @@ test_util_config_line(void)
tor_free(v);
}
+static void
+test_util_config_line_quotes(void)
+{
+ char buf1[1024];
+ char buf2[128];
+ char buf3[128];
+ char buf4[128];
+ char *k=NULL, *v=NULL;
+ const char *str;
+
+ /* Test parse_config_line_from_str */
+ strlcpy(buf1, "kTrailingSpace \"quoted value\" \n"
+ "kTrailingGarbage \"quoted value\"trailing garbage\n"
+ , sizeof(buf1));
+ strlcpy(buf2, "kTrailingSpaceAndGarbage \"quoted value\" trailing space+g\n"
+ , sizeof(buf2));
+ strlcpy(buf3, "kMultilineTrailingSpace \"mline\\ \nvalue w/ trailing sp\"\n"
+ , sizeof(buf3));
+ strlcpy(buf4, "kMultilineNoTrailingBackslash \"naked multiline\nvalue\"\n"
+ , sizeof(buf4));
+ str = buf1;
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "kTrailingSpace");
+ test_streq(v, "quoted value");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_eq_ptr(str, NULL);
+ tor_free(k); tor_free(v);
+
+ str = buf2;
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_eq_ptr(str, NULL);
+ tor_free(k); tor_free(v);
+
+ str = buf3;
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_eq_ptr(str, NULL);
+ tor_free(k); tor_free(v);
+
+ str = buf4;
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_eq_ptr(str, NULL);
+ tor_free(k); tor_free(v);
+
+ done:
+ tor_free(k);
+ tor_free(v);
+}
+
+static void
+test_util_config_line_comment_character(void)
+{
+ char buf[1024];
+ char *k=NULL, *v=NULL;
+ const char *str;
+
+ /* Test parse_config_line_from_str */
+ strlcpy(buf, "k1 \"# in quotes\"\n"
+ "k2 some value # some comment\n"
+ "k3 /home/user/myTorNetwork#2\n" /* Testcase for #1323 */
+ , sizeof(buf));
+ str = buf;
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k1");
+ test_streq(v, "# in quotes");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k2");
+ test_streq(v, "some value");
+ tor_free(k); tor_free(v);
+
+ test_streq(str, "k3 /home/user/myTorNetwork#2\n");
+
+#if 0
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k3");
+ test_streq(v, "/home/user/myTorNetwork#2");
+ tor_free(k); tor_free(v);
+
+ test_streq(str, "");
+#endif
+
+ done:
+ tor_free(k);
+ tor_free(v);
+}
+
+static void
+test_util_config_line_escaped_content(void)
+{
+ char buf1[1024];
+ char buf2[128];
+ char buf3[128];
+ char buf4[128];
+ char buf5[128];
+ char buf6[128];
+ char *k=NULL, *v=NULL;
+ const char *str;
+
+ /* Test parse_config_line_from_str */
+ strlcpy(buf1, "HexadecimalLower \"\\x2a\"\n"
+ "HexadecimalUpper \"\\x2A\"\n"
+ "HexadecimalUpperX \"\\X2A\"\n"
+ "Octal \"\\52\"\n"
+ "Newline \"\\n\"\n"
+ "Tab \"\\t\"\n"
+ "CarriageReturn \"\\r\"\n"
+ "DoubleQuote \"\\\"\"\n"
+ "SimpleQuote \"\\'\"\n"
+ "Backslash \"\\\\\"\n"
+ "Mix \"This is a \\\"star\\\":\\t\\'\\x2a\\'\\nAnd second line\"\n"
+ , sizeof(buf1));
+
+ strlcpy(buf2, "BrokenEscapedContent \"\\a\"\n"
+ , sizeof(buf2));
+
+ strlcpy(buf3, "BrokenEscapedContent \"\\x\"\n"
+ , sizeof(buf3));
+
+ strlcpy(buf4, "BrokenOctal \"\\8\"\n"
+ , sizeof(buf4));
+
+ strlcpy(buf5, "BrokenHex \"\\xg4\"\n"
+ , sizeof(buf5));
+
+ strlcpy(buf6, "BrokenEscape \"\\"
+ , sizeof(buf6));
+
+ str = buf1;
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "HexadecimalLower");
+ test_streq(v, "*");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "HexadecimalUpper");
+ test_streq(v, "*");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "HexadecimalUpperX");
+ test_streq(v, "*");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "Octal");
+ test_streq(v, "*");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "Newline");
+ test_streq(v, "\n");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "Tab");
+ test_streq(v, "\t");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "CarriageReturn");
+ test_streq(v, "\r");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "DoubleQuote");
+ test_streq(v, "\"");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "SimpleQuote");
+ test_streq(v, "'");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "Backslash");
+ test_streq(v, "\\");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "Mix");
+ test_streq(v, "This is a \"star\":\t'*'\nAnd second line");
+ tor_free(k); tor_free(v);
+ test_streq(str, "");
+
+ str = buf2;
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_eq_ptr(str, NULL);
+ tor_free(k); tor_free(v);
+
+ str = buf3;
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_eq_ptr(str, NULL);
+ tor_free(k); tor_free(v);
+
+ str = buf4;
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_eq_ptr(str, NULL);
+ tor_free(k); tor_free(v);
+
+#if 0
+ str = buf5;
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_eq_ptr(str, NULL);
+ tor_free(k); tor_free(v);
+#endif
+
+ str = buf6;
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_eq_ptr(str, NULL);
+ tor_free(k); tor_free(v);
+
+ done:
+ tor_free(k);
+ tor_free(v);
+}
+
+#ifndef _WIN32
+static void
+test_util_expand_filename(void)
+{
+ char *str;
+
+ setenv("HOME", "/home/itv", 1); /* For "internal test value" */
+
+ str = expand_filename("");
+ test_streq("", str);
+ tor_free(str);
+
+ str = expand_filename("/normal/path");
+ test_streq("/normal/path", str);
+ tor_free(str);
+
+ str = expand_filename("/normal/trailing/path/");
+ test_streq("/normal/trailing/path/", str);
+ tor_free(str);
+
+ str = expand_filename("~");
+ test_streq("/home/itv/", str);
+ tor_free(str);
+
+ str = expand_filename("$HOME/nodice");
+ test_streq("$HOME/nodice", str);
+ tor_free(str);
+
+ str = expand_filename("~/");
+ test_streq("/home/itv/", str);
+ tor_free(str);
+
+ str = expand_filename("~/foobarqux");
+ test_streq("/home/itv/foobarqux", str);
+ tor_free(str);
+
+ str = expand_filename("~/../../etc/passwd");
+ test_streq("/home/itv/../../etc/passwd", str);
+ tor_free(str);
+
+ str = expand_filename("~/trailing/");
+ test_streq("/home/itv/trailing/", str);
+ tor_free(str);
+ /* Ideally we'd test ~anotheruser, but that's shady to test (we'd
+ have to somehow inject/fake the get_user_homedir call) */
+
+ /* $HOME ending in a trailing slash */
+ setenv("HOME", "/home/itv/", 1);
+
+ str = expand_filename("~");
+ test_streq("/home/itv/", str);
+ tor_free(str);
+
+ str = expand_filename("~/");
+ test_streq("/home/itv/", str);
+ tor_free(str);
+
+ str = expand_filename("~/foo");
+ test_streq("/home/itv/foo", str);
+ tor_free(str);
+
+ /* Try with empty $HOME */
+
+ setenv("HOME", "", 1);
+
+ str = expand_filename("~");
+ test_streq("/", str);
+ tor_free(str);
+
+ str = expand_filename("~/");
+ test_streq("/", str);
+ tor_free(str);
+
+ str = expand_filename("~/foobar");
+ test_streq("/foobar", str);
+ tor_free(str);
+
+ /* Try with $HOME unset */
+
+ unsetenv("HOME");
+
+ str = expand_filename("~");
+ test_streq("/", str);
+ tor_free(str);
+
+ str = expand_filename("~/");
+ test_streq("/", str);
+ tor_free(str);
+
+ str = expand_filename("~/foobar");
+ test_streq("/foobar", str);
+ tor_free(str);
+
+ done:
+ tor_free(str);
+}
+#endif
+
/** Test basic string functionality. */
static void
test_util_strmisc(void)
@@ -314,56 +733,113 @@ test_util_strmisc(void)
int i;
char *cp;
- /* Tests for corner cases of strl operations */
+ /* Test strl operations */
test_eq(5, strlcpy(buf, "Hello", 0));
+ test_eq(5, strlcpy(buf, "Hello", 10));
+ test_streq(buf, "Hello");
+ test_eq(5, strlcpy(buf, "Hello", 6));
+ test_streq(buf, "Hello");
+ test_eq(5, strlcpy(buf, "Hello", 5));
+ test_streq(buf, "Hell");
strlcpy(buf, "Hello", sizeof(buf));
test_eq(10, strlcat(buf, "Hello", 5));
- /* Test tor_strstrip() */
+ /* Test strstrip() */
strlcpy(buf, "Testing 1 2 3", sizeof(buf));
tor_strstrip(buf, ",!");
test_streq(buf, "Testing 1 2 3");
strlcpy(buf, "!Testing 1 2 3?", sizeof(buf));
tor_strstrip(buf, "!? ");
test_streq(buf, "Testing123");
+ strlcpy(buf, "!!!Testing 1 2 3??", sizeof(buf));
+ tor_strstrip(buf, "!? ");
+ test_streq(buf, "Testing123");
- /* 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 parse_long */
+ /* Empty/zero input */
+ test_eq(0L, tor_parse_long("",10,0,100,&i,NULL));
+ test_eq(0, i);
+ test_eq(0L, tor_parse_long("0",10,0,100,&i,NULL));
+ test_eq(1, i);
+ /* Normal cases */
+ test_eq(10L, tor_parse_long("10",10,0,100,&i,NULL));
+ test_eq(1, i);
+ test_eq(10L, tor_parse_long("10",10,0,10,&i,NULL));
+ test_eq(1, i);
+ test_eq(10L, tor_parse_long("10",10,10,100,&i,NULL));
+ test_eq(1, i);
+ test_eq(-50L, tor_parse_long("-50",10,-100,100,&i,NULL));
+ test_eq(1, i);
+ test_eq(-50L, tor_parse_long("-50",10,-100,0,&i,NULL));
+ test_eq(1, i);
+ test_eq(-50L, tor_parse_long("-50",10,-50,0,&i,NULL));
+ test_eq(1, i);
+ /* Extra garbage */
+ test_eq(0L, tor_parse_long("10m",10,0,100,&i,NULL));
+ test_eq(0, i);
+ test_eq(0L, tor_parse_long("-50 plus garbage",10,-100,100,&i,NULL));
+ test_eq(0, i);
+ test_eq(10L, tor_parse_long("10m",10,0,100,&i,&cp));
+ test_eq(1, i);
+ test_streq(cp, "m");
+ test_eq(-50L, tor_parse_long("-50 plus garbage",10,-100,100,&i,&cp));
+ test_eq(1, i);
+ test_streq(cp, " plus garbage");
+ /* Out of bounds */
+ test_eq(0L, tor_parse_long("10",10,50,100,&i,NULL));
+ test_eq(0, i);
+ test_eq(0L, tor_parse_long("-50",10,0,100,&i,NULL));
+ test_eq(0, i);
+ /* Base different than 10 */
+ test_eq(2L, tor_parse_long("10",2,0,100,NULL,NULL));
+ test_eq(0L, tor_parse_long("2",2,0,100,NULL,NULL));
+ test_eq(0L, tor_parse_long("10",-2,0,100,NULL,NULL));
+ test_eq(68284L, tor_parse_long("10abc",16,0,70000,NULL,NULL));
+ test_eq(68284L, tor_parse_long("10ABC",16,0,70000,NULL,NULL));
+
+ /* Test parse_ulong */
+ test_eq(0UL, tor_parse_ulong("",10,0,100,NULL,NULL));
+ test_eq(0UL, tor_parse_ulong("0",10,0,100,NULL,NULL));
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_eq(10UL, tor_parse_ulong("10",10,0,10,NULL,NULL));
+ test_eq(10UL, tor_parse_ulong("10",10,10,100,NULL,NULL));
+ test_eq(0UL, tor_parse_ulong("8",8,0,100,NULL,NULL));
+ test_eq(50UL, tor_parse_ulong("50",10,50,100,NULL,NULL));
+ test_eq(0UL, tor_parse_ulong("-50",10,-100,100,NULL,NULL));
- /* Test tor_parse_uint64. */
+ /* Test parse_uint64 */
test_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp));
- test_assert(i == 1);
+ test_eq(1, i);
test_streq(cp, " x");
test_assert(U64_LITERAL(12345678901) ==
tor_parse_uint64("12345678901",10,0,UINT64_MAX, &i, &cp));
- test_assert(i == 1);
+ test_eq(1, i);
test_streq(cp, "");
test_assert(U64_LITERAL(0) ==
tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp));
- test_assert(i == 0);
+ test_eq(0, i);
{
- /* Test tor_parse_double. */
+ /* Test parse_double */
double d = tor_parse_double("10", 0, UINT64_MAX,&i,NULL);
- test_assert(i == 1);
+ test_eq(1, i);
test_assert(DBL_TO_U64(d) == 10);
d = tor_parse_double("0", 0, UINT64_MAX,&i,NULL);
- test_assert(i == 1);
+ test_eq(1, i);
test_assert(DBL_TO_U64(d) == 0);
d = tor_parse_double(" ", 0, UINT64_MAX,&i,NULL);
- test_assert(i == 0);
+ test_eq(0, i);
d = tor_parse_double(".0a", 0, UINT64_MAX,&i,NULL);
- test_assert(i == 0);
+ test_eq(0, i);
d = tor_parse_double(".0a", 0, UINT64_MAX,&i,&cp);
- test_assert(i == 1);
+ test_eq(1, i);
d = tor_parse_double("-.0", 0, UINT64_MAX,&i,NULL);
- test_assert(i == 1);
+ test_eq(1, i);
+ test_assert(DBL_TO_U64(d) == 0);
+ d = tor_parse_double("-10", -100.0, 100.0,&i,NULL);
+ test_eq(1, i);
+ test_eq(-10.0, d);
}
{
@@ -381,38 +857,60 @@ test_util_strmisc(void)
test_eq(i, 0);
}
- /* Test failing snprintf cases */
+ /* Test snprintf */
+ /* Returning -1 when there's not enough room in the output buffer */
test_eq(-1, tor_snprintf(buf, 0, "Foo"));
test_eq(-1, tor_snprintf(buf, 2, "Foo"));
-
- /* Test printf with uint64 */
+ test_eq(-1, tor_snprintf(buf, 3, "Foo"));
+ test_neq(-1, tor_snprintf(buf, 4, "Foo"));
+ /* Always NUL-terminate the output */
+ tor_snprintf(buf, 5, "abcdef");
+ test_eq(0, buf[4]);
+ tor_snprintf(buf, 10, "abcdef");
+ test_eq(0, buf[6]);
+ /* uint64 */
tor_snprintf(buf, sizeof(buf), "x!"U64_FORMAT"!x",
U64_PRINTF_ARG(U64_LITERAL(12345678901)));
- test_streq(buf, "x!12345678901!x");
+ test_streq("x!12345678901!x", buf);
- /* Test for strcmpstart and strcmpend. */
+ /* Test str{,case}cmpstart */
test_assert(strcmpstart("abcdef", "abcdef")==0);
test_assert(strcmpstart("abcdef", "abc")==0);
test_assert(strcmpstart("abcdef", "abd")<0);
test_assert(strcmpstart("abcdef", "abb")>0);
test_assert(strcmpstart("ab", "abb")<0);
-
+ test_assert(strcmpstart("ab", "")==0);
+ test_assert(strcmpstart("ab", "ab ")<0);
+ test_assert(strcasecmpstart("abcdef", "abCdEF")==0);
+ test_assert(strcasecmpstart("abcDeF", "abc")==0);
+ test_assert(strcasecmpstart("abcdef", "Abd")<0);
+ test_assert(strcasecmpstart("Abcdef", "abb")>0);
+ test_assert(strcasecmpstart("ab", "Abb")<0);
+ test_assert(strcasecmpstart("ab", "")==0);
+ test_assert(strcasecmpstart("ab", "ab ")<0);
+
+ /* Test str{,case}cmpend */
test_assert(strcmpend("abcdef", "abcdef")==0);
test_assert(strcmpend("abcdef", "def")==0);
test_assert(strcmpend("abcdef", "deg")<0);
test_assert(strcmpend("abcdef", "dee")>0);
- test_assert(strcmpend("ab", "abb")<0);
-
+ test_assert(strcmpend("ab", "aab")>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_assert(strcasecmpend("abcdef", "Deg")<0);
+ test_assert(strcasecmpend("abcDef", "dee")>0);
+ test_assert(strcasecmpend("AB", "abb")<0);
+
+ /* Test digest_is_zero */
+ memset(buf,0,20);
+ buf[20] = 'x';
+ test_assert(tor_digest_is_zero(buf));
+ buf[19] = 'x';
+ test_assert(!tor_digest_is_zero(buf));
/* 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));
@@ -423,11 +921,15 @@ test_util_strmisc(void)
test_assert(!tor_mem_is_zero(buf, 10));
/* Test 'escaped' */
+ test_assert(NULL == escaped(NULL));
test_streq("\"\"", escaped(""));
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_streq("\"\\\\ \\n\\r\\t\\\"\\'\"", escaped("\\ \n\r\t\"'"));
+ test_streq("\"unnecessary \\'backslashes\\'\"",
+ escaped("unnecessary \'backslashes\'"));
+ /* Non-printable characters appear as octal */
+ test_streq("\"z\\001abc\\277d\"", escaped("z\001abc\277d"));
+ test_streq("\"z\\336\\255 ;foo\"", escaped("z\xde\xad\x20;foo"));
/* Test strndup and memdup */
{
@@ -455,42 +957,43 @@ test_util_strmisc(void)
test_assert(!tor_strisnonupper(cp));
tor_strupper(cp);
test_streq(cp, "ABCDEF");
+ tor_strlower(cp);
+ test_streq(cp, "abcdef");
+ test_assert(tor_strisnonupper(cp));
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 and memstr */
{
const char *haystack = "abcde";
- tor_assert(!tor_memmem(haystack, 5, "ef", 2));
+ test_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);
+ test_assert(!tor_memmem(haystack, 4, "cde", 3));
haystack = "ababcad";
test_eq_ptr(tor_memmem(haystack, 7, "abc", 3), haystack + 2);
+ /* memstr */
test_eq_ptr(tor_memstr(haystack, 7, "abc"), haystack + 2);
+ test_eq_ptr(tor_memstr(haystack, 7, "cad"), haystack + 4);
+ test_assert(!tor_memstr(haystack, 6, "cad"));
+ test_assert(!tor_memstr(haystack, 7, "cadd"));
test_assert(!tor_memstr(haystack, 7, "fe"));
- test_assert(!tor_memstr(haystack, 7, "longerthantheoriginal"));
+ test_assert(!tor_memstr(haystack, 7, "ababcade"));
}
/* Test wrap_string */
{
- smartlist_t *sl = smartlist_create();
- wrap_string(sl, "This is a test of string wrapping functionality: woot.",
+ smartlist_t *sl = smartlist_new();
+ wrap_string(sl,
+ "This is a test of string wrapping functionality: woot. "
+ "a functionality? w00t w00t...!",
10, "", "");
cp = smartlist_join_strings(sl, "", 0, NULL);
test_streq(cp,
- "This is a\ntest of\nstring\nwrapping\nfunctional\nity: woot.\n");
+ "This is a\ntest of\nstring\nwrapping\nfunctional\nity: woot.\n"
+ "a\nfunctional\nity? w00t\nw00t...!\n");
tor_free(cp);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
@@ -501,11 +1004,100 @@ test_util_strmisc(void)
test_streq(cp,
"### This is a\n# test of string\n# wrapping\n# functionality:\n"
"# woot.\n");
+ tor_free(cp);
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_clear(sl);
+
+ wrap_string(sl, "A test of string wrapping...", 6, "### ", "# ");
+ cp = smartlist_join_strings(sl, "", 0, NULL);
+ test_streq(cp,
+ "### A\n# test\n# of\n# stri\n# ng\n# wrap\n# ping\n# ...\n");
+ tor_free(cp);
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_clear(sl);
+
+ wrap_string(sl, "Wrapping test", 6, "#### ", "# ");
+ cp = smartlist_join_strings(sl, "", 0, NULL);
+ test_streq(cp, "#### W\n# rapp\n# ing\n# test\n");
+ tor_free(cp);
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_clear(sl);
+
+ wrap_string(sl, "Small test", 6, "### ", "#### ");
+ cp = smartlist_join_strings(sl, "", 0, NULL);
+ test_streq(cp, "### Sm\n#### a\n#### l\n#### l\n#### t\n#### e"
+ "\n#### s\n#### t\n");
+ tor_free(cp);
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_clear(sl);
+ wrap_string(sl, "First null", 6, NULL, "> ");
+ cp = smartlist_join_strings(sl, "", 0, NULL);
+ test_streq(cp, "First\n> null\n");
+ tor_free(cp);
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_clear(sl);
+
+ wrap_string(sl, "Second null", 6, "> ", NULL);
+ cp = smartlist_join_strings(sl, "", 0, NULL);
+ test_streq(cp, "> Seco\nnd\nnull\n");
+ tor_free(cp);
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_clear(sl);
+
+ wrap_string(sl, "Both null", 6, NULL, NULL);
+ cp = smartlist_join_strings(sl, "", 0, NULL);
+ test_streq(cp, "Both\nnull\n");
tor_free(cp);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_free(sl);
+
+ /* Can't test prefixes that have the same length as the line width, because
+ the function has an assert */
}
+
+ /* Test hex_str */
+ {
+ char binary_data[68];
+ size_t i;
+ for (i = 0; i < sizeof(binary_data); ++i)
+ binary_data[i] = i;
+ test_streq(hex_str(binary_data, 0), "");
+ test_streq(hex_str(binary_data, 1), "00");
+ test_streq(hex_str(binary_data, 17), "000102030405060708090A0B0C0D0E0F10");
+ test_streq(hex_str(binary_data, 32),
+ "000102030405060708090A0B0C0D0E0F"
+ "101112131415161718191A1B1C1D1E1F");
+ test_streq(hex_str(binary_data, 34),
+ "000102030405060708090A0B0C0D0E0F"
+ "101112131415161718191A1B1C1D1E1F");
+ /* Repeat these tests for shorter strings after longer strings
+ have been tried, to make sure we're correctly terminating strings */
+ test_streq(hex_str(binary_data, 1), "00");
+ test_streq(hex_str(binary_data, 0), "");
+ }
+
+ /* Test strcmp_opt */
+ tt_int_op(strcmp_opt("", "foo"), <, 0);
+ tt_int_op(strcmp_opt("", ""), ==, 0);
+ tt_int_op(strcmp_opt("foo", ""), >, 0);
+
+ tt_int_op(strcmp_opt(NULL, ""), <, 0);
+ tt_int_op(strcmp_opt(NULL, NULL), ==, 0);
+ tt_int_op(strcmp_opt("", NULL), >, 0);
+
+ tt_int_op(strcmp_opt(NULL, "foo"), <, 0);
+ tt_int_op(strcmp_opt("foo", NULL), >, 0);
+
+ /* Test strcmp_len */
+ tt_int_op(strcmp_len("foo", "bar", 3), >, 0);
+ tt_int_op(strcmp_len("foo", "bar", 2), <, 0); /* First len, then lexical */
+ tt_int_op(strcmp_len("foo2", "foo1", 4), >, 0);
+ tt_int_op(strcmp_len("foo2", "foo1", 3), <, 0); /* Really stop at len */
+ tt_int_op(strcmp_len("foo2", "foo", 3), ==, 0); /* Really stop at len */
+ tt_int_op(strcmp_len("blah", "", 4), >, 0);
+ tt_int_op(strcmp_len("blah", "", 0), ==, 0);
+
done:
;
}
@@ -604,10 +1196,10 @@ test_util_threads(void)
char *s1 = NULL, *s2 = NULL;
int done = 0, timedout = 0;
time_t started;
-#ifndef MS_WINDOWS
+#ifndef _WIN32
struct timeval tv;
tv.tv_sec=0;
- tv.tv_usec=10;
+ tv.tv_usec=100*1000;
#endif
#ifndef TOR_IS_MULTITHREADED
/* Skip this test if we aren't threading. We should be threading most
@@ -634,11 +1226,11 @@ test_util_threads(void)
if (strmap_get(_thread_test_strmap, "thread 1") &&
strmap_get(_thread_test_strmap, "thread 2")) {
done = 1;
- } else if (time(NULL) > started + 25) {
+ } else if (time(NULL) > started + 150) {
timedout = done = 1;
}
tor_mutex_release(_thread_test_mutex);
-#ifndef MS_WINDOWS
+#ifndef _WIN32
/* Prevent the main thread from starving the worker threads. */
select(0, NULL, NULL, NULL, &tv);
#endif
@@ -693,13 +1285,14 @@ test_util_gzip(void)
test_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
GZIP_METHOD));
test_assert(buf2);
- test_assert(!memcmp(buf2, "\037\213", 2)); /* Gzip magic. */
+ test_assert(len1 < strlen(buf1));
test_assert(detect_compression_method(buf2, len1) == GZIP_METHOD);
test_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1,
GZIP_METHOD, 1, LOG_INFO));
test_assert(buf3);
- test_streq(buf1,buf3);
+ test_eq(strlen(buf1) + 1, len2);
+ test_streq(buf1, buf3);
tor_free(buf2);
tor_free(buf3);
@@ -708,13 +1301,13 @@ test_util_gzip(void)
test_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
ZLIB_METHOD));
test_assert(buf2);
- test_assert(!memcmp(buf2, "\x78\xDA", 2)); /* deflate magic. */
test_assert(detect_compression_method(buf2, len1) == ZLIB_METHOD);
test_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1,
ZLIB_METHOD, 1, LOG_INFO));
test_assert(buf3);
- test_streq(buf1,buf3);
+ test_eq(strlen(buf1) + 1, len2);
+ test_streq(buf1, buf3);
/* Check whether we can uncompress concatenated, compressed strings. */
tor_free(buf3);
@@ -722,7 +1315,7 @@ test_util_gzip(void)
memcpy(buf2+len1, buf2, len1);
test_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1*2,
ZLIB_METHOD, 1, LOG_INFO));
- test_eq(len2, (strlen(buf1)+1)*2);
+ test_eq((strlen(buf1)+1)*2, len2);
test_memeq(buf3,
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0",
@@ -737,45 +1330,46 @@ test_util_gzip(void)
tor_strdup("String with low redundancy that won't be compressed much.");
test_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
ZLIB_METHOD));
- tor_assert(len1>16);
+ tt_assert(len1>16);
/* when we allow an incomplete string, we should succeed.*/
- tor_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1-16,
+ tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1-16,
ZLIB_METHOD, 0, LOG_INFO));
+ tt_assert(len2 > 5);
buf3[len2]='\0';
- tor_assert(len2 > 5);
- tor_assert(!strcmpstart(buf1, buf3));
+ tt_assert(!strcmpstart(buf1, buf3));
/* when we demand a complete string, this must fail. */
tor_free(buf3);
- tor_assert(tor_gzip_uncompress(&buf3, &len2, buf2, len1-16,
+ tt_assert(tor_gzip_uncompress(&buf3, &len2, buf2, len1-16,
ZLIB_METHOD, 1, LOG_INFO));
- tor_assert(!buf3);
+ tt_assert(!buf3);
/* Now, try streaming compression. */
tor_free(buf1);
tor_free(buf2);
tor_free(buf3);
state = tor_zlib_new(1, ZLIB_METHOD);
- tor_assert(state);
+ tt_assert(state);
cp1 = buf1 = tor_malloc(1024);
len1 = 1024;
ccp2 = "ABCDEFGHIJABCDEFGHIJ";
len2 = 21;
test_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 0)
== TOR_ZLIB_OK);
- test_eq(len2, 0); /* Make sure we compressed it all. */
+ test_eq(0, len2); /* Make sure we compressed it all. */
test_assert(cp1 > buf1);
len2 = 0;
cp2 = cp1;
test_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 1)
== TOR_ZLIB_DONE);
- test_eq(len2, 0);
+ test_eq(0, len2);
test_assert(cp1 > cp2); /* Make sure we really added something. */
- tor_assert(!tor_gzip_uncompress(&buf3, &len2, buf1, 1024-len1,
+ tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf1, 1024-len1,
ZLIB_METHOD, 1, LOG_WARN));
test_streq(buf3, "ABCDEFGHIJABCDEFGHIJ"); /*Make sure it compressed right.*/
+ test_eq(21, len2);
done:
if (state)
@@ -802,14 +1396,12 @@ test_util_mmap(void)
test_assert(! mapping);
write_str_to_file(fname1, "Short file.", 1);
- write_bytes_to_file(fname2, buf, buflen, 1);
- write_bytes_to_file(fname3, buf, 16384, 1);
mapping = tor_mmap_file(fname1);
test_assert(mapping);
test_eq(mapping->size, strlen("Short file."));
test_streq(mapping->data, "Short file.");
-#ifdef MS_WINDOWS
+#ifdef _WIN32
tor_munmap_file(mapping);
mapping = NULL;
test_assert(unlink(fname1) == 0);
@@ -830,9 +1422,10 @@ test_util_mmap(void)
/* Make sure that we fail to map a no-longer-existent file. */
mapping = tor_mmap_file(fname1);
- test_assert(mapping == NULL);
+ test_assert(! mapping);
/* Now try a big file that stretches across a few pages and isn't aligned */
+ write_bytes_to_file(fname2, buf, buflen, 1);
mapping = tor_mmap_file(fname2);
test_assert(mapping);
test_eq(mapping->size, buflen);
@@ -841,6 +1434,7 @@ test_util_mmap(void)
mapping = NULL;
/* Now try a big aligned file. */
+ write_bytes_to_file(fname3, buf, 16384, 1);
mapping = tor_mmap_file(fname3);
test_assert(mapping);
test_eq(mapping->size, 16384);
@@ -868,12 +1462,12 @@ test_util_control_formats(void)
{
char *out = NULL;
const char *inp =
- "..This is a test\r\nof the emergency \nbroadcast\r\n..system.\r\nZ.\r\n";
+ "..This is a test\r\n.of the emergency \n..system.\r\n\rZ.\r\n";
size_t sz;
sz = read_escaped_data(inp, strlen(inp), &out);
test_streq(out,
- ".This is a test\nof the emergency \nbroadcast\n.system.\nZ.\n");
+ ".This is a test\nof the emergency \n.system.\n\rZ.\n");
test_eq(sz, strlen(out));
done:
@@ -884,85 +1478,169 @@ static void
test_util_sscanf(void)
{
unsigned u1, u2, u3;
- char s1[10], s2[10], s3[10], ch;
+ char s1[20], s2[10], s3[10], ch;
int r;
- r = tor_sscanf("hello world", "hello world"); /* String match: success */
- test_eq(r, 0);
- r = tor_sscanf("hello world 3", "hello worlb %u", &u1); /* String fail */
- test_eq(r, 0);
- r = tor_sscanf("12345", "%u", &u1); /* Simple number */
- test_eq(r, 1);
- test_eq(u1, 12345u);
- r = tor_sscanf("", "%u", &u1); /* absent number */
- test_eq(r, 0);
- r = tor_sscanf("A", "%u", &u1); /* bogus number */
- test_eq(r, 0);
- r = tor_sscanf("4294967295", "%u", &u1); /* UINT32_MAX should work. */
- test_eq(r, 1);
- test_eq(u1, 4294967295u);
- r = tor_sscanf("4294967296", "%u", &u1); /* Always say -1 at 32 bits. */
- test_eq(r, 0);
- r = tor_sscanf("123456", "%2u%u", &u1, &u2); /* Width */
- test_eq(r, 2);
- test_eq(u1, 12u);
- test_eq(u2, 3456u);
- r = tor_sscanf("!12:3:456", "!%2u:%2u:%3u", &u1, &u2, &u3); /* separators */
- test_eq(r, 3);
- test_eq(u1, 12u);
- test_eq(u2, 3u);
- test_eq(u3, 456u);
- r = tor_sscanf("12:3:045", "%2u:%2u:%3u", &u1, &u2, &u3); /* 0s */
- test_eq(r, 3);
- test_eq(u1, 12u);
- test_eq(u2, 3u);
- test_eq(u3, 45u);
+ /* Simple tests (malformed patterns, literal matching, ...) */
+ test_eq(-1, tor_sscanf("123", "%i", &r)); /* %i is not supported */
+ test_eq(-1, tor_sscanf("wrong", "%5c", s1)); /* %c cannot have a number. */
+ test_eq(-1, tor_sscanf("hello", "%s", s1)); /* %s needs a number. */
+ test_eq(-1, tor_sscanf("prettylongstring", "%999999s", s1));
+#if 0
+ /* GCC thinks these two are illegal. */
+ test_eq(-1, tor_sscanf("prettylongstring", "%0s", s1));
+ test_eq(0, tor_sscanf("prettylongstring", "%10s", NULL));
+#endif
+ /* No '%'-strings: always "success" */
+ test_eq(0, tor_sscanf("hello world", "hello world"));
+ test_eq(0, tor_sscanf("hello world", "good bye"));
+ /* Excess data */
+ test_eq(0, tor_sscanf("hello 3", "%u", &u1)); /* have to match the start */
+ test_eq(0, tor_sscanf(" 3 hello", "%u", &u1));
+ test_eq(0, tor_sscanf(" 3 hello", "%2u", &u1)); /* not even in this case */
+ test_eq(1, tor_sscanf("3 hello", "%u", &u1)); /* but trailing is alright */
+
+ /* Numbers (ie. %u) */
+ test_eq(0, tor_sscanf("hello world 3", "hello worlb %u", &u1)); /* d vs b */
+ test_eq(1, tor_sscanf("12345", "%u", &u1));
+ test_eq(12345u, u1);
+ test_eq(1, tor_sscanf("12346 ", "%u", &u1));
+ test_eq(12346u, u1);
+ test_eq(0, tor_sscanf(" 12347", "%u", &u1));
+ test_eq(1, tor_sscanf(" 12348", " %u", &u1));
+ test_eq(12348u, u1);
+ test_eq(1, tor_sscanf("0", "%u", &u1));
+ test_eq(0u, u1);
+ test_eq(1, tor_sscanf("0000", "%u", &u2));
+ test_eq(0u, u2);
+ test_eq(0, tor_sscanf("", "%u", &u1)); /* absent number */
+ test_eq(0, tor_sscanf("A", "%u", &u1)); /* bogus number */
+ test_eq(0, tor_sscanf("-1", "%u", &u1)); /* negative number */
+ test_eq(1, tor_sscanf("4294967295", "%u", &u1)); /* UINT32_MAX should work */
+ test_eq(4294967295u, u1);
+ test_eq(0, tor_sscanf("4294967296", "%u", &u1)); /* But not at 32 bits */
+ test_eq(1, tor_sscanf("4294967296", "%9u", &u1)); /* but parsing only 9... */
+ test_eq(429496729u, u1);
+
+ /* Numbers with size (eg. %2u) */
+ test_eq(0, tor_sscanf("-1", "%2u", &u1));
+ test_eq(2, tor_sscanf("123456", "%2u%u", &u1, &u2));
+ test_eq(12u, u1);
+ test_eq(3456u, u2);
+ test_eq(1, tor_sscanf("123456", "%8u", &u1));
+ test_eq(123456u, u1);
+ test_eq(1, tor_sscanf("123457 ", "%8u", &u1));
+ test_eq(123457u, u1);
+ test_eq(0, tor_sscanf(" 123456", "%8u", &u1));
+ test_eq(3, tor_sscanf("!12:3:456", "!%2u:%2u:%3u", &u1, &u2, &u3));
+ test_eq(12u, u1);
+ test_eq(3u, u2);
+ test_eq(456u, u3);
+ test_eq(3, tor_sscanf("67:8:099", "%2u:%2u:%3u", &u1, &u2, &u3)); /* 0s */
+ test_eq(67u, u1);
+ test_eq(8u, u2);
+ test_eq(99u, u3);
/* %u does not match space.*/
- r = tor_sscanf("12:3: 45", "%2u:%2u:%3u", &u1, &u2, &u3);
- test_eq(r, 2);
+ test_eq(2, tor_sscanf("12:3: 45", "%2u:%2u:%3u", &u1, &u2, &u3));
+ test_eq(12u, u1);
+ test_eq(3u, u2);
/* %u does not match negative numbers. */
- r = tor_sscanf("12:3:-4", "%2u:%2u:%3u", &u1, &u2, &u3);
- test_eq(r, 2);
+ test_eq(2, tor_sscanf("67:8:-9", "%2u:%2u:%3u", &u1, &u2, &u3));
+ test_eq(67u, u1);
+ test_eq(8u, u2);
/* Arbitrary amounts of 0-padding are okay */
- r = tor_sscanf("12:03:000000000000000099", "%2u:%2u:%u", &u1, &u2, &u3);
- test_eq(r, 3);
- test_eq(u1, 12u);
- test_eq(u2, 3u);
- test_eq(u3, 99u);
-
- r = tor_sscanf("99% fresh", "%3u%% fresh", &u1); /* percents are scannable.*/
- test_eq(r, 1);
- test_eq(u1, 99);
-
- r = tor_sscanf("hello", "%s", s1); /* %s needs a number. */
- test_eq(r, -1);
-
- r = tor_sscanf("hello", "%3s%7s", s1, s2); /* %s matches characters. */
- test_eq(r, 2);
+ test_eq(3, tor_sscanf("12:03:000000000000000099", "%2u:%2u:%u",
+ &u1, &u2, &u3));
+ test_eq(12u, u1);
+ test_eq(3u, u2);
+ test_eq(99u, u3);
+
+ /* Hex (ie. %x) */
+ test_eq(3, tor_sscanf("1234 02aBcdEf ff", "%x %x %x", &u1, &u2, &u3));
+ test_eq(0x1234, u1);
+ test_eq(0x2ABCDEF, u2);
+ test_eq(0xFF, u3);
+ /* Width works on %x */
+ test_eq(3, tor_sscanf("f00dcafe444", "%4x%4x%u", &u1, &u2, &u3));
+ test_eq(0xf00d, u1);
+ test_eq(0xcafe, u2);
+ test_eq(444, u3);
+
+ /* Literal '%' (ie. '%%') */
+ test_eq(1, tor_sscanf("99% fresh", "%3u%% fresh", &u1));
+ test_eq(99, u1);
+ test_eq(0, tor_sscanf("99 fresh", "%% %3u %s", &u1, s1));
+ test_eq(1, tor_sscanf("99 fresh", "%3u%% %s", &u1, s1));
+ test_eq(2, tor_sscanf("99 fresh", "%3u %5s %%", &u1, s1));
+ test_eq(99, u1);
+ test_streq(s1, "fresh");
+ test_eq(1, tor_sscanf("% boo", "%% %3s", s1));
+ test_streq("boo", s1);
+
+ /* Strings (ie. %s) */
+ test_eq(2, tor_sscanf("hello", "%3s%7s", s1, s2));
test_streq(s1, "hel");
test_streq(s2, "lo");
- r = tor_sscanf("WD40", "%2s%u", s3, &u1); /* %s%u */
- test_eq(r, 2);
+ test_eq(2, tor_sscanf("WD40", "%2s%u", s3, &u1)); /* %s%u */
test_streq(s3, "WD");
- test_eq(u1, 40);
- r = tor_sscanf("76trombones", "%6u%9s", &u1, s1); /* %u%s */
- test_eq(r, 2);
- test_eq(u1, 76);
+ test_eq(40, u1);
+ test_eq(2, tor_sscanf("WD40", "%3s%u", s3, &u1)); /* %s%u */
+ test_streq(s3, "WD4");
+ test_eq(0, u1);
+ test_eq(2, tor_sscanf("76trombones", "%6u%9s", &u1, s1)); /* %u%s */
+ test_eq(76, u1);
test_streq(s1, "trombones");
- r = tor_sscanf("hello world", "%9s %9s", s1, s2); /* %s doesn't eat space. */
- test_eq(r, 2);
+ test_eq(1, tor_sscanf("prettylongstring", "%999s", s1));
+ test_streq(s1, "prettylongstring");
+ /* %s doesn't eat spaces */
+ test_eq(2, tor_sscanf("hello world", "%9s %9s", s1, s2));
test_streq(s1, "hello");
test_streq(s2, "world");
- r = tor_sscanf("hi", "%9s%9s%3s", s1, s2, s3); /* %s can be empty. */
- test_eq(r, 3);
+ test_eq(2, tor_sscanf("bye world?", "%9s %9s", s1, s2));
+ test_streq(s1, "bye");
+ test_streq(s2, "");
+ test_eq(3, tor_sscanf("hi", "%9s%9s%3s", s1, s2, s3)); /* %s can be empty. */
test_streq(s1, "hi");
test_streq(s2, "");
test_streq(s3, "");
- r = tor_sscanf("1.2.3", "%u.%u.%u%c", &u1, &u2, &u3, &ch);
- test_eq(r, 3);
- r = tor_sscanf("1.2.3 foobar", "%u.%u.%u%c", &u1, &u2, &u3, &ch);
- test_eq(r, 4);
+ test_eq(3, tor_sscanf("1.2.3", "%u.%u.%u%c", &u1, &u2, &u3, &ch));
+ test_eq(4, tor_sscanf("1.2.3 foobar", "%u.%u.%u%c", &u1, &u2, &u3, &ch));
+ test_eq(' ', ch);
+
+ done:
+ ;
+}
+
+static void
+test_util_path_is_relative(void)
+{
+ /* OS-independent tests */
+ test_eq(1, path_is_relative(""));
+ test_eq(1, path_is_relative("dir"));
+ test_eq(1, path_is_relative("dir/"));
+ test_eq(1, path_is_relative("./dir"));
+ test_eq(1, path_is_relative("../dir"));
+
+ test_eq(0, path_is_relative("/"));
+ test_eq(0, path_is_relative("/dir"));
+ test_eq(0, path_is_relative("/dir/"));
+
+ /* Windows */
+#ifdef _WIN32
+ /* I don't have Windows so I can't test this, hence the "#ifdef
+ 0". These are tests that look useful, so please try to get them
+ running and uncomment if it all works as it should */
+ test_eq(1, path_is_relative("dir"));
+ test_eq(1, path_is_relative("dir\\"));
+ test_eq(1, path_is_relative("dir\\a:"));
+ test_eq(1, path_is_relative("dir\\a:\\"));
+ test_eq(1, path_is_relative("http:\\dir"));
+
+ test_eq(0, path_is_relative("\\dir"));
+ test_eq(0, path_is_relative("a:\\dir"));
+ test_eq(0, path_is_relative("z:\\dir"));
+#endif
done:
;
@@ -990,7 +1668,7 @@ test_util_mempool(void)
test_eq(pool->item_alloc_size & 0x03, 0);
test_assert(pool->new_chunk_capacity < 60);
- allocated = smartlist_create();
+ allocated = smartlist_new();
for (i = 0; i < 20000; ++i) {
if (smartlist_len(allocated) < 20 || crypto_rand_int(2)) {
void *m = mp_pool_get(pool);
@@ -1161,30 +1839,71 @@ test_util_strtok(void)
{
char buf[128];
char buf2[128];
+ int i;
char *cp1, *cp2;
- strlcpy(buf, "Graved on the dark in gestures of descent", sizeof(buf));
- strlcpy(buf2, "they.seemed;their!own;most.perfect;monument", sizeof(buf2));
- /* -- "Year's End", Richard Wilbur */
- test_streq("Graved", tor_strtok_r_impl(buf, " ", &cp1));
- test_streq("they", tor_strtok_r_impl(buf2, ".!..;!", &cp2));
+ for (i = 0; i < 3; i++) {
+ const char *pad1="", *pad2="";
+ switch (i) {
+ case 0:
+ break;
+ case 1:
+ pad1 = " ";
+ pad2 = "!";
+ break;
+ case 2:
+ pad1 = " ";
+ pad2 = ";!";
+ break;
+ }
+ tor_snprintf(buf, sizeof(buf), "%s", pad1);
+ tor_snprintf(buf2, sizeof(buf2), "%s", pad2);
+ test_assert(NULL == tor_strtok_r_impl(buf, " ", &cp1));
+ test_assert(NULL == tor_strtok_r_impl(buf2, ".!..;!", &cp2));
+
+ tor_snprintf(buf, sizeof(buf),
+ "%sGraved on the dark in gestures of descent%s", pad1, pad1);
+ tor_snprintf(buf2, sizeof(buf2),
+ "%sthey.seemed;;their!.own;most.perfect;monument%s",pad2,pad2);
+ /* -- "Year's End", Richard Wilbur */
+
+ test_streq("Graved", tor_strtok_r_impl(buf, " ", &cp1));
+ test_streq("they", tor_strtok_r_impl(buf2, ".!..;!", &cp2));
#define S1() tor_strtok_r_impl(NULL, " ", &cp1)
#define S2() tor_strtok_r_impl(NULL, ".!..;!", &cp2)
- test_streq("on", S1());
- test_streq("the", S1());
- test_streq("dark", S1());
- test_streq("seemed", S2());
- test_streq("their", S2());
- test_streq("own", S2());
- test_streq("in", S1());
- test_streq("gestures", S1());
- test_streq("of", S1());
- test_streq("most", S2());
- test_streq("perfect", S2());
- test_streq("descent", S1());
- test_streq("monument", S2());
- test_assert(NULL == S1());
- test_assert(NULL == S2());
+ test_streq("on", S1());
+ test_streq("the", S1());
+ test_streq("dark", S1());
+ test_streq("seemed", S2());
+ test_streq("their", S2());
+ test_streq("own", S2());
+ test_streq("in", S1());
+ test_streq("gestures", S1());
+ test_streq("of", S1());
+ test_streq("most", S2());
+ test_streq("perfect", S2());
+ test_streq("descent", S1());
+ test_streq("monument", S2());
+ test_eq_ptr(NULL, S1());
+ test_eq_ptr(NULL, S2());
+ }
+
+ buf[0] = 0;
+ test_eq_ptr(NULL, tor_strtok_r_impl(buf, " ", &cp1));
+ test_eq_ptr(NULL, tor_strtok_r_impl(buf, "!", &cp1));
+
+ strlcpy(buf, "Howdy!", sizeof(buf));
+ test_streq("Howdy", tor_strtok_r_impl(buf, "!", &cp1));
+ test_eq_ptr(NULL, tor_strtok_r_impl(NULL, "!", &cp1));
+
+ strlcpy(buf, " ", sizeof(buf));
+ test_eq_ptr(NULL, tor_strtok_r_impl(buf, " ", &cp1));
+ strlcpy(buf, " ", sizeof(buf));
+ test_eq_ptr(NULL, tor_strtok_r_impl(buf, " ", &cp1));
+
+ strlcpy(buf, "something ", sizeof(buf));
+ test_streq("something", tor_strtok_r_impl(buf, " ", &cp1));
+ test_eq_ptr(NULL, tor_strtok_r_impl(NULL, ";", &cp1));
done:
;
}
@@ -1193,24 +1912,64 @@ static void
test_util_find_str_at_start_of_line(void *ptr)
{
const char *long_string =
- "hello world. hello world. hello hello. howdy.\n"
- "hello hello world\n";
+ "howdy world. how are you? i hope it's fine.\n"
+ "hello kitty\n"
+ "third line";
+ char *line2 = strchr(long_string,'\n')+1;
+ char *line3 = strchr(line2,'\n')+1;
+ const char *short_string = "hello kitty\n"
+ "second line\n";
+ char *short_line2 = strchr(short_string,'\n')+1;
(void)ptr;
- /* not-found case. */
- tt_assert(! find_str_at_start_of_line(long_string, "fred"));
+ test_eq_ptr(long_string, find_str_at_start_of_line(long_string, ""));
+ test_eq_ptr(NULL, find_str_at_start_of_line(short_string, "nonsense"));
+ test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "nonsense"));
+ test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "\n"));
+ test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "how "));
+ test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "kitty"));
+ test_eq_ptr(long_string, find_str_at_start_of_line(long_string, "h"));
+ test_eq_ptr(long_string, find_str_at_start_of_line(long_string, "how"));
+ test_eq_ptr(line2, find_str_at_start_of_line(long_string, "he"));
+ test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hell"));
+ test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hello k"));
+ test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hello kitty\n"));
+ test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hello kitty\nt"));
+ test_eq_ptr(line3, find_str_at_start_of_line(long_string, "third"));
+ test_eq_ptr(line3, find_str_at_start_of_line(long_string, "third line"));
+ test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "third line\n"));
+ test_eq_ptr(short_line2, find_str_at_start_of_line(short_string,
+ "second line\n"));
+ done:
+ ;
+}
- /* not-found case where haystack doesn't end with \n */
- tt_assert(! find_str_at_start_of_line("foobar\nbaz", "fred"));
+static void
+test_util_string_is_C_identifier(void *ptr)
+{
+ (void)ptr;
- /* start-of-string case */
- tt_assert(long_string ==
- find_str_at_start_of_line(long_string, "hello world."));
+ test_eq(1, string_is_C_identifier("string_is_C_identifier"));
+ test_eq(1, string_is_C_identifier("_string_is_C_identifier"));
+ test_eq(1, string_is_C_identifier("_"));
+ test_eq(1, string_is_C_identifier("i"));
+ test_eq(1, string_is_C_identifier("_____"));
+ test_eq(1, string_is_C_identifier("__00__"));
+ test_eq(1, string_is_C_identifier("__init__"));
+ test_eq(1, string_is_C_identifier("_0"));
+ test_eq(1, string_is_C_identifier("_0string_is_C_identifier"));
+ test_eq(1, string_is_C_identifier("_0"));
+
+ test_eq(0, string_is_C_identifier("0_string_is_C_identifier"));
+ test_eq(0, string_is_C_identifier("0"));
+ test_eq(0, string_is_C_identifier(""));
+ test_eq(0, string_is_C_identifier(";"));
+ test_eq(0, string_is_C_identifier("i;"));
+ test_eq(0, string_is_C_identifier("_;"));
+ test_eq(0, string_is_C_identifier("í"));
+ test_eq(0, string_is_C_identifier("ñ"));
- /* start-of-line case */
- tt_assert(strchr(long_string,'\n')+1 ==
- find_str_at_start_of_line(long_string, "hello hello"));
done:
;
}
@@ -1224,36 +1983,47 @@ test_util_asprintf(void *ptr)
int r;
(void)ptr;
- /* empty string. */
+ /* simple string */
+ r = tor_asprintf(&cp, "simple string 100%% safe");
+ test_assert(cp);
+ test_streq("simple string 100% safe", cp);
+ test_eq(strlen(cp), r);
+
+ /* empty string */
r = tor_asprintf(&cp, "%s", "");
- tt_assert(cp);
- tt_int_op(r, ==, strlen(cp));
- tt_str_op(cp, ==, "");
+ test_assert(cp);
+ test_streq("", cp);
+ test_eq(strlen(cp), r);
+
+ /* numbers (%i) */
+ r = tor_asprintf(&cp, "I like numbers-%2i, %i, etc.", -1, 2);
+ test_assert(cp);
+ test_streq("I like numbers--1, 2, etc.", cp);
+ test_eq(strlen(cp), r);
- /* Short string with some printing in it. */
+ /* numbers (%d) */
r = tor_asprintf(&cp2, "First=%d, Second=%d", 101, 202);
- tt_assert(cp2);
- tt_int_op(r, ==, strlen(cp2));
- tt_str_op(cp2, ==, "First=101, Second=202");
- tt_assert(cp != cp2);
+ test_assert(cp2);
+ test_eq(strlen(cp2), r);
+ test_streq("First=101, Second=202", cp2);
+ test_assert(cp != cp2);
tor_free(cp);
tor_free(cp2);
/* Glass-box test: a string exactly 128 characters long. */
r = tor_asprintf(&cp, "Lorem1: %sLorem2: %s", LOREMIPSUM, LOREMIPSUM);
- tt_assert(cp);
- tt_int_op(r, ==, 128);
- tt_assert(cp[128] == '\0');
- tt_str_op(cp, ==,
- "Lorem1: "LOREMIPSUM"Lorem2: "LOREMIPSUM);
+ test_assert(cp);
+ test_eq(128, r);
+ test_assert(cp[128] == '\0');
+ test_streq("Lorem1: "LOREMIPSUM"Lorem2: "LOREMIPSUM, cp);
tor_free(cp);
/* String longer than 128 characters */
r = tor_asprintf(&cp, "1: %s 2: %s 3: %s",
LOREMIPSUM, LOREMIPSUM, LOREMIPSUM);
- tt_assert(cp);
- tt_int_op(r, ==, strlen(cp));
- tt_str_op(cp, ==, "1: "LOREMIPSUM" 2: "LOREMIPSUM" 3: "LOREMIPSUM);
+ test_assert(cp);
+ test_eq(strlen(cp), r);
+ test_streq("1: "LOREMIPSUM" 2: "LOREMIPSUM" 3: "LOREMIPSUM, cp);
done:
tor_free(cp);
@@ -1264,24 +2034,40 @@ static void
test_util_listdir(void *ptr)
{
smartlist_t *dir_contents = NULL;
- char *fname1=NULL, *fname2=NULL, *dirname=NULL;
+ char *fname1=NULL, *fname2=NULL, *fname3=NULL, *dir1=NULL, *dirname=NULL;
+ int r;
(void)ptr;
fname1 = tor_strdup(get_fname("hopscotch"));
fname2 = tor_strdup(get_fname("mumblety-peg"));
+ fname3 = tor_strdup(get_fname(".hidden-file"));
+ dir1 = tor_strdup(get_fname("some-directory"));
dirname = tor_strdup(get_fname(NULL));
- tt_int_op(write_str_to_file(fname1, "X\n", 0), ==, 0);
- tt_int_op(write_str_to_file(fname2, "Y\n", 0), ==, 0);
+ test_eq(0, write_str_to_file(fname1, "X\n", 0));
+ test_eq(0, write_str_to_file(fname2, "Y\n", 0));
+ test_eq(0, write_str_to_file(fname3, "Z\n", 0));
+#ifdef _WIN32
+ r = mkdir(dir1);
+#else
+ r = mkdir(dir1, 0700);
+#endif
+ if (r) {
+ fprintf(stderr, "Can't create directory %s:", dir1);
+ perror("");
+ exit(1);
+ }
dir_contents = tor_listdir(dirname);
- tt_assert(dir_contents);
+ test_assert(dir_contents);
/* make sure that each filename is listed. */
- tt_assert(smartlist_string_isin_case(dir_contents, "hopscotch"));
- tt_assert(smartlist_string_isin_case(dir_contents, "mumblety-peg"));
+ test_assert(smartlist_string_isin_case(dir_contents, "hopscotch"));
+ test_assert(smartlist_string_isin_case(dir_contents, "mumblety-peg"));
+ test_assert(smartlist_string_isin_case(dir_contents, ".hidden-file"));
+ test_assert(smartlist_string_isin_case(dir_contents, "some-directory"));
- tt_assert(!smartlist_string_isin(dir_contents, "."));
- tt_assert(!smartlist_string_isin(dir_contents, ".."));
+ test_assert(!smartlist_string_isin(dir_contents, "."));
+ test_assert(!smartlist_string_isin(dir_contents, ".."));
done:
tor_free(fname1);
@@ -1299,34 +2085,52 @@ test_util_parent_dir(void *ptr)
char *cp;
(void)ptr;
-#define T(input,expect_ok,output) \
+#define T(output,expect_ok,input) \
do { \
int ok; \
cp = tor_strdup(input); \
ok = get_parent_directory(cp); \
- tt_int_op(ok, ==, expect_ok); \
+ tt_int_op(expect_ok, ==, ok); \
if (ok==0) \
- tt_str_op(cp, ==, output); \
+ tt_str_op(output, ==, cp); \
tor_free(cp); \
} while (0);
- T("/home/wombat/knish", 0, "/home/wombat");
- T("/home/wombat/knish/", 0, "/home/wombat");
- T("./home/wombat/knish/", 0, "./home/wombat");
- T("./wombat", 0, ".");
- T("", -1, "");
- T("/", -1, "");
- T("////", -1, "");
+ T("/home/wombat", 0, "/home/wombat/knish");
+ T("/home/wombat", 0, "/home/wombat/knish/");
+ T("/home/wombat", 0, "/home/wombat/knish///");
+ T("./home/wombat", 0, "./home/wombat/knish/");
+ T("/", 0, "/home");
+ T("/", 0, "/home//");
+ T(".", 0, "./wombat");
+ T(".", 0, "./wombat/");
+ T(".", 0, "./wombat//");
+ T("wombat", 0, "wombat/foo");
+ T("wombat/..", 0, "wombat/../foo");
+ T("wombat/../", 0, "wombat/..//foo"); /* Is this correct? */
+ T("wombat/.", 0, "wombat/./foo");
+ T("wombat/./", 0, "wombat/.//foo"); /* Is this correct? */
+ T("wombat", 0, "wombat/..//");
+ T("wombat", 0, "wombat/foo/");
+ T("wombat", 0, "wombat/.foo");
+ T("wombat", 0, "wombat/.foo/");
+
+ T("wombat", -1, "");
+ T("w", -1, "");
+ T("wombat", 0, "wombat/knish");
+
+ T("/", 0, "/");
+ T("/", 0, "////");
done:
tor_free(cp);
}
-#ifdef MS_WINDOWS
+#ifdef _WIN32
static void
test_util_load_win_lib(void *ptr)
{
- HANDLE h = load_windows_system_library("advapi32.dll");
+ HANDLE h = load_windows_system_library(_T("advapi32.dll"));
(void) ptr;
tt_assert(h);
@@ -1337,6 +2141,506 @@ test_util_load_win_lib(void *ptr)
#endif
static void
+clear_hex_errno(char *hex_errno)
+{
+ memset(hex_errno, '\0', HEX_ERRNO_SIZE + 1);
+}
+
+static void
+test_util_exit_status(void *ptr)
+{
+ /* Leave an extra byte for a \0 so we can do string comparison */
+ char hex_errno[HEX_ERRNO_SIZE + 1];
+ int n;
+
+ (void)ptr;
+
+ clear_hex_errno(hex_errno);
+ n = format_helper_exit_status(0, 0, hex_errno);
+ test_streq("0/0\n", hex_errno);
+ test_eq(n, strlen(hex_errno));
+
+ clear_hex_errno(hex_errno);
+ n = format_helper_exit_status(0, 0x7FFFFFFF, hex_errno);
+ test_streq("0/7FFFFFFF\n", hex_errno);
+ test_eq(n, strlen(hex_errno));
+
+ clear_hex_errno(hex_errno);
+ n = format_helper_exit_status(0xFF, -0x80000000, hex_errno);
+ test_streq("FF/-80000000\n", hex_errno);
+ test_eq(n, strlen(hex_errno));
+
+ clear_hex_errno(hex_errno);
+ n = format_helper_exit_status(0x7F, 0, hex_errno);
+ test_streq("7F/0\n", hex_errno);
+ test_eq(n, strlen(hex_errno));
+
+ clear_hex_errno(hex_errno);
+ n = format_helper_exit_status(0x08, -0x242, hex_errno);
+ test_streq("8/-242\n", hex_errno);
+ test_eq(n, strlen(hex_errno));
+
+ done:
+ ;
+}
+
+#ifndef _WIN32
+/** Check that fgets waits until a full line, and not return a partial line, on
+ * a EAGAIN with a non-blocking pipe */
+static void
+test_util_fgets_eagain(void *ptr)
+{
+ int test_pipe[2] = {-1, -1};
+ int retval;
+ ssize_t retlen;
+ char *retptr;
+ FILE *test_stream = NULL;
+ char buf[10];
+
+ (void)ptr;
+
+ /* Set up a pipe to test on */
+ retval = pipe(test_pipe);
+ tt_int_op(retval, >=, 0);
+
+ /* Set up the read-end to be non-blocking */
+ retval = fcntl(test_pipe[0], F_SETFL, O_NONBLOCK);
+ tt_int_op(retval, >=, 0);
+
+ /* Open it as a stdio stream */
+ test_stream = fdopen(test_pipe[0], "r");
+ tt_ptr_op(test_stream, !=, NULL);
+
+ /* Send in a partial line */
+ retlen = write(test_pipe[1], "A", 1);
+ tt_int_op(retlen, ==, 1);
+ retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_want(retptr == NULL);
+ tt_int_op(errno, ==, EAGAIN);
+
+ /* Send in the rest */
+ retlen = write(test_pipe[1], "B\n", 2);
+ tt_int_op(retlen, ==, 2);
+ retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_ptr_op(retptr, ==, buf);
+ tt_str_op(buf, ==, "AB\n");
+
+ /* Send in a full line */
+ retlen = write(test_pipe[1], "CD\n", 3);
+ tt_int_op(retlen, ==, 3);
+ retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_ptr_op(retptr, ==, buf);
+ tt_str_op(buf, ==, "CD\n");
+
+ /* Send in a partial line */
+ retlen = write(test_pipe[1], "E", 1);
+ tt_int_op(retlen, ==, 1);
+ retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_ptr_op(retptr, ==, NULL);
+ tt_int_op(errno, ==, EAGAIN);
+
+ /* Send in the rest */
+ retlen = write(test_pipe[1], "F\n", 2);
+ tt_int_op(retlen, ==, 2);
+ retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_ptr_op(retptr, ==, buf);
+ tt_str_op(buf, ==, "EF\n");
+
+ /* Send in a full line and close */
+ retlen = write(test_pipe[1], "GH", 2);
+ tt_int_op(retlen, ==, 2);
+ retval = close(test_pipe[1]);
+ test_pipe[1] = -1;
+ tt_int_op(retval, ==, 0);
+ retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_ptr_op(retptr, ==, buf);
+ tt_str_op(buf, ==, "GH");
+
+ /* Check for EOF */
+ retptr = fgets(buf, sizeof(buf), test_stream);
+ tt_ptr_op(retptr, ==, NULL);
+ tt_int_op(feof(test_stream), >, 0);
+
+ 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
+
+/** Helper function for testing tor_spawn_background */
+static void
+run_util_spawn_background(const char *argv[], const char *expected_out,
+ const char *expected_err, int expected_exit,
+ int expected_status)
+{
+ int retval, exit_code;
+ ssize_t pos;
+ process_handle_t *process_handle=NULL;
+ char stdout_buf[100], stderr_buf[100];
+ int status;
+
+ /* Start the program */
+#ifdef _WIN32
+ status = tor_spawn_background(NULL, argv, NULL, &process_handle);
+#else
+ status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
+#endif
+
+ test_eq(expected_status, status);
+ if (status == PROCESS_STATUS_ERROR)
+ return;
+
+ test_assert(process_handle != NULL);
+ test_eq(expected_status, process_handle->status);
+
+#ifdef _WIN32
+ test_assert(process_handle->stdout_pipe != INVALID_HANDLE_VALUE);
+ test_assert(process_handle->stderr_pipe != INVALID_HANDLE_VALUE);
+#else
+ test_assert(process_handle->stdout_pipe > 0);
+ test_assert(process_handle->stderr_pipe > 0);
+#endif
+
+ /* Check stdout */
+ pos = tor_read_all_from_process_stdout(process_handle, stdout_buf,
+ sizeof(stdout_buf) - 1);
+ tt_assert(pos >= 0);
+ stdout_buf[pos] = '\0';
+ test_eq(strlen(expected_out), pos);
+ test_streq(expected_out, stdout_buf);
+
+ /* Check it terminated correctly */
+ retval = tor_get_exit_code(process_handle, 1, &exit_code);
+ test_eq(PROCESS_EXIT_EXITED, retval);
+ test_eq(expected_exit, exit_code);
+ // TODO: Make test-child exit with something other than 0
+
+ /* Check stderr */
+ pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
+ sizeof(stderr_buf) - 1);
+ test_assert(pos >= 0);
+ stderr_buf[pos] = '\0';
+ test_streq(expected_err, stderr_buf);
+ test_eq(strlen(expected_err), pos);
+
+ done:
+ if (process_handle)
+ tor_process_handle_destroy(process_handle, 1);
+}
+
+/** Check that we can launch a process and read the output */
+static void
+test_util_spawn_background_ok(void *ptr)
+{
+#ifdef _WIN32
+ const char *argv[] = {"test-child.exe", "--test", NULL};
+ const char *expected_out = "OUT\r\n--test\r\nSLEEPING\r\nDONE\r\n";
+ const char *expected_err = "ERR\r\n";
+#else
+ const char *argv[] = {BUILDDIR "/src/test/test-child", "--test", NULL};
+ const char *expected_out = "OUT\n--test\nSLEEPING\nDONE\n";
+ const char *expected_err = "ERR\n";
+#endif
+
+ (void)ptr;
+
+ run_util_spawn_background(argv, expected_out, expected_err, 0,
+ PROCESS_STATUS_RUNNING);
+}
+
+/** Check that failing to find the executable works as expected */
+static void
+test_util_spawn_background_fail(void *ptr)
+{
+#ifndef BUILDDIR
+#define BUILDDIR "."
+#endif
+ const char *argv[] = {BUILDDIR "/src/test/no-such-file", "--test", NULL};
+ const char *expected_err = "";
+ char expected_out[1024];
+ char code[32];
+#ifdef _WIN32
+ const int expected_status = PROCESS_STATUS_ERROR;
+#else
+ /* TODO: Once we can signal failure to exec, set this to be
+ * PROCESS_STATUS_ERROR */
+ const int expected_status = PROCESS_STATUS_RUNNING;
+#endif
+
+ (void)ptr;
+
+ tor_snprintf(code, sizeof(code), "%x/%x",
+ 9 /* CHILD_STATE_FAILEXEC */ , ENOENT);
+ tor_snprintf(expected_out, sizeof(expected_out),
+ "ERR: Failed to spawn background process - code %s\n", code);
+
+ run_util_spawn_background(argv, expected_out, expected_err, 255,
+ expected_status);
+}
+
+/** Test that reading from a handle returns a partial read rather than
+ * blocking */
+static void
+test_util_spawn_background_partial_read(void *ptr)
+{
+ const int expected_exit = 0;
+ const int expected_status = PROCESS_STATUS_RUNNING;
+
+ int retval, exit_code;
+ ssize_t pos = -1;
+ process_handle_t *process_handle=NULL;
+ int status;
+ char stdout_buf[100], stderr_buf[100];
+#ifdef _WIN32
+ const char *argv[] = {"test-child.exe", "--test", NULL};
+ const char *expected_out[] = { "OUT\r\n--test\r\nSLEEPING\r\n",
+ "DONE\r\n",
+ NULL };
+ const char *expected_err = "ERR\r\n";
+#else
+ const char *argv[] = {BUILDDIR "/src/test/test-child", "--test", NULL};
+ const char *expected_out[] = { "OUT\n--test\nSLEEPING\n",
+ "DONE\n",
+ NULL };
+ const char *expected_err = "ERR\n";
+ int eof = 0;
+#endif
+ int expected_out_ctr;
+ (void)ptr;
+
+ /* Start the program */
+#ifdef _WIN32
+ status = tor_spawn_background(NULL, argv, NULL, &process_handle);
+#else
+ status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
+#endif
+ test_eq(expected_status, status);
+ test_assert(process_handle);
+ test_eq(expected_status, process_handle->status);
+
+ /* Check stdout */
+ for (expected_out_ctr = 0; expected_out[expected_out_ctr] != NULL;) {
+#ifdef _WIN32
+ pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
+ sizeof(stdout_buf) - 1, NULL);
+#else
+ /* Check that we didn't read the end of file last time */
+ test_assert(!eof);
+ pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
+ sizeof(stdout_buf) - 1, NULL, &eof);
+#endif
+ log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos);
+
+ /* We would have blocked, keep on trying */
+ if (0 == pos)
+ continue;
+
+ test_assert(pos > 0);
+ stdout_buf[pos] = '\0';
+ test_streq(expected_out[expected_out_ctr], stdout_buf);
+ test_eq(strlen(expected_out[expected_out_ctr]), pos);
+ expected_out_ctr++;
+ }
+
+ /* The process should have exited without writing more */
+#ifdef _WIN32
+ pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
+ sizeof(stdout_buf) - 1,
+ process_handle);
+ test_eq(0, pos);
+#else
+ if (!eof) {
+ /* We should have got all the data, but maybe not the EOF flag */
+ pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
+ sizeof(stdout_buf) - 1,
+ process_handle, &eof);
+ test_eq(0, pos);
+ test_assert(eof);
+ }
+ /* Otherwise, we got the EOF on the last read */
+#endif
+
+ /* Check it terminated correctly */
+ retval = tor_get_exit_code(process_handle, 1, &exit_code);
+ test_eq(PROCESS_EXIT_EXITED, retval);
+ test_eq(expected_exit, exit_code);
+
+ // TODO: Make test-child exit with something other than 0
+
+ /* Check stderr */
+ pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
+ sizeof(stderr_buf) - 1);
+ test_assert(pos >= 0);
+ stderr_buf[pos] = '\0';
+ test_streq(expected_err, stderr_buf);
+ test_eq(strlen(expected_err), pos);
+
+ done:
+ tor_process_handle_destroy(process_handle, 1);
+}
+
+/**
+ * Test for format_hex_number_for_helper_exit_status()
+ */
+
+static void
+test_util_format_hex_number(void *ptr)
+{
+ int i, len;
+ char buf[HEX_ERRNO_SIZE + 1];
+ const struct {
+ const char *str;
+ unsigned int x;
+ } test_data[] = {
+ {"0", 0},
+ {"1", 1},
+ {"273A", 0x273a},
+ {"FFFF", 0xffff},
+#if UINT_MAX >= 0xffffffff
+ {"31BC421D", 0x31bc421d},
+ {"FFFFFFFF", 0xffffffff},
+#endif
+ {NULL, 0}
+ };
+
+ (void)ptr;
+
+ for (i = 0; test_data[i].str != NULL; ++i) {
+ len = format_hex_number_for_helper_exit_status(test_data[i].x,
+ buf, HEX_ERRNO_SIZE);
+ test_neq(len, 0);
+ buf[len] = '\0';
+ test_streq(buf, test_data[i].str);
+ }
+
+ done:
+ return;
+}
+
+/**
+ * Test that we can properly format q Windows command line
+ */
+static void
+test_util_join_win_cmdline(void *ptr)
+{
+ /* Based on some test cases from "Parsing C++ Command-Line Arguments" in
+ * MSDN but we don't exercise all quoting rules because tor_join_win_cmdline
+ * will try to only generate simple cases for the child process to parse;
+ * i.e. we never embed quoted strings in arguments. */
+
+ const char *argvs[][4] = {
+ {"a", "bb", "CCC", NULL}, // Normal
+ {NULL, NULL, NULL, NULL}, // Empty argument list
+ {"", NULL, NULL, NULL}, // Empty argument
+ {"\"a", "b\"b", "CCC\"", NULL}, // Quotes
+ {"a\tbc", "dd dd", "E", NULL}, // Whitespace
+ {"a\\\\\\b", "de fg", "H", NULL}, // Backslashes
+ {"a\\\"b", "\\c", "D\\", NULL}, // Backslashes before quote
+ {"a\\\\b c", "d", "E", NULL}, // Backslashes not before quote
+ { NULL } // Terminator
+ };
+
+ const char *cmdlines[] = {
+ "a bb CCC",
+ "",
+ "\"\"",
+ "\\\"a b\\\"b CCC\\\"",
+ "\"a\tbc\" \"dd dd\" E",
+ "a\\\\\\b \"de fg\" H",
+ "a\\\\\\\"b \\c D\\",
+ "\"a\\\\b c\" d E",
+ NULL // Terminator
+ };
+
+ int i;
+ char *joined_argv;
+
+ (void)ptr;
+
+ for (i=0; cmdlines[i]!=NULL; i++) {
+ log_info(LD_GENERAL, "Joining argvs[%d], expecting <%s>", i, cmdlines[i]);
+ joined_argv = tor_join_win_cmdline(argvs[i]);
+ test_streq(cmdlines[i], joined_argv);
+ tor_free(joined_argv);
+ }
+
+ done:
+ ;
+}
+
+#define MAX_SPLIT_LINE_COUNT 4
+struct split_lines_test_t {
+ const char *orig_line; // Line to be split (may contain \0's)
+ int orig_length; // Length of orig_line
+ const char *split_line[MAX_SPLIT_LINE_COUNT]; // Split lines
+};
+
+/**
+ * Test that we properly split a buffer into lines
+ */
+static void
+test_util_split_lines(void *ptr)
+{
+ /* Test cases. orig_line of last test case must be NULL.
+ * The last element of split_line[i] must be NULL. */
+ struct split_lines_test_t tests[] = {
+ {"", 0, {NULL}},
+ {"foo", 3, {"foo", NULL}},
+ {"\n\rfoo\n\rbar\r\n", 12, {"foo", "bar", NULL}},
+ {"fo o\r\nb\tar", 10, {"fo o", "b.ar", NULL}},
+ {"\x0f""f\0o\0\n\x01""b\0r\0\r", 12, {".f.o.", ".b.r.", NULL}},
+ {"line 1\r\nline 2", 14, {"line 1", "line 2", NULL}},
+ {"line 1\r\n\r\nline 2", 16, {"line 1", "line 2", NULL}},
+ {"line 1\r\n\r\r\r\nline 2", 18, {"line 1", "line 2", NULL}},
+ {"line 1\r\n\n\n\n\rline 2", 18, {"line 1", "line 2", NULL}},
+ {"line 1\r\n\r\t\r\nline 3", 18, {"line 1", ".", "line 3", NULL}},
+ {"\n\t\r\t\nline 3", 11, {".", ".", "line 3", NULL}},
+ {NULL, 0, { NULL }}
+ };
+
+ int i, j;
+ char *orig_line=NULL;
+ smartlist_t *sl=NULL;
+
+ (void)ptr;
+
+ for (i=0; tests[i].orig_line; i++) {
+ sl = smartlist_new();
+ /* Allocate space for string and trailing NULL */
+ orig_line = tor_memdup(tests[i].orig_line, tests[i].orig_length + 1);
+ tor_split_lines(sl, orig_line, tests[i].orig_length);
+
+ j = 0;
+ log_info(LD_GENERAL, "Splitting test %d of length %d",
+ i, tests[i].orig_length);
+ SMARTLIST_FOREACH_BEGIN(sl, const char *, line) {
+ /* Check we have not got too many lines */
+ test_assert(j < MAX_SPLIT_LINE_COUNT);
+ /* Check that there actually should be a line here */
+ test_assert(tests[i].split_line[j] != 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 */
+ test_streq(line, tests[i].split_line[j]);
+ j++;
+ } SMARTLIST_FOREACH_END(line);
+ /* Check that we didn't miss some lines */
+ test_eq_ptr(NULL, tests[i].split_line[j]);
+ tor_free(orig_line);
+ smartlist_free(sl);
+ sl = NULL;
+ }
+
+ done:
+ tor_free(orig_line);
+ smartlist_free(sl);
+}
+
+static void
test_util_di_ops(void)
{
#define LT -1
@@ -1389,6 +2693,389 @@ test_util_di_ops(void)
;
}
+/**
+ * Test counting high bits
+ */
+static void
+test_util_n_bits_set(void *ptr)
+{
+ (void)ptr;
+ test_eq(0, n_bits_set_u8(0));
+ test_eq(1, n_bits_set_u8(1));
+ test_eq(3, n_bits_set_u8(7));
+ test_eq(1, n_bits_set_u8(8));
+ test_eq(2, n_bits_set_u8(129));
+ test_eq(8, n_bits_set_u8(255));
+ done:
+ ;
+}
+
+/**
+ * Test LHS whitespace (and comment) eater
+ */
+static void
+test_util_eat_whitespace(void *ptr)
+{
+ const char ws[] = { ' ', '\t', '\r' }; /* Except NL */
+ char str[80];
+ size_t i;
+
+ (void)ptr;
+
+ /* Try one leading ws */
+ strcpy(str, "fuubaar");
+ for (i = 0; i < sizeof(ws); ++i) {
+ str[0] = ws[i];
+ test_eq_ptr(str + 1, eat_whitespace(str));
+ test_eq_ptr(str + 1, eat_whitespace_eos(str, str + strlen(str)));
+ test_eq_ptr(str + 1, eat_whitespace_no_nl(str));
+ test_eq_ptr(str + 1, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+ }
+ str[0] = '\n';
+ test_eq_ptr(str + 1, eat_whitespace(str));
+ test_eq_ptr(str + 1, eat_whitespace_eos(str, str + strlen(str)));
+ test_eq_ptr(str, eat_whitespace_no_nl(str));
+ test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+
+ /* Empty string */
+ strcpy(str, "");
+ test_eq_ptr(str, eat_whitespace(str));
+ test_eq_ptr(str, eat_whitespace_eos(str, str));
+ test_eq_ptr(str, eat_whitespace_no_nl(str));
+ test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str));
+
+ /* Only ws */
+ strcpy(str, " \t\r\n");
+ test_eq_ptr(str + strlen(str), eat_whitespace(str));
+ test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str)));
+ test_eq_ptr(str + strlen(str) - 1,
+ eat_whitespace_no_nl(str));
+ test_eq_ptr(str + strlen(str) - 1,
+ eat_whitespace_eos_no_nl(str, str + strlen(str)));
+
+ strcpy(str, " \t\r ");
+ test_eq_ptr(str + strlen(str), eat_whitespace(str));
+ test_eq_ptr(str + strlen(str),
+ eat_whitespace_eos(str, str + strlen(str)));
+ test_eq_ptr(str + strlen(str), eat_whitespace_no_nl(str));
+ test_eq_ptr(str + strlen(str),
+ eat_whitespace_eos_no_nl(str, str + strlen(str)));
+
+ /* Multiple ws */
+ strcpy(str, "fuubaar");
+ for (i = 0; i < sizeof(ws); ++i)
+ str[i] = ws[i];
+ test_eq_ptr(str + sizeof(ws), eat_whitespace(str));
+ test_eq_ptr(str + sizeof(ws), eat_whitespace_eos(str, str + strlen(str)));
+ test_eq_ptr(str + sizeof(ws), eat_whitespace_no_nl(str));
+ test_eq_ptr(str + sizeof(ws),
+ eat_whitespace_eos_no_nl(str, str + strlen(str)));
+
+ /* Eat comment */
+ strcpy(str, "# Comment \n No Comment");
+ test_streq("No Comment", eat_whitespace(str));
+ test_streq("No Comment", eat_whitespace_eos(str, str + strlen(str)));
+ test_eq_ptr(str, eat_whitespace_no_nl(str));
+ test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+
+ /* Eat comment & ws mix */
+ strcpy(str, " # \t Comment \n\t\nNo Comment");
+ test_streq("No Comment", eat_whitespace(str));
+ test_streq("No Comment", eat_whitespace_eos(str, str + strlen(str)));
+ test_eq_ptr(str + 1, eat_whitespace_no_nl(str));
+ test_eq_ptr(str + 1, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+
+ /* Eat entire comment */
+ strcpy(str, "#Comment");
+ test_eq_ptr(str + strlen(str), eat_whitespace(str));
+ test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str)));
+ test_eq_ptr(str, eat_whitespace_no_nl(str));
+ test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+
+ /* Blank line, then comment */
+ strcpy(str, " \t\n # Comment");
+ test_eq_ptr(str + strlen(str), eat_whitespace(str));
+ test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str)));
+ test_eq_ptr(str + 2, eat_whitespace_no_nl(str));
+ test_eq_ptr(str + 2, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+
+ done:
+ ;
+}
+
+/** Return a newly allocated smartlist containing the lines of text in
+ * <b>lines</b>. The returned strings are heap-allocated, and must be
+ * freed by the caller.
+ *
+ * XXXX? Move to container.[hc] ? */
+static smartlist_t *
+smartlist_new_from_text_lines(const char *lines)
+{
+ smartlist_t *sl = smartlist_new();
+ char *last_line;
+
+ smartlist_split_string(sl, lines, "\n", 0, 0);
+
+ last_line = smartlist_pop_last(sl);
+ if (last_line != NULL && *last_line != '\0') {
+ smartlist_add(sl, last_line);
+ }
+
+ return sl;
+}
+
+/** Test smartlist_new_from_text_lines */
+static void
+test_util_sl_new_from_text_lines(void *ptr)
+{
+ (void)ptr;
+
+ { /* Normal usage */
+ smartlist_t *sl = smartlist_new_from_text_lines("foo\nbar\nbaz\n");
+ int sl_len = smartlist_len(sl);
+
+ tt_want_int_op(sl_len, ==, 3);
+
+ if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo");
+ if (sl_len > 1) tt_want_str_op(smartlist_get(sl, 1), ==, "bar");
+ if (sl_len > 2) tt_want_str_op(smartlist_get(sl, 2), ==, "baz");
+
+ SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
+ smartlist_free(sl);
+ }
+
+ { /* No final newline */
+ smartlist_t *sl = smartlist_new_from_text_lines("foo\nbar\nbaz");
+ int sl_len = smartlist_len(sl);
+
+ tt_want_int_op(sl_len, ==, 3);
+
+ if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo");
+ if (sl_len > 1) tt_want_str_op(smartlist_get(sl, 1), ==, "bar");
+ if (sl_len > 2) tt_want_str_op(smartlist_get(sl, 2), ==, "baz");
+
+ SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
+ smartlist_free(sl);
+ }
+
+ { /* No newlines */
+ smartlist_t *sl = smartlist_new_from_text_lines("foo");
+ int sl_len = smartlist_len(sl);
+
+ tt_want_int_op(sl_len, ==, 1);
+
+ if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo");
+
+ SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
+ smartlist_free(sl);
+ }
+
+ { /* No text at all */
+ smartlist_t *sl = smartlist_new_from_text_lines("");
+ int sl_len = smartlist_len(sl);
+
+ tt_want_int_op(sl_len, ==, 0);
+
+ SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
+ smartlist_free(sl);
+ }
+}
+
+static void
+test_util_envnames(void *ptr)
+{
+ (void) ptr;
+
+ tt_assert(environment_variable_names_equal("abc", "abc"));
+ tt_assert(environment_variable_names_equal("abc", "abc="));
+ tt_assert(environment_variable_names_equal("abc", "abc=def"));
+ tt_assert(environment_variable_names_equal("abc=def", "abc"));
+ tt_assert(environment_variable_names_equal("abc=def", "abc=ghi"));
+
+ tt_assert(environment_variable_names_equal("abc", "abc"));
+ tt_assert(environment_variable_names_equal("abc", "abc="));
+ tt_assert(environment_variable_names_equal("abc", "abc=def"));
+ tt_assert(environment_variable_names_equal("abc=def", "abc"));
+ tt_assert(environment_variable_names_equal("abc=def", "abc=ghi"));
+
+ tt_assert(!environment_variable_names_equal("abc", "abcd"));
+ tt_assert(!environment_variable_names_equal("abc=", "abcd"));
+ tt_assert(!environment_variable_names_equal("abc=", "abcd"));
+ tt_assert(!environment_variable_names_equal("abc=", "def"));
+ tt_assert(!environment_variable_names_equal("abc=", "def="));
+ tt_assert(!environment_variable_names_equal("abc=x", "def=x"));
+
+ tt_assert(!environment_variable_names_equal("", "a=def"));
+ /* A bit surprising. */
+ tt_assert(environment_variable_names_equal("", "=def"));
+ tt_assert(environment_variable_names_equal("=y", "=x"));
+
+ done:
+ ;
+}
+
+/** Test process_environment_make */
+static void
+test_util_make_environment(void *ptr)
+{
+ const char *env_vars_string =
+ "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\n"
+ "HOME=/home/foozer\n";
+ const char expected_windows_env_block[] =
+ "HOME=/home/foozer\000"
+ "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\000"
+ "\000";
+ size_t expected_windows_env_block_len =
+ sizeof(expected_windows_env_block) - 1;
+
+ smartlist_t *env_vars = smartlist_new_from_text_lines(env_vars_string);
+ smartlist_t *env_vars_sorted = smartlist_new();
+ smartlist_t *env_vars_in_unixoid_env_block_sorted = smartlist_new();
+
+ process_environment_t *env;
+
+ (void)ptr;
+
+ env = process_environment_make(env_vars);
+
+ /* Check that the Windows environment block is correct. */
+ tt_want(tor_memeq(expected_windows_env_block, env->windows_environment_block,
+ expected_windows_env_block_len));
+
+ /* Now for the Unixoid environment block. We don't care which order
+ * these environment variables are in, so we sort both lists first. */
+
+ smartlist_add_all(env_vars_sorted, env_vars);
+
+ {
+ char **v;
+ for (v = env->unixoid_environment_block; *v; ++v) {
+ smartlist_add(env_vars_in_unixoid_env_block_sorted, *v);
+ }
+ }
+
+ smartlist_sort_strings(env_vars_sorted);
+ smartlist_sort_strings(env_vars_in_unixoid_env_block_sorted);
+
+ tt_want_int_op(smartlist_len(env_vars_sorted), ==,
+ smartlist_len(env_vars_in_unixoid_env_block_sorted));
+ {
+ int len = smartlist_len(env_vars_sorted);
+ int i;
+
+ if (smartlist_len(env_vars_in_unixoid_env_block_sorted) < len) {
+ len = smartlist_len(env_vars_in_unixoid_env_block_sorted);
+ }
+
+ for (i = 0; i < len; ++i) {
+ tt_want_str_op(smartlist_get(env_vars_sorted, i), ==,
+ smartlist_get(env_vars_in_unixoid_env_block_sorted, i));
+ }
+ }
+
+ /* Clean up. */
+ smartlist_free(env_vars_in_unixoid_env_block_sorted);
+ smartlist_free(env_vars_sorted);
+
+ SMARTLIST_FOREACH(env_vars, char *, x, tor_free(x));
+ smartlist_free(env_vars);
+
+ process_environment_free(env);
+}
+
+/** Test set_environment_variable_in_smartlist */
+static void
+test_util_set_env_var_in_sl(void *ptr)
+{
+ /* The environment variables in these strings are in arbitrary
+ * order; we sort the resulting lists before comparing them.
+ *
+ * (They *will not* end up in the order shown in
+ * expected_resulting_env_vars_string.) */
+
+ const char *base_env_vars_string =
+ "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\n"
+ "HOME=/home/foozer\n"
+ "TERM=xterm\n"
+ "SHELL=/bin/ksh\n"
+ "USER=foozer\n"
+ "LOGNAME=foozer\n"
+ "USERNAME=foozer\n"
+ "LANG=en_US.utf8\n"
+ ;
+
+ const char *new_env_vars_string =
+ "TERM=putty\n"
+ "DISPLAY=:18.0\n"
+ ;
+
+ const char *expected_resulting_env_vars_string =
+ "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\n"
+ "HOME=/home/foozer\n"
+ "TERM=putty\n"
+ "SHELL=/bin/ksh\n"
+ "USER=foozer\n"
+ "LOGNAME=foozer\n"
+ "USERNAME=foozer\n"
+ "LANG=en_US.utf8\n"
+ "DISPLAY=:18.0\n"
+ ;
+
+ smartlist_t *merged_env_vars =
+ smartlist_new_from_text_lines(base_env_vars_string);
+ smartlist_t *new_env_vars =
+ smartlist_new_from_text_lines(new_env_vars_string);
+ smartlist_t *expected_resulting_env_vars =
+ smartlist_new_from_text_lines(expected_resulting_env_vars_string);
+
+ /* Elements of merged_env_vars are heap-allocated, and must be
+ * freed. Some of them are (or should) be freed by
+ * set_environment_variable_in_smartlist.
+ *
+ * Elements of new_env_vars are heap-allocated, but are copied into
+ * merged_env_vars, so they are not freed separately at the end of
+ * the function.
+ *
+ * Elements of expected_resulting_env_vars are heap-allocated, and
+ * must be freed. */
+
+ (void)ptr;
+
+ SMARTLIST_FOREACH(new_env_vars, char *, env_var,
+ set_environment_variable_in_smartlist(merged_env_vars,
+ env_var,
+ _tor_free,
+ 1));
+
+ smartlist_sort_strings(merged_env_vars);
+ smartlist_sort_strings(expected_resulting_env_vars);
+
+ tt_want_int_op(smartlist_len(merged_env_vars), ==,
+ smartlist_len(expected_resulting_env_vars));
+ {
+ int len = smartlist_len(merged_env_vars);
+ int i;
+
+ if (smartlist_len(expected_resulting_env_vars) < len) {
+ len = smartlist_len(expected_resulting_env_vars);
+ }
+
+ for (i = 0; i < len; ++i) {
+ tt_want_str_op(smartlist_get(merged_env_vars, i), ==,
+ smartlist_get(expected_resulting_env_vars, i));
+ }
+ }
+
+ /* Clean up. */
+ SMARTLIST_FOREACH(merged_env_vars, char *, x, tor_free(x));
+ smartlist_free(merged_env_vars);
+
+ smartlist_free(new_env_vars);
+
+ SMARTLIST_FOREACH(expected_resulting_env_vars, char *, x, tor_free(x));
+ smartlist_free(expected_resulting_env_vars);
+}
+
#define UTIL_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name }
@@ -1399,6 +3086,12 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(time),
UTIL_TEST(parse_http_time, 0),
UTIL_LEGACY(config_line),
+ UTIL_LEGACY(config_line_quotes),
+ UTIL_LEGACY(config_line_comment_character),
+ UTIL_LEGACY(config_line_escaped_content),
+#ifndef _WIN32
+ UTIL_LEGACY(expand_filename),
+#endif
UTIL_LEGACY(strmisc),
UTIL_LEGACY(pow2),
UTIL_LEGACY(gzip),
@@ -1409,15 +3102,33 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(mmap),
UTIL_LEGACY(threads),
UTIL_LEGACY(sscanf),
+ UTIL_LEGACY(path_is_relative),
UTIL_LEGACY(strtok),
UTIL_LEGACY(di_ops),
UTIL_TEST(find_str_at_start_of_line, 0),
+ UTIL_TEST(string_is_C_identifier, 0),
UTIL_TEST(asprintf, 0),
UTIL_TEST(listdir, 0),
UTIL_TEST(parent_dir, 0),
-#ifdef MS_WINDOWS
+#ifdef _WIN32
UTIL_TEST(load_win_lib, 0),
#endif
+ UTIL_TEST(exit_status, 0),
+#ifndef _WIN32
+ UTIL_TEST(fgets_eagain, TT_SKIP),
+#endif
+ UTIL_TEST(spawn_background_ok, 0),
+ UTIL_TEST(spawn_background_fail, 0),
+ UTIL_TEST(spawn_background_partial_read, 0),
+ UTIL_TEST(format_hex_number, 0),
+ UTIL_TEST(join_win_cmdline, 0),
+ UTIL_TEST(split_lines, 0),
+ UTIL_TEST(n_bits_set, 0),
+ UTIL_TEST(eat_whitespace, 0),
+ UTIL_TEST(sl_new_from_text_lines, 0),
+ UTIL_TEST(envnames, 0),
+ UTIL_TEST(make_environment, 0),
+ UTIL_TEST(set_env_var_in_sl, 0),
END_OF_TESTCASES
};
diff --git a/src/test/tinytest.c b/src/test/tinytest.c
index 11ffc2fe56..4d9afacce4 100644
--- a/src/test/tinytest.c
+++ b/src/test/tinytest.c
@@ -1,4 +1,4 @@
-/* tinytest.c -- Copyright 2009-2010 Nick Mathewson
+/* tinytest.c -- Copyright 2009-2012 Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -22,13 +22,16 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifdef TINYTEST_LOCAL
+#include "tinytest_local.h"
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <windows.h>
#else
#include <sys/types.h>
@@ -40,9 +43,6 @@
#define __attribute__(x)
#endif
-#ifdef TINYTEST_LOCAL
-#include "tinytest_local.h"
-#endif
#include "tinytest.h"
#include "tinytest_macros.h"
@@ -64,16 +64,16 @@ const char *cur_test_prefix = NULL; /**< prefix of the current test group */
/** Name of the current test, if we haven't logged is yet. Used for --quiet */
const char *cur_test_name = NULL;
-#ifdef WIN32
-/** Pointer to argv[0] for win32. */
-static const char *commandname = NULL;
+#ifdef _WIN32
+/* Copy of argv[0] for win32. */
+static char commandname[MAX_PATH+1];
#endif
static void usage(struct testgroup_t *groups, int list_groups)
__attribute__((noreturn));
static enum outcome
-_testcase_run_bare(const struct testcase_t *testcase)
+testcase_run_bare_(const struct testcase_t *testcase)
{
void *env = NULL;
int outcome;
@@ -100,10 +100,10 @@ _testcase_run_bare(const struct testcase_t *testcase)
#define MAGIC_EXITCODE 42
static enum outcome
-_testcase_run_forked(const struct testgroup_t *group,
+testcase_run_forked_(const struct testgroup_t *group,
const struct testcase_t *testcase)
{
-#ifdef WIN32
+#ifdef _WIN32
/* Fork? On Win32? How primitive! We'll do what the smart kids do:
we'll invoke our own exe (whose name we recall from the command
line) with a command line that tells it to run just the test we
@@ -119,7 +119,7 @@ _testcase_run_forked(const struct testgroup_t *group,
DWORD exitcode;
if (!in_tinytest_main) {
- printf("\nERROR. On Windows, _testcase_run_forked must be"
+ printf("\nERROR. On Windows, testcase_run_forked_ must be"
" called from within tinytest_main.\n");
abort();
}
@@ -165,7 +165,7 @@ _testcase_run_forked(const struct testgroup_t *group,
int test_r, write_r;
char b[1];
close(outcome_pipe[0]);
- test_r = _testcase_run_bare(testcase);
+ test_r = testcase_run_bare_(testcase);
assert(0<=(int)test_r && (int)test_r<=2);
b[0] = "NYS"[test_r];
write_r = (int)write(outcome_pipe[1], b, 1);
@@ -174,6 +174,7 @@ _testcase_run_forked(const struct testgroup_t *group,
exit(1);
}
exit(0);
+ return FAIL; /* unreachable */
} else {
/* parent */
int status, r;
@@ -218,9 +219,9 @@ testcase_run_one(const struct testgroup_t *group,
}
if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
- outcome = _testcase_run_forked(group, testcase);
+ outcome = testcase_run_forked_(group, testcase);
} else {
- outcome = _testcase_run_bare(testcase);
+ outcome = testcase_run_bare_(testcase);
}
if (outcome == OK) {
@@ -239,13 +240,14 @@ testcase_run_one(const struct testgroup_t *group,
if (opt_forked) {
exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
+ return 1; /* unreachable */
} else {
return (int)outcome;
}
}
int
-_tinytest_set_flag(struct testgroup_t *groups, const char *arg, unsigned long flag)
+tinytest_set_flag_(struct testgroup_t *groups, const char *arg, unsigned long flag)
{
int i, j;
size_t length = LONGEST_TEST_NAME;
@@ -277,7 +279,7 @@ usage(struct testgroup_t *groups, int list_groups)
puts(" Use --list-tests for a list of tests.");
if (list_groups) {
puts("Known tests are:");
- _tinytest_set_flag(groups, "..", 0);
+ tinytest_set_flag_(groups, "..", 0);
}
exit(0);
}
@@ -287,8 +289,13 @@ tinytest_main(int c, const char **v, struct testgroup_t *groups)
{
int i, j, n=0;
-#ifdef WIN32
- commandname = v[0];
+#ifdef _WIN32
+ const char *sp = strrchr(v[0], '.');
+ const char *extension = "";
+ if (!sp || stricmp(sp, ".exe"))
+ extension = ".exe"; /* Add an exe so CreateProcess will work */
+ snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
+ commandname[MAX_PATH]='\0';
#endif
for (i=1; i<c; ++i) {
if (v[i][0] == '-') {
@@ -315,28 +322,28 @@ tinytest_main(int c, const char **v, struct testgroup_t *groups)
}
} else {
const char *test = v[i];
- int flag = _TT_ENABLED;
+ int flag = TT_ENABLED_;
if (test[0] == ':') {
++test;
flag = TT_SKIP;
} else {
++n;
}
- if (!_tinytest_set_flag(groups, test, flag)) {
+ if (!tinytest_set_flag_(groups, test, flag)) {
printf("No such test as %s!\n", v[i]);
return -1;
}
}
}
if (!n)
- _tinytest_set_flag(groups, "..", _TT_ENABLED);
+ tinytest_set_flag_(groups, "..", TT_ENABLED_);
setvbuf(stdout, NULL, _IONBF, 0);
++in_tinytest_main;
for (i=0; groups[i].prefix; ++i)
for (j=0; groups[i].cases[j].name; ++j)
- if (groups[i].cases[j].flags & _TT_ENABLED)
+ if (groups[i].cases[j].flags & TT_ENABLED_)
testcase_run_one(&groups[i],
&groups[i].cases[j]);
@@ -355,13 +362,13 @@ tinytest_main(int c, const char **v, struct testgroup_t *groups)
}
int
-_tinytest_get_verbosity(void)
+tinytest_get_verbosity_(void)
{
return opt_verbosity;
}
void
-_tinytest_set_test_failed(void)
+tinytest_set_test_failed_(void)
{
if (opt_verbosity <= 0 && cur_test_name) {
if (opt_verbosity==0) puts("");
@@ -372,7 +379,7 @@ _tinytest_set_test_failed(void)
}
void
-_tinytest_set_test_skipped(void)
+tinytest_set_test_skipped_(void)
{
if (cur_test_outcome==OK)
cur_test_outcome = SKIP;
diff --git a/src/test/tinytest.h b/src/test/tinytest.h
index cbe28b7f51..bcac9f079c 100644
--- a/src/test/tinytest.h
+++ b/src/test/tinytest.h
@@ -1,4 +1,4 @@
-/* tinytest.h -- Copyright 2009-2010 Nick Mathewson
+/* tinytest.h -- Copyright 2009-2012 Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,15 +23,15 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef _TINYTEST_H
-#define _TINYTEST_H
+#ifndef TINYTEST_H_INCLUDED_
+#define TINYTEST_H_INCLUDED_
/** Flag for a test that needs to run in a subprocess. */
#define TT_FORK (1<<0)
/** Runtime flag for a test we've decided to skip. */
#define TT_SKIP (1<<1)
/** Internal runtime flag for a test we've decided to run. */
-#define _TT_ENABLED (1<<2)
+#define TT_ENABLED_ (1<<2)
/** If you add your own flags, make them start at this point. */
#define TT_FIRST_USER_FLAG (1<<3)
@@ -65,18 +65,18 @@ struct testgroup_t {
#define END_OF_GROUPS { NULL, NULL}
/** Implementation: called from a test to indicate failure, before logging. */
-void _tinytest_set_test_failed(void);
+void tinytest_set_test_failed_(void);
/** Implementation: called from a test to indicate that we're skipping. */
-void _tinytest_set_test_skipped(void);
+void tinytest_set_test_skipped_(void);
/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */
-int _tinytest_get_verbosity(void);
+int tinytest_get_verbosity_(void);
/** Implementation: Set a flag on tests matching a name; returns number
* of tests that matched. */
-int _tinytest_set_flag(struct testgroup_t *, const char *, unsigned long);
+int tinytest_set_flag_(struct testgroup_t *, const char *, unsigned long);
/** Set all tests in 'groups' matching the name 'named' to be skipped. */
#define tinytest_skip(groups, named) \
- _tinytest_set_flag(groups, named, TT_SKIP)
+ tinytest_set_flag_(groups, named, TT_SKIP)
/** Run a single testcase in a single group. */
int testcase_run_one(const struct testgroup_t *,const struct testcase_t *);
diff --git a/src/test/tinytest_demo.c b/src/test/tinytest_demo.c
index 4d2f588435..be95ce4c1d 100644
--- a/src/test/tinytest_demo.c
+++ b/src/test/tinytest_demo.c
@@ -1,4 +1,4 @@
-/* tinytest_demo.c -- Copyright 2009 Nick Mathewson
+/* tinytest_demo.c -- Copyright 2009-2012 Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -53,7 +53,7 @@ test_strcmp(void *data)
}
/* Pretty often, calling tt_abort_msg to indicate failure is more
- heavy-weight than you want. Instead, just say: */
+ heavy-weight than you want. Instead, just say: */
tt_assert(strcmp("testcase", "testcase") == 0);
/* Occasionally, you don't want to stop the current testcase just
@@ -91,7 +91,7 @@ test_strcmp(void *data)
/* First you declare a type to hold the environment info, and functions to
set it up and tear it down. */
struct data_buffer {
- /* We're just going to have couple of character buffer. Using
+ /* We're just going to have couple of character buffer. Using
setup/teardown functions is probably overkill for this case.
You could also do file descriptors, complicated handles, temporary
@@ -164,7 +164,7 @@ test_memcpy(void *ptr)
/* ============================================================ */
-/* Now we need to make sure that our tests get invoked. First, you take
+/* Now we need to make sure that our tests get invoked. First, you take
a bunch of related tests and put them into an array of struct testcase_t.
*/
@@ -189,15 +189,15 @@ struct testgroup_t groups[] = {
/* Every group has a 'prefix', and an array of tests. That's it. */
{ "demo/", demo_tests },
- END_OF_GROUPS
+ END_OF_GROUPS
};
int
main(int c, const char **v)
{
- /* Finally, just call tinytest_main(). It lets you specify verbose
- or quiet output with --verbose and --quiet. You can list
+ /* Finally, just call tinytest_main(). It lets you specify verbose
+ or quiet output with --verbose and --quiet. You can list
specific tests:
tinytest-demo demo/memcpy
diff --git a/src/test/tinytest_macros.h b/src/test/tinytest_macros.h
index a7fa64a824..9ff69b1d50 100644
--- a/src/test/tinytest_macros.h
+++ b/src/test/tinytest_macros.h
@@ -1,4 +1,4 @@
-/* tinytest_macros.h -- Copyright 2009-2010 Nick Mathewson
+/* tinytest_macros.h -- Copyright 2009-2012 Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,8 +23,8 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef _TINYTEST_MACROS_H
-#define _TINYTEST_MACROS_H
+#ifndef TINYTEST_MACROS_H_INCLUDED_
+#define TINYTEST_MACROS_H_INCLUDED_
/* Helpers for defining statement-like macros */
#define TT_STMT_BEGIN do {
@@ -51,19 +51,19 @@
/* Announce a non-failure if we're verbose. */
#define TT_BLATHER(args) \
TT_STMT_BEGIN \
- if (_tinytest_get_verbosity()>1) TT_DECLARE(" OK", args); \
+ if (tinytest_get_verbosity_()>1) TT_DECLARE(" OK", args); \
TT_STMT_END
#define TT_DIE(args) \
TT_STMT_BEGIN \
- _tinytest_set_test_failed(); \
+ tinytest_set_test_failed_(); \
TT_GRIPE(args); \
TT_EXIT_TEST_FUNCTION; \
TT_STMT_END
#define TT_FAIL(args) \
TT_STMT_BEGIN \
- _tinytest_set_test_failed(); \
+ tinytest_set_test_failed_(); \
TT_GRIPE(args); \
TT_STMT_END
@@ -74,7 +74,7 @@
#define tt_abort() TT_DIE(("%s", "(Failed.)"))
/* Fail but do not abort the current test for the reason in msg. */
-#define tt_fail_printf(msg) TT_FAIL(msg)
+#define tt_failprint_f(msg) TT_FAIL(msg)
#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno))
#define tt_fail_msg(msg) TT_FAIL(("%s", msg))
#define tt_fail() TT_FAIL(("%s", "(Failed.)"))
@@ -82,28 +82,28 @@
/* End the current test, and indicate we are skipping it. */
#define tt_skip() \
TT_STMT_BEGIN \
- _tinytest_set_test_skipped(); \
+ tinytest_set_test_skipped_(); \
TT_EXIT_TEST_FUNCTION; \
TT_STMT_END
-#define _tt_want(b, msg, fail) \
+#define tt_want_(b, msg, fail) \
TT_STMT_BEGIN \
if (!(b)) { \
- _tinytest_set_test_failed(); \
- TT_GRIPE((msg)); \
+ tinytest_set_test_failed_(); \
+ TT_GRIPE(("%s",msg)); \
fail; \
} else { \
- TT_BLATHER((msg)); \
+ TT_BLATHER(("%s",msg)); \
} \
TT_STMT_END
/* Assert b, but do not stop the test if b fails. Log msg on failure. */
#define tt_want_msg(b, msg) \
- _tt_want(b, msg, );
+ tt_want_(b, msg, );
/* Assert b and stop the test if b fails. Log msg on failure. */
#define tt_assert_msg(b, msg) \
- _tt_want(b, msg, TT_EXIT_TEST_FUNCTION);
+ tt_want_(b, msg, TT_EXIT_TEST_FUNCTION);
/* Assert b, but do not stop the test if b fails. */
#define tt_want(b) tt_want_msg( (b), "want("#b")")
@@ -111,57 +111,74 @@
#define tt_assert(b) tt_assert_msg((b), "assert("#b")")
#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \
- setup_block,cleanup_block) \
+ setup_block,cleanup_block,die_on_fail) \
TT_STMT_BEGIN \
- type _val1 = (type)(a); \
- type _val2 = (type)(b); \
- int _tt_status = (test); \
- if (!_tt_status || _tinytest_get_verbosity()>1) { \
- printf_type _print; \
- printf_type _print1; \
- printf_type _print2; \
- type _value = _val1; \
+ type val1_ = (type)(a); \
+ type val2_ = (type)(b); \
+ int tt_status_ = (test); \
+ if (!tt_status_ || tinytest_get_verbosity_()>1) { \
+ printf_type print_; \
+ printf_type print1_; \
+ printf_type print2_; \
+ type value_ = val1_; \
setup_block; \
- _print1 = _print; \
- _value = _val2; \
+ print1_ = print_; \
+ value_ = val2_; \
setup_block; \
- _print2 = _print; \
- TT_DECLARE(_tt_status?" OK":"FAIL", \
+ print2_ = print_; \
+ TT_DECLARE(tt_status_?" OK":"FAIL", \
("assert(%s): "printf_fmt" vs "printf_fmt, \
- str_test, _print1, _print2)); \
- _print = _print1; \
+ str_test, print1_, print2_)); \
+ print_ = print1_; \
cleanup_block; \
- _print = _print2; \
+ print_ = print2_; \
cleanup_block; \
- if (!_tt_status) { \
- _tinytest_set_test_failed(); \
- TT_EXIT_TEST_FUNCTION; \
+ if (!tt_status_) { \
+ tinytest_set_test_failed_(); \
+ die_on_fail ; \
} \
} \
TT_STMT_END
-#define tt_assert_test_type(a,b,str_test,type,test,fmt) \
+#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail) \
tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \
- {_print=_value;},{})
+ {print_=value_;},{},die_on_fail)
/* Helper: assert that a op b, when cast to type. Format the values with
* printf format fmt on failure. */
#define tt_assert_op_type(a,op,b,type,fmt) \
- tt_assert_test_type(a,b,#a" "#op" "#b,type,(_val1 op _val2),fmt)
+ tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \
+ TT_EXIT_TEST_FUNCTION)
#define tt_int_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,long,(_val1 op _val2),"%ld")
+ tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \
+ "%ld",TT_EXIT_TEST_FUNCTION)
#define tt_uint_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
- (_val1 op _val2),"%lu")
+ (val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION)
#define tt_ptr_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
- (_val1 op _val2),"%p")
+ (val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION)
#define tt_str_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
- (strcmp(_val1,_val2) op 0),"<%s>")
+ (strcmp(val1_,val2_) op 0),"<%s>",TT_EXIT_TEST_FUNCTION)
+
+#define tt_want_int_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0)
+
+#define tt_want_uint_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
+ (val1_ op val2_),"%lu",(void)0)
+
+#define tt_want_ptr_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
+ (val1_ op val2_),"%p",(void)0)
+
+#define tt_want_str_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
+ (strcmp(val1_,val2_) op 0),"<%s>",(void)0)
#endif