source: branches/1.4x/libtransmission/bencode-test.c @ 7455

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

(1.4x libT) backport handshake, peer, bandwidth, peer-io to 1.4x.

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