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

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

run libT, cli, daemon, gtk through the source-code formatter "uncrustify" as promised/threatened

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