2008-05-22 16:41:16 +00:00
|
|
|
#include <ctype.h>
|
2008-01-30 15:39:41 +00:00
|
|
|
#include <stdio.h>
|
2008-08-21 14:57:59 +00:00
|
|
|
#include <string.h>
|
2008-01-30 15:39:41 +00:00
|
|
|
#include "transmission.h"
|
|
|
|
#include "bencode.h"
|
2008-05-13 12:52:58 +00:00
|
|
|
#include "json.h"
|
2008-01-30 15:39:41 +00:00
|
|
|
#include "utils.h" /* tr_free */
|
|
|
|
|
2008-03-30 00:00:28 +00:00
|
|
|
#define VERBOSE 0
|
2008-01-30 15:39:41 +00:00
|
|
|
|
2008-08-11 19:05:02 +00:00
|
|
|
static int test = 0;
|
2008-01-30 15:39:41 +00:00
|
|
|
|
|
|
|
#define check(A) { \
|
|
|
|
++test; \
|
|
|
|
if (A) { \
|
|
|
|
if( VERBOSE ) \
|
|
|
|
fprintf( stderr, "PASS test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
|
|
|
|
} else { \
|
2008-08-19 23:11:35 +00:00
|
|
|
fprintf( stderr, "FAIL test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
|
2008-01-30 15:39:41 +00:00
|
|
|
return test; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
testInt( void )
|
|
|
|
{
|
|
|
|
uint8_t buf[128];
|
|
|
|
int64_t val;
|
|
|
|
int err;
|
|
|
|
const uint8_t * end;
|
|
|
|
|
|
|
|
/* good int string */
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "i64e" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParseInt( buf, buf+4, &end, &val );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( err == 0 );
|
|
|
|
check( val == 64 );
|
|
|
|
check( end == buf + 4 );
|
|
|
|
|
|
|
|
/* missing 'e' */
|
|
|
|
end = NULL;
|
|
|
|
val = 888;
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParseInt( buf, buf+3, &end, &val );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( err == TR_ERROR );
|
|
|
|
check( val == 888 );
|
|
|
|
check( end == NULL );
|
|
|
|
|
|
|
|
/* empty buffer */
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParseInt( buf, buf+0, &end, &val );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( err == TR_ERROR );
|
|
|
|
check( val == 888 );
|
|
|
|
check( end == NULL );
|
|
|
|
|
|
|
|
/* bad number */
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "i6z4e" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParseInt( buf, buf+5, &end, &val );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( err == TR_ERROR );
|
|
|
|
check( val == 888 );
|
|
|
|
check( end == NULL );
|
|
|
|
|
|
|
|
/* negative number */
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "i-3e" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParseInt( buf, buf+4, &end, &val );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( err == TR_OK );
|
|
|
|
check( val == -3 );
|
|
|
|
check( end == buf + 4 );
|
|
|
|
|
|
|
|
/* zero */
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "i0e" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParseInt( buf, buf+4, &end, &val );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( err == TR_OK );
|
|
|
|
check( val == 0 );
|
|
|
|
check( end == buf + 3 );
|
|
|
|
|
|
|
|
/* no leading zeroes allowed */
|
|
|
|
val = 0;
|
|
|
|
end = NULL;
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "i04e" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParseInt( buf, buf+4, &end, &val );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( err == TR_ERROR );
|
|
|
|
check( val == 0 );
|
|
|
|
check( end == NULL );
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
testStr( void )
|
|
|
|
{
|
|
|
|
uint8_t buf[128];
|
|
|
|
int err;
|
|
|
|
const uint8_t * end;
|
2008-08-21 18:40:40 +00:00
|
|
|
const uint8_t * str;
|
2008-01-30 15:39:41 +00:00
|
|
|
size_t len;
|
|
|
|
|
|
|
|
/* good string */
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "4:boat" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParseStr( buf, buf+6, &end, &str, &len );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( err == TR_OK );
|
2008-08-21 18:40:40 +00:00
|
|
|
check( !strncmp( (char*)str, "boat", len ) );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( len == 4 );
|
|
|
|
check( end == buf + 6 );
|
|
|
|
str = NULL;
|
|
|
|
end = NULL;
|
|
|
|
len = 0;
|
|
|
|
|
|
|
|
/* string goes past end of buffer */
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParseStr( buf, buf+5, &end, &str, &len );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( err == TR_ERROR );
|
|
|
|
check( str == NULL );
|
|
|
|
check( end == NULL );
|
|
|
|
check( !len );
|
|
|
|
|
|
|
|
/* empty string */
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "0:" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParseStr( buf, buf+2, &end, &str, &len );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( err == TR_OK );
|
|
|
|
check( !*str );
|
|
|
|
check( !len );
|
|
|
|
check( end == buf + 2 );
|
|
|
|
str = NULL;
|
|
|
|
end = NULL;
|
|
|
|
len = 0;
|
|
|
|
|
|
|
|
/* short string */
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "3:boat" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParseStr( buf, buf+6, &end, &str, &len );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( err == TR_OK );
|
2008-08-21 18:40:40 +00:00
|
|
|
check( !strncmp( (char*)str, "boa", len ) );
|
2008-01-30 15:39:41 +00:00
|
|
|
check( len == 3 );
|
|
|
|
check( end == buf + 5 );
|
|
|
|
str = NULL;
|
|
|
|
end = NULL;
|
|
|
|
len = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2008-01-31 02:24:43 +00:00
|
|
|
|
2008-02-01 15:50:17 +00:00
|
|
|
static int
|
|
|
|
testString( const char * str, int isGood )
|
|
|
|
{
|
2008-02-26 21:58:58 +00:00
|
|
|
tr_benc val;
|
2008-02-01 15:50:17 +00:00
|
|
|
const uint8_t * end = NULL;
|
|
|
|
char * saved;
|
|
|
|
const size_t len = strlen( str );
|
|
|
|
int savedLen;
|
|
|
|
int err = tr_bencParse( str, str+len, &val , &end );
|
|
|
|
if( !isGood ) {
|
|
|
|
check( err );
|
|
|
|
} else {
|
|
|
|
check( !err );
|
2008-05-22 16:41:16 +00:00
|
|
|
#if 0
|
|
|
|
fprintf( stderr, "in: [%s]\n", str );
|
|
|
|
fprintf( stderr, "out:\n%s", tr_bencSaveAsJSON(&val,NULL) );
|
|
|
|
#endif
|
2008-02-01 15:50:17 +00:00
|
|
|
check( end == (const uint8_t*)str + len );
|
|
|
|
saved = tr_bencSave( &val, &savedLen );
|
|
|
|
check( !strcmp( saved, str ) );
|
|
|
|
check( len == (size_t)savedLen );
|
|
|
|
tr_free( saved );
|
|
|
|
tr_bencFree( &val );
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-31 02:24:43 +00:00
|
|
|
static int
|
|
|
|
testParse( void )
|
|
|
|
{
|
2008-02-26 21:58:58 +00:00
|
|
|
tr_benc val;
|
|
|
|
tr_benc * child;
|
|
|
|
tr_benc * child2;
|
2008-01-31 02:24:43 +00:00
|
|
|
uint8_t buf[512];
|
|
|
|
const uint8_t * end;
|
|
|
|
int err;
|
|
|
|
int len;
|
2008-04-13 22:31:07 +00:00
|
|
|
int64_t i;
|
2008-01-31 02:24:43 +00:00
|
|
|
char * saved;
|
|
|
|
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "i64e" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
|
|
|
|
check( !err );
|
2008-04-13 22:31:07 +00:00
|
|
|
check( tr_bencGetInt( &val, &i ) );
|
|
|
|
check( i == 64 );
|
2008-01-31 02:24:43 +00:00
|
|
|
check( end == buf + 4 );
|
|
|
|
tr_bencFree( &val );
|
|
|
|
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "li64ei32ei16ee" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
|
|
|
|
check( !err );
|
|
|
|
check( end == buf + strlen( (char*)buf ) );
|
|
|
|
check( val.val.l.count == 3 );
|
2008-04-13 22:31:07 +00:00
|
|
|
check( tr_bencGetInt( &val.val.l.vals[0], &i ) );
|
|
|
|
check( i == 64 );
|
|
|
|
check( tr_bencGetInt( &val.val.l.vals[1], &i ) );
|
|
|
|
check( i == 32 );
|
|
|
|
check( tr_bencGetInt( &val.val.l.vals[2], &i ) );
|
|
|
|
check( i == 16 );
|
2008-01-31 02:24:43 +00:00
|
|
|
saved = tr_bencSave( &val, &len );
|
|
|
|
check( !strcmp( saved, (char*)buf ) );
|
|
|
|
tr_free( saved );
|
|
|
|
tr_bencFree( &val );
|
|
|
|
|
|
|
|
end = NULL;
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "lllee" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val , &end );
|
|
|
|
check( err );
|
|
|
|
check( end == NULL );
|
|
|
|
|
|
|
|
end = NULL;
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "le" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParse( buf, buf + sizeof( buf ), &val , &end );
|
|
|
|
check( !err );
|
|
|
|
check( end == buf + 2 );
|
|
|
|
saved = tr_bencSave( &val, &len );
|
|
|
|
check( !strcmp( saved, "le" ) );
|
|
|
|
tr_free( saved );
|
|
|
|
tr_bencFree( &val );
|
|
|
|
|
2008-02-01 15:50:17 +00:00
|
|
|
if(( err = testString( "llleee", TRUE )))
|
|
|
|
return err;
|
|
|
|
if(( err = testString( "d3:cow3:moo4:spam4:eggse", TRUE )))
|
|
|
|
return err;
|
|
|
|
if(( err = testString( "d4:spaml1:a1:bee", TRUE )))
|
|
|
|
return err;
|
2008-05-22 16:41:16 +00:00
|
|
|
if(( err = testString( "d5:greenli1ei2ei3ee4:spamd1:ai123e3:keyi214eee", TRUE )))
|
|
|
|
return err;
|
2008-02-01 17:33:49 +00:00
|
|
|
if(( err = testString( "d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee", TRUE )))
|
2008-02-01 15:50:17 +00:00
|
|
|
return err;
|
|
|
|
if(( err = testString( "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e", TRUE )))
|
|
|
|
return err;
|
|
|
|
if(( err = testString( "d1:ai0e1:be", FALSE ))) /* odd number of children */
|
|
|
|
return err;
|
|
|
|
if(( err = testString( "", FALSE )))
|
|
|
|
return err;
|
2008-02-01 17:33:49 +00:00
|
|
|
if(( err = testString( " ", FALSE )))
|
|
|
|
return err;
|
2008-01-31 02:24:43 +00:00
|
|
|
|
|
|
|
/* nested containers
|
|
|
|
* parse an unsorted dict
|
|
|
|
* save as a sorted dict */
|
|
|
|
end = NULL;
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "lld1:bi32e1:ai64eeee" );
|
2008-01-31 02:24:43 +00:00
|
|
|
err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
|
|
|
|
check( !err );
|
|
|
|
check( end == buf + strlen( (const char*)buf ) );
|
2008-05-08 03:25:21 +00:00
|
|
|
check(( child = tr_bencListChild( &val, 0 )));
|
|
|
|
check(( child2 = tr_bencListChild( child, 0 )));
|
2008-01-31 02:24:43 +00:00
|
|
|
saved = tr_bencSave( &val, &len );
|
|
|
|
check( !strcmp( saved, "lld1:ai64e1:bi32eeee" ) );
|
|
|
|
tr_free( saved );
|
|
|
|
tr_bencFree( &val );
|
|
|
|
|
2008-02-01 21:53:01 +00:00
|
|
|
/* too many endings */
|
|
|
|
end = NULL;
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "leee" );
|
2008-02-01 21:53:01 +00:00
|
|
|
err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
|
|
|
|
check( !err );
|
|
|
|
check( end == buf + 2 );
|
|
|
|
saved = tr_bencSave( &val, &len );
|
|
|
|
check( !strcmp( saved, "le" ) );
|
|
|
|
tr_free( saved );
|
|
|
|
tr_bencFree( &val );
|
|
|
|
|
|
|
|
/* no ending */
|
|
|
|
end = NULL;
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "l1:a1:b1:c" );
|
2008-02-01 21:53:01 +00:00
|
|
|
err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
|
|
|
|
check( err );
|
|
|
|
|
|
|
|
/* incomplete string */
|
|
|
|
end = NULL;
|
2008-07-15 17:16:57 +00:00
|
|
|
tr_snprintf( (char*)buf, sizeof( buf ), "1:" );
|
2008-02-01 21:53:01 +00:00
|
|
|
err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val, &end );
|
|
|
|
check( err );
|
|
|
|
|
2008-01-31 02:24:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-05-22 16:41:16 +00:00
|
|
|
static void
|
|
|
|
stripWhitespace( char * in )
|
|
|
|
{
|
|
|
|
char * out;
|
|
|
|
for( out=in; *in; ++in )
|
|
|
|
if( !isspace( *in ) )
|
|
|
|
*out++ = *in;
|
|
|
|
*out = '\0';
|
|
|
|
}
|
|
|
|
|
2008-03-04 19:29:51 +00:00
|
|
|
static int
|
2008-05-12 17:54:57 +00:00
|
|
|
testJSONSnippet( const char * benc_str, const char * expected )
|
2008-03-04 19:29:51 +00:00
|
|
|
{
|
|
|
|
tr_benc top;
|
|
|
|
char * serialized;
|
|
|
|
tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
|
2008-05-12 17:54:57 +00:00
|
|
|
serialized = tr_bencSaveAsJSON( &top, NULL );
|
2008-05-22 16:41:16 +00:00
|
|
|
stripWhitespace( serialized );
|
2008-05-13 12:52:58 +00:00
|
|
|
#if 0
|
2008-05-22 16:41:16 +00:00
|
|
|
fprintf( stderr, "benc: %s\n", benc_str );
|
|
|
|
fprintf( stderr, "json: %s\n", serialized );
|
|
|
|
fprintf( stderr, "want: %s\n", expected );
|
2008-05-13 12:52:58 +00:00
|
|
|
#endif
|
2008-03-04 19:29:51 +00:00
|
|
|
check( !strcmp( serialized, expected ) );
|
|
|
|
tr_free( serialized );
|
|
|
|
tr_bencFree( &top );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2008-05-12 17:54:57 +00:00
|
|
|
testJSON( void )
|
2008-03-04 19:29:51 +00:00
|
|
|
{
|
|
|
|
int val;
|
|
|
|
const char * benc_str;
|
|
|
|
const char * expected;
|
|
|
|
|
|
|
|
benc_str = "i6e";
|
2008-05-12 17:54:57 +00:00
|
|
|
expected = "6";
|
|
|
|
if(( val = testJSONSnippet( benc_str, expected )))
|
2008-03-04 19:29:51 +00:00
|
|
|
return val;
|
|
|
|
|
2008-05-12 17:54:57 +00:00
|
|
|
benc_str = "d5:helloi1e5:worldi2ee";
|
2008-05-22 16:41:16 +00:00
|
|
|
expected = "{\"hello\":1,\"world\":2}";
|
2008-05-12 17:54:57 +00:00
|
|
|
if(( val = testJSONSnippet( benc_str, expected )))
|
2008-03-04 19:29:51 +00:00
|
|
|
return val;
|
|
|
|
|
2008-08-11 17:00:23 +00:00
|
|
|
benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3eee";
|
2008-05-22 16:41:16 +00:00
|
|
|
expected = "{\"foo\":[1,2,3],\"hello\":1,\"world\":2}";
|
2008-05-12 17:54:57 +00:00
|
|
|
if(( val = testJSONSnippet( benc_str, expected )))
|
|
|
|
return val;
|
|
|
|
|
2008-08-11 17:00:23 +00:00
|
|
|
benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eeee";
|
2008-05-22 16:41:16 +00:00
|
|
|
expected = "{\"foo\":[1,2,3,{\"a\":0}],\"hello\":1,\"world\":2}";
|
2008-05-12 17:54:57 +00:00
|
|
|
if(( val = testJSONSnippet( benc_str, expected )))
|
2008-03-04 19:29:51 +00:00
|
|
|
return val;
|
|
|
|
|
2008-05-22 16:41:16 +00:00
|
|
|
benc_str = "d4:argsd6:statusle7:status2lee6:result7:successe";
|
|
|
|
expected = "{\"args\":{\"status\":[],\"status2\":[]},\"result\":\"success\"}";
|
2008-05-13 12:52:58 +00:00
|
|
|
if(( val = testJSONSnippet( benc_str, expected )))
|
|
|
|
return val;
|
|
|
|
|
2008-03-04 19:29:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-31 02:24:43 +00:00
|
|
|
static int
|
|
|
|
testStackSmash( void )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int len;
|
|
|
|
int depth;
|
|
|
|
int err;
|
|
|
|
uint8_t * in;
|
|
|
|
const uint8_t * end;
|
2008-02-26 21:58:58 +00:00
|
|
|
tr_benc val;
|
2008-01-31 02:24:43 +00:00
|
|
|
char * saved;
|
|
|
|
|
|
|
|
depth = 1000000;
|
|
|
|
in = tr_new( uint8_t, depth*2 + 1 );
|
|
|
|
for( i=0; i<depth; ++i ) {
|
|
|
|
in[i] = 'l';
|
|
|
|
in[depth+i] = 'e';
|
|
|
|
}
|
|
|
|
in[depth*2] = '\0';
|
|
|
|
err = tr_bencParse( in, in+(depth*2), &val, &end );
|
|
|
|
check( !err );
|
|
|
|
check( end == in+(depth*2) );
|
|
|
|
saved = tr_bencSave( &val, &len );
|
|
|
|
check( !strcmp( saved, (char*)in ) );
|
|
|
|
tr_free( in );
|
|
|
|
tr_free( saved );
|
|
|
|
tr_bencFree( &val );
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-30 15:39:41 +00:00
|
|
|
int
|
|
|
|
main( void )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2008-01-31 02:24:43 +00:00
|
|
|
if(( i = testInt( )))
|
|
|
|
return i;
|
|
|
|
|
|
|
|
if(( i = testStr( )))
|
|
|
|
return i;
|
|
|
|
|
|
|
|
if(( i = testParse( )))
|
2008-01-30 15:39:41 +00:00
|
|
|
return i;
|
|
|
|
|
2008-05-12 17:54:57 +00:00
|
|
|
if(( i = testJSON( )))
|
2008-03-04 19:29:51 +00:00
|
|
|
return i;
|
|
|
|
|
2008-01-31 02:24:43 +00:00
|
|
|
if(( i = testStackSmash( )))
|
2008-01-30 15:39:41 +00:00
|
|
|
return i;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|