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

Last change on this file since 6484 was 6484, checked in by charles, 13 years ago

(libT) #1176: memory leaks in libtransmission

  • Property svn:keywords set to Date Rev Author Id
File size: 10.0 KB
Line 
1#include <ctype.h>
2#include <stdio.h>
3#include "transmission.h"
4#include "bencode.h"
5#include "json.h"
6#include "utils.h" /* tr_free */
7
8#define VERBOSE 0
9
10int test = 0;
11
12#define check(A) { \
13    ++test; \
14    if (A) { \
15        if( VERBOSE ) \
16            fprintf( stderr, "PASS test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
17    } else { \
18        if( VERBOSE ) \
19            fprintf( stderr, "FAIL test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
20        return test; \
21    } \
22}
23
24static int
25testInt( void )
26{
27    uint8_t buf[128];
28    int64_t val;
29    int err;
30    const uint8_t * end;
31
32    /* good int string */
33    tr_snprintf( (char*)buf, sizeof( buf ), "i64e" );
34    err = tr_bencParseInt( buf, buf+4, &end, &val );
35    check( err == 0 );
36    check( val == 64 );
37    check( end == buf + 4 );
38
39    /* missing 'e' */
40    end = NULL;
41    val = 888;
42    err = tr_bencParseInt( buf, buf+3, &end, &val );
43    check( err == TR_ERROR ); 
44    check( val == 888 );
45    check( end == NULL );
46
47    /* empty buffer */
48    err = tr_bencParseInt( buf, buf+0, &end, &val );
49    check( err == TR_ERROR ); 
50    check( val == 888 );
51    check( end == NULL );
52
53    /* bad number */
54    tr_snprintf( (char*)buf, sizeof( buf ), "i6z4e" );
55    err = tr_bencParseInt( buf, buf+5, &end, &val );
56    check( err == TR_ERROR );
57    check( val == 888 );
58    check( end == NULL );
59
60    /* negative number */
61    tr_snprintf( (char*)buf, sizeof( buf ), "i-3e" );
62    err = tr_bencParseInt( buf, buf+4, &end, &val );
63    check( err == TR_OK );
64    check( val == -3 );
65    check( end == buf + 4 );
66
67    /* zero */
68    tr_snprintf( (char*)buf, sizeof( buf ), "i0e" );
69    err = tr_bencParseInt( buf, buf+4, &end, &val );
70    check( err == TR_OK );
71    check( val == 0 );
72    check( end == buf + 3 );
73
74    /* no leading zeroes allowed */
75    val = 0;
76    end = NULL;
77    tr_snprintf( (char*)buf, sizeof( buf ), "i04e" );
78    err = tr_bencParseInt( buf, buf+4, &end, &val );
79    check( err == TR_ERROR );
80    check( val == 0 );
81    check( end == NULL );
82
83    return 0;
84}
85
86static int
87testStr( void )
88{
89    uint8_t buf[128];
90    int err;
91    const uint8_t * end;
92    uint8_t * str;
93    size_t len;
94
95    /* good string */
96    tr_snprintf( (char*)buf, sizeof( buf ), "4:boat" );
97    err = tr_bencParseStr( buf, buf+6, &end, &str, &len );
98    check( err == TR_OK );
99    check( !strcmp( (char*)str, "boat" ) );
100    check( len == 4 );
101    check( end == buf + 6 );
102    tr_free( str );
103    str = NULL;
104    end = NULL;
105    len = 0;
106
107    /* string goes past end of buffer */
108    err = tr_bencParseStr( buf, buf+5, &end, &str, &len );
109    check( err == TR_ERROR );
110    check( str == NULL );
111    check( end == NULL );
112    check( !len );
113
114    /* empty string */
115    tr_snprintf( (char*)buf, sizeof( buf ), "0:" );
116    err = tr_bencParseStr( buf, buf+2, &end, &str, &len );
117    check( err == TR_OK );
118    check( !*str );
119    check( !len );
120    check( end == buf + 2 );
121    tr_free( str );
122    str = NULL;
123    end = NULL;
124    len = 0;
125
126    /* short string */
127    tr_snprintf( (char*)buf, sizeof( buf ), "3:boat" );
128    err = tr_bencParseStr( buf, buf+6, &end, &str, &len );
129    check( err == TR_OK );
130    check( !strcmp( (char*)str, "boa" ) );
131    check( len == 3 );
132    check( end == buf + 5 );
133    tr_free( str );
134    str = NULL;
135    end = NULL;
136    len = 0;
137
138    return 0;
139}
140
141static int
142testString( const char * str, int isGood )
143{
144    tr_benc val;
145    const uint8_t * end = NULL;
146    char * saved;
147    const size_t len = strlen( str );
148    int savedLen;
149    int err = tr_bencParse( str, str+len, &val , &end );
150    if( !isGood ) {
151        check( err );
152    } else {
153        check( !err );
154#if 0
155        fprintf( stderr, "in: [%s]\n", str );
156        fprintf( stderr, "out:\n%s", tr_bencSaveAsJSON(&val,NULL) );
157#endif
158        check( end == (const uint8_t*)str + len );
159        saved = tr_bencSave( &val, &savedLen );
160        check( !strcmp( saved, str ) );
161        check( len == (size_t)savedLen );
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( i == 64 );
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( i == 64 );
196    check( tr_bencGetInt( &val.val.l.vals[1], &i ) );
197    check( i == 32 );
198    check( tr_bencGetInt( &val.val.l.vals[2], &i ) );
199    check( i == 16 );
200    saved = tr_bencSave( &val, &len );
201    check( !strcmp( saved, (char*)buf ) );
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_bencSave( &val, &len );
217    check( !strcmp( saved, "le" ) );
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 = testString( "d5:greenli1ei2ei3ee4:spamd1:ai123e3:keyi214eee", TRUE )))
228        return err;
229    if(( err = testString( "d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee", TRUE )))
230        return err;
231    if(( err = testString( "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e", TRUE )))
232        return err;
233    if(( err = testString( "d1:ai0e1:be", FALSE ))) /* odd number of children */
234        return err;
235    if(( err = testString( "", FALSE )))
236        return err;
237    if(( err = testString( " ", FALSE )))
238        return err;
239
240    /* nested containers
241     * parse an unsorted dict
242     * save as a sorted dict */
243    end = NULL;
244    tr_snprintf( (char*)buf, sizeof( buf ), "lld1:bi32e1:ai64eeee" );
245    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
246    check( !err );
247    check( end == buf + strlen( (const char*)buf ) );
248    check(( child = tr_bencListChild( &val, 0 )));
249    check(( child2 = tr_bencListChild( child, 0 )));
250    saved = tr_bencSave( &val, &len );
251    check( !strcmp( saved, "lld1:ai64e1:bi32eeee" ) );
252    tr_free( saved );
253    tr_bencFree( &val );
254
255    /* too many endings */
256    end = NULL;
257    tr_snprintf( (char*)buf, sizeof( buf ), "leee" );
258    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
259    check( !err );
260    check( end == buf + 2 );
261    saved = tr_bencSave( &val, &len );
262    check( !strcmp( saved, "le" ) );
263    tr_free( saved );
264    tr_bencFree( &val );
265
266    /* no ending */
267    end = NULL;
268    tr_snprintf( (char*)buf, sizeof( buf ), "l1:a1:b1:c" );
269    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
270    check( err );
271
272    /* incomplete string */
273    end = NULL;
274    tr_snprintf( (char*)buf, sizeof( buf ), "1:" );
275    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
276    check( err );
277
278    return 0;
279}
280
281static void
282stripWhitespace( char * in )
283{
284    char * out;
285    for( out=in; *in; ++in )
286        if( !isspace( *in ) )
287            *out++ = *in;
288    *out = '\0';
289}
290
291static int
292testJSONSnippet( const char * benc_str, const char * expected )
293{
294    tr_benc top;
295    char * serialized;
296    tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
297    serialized = tr_bencSaveAsJSON( &top, NULL );
298    stripWhitespace( serialized );
299#if 0
300fprintf( stderr, "benc: %s\n", benc_str );
301fprintf( stderr, "json: %s\n", serialized );
302fprintf( stderr, "want: %s\n", expected );
303#endif
304    check( !strcmp( serialized, expected ) );
305    tr_free( serialized );
306    tr_bencFree( &top );
307    return 0;
308}
309
310static int
311testJSON( void )
312{
313    int val;
314    const char * benc_str;
315    const char * expected;
316
317    benc_str = "i6e";
318    expected = "6";
319    if(( val = testJSONSnippet( benc_str, expected )))
320        return val;
321
322    benc_str = "d5:helloi1e5:worldi2ee";
323    expected = "{\"hello\":1,\"world\":2}"; 
324    if(( val = testJSONSnippet( benc_str, expected )))
325        return val;
326
327    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3eee";
328    expected = "{\"foo\":[1,2,3],\"hello\":1,\"world\":2}";
329    if(( val = testJSONSnippet( benc_str, expected )))
330        return val;
331
332    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eeee";
333    expected = "{\"foo\":[1,2,3,{\"a\":0}],\"hello\":1,\"world\":2}";
334    if(( val = testJSONSnippet( benc_str, expected )))
335        return val;
336
337    benc_str = "d4:argsd6:statusle7:status2lee6:result7:successe";
338    expected = "{\"args\":{\"status\":[],\"status2\":[]},\"result\":\"success\"}";
339    if(( val = testJSONSnippet( benc_str, expected )))
340        return val;
341
342    return 0;
343}
344
345static int
346testStackSmash( void )
347{
348    int i;
349    int len;
350    int depth;
351    int err;
352    uint8_t * in;
353    const uint8_t * end;
354    tr_benc val;
355    char * saved;
356
357    depth = 1000000;
358    in = tr_new( uint8_t, depth*2 + 1 );
359    for( i=0; i<depth; ++i ) {
360        in[i] = 'l';
361        in[depth+i] = 'e';
362    }
363    in[depth*2] = '\0';
364    err = tr_bencParse( in, in+(depth*2), &val, &end );
365    check( !err );
366    check( end == in+(depth*2) );
367    saved = tr_bencSave( &val, &len );
368    check( !strcmp( saved, (char*)in ) );
369    tr_free( in );
370    tr_free( saved );
371    tr_bencFree( &val );
372
373    return 0;
374}
375
376
377int
378main( void )
379{
380    int i;
381
382    if(( i = testInt( )))
383        return i;
384
385    if(( i = testStr( )))
386        return i;
387
388    if(( i = testParse( )))
389        return i;
390
391    if(( i = testJSON( )))
392        return i;
393
394    if(( i = testStackSmash( )))
395        return i;
396
397    return 0;
398}
Note: See TracBrowser for help on using the repository browser.