365 lines
13 KiB
C++
365 lines
13 KiB
C++
/*
|
|
* Copyright 2015 - 2024 gary@drinkingtea.net
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#undef NDEBUG
|
|
|
|
#include <map>
|
|
|
|
#include <ox/model/model.hpp>
|
|
#include <ox/oc/oc.hpp>
|
|
#include <ox/std/std.hpp>
|
|
|
|
template<typename T>
|
|
union U {
|
|
T t;
|
|
int i;
|
|
};
|
|
|
|
U<short> u;
|
|
|
|
union TestUnion {
|
|
static constexpr auto TypeName = "TestUnion";
|
|
static constexpr auto TypeVersion = 1;
|
|
bool Bool;
|
|
uint32_t Int = 5;
|
|
char *String;
|
|
};
|
|
|
|
struct TestStructNest {
|
|
static constexpr auto TypeName = "TestStructNest";
|
|
static constexpr auto TypeVersion = 1;
|
|
bool Bool = false;
|
|
uint32_t Int = 0;
|
|
ox::IString<32> String = "";
|
|
};
|
|
|
|
struct TestStruct {
|
|
static constexpr auto TypeName = "TestStruct";
|
|
static constexpr auto TypeVersion = 1;
|
|
bool Bool = false;
|
|
int32_t Int = 0;
|
|
int32_t Int1 = 0;
|
|
int32_t Int2 = 0;
|
|
int32_t Int3 = 0;
|
|
int32_t Int4 = 0;
|
|
int32_t Int5 = 0;
|
|
int32_t Int6 = 0;
|
|
int32_t Int7 = 0;
|
|
int32_t Int8 = 0;
|
|
int unionIdx = 1;
|
|
TestUnion Union;
|
|
ox::String String{""};
|
|
uint32_t List[4] = {0, 0, 0, 0};
|
|
ox::HashMap<ox::String, int> Map;
|
|
TestStructNest EmptyStruct;
|
|
TestStructNest Struct;
|
|
|
|
TestStruct() noexcept = default;
|
|
|
|
TestStruct(TestStruct &&other) noexcept;
|
|
|
|
constexpr ~TestStruct() noexcept {
|
|
if (unionIdx == 2) {
|
|
ox::safeDelete(Union.String);
|
|
}
|
|
}
|
|
|
|
constexpr TestStruct &operator=(TestStruct&&) noexcept;
|
|
|
|
};
|
|
|
|
constexpr ox::Error model(auto *io, ox::CommonPtrWith<TestUnion> auto *obj) noexcept {
|
|
OX_RETURN_ERROR(io->template setTypeInfo<TestUnion>());
|
|
OX_RETURN_ERROR(io->field("Bool", &obj->Bool));
|
|
OX_RETURN_ERROR(io->field("Int", &obj->Int));
|
|
OX_RETURN_ERROR(io->fieldCString("String", &obj->String));
|
|
return ox::Error(0);
|
|
}
|
|
|
|
constexpr ox::Error model(auto *io, ox::CommonPtrWith<TestStructNest> auto *obj) noexcept {
|
|
OX_RETURN_ERROR(io->template setTypeInfo<TestStructNest>());
|
|
OX_RETURN_ERROR(io->field("Bool", &obj->Bool));
|
|
OX_RETURN_ERROR(io->field("Int", &obj->Int));
|
|
OX_RETURN_ERROR(io->field("String", &obj->String));
|
|
return ox::Error(0);
|
|
}
|
|
|
|
constexpr ox::Error model(auto *io, ox::CommonPtrWith<TestStruct> auto *obj) noexcept {
|
|
OX_RETURN_ERROR(io->template setTypeInfo<TestStruct>());
|
|
OX_RETURN_ERROR(io->field("Bool", &obj->Bool));
|
|
OX_RETURN_ERROR(io->field("Int", &obj->Int));
|
|
OX_RETURN_ERROR(io->field("Int1", &obj->Int1));
|
|
OX_RETURN_ERROR(io->field("Int2", &obj->Int2));
|
|
OX_RETURN_ERROR(io->field("Int3", &obj->Int3));
|
|
OX_RETURN_ERROR(io->field("Int4", &obj->Int4));
|
|
OX_RETURN_ERROR(io->field("Int5", &obj->Int5));
|
|
OX_RETURN_ERROR(io->field("Int6", &obj->Int6));
|
|
OX_RETURN_ERROR(io->field("Int7", &obj->Int7));
|
|
OX_RETURN_ERROR(io->field("Int8", &obj->Int8));
|
|
OX_RETURN_ERROR(io->field("unionIdx", &obj->unionIdx));
|
|
if (io->opType() == ox::OpType::Reflect) {
|
|
OX_RETURN_ERROR(io->field("Union", ox::UnionView{&obj->Union, 0}));
|
|
} else {
|
|
OX_RETURN_ERROR(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx}));
|
|
}
|
|
OX_RETURN_ERROR(io->field("String", &obj->String));
|
|
OX_RETURN_ERROR(io->field("List", obj->List, 4));
|
|
OX_RETURN_ERROR(io->field("Map", &obj->Map));
|
|
OX_RETURN_ERROR(io->field("EmptyStruct", &obj->EmptyStruct));
|
|
OX_RETURN_ERROR(io->field("Struct", &obj->Struct));
|
|
return ox::Error(0);
|
|
}
|
|
|
|
TestStruct::TestStruct(TestStruct &&other) noexcept {
|
|
ox::moveModel(this, &other);
|
|
}
|
|
|
|
constexpr TestStruct &TestStruct::operator=(TestStruct &&other) noexcept {
|
|
ox::moveModel(this, &other);
|
|
return *this;
|
|
}
|
|
|
|
const std::map<ox::StringView, ox::Error(*)()> tests = {
|
|
{
|
|
{
|
|
"OrganicClawWriter",
|
|
[] {
|
|
// This test doesn't confirm much, but it does show that the writer
|
|
// doesn't segfault
|
|
TestStruct ts;
|
|
return ox::writeOC(ts).error;
|
|
}
|
|
},
|
|
{
|
|
"OrganicClawReader",
|
|
[] {
|
|
TestStruct testIn;
|
|
testIn.Bool = true;
|
|
testIn.Int = 42;
|
|
testIn.Union.Int = 52;
|
|
testIn.String = "Test String 1";
|
|
testIn.List[0] = 1;
|
|
testIn.List[1] = 2;
|
|
testIn.List[2] = 3;
|
|
testIn.List[3] = 4;
|
|
testIn.Map["asdf"] = 93;
|
|
testIn.Map["aoeu"] = 94;
|
|
testIn.Struct.Bool = false;
|
|
testIn.Struct.Int = 300;
|
|
testIn.Struct.String = "Test String 2";
|
|
|
|
auto [oc, writeErr] = ox::writeOC(testIn);
|
|
oxAssert(writeErr, "writeOC failed");
|
|
oxOutf("{}\n", oc.data());
|
|
auto [testOut, readErr] = ox::readOC<TestStruct>(oc.data());
|
|
oxAssert(readErr, "readOC failed");
|
|
|
|
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
|
|
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
|
|
oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch");
|
|
oxAssert(testIn.Int2 == testOut.Int2, "Int2 value mismatch");
|
|
oxAssert(testIn.Int3 == testOut.Int3, "Int3 value mismatch");
|
|
oxAssert(testIn.Int4 == testOut.Int4, "Int4 value mismatch");
|
|
oxAssert(testIn.Int5 == testOut.Int5, "Int5 value mismatch");
|
|
oxAssert(testIn.Int6 == testOut.Int6, "Int6 value mismatch");
|
|
oxAssert(testIn.Int7 == testOut.Int7, "Int7 value mismatch");
|
|
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
|
|
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
|
|
oxAssert(testIn.String == testOut.String, "String value mismatch");
|
|
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
|
|
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
|
|
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
|
|
oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch");
|
|
oxAssert(testIn.Map["asdf"] == testOut.Map["asdf"], "Map[\"asdf\"] value mismatch");
|
|
oxAssert(testIn.Map["aoeu"] == testOut.Map["aoeu"], "Map[\"aoeu\"] value mismatch");
|
|
oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
|
|
oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch");
|
|
oxAssert(testIn.EmptyStruct.String == testOut.EmptyStruct.String, "EmptyStruct.String value mismatch");
|
|
oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch");
|
|
oxAssert(testIn.Struct.String == testOut.Struct.String, "Struct.String value mismatch");
|
|
oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch");
|
|
|
|
return ox::Error(0);
|
|
}
|
|
},
|
|
|
|
{
|
|
"OrganicClawModelValue",
|
|
[] {
|
|
ox::Buffer dataBuff;
|
|
TestStruct testIn;
|
|
testIn.Bool = true;
|
|
testIn.Int = 42;
|
|
testIn.String = "Test String 1";
|
|
testIn.List[0] = 1;
|
|
testIn.List[1] = 2;
|
|
testIn.List[2] = 3;
|
|
testIn.List[3] = 4;
|
|
testIn.Struct.Bool = false;
|
|
testIn.Struct.Int = 300;
|
|
testIn.Struct.String = "Test String 2";
|
|
testIn.unionIdx = 1;
|
|
testIn.Union.Int = 93;
|
|
oxAssert(ox::writeOC(testIn).moveTo(dataBuff), "Data generation failed");
|
|
ox::TypeStore typeStore;
|
|
auto type = ox::buildTypeDef(typeStore, testIn);
|
|
oxAssert(type.error, "Descriptor write failed");
|
|
ox::ModelObject testOut;
|
|
OX_RETURN_ERROR(testOut.setType(type.value));
|
|
oxAssert(ox::readOC(dataBuff, testOut), "Data read failed");
|
|
oxAssert(testOut.get("Int").unwrap()->get<int>() == testIn.Int, "testOut.Int failed");
|
|
oxAssert(testOut.get("Bool").unwrap()->get<bool>() == testIn.Bool, "testOut.Bool failed");
|
|
oxAssert(testOut.get("String").unwrap()->get<ox::String>() == testIn.String, "testOut.String failed");
|
|
auto &testOutStruct = testOut.get("Struct").unwrap()->get<ox::ModelObject>();
|
|
auto &testOutUnion = testOut.get("Union").unwrap()->get<ox::ModelUnion>();
|
|
auto &testOutList = testOut.get("List").unwrap()->get<ox::ModelValueVector>();
|
|
auto testOutStructCopy = testOut.get("Struct").unwrap()->get<ox::ModelObject>();
|
|
auto testOutUnionCopy = testOut.get("Union").unwrap()->get<ox::ModelUnion>();
|
|
auto testOutListCopy = testOut.get("List").unwrap()->get<ox::ModelValueVector>();
|
|
oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed");
|
|
oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed");
|
|
oxAssert(testOutStruct.get("Bool").unwrap()->get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool failed");
|
|
oxAssert(testOutStruct.get("String").unwrap()->get<ox::String>() == testIn.Struct.String.c_str(), "testOut.Struct.String failed");
|
|
oxAssert(testOut.get("unionIdx").unwrap()->get<int>() == testIn.unionIdx, "testOut.unionIdx failed");
|
|
oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong");
|
|
oxAssert(testOutUnion.get("Int").unwrap()->get<uint32_t>() == testIn.Union.Int, "testOut.Union.Int failed");
|
|
oxAssert(testOutList[0].get<uint32_t>() == testIn.List[0], "testOut.List[0] failed");
|
|
oxAssert(testOutList[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] failed");
|
|
oxAssert(testOutStructCopy.get("Bool").unwrap()->get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed");
|
|
oxAssert(testOutStructCopy.get("String").unwrap()->get<ox::String>() == testIn.Struct.String.c_str(), "testOut.Struct.String (copy) failed");
|
|
oxAssert(testOutListCopy[0].get<uint32_t>() == testIn.List[0], "testOut.Struct.List[0] (copy) failed");
|
|
oxAssert(testOutListCopy[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] (copy) failed");
|
|
return ox::Error(0);
|
|
}
|
|
},
|
|
|
|
{
|
|
"OrganicClawDef",
|
|
[] {
|
|
TestStruct testIn, testOut;
|
|
|
|
testIn.Bool = true;
|
|
testIn.Int = 42;
|
|
testIn.String = "Test String 1";
|
|
testIn.List[0] = 1;
|
|
testIn.List[1] = 2;
|
|
testIn.List[2] = 3;
|
|
testIn.List[3] = 4;
|
|
testIn.Struct.Bool = false;
|
|
testIn.Struct.Int = 300;
|
|
testIn.Struct.String = "Test String 2";
|
|
|
|
auto [oc, ocErr] = ox::writeOC(testIn);
|
|
oxAssert(ocErr, "Data generation failed");
|
|
ox::TypeStore typeStore;
|
|
auto type = ox::buildTypeDef(typeStore, testIn);
|
|
oxAssert(type.error, "Descriptor write failed");
|
|
OX_RETURN_ERROR(ox::walkModel<ox::OrganicClawReader>(type.value, oc.data(), oc.size(),
|
|
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::String>&, const ox::DescriptorField &f,
|
|
ox::OrganicClawReader *rdr) -> ox::Error {
|
|
auto fieldName = f.fieldName.c_str();
|
|
switch (f.type->primitiveType) {
|
|
case ox::PrimitiveType::UnsignedInteger:
|
|
oxOutf("{}:\tuint{}_t:\t", fieldName, f.type->length * 8);
|
|
switch (f.type->length) {
|
|
case 1: {
|
|
uint8_t i = {};
|
|
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
|
oxOutf("{}", i);
|
|
break;
|
|
}
|
|
case 2: {
|
|
uint16_t i = {};
|
|
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
|
oxOutf("{}", i);
|
|
break;
|
|
}
|
|
case 4: {
|
|
uint32_t i = {};
|
|
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
|
oxOutf("{}", i);
|
|
break;
|
|
}
|
|
case 8: {
|
|
uint64_t i = {};
|
|
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
|
oxOutf("{}", i);
|
|
break;
|
|
}
|
|
}
|
|
oxOut("\n");
|
|
break;
|
|
case ox::PrimitiveType::SignedInteger:
|
|
oxOutf("{}:\tint{}_t:\t", fieldName, f.type->length * 8);
|
|
switch (f.type->length) {
|
|
case 1: {
|
|
int8_t i = {};
|
|
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
|
oxOutf("{}", i);
|
|
break;
|
|
}
|
|
case 2: {
|
|
int16_t i = {};
|
|
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
|
oxOutf("{}", i);
|
|
break;
|
|
}
|
|
case 4: {
|
|
int32_t i = {};
|
|
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
|
oxOutf("{}", i);
|
|
break;
|
|
}
|
|
case 8: {
|
|
int64_t i = {};
|
|
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
|
oxOutf("{}", i);
|
|
break;
|
|
}
|
|
}
|
|
oxOut("\n");
|
|
break;
|
|
case ox::PrimitiveType::Bool: {
|
|
bool i = {};
|
|
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
|
oxOutf("{}:\tbool:\t{}\n", fieldName, i ? "true" : "false");
|
|
break;
|
|
}
|
|
case ox::PrimitiveType::String: {
|
|
ox::Vector<char> v(rdr->stringLength(fieldName) + 1);
|
|
oxAssert(rdr->fieldCString(fieldName, v.data(), v.size()), "Walking model failed.");
|
|
oxOutf("{}:\tstring:\t{}\n", fieldName, v.data());
|
|
break;
|
|
}
|
|
case ox::PrimitiveType::Struct:
|
|
break;
|
|
case ox::PrimitiveType::Union:
|
|
break;
|
|
}
|
|
return ox::Error(0);
|
|
}
|
|
));
|
|
return ox::Error(0);
|
|
}
|
|
},
|
|
}
|
|
};
|
|
|
|
int main(int argc, const char **args) {
|
|
if (argc < 2) {
|
|
oxError("Must specify test to run");
|
|
}
|
|
auto const testName = args[1];
|
|
auto const func = tests.find(testName);
|
|
if (func != tests.end()) {
|
|
oxAssert(func->second(), "Test returned Error");
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|