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

Last change on this file since 6728 was 6728, checked in by muks, 13 years ago

(win32) Stack smash test fails with too much depth on win32

  • 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 <string.h>
4#include "transmission.h"
5#include "bencode.h"
6#include "json.h"
7#include "utils.h" /* tr_free */
8
9#define VERBOSE 0
10
11static int test = 0;
12
13#define check(A) { \
14    ++test; \
15    if (A) { \
16        if( VERBOSE ) \
17            fprintf( stderr, "PASS test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
18    } else { \
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    const 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( !strncmp( (char*)str, "boat", len ) );
100    check( len == 4 );
101    check( end == buf + 6 );
102    str = NULL;
103    end = NULL;
104    len = 0;
105
106    /* string goes past end of buffer */
107    err = tr_bencParseStr( buf, buf+5, &end, &str, &len );
108    check( err == TR_ERROR );
109    check( str == NULL );
110    check( end == NULL );
111    check( !len );
112
113    /* empty string */
114    tr_snprintf( (char*)buf, sizeof( buf ), "0:" );
115    err = tr_bencParseStr( buf, buf+2, &end, &str, &len );
116    check( err == TR_OK );
117    check( !*str );
118    check( !len );
119    check( end == buf + 2 );
120    str = NULL;
121    end = NULL;
122    len = 0;
123
124    /* short string */
125    tr_snprintf( (char*)buf, sizeof( buf ), "3:boat" );
126    err = tr_bencParseStr( buf, buf+6, &end, &str, &len );
127    check( err == TR_OK );
128    check( !strncmp( (char*)str, "boa", len ) );
129    check( len == 3 );
130    check( end == buf + 5 );
131    str = NULL;
132    end = NULL;
133    len = 0;
134
135    return 0;
136}
137
138static int
139testString( const char * str, int isGood )
140{
141    tr_benc val;
142    const uint8_t * end = NULL;
143    char * saved;
144    const size_t len = strlen( str );
145    int savedLen;
146    int err = tr_bencParse( str, str+len, &val , &end );
147    if( !isGood ) {
148        check( err );
149    } else {
150        check( !err );
151#if 0
152        fprintf( stderr, "in: [%s]\n", str );
153        fprintf( stderr, "out:\n%s", tr_bencSaveAsJSON(&val,NULL) );
154#endif
155        check( end == (const uint8_t*)str + len );
156        saved = tr_bencSave( &val, &savedLen );
157        check( !strcmp( saved, str ) );
158        check( len == (size_t)savedLen );
159        tr_free( saved );
160        tr_bencFree( &val );
161    }
162    return 0;
163}
164
165static int
166testParse( void )
167{
168    tr_benc val;
169    tr_benc * child;
170    tr_benc * child2;
171    uint8_t buf[512];
172    const uint8_t * end;
173    int err;
174    int len;
175    int64_t i;
176    char * saved;
177
178    tr_snprintf( (char*)buf, sizeof( buf ), "i64e" );
179    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
180    check( !err );
181    check( tr_bencGetInt( &val, &i ) );
182    check( i == 64 );
183    check( end == buf + 4 );
184    tr_bencFree( &val );
185
186    tr_snprintf( (char*)buf, sizeof( buf ), "li64ei32ei16ee" );
187    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
188    check( !err );
189    check( end == buf + strlen( (char*)buf ) );
190    check( val.val.l.count == 3 );
191    check( tr_bencGetInt( &val.val.l.vals[0], &i ) );
192    check( i == 64 );
193    check( tr_bencGetInt( &val.val.l.vals[1], &i ) );
194    check( i == 32 );
195    check( tr_bencGetInt( &val.val.l.vals[2], &i ) );
196    check( i == 16 );
197    saved = tr_bencSave( &val, &len );
198    check( !strcmp( saved, (char*)buf ) );
199    tr_free( saved );
200    tr_bencFree( &val );
201
202    end = NULL;
203    tr_snprintf( (char*)buf, sizeof( buf ), "lllee" );
204    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val , &end );
205    check( err );
206    check( end == NULL );
207
208    end = NULL;
209    tr_snprintf( (char*)buf, sizeof( buf ), "le" );
210    err = tr_bencParse( buf, buf + sizeof( buf ), &val , &end );
211    check( !err );
212    check( end == buf + 2 );
213    saved = tr_bencSave( &val, &len );
214    check( !strcmp( saved, "le" ) );
215    tr_free( saved );
216    tr_bencFree( &val );
217
218    if(( err = testString( "llleee", TRUE )))
219        return err;
220    if(( err = testString( "d3:cow3:moo4:spam4:eggse", TRUE )))
221        return err;
222    if(( err = testString( "d4:spaml1:a1:bee", TRUE )))
223        return err;
224    if(( err = testString( "d5:greenli1ei2ei3ee4:spamd1:ai123e3:keyi214eee", TRUE )))
225        return err;
226    if(( err = testString( "d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee", TRUE )))
227        return err;
228    if(( err = testString( "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e", TRUE )))
229        return err;
230    if(( err = testString( "d1:ai0e1:be", FALSE ))) /* odd number of children */
231        return err;
232    if(( err = testString( "", FALSE )))
233        return err;
234    if(( err = testString( " ", FALSE )))
235        return err;
236
237    /* nested containers
238     * parse an unsorted dict
239     * save as a sorted dict */
240    end = NULL;
241    tr_snprintf( (char*)buf, sizeof( buf ), "lld1:bi32e1:ai64eeee" );
242    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
243    check( !err );
244    check( end == buf + strlen( (const char*)buf ) );
245    check(( child = tr_bencListChild( &val, 0 )));
246    check(( child2 = tr_bencListChild( child, 0 )));
247    saved = tr_bencSave( &val, &len );
248    check( !strcmp( saved, "lld1:ai64e1:bi32eeee" ) );
249    tr_free( saved );
250    tr_bencFree( &val );
251
252    /* too many endings */
253    end = NULL;
254    tr_snprintf( (char*)buf, sizeof( buf ), "leee" );
255    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
256    check( !err );
257    check( end == buf + 2 );
258    saved = tr_bencSave( &val, &len );
259    check( !strcmp( saved, "le" ) );
260    tr_free( saved );
261    tr_bencFree( &val );
262
263    /* no ending */
264    end = NULL;
265    tr_snprintf( (char*)buf, sizeof( buf ), "l1:a1:b1:c" );
266    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
267    check( err );
268
269    /* incomplete string */
270    end = NULL;
271    tr_snprintf( (char*)buf, sizeof( buf ), "1:" );
272    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
273    check( err );
274
275    return 0;
276}
277
278static void
279stripWhitespace( char * in )
280{
281    char * out;
282    for( out=in; *in; ++in )
283        if( !isspace( *in ) )
284            *out++ = *in;
285    *out = '\0';
286}
287
288static int
289testJSONSnippet( const char * benc_str, const char * expected )
290{
291    tr_benc top;
292    char * serialized;
293    tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
294    serialized = tr_bencSaveAsJSON( &top, NULL );
295    stripWhitespace( serialized );
296#if 0
297fprintf( stderr, "benc: %s\n", benc_str );
298fprintf( stderr, "json: %s\n", serialized );
299fprintf( stderr, "want: %s\n", expected );
300#endif
301    check( !strcmp( serialized, expected ) );
302    tr_free( serialized );
303    tr_bencFree( &top );
304    return 0;
305}
306
307static int
308testJSON( void )
309{
310    int val;
311    const char * benc_str;
312    const char * expected;
313
314    benc_str = "i6e";
315    expected = "6";
316    if(( val = testJSONSnippet( benc_str, expected )))
317        return val;
318
319    benc_str = "d5:helloi1e5:worldi2ee";
320    expected = "{\"hello\":1,\"world\":2}"; 
321    if(( val = testJSONSnippet( benc_str, expected )))
322        return val;
323
324    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3eee";
325    expected = "{\"foo\":[1,2,3],\"hello\":1,\"world\":2}";
326    if(( val = testJSONSnippet( benc_str, expected )))
327        return val;
328
329    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eeee";
330    expected = "{\"foo\":[1,2,3,{\"a\":0}],\"hello\":1,\"world\":2}";
331    if(( val = testJSONSnippet( benc_str, expected )))
332        return val;
333
334    benc_str = "d4:argsd6:statusle7:status2lee6:result7:successe";
335    expected = "{\"args\":{\"status\":[],\"status2\":[]},\"result\":\"success\"}";
336    if(( val = testJSONSnippet( benc_str, expected )))
337        return val;
338
339    return 0;
340}
341
342static int
343testStackSmash( int depth )
344{
345    int i;
346    int len;
347    int err;
348    uint8_t * in;
349    const uint8_t * end;
350    tr_benc val;
351    char * saved;
352
353    in = tr_new( uint8_t, depth*2 + 1 );
354    for( i=0; i<depth; ++i ) {
355        in[i] = 'l';
356        in[depth+i] = 'e';
357    }
358    in[depth*2] = '\0';
359    err = tr_bencParse( in, in+(depth*2), &val, &end );
360    check( !err );
361    check( end == in+(depth*2) );
362    saved = tr_bencSave( &val, &len );
363    check( !strcmp( saved, (char*)in ) );
364    tr_free( in );
365    tr_free( saved );
366    tr_bencFree( &val );
367
368    return 0;
369}
370
371
372int
373main( void )
374{
375    int i;
376
377    if(( i = testInt( )))
378        return i;
379
380    if(( i = testStr( )))
381        return i;
382
383    if(( i = testParse( )))
384        return i;
385
386    if(( i = testJSON( )))
387        return i;
388
389#ifndef WIN32
390    i = testStackSmash( 1000000 );
391#else
392    i = testStackSmash( 100000 );
393#endif
394    if( i )
395        return i;
396
397    return 0;
398}
Note: See TracBrowser for help on using the repository browser.