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

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

RPC/IPC redesign

  • Property svn:keywords set to Date Rev Author Id
File size: 10.4 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 );
278#if 0
279fprintf( stderr, " expected: [%s]\n", expected );
280fprintf( stderr, "      got: [%s]\n", serialized );
281#endif
282    check( !strcmp( serialized, expected ) );
283    tr_free( serialized );
284    return 0;
285}
286
287static int
288testRISON( void )
289{
290    int val;
291    const char * rison;
292    const char * expected;
293
294    rison = "(a:0,b:foo,c:'23skidoo')";
295    expected = "{ \"a\": 0, \"b\": \"foo\", \"c\": \"23skidoo\" }";
296    if(( val = testRISONSnippet( rison, expected )))
297        return val;
298
299    rison = "(method:torrent-info)";
300    expected = "{ \"method\": \"torrent-info\" }";
301    if(( val = testRISONSnippet( rison, expected )))
302        return val;
303
304    return 0;
305}
306
307static int
308testJSONSnippet( const char * benc_str, const char * expected )
309{
310    tr_benc top;
311    char * serialized;
312    tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
313    serialized = tr_bencSaveAsJSON( &top, NULL );
314#if 0
315fprintf( stderr, " expected: [%s]\n", expected );
316fprintf( stderr, "      got: [%s]\n", serialized );
317#endif
318    check( !strcmp( serialized, expected ) );
319    tr_free( serialized );
320    tr_bencFree( &top );
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:fooli1ei2ei3ee";
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:ai0eee";
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:statuslee6:result7:successe";
352    expected = "{ \"args\": { \"status\": [  ] }, \"result\": \"success\" }";
353    if(( val = testJSONSnippet( benc_str, expected )))
354        return val;
355
356    return 0;
357}
358
359static int
360testStackSmash( void )
361{
362    int i;
363    int len;
364    int depth;
365    int err;
366    uint8_t * in;
367    const uint8_t * end;
368    tr_benc val;
369    char * saved;
370
371    depth = 1000000;
372    in = tr_new( uint8_t, depth*2 + 1 );
373    for( i=0; i<depth; ++i ) {
374        in[i] = 'l';
375        in[depth+i] = 'e';
376    }
377    in[depth*2] = '\0';
378    err = tr_bencParse( in, in+(depth*2), &val, &end );
379    check( !err );
380    check( end == in+(depth*2) );
381    saved = tr_bencSave( &val, &len );
382    check( !strcmp( saved, (char*)in ) );
383    tr_free( in );
384    tr_free( saved );
385    tr_bencFree( &val );
386
387    return 0;
388}
389
390
391int
392main( void )
393{
394    int i;
395
396    if(( i = testInt( )))
397        return i;
398
399    if(( i = testStr( )))
400        return i;
401
402    if(( i = testParse( )))
403        return i;
404
405    if(( i = testJSON( )))
406        return i;
407
408    if(( i = testRISON( )))
409        return i;
410
411    if(( i = testStackSmash( )))
412        return i;
413
414    return 0;
415}
Note: See TracBrowser for help on using the repository browser.