Files
EVEngine/test/schema.cpp
T

88 lines
3.4 KiB
C++

#include "zeroerr/assert.h"
#include "zeroerr/unittest.h"
#include "schema/Schema.h"
#include "schema/SchemaRegistry.h"
#include <simplesquirrel/simplesquirrel.hpp>
using namespace eve::schema;
namespace {
const char* unitSchema = R"({
"id":"unit", "version":2, "title":"Unit", "additionalProperties":false,
"fields":[
{"name":"id", "type":"string", "required":true, "minLength":1},
{"name":"speed", "type":"number", "minimum":0, "maximum":100},
{"name":"role", "type":"string", "enum":["tank","infantry"]},
{"name":"weapons", "type":"array", "elementType":"string", "reference":"weapon"}
]
})";
} // namespace
TEST_CASE("schema.registry.metadataAndStableEnumeration") {
SchemaRegistry::clear();
std::string error;
CHECK(SchemaRegistry::registerFromJson(unitSchema, &error));
CHECK(error.empty());
CHECK(SchemaRegistry::registerFromJson(R"({"id":"ability","version":1})"));
CHECK_EQ(SchemaRegistry::count(), 2);
CHECK_EQ(SchemaRegistry::ids()[0], "ability");
const auto* schema = SchemaRegistry::find("unit");
REQUIRE(schema != nullptr);
CHECK_EQ(schema->version, 2);
CHECK_EQ(schema->fields.size(), size_t(4));
CHECK(schema->fields[0].required);
CHECK_EQ(schema->fields[3].reference, "weapon");
}
TEST_CASE("schema.registry.rejectsMalformedDefinitions") {
SchemaRegistry::clear();
std::string error;
CHECK(!SchemaRegistry::registerFromJson(R"({"id":"","version":1})", &error));
CHECK(!error.empty());
CHECK(!SchemaRegistry::registerFromJson(R"({"id":"bad","fields":[{"name":"x","type":"mystery"}]})", &error));
CHECK(!SchemaRegistry::registerFromJson(R"({"id":"duplicate","fields":[{"name":"x"},{"name":"x"}]})", &error));
CHECK_EQ(SchemaRegistry::count(), 0);
}
TEST_CASE("schema.validation.returnsStructuredErrors") {
SchemaRegistry::clear();
REQUIRE(SchemaRegistry::registerFromJson(unitSchema));
const auto valid =
SchemaRegistry::validate("unit", R"({"id":"heavy_tank","speed":42,"role":"tank","weapons":["cannon"]})");
CHECK(valid.empty());
const auto errors =
SchemaRegistry::validate("unit", R"({"speed":120,"role":"scout","weapons":["gun",3],"extra":true})");
CHECK_EQ(errors.size(), size_t(5));
CHECK_EQ(errors[0].path, "/id");
CHECK_EQ(errors[0].code, "required");
CHECK_EQ(errors[1].code, "maximum");
CHECK_EQ(errors[2].code, "enum");
CHECK_EQ(errors[3].path, "/weapons/1");
CHECK_EQ(errors[4].code, "additional_property");
}
TEST_CASE("schema.module.scriptBinding") {
SchemaRegistry::clear();
ssq::VM vm(1024, ssq::Libs::ALL);
eve::ModuleManager::expose(vm);
auto script = vm.compileSource(R"(
function schemaBindingTest() {
local s = eve.Schema();
s.clear();
if (!s.registerJson(@"{""id"":""rank"",""version"":3,""fields"":[{""name"":""level"",""type"":""integer"",""required"":true}]}")) return false;
if (s.getSchemaId(0) != "rank" || s.getSchemaVersion("rank") != 3) return false;
if (s.getFieldName("rank", 0) != "level" || !s.getFieldRequired("rank", 0)) return false;
if (!s.validateJson("rank", @"{""level"":2}")) return false;
if (s.validateJson("rank", @"{""level"":2.5}")) return false;
return s.getValidationErrorCode(0) == "type";
}
)");
vm.run(script);
CHECK(vm.callFunc(vm.findFunc("schemaBindingTest"), vm).toBool());
}