summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/runner.c3
-rw-r--r--tests/t_fdstate.c224
-rw-r--r--tests/t_hex.c28
-rw-r--r--tests/t_iovec.c20
-rw-r--r--tests/t_urlencoded.c (renamed from tests/t_scan_urlencoded_query.c)66
-rw-r--r--tests/t_vector.c16
-rw-r--r--tests/test.h3
7 files changed, 293 insertions, 67 deletions
diff --git a/tests/runner.c b/tests/runner.c
index 148b928..9e5c99f 100644
--- a/tests/runner.c
+++ b/tests/runner.c
@@ -14,7 +14,7 @@ struct module {
14 void (*run)(void); 14 void (*run)(void);
15}; 15};
16 16
17static const struct module modules[] = {{"scan_urlencoded_query", test_scan_urlencoded_query}, 17static const struct module modules[] = {{"ot_urlencoded", test_urlencoded},
18 {"ot_iovec", test_iovec}, 18 {"ot_iovec", test_iovec},
19 {"ot_vector", test_vector}, 19 {"ot_vector", test_vector},
20 {"ot_random", test_random}, 20 {"ot_random", test_random},
@@ -25,6 +25,7 @@ static const struct module modules[] = {{"scan_urlencoded_query", test_scan_urle
25 {"ot_socket", test_socket}, 25 {"ot_socket", test_socket},
26 {"ot_mutex", test_mutex}, 26 {"ot_mutex", test_mutex},
27 {"ot_batch", test_batch}, 27 {"ot_batch", test_batch},
28 {"ot_fdstate", test_fdstate},
28 {"ot_accesslist", test_accesslist}, 29 {"ot_accesslist", test_accesslist},
29 {NULL, NULL}}; 30 {NULL, NULL}};
30 31
diff --git a/tests/t_fdstate.c b/tests/t_fdstate.c
new file mode 100644
index 0000000..bf8724a
--- /dev/null
+++ b/tests/t_fdstate.c
@@ -0,0 +1,224 @@
1/* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever.
3
4 $id$ */
5
6/* System */
7#include <pthread.h>
8#include <stdatomic.h>
9#include <stdint.h>
10#include <stdlib.h>
11#include <string.h>
12
13/* Opentracker */
14#include "ot_fdstate.h"
15#include "test.h"
16
17/* ------------------------------------------------------- one thread first */
18
19static void case_open_claim_release(void) {
20 char cookie[4];
21 uint32_t generation;
22
23 test_case("a descriptor taken into the table can be claimed and gives back its cookie");
24 generation = fdstate_open(7, cookie, 0);
25 CHECK_INT(fdstate_claim(7, generation), 1);
26 CHECK_PTR(fdstate_cookie(7), cookie);
27 fdstate_release(7);
28
29 test_case("and can be claimed again once released");
30 CHECK_INT(fdstate_claim(7, generation), 1);
31 fdstate_release(7);
32 fdstate_close(7);
33}
34
35static void case_one_holder_at_a_time(void) {
36 uint32_t generation = fdstate_open(8, NULL, 0);
37
38 test_case("a descriptor somebody holds cannot be claimed again");
39 CHECK_INT(fdstate_claim(8, generation), 1);
40 CHECK_INT(fdstate_claim(8, generation), 0);
41 fdstate_release(8);
42 CHECK_INT(fdstate_claim(8, generation), 1);
43 fdstate_release(8);
44 fdstate_close(8);
45}
46
47static void case_stale_generation_is_refused(void) {
48 char first[4], second[4];
49 uint32_t old, new;
50
51 test_case("a caller quoting the generation of a closed descriptor is turned away");
52 old = fdstate_open(9, first, 0);
53 fdstate_close(9);
54 new = fdstate_open(9, second, 0);
55 CHECK(old != new);
56 CHECK_INT(fdstate_claim(9, old), 0);
57
58 test_case("while the one quoting the new generation gets the new cookie");
59 CHECK_INT(fdstate_claim(9, new), 1);
60 CHECK_PTR(fdstate_cookie(9), second);
61 fdstate_release(9);
62 fdstate_close(9);
63}
64
65static void case_expiry(void) {
66 uint32_t generation = fdstate_open(10, NULL, 100);
67
68 test_case("a descriptor past its expiry is collected");
69 CHECK_INT(fdstate_claim_expired(10, 99), 0);
70 CHECK_INT(fdstate_claim_expired(10, 100), 1);
71 fdstate_close(10);
72
73 test_case("one that never expires is never collected");
74 generation = fdstate_open(10, NULL, 0);
75 CHECK_INT(fdstate_claim_expired(10, 1 << 30), 0);
76
77 test_case("and one somebody is working on is left alone");
78 fdstate_set_expiry(10, 1);
79 CHECK_INT(fdstate_claim(10, generation), 1);
80 CHECK_INT(fdstate_claim_expired(10, 1 << 30), 0);
81 fdstate_release(10);
82 CHECK_INT(fdstate_claim_expired(10, 1 << 30), 1);
83 fdstate_close(10);
84}
85
86static void case_out_of_range(void) {
87 test_case("a descriptor outside the table is refused rather than trusted");
88 CHECK_INT(fdstate_claim(-1, 0), 0);
89 CHECK_INT(fdstate_claim((int)fdstate_slots(), 0), 0);
90 CHECK_INT(fdstate_claim_expired(-1, 0), 0);
91 CHECK_PTR(fdstate_cookie(-1), NULL);
92}
93
94/* --------------------------------------------------------- then in anger */
95
96/* The race this is about only exists while a descriptor is being recycled,
97 so recycling is driven by work done rather than by a clock: every slot is
98 given up after RECYCLE_AFTER claims, whatever the machine's speed. */
99
100#define STRESS_SLOTS 64
101#define RECYCLE_AFTER 32
102#define STRESS_CLAIMS 200000
103#define STRESS_GIVEUP (STRESS_CLAIMS * 100)
104
105static _Atomic long stress_claims, stress_recycles, stress_violations, stress_attempts;
106static _Atomic int stress_lives[STRESS_SLOTS];
107static _Atomic int stress_live[STRESS_SLOTS];
108
109/* Generation and cookie are published in one word so a worker can never read
110 a cookie that belongs to a different generation than the one it claimed
111 with. Each connection gets a cookie nobody else ever gets. */
112static _Atomic uint64_t stress_conn[STRESS_SLOTS];
113static _Atomic uint64_t stress_next_cookie;
114
115#define STRESS_CONN(cookie, gen) (((uint64_t)(cookie) << 32) | (uint32_t)(gen))
116#define STRESS_CONN_COOKIE(w) ((void *)(uintptr_t)((w) >> 32))
117#define STRESS_CONN_GEN(w) ((uint32_t)(w))
118
119static int stress_running(void) {
120 return atomic_load(&stress_claims) < STRESS_CLAIMS && atomic_load(&stress_attempts) < STRESS_GIVEUP;
121}
122
123static void *stress_worker(void *arg) {
124 unsigned seed = (unsigned)(uintptr_t)arg;
125
126 while (stress_running()) {
127 int fd = (int)(rand_r(&seed) % STRESS_SLOTS);
128 uint64_t conn = atomic_load(&stress_conn[fd]);
129
130 atomic_fetch_add(&stress_attempts, 1);
131 if (!fdstate_claim(fd, STRESS_CONN_GEN(conn)))
132 continue;
133
134 if (fdstate_cookie(fd) != STRESS_CONN_COOKIE(conn))
135 atomic_fetch_add(&stress_violations, 1);
136 if (atomic_fetch_sub(&stress_lives[fd], 1) <= 1)
137 fdstate_set_expiry(fd, 1); /* retired by its holder, as a handler would */
138 if (fdstate_cookie(fd) != STRESS_CONN_COOKIE(conn))
139 atomic_fetch_add(&stress_violations, 1);
140
141 fdstate_release(fd);
142 atomic_fetch_add(&stress_claims, 1);
143 }
144 return NULL;
145}
146
147static void *stress_keeper(void *arg) {
148 (void)arg;
149 while (stress_running()) {
150 int fd;
151
152 for (fd = 0; fd < STRESS_SLOTS; ++fd) {
153 if (atomic_load(&stress_live[fd])) {
154 if (!fdstate_claim_expired(fd, 1))
155 continue; /* a worker has it, come back */
156 fdstate_close(fd);
157 atomic_store(&stress_live[fd], 0);
158 atomic_fetch_add(&stress_recycles, 1);
159 }
160 {
161 void *cookie = (void *)(uintptr_t)(atomic_fetch_add(&stress_next_cookie, 1) + 1);
162 uint32_t gen = fdstate_open(fd, cookie, 0);
163
164 atomic_store(&stress_lives[fd], RECYCLE_AFTER);
165 atomic_store(&stress_conn[fd], STRESS_CONN((uintptr_t)cookie, gen));
166 atomic_store(&stress_live[fd], 1);
167 }
168 }
169 }
170 return NULL;
171}
172
173static void case_recycling_under_load(void) {
174 pthread_t worker[4], keeper;
175 size_t i;
176
177 test_case("no worker is ever handed a connection from another generation");
178 atomic_store(&stress_claims, 0);
179 atomic_store(&stress_recycles, 0);
180 atomic_store(&stress_violations, 0);
181 atomic_store(&stress_attempts, 0);
182 atomic_store(&stress_next_cookie, 0);
183 /* Every slot is opened and published before any worker runs: a worker only
184 ever learns of a descriptor from whoever registered it, and never
185 invents a generation of its own. */
186 for (i = 0; i < STRESS_SLOTS; ++i) {
187 void *cookie = (void *)(uintptr_t)(atomic_fetch_add(&stress_next_cookie, 1) + 1);
188 uint32_t gen = fdstate_open((int)i, cookie, 0);
189
190 atomic_store(&stress_lives[i], RECYCLE_AFTER);
191 atomic_store(&stress_conn[i], STRESS_CONN((uintptr_t)cookie, gen));
192 atomic_store(&stress_live[i], 1);
193 }
194
195 pthread_create(&keeper, NULL, stress_keeper, NULL);
196 for (i = 0; i < sizeof(worker) / sizeof(worker[0]); ++i)
197 pthread_create(&worker[i], NULL, stress_worker, (void *)(uintptr_t)(i + 1));
198 for (i = 0; i < sizeof(worker) / sizeof(worker[0]); ++i)
199 pthread_join(worker[i], NULL);
200 pthread_join(keeper, NULL);
201
202 CHECK_INT(atomic_load(&stress_violations), 0);
203
204 test_case("and the run actually recycled descriptors, or it proved nothing");
205 CHECK(atomic_load(&stress_claims) >= STRESS_CLAIMS);
206 CHECK(atomic_load(&stress_recycles) > STRESS_CLAIMS / (RECYCLE_AFTER * 4));
207
208 for (i = 0; i < STRESS_SLOTS; ++i)
209 fdstate_close((int)i);
210}
211
212void test_fdstate(void) {
213 CHECK_INT(fdstate_init(), 0);
214 CHECK(fdstate_slots() > STRESS_SLOTS);
215
216 case_open_claim_release();
217 case_one_holder_at_a_time();
218 case_stale_generation_is_refused();
219 case_expiry();
220 case_out_of_range();
221 case_recycling_under_load();
222
223 fdstate_deinit();
224}
diff --git a/tests/t_hex.c b/tests/t_hex.c
index 7cce8ac..a761737 100644
--- a/tests/t_hex.c
+++ b/tests/t_hex.c
@@ -18,7 +18,7 @@ static void case_encode(void) {
18 18
19 test_case("a hash encodes to forty upper case digits and a terminator"); 19 test_case("a hash encodes to forty upper case digits and a terminator");
20 memset(dest, 0x7f, sizeof(dest)); 20 memset(dest, 0x7f, sizeof(dest));
21 CHECK_PTR(hex_fromhash(dest, sample), dest); 21 CHECK_PTR(hex_from_hash(dest, sample), dest);
22 CHECK_STR(dest, "000123456789ABCDEFFF10203040506070809" "0A0"); 22 CHECK_STR(dest, "000123456789ABCDEFFF10203040506070809" "0A0");
23 CHECK_INT(strlen(dest), 40); 23 CHECK_INT(strlen(dest), 40);
24 CHECK_INT((unsigned char)dest[41], 0x7f); 24 CHECK_INT((unsigned char)dest[41], 0x7f);
@@ -28,7 +28,7 @@ static void case_decode(void) {
28 ot_hash hash; 28 ot_hash hash;
29 29
30 test_case("forty digits decode back to the hash"); 30 test_case("forty digits decode back to the hash");
31 CHECK(hex_tohash(hash, "000123456789ABCDEFFF10203040506070809" "0A0")); 31 CHECK(hex_to_hash(hash, "000123456789ABCDEFFF10203040506070809" "0A0"));
32 CHECK_MEM(hash, sample, sizeof(sample)); 32 CHECK_MEM(hash, sample, sizeof(sample));
33} 33}
34 34
@@ -41,8 +41,8 @@ static void case_round_trip(void) {
41 for (i = 0; i < 256; ++i) { 41 for (i = 0; i < 256; ++i) {
42 uint8_t probe[20]; 42 uint8_t probe[20];
43 memset(probe, (uint8_t)i, sizeof(probe)); 43 memset(probe, (uint8_t)i, sizeof(probe));
44 hex_fromhash(text, probe); 44 hex_from_hash(text, probe);
45 if (!hex_tohash(hash, text) || memcmp(hash, probe, sizeof(probe))) { 45 if (!hex_to_hash(hash, text) || memcmp(hash, probe, sizeof(probe))) {
46 test_failf(__FILE__, __LINE__, "round trip failed for byte value %zu", i); 46 test_failf(__FILE__, __LINE__, "round trip failed for byte value %zu", i);
47 return; 47 return;
48 } 48 }
@@ -54,8 +54,8 @@ static void case_decode_is_case_insensitive(void) {
54 ot_hash upper, lower; 54 ot_hash upper, lower;
55 55
56 test_case("lower case digits decode the same as upper case"); 56 test_case("lower case digits decode the same as upper case");
57 CHECK(hex_tohash(upper, "ABCDEF0123456789ABCDEF0123456789ABCDEF01")); 57 CHECK(hex_to_hash(upper, "ABCDEF0123456789ABCDEF0123456789ABCDEF01"));
58 CHECK(hex_tohash(lower, "abcdef0123456789abcdef0123456789abcdef01")); 58 CHECK(hex_to_hash(lower, "abcdef0123456789abcdef0123456789abcdef01"));
59 CHECK_MEM(lower, upper, sizeof(ot_hash)); 59 CHECK_MEM(lower, upper, sizeof(ot_hash));
60} 60}
61 61
@@ -63,18 +63,18 @@ static void case_rejects_non_digits(void) {
63 ot_hash hash; 63 ot_hash hash;
64 64
65 test_case("a non hex character anywhere rejects the whole string"); 65 test_case("a non hex character anywhere rejects the whole string");
66 CHECK_INT(hex_tohash(hash, "g00123456789ABCDEFFF102030405060708090A0"), 0); 66 CHECK_INT(hex_to_hash(hash, "g00123456789ABCDEFFF102030405060708090A0"), 0);
67 CHECK_INT(hex_tohash(hash, "000123456789ABCDEFFF102030405060708090Ag"), 0); 67 CHECK_INT(hex_to_hash(hash, "000123456789ABCDEFFF102030405060708090Ag"), 0);
68 CHECK_INT(hex_tohash(hash, "000123456789ABCDEF:F102030405060708090A"), 0); 68 CHECK_INT(hex_to_hash(hash, "000123456789ABCDEF:F102030405060708090A"), 0);
69} 69}
70 70
71static void case_rejects_short_input(void) { 71static void case_rejects_short_input(void) {
72 ot_hash hash; 72 ot_hash hash;
73 73
74 test_case("a string shorter than forty digits is rejected"); 74 test_case("a string shorter than forty digits is rejected");
75 CHECK_INT(hex_tohash(hash, ""), 0); 75 CHECK_INT(hex_to_hash(hash, ""), 0);
76 CHECK_INT(hex_tohash(hash, "00"), 0); 76 CHECK_INT(hex_to_hash(hash, "00"), 0);
77 CHECK_INT(hex_tohash(hash, "000123456789ABCDEFFF102030405060708090A"), 0); 77 CHECK_INT(hex_to_hash(hash, "000123456789ABCDEFFF102030405060708090A"), 0);
78} 78}
79 79
80static void case_leaves_hash_untouched_on_failure(void) { 80static void case_leaves_hash_untouched_on_failure(void) {
@@ -82,7 +82,7 @@ static void case_leaves_hash_untouched_on_failure(void) {
82 82
83 test_case("a rejected string leaves the destination untouched"); 83 test_case("a rejected string leaves the destination untouched");
84 memset(hash, 0x5a, sizeof(hash)); 84 memset(hash, 0x5a, sizeof(hash));
85 CHECK_INT(hex_tohash(hash, "000123456789ABCDEFFF10203040506070809XX0"), 0); 85 CHECK_INT(hex_to_hash(hash, "000123456789ABCDEFFF10203040506070809XX0"), 0);
86 CHECK_MEM(hash, "\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a", sizeof(hash)); 86 CHECK_MEM(hash, "\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a", sizeof(hash));
87} 87}
88 88
@@ -96,7 +96,7 @@ static void case_stops_at_the_terminator(void) {
96 memcpy(guarded, "0012", 4); 96 memcpy(guarded, "0012", 4);
97 guarded[4] = 0; 97 guarded[4] = 0;
98 memset(guarded + 5, 'f', 3); 98 memset(guarded + 5, 'f', 3);
99 CHECK_INT(hex_tohash(hash, guarded), 0); 99 CHECK_INT(hex_to_hash(hash, guarded), 0);
100} 100}
101 101
102static void case_isdigit(void) { 102static void case_isdigit(void) {
diff --git a/tests/t_iovec.c b/tests/t_iovec.c
index 89f3fda..2553141 100644
--- a/tests/t_iovec.c
+++ b/tests/t_iovec.c
@@ -18,13 +18,13 @@ static void case_increase_and_length(void) {
18 void *first, *second; 18 void *first, *second;
19 19
20 test_case("increase appends an entry and length is their sum"); 20 test_case("increase appends an entry and length is their sum");
21 first = iovec_increase(&entries, &vector, 100); 21 first = iovec_new_chunk(&entries, &vector, 100);
22 CHECK(first != NULL); 22 CHECK(first != NULL);
23 CHECK_INT(entries, 1); 23 CHECK_INT(entries, 1);
24 CHECK_INT(vector[0].iov_len, 100); 24 CHECK_INT(vector[0].iov_len, 100);
25 CHECK_PTR(vector[0].iov_base, first); 25 CHECK_PTR(vector[0].iov_base, first);
26 26
27 second = iovec_increase(&entries, &vector, 50); 27 second = iovec_new_chunk(&entries, &vector, 50);
28 CHECK(second != NULL); 28 CHECK(second != NULL);
29 CHECK_INT(entries, 2); 29 CHECK_INT(entries, 2);
30 CHECK_INT(vector[1].iov_len, 50); 30 CHECK_INT(vector[1].iov_len, 50);
@@ -38,8 +38,8 @@ static void case_free_resets(void) {
38 struct iovec *vector = NULL; 38 struct iovec *vector = NULL;
39 39
40 test_case("free releases the entries and resets the vector"); 40 test_case("free releases the entries and resets the vector");
41 CHECK(iovec_increase(&entries, &vector, 10) != NULL); 41 CHECK(iovec_new_chunk(&entries, &vector, 10) != NULL);
42 CHECK(iovec_increase(&entries, &vector, 10) != NULL); 42 CHECK(iovec_new_chunk(&entries, &vector, 10) != NULL);
43 iovec_free(&entries, &vector); 43 iovec_free(&entries, &vector);
44 CHECK_INT(entries, 0); 44 CHECK_INT(entries, 0);
45 CHECK_PTR(vector, NULL); 45 CHECK_PTR(vector, NULL);
@@ -52,12 +52,12 @@ static void case_fixlast_shrinks(void) {
52 char *block; 52 char *block;
53 53
54 test_case("fixlast trims the last entry to the bytes actually used"); 54 test_case("fixlast trims the last entry to the bytes actually used");
55 CHECK(iovec_increase(&entries, &vector, 64) != NULL); 55 CHECK(iovec_new_chunk(&entries, &vector, 64) != NULL);
56 block = iovec_increase(&entries, &vector, 1000); 56 block = iovec_new_chunk(&entries, &vector, 1000);
57 CHECK(block != NULL); 57 CHECK(block != NULL);
58 memset(block, 'x', 20); 58 memset(block, 'x', 20);
59 59
60 iovec_fixlast(&entries, &vector, block + 20); 60 iovec_trim_last(&entries, &vector, block + 20);
61 CHECK_INT(entries, 2); 61 CHECK_INT(entries, 2);
62 CHECK_INT(vector[1].iov_len, 20); 62 CHECK_INT(vector[1].iov_len, 20);
63 CHECK_INT(iovec_length(&entries, (const struct iovec **)&vector), 84); 63 CHECK_INT(iovec_length(&entries, (const struct iovec **)&vector), 84);
@@ -71,7 +71,7 @@ static void case_fixlast_on_empty(void) {
71 struct iovec *vector = NULL; 71 struct iovec *vector = NULL;
72 72
73 test_case("fixlast on an empty vector does nothing"); 73 test_case("fixlast on an empty vector does nothing");
74 iovec_fixlast(&entries, &vector, NULL); 74 iovec_trim_last(&entries, &vector, NULL);
75 CHECK_INT(entries, 0); 75 CHECK_INT(entries, 0);
76 CHECK_PTR(vector, NULL); 76 CHECK_PTR(vector, NULL);
77} 77}
@@ -103,9 +103,9 @@ static void case_fix_increase(void) {
103 char *block; 103 char *block;
104 104
105 test_case("fix_increase trims the previous entry and adds a new one"); 105 test_case("fix_increase trims the previous entry and adds a new one");
106 block = iovec_increase(&entries, &vector, 500); 106 block = iovec_new_chunk(&entries, &vector, 500);
107 CHECK(block != NULL); 107 CHECK(block != NULL);
108 block = iovec_fix_increase_or_free(&entries, &vector, block + 30, 200); 108 block = iovec_next_chunk(&entries, &vector, block + 30, 200);
109 CHECK(block != NULL); 109 CHECK(block != NULL);
110 CHECK_INT(entries, 2); 110 CHECK_INT(entries, 2);
111 CHECK_INT(vector[0].iov_len, 30); 111 CHECK_INT(vector[0].iov_len, 30);
diff --git a/tests/t_scan_urlencoded_query.c b/tests/t_urlencoded.c
index f660ea3..1239e6b 100644
--- a/tests/t_scan_urlencoded_query.c
+++ b/tests/t_urlencoded.c
@@ -7,7 +7,7 @@
7#include <string.h> 7#include <string.h>
8 8
9/* Opentracker */ 9/* Opentracker */
10#include "scan_urlencoded_query.h" 10#include "ot_urlencoded.h"
11#include "test.h" 11#include "test.h"
12 12
13/* The scanner returns the number of bytes written to the destination, or 13/* The scanner returns the number of bytes written to the destination, or
@@ -23,7 +23,7 @@ static void case_path(void) {
23 ssize_t n; 23 ssize_t n;
24 24
25 test_case("path stops at the question mark"); 25 test_case("path stops at the question mark");
26 n = scan_urlencoded_query(&p, dest, SCAN_PATH); 26 n = urlencoded_parse(&p, dest, SCAN_PATH);
27 CHECK_INT(n, 9); 27 CHECK_INT(n, 9);
28 dest[n] = 0; 28 dest[n] = 0;
29 CHECK_STR(dest, "/announce"); 29 CHECK_STR(dest, "/announce");
@@ -37,22 +37,22 @@ static void case_param_and_value(void) {
37 ssize_t n; 37 ssize_t n;
38 38
39 test_case("parameter stops at '=', value stops at '&'"); 39 test_case("parameter stops at '=', value stops at '&'");
40 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_PARAM); 40 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_PARAM);
41 CHECK_INT(n, 9); 41 CHECK_INT(n, 9);
42 dest[n] = 0; 42 dest[n] = 0;
43 CHECK_STR(dest, "info_hash"); 43 CHECK_STR(dest, "info_hash");
44 44
45 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_VALUE); 45 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_VALUE);
46 CHECK_INT(n, 3); 46 CHECK_INT(n, 3);
47 dest[n] = 0; 47 dest[n] = 0;
48 CHECK_STR(dest, "abc"); 48 CHECK_STR(dest, "abc");
49 49
50 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_PARAM); 50 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_PARAM);
51 CHECK_INT(n, 4); 51 CHECK_INT(n, 4);
52 dest[n] = 0; 52 dest[n] = 0;
53 CHECK_STR(dest, "port"); 53 CHECK_STR(dest, "port");
54 54
55 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_VALUE); 55 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_VALUE);
56 CHECK_INT(n, 2); 56 CHECK_INT(n, 2);
57 dest[n] = 0; 57 dest[n] = 0;
58 CHECK_STR(dest, "80"); 58 CHECK_STR(dest, "80");
@@ -65,7 +65,7 @@ static void case_percent_decoding(void) {
65 ssize_t n; 65 ssize_t n;
66 66
67 test_case("percent escapes decode"); 67 test_case("percent escapes decode");
68 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_VALUE); 68 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_VALUE);
69 CHECK_INT(n, 3); 69 CHECK_INT(n, 3);
70 CHECK_MEM(dest, "ABC", 3); 70 CHECK_MEM(dest, "ABC", 3);
71} 71}
@@ -79,7 +79,7 @@ static void case_binary_info_hash(void) {
79 ssize_t n; 79 ssize_t n;
80 80
81 test_case("twenty byte binary value survives decoding"); 81 test_case("twenty byte binary value survives decoding");
82 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_VALUE); 82 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_VALUE);
83 CHECK_INT(n, 20); 83 CHECK_INT(n, 20);
84 CHECK_MEM(dest, want, 20); 84 CHECK_MEM(dest, want, 20);
85} 85}
@@ -90,7 +90,7 @@ static void case_in_place(void) {
90 ssize_t n; 90 ssize_t n;
91 91
92 test_case("decoding in place over the source is safe"); 92 test_case("decoding in place over the source is safe");
93 n = scan_urlencoded_query(&p, query, SCAN_SEARCHPATH_VALUE); 93 n = urlencoded_parse(&p, query, SCAN_SEARCHPATH_VALUE);
94 CHECK_INT(n, 2); 94 CHECK_INT(n, 2);
95 CHECK_MEM(query, "AB", 2); 95 CHECK_MEM(query, "AB", 2);
96} 96}
@@ -102,7 +102,7 @@ static void case_bad_escape(void) {
102 ssize_t n; 102 ssize_t n;
103 103
104 test_case("a non hexadecimal escape is a parse error"); 104 test_case("a non hexadecimal escape is a parse error");
105 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_VALUE); 105 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_VALUE);
106 CHECK_INT(n, -1); 106 CHECK_INT(n, -1);
107} 107}
108 108
@@ -113,7 +113,7 @@ static void case_truncated_escape(void) {
113 ssize_t n; 113 ssize_t n;
114 114
115 test_case("an escape cut short by the terminator is a parse error"); 115 test_case("an escape cut short by the terminator is a parse error");
116 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_VALUE); 116 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_VALUE);
117 CHECK_INT(n, -1); 117 CHECK_INT(n, -1);
118} 118}
119 119
@@ -125,11 +125,11 @@ static void case_terminator(void) {
125 ssize_t n; 125 ssize_t n;
126 126
127 test_case("a hard terminator before any output reports end of input"); 127 test_case("a hard terminator before any output reports end of input");
128 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_PARAM); 128 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_PARAM);
129 CHECK_INT(n, -2); 129 CHECK_INT(n, -2);
130 130
131 p = space; 131 p = space;
132 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_PARAM); 132 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_PARAM);
133 CHECK_INT(n, -2); 133 CHECK_INT(n, -2);
134} 134}
135 135
@@ -140,10 +140,10 @@ static void case_terminator_after_output(void) {
140 ssize_t n; 140 ssize_t n;
141 141
142 test_case("a hard terminator after output is left for the next call"); 142 test_case("a hard terminator after output is left for the next call");
143 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_VALUE); 143 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_VALUE);
144 CHECK_INT(n, 3); 144 CHECK_INT(n, 3);
145 CHECK_INT(*p, 0); 145 CHECK_INT(*p, 0);
146 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_VALUE); 146 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_VALUE);
147 CHECK_INT(n, -2); 147 CHECK_INT(n, -2);
148} 148}
149 149
@@ -159,14 +159,14 @@ static void case_separators_are_contextual(void) {
159 ssize_t n; 159 ssize_t n;
160 160
161 test_case("a question mark is literal inside a value"); 161 test_case("a question mark is literal inside a value");
162 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_VALUE); 162 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_VALUE);
163 CHECK_INT(n, 3); 163 CHECK_INT(n, 3);
164 dest[n] = 0; 164 dest[n] = 0;
165 CHECK_STR(dest, "a?b"); 165 CHECK_STR(dest, "a?b");
166 166
167 test_case("an equals sign is literal inside a value"); 167 test_case("an equals sign is literal inside a value");
168 p = equals; 168 p = equals;
169 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_VALUE); 169 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_VALUE);
170 CHECK_INT(n, 3); 170 CHECK_INT(n, 3);
171 dest[n] = 0; 171 dest[n] = 0;
172 CHECK_STR(dest, "a=b"); 172 CHECK_STR(dest, "a=b");
@@ -179,7 +179,7 @@ static void case_ampersand_in_path(void) {
179 ssize_t n; 179 ssize_t n;
180 180
181 test_case("an ampersand in a path is a parse error"); 181 test_case("an ampersand in a path is a parse error");
182 n = scan_urlencoded_query(&p, dest, SCAN_PATH); 182 n = urlencoded_parse(&p, dest, SCAN_PATH);
183 CHECK_INT(n, -1); 183 CHECK_INT(n, -1);
184} 184}
185 185
@@ -190,7 +190,7 @@ static void case_raw_high_byte(void) {
190 ssize_t n; 190 ssize_t n;
191 191
192 test_case("an undecoded byte above ASCII is a parse error"); 192 test_case("an undecoded byte above ASCII is a parse error");
193 n = scan_urlencoded_query(&p, dest, SCAN_SEARCHPATH_VALUE); 193 n = urlencoded_parse(&p, dest, SCAN_SEARCHPATH_VALUE);
194 CHECK_INT(n, -1); 194 CHECK_INT(n, -1);
195} 195}
196 196
@@ -200,12 +200,12 @@ static void case_skipvalue(void) {
200 char *p = query; 200 char *p = query;
201 201
202 test_case("skipvalue steps over the value and its separator"); 202 test_case("skipvalue steps over the value and its separator");
203 scan_urlencoded_skipvalue(&p); 203 urlencoded_skip_value(&p);
204 CHECK_STR(p, "next=1"); 204 CHECK_STR(p, "next=1");
205 205
206 test_case("skipvalue leaves a hard terminator in place"); 206 test_case("skipvalue leaves a hard terminator in place");
207 p = bare; 207 p = bare;
208 scan_urlencoded_skipvalue(&p); 208 urlencoded_skip_value(&p);
209 CHECK_INT(*p, 0); 209 CHECK_INT(*p, 0);
210} 210}
211 211
@@ -217,15 +217,15 @@ static void case_find_keywords(void) {
217 char *p = match; 217 char *p = match;
218 218
219 test_case("a known keyword returns its value"); 219 test_case("a known keyword returns its value");
220 CHECK_INT(scan_find_keywords(keywords, &p, SCAN_SEARCHPATH_PARAM), 2); 220 CHECK_INT(urlencoded_match_keyword(keywords, &p, SCAN_SEARCHPATH_PARAM), 2);
221 221
222 test_case("an unknown keyword returns -3"); 222 test_case("an unknown keyword returns -3");
223 p = nomatch; 223 p = nomatch;
224 CHECK_INT(scan_find_keywords(keywords, &p, SCAN_SEARCHPATH_PARAM), -3); 224 CHECK_INT(urlencoded_match_keyword(keywords, &p, SCAN_SEARCHPATH_PARAM), -3);
225 225
226 test_case("a prefix of a keyword does not match it"); 226 test_case("a prefix of a keyword does not match it");
227 p = prefix; 227 p = prefix;
228 CHECK_INT(scan_find_keywords(keywords, &p, SCAN_SEARCHPATH_PARAM), -3); 228 CHECK_INT(urlencoded_match_keyword(keywords, &p, SCAN_SEARCHPATH_PARAM), -3);
229} 229}
230 230
231static void case_fixed_int(void) { 231static void case_fixed_int(void) {
@@ -265,7 +265,7 @@ static void case_fmt_passes_safe_bytes(void) {
265 size_t n; 265 size_t n;
266 266
267 test_case("alphanumerics and the safe punctuation pass through"); 267 test_case("alphanumerics and the safe punctuation pass through");
268 n = fmt_urlencoded(dest, src, 11); 268 n = urlencoded_format(dest, src, 11);
269 dest[n] = 0; 269 dest[n] = 0;
270 CHECK_INT(n, 11); 270 CHECK_INT(n, 11);
271 CHECK_STR(dest, "aZ09$-./=_~"); 271 CHECK_STR(dest, "aZ09$-./=_~");
@@ -277,7 +277,7 @@ static void case_fmt_escapes_the_rest(void) {
277 size_t n; 277 size_t n;
278 278
279 test_case("everything else becomes a percent escape"); 279 test_case("everything else becomes a percent escape");
280 n = fmt_urlencoded(dest, src, sizeof(src)); 280 n = urlencoded_format(dest, src, sizeof(src));
281 dest[n] = 0; 281 dest[n] = 0;
282 CHECK_INT(n, 18); 282 CHECK_INT(n, 18);
283 CHECK_STR(dest, "%20%25%26%2b%3a%3f"); 283 CHECK_STR(dest, "%20%25%26%2b%3a%3f");
@@ -289,7 +289,7 @@ static void case_fmt_hex_is_lower_case(void) {
289 size_t n; 289 size_t n;
290 290
291 test_case("escapes use lower case hex digits"); 291 test_case("escapes use lower case hex digits");
292 n = fmt_urlencoded(dest, src, sizeof(src)); 292 n = urlencoded_format(dest, src, sizeof(src));
293 dest[n] = 0; 293 dest[n] = 0;
294 CHECK_INT(n, 9); 294 CHECK_INT(n, 9);
295 CHECK_STR(dest, "%00%ab%ff"); 295 CHECK_STR(dest, "%00%ab%ff");
@@ -300,7 +300,7 @@ static void case_fmt_zero_length(void) {
300 300
301 test_case("a zero length input writes nothing"); 301 test_case("a zero length input writes nothing");
302 memset(dest, 0x5a, sizeof(dest)); 302 memset(dest, 0x5a, sizeof(dest));
303 CHECK_INT(fmt_urlencoded(dest, (const uint8_t *)"abc", 0), 0); 303 CHECK_INT(urlencoded_format(dest, (const uint8_t *)"abc", 0), 0);
304 CHECK_MEM(dest, "\x5a\x5a\x5a\x5a", 4); 304 CHECK_MEM(dest, "\x5a\x5a\x5a\x5a", 4);
305} 305}
306 306
@@ -312,7 +312,7 @@ static void case_fmt_worst_case_fits(void) {
312 test_case("a hash of entirely unsafe bytes needs three times its length"); 312 test_case("a hash of entirely unsafe bytes needs three times its length");
313 for (i = 0; i < sizeof(src); ++i) 313 for (i = 0; i < sizeof(src); ++i)
314 src[i] = 0xff; 314 src[i] = 0xff;
315 n = fmt_urlencoded(dest, src, sizeof(src)); 315 n = urlencoded_format(dest, src, sizeof(src));
316 dest[n] = 0; 316 dest[n] = 0;
317 CHECK_INT(n, 60); 317 CHECK_INT(n, 60);
318 for (i = 0; i < 20; ++i) 318 for (i = 0; i < 20; ++i)
@@ -328,7 +328,7 @@ static void case_fmt_decoder_disagrees_on_dollar(void) {
328 encoder passes through unescaped, '$' is the only one the decoder then 328 encoder passes through unescaped, '$' is the only one the decoder then
329 refuses, and it refuses the whole string rather than stopping short. 329 refuses, and it refuses the whole string rather than stopping short.
330 Output of the urlencoded full scrape therefore does not round trip 330 Output of the urlencoded full scrape therefore does not round trip
331 through scan_urlencoded_query when a hash contains 0x24. Harmless today 331 through urlencoded_parse when a hash contains 0x24. Harmless today
332 because only third party tooling reads that output. */ 332 because only third party tooling reads that output. */
333 const uint8_t src[] = {'a', '$', 'b'}; 333 const uint8_t src[] = {'a', '$', 'b'};
334 char dest[16]; 334 char dest[16];
@@ -338,15 +338,15 @@ static void case_fmt_decoder_disagrees_on_dollar(void) {
338 ssize_t got; 338 ssize_t got;
339 339
340 test_case("the encoder passes '$' but the decoder rejects it"); 340 test_case("the encoder passes '$' but the decoder rejects it");
341 n = fmt_urlencoded(dest, src, sizeof(src)); 341 n = urlencoded_format(dest, src, sizeof(src));
342 dest[n] = 0; 342 dest[n] = 0;
343 CHECK_STR(dest, "a$b"); 343 CHECK_STR(dest, "a$b");
344 344
345 got = scan_urlencoded_query(&p, scanned, SCAN_SEARCHPATH_VALUE); 345 got = urlencoded_parse(&p, scanned, SCAN_SEARCHPATH_VALUE);
346 CHECK_INT(got, -1); 346 CHECK_INT(got, -1);
347} 347}
348 348
349void test_scan_urlencoded_query(void) { 349void test_urlencoded(void) {
350 case_path(); 350 case_path();
351 case_param_and_value(); 351 case_param_and_value();
352 case_percent_decoding(); 352 case_percent_decoding();
diff --git a/tests/t_vector.c b/tests/t_vector.c
index a8186b2..541a6da 100644
--- a/tests/t_vector.c
+++ b/tests/t_vector.c
@@ -13,7 +13,7 @@
13#include "trackerlogic.h" 13#include "trackerlogic.h"
14#include "test.h" 14#include "test.h"
15 15
16/* binary_search returns the matching member when there is one, and otherwise 16/* vector_binary_search returns the matching member when there is one, and otherwise
17 the position at which the key would have to be inserted to keep the vector 17 the position at which the key would have to be inserted to keep the vector
18 sorted. exactmatch distinguishes the two. */ 18 sorted. exactmatch distinguishes the two. */
19 19
@@ -25,7 +25,7 @@ static void case_search_finds_member(void) {
25 void *found; 25 void *found;
26 26
27 test_case("an existing key is found"); 27 test_case("an existing key is found");
28 found = binary_search(key, sorted, 5, 4, 4, &exactmatch); 28 found = vector_binary_search(key, sorted, 5, 4, 4, &exactmatch);
29 CHECK(exactmatch != 0); 29 CHECK(exactmatch != 0);
30 CHECK_PTR(found, sorted[2]); 30 CHECK_PTR(found, sorted[2]);
31} 31}
@@ -36,9 +36,9 @@ static void case_search_finds_first_and_last(void) {
36 int exactmatch; 36 int exactmatch;
37 37
38 test_case("the first and last members are found"); 38 test_case("the first and last members are found");
39 CHECK_PTR(binary_search(first, sorted, 5, 4, 4, &exactmatch), sorted[0]); 39 CHECK_PTR(vector_binary_search(first, sorted, 5, 4, 4, &exactmatch), sorted[0]);
40 CHECK(exactmatch != 0); 40 CHECK(exactmatch != 0);
41 CHECK_PTR(binary_search(last, sorted, 5, 4, 4, &exactmatch), sorted[4]); 41 CHECK_PTR(vector_binary_search(last, sorted, 5, 4, 4, &exactmatch), sorted[4]);
42 CHECK(exactmatch != 0); 42 CHECK(exactmatch != 0);
43} 43}
44 44
@@ -49,11 +49,11 @@ static void case_search_insert_position(void) {
49 void *slot; 49 void *slot;
50 50
51 test_case("a missing key yields its insert position"); 51 test_case("a missing key yields its insert position");
52 slot = binary_search(middle, sorted, 5, 4, 4, &exactmatch); 52 slot = vector_binary_search(middle, sorted, 5, 4, 4, &exactmatch);
53 CHECK_INT(exactmatch, 0); 53 CHECK_INT(exactmatch, 0);
54 CHECK_PTR(slot, sorted[2]); 54 CHECK_PTR(slot, sorted[2]);
55 55
56 slot = binary_search(before, sorted, 5, 4, 4, &exactmatch); 56 slot = vector_binary_search(before, sorted, 5, 4, 4, &exactmatch);
57 CHECK_INT(exactmatch, 0); 57 CHECK_INT(exactmatch, 0);
58 CHECK_PTR(slot, sorted[0]); 58 CHECK_PTR(slot, sorted[0]);
59} 59}
@@ -64,7 +64,7 @@ static void case_search_past_the_end(void) {
64 void *slot; 64 void *slot;
65 65
66 test_case("a key above every member yields the position past the end"); 66 test_case("a key above every member yields the position past the end");
67 slot = binary_search(beyond, sorted, 5, 4, 4, &exactmatch); 67 slot = vector_binary_search(beyond, sorted, 5, 4, 4, &exactmatch);
68 CHECK_INT(exactmatch, 0); 68 CHECK_INT(exactmatch, 0);
69 CHECK_PTR(slot, sorted[5]); 69 CHECK_PTR(slot, sorted[5]);
70} 70}
@@ -74,7 +74,7 @@ static void case_search_empty(void) {
74 void *base = (void *)sorted; 74 void *base = (void *)sorted;
75 75
76 test_case("searching an empty vector reports no match at the base"); 76 test_case("searching an empty vector reports no match at the base");
77 CHECK_PTR(binary_search(sorted[0], base, 0, 4, 4, &exactmatch), base); 77 CHECK_PTR(vector_binary_search(sorted[0], base, 0, 4, 4, &exactmatch), base);
78 CHECK_INT(exactmatch, 0); 78 CHECK_INT(exactmatch, 0);
79} 79}
80 80
diff --git a/tests/test.h b/tests/test.h
index fd574c2..cebd08a 100644
--- a/tests/test.h
+++ b/tests/test.h
@@ -76,7 +76,7 @@ extern unsigned long test_failures;
76 } while (0) 76 } while (0)
77 77
78/* One entry point per module under test */ 78/* One entry point per module under test */
79void test_scan_urlencoded_query(void); 79void test_urlencoded(void);
80void test_iovec(void); 80void test_iovec(void);
81void test_vector(void); 81void test_vector(void);
82void test_random(void); 82void test_random(void);
@@ -88,5 +88,6 @@ void test_ip(void);
88void test_socket(void); 88void test_socket(void);
89void test_mutex(void); 89void test_mutex(void);
90void test_batch(void); 90void test_batch(void);
91void test_fdstate(void);
91 92
92#endif 93#endif