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

Last change on this file since 7552 was 7552, checked in by charles, 12 years ago

(trunk libT) have tr_bencSaveAsJSON() use an evbuffer

  • Property svn:keywords set to Date Rev Author Id
File size: 12.5 KB
Line 
1#include <ctype.h>
2#include <errno.h>
3#include <stdio.h>
4#include <string.h>
5
6#include "event.h"
7
8#include "transmission.h"
9#include "bencode.h"
10#include "json.h"
11#include "utils.h" /* tr_free */
12
13#define VERBOSE 0
14
15static int test = 0;
16
17#define check( A ) \
18    { \
19        ++test; \
20        if( A ){ \
21            if( VERBOSE ) \
22                fprintf( stderr, "PASS test #%d (%s, %d)\n", test, __FILE__,\
23                         __LINE__ );\
24        } else { \
25            fprintf( stderr, "FAIL test #%d (%s, %d)\n", test, __FILE__,\
26                     __LINE__ ); \
27            return test; \
28        } \
29    }
30
31static int
32testInt( void )
33{
34    uint8_t         buf[128];
35    int64_t         val;
36    int             err;
37    const uint8_t * end;
38
39    /* good int string */
40    tr_snprintf( (char*)buf, sizeof( buf ), "i64e" );
41    err = tr_bencParseInt( buf, buf + 4, &end, &val );
42    check( err == 0 );
43    check( val == 64 );
44    check( end == buf + 4 );
45
46    /* missing 'e' */
47    end = NULL;
48    val = 888;
49    err = tr_bencParseInt( buf, buf + 3, &end, &val );
50    check( err == EILSEQ );
51    check( val == 888 );
52    check( end == NULL );
53
54    /* empty buffer */
55    err = tr_bencParseInt( buf, buf + 0, &end, &val );
56    check( err == EILSEQ );
57    check( val == 888 );
58    check( end == NULL );
59
60    /* bad number */
61    tr_snprintf( (char*)buf, sizeof( buf ), "i6z4e" );
62    err = tr_bencParseInt( buf, buf + 5, &end, &val );
63    check( err == EILSEQ );
64    check( val == 888 );
65    check( end == NULL );
66
67    /* negative number */
68    tr_snprintf( (char*)buf, sizeof( buf ), "i-3e" );
69    err = tr_bencParseInt( buf, buf + 4, &end, &val );
70    check( err == 0 );
71    check( val == -3 );
72    check( end == buf + 4 );
73
74    /* zero */
75    tr_snprintf( (char*)buf, sizeof( buf ), "i0e" );
76    err = tr_bencParseInt( buf, buf + 4, &end, &val );
77    check( err == 0 );
78    check( val == 0 );
79    check( end == buf + 3 );
80
81    /* no leading zeroes allowed */
82    val = 0;
83    end = NULL;
84    tr_snprintf( (char*)buf, sizeof( buf ), "i04e" );
85    err = tr_bencParseInt( buf, buf + 4, &end, &val );
86    check( err == EILSEQ );
87    check( val == 0 );
88    check( end == NULL );
89
90    return 0;
91}
92
93static int
94testStr( void )
95{
96    uint8_t         buf[128];
97    int             err;
98    const uint8_t * end;
99    const uint8_t * str;
100    size_t          len;
101
102    /* good string */
103    tr_snprintf( (char*)buf, sizeof( buf ), "4:boat" );
104    err = tr_bencParseStr( buf, buf + 6, &end, &str, &len );
105    check( err == 0 );
106    check( !strncmp( (char*)str, "boat", len ) );
107    check( len == 4 );
108    check( end == buf + 6 );
109    str = NULL;
110    end = NULL;
111    len = 0;
112
113    /* string goes past end of buffer */
114    err = tr_bencParseStr( buf, buf + 5, &end, &str, &len );
115    check( err == EILSEQ );
116    check( str == NULL );
117    check( end == NULL );
118    check( !len );
119
120    /* empty string */
121    tr_snprintf( (char*)buf, sizeof( buf ), "0:" );
122    err = tr_bencParseStr( buf, buf + 2, &end, &str, &len );
123    check( err == 0 );
124    check( !*str );
125    check( !len );
126    check( end == buf + 2 );
127    str = NULL;
128    end = NULL;
129    len = 0;
130
131    /* short string */
132    tr_snprintf( (char*)buf, sizeof( buf ), "3:boat" );
133    err = tr_bencParseStr( buf, buf + 6, &end, &str, &len );
134    check( err == 0 );
135    check( !strncmp( (char*)str, "boa", len ) );
136    check( len == 3 );
137    check( end == buf + 5 );
138    str = NULL;
139    end = NULL;
140    len = 0;
141
142    return 0;
143}
144
145static int
146testString( const char * str,
147            int          isGood )
148{
149    tr_benc         val;
150    const uint8_t * end = NULL;
151    char *          saved;
152    const size_t    len = strlen( str );
153    int             savedLen;
154    int             err = tr_bencParse( str, str + len, &val, &end );
155
156    if( !isGood )
157    {
158        check( err );
159    }
160    else
161    {
162        check( !err );
163#if 0
164        fprintf( stderr, "in: [%s]\n", str );
165        fprintf( stderr, "out:\n%s", tr_bencSaveAsJSON( &val, NULL ) );
166#endif
167        check( end == (const uint8_t*)str + len );
168        saved = tr_bencSave( &val, &savedLen );
169        check( !strcmp( saved, str ) );
170        check( len == (size_t)savedLen );
171        tr_free( saved );
172        tr_bencFree( &val );
173    }
174    return 0;
175}
176
177static int
178testParse( void )
179{
180    tr_benc         val;
181    tr_benc *       child;
182    tr_benc *       child2;
183    uint8_t         buf[512];
184    const uint8_t * end;
185    int             err;
186    int             len;
187    int64_t         i;
188    char *          saved;
189
190    tr_snprintf( (char*)buf, sizeof( buf ), "i64e" );
191    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
192    check( !err );
193    check( tr_bencGetInt( &val, &i ) );
194    check( i == 64 );
195    check( end == buf + 4 );
196    tr_bencFree( &val );
197
198    tr_snprintf( (char*)buf, sizeof( buf ), "li64ei32ei16ee" );
199    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
200    check( !err );
201    check( end == buf + strlen( (char*)buf ) );
202    check( val.val.l.count == 3 );
203    check( tr_bencGetInt( &val.val.l.vals[0], &i ) );
204    check( i == 64 );
205    check( tr_bencGetInt( &val.val.l.vals[1], &i ) );
206    check( i == 32 );
207    check( tr_bencGetInt( &val.val.l.vals[2], &i ) );
208    check( i == 16 );
209    saved = tr_bencSave( &val, &len );
210    check( !strcmp( saved, (char*)buf ) );
211    tr_free( saved );
212    tr_bencFree( &val );
213
214    end = NULL;
215    tr_snprintf( (char*)buf, sizeof( buf ), "lllee" );
216    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
217    check( err );
218    check( end == NULL );
219
220    end = NULL;
221    tr_snprintf( (char*)buf, sizeof( buf ), "le" );
222    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
223    check( !err );
224    check( end == buf + 2 );
225    saved = tr_bencSave( &val, &len );
226    check( !strcmp( saved, "le" ) );
227    tr_free( saved );
228    tr_bencFree( &val );
229
230    if( ( err = testString( "llleee", TRUE ) ) )
231        return err;
232    if( ( err = testString( "d3:cow3:moo4:spam4:eggse", TRUE ) ) )
233        return err;
234    if( ( err = testString( "d4:spaml1:a1:bee", TRUE ) ) )
235        return err;
236    if( ( err =
237             testString( "d5:greenli1ei2ei3ee4:spamd1:ai123e3:keyi214eee",
238                         TRUE ) ) )
239        return err;
240    if( ( err =
241             testString(
242                 "d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee",
243                 TRUE ) ) )
244        return err;
245    if( ( err =
246             testString(
247                 "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e",
248                 TRUE ) ) )
249        return err;
250    if( ( err = testString( "d1:ai0e1:be", FALSE ) ) ) /* odd number of children
251                                                         */
252        return err;
253    if( ( err = testString( "", FALSE ) ) )
254        return err;
255    if( ( err = testString( " ", FALSE ) ) )
256        return err;
257
258    /* nested containers
259     * parse an unsorted dict
260     * save as a sorted dict */
261    end = NULL;
262    tr_snprintf( (char*)buf, sizeof( buf ), "lld1:bi32e1:ai64eeee" );
263    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
264    check( !err );
265    check( end == buf + strlen( (const char*)buf ) );
266    check( ( child = tr_bencListChild( &val, 0 ) ) );
267    check( ( child2 = tr_bencListChild( child, 0 ) ) );
268    saved = tr_bencSave( &val, &len );
269    check( !strcmp( saved, "lld1:ai64e1:bi32eeee" ) );
270    tr_free( saved );
271    tr_bencFree( &val );
272
273    /* too many endings */
274    end = NULL;
275    tr_snprintf( (char*)buf, sizeof( buf ), "leee" );
276    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
277    check( !err );
278    check( end == buf + 2 );
279    saved = tr_bencSave( &val, &len );
280    check( !strcmp( saved, "le" ) );
281    tr_free( saved );
282    tr_bencFree( &val );
283
284    /* no ending */
285    end = NULL;
286    tr_snprintf( (char*)buf, sizeof( buf ), "l1:a1:b1:c" );
287    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
288    check( err );
289
290    /* incomplete string */
291    end = NULL;
292    tr_snprintf( (char*)buf, sizeof( buf ), "1:" );
293    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
294    check( err );
295
296    return 0;
297}
298
299static void
300stripWhitespace( char * in )
301{
302    char * out;
303
304    for( out = in; *in; ++in )
305        if( !isspace( *in ) )
306            *out++ = *in;
307    *out = '\0';
308}
309
310static int
311testJSONSnippet( const char * benc_str,
312                 const char * expected )
313{
314    tr_benc top;
315    struct evbuffer * buf = tr_getBuffer( );
316    char * serialized;
317
318    tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
319    serialized = tr_bencSaveAsJSON( &top, buf );
320    stripWhitespace( serialized );
321#if 0
322    fprintf( stderr, "benc: %s\n", benc_str );
323    fprintf( stderr, "json: %s\n", serialized );
324    fprintf( stderr, "want: %s\n", expected );
325#endif
326    check( !strcmp( serialized, expected ) );
327    tr_bencFree( &top );
328    tr_releaseBuffer( buf );
329    return 0;
330}
331
332static int
333testJSON( void )
334{
335    int          val;
336    const char * benc_str;
337    const char * expected;
338
339    benc_str = "i6e";
340    expected = "6";
341    if( ( val = testJSONSnippet( benc_str, expected ) ) )
342        return val;
343
344    benc_str = "d5:helloi1e5:worldi2ee";
345    expected = "{\"hello\":1,\"world\":2}";
346    if( ( val = testJSONSnippet( benc_str, expected ) ) )
347        return val;
348
349    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3eee";
350    expected = "{\"foo\":[1,2,3],\"hello\":1,\"world\":2}";
351    if( ( val = testJSONSnippet( benc_str, expected ) ) )
352        return val;
353
354    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eeee";
355    expected = "{\"foo\":[1,2,3,{\"a\":0}],\"hello\":1,\"world\":2}";
356    if( ( val = testJSONSnippet( benc_str, expected ) ) )
357        return val;
358
359    benc_str = "d4:argsd6:statusle7:status2lee6:result7:successe";
360    expected =
361        "{\"args\":{\"status\":[],\"status2\":[]},\"result\":\"success\"}";
362    if( ( val = testJSONSnippet( benc_str, expected ) ) )
363        return val;
364
365    return 0;
366}
367
368static int 
369testMerge( void )
370{ 
371    tr_benc dest, src; 
372    int64_t i; 
373    const char * s; 
374
375    /* initial dictionary (default values)  */
376    tr_bencInitDict( &dest, 10 ); 
377    tr_bencDictAddInt( &dest, "i1", 1 ); 
378    tr_bencDictAddInt( &dest, "i2", 2 ); 
379    tr_bencDictAddInt( &dest, "i4", -35 ); /* remains untouched */
380    tr_bencDictAddStr( &dest, "s5", "abc" ); 
381    tr_bencDictAddStr( &dest, "s6", "def" ); 
382    tr_bencDictAddStr( &dest, "s7", "127.0.0.1" ); /* remains untouched */
383
384    /* new dictionary, will overwrite items in dest  */
385    tr_bencInitDict( &src, 10 ); 
386    tr_bencDictAddInt( &src, "i1", 1 );     /* same value */
387    tr_bencDictAddInt( &src, "i2", 4 );     /* new value */
388    tr_bencDictAddInt( &src, "i3", 3 );     /* new key:value */
389    tr_bencDictAddStr( &src, "s5", "abc" ); /* same value */
390    tr_bencDictAddStr( &src, "s6", "xyz" ); /* new value */
391    tr_bencDictAddStr( &src, "s8", "ghi" ); /* new key:value */
392
393    tr_bencMergeDicts( &dest, /*const*/ &src ); 
394
395    check( tr_bencDictFindInt( &dest, "i1", &i )); 
396    check( i == 1); 
397    check( tr_bencDictFindInt( &dest, "i2", &i )); 
398    check( i == 4); 
399    check( tr_bencDictFindInt( &dest, "i3", &i )); 
400    check( i == 3); 
401    check( tr_bencDictFindInt( &dest, "i4", &i )); 
402    check( i == -35); 
403    check( tr_bencDictFindStr( &dest, "s5", &s )); 
404    check( strcmp( "abc", s ) == 0 ); 
405    check( tr_bencDictFindStr( &dest, "s6", &s )); 
406    check( strcmp( "xyz", s ) == 0 ); 
407    check( tr_bencDictFindStr( &dest, "s7", &s )); 
408    check( strcmp( "127.0.0.1", s ) == 0 ); 
409    check( tr_bencDictFindStr( &dest, "s8", &s )); 
410    check( strcmp( "ghi", s ) == 0 ); 
411
412    tr_bencFree( &dest ); 
413    tr_bencFree( &src ); 
414    return 0; 
415} 
416
417static int
418testStackSmash( int depth )
419{
420    int             i;
421    int             len;
422    int             err;
423    uint8_t *       in;
424    const uint8_t * end;
425    tr_benc         val;
426    char *          saved;
427
428    in = tr_new( uint8_t, depth * 2 + 1 );
429    for( i = 0; i < depth; ++i )
430    {
431        in[i] = 'l';
432        in[depth + i] = 'e';
433    }
434    in[depth * 2] = '\0';
435    err = tr_bencParse( in, in + ( depth * 2 ), &val, &end );
436    check( !err );
437    check( end == in + ( depth * 2 ) );
438    saved = tr_bencSave( &val, &len );
439    check( !strcmp( saved, (char*)in ) );
440    tr_free( in );
441    tr_free( saved );
442    tr_bencFree( &val );
443
444    return 0;
445}
446
447int
448main( void )
449{
450    int i;
451
452    if(( i = testInt( )))
453        return i;
454
455    if(( i = testStr( )))
456        return i;
457
458    if(( i = testParse( )))
459        return i;
460
461    if(( i = testJSON( )))
462        return i;
463
464    if(( i = testMerge( )))
465        return i;
466
467#ifndef WIN32
468    i = testStackSmash( 1000000 );
469#else
470    i = testStackSmash( 100000 );
471#endif
472    if( i )
473        return i;
474
475    return 0;
476}
477
Note: See TracBrowser for help on using the repository browser.