void TestBencodeDictGetNextTwice(
    CuTest * tc
)
{
    bencode_t ben;

    bencode_t ben2;

    char *str = strdup("d4:test3:egg3:foo3:hame");

    const char *ren;

    int len;

    bencode_init(&ben, str, strlen(str));

    bencode_dict_get_next(&ben, &ben2, &ren, &len);
    CuAssertTrue(tc, !strncmp(ren, "test", len));
    bencode_string_value(&ben2, &ren, &len);
    CuAssertTrue(tc, !strncmp("egg", ren, len));

    bencode_dict_get_next(&ben, &ben2, &ren, &len);
    CuAssertTrue(tc, !strncmp(ren, "foo", len));
    bencode_string_value(&ben2, &ren, &len);
    CuAssertTrue(tc, !strncmp("ham", ren, len));
//    printf("%s\n", str);
//    CuAssertTrue(tc, !strcmp("l4:test3:fooe", str));
    free(str);
}
void TestBencodeStringHandlesNonAscii0(
    CuTest * tc
)
{
    bencode_t ben;

    char *str = strdup("6:xxxxxx");

    const char *ren;

    int len;

    /*  127.0.0.1:80 */
    str[2] = 127;
    str[3] = 0;
    str[4] = 0;
    str[5] = 1;
    str[6] = 0;
    str[7] = 80;

    bencode_init(&ben, str, 8);

    bencode_string_value(&ben, &ren, &len);
    CuAssertTrue(tc, ren[0] == 127);
    CuAssertTrue(tc, ren[1] == 0);
    CuAssertTrue(tc, ren[2] == 0);
    CuAssertTrue(tc, ren[3] == 1);
    CuAssertTrue(tc, ren[4] == 0);
    CuAssertTrue(tc, ren[5] == 80);
    bencode_done(&ben);
    free(str);
}
void TestBencodeListGetNextTwice(
    CuTest * tc
)
{
    bencode_t ben;

    bencode_t ben2;

    char *str = strdup("l4:test3:fooe");

    const char *ren;

    int len;

    bencode_init(&ben, str, strlen(str));

    CuAssertTrue(tc, 1 == bencode_list_get_next(&ben, &ben2));
    bencode_string_value(&ben2, &ren, &len);
    CuAssertTrue(tc, !strncmp("test", ren, len));

    CuAssertTrue(tc, 1 == bencode_list_get_next(&ben, &ben2));
    bencode_string_value(&ben2, &ren, &len);
    CuAssertTrue(tc, !strncmp("foo", ren, len));

//    printf("%s\n", str);
//    CuAssertTrue(tc, !strcmp("l4:test3:fooe", str));
    free(str);
}
void TestBencodeDictInnerList(
    CuTest * tc
)
{
    bencode_t ben;

    bencode_t ben2;

    char *str = strdup("d3:keyl4:test3:fooe3:foo3:bare");

    const char *ren;

    int len;

    bencode_init(&ben, str, strlen(str));

    bencode_dict_get_next(&ben, &ben2, &ren, &len);
    CuAssertTrue(tc, !strncmp(ren, "key", len));

    bencode_dict_get_next(&ben, &ben2, &ren, &len);
    CuAssertTrue(tc, !strncmp(ren, "foo", len));

    CuAssertTrue(tc, !bencode_dict_has_next(&ben));
//    printf("%s\n", str);
//    CuAssertTrue(tc, !strcmp("l4:test3:fooe", str));
    free(str);
}
void TestBencodeDictGetNextInnerList(
    CuTest * tc
)
{
    bencode_t ben, ben2, ben3;
    char *str;
    const char *ren;
    int len;

    str = strdup("d3:keyl4:test3:fooee");
    bencode_init(&ben, str, strlen(str));

    bencode_dict_get_next(&ben, &ben2, &ren, &len);
    CuAssertTrue(tc, !strncmp(ren, "key", len));

    bencode_list_get_next(&ben2, &ben3);
    bencode_string_value(&ben3, &ren, &len);
    CuAssertTrue(tc, !strncmp("test", ren, len));

    bencode_list_get_next(&ben2, &ben3);
    bencode_string_value(&ben3, &ren, &len);
    CuAssertTrue(tc, !strncmp("foo", ren, len));

    CuAssertTrue(tc, !bencode_dict_has_next(&ben));
    free(str);
}
int BencodeParser::bencode_dict_get_next(
		bencode_t * be,
		bencode_t * be_item,
		const char **key,
		int *klen
)
{
	const char *sp = be->str;
	const char *keyin;
	int len;

	assert(*sp != 'e');

	/* if at start increment to 1st key */
	if (*sp == 'd')
	{
		sp++;
	}

	/* can't get the next item if we are at the end of the dict */
	if (*sp == 'e')
	{
		return 0;
	}

	/* 1. find out what the key's length is */
	keyin = __read_string_len(sp, &len);

	/* 2. if we have a value bencode, lets put the value inside */
	if (be_item)
	{
		*klen = len;
		bencode_init(be_item, keyin + len, __carry_length(be, keyin + len));
	}

	/* 3. iterate to next dict key, or move to next item in parent */
	if (!(be->str = __iterate_to_next_string_pos(be, keyin + len)))
	{
		/*  if there isn't anything else or we are at the end of the string */
		return 0;
	}

#if 0
	/*  if at the end of bencode, check that the 'e' terminator is there */
	if (be->str == be->start + be->len - 1 && *be->str != 'e')
	{
		be->str = NULL;
		return 0;
	}
#endif

	assert(be->str);

	if (key)
	{
		*key = keyin;
	}

	return 1;
}
void TestBencodeIsDictEmpty(
    CuTest * tc
)
{
    bencode_t ben;

    char *str = strdup(" ");

    bencode_init(&ben, str, strlen(str));
    CuAssertTrue(tc, 0 == bencode_is_dict(&ben));
    free(str);
}
void TestBencodeIsString(
    CuTest * tc
)
{
    bencode_t ben;

    char *str = strdup("4:test");

    bencode_init(&ben, str, strlen(str));

    CuAssertTrue(tc, 1 == bencode_is_string(&ben));
    free(str);
}
void TestBencodeIsList(
    CuTest * tc
)
{
    bencode_t ben;

    char *str = strdup("l4:test3:fooe");

    bencode_init(&ben, str, strlen(str));

    CuAssertTrue(tc, 1 == bencode_is_list(&ben));
    free(str);
}
void TestBencodeListGetNextTwiceWhereOnlyOneAvailable(
    CuTest * tc
)
{
    bencode_t ben, ben2;

    char *str = strdup("l4:teste");

    bencode_init(&ben, str, strlen(str));
    CuAssertTrue(tc, 1 == bencode_list_get_next(&ben, &ben2));
    CuAssertTrue(tc, 0 == bencode_list_get_next(&ben, &ben2));
    free(str);
}
void TestBencodeListWontGetNextIfEmpty(
    CuTest * tc
)
{
    bencode_t ben, ben2;

    char *str = strdup("le");

    bencode_init(&ben, str, strlen(str));

    CuAssertTrue(tc, 0 == bencode_list_get_next(&ben, &ben2));
    free(str);
}
void TestBencodeDictHasNext(
    CuTest * tc
)
{
    bencode_t ben;

    char *str = strdup("d4:test3:fooe");

    bencode_init(&ben, str, strlen(str));

    CuAssertTrue(tc, 1 == bencode_dict_has_next(&ben));
    free(str);
}
void TestBencodeIsInt(
    CuTest * tc
)
{
    bencode_t ben;

    char *str = strdup("i666e");

    bencode_init(&ben, str, strlen(str));

    CuAssertTrue(tc, 1 == bencode_is_int(&ben));
    free(str);
}
void TestBencodeListGetNextAtInvalidEnd(
    CuTest * tc
)
{
    bencode_t ben, ben2;

    char *str = strdup("l4:testg");

    bencode_init(&ben, str, strlen(str));

    CuAssertTrue(tc, 1 == bencode_list_get_next(&ben, &ben2));
    CuAssertTrue(tc, -1 == bencode_list_get_next(&ben, &ben2));

    free(str);
}
void TestBencodeWontDoShortExpectedLength2(
    CuTest * tc
)
{
    bencode_t ben;

    char *str = strdup("4:test");

    const char *ren;

    int len;

    bencode_init(&ben, str, 1);
    CuAssertTrue(tc, 0 == bencode_string_value(&ben, &ren, &len));
    free(str);
}
void TestBencodeIntValue(
    CuTest * tc
)
{
    bencode_t ben;

    char *str = strdup("i666e");

    long int val;

    bencode_init(&ben, str, strlen(str));

    bencode_int_value(&ben, &val);
    CuAssertTrue(tc, 666 == val);
    free(str);
}
int BencodeParser::bencode_list_get_next(
		bencode_t * be,
		bencode_t * be_item
)
{
	const char *sp;

	sp = be->str;

#if 0 /* debugging */
	printf("%.*s\n", be->len - (be->str - be->start), be->str);
#endif

	/* we're at the end */
	if (!sp || *sp == 'e')
		return 0;

	if (*sp == 'l')
	{
		/* just move off the start of this list */
		if (be->start == be->str)
		{
			sp++;
		}
	}

	/* can't get the next item if we are at the end of the list */
	if (*sp == 'e')
	{
		be->str = sp;
		return 0;
	}

	/* populate the be_item if it is available */
	if (be_item)
	{
		bencode_init(be_item, sp, __carry_length(be, sp));
	}

	/* iterate to next value */
	if (!(be->str = __iterate_to_next_string_pos(be, sp)))
	{
		return -1;
	}

	return 1;
}
void TestBencodeStringValue2(
    CuTest * tc
)
{
    bencode_t ben;

    char *str = strdup("12:flyinganimal");

    const char *ren;

    int len;

    bencode_init(&ben, str, strlen(str));
    bencode_string_value(&ben, &ren, &len);
    CuAssertTrue(tc, !strncmp("flyinganimal", ren, len));
    free(str);
}
/**
 * The string value function errors when the string is of insufficient length
 * */
void TestBencodeStringInvalid(
    CuTest * tc
)
{
    bencode_t ben;

    char *str = strdup("5:test");

    const char *ren;

    int len;

    bencode_init(&ben, str, strlen(str));
    bencode_string_value(&ben, &ren, &len);
    CuAssertTrue(tc, !ren);
    free(str);
}
void TestBencodeDictWontGetNextIfEmpty(
    CuTest * tc
)
{
    bencode_t ben, ben2;

    char *str = strdup("de");

    const char *ren;

    int len, ret;

    bencode_init(&ben, str, strlen(str));
    ret = bencode_dict_get_next(&ben, &ben2, &ren, &len);
    CuAssertTrue(tc, 0 == ret);
    free(str);
}
void TestBencodeCloneClones(
    CuTest * tc
)
{
    bencode_t ben, ben2;

    char *str = strdup("d3:keyl4:test3:fooe3:foo3:bare");

    bencode_init(&ben, str, strlen(str));

    bencode_clone(&ben, &ben2);

    CuAssertTrue(tc, !strcmp(ben.str, ben2.str));
    CuAssertTrue(tc, !strcmp(ben.start, ben2.start));
    CuAssertTrue(tc, ben.len == ben2.len);
    free(str);
}
void TestBencodeEmptyListInListWontGetNextTwiceIfEmpty(
    CuTest * tc
)
{
    bencode_t ben, ben2;

    char *str = strdup("llelee");

    bencode_init(&ben, str, strlen(str));

    CuAssertTrue(tc, 1 == bencode_list_has_next(&ben));
    CuAssertTrue(tc, 1 == bencode_list_get_next(&ben, &ben2));
    CuAssertTrue(tc, 1 == bencode_is_list(&ben2));
    CuAssertTrue(tc, 1 == bencode_list_get_next(&ben, &ben2));
    CuAssertTrue(tc, 1 == bencode_is_list(&ben2));
    CuAssertTrue(tc, 0 == bencode_list_get_next(&ben, &ben2));
    free(str);
}
void TestBencodeListGetNext(
    CuTest * tc
)
{
    bencode_t ben, ben2;

    char *str = strdup("l3:foo3:bare");

    const char *ren;

    int len;

    bencode_init(&ben, str, strlen(str));

    CuAssertTrue(tc, 1 == bencode_list_get_next(&ben, &ben2));
    bencode_string_value(&ben2, &ren, &len);
    CuAssertTrue(tc, !strncmp("foo", ren, len));
    free(str);
}
void TxestBencodeDictGetNextOnlyIfValidDictEnd(
    CuTest * tc
)
{
    bencode_t ben, ben2;

    /*  no terminating 'e' */
    char *str = strdup("d3:foo3:barz");

    const char *ren;

    int len, ret;

    bencode_init(&ben, str, strlen(str));

    ret = bencode_dict_get_next(&ben, &ben2, &ren, &len);
    CuAssertTrue(tc, 0 == ret);
    free(str);
}
void TestBencodeStringValue(
    CuTest * tc
)
{
    bencode_t ben;

    char *str = strdup("4:test");

    const char *ren;

    int len;

    //*ptr = 0;
    bencode_init(&ben, str, strlen(str));
    bencode_string_value(&ben, &ren, &len);
    CuAssertTrue(tc, !strncmp("test", ren, len));
    bencode_done(&ben);
    free(str);
}
void TestBencodeDictGetNextTwiceOnlyIfSecondKeyValid(
    CuTest * tc
)
{
    bencode_t ben, ben2;

    char *str = strdup("d4:test3:egg2:foo3:hame");

    const char *ren;

    int len, ret;

    bencode_init(&ben, str, strlen(str));

    bencode_dict_get_next(&ben, &ben2, &ren, &len);

    ret = bencode_dict_get_next(&ben, &ben2, &ren, &len);
    CuAssertTrue(tc, ret == 0);
    free(str);
}
void TestBencodeListInListWithValue(
    CuTest * tc
)
{
    bencode_t ben, ben2, ben3;
    const char *ren;
    char *str = strdup("ll3:fooee");
    int len;

    bencode_init(&ben, str, strlen(str));

    CuAssertTrue(tc, 1 == bencode_is_list(&ben));
    CuAssertTrue(tc, 1 == bencode_list_get_next(&ben, &ben2));
    CuAssertTrue(tc, 1 == bencode_is_list(&ben2));
    CuAssertTrue(tc, 1 == bencode_list_get_next(&ben2, &ben3));
    CuAssertTrue(tc, 1 == bencode_is_string(&ben3));
    bencode_string_value(&ben3, &ren, &len);
    CuAssertTrue(tc, !strncmp("foo", ren, len));
    CuAssertTrue(tc, 0 == bencode_list_get_next(&ben, &ben2));
    free(str);
}
void TestBencodeDictGetNext(
    CuTest * tc
)
{
    bencode_t ben, ben2;

    char *str = strdup("d3:foo3:bare");

    const char *ren;

    int len, ret;

    bencode_init(&ben, str, strlen(str));

    ret = bencode_dict_get_next(&ben, &ben2, &ren, &len);
    CuAssertTrue(tc, 1 == ret);
    CuAssertTrue(tc, !strncmp("foo", ren, len));
    bencode_string_value(&ben2, &ren, &len);
    CuAssertPtrNotNull(tc, ren);
    CuAssertTrue(tc, !strncmp("bar", ren, len));
    free(str);
}