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

Last change on this file since 13442 was 13442, checked in by jordan, 10 years ago

(trunk, libtransmission) #4934 "Create a test harness and use it for current tests" -- patch by gvdl

  • Property svn:keywords set to Date Rev Author Id
File size: 14.4 KB
Line 
1#include <ctype.h>
2#include <errno.h>
3#include <stdio.h>
4#include <string.h>
5
6#include <event2/buffer.h>
7
8#include "transmission.h"
9#include "bencode.h"
10#include "utils.h" /* tr_free */
11
12// #define VERBOSE
13#include "libtransmission-test.h"
14
15#ifndef WIN32
16#define STACK_SMASH_DEPTH (1 * 1000 * 1000)
17#else
18#define STACK_SMASH_DEPTH (     100 * 1000)
19#endif
20
21static int
22testInt( void )
23{
24    uint8_t         buf[128];
25    int64_t         val;
26    int             err;
27    const uint8_t * end;
28
29    /* good int string */
30    tr_snprintf( (char*)buf, sizeof( buf ), "i64e" );
31    err = tr_bencParseInt( buf, buf + 4, &end, &val );
32    check( err == 0 );
33    check( val == 64 );
34    check( end == buf + 4 );
35
36    /* missing 'e' */
37    end = NULL;
38    val = 888;
39    err = tr_bencParseInt( buf, buf + 3, &end, &val );
40    check( err == EILSEQ );
41    check( val == 888 );
42    check( end == NULL );
43
44    /* empty buffer */
45    err = tr_bencParseInt( buf, buf + 0, &end, &val );
46    check( err == EILSEQ );
47    check( val == 888 );
48    check( end == NULL );
49
50    /* bad number */
51    tr_snprintf( (char*)buf, sizeof( buf ), "i6z4e" );
52    err = tr_bencParseInt( buf, buf + 5, &end, &val );
53    check( err == EILSEQ );
54    check( val == 888 );
55    check( end == NULL );
56
57    /* negative number */
58    tr_snprintf( (char*)buf, sizeof( buf ), "i-3e" );
59    err = tr_bencParseInt( buf, buf + 4, &end, &val );
60    check( err == 0 );
61    check( val == -3 );
62    check( end == buf + 4 );
63
64    /* zero */
65    tr_snprintf( (char*)buf, sizeof( buf ), "i0e" );
66    err = tr_bencParseInt( buf, buf + 4, &end, &val );
67    check( err == 0 );
68    check( val == 0 );
69    check( end == buf + 3 );
70
71    /* no leading zeroes allowed */
72    val = 0;
73    end = NULL;
74    tr_snprintf( (char*)buf, sizeof( buf ), "i04e" );
75    err = tr_bencParseInt( buf, buf + 4, &end, &val );
76    check( err == EILSEQ );
77    check( val == 0 );
78    check( end == NULL );
79
80    return 0;
81}
82
83static int
84testStr( void )
85{
86    uint8_t         buf[128];
87    int             err;
88    const uint8_t * end;
89    const uint8_t * str;
90    size_t          len;
91
92    /* good string */
93    tr_snprintf( (char*)buf, sizeof( buf ), "4:boat" );
94    err = tr_bencParseStr( buf, buf + 6, &end, &str, &len );
95    check( err == 0 );
96    check( !strncmp( (char*)str, "boat", len ) );
97    check( len == 4 );
98    check( end == buf + 6 );
99    str = NULL;
100    end = NULL;
101    len = 0;
102
103    /* string goes past end of buffer */
104    err = tr_bencParseStr( buf, buf + 5, &end, &str, &len );
105    check( err == EILSEQ );
106    check( str == NULL );
107    check( end == NULL );
108    check( !len );
109
110    /* empty string */
111    tr_snprintf( (char*)buf, sizeof( buf ), "0:" );
112    err = tr_bencParseStr( buf, buf + 2, &end, &str, &len );
113    check( err == 0 );
114    check( !*str );
115    check( !len );
116    check( end == buf + 2 );
117    str = NULL;
118    end = NULL;
119    len = 0;
120
121    /* short string */
122    tr_snprintf( (char*)buf, sizeof( buf ), "3:boat" );
123    err = tr_bencParseStr( buf, buf + 6, &end, &str, &len );
124    check( err == 0 );
125    check( !strncmp( (char*)str, "boa", len ) );
126    check( len == 3 );
127    check( end == buf + 5 );
128    str = NULL;
129    end = NULL;
130    len = 0;
131
132    return 0;
133}
134
135static int
136testString( const char * str,
137            int          isGood )
138{
139    tr_benc         val;
140    const uint8_t * end = NULL;
141    char *          saved;
142    const size_t    len = strlen( str );
143    int             savedLen;
144    int             err = tr_bencParse( str, str + len, &val, &end );
145
146    if( !isGood )
147    {
148        check( err );
149    }
150    else
151    {
152        check( !err );
153#if 0
154        fprintf( stderr, "in: [%s]\n", str );
155        fprintf( stderr, "out:\n%s", tr_bencToStr( &val, TR_FMT_JSON, NULL ) );
156#endif
157        check( end == (const uint8_t*)str + len );
158        saved = tr_bencToStr( &val, TR_FMT_BENC, &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_bencToStr( &val, TR_FMT_BENC, &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_bencToStr( &val, TR_FMT_BENC, &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 =
227             testString( "d5:greenli1ei2ei3ee4:spamd1:ai123e3:keyi214eee",
228                         true ) ) )
229        return err;
230    if( ( err =
231             testString(
232                 "d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee",
233                 true ) ) )
234        return err;
235    if( ( err =
236             testString(
237                 "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e",
238                 true ) ) )
239        return err;
240    if( ( err = testString( "d1:ai0e1:be", false ) ) ) /* odd number of children
241                                                         */
242        return err;
243    if( ( err = testString( "", false ) ) )
244        return err;
245    if( ( err = testString( " ", false ) ) )
246        return err;
247
248    /* nested containers
249     * parse an unsorted dict
250     * save as a sorted dict */
251    end = NULL;
252    tr_snprintf( (char*)buf, sizeof( buf ), "lld1:bi32e1:ai64eeee" );
253    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
254    check( !err );
255    check( end == buf + strlen( (const char*)buf ) );
256    check( ( child = tr_bencListChild( &val, 0 ) ) );
257    check( ( child2 = tr_bencListChild( child, 0 ) ) );
258    saved = tr_bencToStr( &val, TR_FMT_BENC, &len );
259    check( !strcmp( saved, "lld1:ai64e1:bi32eeee" ) );
260    tr_free( saved );
261    tr_bencFree( &val );
262
263    /* too many endings */
264    end = NULL;
265    tr_snprintf( (char*)buf, sizeof( buf ), "leee" );
266    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
267    check( !err );
268    check( end == buf + 2 );
269    saved = tr_bencToStr( &val, TR_FMT_BENC, &len );
270    check( !strcmp( saved, "le" ) );
271    tr_free( saved );
272    tr_bencFree( &val );
273
274    /* no ending */
275    end = NULL;
276    tr_snprintf( (char*)buf, sizeof( buf ), "l1:a1:b1:c" );
277    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
278    check( err );
279
280    /* incomplete string */
281    end = NULL;
282    tr_snprintf( (char*)buf, sizeof( buf ), "1:" );
283    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
284    check( err );
285
286    return 0;
287}
288
289static void
290stripWhitespace( char * in )
291{
292    char * out;
293
294    for( out = in; *in; ++in )
295        if( !isspace( *in ) )
296            *out++ = *in;
297    *out = '\0';
298}
299
300static int
301testJSONSnippet( const char * benc_str,
302                 const char * expected )
303{
304    tr_benc top;
305    char * serialized;
306    struct evbuffer * buf;
307
308    tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
309    buf = tr_bencToBuf( &top, TR_FMT_JSON );
310    serialized = (char*) evbuffer_pullup( buf, -1 );
311    stripWhitespace( serialized );
312#if 0
313    fprintf( stderr, "benc: %s\n", benc_str );
314    fprintf( stderr, "json: %s\n", serialized );
315    fprintf( stderr, "want: %s\n", expected );
316#endif
317    check( !strcmp( serialized, expected ) );
318    tr_bencFree( &top );
319    evbuffer_free( buf );
320    return 0;
321}
322
323static int
324testJSON( void )
325{
326    int          val;
327    const char * benc_str;
328    const char * expected;
329
330    benc_str = "i6e";
331    expected = "6";
332    if( ( val = testJSONSnippet( benc_str, expected ) ) )
333        return val;
334
335    benc_str = "d5:helloi1e5:worldi2ee";
336    expected = "{\"hello\":1,\"world\":2}";
337    if( ( val = testJSONSnippet( benc_str, expected ) ) )
338        return val;
339
340    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3eee";
341    expected = "{\"foo\":[1,2,3],\"hello\":1,\"world\":2}";
342    if( ( val = testJSONSnippet( benc_str, expected ) ) )
343        return val;
344
345    benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eeee";
346    expected = "{\"foo\":[1,2,3,{\"a\":0}],\"hello\":1,\"world\":2}";
347    if( ( val = testJSONSnippet( benc_str, expected ) ) )
348        return val;
349
350    benc_str = "d4:argsd6:statusle7:status2lee6:result7:successe";
351    expected =
352        "{\"args\":{\"status\":[],\"status2\":[]},\"result\":\"success\"}";
353    if( ( val = testJSONSnippet( benc_str, expected ) ) )
354        return val;
355
356    return 0;
357}
358
359static int
360testMerge( void )
361{
362    tr_benc dest, src;
363    int64_t i;
364    const char * s;
365
366    /* initial dictionary (default values)  */
367    tr_bencInitDict( &dest, 10 );
368    tr_bencDictAddInt( &dest, "i1", 1 );
369    tr_bencDictAddInt( &dest, "i2", 2 );
370    tr_bencDictAddInt( &dest, "i4", -35 ); /* remains untouched */
371    tr_bencDictAddStr( &dest, "s5", "abc" );
372    tr_bencDictAddStr( &dest, "s6", "def" );
373    tr_bencDictAddStr( &dest, "s7", "127.0.0.1" ); /* remains untouched */
374
375    /* new dictionary, will overwrite items in dest  */
376    tr_bencInitDict( &src, 10 );
377    tr_bencDictAddInt( &src, "i1", 1 );     /* same value */
378    tr_bencDictAddInt( &src, "i2", 4 );     /* new value */
379    tr_bencDictAddInt( &src, "i3", 3 );     /* new key:value */
380    tr_bencDictAddStr( &src, "s5", "abc" ); /* same value */
381    tr_bencDictAddStr( &src, "s6", "xyz" ); /* new value */
382    tr_bencDictAddStr( &src, "s8", "ghi" ); /* new key:value */
383
384    tr_bencMergeDicts( &dest, /*const*/ &src );
385
386    check( tr_bencDictFindInt( &dest, "i1", &i ));
387    check( i == 1);
388    check( tr_bencDictFindInt( &dest, "i2", &i ));
389    check( i == 4);
390    check( tr_bencDictFindInt( &dest, "i3", &i ));
391    check( i == 3);
392    check( tr_bencDictFindInt( &dest, "i4", &i ));
393    check( i == -35);
394    check( tr_bencDictFindStr( &dest, "s5", &s ));
395    check( strcmp( "abc", s ) == 0 );
396    check( tr_bencDictFindStr( &dest, "s6", &s ));
397    check( strcmp( "xyz", s ) == 0 );
398    check( tr_bencDictFindStr( &dest, "s7", &s ));
399    check( strcmp( "127.0.0.1", s ) == 0 );
400    check( tr_bencDictFindStr( &dest, "s8", &s ));
401    check( strcmp( "ghi", s ) == 0 );
402
403    tr_bencFree( &dest );
404    tr_bencFree( &src );
405    return 0;
406}
407
408static int
409testStackSmash( void )
410{
411    int             i;
412    int             len;
413    int             err;
414    uint8_t *       in;
415    const uint8_t * end;
416    tr_benc         val;
417    char *          saved;
418    const int       depth = STACK_SMASH_DEPTH;
419
420    in = tr_new( uint8_t, depth * 2 + 1 );
421    for( i = 0; i < depth; ++i )
422    {
423        in[i] = 'l';
424        in[depth + i] = 'e';
425    }
426    in[depth * 2] = '\0';
427    err = tr_bencParse( in, in + ( depth * 2 ), &val, &end );
428    check( !err );
429    check( end == in + ( depth * 2 ) );
430    saved = tr_bencToStr( &val, TR_FMT_BENC, &len );
431    check( !strcmp( saved, (char*)in ) );
432    tr_free( in );
433    tr_free( saved );
434    tr_bencFree( &val );
435
436    return 0;
437}
438
439static int
440testBool( void )
441{
442    tr_benc top;
443    int64_t intVal;
444    bool boolVal;
445
446    tr_bencInitDict( &top, 0 );
447
448    tr_bencDictAddBool( &top, "key1", false );
449    tr_bencDictAddBool( &top, "key2", 0 );
450    tr_bencDictAddInt ( &top, "key3", true );
451    tr_bencDictAddInt ( &top, "key4", 1 );
452    check( tr_bencDictFindBool( &top, "key1", &boolVal ) );
453    check( !boolVal );
454    check( tr_bencDictFindBool( &top, "key2", &boolVal ) );
455    check( !boolVal );
456    check( tr_bencDictFindBool( &top, "key3", &boolVal ) );
457    check( boolVal );
458    check( tr_bencDictFindBool( &top, "key4", &boolVal ) );
459    check( boolVal );
460    check( tr_bencDictFindInt( &top, "key1", &intVal ) );
461    check( !intVal);
462    check( tr_bencDictFindInt( &top, "key2", &intVal ) );
463    check( !intVal );
464    check( tr_bencDictFindInt( &top, "key3", &intVal ) );
465    check( intVal );
466    check( tr_bencDictFindInt( &top, "key4", &intVal ) );
467    check( intVal );
468
469    tr_bencFree( &top );
470    return 0;
471}
472
473static int
474testParse2( void )
475{
476    tr_benc top;
477    tr_benc top2;
478    int64_t intVal;
479    const char * strVal;
480    double realVal;
481    bool boolVal;
482    int len;
483    char * benc;
484    const uint8_t * end;
485
486    tr_bencInitDict( &top, 0 );
487    tr_bencDictAddBool( &top, "this-is-a-bool", true );
488    tr_bencDictAddInt( &top, "this-is-an-int", 1234 );
489    tr_bencDictAddReal( &top, "this-is-a-real", 0.5 );
490    tr_bencDictAddStr( &top, "this-is-a-string", "this-is-a-string" );
491
492    benc = tr_bencToStr( &top, TR_FMT_BENC, &len );
493    check( !strcmp( benc, "d14:this-is-a-booli1e14:this-is-a-real8:0.50000016:this-is-a-string16:this-is-a-string14:this-is-an-inti1234ee" ) );
494    check( !tr_bencParse( benc, benc+len, &top2, &end ) );
495    check( (char*)end == benc + len );
496    check( tr_bencIsDict( &top2 ) );
497    check( tr_bencDictFindInt( &top, "this-is-an-int", &intVal ) );
498    check( intVal == 1234 );
499    check( tr_bencDictFindBool( &top, "this-is-a-bool", &boolVal ) );
500    check( boolVal == true );
501    check( tr_bencDictFindStr( &top, "this-is-a-string", &strVal ) );
502    check( !strcmp( strVal, "this-is-a-string" ) );
503    check( tr_bencDictFindReal( &top, "this-is-a-real", &realVal ) );
504    check( (int)(realVal*100) == 50 );
505
506    tr_bencFree( &top2 );
507    tr_free( benc );
508    tr_bencFree( &top );
509
510    return 0;
511}
512
513int
514main( void )
515{
516    static const testFunc tests[] = {
517        testInt, testStr, testParse, testJSON, testMerge, testBool,
518        testParse2, testStackSmash,
519    };
520
521    return runTests(tests, NUM_TESTS(tests));
522}
Note: See TracBrowser for help on using the repository browser.