source: trunk/libtransmission/variant-test.c

Last change on this file was 14721, checked in by jordan, 5 years ago

fix a handful of minor compiler warnings, mostly in the unit tests, eg field width shortening or implicit signed/unsigned conversions

  • Property svn:keywords set to Date Rev Author Id
File size: 15.1 KB
Line 
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 * $Id: variant-test.c 14721 2016-03-29 03:04:54Z mikedld $
8 */
9
10#include <ctype.h> /* isspace () */
11#include <errno.h> /* EILSEQ */
12#include <string.h> /* strlen (), strncmp () */
13
14#include <event2/buffer.h>
15
16#define __LIBTRANSMISSION_VARIANT_MODULE__
17#include "transmission.h"
18#include "utils.h" /* tr_free */
19#include "variant.h"
20#include "variant-common.h"
21
22#include "libtransmission-test.h"
23
24#ifndef _WIN32
25#define STACK_SMASH_DEPTH (1 * 1000 * 1000)
26#else
27#define STACK_SMASH_DEPTH ( 100 * 1000)
28#endif
29
30static int
31testInt (void)
32{
33  uint8_t buf[128];
34  int64_t val;
35  int err;
36  const uint8_t * end;
37
38  /* good int string */
39  tr_snprintf ((char*)buf, sizeof (buf), "i64e");
40  err = tr_bencParseInt (buf, buf + 4, &end, &val);
41  check_int_eq (0, err);
42  check_int_eq (64, val);
43  check ((buf + 4) ==  end);
44
45  /* missing 'e' */
46  end = NULL;
47  val = 888;
48  err = tr_bencParseInt (buf, buf + 3, &end, &val);
49  check_int_eq (EILSEQ, err);
50  check_int_eq (888, val);
51  check (end == NULL);
52
53  /* empty buffer */
54  err = tr_bencParseInt (buf, buf + 0, &end, &val);
55  check_int_eq (EILSEQ, err);
56  check_int_eq (888, val);
57  check (end == NULL);
58
59  /* bad number */
60  tr_snprintf ((char*)buf, sizeof (buf), "i6z4e");
61  err = tr_bencParseInt (buf, buf + 5, &end, &val);
62  check_int_eq (EILSEQ, err);
63  check_int_eq (888, val);
64  check (end == NULL);
65
66  /* negative number */
67  tr_snprintf ((char*)buf, sizeof (buf), "i-3e");
68  err = tr_bencParseInt (buf, buf + 4, &end, &val);
69  check_int_eq (0, err);
70  check_int_eq (-3, val);
71  check ((buf + 4) == end);
72
73  /* zero */
74  tr_snprintf ((char*)buf, sizeof (buf), "i0e");
75  err = tr_bencParseInt (buf, buf + 4, &end, &val);
76  check_int_eq (0, err);
77  check_int_eq (0, val);
78  check ((buf + 3) == end);
79
80  /* no leading zeroes allowed */
81  val = 0;
82  end = NULL;
83  tr_snprintf ((char*)buf, sizeof (buf), "i04e");
84  err = tr_bencParseInt (buf, buf + 4, &end, &val);
85  check_int_eq (EILSEQ, err);
86  check_int_eq (0, val);
87  check (NULL == end);
88
89  return 0;
90}
91
92static int
93testStr (void)
94{
95  uint8_t buf[128];
96  int err;
97  int n;
98  const uint8_t * end;
99  const uint8_t * str;
100  size_t len;
101
102  /* string len is designed to overflow */
103  n = tr_snprintf ((char*)buf, sizeof (buf), "%zu:boat", (size_t)(SIZE_MAX-2));
104  err = tr_bencParseStr (buf, buf+n, &end, &str, &len);
105  check_int_eq (EILSEQ, err);
106  check_uint_eq (0, len);
107  check (str == NULL);
108  check (end == NULL);
109  check (!len);
110
111  /* good string */
112  n = tr_snprintf ((char*)buf, sizeof (buf), "4:boat");
113  err = tr_bencParseStr (buf, buf+n, &end, &str, &len);
114  check_int_eq (0, err);
115  check_uint_eq (4, len);
116  check (strncmp ((const char*)str, "boat", len) == 0);
117  check (end == buf + 6);
118  str = NULL;
119  end = NULL;
120  len = 0;
121
122  /* string goes past end of buffer */
123  err = tr_bencParseStr (buf, buf+(n-1), &end, &str, &len);
124  check_int_eq (EILSEQ, err);
125  check_uint_eq (0, len);
126  check (str == NULL);
127  check (end == NULL);
128  check (!len);
129
130  /* empty string */
131  n = tr_snprintf ((char*)buf, sizeof (buf), "0:");
132  err = tr_bencParseStr (buf, buf+n, &end, &str, &len);
133  check_int_eq (0, err);
134  check_uint_eq (0, len);
135  check (!*str);
136  check (end == buf + 2);
137  str = NULL;
138  end = NULL;
139  len = 0;
140
141  /* short string */
142  n = tr_snprintf ((char*)buf, sizeof (buf), "3:boat");
143  err = tr_bencParseStr (buf, buf+n, &end, &str, &len);
144  check_int_eq (0, err);
145  check_uint_eq (3, len);
146  check (strncmp ((const char*)str, "boa", len) == 0);
147  check (end == buf + 5);
148  str = NULL;
149  end = NULL;
150  len = 0;
151
152  return 0;
153}
154
155static int
156testString (const char * str, bool isGood)
157{
158  tr_variant val;
159  const char * end = NULL;
160  char * saved;
161  const size_t    len = strlen (str);
162  size_t savedLen;
163  int err;
164
165  err = tr_variantFromBencFull (&val, str, len, NULL, &end);
166
167  if (!isGood)
168    {
169      check (err);
170    }
171  else
172    {
173      check (!err);
174#if 0
175      fprintf (stderr, "in: [%s]\n", str);
176      fprintf (stderr, "out:\n%s", tr_variantToStr (&val, TR_VARIANT_FMT_JSON, NULL));
177#endif
178      check (end == str + len);
179      saved = tr_variantToStr (&val, TR_VARIANT_FMT_BENC, &savedLen);
180      check_streq (str, saved);
181      check_uint_eq (savedLen, len);
182      tr_free (saved);
183      tr_variantFree (&val);
184    }
185
186  return 0;
187}
188
189static int
190testParse (void)
191{
192  tr_variant val;
193  tr_variant * child;
194  tr_variant * child2;
195  char buf[512];
196  const char * end;
197  int err;
198  size_t len;
199  int64_t i;
200  char * saved;
201
202  tr_snprintf ((char*)buf, sizeof (buf), "i64e");
203  err = tr_variantFromBencFull (&val, buf, sizeof(buf), NULL, &end);
204  check (!err);
205  check (tr_variantGetInt (&val, &i));
206  check_int_eq (64, i);
207  check (end == buf + 4);
208  tr_variantFree (&val);
209
210  tr_snprintf ((char*)buf, sizeof (buf), "li64ei32ei16ee");
211  err = tr_variantFromBencFull (&val, buf, sizeof(buf), NULL, &end);
212  check (!err);
213  check (end == buf + strlen ((char*)buf));
214  check (val.val.l.count == 3);
215  check (tr_variantGetInt (&val.val.l.vals[0], &i));
216  check_int_eq (64, i);
217  check (tr_variantGetInt (&val.val.l.vals[1], &i));
218  check_int_eq (32, i);
219  check (tr_variantGetInt (&val.val.l.vals[2], &i));
220  check_int_eq (16, i);
221  saved = tr_variantToStr (&val, TR_VARIANT_FMT_BENC, &len);
222  check_streq ((char*)buf, saved);
223  tr_free (saved);
224  tr_variantFree (&val);
225
226  end = NULL;
227  tr_snprintf ((char*)buf, sizeof (buf), "lllee");
228  err = tr_variantFromBencFull (&val, buf, sizeof(buf), NULL, &end);
229  check (err);
230  check (end == NULL);
231
232  end = NULL;
233  tr_snprintf ((char*)buf, sizeof (buf), "le");
234  err = tr_variantFromBencFull (&val, buf, sizeof(buf), NULL, &end);
235  check (!err);
236  check (end == buf + 2);
237  saved = tr_variantToStr (&val, TR_VARIANT_FMT_BENC, &len);
238  check_streq ("le", saved);
239  tr_free (saved);
240  tr_variantFree (&val);
241
242  if ((err = testString ("llleee", true)))
243    return err;
244  if ((err = testString ("d3:cow3:moo4:spam4:eggse", true)))
245    return err;
246  if ((err = testString ("d4:spaml1:a1:bee", true)))
247    return err;
248  if ((err = testString ("d5:greenli1ei2ei3ee4:spamd1:ai123e3:keyi214eee", true)))
249    return err;
250  if ((err = testString ("d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee", true)))
251    return err;
252  if ((err = testString ("d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e", true)))
253    return err;
254  if ((err = testString ("d1:ai0e1:be", false))) /* odd number of children */
255    return err;
256  if ((err = testString ("", false)))
257    return err;
258  if ((err = testString (" ", false)))
259    return err;
260
261  /* nested containers
262   * parse an unsorted dict
263   * save as a sorted dict */
264  end = NULL;
265  tr_snprintf ((char*)buf, sizeof (buf), "lld1:bi32e1:ai64eeee");
266  err = tr_variantFromBencFull (&val, buf, sizeof(buf), NULL, &end);
267  check (!err);
268  check (end == buf + strlen ((const char*)buf));
269  check ((child = tr_variantListChild (&val, 0)));
270  check ((child2 = tr_variantListChild (child, 0)));
271  saved = tr_variantToStr (&val, TR_VARIANT_FMT_BENC, &len);
272  check_streq ("lld1:ai64e1:bi32eeee", saved);
273  tr_free (saved);
274  tr_variantFree (&val);
275
276  /* too many endings */
277  end = NULL;
278  tr_snprintf ((char*)buf, sizeof (buf), "leee");
279  err = tr_variantFromBencFull (&val, buf, sizeof(buf), NULL, &end);
280  check (!err);
281  check (end == buf + 2);
282  saved = tr_variantToStr (&val, TR_VARIANT_FMT_BENC, &len);
283  check_streq ("le", saved);
284  tr_free (saved);
285  tr_variantFree (&val);
286
287  /* no ending */
288  end = NULL;
289  tr_snprintf ((char*)buf, sizeof (buf), "l1:a1:b1:c");
290  err = tr_variantFromBencFull (&val, buf, strlen(buf), NULL, &end);
291  check (err);
292
293  /* incomplete string */
294  end = NULL;
295  tr_snprintf ((char*)buf, sizeof (buf), "1:");
296  err = tr_variantFromBencFull (&val, buf, strlen(buf), NULL, &end);
297  check (err);
298
299  return 0;
300}
301
302static void
303stripWhitespace (char * in)
304{
305  char * out;
306
307  for (out=in; in && *in; ++in)
308    if (!isspace (*in))
309      *out++ = *in;
310
311  *out = '\0';
312}
313
314static int
315testJSONSnippet (const char * benc_str,
316                 const char * expected)
317{
318  tr_variant top;
319  char * serialized;
320  struct evbuffer * buf;
321
322  tr_variantFromBenc (&top, benc_str, strlen(benc_str));
323  buf = tr_variantToBuf (&top, TR_VARIANT_FMT_JSON);
324  serialized = (char*) evbuffer_pullup (buf, -1);
325  stripWhitespace (serialized);
326#if 0
327  fprintf (stderr, "benc: %s\n", benc_str);
328  fprintf (stderr, "json: %s\n", serialized);
329  fprintf (stderr, "want: %s\n", expected);
330#endif
331  check_streq (expected, serialized);
332  tr_variantFree (&top);
333  evbuffer_free (buf);
334  return 0;
335}
336
337static int
338testJSON (void)
339{
340  int val;
341  const char * benc_str;
342  const char * expected;
343
344  benc_str = "i6e";
345  expected = "6";
346  if ((val = testJSONSnippet (benc_str, expected)))
347    return val;
348
349  benc_str = "d5:helloi1e5:worldi2ee";
350  expected = "{\"hello\":1,\"world\":2}";
351  if ((val = testJSONSnippet (benc_str, expected)))
352    return val;
353
354  benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3eee";
355  expected = "{\"foo\":[1,2,3],\"hello\":1,\"world\":2}";
356  if ((val = testJSONSnippet (benc_str, expected)))
357    return val;
358
359  benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eeee";
360  expected = "{\"foo\":[1,2,3,{\"a\":0}],\"hello\":1,\"world\":2}";
361  if ((val = testJSONSnippet (benc_str, expected)))
362    return val;
363
364  benc_str = "d4:argsd6:statusle7:status2lee6:result7:successe";
365  expected = "{\"args\":{\"status\":[],\"status2\":[]},\"result\":\"success\"}";
366  if ((val = testJSONSnippet (benc_str, expected)))
367    return val;
368
369  return 0;
370}
371
372static int
373testMerge (void)
374{
375  size_t len;
376  tr_variant dest, src;
377  int64_t i;
378  const char * s;
379  const tr_quark i1 = tr_quark_new ("i1", 2);
380  const tr_quark i2 = tr_quark_new ("i2", 2);
381  const tr_quark i3 = tr_quark_new ("i3", 2);
382  const tr_quark i4 = tr_quark_new ("i4", 2);
383  const tr_quark s5 = tr_quark_new ("s5", 2);
384  const tr_quark s6 = tr_quark_new ("s6", 2);
385  const tr_quark s7 = tr_quark_new ("s7", 2);
386  const tr_quark s8 = tr_quark_new ("s8", 2);
387
388  /* initial dictionary (default values)  */
389  tr_variantInitDict (&dest, 10);
390  tr_variantDictAddInt (&dest, i1, 1);
391  tr_variantDictAddInt (&dest, i2, 2);
392  tr_variantDictAddInt (&dest, i4, -35); /* remains untouched */
393  tr_variantDictAddStr (&dest, s5, "abc");
394  tr_variantDictAddStr (&dest, s6, "def");
395  tr_variantDictAddStr (&dest, s7, "127.0.0.1"); /* remains untouched */
396
397  /* new dictionary, will overwrite items in dest  */
398  tr_variantInitDict (&src, 10);
399  tr_variantDictAddInt (&src, i1, 1);     /* same value */
400  tr_variantDictAddInt (&src, i2, 4);     /* new value */
401  tr_variantDictAddInt (&src, i3, 3);     /* new key:value */
402  tr_variantDictAddStr (&src, s5, "abc"); /* same value */
403  tr_variantDictAddStr (&src, s6, "xyz"); /* new value */
404  tr_variantDictAddStr (&src, s8, "ghi"); /* new key:value */
405
406  tr_variantMergeDicts (&dest, /*const*/ &src);
407
408  check (tr_variantDictFindInt (&dest, i1, &i));
409  check_int_eq (1, i);
410  check (tr_variantDictFindInt (&dest, i2, &i));
411  check_int_eq (4, i);
412  check (tr_variantDictFindInt (&dest, i3, &i));
413  check_int_eq (3, i);
414  check (tr_variantDictFindInt (&dest, i4, &i));
415  check_int_eq (-35, i);
416  check (tr_variantDictFindStr (&dest, s5, &s, &len));
417  check_uint_eq (3, len);
418  check_streq ("abc", s);
419  check (tr_variantDictFindStr (&dest, s6, &s, &len));
420  check_uint_eq (3, len);
421  check_streq ("xyz", s);
422  check (tr_variantDictFindStr (&dest, s7, &s,  &len));
423  check_uint_eq (9, len);
424  check_streq ("127.0.0.1", s);
425  check (tr_variantDictFindStr (&dest, s8, &s, &len));
426  check_uint_eq (3, len);
427  check_streq ("ghi", s);
428
429  tr_variantFree (&dest);
430  tr_variantFree (&src);
431  return 0;
432}
433
434static int
435testStackSmash (void)
436{
437  int i;
438  size_t len;
439  int err;
440  char * in;
441  const char * end;
442  tr_variant val;
443  char * saved;
444  const int depth = STACK_SMASH_DEPTH;
445
446  in = tr_new (char, depth * 2 + 1);
447  for (i = 0; i < depth; ++i)
448    {
449      in[i] = 'l';
450      in[depth + i] = 'e';
451    }
452  in[depth * 2] = '\0';
453  err = tr_variantFromBencFull (&val, in, depth*2, NULL, &end);
454  check_int_eq (0, err);
455  check (end == in + (depth * 2));
456  saved = tr_variantToStr (&val, TR_VARIANT_FMT_BENC, &len);
457  check_streq ((char*)in, saved);
458  tr_free (in);
459  tr_free (saved);
460  tr_variantFree (&val);
461
462  return 0;
463}
464
465static int
466testBool (void)
467{
468  tr_variant top;
469  int64_t intVal;
470  bool boolVal;
471  const tr_quark key1 = tr_quark_new ("key1", 4);
472  const tr_quark key2 = tr_quark_new ("key2", 4);
473  const tr_quark key3 = tr_quark_new ("key3", 4);
474  const tr_quark key4 = tr_quark_new ("key4", 4);
475
476  tr_variantInitDict (&top, 0);
477
478  tr_variantDictAddBool (&top, key1, false);
479  tr_variantDictAddBool (&top, key2, 0);
480  tr_variantDictAddInt  (&top, key3, true);
481  tr_variantDictAddInt  (&top, key4, 1);
482  check (tr_variantDictFindBool (&top, key1, &boolVal));
483  check (!boolVal);
484  check (tr_variantDictFindBool (&top, key2, &boolVal));
485  check (!boolVal);
486  check (tr_variantDictFindBool (&top, key3, &boolVal));
487  check (boolVal);
488  check (tr_variantDictFindBool (&top, key4, &boolVal));
489  check (boolVal);
490  check (tr_variantDictFindInt (&top, key1, &intVal));
491  check (!intVal);
492  check (tr_variantDictFindInt (&top, key2, &intVal));
493  check (!intVal);
494  check (tr_variantDictFindInt (&top, key3, &intVal));
495  check (intVal);
496  check (tr_variantDictFindInt (&top, key4, &intVal));
497  check (intVal);
498
499  tr_variantFree (&top);
500  return 0;
501}
502
503static int
504testParse2 (void)
505{
506  tr_variant top;
507  tr_variant top2;
508  int64_t intVal;
509  const char * strVal;
510  double realVal;
511  bool boolVal;
512  size_t len;
513  char * benc;
514  const char * end;
515  size_t strLen;
516  const tr_quark key_bool = tr_quark_new ("this-is-a-bool", TR_BAD_SIZE);
517  const tr_quark key_real = tr_quark_new ("this-is-a-real", TR_BAD_SIZE);
518  const tr_quark key_int  = tr_quark_new ("this-is-an-int", TR_BAD_SIZE);
519  const tr_quark key_str  = tr_quark_new ("this-is-a-string", TR_BAD_SIZE);
520
521  tr_variantInitDict (&top, 0);
522  tr_variantDictAddBool (&top, key_bool, true);
523  tr_variantDictAddInt  (&top, key_int,  1234);
524  tr_variantDictAddReal (&top, key_real, 0.5);
525  tr_variantDictAddStr  (&top, key_str, "this-is-a-string");
526
527  benc = tr_variantToStr (&top, TR_VARIANT_FMT_BENC, &len);
528  check_streq ("d14:this-is-a-booli1e14:this-is-a-real8:0.50000016:this-is-a-string16:this-is-a-string14:this-is-an-inti1234ee", benc);
529  check (!tr_variantFromBencFull (&top2, benc, len, NULL, &end));
530  check (end == benc + len);
531  check (tr_variantIsDict (&top2));
532  check (tr_variantDictFindInt (&top, key_int, &intVal));
533  check_int_eq (1234, intVal);
534  check (tr_variantDictFindBool (&top, key_bool, &boolVal));
535  check (boolVal == true);
536  check (tr_variantDictFindStr (&top, key_str, &strVal, &strLen));
537  check_uint_eq (16, strLen);
538  check_streq ("this-is-a-string", strVal);
539  check (tr_variantDictFindReal (&top, key_real, &realVal));
540  check_int_eq (50, (int)(realVal*100));
541
542  tr_variantFree (&top2);
543  tr_free (benc);
544  tr_variantFree (&top);
545
546  return 0;
547}
548
549int
550main (void)
551{
552  static const testFunc tests[] = { testInt,
553                                    testStr,
554                                    testParse,
555                                    testJSON,
556                                    testMerge,
557                                    testBool,
558                                    testParse2,
559                                    testStackSmash };
560  return runTests (tests, NUM_TESTS (tests));
561}
Note: See TracBrowser for help on using the repository browser.