1 /*
2 * This file Copyright (C) 2013-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 */
8
9 #include <limits.h> /* INT_MAX */
10 #include <math.h> /* sqrt() */
11 #include <string.h> /* strlen() */
12 #include <stdlib.h> /* setenv(), unsetenv() */
13
14 #ifdef _WIN32
15 #include <windows.h>
16 #define setenv(key, value, unused) SetEnvironmentVariableA(key, value)
17 #define unsetenv(key) SetEnvironmentVariableA(key, NULL)
18 #endif
19
20 #include "transmission.h"
21 #include "ConvertUTF.h" /* tr_utf8_validate*/
22 #include "platform.h"
23 #include "crypto-utils.h" /* tr_rand_int_weak */
24 #include "utils.h"
25 #include "web.h"
26
27 #define SPEED_TEST 0
28
29 #if SPEED_TEST
30 #define VERBOSE
31 #endif
32
33 #include "libtransmission-test.h"
34
test_strip_positional_args(void)35 static int test_strip_positional_args(void)
36 {
37 char const* in;
38 char const* out;
39 char const* expected;
40
41 in = "Hello %1$s foo %2$.*f";
42 expected = "Hello %s foo %.*f";
43 out = tr_strip_positional_args(in);
44 check_str(out, ==, expected);
45
46 in = "Hello %1$'d foo %2$'f";
47 expected = "Hello %d foo %f";
48 out = tr_strip_positional_args(in);
49 check_str(out, ==, expected);
50
51 return 0;
52 }
53
test_strstrip(void)54 static int test_strstrip(void)
55 {
56 char* in;
57 char* out;
58
59 /* strstrip */
60 in = tr_strdup(" test ");
61 out = tr_strstrip(in);
62 check_ptr(in, ==, out);
63 check_str(out, ==, "test");
64 tr_free(in);
65
66 /* strstrip */
67 in = tr_strdup(" test test ");
68 out = tr_strstrip(in);
69 check_ptr(in, ==, out);
70 check_str(out, ==, "test test");
71 tr_free(in);
72
73 /* strstrip */
74 in = tr_strdup("test");
75 out = tr_strstrip(in);
76 check_ptr(in, ==, out);
77 check_str(out, ==, "test");
78 tr_free(in);
79
80 return 0;
81 }
82
test_strjoin(void)83 static int test_strjoin(void)
84 {
85 char* out;
86
87 char const* in1[] = { "one", "two" };
88 out = tr_strjoin(in1, 2, ", ");
89 check_str(out, ==, "one, two");
90 tr_free(out);
91
92 char const* in2[] = { "hello" };
93 out = tr_strjoin(in2, 1, "###");
94 check_str(out, ==, "hello");
95 tr_free(out);
96
97 char const* in3[] = { "a", "b", "ccc", "d", "eeeee" };
98 out = tr_strjoin(in3, 5, " ");
99 check_str(out, ==, "a b ccc d eeeee");
100 tr_free(out);
101
102 char const* in4[] = { "7", "ate", "9" };
103 out = tr_strjoin(in4, 3, "");
104 check_str(out, ==, "7ate9");
105 tr_free(out);
106
107 char const** in5;
108 out = tr_strjoin(in5, 0, "a");
109 check_str(out, ==, "");
110 tr_free(out);
111
112 return 0;
113 }
114
test_buildpath(void)115 static int test_buildpath(void)
116 {
117 char* out;
118
119 out = tr_buildPath("foo", "bar", NULL);
120 check_str(out, ==, "foo" TR_PATH_DELIMITER_STR "bar");
121 tr_free(out);
122
123 out = tr_buildPath("", "foo", "bar", NULL);
124 check_str(out, ==, TR_PATH_DELIMITER_STR "foo" TR_PATH_DELIMITER_STR "bar");
125 tr_free(out);
126
127 return 0;
128 }
129
test_utf8(void)130 static int test_utf8(void)
131 {
132 char const* in;
133 char* out;
134
135 in = "hello world";
136 out = tr_utf8clean(in, TR_BAD_SIZE);
137 check_str(out, ==, in);
138 tr_free(out);
139
140 in = "hello world";
141 out = tr_utf8clean(in, 5);
142 check_str(out, ==, "hello");
143 tr_free(out);
144
145 /* this version is not utf-8 (but cp866) */
146 in = "\x92\xE0\xE3\xA4\xAD\xAE \xA1\xEB\xE2\xEC \x81\xAE\xA3\xAE\xAC";
147 out = tr_utf8clean(in, 17);
148 check_ptr(out, !=, NULL);
149 check(strlen(out) == 17 || strlen(out) == 33);
150 check(tr_utf8_validate(out, TR_BAD_SIZE, NULL));
151 tr_free(out);
152
153 /* same string, but utf-8 clean */
154 in = "Трудно быть Богом";
155 out = tr_utf8clean(in, TR_BAD_SIZE);
156 check_ptr(out, !=, NULL);
157 check(tr_utf8_validate(out, TR_BAD_SIZE, NULL));
158 check_str(out, ==, in);
159 tr_free(out);
160
161 in = "\xF4\x00\x81\x82";
162 out = tr_utf8clean(in, 4);
163 check_ptr(out, !=, NULL);
164 check(strlen(out) == 1 || strlen(out) == 2);
165 check(tr_utf8_validate(out, TR_BAD_SIZE, NULL));
166 tr_free(out);
167
168 in = "\xF4\x33\x81\x82";
169 out = tr_utf8clean(in, 4);
170 check_ptr(out, !=, NULL);
171 check(strlen(out) == 4 || strlen(out) == 7);
172 check(tr_utf8_validate(out, TR_BAD_SIZE, NULL));
173 tr_free(out);
174
175 return 0;
176 }
177
test_numbers(void)178 static int test_numbers(void)
179 {
180 int count;
181 int* numbers;
182
183 numbers = tr_parseNumberRange("1-10,13,16-19", TR_BAD_SIZE, &count);
184 check_int(count, ==, 15);
185 check_int(numbers[0], ==, 1);
186 check_int(numbers[5], ==, 6);
187 check_int(numbers[9], ==, 10);
188 check_int(numbers[10], ==, 13);
189 check_int(numbers[11], ==, 16);
190 check_int(numbers[14], ==, 19);
191 tr_free(numbers);
192
193 numbers = tr_parseNumberRange("1-5,3-7,2-6", TR_BAD_SIZE, &count);
194 check_int(count, ==, 7);
195 check_ptr(numbers, !=, NULL);
196
197 for (int i = 0; i < count; ++i)
198 {
199 check_int(numbers[i], ==, i + 1);
200 }
201
202 tr_free(numbers);
203
204 numbers = tr_parseNumberRange("1-Hello", TR_BAD_SIZE, &count);
205 check_int(count, ==, 0);
206 check_ptr(numbers, ==, NULL);
207
208 numbers = tr_parseNumberRange("1-", TR_BAD_SIZE, &count);
209 check_int(count, ==, 0);
210 check_ptr(numbers, ==, NULL);
211
212 numbers = tr_parseNumberRange("Hello", TR_BAD_SIZE, &count);
213 check_int(count, ==, 0);
214 check_ptr(numbers, ==, NULL);
215
216 return 0;
217 }
218
compareInts(void const * va,void const * vb)219 static int compareInts(void const* va, void const* vb)
220 {
221 int const a = *(int const*)va;
222 int const b = *(int const*)vb;
223 return a - b;
224 }
225
test_lowerbound(void)226 static int test_lowerbound(void)
227 {
228 int const A[] = { 1, 2, 3, 3, 3, 5, 8 };
229 int const expected_pos[] = { 0, 1, 2, 5, 5, 6, 6, 6, 7, 7 };
230 bool const expected_exact[] = { true, true, true, false, true, false, false, true, false, false };
231 int const N = TR_N_ELEMENTS(A);
232
233 for (int i = 1; i <= 10; i++)
234 {
235 bool exact;
236 int const pos = tr_lowerBound(&i, A, N, sizeof(int), compareInts, &exact);
237
238 #if 0
239
240 fprintf(stderr, "searching for %d. ", i);
241 fprintf(stderr, "result: index = %d, ", pos);
242
243 if (pos != N)
244 {
245 fprintf(stderr, "A[%d] == %d\n", pos, A[pos]);
246 }
247 else
248 {
249 fprintf(stderr, "which is off the end.\n");
250 }
251
252 #endif
253
254 check_int(pos, ==, expected_pos[i - 1]);
255 check_int(exact, ==, expected_exact[i - 1]);
256 }
257
258 return 0;
259 }
260
test_quickFindFirst_Iteration(size_t const k,size_t const n,int * buf,int range)261 static int test_quickFindFirst_Iteration(size_t const k, size_t const n, int* buf, int range)
262 {
263 int highest_low;
264 int lowest_high;
265
266 /* populate buf with random ints */
267 for (size_t i = 0; i < n; ++i)
268 {
269 buf[i] = tr_rand_int_weak(range);
270 }
271
272 /* find the best k */
273 tr_quickfindFirstK(buf, n, sizeof(int), compareInts, k);
274
275 /* confirm that the smallest K ints are in the first slots K slots in buf */
276
277 highest_low = INT_MIN;
278
279 for (size_t i = 0; i < k; ++i)
280 {
281 if (highest_low < buf[i])
282 {
283 highest_low = buf[i];
284 }
285 }
286
287 lowest_high = INT_MAX;
288
289 for (size_t i = k; i < n; ++i)
290 {
291 if (lowest_high > buf[i])
292 {
293 lowest_high = buf[i];
294 }
295 }
296
297 check_int(highest_low, <=, lowest_high);
298
299 return 0;
300 }
301
test_quickfindFirst(void)302 static int test_quickfindFirst(void)
303 {
304 size_t const k = 10;
305 size_t const n = 100;
306 size_t const n_trials = 1000;
307 int* buf = tr_new(int, n);
308
309 for (size_t i = 0; i < n_trials; ++i)
310 {
311 check_int(test_quickFindFirst_Iteration(k, n, buf, 100), ==, 0);
312 }
313
314 tr_free(buf);
315 return 0;
316 }
317
test_memmem(void)318 static int test_memmem(void)
319 {
320 char const haystack[12] = "abcabcabcabc";
321 char const needle[3] = "cab";
322
323 check_ptr(tr_memmem(haystack, sizeof(haystack), haystack, sizeof(haystack)), ==, haystack);
324 check_ptr(tr_memmem(haystack, sizeof(haystack), needle, sizeof(needle)), ==, haystack + 2);
325 check_ptr(tr_memmem(needle, sizeof(needle), haystack, sizeof(haystack)), ==, NULL);
326
327 return 0;
328 }
329
test_hex(void)330 static int test_hex(void)
331 {
332 char hex1[41];
333 char hex2[41];
334 uint8_t binary[20];
335
336 memcpy(hex1, "fb5ef5507427b17e04b69cef31fa3379b456735a", 41);
337 tr_hex_to_binary(hex1, binary, 20);
338 tr_binary_to_hex(binary, hex2, 20);
339 check_str(hex1, ==, hex2);
340
341 return 0;
342 }
343
test_array(void)344 static int test_array(void)
345 {
346 size_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
347 size_t n = TR_N_ELEMENTS(array);
348
349 tr_removeElementFromArray(array, 5U, sizeof(size_t), n);
350 --n;
351
352 for (size_t i = 0; i < n; ++i)
353 {
354 check_int(array[i], ==, i < 5 ? i : i + 1);
355 }
356
357 tr_removeElementFromArray(array, 0U, sizeof(size_t), n);
358 --n;
359
360 for (size_t i = 0; i < n; ++i)
361 {
362 check_int(array[i], ==, i < 4 ? i + 1 : i + 2);
363 }
364
365 tr_removeElementFromArray(array, n - 1, sizeof(size_t), n);
366 --n;
367
368 for (size_t i = 0; i < n; ++i)
369 {
370 check_int(array[i], ==, i < 4 ? i + 1 : i + 2);
371 }
372
373 return 0;
374 }
375
test_url(void)376 static int test_url(void)
377 {
378 int port;
379 char* scheme;
380 char* host;
381 char* path;
382 char* str;
383 char const* url;
384
385 url = "http://1";
386 check(tr_urlParse(url, TR_BAD_SIZE, &scheme, &host, &port, &path));
387 check_str(scheme, ==, "http");
388 check_str(host, ==, "1");
389 check_str(path, ==, "/");
390 check_int(port, ==, 80);
391 tr_free(scheme);
392 tr_free(path);
393 tr_free(host);
394
395 url = "http://www.some-tracker.org/some/path";
396 check(tr_urlParse(url, TR_BAD_SIZE, &scheme, &host, &port, &path));
397 check_str(scheme, ==, "http");
398 check_str(host, ==, "www.some-tracker.org");
399 check_str(path, ==, "/some/path");
400 check_int(port, ==, 80);
401 tr_free(scheme);
402 tr_free(path);
403 tr_free(host);
404
405 url = "http://www.some-tracker.org:80/some/path";
406 check(tr_urlParse(url, TR_BAD_SIZE, &scheme, &host, &port, &path));
407 check_str(scheme, ==, "http");
408 check_str(host, ==, "www.some-tracker.org");
409 check_str(path, ==, "/some/path");
410 check_int(port, ==, 80);
411 tr_free(scheme);
412 tr_free(path);
413 tr_free(host);
414
415 url = "http%3A%2F%2Fwww.example.com%2F~user%2F%3Ftest%3D1%26test1%3D2";
416 str = tr_http_unescape(url, strlen(url));
417 check_str(str, ==, "http://www.example.com/~user/?test=1&test1=2");
418 tr_free(str);
419
420 return 0;
421 }
422
test_truncd(void)423 static int test_truncd(void)
424 {
425 char buf[32];
426 double const nan = sqrt(-1);
427
428 tr_snprintf(buf, sizeof(buf), "%.2f%%", 99.999);
429 check_str(buf, ==, "100.00%");
430
431 tr_snprintf(buf, sizeof(buf), "%.2f%%", tr_truncd(99.999, 2));
432 check_str(buf, ==, "99.99%");
433
434 tr_snprintf(buf, sizeof(buf), "%.4f", tr_truncd(403650.656250, 4));
435 check_str(buf, ==, "403650.6562");
436
437 tr_snprintf(buf, sizeof(buf), "%.2f", tr_truncd(2.15, 2));
438 check_str(buf, ==, "2.15");
439
440 tr_snprintf(buf, sizeof(buf), "%.2f", tr_truncd(2.05, 2));
441 check_str(buf, ==, "2.05");
442
443 tr_snprintf(buf, sizeof(buf), "%.2f", tr_truncd(3.3333, 2));
444 check_str(buf, ==, "3.33");
445
446 tr_snprintf(buf, sizeof(buf), "%.0f", tr_truncd(3.3333, 0));
447 check_str(buf, ==, "3");
448
449 tr_snprintf(buf, sizeof(buf), "%.0f", tr_truncd(3.9999, 0));
450 check_str(buf, ==, "3");
451
452 #if !(defined(_MSC_VER) || (defined(__MINGW32__) && defined(__MSVCRT__)))
453 /* FIXME: MSCVRT behaves differently in case of nan */
454 tr_snprintf(buf, sizeof(buf), "%.2f", tr_truncd(nan, 2));
455 check(strstr(buf, "nan") != NULL || strstr(buf, "NaN") != NULL);
456 #else
457 (void)nan;
458 #endif
459
460 return 0;
461 }
462
463 static char* test_strdup_printf_valist(char const* fmt, ...) TR_GNUC_PRINTF(1, 2);
464
test_strdup_printf_valist(char const * fmt,...)465 static char* test_strdup_printf_valist(char const* fmt, ...)
466 {
467 va_list args;
468 char* ret;
469
470 va_start(args, fmt);
471 ret = tr_strdup_vprintf(fmt, args);
472 va_end(args);
473
474 return ret;
475 }
476
test_strdup_printf(void)477 static int test_strdup_printf(void)
478 {
479 char* s;
480 char* s2;
481 char* s3;
482
483 s = tr_strdup_printf("%s", "test");
484 check_str(s, ==, "test");
485 tr_free(s);
486
487 s = tr_strdup_printf("%d %s %c %u", -1, "0", '1', 2);
488 check_str(s, ==, "-1 0 1 2");
489 tr_free(s);
490
491 s3 = tr_malloc0(4098);
492 memset(s3, '-', 4097);
493 s3[2047] = 't';
494 s3[2048] = 'e';
495 s3[2049] = 's';
496 s3[2050] = 't';
497
498 s2 = tr_malloc0(4096);
499 memset(s2, '-', 4095);
500 s2[2047] = '%';
501 s2[2048] = 's';
502
503 s = tr_strdup_printf(s2, "test");
504 check_str(s, ==, s3);
505 tr_free(s);
506
507 tr_free(s2);
508
509 s = tr_strdup_printf("%s", s3);
510 check_str(s, ==, s3);
511 tr_free(s);
512
513 tr_free(s3);
514
515 s = test_strdup_printf_valist("\n-%s-%s-%s-\n", "\r", "\t", "\b");
516 check_str(s, ==, "\n-\r-\t-\b-\n");
517 tr_free(s);
518
519 return 0;
520 }
521
test_env(void)522 static int test_env(void)
523 {
524 char const* test_key = "TR_TEST_ENV";
525 int x;
526 char* s;
527
528 unsetenv(test_key);
529
530 check(!tr_env_key_exists(test_key));
531 x = tr_env_get_int(test_key, 123);
532 check_int(x, ==, 123);
533 s = tr_env_get_string(test_key, NULL);
534 check_str(s, ==, NULL);
535 s = tr_env_get_string(test_key, "a");
536 check_str(s, ==, "a");
537 tr_free(s);
538
539 setenv(test_key, "", 1);
540
541 check(tr_env_key_exists(test_key));
542 x = tr_env_get_int(test_key, 456);
543 check_int(x, ==, 456);
544 s = tr_env_get_string(test_key, NULL);
545 check_str(s, ==, "");
546 tr_free(s);
547 s = tr_env_get_string(test_key, "b");
548 check_str(s, ==, "");
549 tr_free(s);
550
551 setenv(test_key, "135", 1);
552
553 check(tr_env_key_exists(test_key));
554 x = tr_env_get_int(test_key, 789);
555 check_int(x, ==, 135);
556 s = tr_env_get_string(test_key, NULL);
557 check_str(s, ==, "135");
558 tr_free(s);
559 s = tr_env_get_string(test_key, "c");
560 check_str(s, ==, "135");
561 tr_free(s);
562
563 return 0;
564 }
565
main(void)566 int main(void)
567 {
568 testFunc const tests[] =
569 {
570 test_array,
571 test_buildpath,
572 test_hex,
573 test_lowerbound,
574 test_quickfindFirst,
575 test_memmem,
576 test_numbers,
577 test_strip_positional_args,
578 test_strdup_printf,
579 test_strstrip,
580 test_strjoin,
581 test_truncd,
582 test_url,
583 test_utf8,
584 test_env
585 };
586
587 return runTests(tests, NUM_TESTS(tests));
588 }
589