Merge pull request #209 from michael-loki/bencode_tests

Add test suite for bencode
pull/210/head
Jeff 6 years ago committed by GitHub
commit f6b23a28dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -625,6 +625,7 @@ set(TEST_SRC
test/test_dnsd_unit.cpp
test/test_dnslib.cpp
test/test_llarp_aligned.cpp
test/test_llarp_bencode.cpp
test/test_llarp_dht_key.cpp
test/test_llarp_queue_manager.cpp
test/test_llarp_queue.cpp

@ -1,44 +1,7 @@
#include <bencode.h>
#include <logger.hpp>
bool
bencode_write_bytestring(llarp_buffer_t* buff, const void* data, size_t sz)
{
if(!llarp_buffer_writef(buff, "%zu:", sz))
return false;
return llarp_buffer_write(buff, data, sz);
}
bool
bencode_write_uint64(llarp_buffer_t* buff, uint64_t i)
{
return llarp_buffer_writef(buff, "i%llu", i)
&& llarp_buffer_write(buff, "e", 1);
}
bool
bencode_start_list(llarp_buffer_t* buff)
{
return llarp_buffer_write(buff, "l", 1);
}
bool
bencode_start_dict(llarp_buffer_t* buff)
{
return llarp_buffer_write(buff, "d", 1);
}
bool
bencode_end(llarp_buffer_t* buff)
{
return llarp_buffer_write(buff, "e", 1);
}
bool
bencode_write_version_entry(llarp_buffer_t* buff)
{
return llarp_buffer_writef(buff, "1:vi%de", LLARP_PROTO_VERSION);
}
#include <cstdlib>
bool
bencode_read_integer(struct llarp_buffer_t* buffer, uint64_t* result)
@ -54,39 +17,43 @@ bencode_read_integer(struct llarp_buffer_t* buffer, uint64_t* result)
len =
llarp_buffer_read_until(buffer, 'e', (byte_t*)numbuf, sizeof(numbuf) - 1);
if(!len)
{
return false;
}
buffer->cur++;
numbuf[len] = '\0';
*result = strtoull(numbuf, nullptr, 10);
*result = std::strtoull(numbuf, nullptr, 10);
return true;
}
bool
bencode_read_string(llarp_buffer_t* buffer, llarp_buffer_t* result)
{
size_t len, slen;
int num;
char numbuf[10];
len =
size_t len =
llarp_buffer_read_until(buffer, ':', (byte_t*)numbuf, sizeof(numbuf) - 1);
if(!len)
return false;
numbuf[len] = '\0';
num = atoi(numbuf);
const int num = atoi(numbuf);
if(num < 0)
{
return false;
}
slen = num;
const size_t slen = num;
buffer->cur++;
len = llarp_buffer_size_left(*buffer);
if(len < slen)
{
return false;
}
result->base = buffer->cur;
result->cur = buffer->cur;
@ -95,6 +62,47 @@ bencode_read_string(llarp_buffer_t* buffer, llarp_buffer_t* result)
return true;
}
bool
bencode_write_bytestring(llarp_buffer_t* buff, const void* data, size_t sz)
{
if(!llarp_buffer_writef(buff, "%zu:", sz))
{
return false;
}
return llarp_buffer_write(buff, data, sz);
}
bool
bencode_write_uint64(llarp_buffer_t* buff, uint64_t i)
{
return llarp_buffer_writef(buff, "i%llu", i)
&& llarp_buffer_write(buff, "e", 1);
}
bool
bencode_write_version_entry(llarp_buffer_t* buff)
{
return llarp_buffer_writef(buff, "1:vi%de", LLARP_PROTO_VERSION);
}
bool
bencode_start_list(llarp_buffer_t* buff)
{
return llarp_buffer_write(buff, "l", 1);
}
bool
bencode_start_dict(llarp_buffer_t* buff)
{
return llarp_buffer_write(buff, "d", 1);
}
bool
bencode_end(llarp_buffer_t* buff)
{
return llarp_buffer_write(buff, "e", 1);
}
bool
bencode_read_dict(llarp_buffer_t* buff, struct dict_reader* r)
{

@ -5,6 +5,7 @@
#include <common.hpp>
#include <proto.hpp>
#include <functional>
#include <stdbool.h>
#include <stdint.h>
@ -17,28 +18,28 @@
*/
bool
bencode_write_bytestring(llarp_buffer_t* buff, const void* data, size_t sz);
bencode_read_integer(llarp_buffer_t* buffer, uint64_t* result);
bool
bencode_write_uint64(llarp_buffer_t* buff, uint64_t i);
bencode_read_string(llarp_buffer_t* buffer, llarp_buffer_t* result);
bool
bencode_start_list(llarp_buffer_t* buff);
bencode_write_bytestring(llarp_buffer_t* buff, const void* data, size_t sz);
bool
bencode_start_dict(llarp_buffer_t* buff);
bencode_write_uint64(llarp_buffer_t* buff, uint64_t i);
bool
bencode_end(llarp_buffer_t* buff);
bencode_write_version_entry(llarp_buffer_t* buff);
bool
bencode_write_version_entry(llarp_buffer_t* buff);
bencode_start_list(llarp_buffer_t* buff);
bool
bencode_read_integer(struct llarp_buffer_t* buffer, uint64_t* result);
bencode_start_dict(llarp_buffer_t* buff);
bool
bencode_read_string(llarp_buffer_t* buffer, llarp_buffer_t* result);
bencode_end(llarp_buffer_t* buff);
struct dict_reader
{
@ -51,7 +52,7 @@ struct dict_reader
* called when we got a key string, return true to continue iteration
* called with null key on done iterating
*/
bool (*on_key)(struct dict_reader*, llarp_buffer_t*);
std::function< bool(dict_reader*, llarp_buffer_t*) > on_key;
};
bool
@ -68,7 +69,7 @@ struct list_reader
* called with true when we got an element, return true to continue iteration
* called with false on iteration completion
*/
bool (*on_item)(struct list_reader*, bool);
std::function< bool(list_reader*, bool) > on_item;
};
bool

@ -48,7 +48,9 @@ namespace llarp
if(llarp_buffer_eq(key, k))
{
if(!BEncodeReadList(item, buf))
{
return false;
}
read = true;
}
return true;

@ -4,6 +4,7 @@
#include <common.hpp>
#include <mem.h>
#include <cassert>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@ -54,7 +55,7 @@ typedef uint8_t byte_t;
ABSOLUTELY NEVER USE DOUBLE POINTERS.
*/
typedef struct llarp_buffer_t
struct llarp_buffer_t
{
/// starting memory address
byte_t *base;
@ -63,13 +64,22 @@ typedef struct llarp_buffer_t
/// max size of buffer
size_t sz;
#ifdef __cplusplus
byte_t operator[](size_t x)
{
return *(this->base + x);
}
#endif
} llarp_buffer_t;
llarp_buffer_t() : base(nullptr), cur(nullptr), sz(0)
{
}
llarp_buffer_t(byte_t *b, byte_t *c, size_t s) : base(b), cur(c), sz(s)
{
assert(b != nullptr);
assert(c != nullptr);
assert(s != 0);
}
};
/// how much room is left in buffer
size_t

@ -34,13 +34,10 @@ namespace llarp
llarp_buffer_t
Buffer(T& t)
{
llarp_buffer_t buff;
// use data over the first element to "enforce" the container used has
// contiguous memory. (Note this isn't required by the standard, but a
// reasonable test on most standard library implementations).
buff.base = t.data();
buff.cur = buff.base;
buff.sz = t.size();
llarp_buffer_t buff(t.data(), t.data(), t.size());
return buff;
}

@ -14,7 +14,7 @@ namespace llarp
{
constexpr size_t MAX_MSG_SIZE = 2048;
struct IMessage : public llarp::IBEncodeMessage
struct IMessage : public IBEncodeMessage
{
virtual ~IMessage(){};

@ -1,7 +1,6 @@
#include <gtest/gtest.h>
#include <aligned.hpp>
#include <crypto.hpp>
#include <iostream>
#include <sstream>
@ -21,10 +20,6 @@ using TestSizes =
template < typename T >
struct AlignedBufferTest : public ::testing::Test
{
AlignedBufferTest() : crypto(llarp::Crypto::sodium{})
{
}
llarp::Crypto crypto;
};
TYPED_TEST_CASE(AlignedBufferTest, TestSizes);
@ -228,5 +223,3 @@ TYPED_TEST(AlignedBufferTest, TestHash)
EXPECT_FALSE(m[k_copy] == 2);
EXPECT_TRUE(m[k_copy] == 1);
};
// TEST_P(Copy, )

@ -0,0 +1,434 @@
#include <bencode.h>
#include <bencode.hpp>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
using TestBuffer = std::vector< byte_t >;
template < typename Result >
struct TestReadData
{
TestBuffer buffer;
bool rc;
Result result;
};
using TestReadInt = TestReadData< uint64_t >;
using TestReadString = TestReadData< std::string >;
template < typename Result >
std::ostream&
operator<<(std::ostream& os, const TestReadData< Result >& d)
{
os << "buf = [ ";
for(auto x : d.buffer)
{
os << x << " ";
}
os << "] rc = ";
os << std::boolalpha << d.rc << " result = " << d.result;
return os;
}
struct ReadInt : public ::testing::TestWithParam< TestReadInt >
{
};
TEST_P(ReadInt, readInt)
{
auto d = GetParam();
llarp_buffer_t buffer = llarp::Buffer(d.buffer);
uint64_t result = 0;
bool rc = bencode_read_integer(&buffer, &result);
EXPECT_EQ(rc, d.rc);
EXPECT_EQ(result, d.result);
}
static constexpr byte_t i = 'i';
static constexpr byte_t e = 'e';
static constexpr byte_t zero = '0';
static constexpr byte_t one = '1';
static constexpr byte_t two = '2';
static constexpr byte_t f = 'f';
static constexpr byte_t z = 'z';
static constexpr byte_t colon = ':';
static const TestReadInt testReadInt[] = {
// good cases
{{i, 0, e}, true, 0},
{{i, zero, e}, true, 0},
{{i, one, e}, true, 1},
{{i, two, e}, true, 2},
{{i, two, e, e, e}, true, 2},
{{i, one, one, one, two, e}, true, 1112},
{{i, f, e}, true, 0},
{{i, z, e}, true, 0},
{{i, one, two, e, one, one}, true, 12},
// failure cases
{{i, e}, false, 0},
{{e}, false, 0},
{{z}, false, 0},
};
INSTANTIATE_TEST_CASE_P(TestBencode, ReadInt, ::testing::ValuesIn(testReadInt));
struct ReadStr : public ::testing::TestWithParam< TestReadString >
{
};
TEST_P(ReadStr, readStr)
{
auto d = GetParam();
llarp_buffer_t buffer = llarp::Buffer(d.buffer);
llarp_buffer_t result;
bool rc = bencode_read_string(&buffer, &result);
EXPECT_EQ(rc, d.rc);
EXPECT_EQ(result.sz, d.result.size());
EXPECT_EQ(std::string(result.base, result.base + result.sz), d.result);
}
static const TestReadString testReadStr[] = {
// good cases
{{one, colon, 'a'}, true, "a"},
{{one, colon, 'b'}, true, "b"},
{{two, colon, f, z}, true, "fz"},
{{two, colon, f, z, f, f}, true, "fz"},
{{zero, colon}, true, ""},
// failure cases
{{two, colon, f}, false, ""},
{{two, f}, false, ""},
{{'-', one, colon, f}, false, ""},
{{f}, false, ""},
{{one, f, colon}, false, ""},
{{colon}, false, ""},
{{colon, colon}, false, ""},
};
INSTANTIATE_TEST_CASE_P(TestBencode, ReadStr, ::testing::ValuesIn(testReadStr));
template < typename Input >
struct TestWriteData
{
Input input;
size_t bufferSize;
bool rc;
std::string output;
};
using TestWriteByteString = TestWriteData< std::string >;
using TestWriteInt = TestWriteData< uint64_t >;
struct WriteByteStr : public ::testing::TestWithParam< TestWriteByteString >
{
};
TEST_P(WriteByteStr, writeByte)
{
auto d = GetParam();
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
llarp_buffer_t buffer = llarp::Buffer(backingBuffer);
bool rc = bencode_write_bytestring(&buffer, d.input.data(), d.input.size());
ASSERT_EQ(rc, d.rc);
ASSERT_EQ(std::string(buffer.base, buffer.cur), d.output);
}
static constexpr size_t MAX_1 =
static_cast< size_t >(std::numeric_limits< int16_t >::max()) + 1;
static const TestWriteByteString testWriteByteString[] = {
// good cases
{"abacus", 100, true, "6:abacus"},
{" abacus", 100, true, "8: abacus"},
{"", 100, true, "0:"},
{std::string("\0\0\0", 3), 100, true, std::string("3:\0\0\0", 5)},
{std::string(MAX_1, 'a'), MAX_1 + 100, true,
std::to_string(MAX_1) + std::string(":") + std::string(MAX_1, 'a')},
// bad cases
{"a", 1, false, ""},
};
INSTANTIATE_TEST_CASE_P(TestBencode, WriteByteStr,
::testing::ValuesIn(testWriteByteString));
struct WriteInt : public ::testing::TestWithParam< TestWriteInt >
{
};
TEST_P(WriteInt, writeInt)
{
auto d = GetParam();
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
llarp_buffer_t buffer = llarp::Buffer(backingBuffer);
bool rc = bencode_write_uint64(&buffer, d.input);
ASSERT_EQ(rc, d.rc);
ASSERT_EQ(std::string(buffer.base, buffer.cur), d.output);
}
static const TestWriteInt testWriteInt[] = {
// Good cases
{0, 100, true, "i0e"},
{1234, 100, true, "i1234e"},
{uint64_t(-1), 100, true, "i18446744073709551615e"},
// Bad cases
{1234567, 3, false, ""},
};
INSTANTIATE_TEST_CASE_P(TestBencode, WriteInt,
::testing::ValuesIn(testWriteInt));
struct WriteIntValues : public ::testing::TestWithParam< uint64_t >
{
};
TEST_P(WriteIntValues, anyvalue)
{
// test we can encode any uint64_t into a buffer.
uint64_t val = GetParam();
std::vector< byte_t > backingBuffer(100, 0);
llarp_buffer_t buffer = llarp::Buffer(backingBuffer);
bool rc = bencode_write_uint64(&buffer, val);
ASSERT_TRUE(rc);
uint64_t result = 0;
buffer = llarp::Buffer(backingBuffer);
rc = bencode_read_integer(&buffer, &result);
ASSERT_TRUE(rc);
ASSERT_EQ(result, val);
}
INSTANTIATE_TEST_CASE_P(
TestBencode, WriteIntValues,
::testing::Values(std::numeric_limits< uint64_t >::min(),
std::numeric_limits< uint64_t >::max(),
std::numeric_limits< uint64_t >::max() / 2,
std::numeric_limits< uint64_t >::max() / 3));
TEST(TestBencode, version)
{
std::vector< byte_t > backingBuffer(100, 0);
llarp_buffer_t buffer = llarp::Buffer(backingBuffer);
ASSERT_TRUE(bencode_write_version_entry(&buffer));
ASSERT_EQ(std::string(buffer.base, buffer.cur), "1:vi0e");
std::vector< byte_t > otherBuffer(1, 0);
buffer = llarp::Buffer(otherBuffer);
ASSERT_FALSE(bencode_write_version_entry(&buffer));
}
struct ValueData
{
// Variant-ish
std::string theString;
uint64_t theInt;
bool isString;
};
struct ListTestData
{
std::vector< ValueData > list;
size_t bufferSize;
std::string result;
};
struct ListTest : public ::testing::TestWithParam< ListTestData >
{
};
TEST_P(ListTest, list)
{
auto d = GetParam();
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
llarp_buffer_t buffer = llarp::Buffer(backingBuffer);
ASSERT_TRUE(bencode_start_list(&buffer));
for(const auto& x : d.list)
{
if(x.isString)
{
ASSERT_TRUE(bencode_write_bytestring(&buffer, x.theString.data(),
x.theString.size()));
}
else
{
ASSERT_TRUE(bencode_write_uint64(&buffer, x.theInt));
}
}
ASSERT_TRUE(bencode_end(&buffer));
ASSERT_EQ(std::string(buffer.base, buffer.cur), d.result);
}
ListTestData listTestData[] = {
{{}, 100, "le"},
{{{"", 0, true}}, 100, "l0:e"},
{{{"", 0, false}}, 100, "li0ee"},
{{{"", 0, false}, {"", 0, true}}, 100, "li0e0:e"},
{{{"", 123, false}, {"abc", 0, true}}, 100, "li123e3:abce"},
{{{"", 123, false}, {"abc", 0, true}, {"abc", 0, true}},
100,
"li123e3:abc3:abce"},
};
INSTANTIATE_TEST_CASE_P(TestBencode, ListTest,
::testing::ValuesIn(listTestData));
struct DictTestData
{
std::vector< std::pair< char, ValueData > > list;
size_t bufferSize;
std::string result;
};
struct DictTest : public ::testing::TestWithParam< DictTestData >
{
};
TEST_P(DictTest, dict)
{
auto d = GetParam();
std::vector< byte_t > backingBuffer(d.bufferSize, 0);
llarp_buffer_t buffer = llarp::Buffer(backingBuffer);
ASSERT_TRUE(bencode_start_dict(&buffer));
for(const auto& x : d.list)
{
ASSERT_TRUE(bencode_write_bytestring(&buffer, &x.first, 1));
if(x.second.isString)
{
ASSERT_TRUE(bencode_write_bytestring(&buffer, x.second.theString.data(),
x.second.theString.size()));
}
else
{
ASSERT_TRUE(bencode_write_uint64(&buffer, x.second.theInt));
}
}
ASSERT_TRUE(bencode_end(&buffer));
ASSERT_EQ(std::string(buffer.base, buffer.cur), d.result);
}
DictTestData dictTestData[] = {
{{}, 100, "de"},
{{{'a', {"", 0, true}}}, 100, "d1:a0:e"},
{{{'b', {"", 0, false}}}, 100, "d1:bi0ee"},
{{{'c', {"", 0, false}}, {'d', {"", 0, true}}}, 100, "d1:ci0e1:d0:e"},
{{{'e', {"", 123, false}}, {'f', {"abc", 0, true}}},
100,
"d1:ei123e1:f3:abce"},
{{{'a', {"", 123, false}},
{'b', {"abc", 0, true}},
{'c', {"abc", 0, true}}},
100,
"d1:ai123e1:b3:abc1:c3:abce"},
};
INSTANTIATE_TEST_CASE_P(TestBencode, DictTest,
::testing::ValuesIn(dictTestData));
struct ReadData
{
std::string input;
std::vector< std::string > output;
};
struct DictReadTest : public ::testing::TestWithParam< ReadData >
{
};
TEST_P(DictReadTest, readtest)
{
auto d = GetParam();
byte_t* input =
const_cast< byte_t* >(reinterpret_cast< const byte_t* >(d.input.data()));
llarp_buffer_t buffer(input, input, d.input.size());
std::vector< std::string > result;
dict_reader reader{nullptr, nullptr, [&](dict_reader*, llarp_buffer_t* buf) {
if(buf)
{
result.emplace_back(buf->base, buf->base + buf->sz);
}
return true;
}};
ASSERT_TRUE(bencode_read_dict(&buffer, &reader));
ASSERT_EQ(result, d.output);
}
ReadData dictReadData[] = {{"de", {}},
{"d1:a0:e", {"a", ""}},
{"d1:be", {"b"}},
{"d1:b2:23e", {"b", "23"}}};
INSTANTIATE_TEST_CASE_P(TestBencode, DictReadTest,
::testing::ValuesIn(dictReadData));
struct ListReadTest : public ::testing::TestWithParam< ReadData >
{
};
TEST_P(ListReadTest, readtest)
{
auto d = GetParam();
byte_t* input =
const_cast< byte_t* >(reinterpret_cast< const byte_t* >(d.input.data()));
llarp_buffer_t buffer(input, input, d.input.size());
std::vector< std::string > result;
list_reader reader{nullptr, nullptr, [&](list_reader* r, bool cont) {
if(cont)
{
auto b = r->buffer;
llarp_buffer_t tmp;
bencode_read_string(b, &tmp);
result.emplace_back(tmp.base, tmp.cur);
}
return true;
}};
ASSERT_TRUE(bencode_read_list(&buffer, &reader));
ASSERT_EQ(result, d.output);
}
ReadData listReadData[] = {
{"le", {}}, {"l1:ae", {"a"}}, {"l1:be", {"b"}}, {"l1:b2:23e", {"b", "23"}}};
INSTANTIATE_TEST_CASE_P(TestBencode, ListReadTest,
::testing::ValuesIn(listReadData));

@ -44,9 +44,11 @@
#define APPLE_UTUN "com.apple.net.utun_control"
#define UTUN_OPT_IFNAME 2
static int
tuntap_sys_start(struct device *dev, int, int)
int
tuntap_sys_start(struct device *dev, int mode, int tun)
{
(void)mode;
(void)tun;
uint32_t namesz = IFNAMSIZ;
char name[IFNAMSIZ + 1];
int fd;

Loading…
Cancel
Save