source: trunk/libtransmission/bencode-test.c @ 13569

Last change on this file since 13569 was 13569, checked in by jordan, 10 years ago

retrofit some of the tests to use the more expressive test API

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