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

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

fix bug in the benc-to-json converter.
add rison-to-json converter so we can pass commands to transmission in a uri.
add unit tests for the new code.

  • Property svn:keywords set to Date Rev Author Id
File size: 10.2 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    return 0;
300}
301
302static int
303testJSONSnippet( const char * benc_str, const char * expected )
304{
305    tr_benc top;
306    char * serialized;
307    tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
308    serialized = tr_bencSaveAsJSON( &top, NULL );
309#if 0
310fprintf( stderr, " expected: [%s]\n", expected );
311fprintf( stderr, "      got: [%s]\n", serialized );
312#endif
313    check( !strcmp( serialized, expected ) );
314    tr_free( serialized );
315    tr_bencFree( &top );
316    return 0;
317}
318
319static int
320testJSON( void )
321{
322    int val;
323    const char * benc_str;
324    const char * expected;
325
326    benc_str = "i6e";
327    expected = "6";
328    if(( val = testJSONSnippet( benc_str, expected )))
329        return val;
330
331    benc_str = "d5:helloi1e5:worldi2ee";
332    expected = "{ \"hello\": 1, \"world\": 2 }"; 
333    if(( val = testJSONSnippet( benc_str, expected )))
334        return val;
335
336    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ee";
337    expected = "{ \"foo\": [ 1, 2, 3 ], \"hello\": 1, \"world\": 2 }";
338    if(( val = testJSONSnippet( benc_str, expected )))
339        return val;
340
341    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eee";
342    expected = "{ \"foo\": [ 1, 2, 3, { \"a\": 0 } ], \"hello\": 1, \"world\": 2 }";
343    if(( val = testJSONSnippet( benc_str, expected )))
344        return val;
345
346    benc_str = "d4:argsd6:statuslee6:result7:successe";
347    expected = "{ \"args\": { \"status\": [  ] }, \"result\": \"success\" }";
348    if(( val = testJSONSnippet( benc_str, expected )))
349        return val;
350
351    return 0;
352}
353
354static int
355testStackSmash( void )
356{
357    int i;
358    int len;
359    int depth;
360    int err;
361    uint8_t * in;
362    const uint8_t * end;
363    tr_benc val;
364    char * saved;
365
366    depth = 1000000;
367    in = tr_new( uint8_t, depth*2 + 1 );
368    for( i=0; i<depth; ++i ) {
369        in[i] = 'l';
370        in[depth+i] = 'e';
371    }
372    in[depth*2] = '\0';
373    err = tr_bencParse( in, in+(depth*2), &val, &end );
374    check( !err );
375    check( end == in+(depth*2) );
376    saved = tr_bencSave( &val, &len );
377    check( !strcmp( saved, (char*)in ) );
378    tr_free( in );
379    tr_free( saved );
380    tr_bencFree( &val );
381
382    return 0;
383}
384
385
386int
387main( void )
388{
389    int i;
390
391    if(( i = testInt( )))
392        return i;
393
394    if(( i = testStr( )))
395        return i;
396
397    if(( i = testParse( )))
398        return i;
399
400    if(( i = testJSON( )))
401        return i;
402
403    if(( i = testRISON( )))
404        return i;
405
406    if(( i = testStackSmash( )))
407        return i;
408
409    return 0;
410}
Note: See TracBrowser for help on using the repository browser.