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

Last change on this file since 8685 was 8685, checked in by charles, 12 years ago

(trunk libT) remove the last calls to tr_getBuffer() and tr_releaseBuffer()

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