[tor-commits] [tor/master] Introduce full coverage tests for module routerset.c.

nickm at torproject.org nickm at torproject.org
Fri Aug 29 16:58:36 UTC 2014


commit c887e20e6a5a2c17c65f308e70e578e773b2ab23
Author: dana koch <dsk at google.com>
Date:   Wed Aug 27 20:41:25 2014 +1000

    Introduce full coverage tests for module routerset.c.
    
    This is using the paradigm introduced for test_status.c.
---
 src/common/container.c    |   24 +-
 src/common/container.h    |    8 +-
 src/or/geoip.c            |   16 +-
 src/or/geoip.h            |    8 +-
 src/or/nodelist.c         |    8 +-
 src/or/nodelist.h         |    5 +-
 src/or/policies.c         |    6 +-
 src/or/policies.h         |    4 +-
 src/or/routerparse.c      |    4 +-
 src/or/routerparse.h      |    4 +-
 src/or/routerset.c        |   39 +-
 src/or/routerset.h        |   40 +
 src/test/include.am       |    1 +
 src/test/test.c           |    2 +
 src/test/test_routerset.c | 2122 +++++++++++++++++++++++++++++++++++++++++++++
 15 files changed, 2213 insertions(+), 78 deletions(-)

diff --git a/src/common/container.c b/src/common/container.c
index 7f02dec..7481d31 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -28,8 +28,8 @@
 
 /** Allocate and return an empty smartlist.
  */
-smartlist_t *
-smartlist_new(void)
+MOCK_IMPL(smartlist_t *,
+smartlist_new,(void))
 {
   smartlist_t *sl = tor_malloc(sizeof(smartlist_t));
   sl->num_used = 0;
@@ -41,8 +41,8 @@ smartlist_new(void)
 /** Deallocate a smartlist.  Does not release storage associated with the
  * list's elements.
  */
-void
-smartlist_free(smartlist_t *sl)
+MOCK_IMPL(void,
+smartlist_free,(smartlist_t *sl))
 {
   if (!sl)
     return;
@@ -1062,8 +1062,8 @@ HT_GENERATE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
 
 /** Constructor to create a new empty map from strings to void*'s.
  */
-strmap_t *
-strmap_new(void)
+MOCK_IMPL(strmap_t *,
+strmap_new,(void))
 {
   strmap_t *result;
   result = tor_malloc(sizeof(strmap_t));
@@ -1073,8 +1073,8 @@ strmap_new(void)
 
 /** Constructor to create a new empty map from digests to void*'s.
  */
-digestmap_t *
-digestmap_new(void)
+MOCK_IMPL(digestmap_t *,
+digestmap_new,(void))
 {
   digestmap_t *result;
   result = tor_malloc(sizeof(digestmap_t));
@@ -1427,8 +1427,8 @@ digestmap_iter_done(digestmap_iter_t *iter)
  * entries.  If free_val is provided, it is invoked on every value in
  * <b>map</b>.
  */
-void
-strmap_free(strmap_t *map, void (*free_val)(void*))
+MOCK_IMPL(void,
+strmap_free,(strmap_t *map, void (*free_val)(void*)))
 {
   strmap_entry_t **ent, **next, *this;
   if (!map)
@@ -1451,8 +1451,8 @@ strmap_free(strmap_t *map, void (*free_val)(void*))
  * entries.  If free_val is provided, it is invoked on every value in
  * <b>map</b>.
  */
-void
-digestmap_free(digestmap_t *map, void (*free_val)(void*))
+MOCK_IMPL(void,
+digestmap_free, (digestmap_t *map, void (*free_val)(void*)))
 {
   digestmap_entry_t **ent, **next, *this;
   if (!map)
diff --git a/src/common/container.h b/src/common/container.h
index 08da34e..9fb4cf3 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -27,8 +27,8 @@ typedef struct smartlist_t {
   /** @} */
 } smartlist_t;
 
-smartlist_t *smartlist_new(void);
-void smartlist_free(smartlist_t *sl);
+MOCK_DECL(smartlist_t *, smartlist_new, (void));
+MOCK_DECL(void, smartlist_free, (smartlist_t *sl));
 void smartlist_clear(smartlist_t *sl);
 void smartlist_add(smartlist_t *sl, void *element);
 void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
@@ -328,11 +328,11 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
 #define DECLARE_MAP_FNS(maptype, keytype, prefix)                       \
   typedef struct maptype maptype;                                       \
   typedef struct prefix##entry_t *prefix##iter_t;                       \
-  maptype* prefix##new(void);                                           \
+  MOCK_DECL(maptype*, prefix##new, (void));                             \
   void* prefix##set(maptype *map, keytype key, void *val);              \
   void* prefix##get(const maptype *map, keytype key);                   \
   void* prefix##remove(maptype *map, keytype key);                      \
-  void prefix##free(maptype *map, void (*free_val)(void*));             \
+  MOCK_DECL(void, prefix##free, (maptype *map, void (*free_val)(void*))); \
   int prefix##isempty(const maptype *map);                              \
   int prefix##size(const maptype *map);                                 \
   prefix##iter_t *prefix##iter_init(maptype *map);                      \
diff --git a/src/or/geoip.c b/src/or/geoip.c
index feb54aa..108385e 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -58,8 +58,8 @@ static char geoip6_digest[DIGEST_LEN];
 /** Return the index of the <b>country</b>'s entry in the GeoIP
  * country list if it is a valid 2-letter country code, otherwise
  * return -1. */
-country_t
-geoip_get_country(const char *country)
+MOCK_IMPL(country_t,
+geoip_get_country,(const char *country))
 {
   void *idxplus1_;
   intptr_t idx;
@@ -396,8 +396,8 @@ geoip_get_country_by_ipv6(const struct in6_addr *addr)
  * the 'unknown country'.  The return value will always be less than
  * geoip_get_n_countries().  To decode it, call geoip_get_country_name().
  */
-int
-geoip_get_country_by_addr(const tor_addr_t *addr)
+MOCK_IMPL(int,
+geoip_get_country_by_addr,(const tor_addr_t *addr))
 {
   if (tor_addr_family(addr) == AF_INET) {
     return geoip_get_country_by_ipv4(tor_addr_to_ipv4h(addr));
@@ -409,8 +409,8 @@ geoip_get_country_by_addr(const tor_addr_t *addr)
 }
 
 /** Return the number of countries recognized by the GeoIP country list. */
-int
-geoip_get_n_countries(void)
+MOCK_IMPL(int,
+geoip_get_n_countries,(void))
 {
   if (!geoip_countries)
     init_geoip_countries();
@@ -430,8 +430,8 @@ geoip_get_country_name(country_t num)
 }
 
 /** Return true iff we have loaded a GeoIP database.*/
-int
-geoip_is_loaded(sa_family_t family)
+MOCK_IMPL(int,
+geoip_is_loaded,(sa_family_t family))
 {
   tor_assert(family == AF_INET || family == AF_INET6);
   if (geoip_countries == NULL)
diff --git a/src/or/geoip.h b/src/or/geoip.h
index b9b53c3..f702617 100644
--- a/src/or/geoip.h
+++ b/src/or/geoip.h
@@ -21,12 +21,12 @@ STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr);
 #endif
 int should_record_bridge_info(const or_options_t *options);
 int geoip_load_file(sa_family_t family, const char *filename);
-int geoip_get_country_by_addr(const tor_addr_t *addr);
-int geoip_get_n_countries(void);
+MOCK_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+MOCK_DECL(int, geoip_get_n_countries, (void));
 const char *geoip_get_country_name(country_t num);
-int geoip_is_loaded(sa_family_t family);
+MOCK_DECL(int, geoip_is_loaded, (sa_family_t family));
 const char *geoip_db_digest(sa_family_t family);
-country_t geoip_get_country(const char *countrycode);
+MOCK_DECL(country_t, geoip_get_country, (const char *countrycode));
 
 void geoip_note_client_seen(geoip_client_action_t action,
                             const tor_addr_t *addr, const char *transport_name,
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index 7b1f338..21e4ec2 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -474,8 +474,8 @@ nodelist_assert_ok(void)
 /** Return a list of a node_t * for every node we know about.  The caller
  * MUST NOT modify the list. (You can set and clear flags in the nodes if
  * you must, but you must not add or remove nodes.) */
-smartlist_t *
-nodelist_get_list(void)
+MOCK_IMPL(smartlist_t *,
+nodelist_get_list,(void))
 {
   init_nodelist();
   return the_nodelist->nodes;
@@ -517,8 +517,8 @@ node_get_by_hex_id(const char *hex_id)
  * the corresponding node_t, or NULL if none exists.  Warn the user if
  * <b>warn_if_unnamed</b> is set, and they have specified a router by
  * nickname, but the Named flag isn't set for that router. */
-const node_t *
-node_get_by_nickname(const char *nickname, int warn_if_unnamed)
+MOCK_IMPL(const node_t *,
+node_get_by_nickname,(const char *nickname, int warn_if_unnamed))
 {
   const node_t *node;
   if (!the_nodelist)
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index 8e719e0..cb54cec 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -31,7 +31,8 @@ smartlist_t *nodelist_find_nodes_with_microdesc(const microdesc_t *md);
 void nodelist_free_all(void);
 void nodelist_assert_ok(void);
 
-const node_t *node_get_by_nickname(const char *nickname, int warn_if_unnamed);
+MOCK_DECL(const node_t *, node_get_by_nickname,
+    (const char *nickname, int warn_if_unnamed));
 void node_get_verbose_nickname(const node_t *node,
                                char *verbose_name_out);
 void node_get_verbose_nickname_by_id(const char *id_digest,
@@ -60,7 +61,7 @@ void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out);
 void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out);
 int node_has_curve25519_onion_key(const node_t *node);
 
-smartlist_t *nodelist_get_list(void);
+MOCK_DECL(smartlist_t *, nodelist_get_list, (void));
 
 /* Temporary during transition to multiple addresses.  */
 void node_get_addr(const node_t *node, tor_addr_t *addr_out);
diff --git a/src/or/policies.c b/src/or/policies.c
index 6a9e73b..4dbb43e 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -769,9 +769,9 @@ compare_unknown_tor_addr_to_addr_policy(uint16_t port,
  * We could do better by assuming that some ranges never match typical
  * addresses (127.0.0.1, and so on).  But we'll try this for now.
  */
-addr_policy_result_t
-compare_tor_addr_to_addr_policy(const tor_addr_t *addr, uint16_t port,
-                                const smartlist_t *policy)
+MOCK_IMPL(addr_policy_result_t,
+compare_tor_addr_to_addr_policy,(const tor_addr_t *addr, uint16_t port,
+                                 const smartlist_t *policy))
 {
   if (!policy) {
     /* no policy? accept all. */
diff --git a/src/or/policies.h b/src/or/policies.h
index 91ac427..5f81912 100644
--- a/src/or/policies.h
+++ b/src/or/policies.h
@@ -37,8 +37,8 @@ int policies_parse_from_options(const or_options_t *options);
 
 addr_policy_t *addr_policy_get_canonical_entry(addr_policy_t *ent);
 int cmp_addr_policies(smartlist_t *a, smartlist_t *b);
-addr_policy_result_t compare_tor_addr_to_addr_policy(const tor_addr_t *addr,
-                              uint16_t port, const smartlist_t *policy);
+MOCK_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+    (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
 
 addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr,
                               uint16_t port, const node_t *node);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 6546d19..bdf0809 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -3243,8 +3243,8 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
  * AF_UNSPEC for '*'.  Use policy_expand_unspec() to turn this into a pair
  * of AF_INET and AF_INET6 items.
  */
-addr_policy_t *
-router_parse_addr_policy_item_from_string(const char *s, int assume_action)
+MOCK_IMPL(addr_policy_t *,
+router_parse_addr_policy_item_from_string,(const char *s, int assume_action))
 {
   directory_token_t *tok = NULL;
   const char *cp, *eos;
diff --git a/src/or/routerparse.h b/src/or/routerparse.h
index 5d5d9e5..fa275c8 100644
--- a/src/or/routerparse.h
+++ b/src/or/routerparse.h
@@ -37,8 +37,8 @@ routerinfo_t *router_parse_entry_from_string(const char *s, const char *end,
                                              const char *prepend_annotations);
 extrainfo_t *extrainfo_parse_entry_from_string(const char *s, const char *end,
                          int cache_copy, struct digest_ri_map_t *routermap);
-addr_policy_t *router_parse_addr_policy_item_from_string(const char *s,
-                                                  int assume_action);
+MOCK_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
+    (const char *s, int assume_action));
 version_status_t tor_version_is_obsolete(const char *myversion,
                                          const char *versionlist);
 int tor_version_supports_microdescriptors(const char *platform);
diff --git a/src/or/routerset.c b/src/or/routerset.c
index 7aee90d..e1b8e23 100644
--- a/src/or/routerset.c
+++ b/src/or/routerset.c
@@ -4,6 +4,8 @@
  * Copyright (c) 2007-2013, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
+#define ROUTERSET_PRIVATE
+
 #include "or.h"
 #include "geoip.h"
 #include "nodelist.h"
@@ -12,39 +14,6 @@
 #include "routerparse.h"
 #include "routerset.h"
 
-/** A routerset specifies constraints on a set of possible routerinfos, based
- * on their names, identities, or addresses.  It is optimized for determining
- * whether a router is a member or not, in O(1+P) time, where P is the number
- * of address policy constraints. */
-struct routerset_t {
-  /** A list of strings for the elements of the policy.  Each string is either
-   * a nickname, a hexadecimal identity fingerprint, or an address policy.  A
-   * router belongs to the set if its nickname OR its identity OR its address
-   * matches an entry here. */
-  smartlist_t *list;
-  /** A map from lowercase nicknames of routers in the set to (void*)1 */
-  strmap_t *names;
-  /** A map from identity digests routers in the set to (void*)1 */
-  digestmap_t *digests;
-  /** An address policy for routers in the set.  For implementation reasons,
-   * a router belongs to the set if it is _rejected_ by this policy. */
-  smartlist_t *policies;
-
-  /** A human-readable description of what this routerset is for.  Used in
-   * log messages. */
-  char *description;
-
-  /** A list of the country codes in this set. */
-  smartlist_t *country_names;
-  /** Total number of countries we knew about when we built <b>countries</b>.*/
-  int n_countries;
-  /** Bit array mapping the return value of geoip_get_country() to 1 iff the
-   * country is a member of this routerset.  Note that we MUST call
-   * routerset_refresh_countries() whenever the geoip country list is
-   * reloaded. */
-  bitarray_t *countries;
-};
-
 /** Return a new empty routerset. */
 routerset_t *
 routerset_new(void)
@@ -60,7 +29,7 @@ routerset_new(void)
 
 /** If <b>c</b> is a country code in the form {cc}, return a newly allocated
  * string holding the "cc" part.  Else, return NULL. */
-static char *
+STATIC char *
 routerset_get_countryname(const char *c)
 {
   char *country;
@@ -200,7 +169,7 @@ routerset_is_empty(const routerset_t *set)
  *
  * (If country is -1, then we take the country
  * from addr.) */
-static int
+STATIC int
 routerset_contains(const routerset_t *set, const tor_addr_t *addr,
                    uint16_t orport,
                    const char *nickname, const char *id_digest,
diff --git a/src/or/routerset.h b/src/or/routerset.h
index 8261c7f..eafd331 100644
--- a/src/or/routerset.h
+++ b/src/or/routerset.h
@@ -39,5 +39,45 @@ char *routerset_to_string(const routerset_t *routerset);
 int routerset_equal(const routerset_t *old, const routerset_t *new);
 void routerset_free(routerset_t *routerset);
 
+#ifdef ROUTERSET_PRIVATE
+STATIC char * routerset_get_countryname(const char *c);
+STATIC int routerset_contains(const routerset_t *set, const tor_addr_t *addr,
+                   uint16_t orport,
+                   const char *nickname, const char *id_digest,
+                   country_t country);
+
+/** A routerset specifies constraints on a set of possible routerinfos, based
+ * on their names, identities, or addresses.  It is optimized for determining
+ * whether a router is a member or not, in O(1+P) time, where P is the number
+ * of address policy constraints. */
+struct routerset_t {
+  /** A list of strings for the elements of the policy.  Each string is either
+   * a nickname, a hexadecimal identity fingerprint, or an address policy.  A
+   * router belongs to the set if its nickname OR its identity OR its address
+   * matches an entry here. */
+  smartlist_t *list;
+  /** A map from lowercase nicknames of routers in the set to (void*)1 */
+  strmap_t *names;
+  /** A map from identity digests routers in the set to (void*)1 */
+  digestmap_t *digests;
+  /** An address policy for routers in the set.  For implementation reasons,
+   * a router belongs to the set if it is _rejected_ by this policy. */
+  smartlist_t *policies;
+
+  /** A human-readable description of what this routerset is for.  Used in
+   * log messages. */
+  char *description;
+
+  /** A list of the country codes in this set. */
+  smartlist_t *country_names;
+  /** Total number of countries we knew about when we built <b>countries</b>.*/
+  int n_countries;
+  /** Bit array mapping the return value of geoip_get_country() to 1 iff the
+   * country is a member of this routerset.  Note that we MUST call
+   * routerset_refresh_countries() whenever the geoip country list is
+   * reloaded. */
+  bitarray_t *countries;
+};
+#endif
 #endif
 
diff --git a/src/test/include.am b/src/test/include.am
index d5163aa..77c92f1 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -46,6 +46,7 @@ src_test_test_SOURCES = \
 	src/test/test_nodelist.c \
 	src/test/test_policy.c \
 	src/test/test_status.c \
+	src/test/test_routerset.c \
 	src/ext/tinytest.c
 
 src_test_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
diff --git a/src/test/test.c b/src/test/test.c
index 98552dc..e836160 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1324,6 +1324,7 @@ extern struct testcase_t routerkeys_tests[];
 extern struct testcase_t oom_tests[];
 extern struct testcase_t policy_tests[];
 extern struct testcase_t status_tests[];
+extern struct testcase_t routerset_tests[];
 
 static struct testgroup_t testgroups[] = {
   { "", test_array },
@@ -1355,6 +1356,7 @@ static struct testgroup_t testgroups[] = {
   { "oom/", oom_tests },
   { "policy/" , policy_tests },
   { "status/" , status_tests },
+  { "routerset/" , routerset_tests },
   END_OF_GROUPS
 };
 
diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c
new file mode 100644
index 0000000..d6bdd1a
--- /dev/null
+++ b/src/test/test_routerset.c
@@ -0,0 +1,2122 @@
+#define ROUTERSET_PRIVATE
+
+#include "or.h"
+#include "geoip.h"
+#include "routerset.h"
+#include "routerparse.h"
+#include "policies.h"
+#include "nodelist.h"
+#include "test.h"
+
+#define NS_MODULE routerset
+
+#define NS_SUBMODULE routerset_new
+
+/*
+ * Functional (blackbox) test to determine that each member of the routerset
+ * is non-NULL
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *rs;
+  (void)arg;
+
+  rs = routerset_new();
+
+  tt_ptr_op(rs, !=, NULL);
+  tt_ptr_op(rs->list, !=, NULL);
+  tt_ptr_op(rs->names, !=, NULL);
+  tt_ptr_op(rs->digests, !=, NULL);
+  tt_ptr_op(rs->policies, !=, NULL);
+  tt_ptr_op(rs->country_names, !=, NULL);
+
+  done:
+    routerset_free(rs);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_get_countryname
+
+/*
+ * Functional test to strip the braces from a "{xx}" country code string.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  const char *input;
+  char *name;
+  (void)arg;
+
+  /* strlen(c) < 4 */
+  input = "xxx";
+  name = routerset_get_countryname(input);
+  tt_ptr_op(name, ==, NULL);
+  tor_free(name);
+
+  /* c[0] != '{' */
+  input = "xxx}";
+  name = routerset_get_countryname(input);
+  tt_ptr_op(name, ==, NULL);
+  tor_free(name);
+
+  /* c[3] != '}' */
+  input = "{xxx";
+  name = routerset_get_countryname(input);
+  tt_ptr_op(name, ==, NULL);
+  tor_free(name);
+
+  /* tor_strlower */
+  input = "{XX}";
+  name = routerset_get_countryname(input);
+  tt_str_op(name, ==, "xx");
+  tor_free(name);
+
+  input = "{xx}";
+  name = routerset_get_countryname(input);
+  tt_str_op(name, ==, "xx");
+  done:
+    tor_free(name);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_refresh_counties, geoip_not_loaded)
+
+/*
+ * Structural (whitebox) test for routerset_refresh_counties, when the GeoIP DB
+ * is not loaded.
+ */
+
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+NS_DECL(int, geoip_get_n_countries, (void));
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  (void)arg;
+
+  NS_MOCK(geoip_is_loaded);
+  NS_MOCK(geoip_get_n_countries);
+
+  routerset_refresh_countries(set);
+
+  tt_ptr_op(set->countries, ==, NULL);
+  tt_int_op(set->n_countries, ==, 0);
+  tt_int_op(CALLED(geoip_is_loaded), ==, 1);
+  tt_int_op(CALLED(geoip_get_n_countries), ==, 0);
+
+  done:
+    NS_UNMOCK(geoip_is_loaded);
+    NS_UNMOCK(geoip_get_n_countries);
+    routerset_free(set);
+}
+
+static int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+  (void)family;
+  CALLED(geoip_is_loaded)++;
+
+  return 0;
+}
+
+static int
+NS(geoip_get_n_countries)(void)
+{
+  CALLED(geoip_get_n_countries)++;
+
+  return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_refresh_counties, no_countries)
+
+/*
+ * Structural test for routerset_refresh_counties, when there are no countries.
+ */
+
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+NS_DECL(int, geoip_get_n_countries, (void));
+NS_DECL(country_t, geoip_get_country, (const char *country));
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  (void)arg;
+
+  NS_MOCK(geoip_is_loaded);
+  NS_MOCK(geoip_get_n_countries);
+  NS_MOCK(geoip_get_country);
+
+  routerset_refresh_countries(set);
+
+  tt_ptr_op(set->countries, !=, NULL);
+  tt_int_op(set->n_countries, ==, 1);
+  tt_int_op((unsigned int)(*set->countries), ==, 0);
+  tt_int_op(CALLED(geoip_is_loaded), ==, 1);
+  tt_int_op(CALLED(geoip_get_n_countries), ==, 1);
+  tt_int_op(CALLED(geoip_get_country), ==, 0);
+
+  done:
+    NS_UNMOCK(geoip_is_loaded);
+    NS_UNMOCK(geoip_get_n_countries);
+    NS_UNMOCK(geoip_get_country);
+    routerset_free(set);
+}
+
+static int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+  (void)family;
+  CALLED(geoip_is_loaded)++;
+
+  return 1;
+}
+
+static int
+NS(geoip_get_n_countries)(void)
+{
+  CALLED(geoip_get_n_countries)++;
+
+  return 1;
+}
+
+static country_t
+NS(geoip_get_country)(const char *countrycode)
+{
+  (void)countrycode;
+  CALLED(geoip_get_country)++;
+
+  return 1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_refresh_counties, one_valid_country)
+
+/*
+ * Structural test for routerset_refresh_counties, with one valid country.
+ */
+
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+NS_DECL(int, geoip_get_n_countries, (void));
+NS_DECL(country_t, geoip_get_country, (const char *country));
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  (void)arg;
+
+  NS_MOCK(geoip_is_loaded);
+  NS_MOCK(geoip_get_n_countries);
+  NS_MOCK(geoip_get_country);
+  smartlist_add(set->country_names, tor_strndup("foo", 3));
+
+  routerset_refresh_countries(set);
+
+  tt_ptr_op(set->countries, !=, NULL);
+  tt_int_op(set->n_countries, ==, 2);
+  tt_int_op(CALLED(geoip_is_loaded), ==, 1);
+  tt_int_op(CALLED(geoip_get_n_countries), ==, 1);
+  tt_int_op(CALLED(geoip_get_country), ==, 1);
+  tt_int_op((unsigned int)(*set->countries), !=, 0);
+
+  done:
+    NS_UNMOCK(geoip_is_loaded);
+    NS_UNMOCK(geoip_get_n_countries);
+    NS_UNMOCK(geoip_get_country);
+    routerset_free(set);
+}
+
+static int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+  (void)family;
+  CALLED(geoip_is_loaded)++;
+
+  return 1;
+}
+
+static int
+NS(geoip_get_n_countries)(void)
+{
+  CALLED(geoip_get_n_countries)++;
+
+  return 2;
+}
+
+static country_t
+NS(geoip_get_country)(const char *countrycode)
+{
+  (void)countrycode;
+  CALLED(geoip_get_country)++;
+
+  return 1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_refresh_counties, one_invalid_country)
+
+/*
+ * Structural test for routerset_refresh_counties, with one invalid
+ * country code..
+ */
+
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+NS_DECL(int, geoip_get_n_countries, (void));
+NS_DECL(country_t, geoip_get_country, (const char *country));
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  (void)arg;
+
+  NS_MOCK(geoip_is_loaded);
+  NS_MOCK(geoip_get_n_countries);
+  NS_MOCK(geoip_get_country);
+  smartlist_add(set->country_names, tor_strndup("foo", 3));
+
+  routerset_refresh_countries(set);
+
+  tt_ptr_op(set->countries, !=, NULL);
+  tt_int_op(set->n_countries, ==, 2);
+  tt_int_op(CALLED(geoip_is_loaded), ==, 1);
+  tt_int_op(CALLED(geoip_get_n_countries), ==, 1);
+  tt_int_op(CALLED(geoip_get_country), ==, 1);
+  tt_int_op((unsigned int)(*set->countries), ==, 0);
+
+  done:
+    NS_UNMOCK(geoip_is_loaded);
+    NS_UNMOCK(geoip_get_n_countries);
+    NS_UNMOCK(geoip_get_country);
+    routerset_free(set);
+}
+
+static int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+  (void)family;
+  CALLED(geoip_is_loaded)++;
+
+  return 1;
+}
+
+static int
+NS(geoip_get_n_countries)(void)
+{
+  CALLED(geoip_get_n_countries)++;
+
+  return 2;
+}
+
+static country_t
+NS(geoip_get_country)(const char *countrycode)
+{
+  (void)countrycode;
+  CALLED(geoip_get_country)++;
+
+  return -1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_parse, malformed)
+
+/*
+ * Functional test, with a malformed string to parse.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  const char *s = "_";
+  int r;
+  (void)arg;
+
+  r = routerset_parse(set, s, "");
+
+  tt_int_op(r, ==, -1);
+
+  done:
+    routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_parse, valid_hexdigest)
+
+/*
+ * Functional test for routerset_parse, that routerset_parse returns 0
+ * on a valid hexdigest entry.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set;
+  const char *s;
+  int r;
+  (void)arg;
+
+  set = routerset_new();
+  s = "$0000000000000000000000000000000000000000";
+  r = routerset_parse(set, s, "");
+  tt_int_op(r, ==, 0);
+  tt_int_op(digestmap_isempty(set->digests), !=, 1);
+
+  done:
+    routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_parse, valid_nickname)
+
+/*
+ * Functional test for routerset_parse, when given a valid nickname as input.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set;
+  const char *s;
+  int r;
+  (void)arg;
+
+  set = routerset_new();
+  s = "fred";
+  r = routerset_parse(set, s, "");
+  tt_int_op(r, ==, 0);
+  tt_int_op(strmap_isempty(set->names), !=, 1);
+
+  done:
+    routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_parse, get_countryname)
+
+/*
+ * Functional test for routerset_parse, when given a valid countryname.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set;
+  const char *s;
+  int r;
+  (void)arg;
+
+  set = routerset_new();
+  s = "{cc}";
+  r = routerset_parse(set, s, "");
+  tt_int_op(r, ==, 0);
+  tt_int_op(smartlist_len(set->country_names), !=, 0);
+
+  done:
+    routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_parse, policy)
+
+/*
+ * Structural test for routerset_parse, when given a valid policy.
+ */
+
+NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
+    (const char *s, int assume_action));
+
+addr_policy_t *NS(mock_addr_policy);
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set;
+  const char *s;
+  int r;
+  (void)arg;
+
+  NS_MOCK(router_parse_addr_policy_item_from_string);
+  NS(mock_addr_policy) = tor_malloc_zero(sizeof(NS(mock_addr_policy)));
+
+  set = routerset_new();
+  s = "*";
+  r = routerset_parse(set, s, "");
+  tt_int_op(r, ==, 0);
+  tt_int_op(smartlist_len(set->policies), !=, 0);
+  tt_int_op(CALLED(router_parse_addr_policy_item_from_string), ==, 1);
+
+  done:
+    routerset_free(set);
+}
+
+addr_policy_t *
+NS(router_parse_addr_policy_item_from_string)(const char *s, int assume_action)
+{
+  (void)s;
+  (void)assume_action;
+  CALLED(router_parse_addr_policy_item_from_string)++;
+
+  return NS(mock_addr_policy);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_union, source_bad)
+
+/*
+ * Structural test for routerset_union, when given a bad source argument.
+ */
+
+NS_DECL(smartlist_t *, smartlist_new, (void));
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set, *bad_set;
+  (void)arg;
+
+  set = routerset_new();
+  bad_set = routerset_new();
+  smartlist_free(bad_set->list);
+  bad_set->list = NULL;
+
+  NS_MOCK(smartlist_new);
+
+  routerset_union(set, NULL);
+  tt_int_op(CALLED(smartlist_new), ==, 0);
+
+  routerset_union(set, bad_set);
+  tt_int_op(CALLED(smartlist_new), ==, 0);
+
+  done:
+    NS_UNMOCK(smartlist_new);
+    routerset_free(set);
+
+    /* Just recreate list, so we can simply use routerset_free. */
+    bad_set->list = smartlist_new();
+    routerset_free(bad_set);
+}
+
+static smartlist_t *
+NS(smartlist_new)(void)
+{
+  CALLED(smartlist_new)++;
+
+  return NULL;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_union, one)
+
+/*
+ * Functional test for routerset_union.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *src = routerset_new();
+  routerset_t *tgt;
+  (void)arg;
+
+  tgt = routerset_new();
+  smartlist_add(src->list, tor_strdup("{xx}"));
+  routerset_union(tgt, src);
+
+  tt_int_op(smartlist_len(tgt->list), !=, 0);
+
+  done:
+    routerset_free(src);
+    routerset_free(tgt);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_is_list
+
+/*
+ * Functional tests for routerset_is_list.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set;
+  addr_policy_t *policy;
+  int is_list;
+  (void)arg;
+
+  /* len(set->country_names) == 0, len(set->policies) == 0 */
+  set = routerset_new();
+  is_list = routerset_is_list(set);
+  routerset_free(set);
+  set = NULL;
+  tt_int_op(is_list, !=, 0);
+
+  /* len(set->country_names) != 0, len(set->policies) == 0 */
+  set = routerset_new();
+  smartlist_add(set->country_names, tor_strndup("foo", 3));
+  is_list = routerset_is_list(set);
+  routerset_free(set);
+  set = NULL;
+  tt_int_op(is_list, ==, 0);
+
+  /* len(set->country_names) == 0, len(set->policies) != 0 */
+  set = routerset_new();
+  policy = tor_malloc_zero(sizeof(addr_policy_t));
+  smartlist_add(set->policies, (void *)policy);
+  is_list = routerset_is_list(set);
+  routerset_free(set);
+  set = NULL;
+  tt_int_op(is_list, ==, 0);
+
+  /* len(set->country_names) != 0, len(set->policies) != 0 */
+  set = routerset_new();
+  smartlist_add(set->country_names, tor_strndup("foo", 3));
+  policy = tor_malloc_zero(sizeof(addr_policy_t));
+  smartlist_add(set->policies, (void *)policy);
+  is_list = routerset_is_list(set);
+  routerset_free(set);
+  set = NULL;
+  tt_int_op(is_list, ==, 0);
+
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_needs_geoip
+
+/*
+ * Functional tests for routerset_needs_geoip.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  const routerset_t *set;
+  int needs_geoip;
+  (void)arg;
+
+  set = NULL;
+  needs_geoip = routerset_needs_geoip(set);
+  tt_int_op(needs_geoip, ==, 0);
+
+  set = routerset_new();
+  needs_geoip = routerset_needs_geoip(set);
+  routerset_free((routerset_t *)set);
+  tt_int_op(needs_geoip, ==, 0);
+  set = NULL;
+
+  set = routerset_new();
+  smartlist_add(set->country_names, tor_strndup("xx", 2));
+  needs_geoip = routerset_needs_geoip(set);
+  routerset_free((routerset_t *)set);
+  set = NULL;
+  tt_int_op(needs_geoip, !=, 0);
+
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_is_empty
+
+/*
+ * Functional tests for routerset_is_empty.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = NULL;
+  int is_empty;
+  (void)arg;
+
+  is_empty = routerset_is_empty(set);
+  tt_int_op(is_empty, !=, 0);
+
+  set = routerset_new();
+  is_empty = routerset_is_empty(set);
+  routerset_free(set);
+  set = NULL;
+  tt_int_op(is_empty, !=, 0);
+
+  set = routerset_new();
+  smartlist_add(set->list, tor_strdup("{xx}"));
+  is_empty = routerset_is_empty(set);
+  routerset_free(set);
+  set = NULL;
+  tt_int_op(is_empty, ==, 0);
+
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, null_set_or_null_set_list)
+
+/*
+ * Functional test for routerset_contains, when given a NULL set or the
+ * set has a NULL list.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = NULL;
+  int contains;
+  (void)arg;
+
+  contains = routerset_contains(set, NULL, 0, NULL, NULL, 0);
+
+  tt_int_op(contains, ==, 0);
+
+  set = tor_malloc_zero(sizeof(routerset_t));
+  set->list = NULL;
+  contains = routerset_contains(set, NULL, 0, NULL, NULL, 0);
+  tor_free(set);
+  tt_int_op(contains, ==, 0);
+
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_nickname)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset but a
+ * NULL nickname.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  char *nickname = NULL;
+  int contains;
+  (void)arg;
+
+  contains = routerset_contains(set, NULL, 0, nickname, NULL, 0);
+  routerset_free(set);
+
+  tt_int_op(contains, ==, 0);
+
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_nickname)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset
+ * and the nickname is in the routerset.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  const char *nickname;
+  int contains;
+  (void)arg;
+
+  nickname = "Foo";  /* This tests the lowercase comparison as well. */
+  strmap_set_lc(set->names, nickname, (void *)1);
+  contains = routerset_contains(set, NULL, 0, nickname, NULL, 0);
+  routerset_free(set);
+
+  tt_int_op(contains, ==, 4);
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_nickname)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset
+ * and the nickname is not in the routerset.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  int contains;
+  (void)arg;
+
+  strmap_set_lc(set->names, "bar", (void *)1);
+  contains = routerset_contains(set, NULL, 0, "foo", NULL, 0);
+  routerset_free(set);
+
+  tt_int_op(contains, ==, 0);
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_digest)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset
+ * and the digest is contained in the routerset.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  int contains;
+  (void)arg;
+
+  digestmap_set(set->digests, "foo", (void *)1);
+  contains = routerset_contains(set, NULL, 0, NULL, "foo", 0);
+  routerset_free(set);
+
+  tt_int_op(contains, ==, 4);
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_digest)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset
+ * and the digest is not contained in the routerset.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  int contains;
+  (void)arg;
+
+  digestmap_set(set->digests, "bar", (void *)1);
+  contains = routerset_contains(set, NULL, 0, NULL, "foo", 0);
+  routerset_free(set);
+
+  tt_int_op(contains, ==, 0);
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_digest)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset
+ * and the digest is NULL.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  int contains;
+  (void)arg;
+
+  digestmap_set(set->digests, "bar", (void *)1);
+  contains = routerset_contains(set, NULL, 0, NULL, NULL, 0);
+  routerset_free(set);
+
+  tt_int_op(contains, ==, 0);
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_addr)
+
+/*
+ * Structural test for routerset_contains, when given a valid routerset
+ * and the address is rejected by policy.
+ */
+
+NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+    (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+
+#define MOCK_TOR_ADDR_PTR (tor_addr_t *)0xdeafbead
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  tor_addr_t *addr = MOCK_TOR_ADDR_PTR;
+  int contains;
+  (void)arg;
+
+  NS_MOCK(compare_tor_addr_to_addr_policy);
+
+  contains = routerset_contains(set, addr, 0, NULL, NULL, 0);
+  routerset_free(set);
+
+  tt_int_op(CALLED(compare_tor_addr_to_addr_policy), ==, 1);
+  tt_int_op(contains, ==, 3);
+
+  done:
+    ;
+}
+
+addr_policy_result_t
+NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+    const smartlist_t *policy)
+{
+  (void)port;
+  (void)policy;
+  CALLED(compare_tor_addr_to_addr_policy)++;
+  tt_ptr_op(addr, ==, MOCK_TOR_ADDR_PTR);
+  return ADDR_POLICY_REJECTED;
+
+  done:
+    return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_addr)
+
+/*
+ * Structural test for routerset_contains, when given a valid routerset
+ * and the address is not rejected by policy.
+ */
+
+NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+    (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+
+#define MOCK_TOR_ADDR_PTR (tor_addr_t *)0xdeafbead
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  tor_addr_t *addr = MOCK_TOR_ADDR_PTR;
+  int contains;
+  (void)arg;
+
+  NS_MOCK(compare_tor_addr_to_addr_policy);
+
+  contains = routerset_contains(set, addr, 0, NULL, NULL, 0);
+  routerset_free(set);
+
+  tt_int_op(CALLED(compare_tor_addr_to_addr_policy), ==, 1);
+  tt_int_op(contains, ==, 0);
+
+  done:
+    ;
+}
+
+addr_policy_result_t
+NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+    const smartlist_t *policy)
+{
+  (void)port;
+  (void)policy;
+  CALLED(compare_tor_addr_to_addr_policy)++;
+  tt_ptr_op(addr, ==, MOCK_TOR_ADDR_PTR);
+
+  return ADDR_POLICY_ACCEPTED;
+
+  done:
+      return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_addr)
+
+/*
+ * Structural test for routerset_contains, when given a valid routerset
+ * and the address is NULL.
+ */
+
+NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+    (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+
+#define MOCK_TOR_ADDR_PTR (tor_addr_t *)0xdeafbead
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  int contains;
+  (void)arg;
+
+  NS_MOCK(compare_tor_addr_to_addr_policy);
+
+  contains = routerset_contains(set, NULL, 0, NULL, NULL, 0);
+  routerset_free(set);
+
+  tt_int_op(contains, ==, 0);
+
+  done:
+    ;
+}
+
+addr_policy_result_t
+NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+    const smartlist_t *policy)
+{
+  (void)port;
+  (void)policy;
+  CALLED(compare_tor_addr_to_addr_policy)++;
+  tt_ptr_op(addr, ==, MOCK_TOR_ADDR_PTR);
+
+  return ADDR_POLICY_ACCEPTED;
+
+  done:
+    return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, countries_no_geoip)
+
+/*
+ * Structural test for routerset_contains, when there is no matching country
+ * for the address.
+ */
+
+NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+    (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+
+#define MOCK_TOR_ADDR_PTR (tor_addr_t *)0xdeafbead
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  int contains = 1;
+  (void)arg;
+
+  NS_MOCK(compare_tor_addr_to_addr_policy);
+  NS_MOCK(geoip_get_country_by_addr);
+
+  set->countries = bitarray_init_zero(1);
+  bitarray_set(set->countries, 1);
+  contains = routerset_contains(set, MOCK_TOR_ADDR_PTR, 0, NULL, NULL, -1);
+  routerset_free(set);
+
+  tt_int_op(contains, ==, 0);
+  tt_int_op(CALLED(compare_tor_addr_to_addr_policy), ==, 1);
+  tt_int_op(CALLED(geoip_get_country_by_addr), ==, 1);
+
+  done:
+    ;
+}
+
+addr_policy_result_t
+NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+    const smartlist_t *policy)
+{
+  (void)port;
+  (void)policy;
+  CALLED(compare_tor_addr_to_addr_policy)++;
+  tt_ptr_op(addr, ==, MOCK_TOR_ADDR_PTR);
+
+  done:
+    return ADDR_POLICY_ACCEPTED;
+}
+
+int
+NS(geoip_get_country_by_addr)(const tor_addr_t *addr)
+{
+  CALLED(geoip_get_country_by_addr)++;
+  tt_ptr_op(addr, ==, MOCK_TOR_ADDR_PTR);
+
+  done:
+    return -1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, countries_geoip)
+
+/*
+ * Structural test for routerset_contains, when there a matching country
+ * for the address.
+ */
+
+NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+    (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+
+#define MOCK_TOR_ADDR_PTR (tor_addr_t *)0xdeafbead
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  int contains = 1;
+  (void)arg;
+
+  NS_MOCK(compare_tor_addr_to_addr_policy);
+  NS_MOCK(geoip_get_country_by_addr);
+
+  set->n_countries = 2;
+  set->countries = bitarray_init_zero(1);
+  bitarray_set(set->countries, 1);
+  contains = routerset_contains(set, MOCK_TOR_ADDR_PTR, 0, NULL, NULL, -1);
+  routerset_free(set);
+
+  tt_int_op(contains, ==, 2);
+  tt_int_op(CALLED(compare_tor_addr_to_addr_policy), ==, 1);
+  tt_int_op(CALLED(geoip_get_country_by_addr), ==, 1);
+
+  done:
+    ;
+}
+
+addr_policy_result_t
+NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+    const smartlist_t *policy)
+{
+  (void)port;
+  (void)policy;
+  CALLED(compare_tor_addr_to_addr_policy)++;
+  tt_ptr_op(addr, ==, MOCK_TOR_ADDR_PTR);
+
+  done:
+    return ADDR_POLICY_ACCEPTED;
+}
+
+int
+NS(geoip_get_country_by_addr)(const tor_addr_t *addr)
+{
+  CALLED(geoip_get_country_by_addr)++;
+  tt_ptr_op(addr, ==, MOCK_TOR_ADDR_PTR);
+
+  done:
+    return 1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, only_flag_and_no_ccs)
+
+/*
+ * Functional test for routerset_add_unknown_ccs, where only_if_some_cc_set
+ * is set and there are no country names.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  routerset_t **setp = &set;
+  int r;
+  (void)arg;
+
+  r = routerset_add_unknown_ccs(setp, 1);
+
+  tt_int_op(r, ==, 0);
+
+  done:
+    routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, creates_set)
+
+/*
+ * Functional test for routerset_add_unknown_ccs, where the set argument
+ * is created if passed in as NULL.
+ */
+
+/* The mock is only used to stop the test from asserting erroneously. */
+NS_DECL(country_t, geoip_get_country, (const char *country));
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = NULL;
+  routerset_t **setp = &set;
+  int r;
+  (void)arg;
+
+  NS_MOCK(geoip_get_country);
+
+  r = routerset_add_unknown_ccs(setp, 0);
+
+  tt_ptr_op(*setp, !=, NULL);
+  tt_int_op(r, ==, 0);
+
+  done:
+    if (set != NULL)
+      routerset_free(set);
+}
+
+country_t
+NS(geoip_get_country)(const char *country)
+{
+  (void)country;
+  CALLED(geoip_get_country)++;
+
+  return -1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, add_unknown)
+
+/*
+ * Structural test for routerset_add_unknown_ccs, that the "{??}"
+ * country code is added to the list.
+ */
+
+NS_DECL(country_t, geoip_get_country, (const char *country));
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  routerset_t **setp = &set;
+  int r;
+  (void)arg;
+
+  NS_MOCK(geoip_get_country);
+  NS_MOCK(geoip_is_loaded);
+
+  r = routerset_add_unknown_ccs(setp, 0);
+
+  tt_int_op(r, ==, 1);
+  tt_int_op(smartlist_contains_string(set->country_names, "??"), ==, 1);
+  tt_int_op(smartlist_contains_string(set->list, "{??}"), ==, 1);
+
+  done:
+    if (set != NULL)
+      routerset_free(set);
+}
+
+country_t
+NS(geoip_get_country)(const char *country)
+{
+  int arg_is_qq, arg_is_a1;
+
+  CALLED(geoip_get_country)++;
+
+  arg_is_qq = !strcmp(country, "??");
+  arg_is_a1 = !strcmp(country, "A1");
+
+  tt_int_op(arg_is_qq || arg_is_a1, ==, 1);
+
+  if (arg_is_qq)
+    return 1;
+
+  done:
+    return -1;
+}
+
+int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+  CALLED(geoip_is_loaded)++;
+
+  tt_int_op(family, ==, AF_INET);
+
+  done:
+    return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, add_a1)
+
+/*
+ * Structural test for routerset_add_unknown_ccs, that the "{a1}"
+ * country code is added to the list.
+ */
+
+NS_DECL(country_t, geoip_get_country, (const char *country));
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  routerset_t **setp = &set;
+  int r;
+  (void)arg;
+
+  NS_MOCK(geoip_get_country);
+  NS_MOCK(geoip_is_loaded);
+
+  r = routerset_add_unknown_ccs(setp, 0);
+
+  tt_int_op(r, ==, 1);
+  tt_int_op(smartlist_contains_string(set->country_names, "a1"), ==, 1);
+  tt_int_op(smartlist_contains_string(set->list, "{a1}"), ==, 1);
+
+  done:
+    if (set != NULL)
+      routerset_free(set);
+}
+
+country_t
+NS(geoip_get_country)(const char *country)
+{
+  int arg_is_qq, arg_is_a1;
+
+  CALLED(geoip_get_country)++;
+
+  arg_is_qq = !strcmp(country, "??");
+  arg_is_a1 = !strcmp(country, "A1");
+
+  tt_int_op(arg_is_qq || arg_is_a1, ==, 1);
+
+  if (arg_is_a1)
+    return 1;
+
+  done:
+    return -1;
+}
+
+int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+  CALLED(geoip_is_loaded)++;
+
+  tt_int_op(family, ==, AF_INET);
+
+  done:
+    return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_contains_extendinfo
+
+/*
+ * Functional test for routerset_contains_extendinfo.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  extend_info_t ei;
+  int r;
+  const char *nickname = "foo";
+  (void)arg;
+
+  strmap_set_lc(set->names, nickname, (void *)1);
+  strncpy(ei.nickname, nickname, sizeof(ei.nickname) - 1);
+  ei.nickname[sizeof(ei.nickname) - 1] = '\0';
+
+  r = routerset_contains_extendinfo(set, &ei);
+
+  tt_int_op(r, ==, 4);
+  done:
+    routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_contains_router
+
+/*
+ * Functional test for routerset_contains_router.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  routerinfo_t ri;
+  country_t country = 1;
+  int r;
+  const char *nickname = "foo";
+  (void)arg;
+
+  strmap_set_lc(set->names, nickname, (void *)1);
+  ri.nickname = (char *)nickname;
+
+  r = routerset_contains_router(set, &ri, country);
+
+  tt_int_op(r, ==, 4);
+  done:
+    routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_contains_routerstatus
+
+/*
+ * Functional test for routerset_contains_routerstatus.
+ */
+
+// XXX: This is a bit brief. It only populates and tests the nickname fields
+// ie., enough to make the containment check succeed. Perhaps it should do
+// a bit more or test a bit more.
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  routerstatus_t rs;
+  country_t country = 1;
+  int r;
+  const char *nickname = "foo";
+  (void)arg;
+
+  strmap_set_lc(set->names, nickname, (void *)1);
+  strncpy(rs.nickname, nickname, sizeof(rs.nickname) - 1);
+  rs.nickname[sizeof(rs.nickname) - 1] = '\0';
+
+  r = routerset_contains_routerstatus(set, &rs, country);
+
+  tt_int_op(r, ==, 4);
+  done:
+    routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains_node, none)
+
+/*
+ * Functional test for routerset_contains_node, when the node has no
+ * routerset or routerinfo.
+ */
+
+node_t NS(mock_node);
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  int r;
+  (void)arg;
+
+  NS(mock_node).ri = NULL;
+  NS(mock_node).rs = NULL;
+
+  r = routerset_contains_node(set, &NS(mock_node));
+  tt_int_op(r, ==, 0);
+
+  done:
+    routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains_node, routerstatus)
+
+/*
+ * Functional test for routerset_contains_node, when the node has a
+ * routerset and no routerinfo.
+ */
+
+node_t NS(mock_node);
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  int r;
+  const char *nickname = "foo";
+  routerstatus_t rs;
+  (void)arg;
+
+  strmap_set_lc(set->names, nickname, (void *)1);
+
+  strncpy(rs.nickname, nickname, sizeof(rs.nickname) - 1);
+  rs.nickname[sizeof(rs.nickname) - 1] = '\0';
+  NS(mock_node).ri = NULL;
+  NS(mock_node).rs = &rs;
+
+  r = routerset_contains_node(set, &NS(mock_node));
+
+  tt_int_op(r, ==, 4);
+  done:
+    routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains_node, routerinfo)
+
+/*
+ * Functional test for routerset_contains_node, when the node has no
+ * routerset and a routerinfo.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  int r;
+  const char *nickname = "foo";
+  routerinfo_t ri;
+  node_t mock_node;
+  (void)arg;
+
+  strmap_set_lc(set->names, nickname, (void *)1);
+
+  ri.nickname = (char *)nickname;
+  mock_node.ri = &ri;
+  mock_node.rs = NULL;
+
+  r = routerset_contains_node(set, &mock_node);
+
+  tt_int_op(r, ==, 4);
+  done:
+    routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, no_routerset)
+
+/*
+ * Functional test for routerset_get_all_nodes, when routerset is NULL or
+ * the routerset list is NULL.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  smartlist_t *out = smartlist_new();
+  routerset_t *set = NULL;
+  (void)arg;
+
+  tt_int_op(smartlist_len(out), ==, 0);
+  routerset_get_all_nodes(out, NULL, NULL, 0);
+
+  tt_int_op(smartlist_len(out), ==, 0);
+
+  set = routerset_new();
+  smartlist_free(set->list);
+  routerset_get_all_nodes(out, NULL, NULL, 0);
+  tt_int_op(smartlist_len(out), ==, 0);
+
+  /* Just recreate list, so we can simply use routerset_free. */
+  set->list = smartlist_new();
+
+  done:
+     routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list_with_no_nodes)
+
+/*
+ * Structural test for routerset_get_all_nodes, when the routerset list
+ * is empty.
+ */
+
+NS_DECL(const node_t *, node_get_by_nickname,
+    (const char *nickname, int warn_if_unused));
+const char *NS(mock_nickname);
+
+static void
+NS(test_main)(void *arg)
+{
+  smartlist_t *out = smartlist_new();
+  routerset_t *set = routerset_new();
+  int out_len;
+  (void)arg;
+
+  NS_MOCK(node_get_by_nickname);
+
+  NS(mock_nickname) = "foo";
+  smartlist_add(set->list, tor_strdup(NS(mock_nickname)));
+
+  routerset_get_all_nodes(out, set, NULL, 0);
+  out_len = smartlist_len(out);
+
+  smartlist_free(out);
+  routerset_free(set);
+
+  tt_int_op(out_len, ==, 0);
+  tt_int_op(CALLED(node_get_by_nickname), ==, 1);
+
+  done:
+    ;
+}
+
+const node_t *
+NS(node_get_by_nickname)(const char *nickname, int warn_if_unused)
+{
+  CALLED(node_get_by_nickname)++;
+  tt_str_op(nickname, ==, NS(mock_nickname));
+  tt_int_op(warn_if_unused, ==, 1);
+
+  done:
+    return NULL;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list_flag_not_running)
+
+/*
+ * Structural test for routerset_get_all_nodes, with the running_only flag
+ * is set but the nodes are not running.
+ */
+
+NS_DECL(const node_t *, node_get_by_nickname,
+    (const char *nickname, int warn_if_unused));
+const char *NS(mock_nickname);
+node_t NS(mock_node);
+
+static void
+NS(test_main)(void *arg)
+{
+  smartlist_t *out = smartlist_new();
+  routerset_t *set = routerset_new();
+  int out_len;
+  (void)arg;
+
+  NS_MOCK(node_get_by_nickname);
+
+  NS(mock_node).is_running = 0;
+  NS(mock_nickname) = "foo";
+  smartlist_add(set->list, tor_strdup(NS(mock_nickname)));
+
+  routerset_get_all_nodes(out, set, NULL, 1);
+  out_len = smartlist_len(out);
+
+  smartlist_free(out);
+  routerset_free(set);
+
+  tt_int_op(out_len, ==, 0);
+  tt_int_op(CALLED(node_get_by_nickname), ==, 1);
+
+  done:
+    ;
+}
+
+const node_t *
+NS(node_get_by_nickname)(const char *nickname, int warn_if_unused)
+{
+  CALLED(node_get_by_nickname)++;
+  tt_str_op(nickname, ==, NS(mock_nickname));
+  tt_int_op(warn_if_unused, ==, 1);
+
+  done:
+    return &NS(mock_node);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list)
+
+/*
+ * Structural test for routerset_get_all_nodes.
+ */
+
+NS_DECL(const node_t *, node_get_by_nickname,
+    (const char *nickname, int warn_if_unused));
+char *NS(mock_nickname);
+node_t NS(mock_node);
+
+static void
+NS(test_main)(void *arg)
+{
+  smartlist_t *out = smartlist_new();
+  routerset_t *set = routerset_new();
+  int out_len;
+  node_t *ent;
+  (void)arg;
+
+  NS_MOCK(node_get_by_nickname);
+
+  NS(mock_nickname) = tor_strdup("foo");
+  smartlist_add(set->list, NS(mock_nickname));
+
+  routerset_get_all_nodes(out, set, NULL, 0);
+  out_len = smartlist_len(out);
+  ent = (node_t *)smartlist_get(out, 0);
+
+  smartlist_free(out);
+  routerset_free(set);
+
+  tt_int_op(out_len, ==, 1);
+  tt_ptr_op(ent, ==, &NS(mock_node));
+  tt_int_op(CALLED(node_get_by_nickname), ==, 1);
+
+  done:
+    ;
+}
+
+const node_t *
+NS(node_get_by_nickname)(const char *nickname, int warn_if_unused)
+{
+  CALLED(node_get_by_nickname)++;
+  tt_str_op(nickname, ==, NS(mock_nickname));
+  tt_int_op(warn_if_unused, ==, 1);
+
+  done:
+    return &NS(mock_node);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, nodelist_with_no_nodes)
+
+/*
+ * Structural test for routerset_get_all_nodes, when the nodelist has no nodes.
+ */
+
+NS_DECL(smartlist_t *, nodelist_get_list, (void));
+
+smartlist_t *NS(mock_smartlist);
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  smartlist_t *out = smartlist_new();
+  int r;
+  (void)arg;
+
+  NS_MOCK(nodelist_get_list);
+
+  smartlist_add(set->country_names, tor_strdup("{xx}"));
+  NS(mock_smartlist) = smartlist_new();
+
+  routerset_get_all_nodes(out, set, NULL, 1);
+  r = smartlist_len(out);
+  routerset_free(set);
+  smartlist_free(out);
+  smartlist_free(NS(mock_smartlist));
+
+  tt_int_op(r, ==, 0);
+  tt_int_op(CALLED(nodelist_get_list), ==, 1);
+
+  done:
+    ;
+}
+
+smartlist_t *
+NS(nodelist_get_list)(void)
+{
+  CALLED(nodelist_get_list)++;
+
+  return NS(mock_smartlist);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, nodelist_flag_not_running)
+
+/*
+ * Structural test for routerset_get_all_nodes, with a non-list routerset
+ * the running_only flag is set, but the nodes are not running.
+ */
+
+NS_DECL(smartlist_t *, nodelist_get_list, (void));
+
+smartlist_t *NS(mock_smartlist);
+node_t NS(mock_node);
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  smartlist_t *out = smartlist_new();
+  int r;
+  (void)arg;
+
+  NS_MOCK(nodelist_get_list);
+
+  smartlist_add(set->country_names, tor_strdup("{xx}"));
+  NS(mock_smartlist) = smartlist_new();
+  NS(mock_node).is_running = 0;
+  smartlist_add(NS(mock_smartlist), (void *)&NS(mock_node));
+
+  routerset_get_all_nodes(out, set, NULL, 1);
+  r = smartlist_len(out);
+  routerset_free(set);
+  smartlist_free(out);
+  smartlist_free(NS(mock_smartlist));
+
+  tt_int_op(r, ==, 0);
+  tt_int_op(CALLED(nodelist_get_list), ==, 1);
+
+  done:
+    ;
+}
+
+smartlist_t *
+NS(nodelist_get_list)(void)
+{
+  CALLED(nodelist_get_list)++;
+
+  return NS(mock_smartlist);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_subtract_nodes
+
+/*
+ * Functional test for routerset_subtract_nodes.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = routerset_new();
+  smartlist_t *list = smartlist_new();
+  const char *nickname = "foo";
+  routerinfo_t ri;
+  node_t mock_node;
+  (void)arg;
+
+  strmap_set_lc(set->names, nickname, (void *)1);
+
+  ri.nickname = (char *)nickname;
+  mock_node.rs = NULL;
+  mock_node.ri = &ri;
+  smartlist_add(list, (void *)&mock_node);
+
+  tt_int_op(smartlist_len(list), !=, 0);
+  routerset_subtract_nodes(list, set);
+
+  tt_int_op(smartlist_len(list), ==, 0);
+  done:
+    routerset_free(set);
+    smartlist_free(list);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_subtract_nodes, null_routerset)
+
+/*
+ * Functional test for routerset_subtract_nodes, with a NULL routerset.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *set = NULL;
+  smartlist_t *list = smartlist_new();
+  const char *nickname = "foo";
+  routerinfo_t ri;
+  node_t mock_node;
+  (void)arg;
+
+  ri.nickname = (char *)nickname;
+  mock_node.ri = &ri;
+  smartlist_add(list, (void *)&mock_node);
+
+  tt_int_op(smartlist_len(list), !=, 0);
+  routerset_subtract_nodes(list, set);
+
+  tt_int_op(smartlist_len(list), !=, 0);
+  done:
+    routerset_free(set);
+    smartlist_free(list);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_to_string
+
+/*
+ * Functional test for routerset_to_string.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  const routerset_t *set;
+  char *s;
+  (void)arg;
+
+  set = NULL;
+  s = routerset_to_string(set);
+  tt_str_op(s, ==, "");
+  tor_free(s);
+
+  set = routerset_new();
+  s = routerset_to_string(set);
+  tt_str_op(s, ==, "");
+  tor_free(s);
+
+  set = routerset_new();
+  smartlist_add(set->list, tor_strndup("a", 1));
+  s = routerset_to_string(set);
+  tt_str_op(s, ==, "a");
+  tor_free(s);
+
+  set = routerset_new();
+  smartlist_add(set->list, tor_strndup("a", 1));
+  smartlist_add(set->list, tor_strndup("b", 1));
+  s = routerset_to_string(set);
+  tt_str_op(s, ==, "a,b");
+  tor_free(s);
+
+  done:
+    if (s)
+      tor_free(s);
+    if (set)
+      routerset_free((routerset_t *)set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_equal, empty_empty)
+
+/*
+ * Functional test for routerset_equal, with both routersets empty.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *a = routerset_new(), *b = routerset_new();
+  int r;
+  (void)arg;
+
+  r = routerset_equal(a, b);
+  routerset_free(a);
+  routerset_free(b);
+
+  tt_int_op(r, ==, 1);
+
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_equal, empty_not_empty)
+
+/*
+ * Functional test for routerset_equal, with one routersets empty.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *a = routerset_new(), *b = routerset_new();
+  int r;
+  (void)arg;
+
+  smartlist_add(b->list, tor_strdup("{xx}"));
+  r = routerset_equal(a, b);
+  routerset_free(a);
+  routerset_free(b);
+
+  tt_int_op(r, ==, 0);
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_equal, differing_lengths)
+
+/*
+ * Functional test for routerset_equal, with the routersets having
+ * differing lengths.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *a = routerset_new(), *b = routerset_new();
+  int r;
+  (void)arg;
+
+  smartlist_add(a->list, tor_strdup("{aa}"));
+  smartlist_add(b->list, tor_strdup("{b1}"));
+  smartlist_add(b->list, tor_strdup("{b2}"));
+  r = routerset_equal(a, b);
+  routerset_free(a);
+  routerset_free(b);
+
+  tt_int_op(r, ==, 0);
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_equal, unequal)
+
+/*
+ * Functional test for routerset_equal, with the routersets being
+ * different.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *a = routerset_new(), *b = routerset_new();
+  int r;
+  (void)arg;
+
+  smartlist_add(a->list, tor_strdup("foo"));
+  smartlist_add(b->list, tor_strdup("bar"));
+  r = routerset_equal(a, b);
+  routerset_free(a);
+  routerset_free(b);
+
+  tt_int_op(r, ==, 0);
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_equal, equal)
+
+/*
+ * Functional test for routerset_equal, with the routersets being
+ * equal.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *a = routerset_new(), *b = routerset_new();
+  int r;
+  (void)arg;
+
+  smartlist_add(a->list, tor_strdup("foo"));
+  smartlist_add(b->list, tor_strdup("foo"));
+  r = routerset_equal(a, b);
+  routerset_free(a);
+  routerset_free(b);
+
+  tt_int_op(r, ==, 1);
+  done:
+    ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_free, null_routerset)
+
+/*
+ * Structural test for routerset_free, where the routerset is NULL.
+ */
+
+NS_DECL(void, smartlist_free, (smartlist_t *sl));
+
+static void
+NS(test_main)(void *arg)
+{
+  (void)arg;
+
+  NS_MOCK(smartlist_free);
+
+  routerset_free(NULL);
+
+  tt_int_op(CALLED(smartlist_free), ==, 0);
+
+  done:
+    ;
+}
+
+void
+NS(smartlist_free)(smartlist_t *s)
+{
+  (void)s;
+  CALLED(smartlist_free)++;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_free
+
+/*
+ * Structural test for routerset_free.
+ */
+
+NS_DECL(void, smartlist_free, (smartlist_t *sl));
+NS_DECL(void, strmap_free,(strmap_t *map, void (*free_val)(void*)));
+NS_DECL(void, digestmap_free, (digestmap_t *map, void (*free_val)(void*)));
+
+static void
+NS(test_main)(void *arg)
+{
+  routerset_t *routerset = routerset_new();
+  (void)arg;
+
+  NS_MOCK(smartlist_free);
+  NS_MOCK(strmap_free);
+  NS_MOCK(digestmap_free);
+
+  routerset_free(routerset);
+
+  tt_int_op(CALLED(smartlist_free), !=, 0);
+  tt_int_op(CALLED(strmap_free), !=, 0);
+  tt_int_op(CALLED(digestmap_free), !=, 0);
+
+  done:
+    ;
+}
+
+void
+NS(smartlist_free)(smartlist_t *s)
+{
+  (void)s;
+  CALLED(smartlist_free)++;
+}
+
+void
+NS(strmap_free)(strmap_t *map, void (*free_val)(void*))
+{
+  (void)map;
+  (void)free_val;
+  CALLED(strmap_free)++;
+}
+
+void
+NS(digestmap_free)(digestmap_t *map, void (*free_val)(void*))
+{
+  (void)map;
+  (void)free_val;
+  CALLED(digestmap_free)++;
+}
+
+#undef NS_SUBMODULE
+
+struct testcase_t routerset_tests[] = {
+  TEST_CASE(routerset_new),
+  TEST_CASE(routerset_get_countryname),
+  TEST_CASE(routerset_is_list),
+  TEST_CASE(routerset_needs_geoip),
+  TEST_CASE(routerset_is_empty),
+  TEST_CASE_ASPECT(routerset_contains, null_set_or_null_set_list),
+  TEST_CASE_ASPECT(routerset_contains, set_and_nickname),
+  TEST_CASE_ASPECT(routerset_contains, set_and_null_nickname),
+  TEST_CASE_ASPECT(routerset_contains, set_and_no_nickname),
+  TEST_CASE_ASPECT(routerset_contains, set_and_digest),
+  TEST_CASE_ASPECT(routerset_contains, set_and_no_digest),
+  TEST_CASE_ASPECT(routerset_contains, set_and_null_digest),
+  TEST_CASE_ASPECT(routerset_contains, set_and_addr),
+  TEST_CASE_ASPECT(routerset_contains, set_and_no_addr),
+  TEST_CASE_ASPECT(routerset_contains, set_and_null_addr),
+  TEST_CASE_ASPECT(routerset_contains, countries_no_geoip),
+  TEST_CASE_ASPECT(routerset_contains, countries_geoip),
+  TEST_CASE_ASPECT(routerset_add_unknown_ccs, only_flag_and_no_ccs),
+  TEST_CASE_ASPECT(routerset_add_unknown_ccs, creates_set),
+  TEST_CASE_ASPECT(routerset_add_unknown_ccs, add_unknown),
+  TEST_CASE_ASPECT(routerset_add_unknown_ccs, add_a1),
+  TEST_CASE(routerset_contains_extendinfo),
+  TEST_CASE(routerset_contains_router),
+  TEST_CASE(routerset_contains_routerstatus),
+  TEST_CASE_ASPECT(routerset_contains_node, none),
+  TEST_CASE_ASPECT(routerset_contains_node, routerinfo),
+  TEST_CASE_ASPECT(routerset_contains_node, routerstatus),
+  TEST_CASE_ASPECT(routerset_get_all_nodes, no_routerset),
+  TEST_CASE_ASPECT(routerset_get_all_nodes, list_with_no_nodes),
+  TEST_CASE_ASPECT(routerset_get_all_nodes, list_flag_not_running),
+  TEST_CASE_ASPECT(routerset_get_all_nodes, list),
+  TEST_CASE_ASPECT(routerset_get_all_nodes, nodelist_with_no_nodes),
+  TEST_CASE_ASPECT(routerset_get_all_nodes, nodelist_flag_not_running),
+  TEST_CASE_ASPECT(routerset_refresh_counties, geoip_not_loaded),
+  TEST_CASE_ASPECT(routerset_refresh_counties, no_countries),
+  TEST_CASE_ASPECT(routerset_refresh_counties, one_valid_country),
+  TEST_CASE_ASPECT(routerset_refresh_counties, one_invalid_country),
+  TEST_CASE_ASPECT(routerset_union, source_bad),
+  TEST_CASE_ASPECT(routerset_union, one),
+  TEST_CASE_ASPECT(routerset_parse, malformed),
+  TEST_CASE_ASPECT(routerset_parse, valid_hexdigest),
+  TEST_CASE_ASPECT(routerset_parse, valid_nickname),
+  TEST_CASE_ASPECT(routerset_parse, get_countryname),
+  TEST_CASE_ASPECT(routerset_parse, policy),
+  TEST_CASE(routerset_subtract_nodes),
+  TEST_CASE_ASPECT(routerset_subtract_nodes, null_routerset),
+  TEST_CASE(routerset_to_string),
+  TEST_CASE_ASPECT(routerset_equal, empty_empty),
+  TEST_CASE_ASPECT(routerset_equal, empty_not_empty),
+  TEST_CASE_ASPECT(routerset_equal, differing_lengths),
+  TEST_CASE_ASPECT(routerset_equal, unequal),
+  TEST_CASE_ASPECT(routerset_equal, equal),
+  TEST_CASE_ASPECT(routerset_free, null_routerset),
+  TEST_CASE(routerset_free),
+  END_OF_TESTCASES
+};
+



More information about the tor-commits mailing list