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