Refactor the core of choosing by weights into a function

This eliminates duplicated code, and lets us test a hairy piece of
functionality.
This commit is contained in:
Nick Mathewson
2012-08-09 13:47:42 -04:00
parent 9bfb274abb
commit 07df4dd52d
5 changed files with 160 additions and 96 deletions
+4
View File
@@ -65,6 +65,10 @@
#define test_memeq_hex(expr1, hex) test_mem_op_hex(expr1, ==, hex)
#define tt_double_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,double,(val1_ op val2_),"%f", \
TT_EXIT_TEST_FUNCTION)
const char *get_fname(const char *name);
crypto_pk_t *pk_generate(int idx);
+81
View File
@@ -7,6 +7,7 @@
#define DIRSERV_PRIVATE
#define DIRVOTE_PRIVATE
#define ROUTER_PRIVATE
#define ROUTERLIST_PRIVATE
#define HIBERNATE_PRIVATE
#include "or.h"
#include "directory.h"
@@ -1381,6 +1382,85 @@ test_dir_v3_networkstatus(void)
ns_detached_signatures_free(dsig2);
}
static void
test_dir_random_weighted(void *testdata)
{
int histogram[10];
uint64_t vals[10] = {3,1,2,4,6,0,7,5,8,9}, total=0;
uint64_t zeros[5] = {0,0,0,0,0};
int i, choice;
const int n = 50000;
double max_sq_error;
(void) testdata;
/* Try a ten-element array with values from 0 through 10. The values are
* in a scrambled order to make sure we don't depend on order. */
memset(histogram,0,sizeof(histogram));
for (i=0; i<10; ++i)
total += vals[i];
tt_int_op(total, ==, 45);
for (i=0; i<n; ++i) {
uint64_t t;
choice = choose_array_element_by_weight(vals, 10, &t);
tt_int_op(t, ==, total);
tt_int_op(choice, >=, 0);
tt_int_op(choice, <, 10);
histogram[choice]++;
}
/* Now see if we chose things about frequently enough. */
max_sq_error = 0;
for (i=0; i<10; ++i) {
int expected = (int)(n*vals[i]/total);
double frac_diff = 0, sq;
TT_BLATHER((" %d : %5d vs %5d\n", (int)vals[i], histogram[i], expected));
if (expected)
frac_diff = (histogram[i] - expected) / ((double)expected);
else
tt_int_op(histogram[i], ==, 0);
sq = frac_diff * frac_diff;
if (sq > max_sq_error)
max_sq_error = sq;
}
/* It should almost always be much much less than this. If you want to
* figure out the odds, please feel free. */
tt_double_op(max_sq_error, <, .05);
/* Now try a singleton; do we choose it? */
for (i = 0; i < 100; ++i) {
choice = choose_array_element_by_weight(vals, 1, NULL);
tt_int_op(choice, ==, 0);
}
/* Now try an array of zeros. We should choose randomly. */
memset(histogram,0,sizeof(histogram));
for (i = 0; i < n; ++i) {
uint64_t t;
choice = choose_array_element_by_weight(zeros, 5, &t);
tt_int_op(t, ==, 0);
tt_int_op(choice, >=, 0);
tt_int_op(choice, <, 5);
histogram[choice]++;
}
/* Now see if we chose things about frequently enough. */
max_sq_error = 0;
for (i=0; i<5; ++i) {
int expected = n/5;
double frac_diff = 0, sq;
TT_BLATHER((" %d : %5d vs %5d\n", (int)vals[i], histogram[i], expected));
frac_diff = (histogram[i] - expected) / ((double)expected);
sq = frac_diff * frac_diff;
if (sq > max_sq_error)
max_sq_error = sq;
}
/* It should almost always be much much less than this. If you want to
* figure out the odds, please feel free. */
tt_double_op(max_sq_error, <, .05);
done:
;
}
#define DIR_LEGACY(name) \
{ #name, legacy_test_helper, TT_FORK, &legacy_setup, test_dir_ ## name }
@@ -1396,6 +1476,7 @@ struct testcase_t dir_tests[] = {
DIR_LEGACY(measured_bw),
DIR_LEGACY(param_voting),
DIR_LEGACY(v3_networkstatus),
DIR(random_weighted),
END_OF_TESTCASES
};