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

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

(libT) do proper JSON escaping

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