Skip to content

Commit

Permalink
more element tests
Browse files Browse the repository at this point in the history
  • Loading branch information
voivoid committed Apr 6, 2017
1 parent 9a1656c commit da3c807
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 92 deletions.
12 changes: 12 additions & 0 deletions inc/Bson/Details/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <vector>
#include <iterator>
#include <string>

namespace Bson
{
Expand All @@ -23,4 +24,15 @@ using Bytes = std::vector<Byte>;
using Istream = std::basic_istream<Byte>;
using Ostream = std::basic_ostream<Byte>;

using String = std::string;

struct CString
{
bool operator==(const CString& rhs) const { return s == rhs.s; }
std::string s;
};

struct True{ bool operator==(const True&) const { return true; }};
struct False{ bool operator==(const False&) const { return true; }};

} // namespace Bson
45 changes: 23 additions & 22 deletions inc/Bson/Details/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,45 @@
#include <cstdint>
#include <string>
#include <vector>
#include <type_traits>

#include <boost/variant.hpp>
#include <boost/hana/map.hpp>

namespace Bson
{

template <typename T>
T read(Istream& stream);

template <typename T>
void write(T value, Ostream& stream);

std::string readCString(Istream& stream);
std::string readString(Istream& stream);

void writeCString(const std::string& string, Ostream& stream);
void writeString(const std::string& string, Ostream& stream);

struct True {};
struct False {};

struct Element
{
static constexpr auto TypeInfoMap = boost::hana::make_map(boost::hana::make_pair(boost::hana::type_c<Double>, 0x01),
boost::hana::make_pair(boost::hana::type_c<Int32>, 0x10));
boost::hana::make_pair(boost::hana::type_c<String>, 0x02),
boost::hana::make_pair(boost::hana::type_c<False>, 0x08),
boost::hana::make_pair(boost::hana::type_c<True>, 0x09),
boost::hana::make_pair(boost::hana::type_c<Int32>, 0x10),
boost::hana::make_pair(boost::hana::type_c<Uint64>, 0x11),
boost::hana::make_pair(boost::hana::type_c<Int64>, 0x12),
boost::hana::make_pair(boost::hana::type_c<Decimal>, 0x13));
using Value = decltype(boost::hana::unpack(boost::hana::keys(TypeInfoMap), boost::hana::template_<boost::variant>))::type;

std::string name;
bool operator==(const Element& rhs) const { return name == rhs.name && value == rhs.value; }

CString name;
Value value;
};

Element readElement(Istream& stream);
void writeElement(const Element& element, Ostream& stream);

using List = std::vector<Element>;
List readList(Istream& stream);
void writeList(const List& list, Ostream& stream);

template <typename T>
T read(Istream& stream);

template <typename T>
typename std::enable_if_t<std::is_pod<T>::value> write(T value, Ostream& stream);
void write(const String& string, Ostream& stream);
void write(True, Ostream& stream);
void write(False, Ostream& stream);
void write(const CString& string, Ostream& stream);
void write(const Element& element, Ostream& stream);
void write(const List& list, Ostream& stream);


} // namespace Bson
109 changes: 69 additions & 40 deletions src/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,35 @@ namespace

const size_t MaxCStringBuff = 16384;

template <typename T, T(*f)(Istream&)>
Element::Value adapt(Istream& stream)
{
return {f(stream)};
}

using Reader = Element::Value(*)(Istream&);

struct GetElementIndexVisitor : boost::static_visitor<size_t> {
struct GetElementIndexVisitor : boost::static_visitor<Byte> {
template <typename T>
size_t operator()(const T&) const
Byte operator()(const T&) const
{
return 0;
return Element::TypeInfoMap[boost::hana::type_c<T>];
}
};

struct WriteElementVisitor : boost::static_visitor<void> {

WriteElementVisitor(Ostream& stream) : stream(stream) {}

template <typename T>
void operator()(const T& value) const
{
write<T>(value, stream);
write(value, stream);
}

private:
Ostream& stream;
};

template <typename T, T(*reader)(Istream&)>
Element::Value adaptReader(Istream& stream)
{
return {reader(stream)};
}

using Reader = Element::Value(*)(Istream&);

}

const auto IndexToReaderMap = boost::hana::fold_left(Element::TypeInfoMap, std::map<int, Reader>{}, [](auto map, const auto pair) {
Expand All @@ -54,26 +53,27 @@ const auto IndexToReaderMap = boost::hana::fold_left(Element::TypeInfoMap, std::

using Type = typename decltype(type)::type;

map[index] = &adapt<Type, &read<Type>>;
map[index] = &adaptReader<Type, &read<Type>>;

return map;
});



// TODO: handle endianness

template <typename T>
T read(Istream& stream)
{
static_assert(std::is_pod<T>::value);

T value;
stream.read(reinterpret_cast<Byte*>(&value), sizeof(value));
return value;
}

template <typename T>
void write(const T value, Ostream& stream)
typename std::enable_if_t<std::is_pod<T>::value> write(const T value, Ostream& stream)
{
static_assert(std::is_pod<T>::value);
stream.write(reinterpret_cast<const Byte*>(&value), sizeof(value));
}

Expand All @@ -88,45 +88,55 @@ BSON_INSTANTIATE_FUNCS(Uint64);
BSON_INSTANTIATE_FUNCS(Double);
BSON_INSTANTIATE_FUNCS(Decimal);

std::string readCString(Istream& stream)
{
Byte buff[MaxCStringBuff];
stream.getline(buff, MaxCStringBuff, 0);

return std::string(reinterpret_cast<char*>(buff));
}

std::string readString(Istream& stream)
template <>
String read(Istream& stream)
{
Int32 strLen = read<Int32>(stream);

assert(strLen > 0);

std::string s;
s.resize(strLen - 1);
String s;
s.resize(static_cast<size_t>(strLen) - 1);
stream.read(reinterpret_cast<Byte*>(&s[0]), strLen - 1);
stream.ignore(1);

return s;
}

void writeCString(const std::string& string, Ostream& stream)
template <>
CString read(Istream& stream)
{
stream.write(reinterpret_cast<const Byte*>(string.c_str()), string.length() + 1);
Byte buff[MaxCStringBuff];
stream.getline(buff, MaxCStringBuff, 0);

return {String(reinterpret_cast<char*>(buff))};
}

void writeString(const std::string& string, Ostream& stream)
template <>
False read(Istream& stream)
{
write(static_cast<Int32>(string.length() + 1), stream);
writeCString(string, stream);
const auto byte = read<Byte>(stream);
assert(byte == 0x00);

return {};
}

Element readElement(Istream& stream)
template <>
True read(Istream& stream)
{
const auto byte = read<Byte>(stream);
assert(byte == 0x01);

return {};
}

template <>
Element read(Istream& stream)
{
const auto elementTypeIdx = read<Byte>(stream);
const auto reader = IndexToReaderMap.at(elementTypeIdx);

auto name = readCString(stream);
auto name = read<CString>(stream);

Element elem;
elem.name = std::move(name);
Expand All @@ -135,13 +145,32 @@ Element readElement(Istream& stream)
return elem;
}

void writeElement(const Element& element, Ostream& stream)
void write(const String& string, Ostream& stream)
{
const size_t index = boost::apply_visitor(GetElementIndexVisitor{}, element.value);
assert(index <= 255);
write<Byte>(index, stream);
write(static_cast<Int32>(string.length() + 1), stream);
stream.write(reinterpret_cast<const Byte*>(string.c_str()), string.length() + 1);
}

writeCString(element.name, stream);
void write(const CString& string, Ostream& stream)
{
stream.write(reinterpret_cast<const Byte*>(string.s.c_str()), string.s.length() + 1);
}

void write(True, Ostream& stream)
{
write<Byte>(0x01, stream);
}

void write(False, Ostream& stream)
{
write<Byte>(0x00, stream);
}

void write(const Element& element, Ostream& stream)
{
const Byte index = boost::apply_visitor(GetElementIndexVisitor{}, element.value);
write<Byte>(index, stream);
write(element.name, stream);

boost::apply_visitor(WriteElementVisitor{stream}, element.value);
}
Expand Down
66 changes: 36 additions & 30 deletions test/test-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,49 +11,43 @@
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>

template <typename T, typename WriteFunc, typename ReadFunc>
bool testMemory(const T& value, size_t buffSize, WriteFunc write, ReadFunc read)
template <typename T>
size_t getValueSize(const T&)
{
//TODO : calc size
return 1024;
}

template <typename T>
bool testMemory(const T& value)
{
std::vector<Bson::Byte> data(buffSize, 0);
std::vector<Bson::Byte> data(getValueSize(value), 0);

boost::iostreams::basic_array<Bson::Byte> arr(data.data(), data.size());
boost::iostreams::stream<boost::iostreams::basic_array<Bson::Byte>> istream(arr);
boost::iostreams::stream<boost::iostreams::basic_array<Bson::Byte>> ostream(arr);

write(value, ostream);
const auto result = read(istream);
Bson::write(value, ostream);
const auto result = Bson::read<T>(istream);

return result == value;
}

template <typename T, typename WriteFunc, typename ReadFunc>
bool testStream(T val, WriteFunc write, ReadFunc read)
template <typename T>
bool testStream(const T& val)
{
std::basic_stringstream<Bson::Byte> ss(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
write(val, ss);
const auto result = read(ss);
Bson::write(val, ss);
const auto result = Bson::read<T>(ss);

return val == result;
}

template <typename T>
void test(T value)
{
assert(testMemory(value, sizeof(value), Bson::write<T>, Bson::read<T>));
assert(testStream(value, Bson::write<T>, Bson::read<T>));
}

void testString(const std::string& value)
{
assert(testMemory(value, value.length() + sizeof(Bson::Int32) + 1, Bson::writeString, Bson::readString));
assert(testStream(value, Bson::writeString, Bson::readString));
}

void test(const std::string& value)
void test(const T& value)
{
assert(testMemory(value, value.length() + 1, Bson::writeCString, Bson::readCString));
assert(testStream(value, Bson::writeCString, Bson::readCString));
testString(value);
assert(testMemory(value));
assert(testStream(value));
}

int main() {
Expand All @@ -69,7 +63,7 @@ int main() {
test<Bson::Int32>(42);
test<Bson::Int32>(-42);
test<Bson::Int32>(0x01020304);
test<Bson::Int32>(0xff0000ff);
test<Bson::Int32>(0x00ff00ff);
test<Bson::Int32>(std::numeric_limits<Bson::Int32>::min());
test<Bson::Int32>(std::numeric_limits<Bson::Int32>::max());

Expand Down Expand Up @@ -105,10 +99,22 @@ int main() {
test<Bson::Decimal>(std::numeric_limits<Bson::Decimal>::min());
test<Bson::Decimal>(std::numeric_limits<Bson::Decimal>::max());

test(std::string(""));
test(std::string("hello"));
test(std::string("hello world"));
testString(std::string("hello\0world", 11));
test(Bson::CString{{""}});
test(Bson::CString{{"hello"}});
test(Bson::CString{{"hello world"}});
test(Bson::String(""));
test(Bson::String("hello"));
test(Bson::String("hello world"));
test(Bson::String("hello\0world", 11));

test(Bson::Element{{"test double"}, Bson::Double{42.0}});
test(Bson::Element{{"test string"}, Bson::String{"Hello world"}});
test(Bson::Element{{"test true"}, Bson::True{}});
test(Bson::Element{{"test false"}, Bson::False{}});
test(Bson::Element{{"test int32"}, Bson::Int32{42}});
test(Bson::Element{{"test uint64"}, Bson::Uint64{42}});
test(Bson::Element{{"test int64"}, Bson::Int64{42}});
test(Bson::Element{{"test Decimal"}, Bson::Decimal{42.0}});

return 0;
}

0 comments on commit da3c807

Please sign in to comment.