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

Last change on this file since 5829 was 5829, checked in by charles, 14 years ago

more work on rpc. bug fixes, regression tests, and spec tweaks.

  • Property svn:keywords set to Date Rev Author Id
File size: 10.3 KB
Line 
1#include <stdio.h>
2#include "transmission.h"
3#include "bencode.h"
4#include "json.h"
5#include "utils.h" /* tr_free */
6
7#define VERBOSE 0
8
9int test = 0;
10
11#define check(A) { \
12    ++test; \
13    if (A) { \
14        if( VERBOSE ) \
15            fprintf( stderr, "PASS test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
16    } else { \
17        if( VERBOSE ) \
18            fprintf( stderr, "FAIL test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
19        return test; \
20    } \
21}
22
23static int
24testInt( void )
25{
26    uint8_t buf[128];
27    int64_t val;
28    int err;
29    const uint8_t * end;
30
31    /* good int string */
32    snprintf( (char*)buf, sizeof( buf ), "i64e" );
33    err = tr_bencParseInt( buf, buf+4, &end, &val );
34    check( err == 0 );
35    check( val == 64 );
36    check( end == buf + 4 );
37
38    /* missing 'e' */
39    end = NULL;
40    val = 888;
41    err = tr_bencParseInt( buf, buf+3, &end, &val );
42    check( err == TR_ERROR ); 
43    check( val == 888 );
44    check( end == NULL );
45
46    /* empty buffer */
47    err = tr_bencParseInt( buf, buf+0, &end, &val );
48    check( err == TR_ERROR ); 
49    check( val == 888 );
50    check( end == NULL );
51
52    /* bad number */
53    snprintf( (char*)buf, sizeof( buf ), "i6z4e" );
54    err = tr_bencParseInt( buf, buf+5, &end, &val );
55    check( err == TR_ERROR );
56    check( val == 888 );
57    check( end == NULL );
58
59    /* negative number */
60    snprintf( (char*)buf, sizeof( buf ), "i-3e" );
61    err = tr_bencParseInt( buf, buf+4, &end, &val );
62    check( err == TR_OK );
63    check( val == -3 );
64    check( end == buf + 4 );
65
66    /* zero */
67    snprintf( (char*)buf, sizeof( buf ), "i0e" );
68    err = tr_bencParseInt( buf, buf+4, &end, &val );
69    check( err == TR_OK );
70    check( val == 0 );
71    check( end == buf + 3 );
72
73    /* no leading zeroes allowed */
74    val = 0;
75    end = NULL;
76    snprintf( (char*)buf, sizeof( buf ), "i04e" );
77    err = tr_bencParseInt( buf, buf+4, &end, &val );
78    check( err == TR_ERROR );
79    check( val == 0 );
80    check( end == NULL );
81
82    return 0;
83}
84
85static int
86testStr( void )
87{
88    uint8_t buf[128];
89    int err;
90    const uint8_t * end;
91    uint8_t * str;
92    size_t len;
93
94    /* good string */
95    snprintf( (char*)buf, sizeof( buf ), "4:boat" );
96    err = tr_bencParseStr( buf, buf+6, &end, &str, &len );
97    check( err == TR_OK );
98    check( !strcmp( (char*)str, "boat" ) );
99    check( len == 4 );
100    check( end == buf + 6 );
101    tr_free( str );
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    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    tr_free( str );
121    str = NULL;
122    end = NULL;
123    len = 0;
124
125    /* short string */
126    snprintf( (char*)buf, sizeof( buf ), "3:boat" );
127    err = tr_bencParseStr( buf, buf+6, &end, &str, &len );
128    check( err == TR_OK );
129    check( !strcmp( (char*)str, "boa" ) );
130    check( len == 3 );
131    check( end == buf + 5 );
132    tr_free( str );
133    str = NULL;
134    end = NULL;
135    len = 0;
136
137    return 0;
138}
139
140static int
141testString( const char * str, int isGood )
142{
143    tr_benc val;
144    const uint8_t * end = NULL;
145    char * saved;
146    const size_t len = strlen( str );
147    int savedLen;
148    int err = tr_bencParse( str, str+len, &val , &end );
149    if( !isGood ) {
150        check( err );
151    } else {
152        check( !err );
153        check( end == (const uint8_t*)str + len );
154        saved = tr_bencSave( &val, &savedLen );
155        check( !strcmp( saved, str ) );
156        check( len == (size_t)savedLen );
157        tr_free( saved );
158        tr_bencFree( &val );
159    }
160    return 0;
161}
162
163static int
164testParse( void )
165{
166    tr_benc val;
167    tr_benc * child;
168    tr_benc * child2;
169    uint8_t buf[512];
170    const uint8_t * end;
171    int err;
172    int len;
173    int64_t i;
174    char * saved;
175
176    snprintf( (char*)buf, sizeof( buf ), "i64e" );
177    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
178    check( !err );
179    check( tr_bencGetInt( &val, &i ) );
180    check( i == 64 );
181    check( end == buf + 4 );
182    tr_bencFree( &val );
183
184    snprintf( (char*)buf, sizeof( buf ), "li64ei32ei16ee" );
185    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
186    check( !err );
187    check( end == buf + strlen( (char*)buf ) );
188    check( val.val.l.count == 3 );
189    check( tr_bencGetInt( &val.val.l.vals[0], &i ) );
190    check( i == 64 );
191    check( tr_bencGetInt( &val.val.l.vals[1], &i ) );
192    check( i == 32 );
193    check( tr_bencGetInt( &val.val.l.vals[2], &i ) );
194    check( i == 16 );
195    saved = tr_bencSave( &val, &len );
196    check( !strcmp( saved, (char*)buf ) );
197    tr_free( saved );
198    tr_bencFree( &val );
199
200    end = NULL;
201    snprintf( (char*)buf, sizeof( buf ), "lllee" );
202    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val , &end );
203    check( err );
204    check( end == NULL );
205
206    end = NULL;
207    snprintf( (char*)buf, sizeof( buf ), "le" );
208    err = tr_bencParse( buf, buf + sizeof( buf ), &val , &end );
209    check( !err );
210    check( end == buf + 2 );
211    saved = tr_bencSave( &val, &len );
212    check( !strcmp( saved, "le" ) );
213    tr_free( saved );
214    tr_bencFree( &val );
215
216    if(( err = testString( "llleee", TRUE )))
217        return err;
218    if(( err = testString( "d3:cow3:moo4:spam4:eggse", TRUE )))
219        return err;
220    if(( err = testString( "d4:spaml1:a1:bee", TRUE )))
221        return err;
222    if(( err = testString( "d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee", TRUE )))
223        return err;
224    if(( err = testString( "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e", TRUE )))
225        return err;
226    if(( err = testString( "d1:ai0e1:be", FALSE ))) /* odd number of children */
227        return err;
228    if(( err = testString( "", FALSE )))
229        return err;
230    if(( err = testString( " ", FALSE )))
231        return err;
232
233    /* nested containers
234     * parse an unsorted dict
235     * save as a sorted dict */
236    end = NULL;
237    snprintf( (char*)buf, sizeof( buf ), "lld1:bi32e1:ai64eeee" );
238    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
239    check( !err );
240    check( end == buf + strlen( (const char*)buf ) );
241    check(( child = tr_bencListChild( &val, 0 )));
242    check(( child2 = tr_bencListChild( child, 0 )));
243    saved = tr_bencSave( &val, &len );
244    check( !strcmp( saved, "lld1:ai64e1:bi32eeee" ) );
245    tr_free( saved );
246    tr_bencFree( &val );
247
248    /* too many endings */
249    end = NULL;
250    snprintf( (char*)buf, sizeof( buf ), "leee" );
251    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
252    check( !err );
253    check( end == buf + 2 );
254    saved = tr_bencSave( &val, &len );
255    check( !strcmp( saved, "le" ) );
256    tr_free( saved );
257    tr_bencFree( &val );
258
259    /* no ending */
260    end = NULL;
261    snprintf( (char*)buf, sizeof( buf ), "l1:a1:b1:c" );
262    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
263    check( err );
264
265    /* incomplete string */
266    end = NULL;
267    snprintf( (char*)buf, sizeof( buf ), "1:" );
268    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
269    check( err );
270
271    return 0;
272}
273
274static int
275testRISONSnippet( const char * rison_str, const char * expected )
276{
277    char * serialized = tr_rison2json( rison_str, -1 );
278fprintf( stderr, " expected: [%s]\n", expected );
279fprintf( stderr, "      got: [%s]\n", serialized );
280    check( !strcmp( serialized, expected ) );
281    tr_free( serialized );
282    return 0;
283}
284
285static int
286testRISON( void )
287{
288    int val;
289    const char * rison;
290    const char * expected;
291
292    rison = "(a:0,b:foo,c:'23skidoo')";
293    expected = "{ \"a\": 0, \"b\": \"foo\", \"c\": \"23skidoo\" }";
294    if(( val = testRISONSnippet( rison, expected )))
295        return val;
296
297    rison = "(method:torrent-info)";
298    expected = "{ \"method\": \"torrent-info\" }";
299    if(( val = testRISONSnippet( rison, expected )))
300        return val;
301
302    return 0;
303}
304
305static int
306testJSONSnippet( const char * benc_str, const char * expected )
307{
308    tr_benc top;
309    char * serialized;
310    tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
311    serialized = tr_bencSaveAsJSON( &top, NULL );
312#if 0
313fprintf( stderr, " expected: [%s]\n", expected );
314fprintf( stderr, "      got: [%s]\n", serialized );
315#endif
316    check( !strcmp( serialized, expected ) );
317    tr_free( serialized );
318    tr_bencFree( &top );
319    return 0;
320}
321
322static int
323testJSON( void )
324{
325    int val;
326    const char * benc_str;
327    const char * expected;
328
329    benc_str = "i6e";
330    expected = "6";
331    if(( val = testJSONSnippet( benc_str, expected )))
332        return val;
333
334    benc_str = "d5:helloi1e5:worldi2ee";
335    expected = "{ \"hello\": 1, \"world\": 2 }"; 
336    if(( val = testJSONSnippet( benc_str, expected )))
337        return val;
338
339    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ee";
340    expected = "{ \"foo\": [ 1, 2, 3 ], \"hello\": 1, \"world\": 2 }";
341    if(( val = testJSONSnippet( benc_str, expected )))
342        return val;
343
344    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eee";
345    expected = "{ \"foo\": [ 1, 2, 3, { \"a\": 0 } ], \"hello\": 1, \"world\": 2 }";
346    if(( val = testJSONSnippet( benc_str, expected )))
347        return val;
348
349    benc_str = "d4:argsd6:statuslee6:result7:successe";
350    expected = "{ \"args\": { \"status\": [  ] }, \"result\": \"success\" }";
351    if(( val = testJSONSnippet( benc_str, expected )))
352        return val;
353
354    return 0;
355}
356
357static int
358testStackSmash( void )
359{
360    int i;
361    int len;
362    int depth;
363    int err;
364    uint8_t * in;
365    const uint8_t * end;
366    tr_benc val;
367    char * saved;
368
369    depth = 1000000;
370    in = tr_new( uint8_t, depth*2 + 1 );
371    for( i=0; i<depth; ++i ) {
372        in[i] = 'l';
373        in[depth+i] = 'e';
374    }
375    in[depth*2] = '\0';
376    err = tr_bencParse( in, in+(depth*2), &val, &end );
377    check( !err );
378    check( end == in+(depth*2) );
379    saved = tr_bencSave( &val, &len );
380    check( !strcmp( saved, (char*)in ) );
381    tr_free( in );
382    tr_free( saved );
383    tr_bencFree( &val );
384
385    return 0;
386}
387
388
389int
390main( void )
391{
392    int i;
393
394    if(( i = testInt( )))
395        return i;
396
397    if(( i = testStr( )))
398        return i;
399
400    if(( i = testParse( )))
401        return i;
402
403    if(( i = testJSON( )))
404        return i;
405
406    if(( i = testRISON( )))
407        return i;
408
409    if(( i = testStackSmash( )))
410        return i;
411
412    return 0;
413}
Note: See TracBrowser for help on using the repository browser.