// Tests for authkit#14 PR 1 — role_templates schema contribution composes // correctly with the TemporalRepository decorator. #include "oatpp-authkit/db/RoleTemplateDb.hpp" #include "oatpp-authkit/dto/RoleTemplateDto.hpp" #include "oatpp-authkit/repo/ConcreteRoleTemplateRepository.hpp" #include "oatpp-authkit/repo/SchemaContract.hpp" #include "oatpp-authkit/repo/TemporalRepository.hpp" #include #include #include #include #define REQUIRE(cond) do { \ if (!(cond)) { std::fprintf(stderr, "REQUIRE failed: %s @ %s:%d\n", \ #cond, __FILE__, __LINE__); std::abort(); } } while (0) namespace { bool contains(const std::string& haystack, const std::string& needle) { return haystack.find(needle) != std::string::npos; } // SchemaBuilder> // emits the three tables + their indexes. Verify the composition. void test_role_templates_full_create() { using namespace oatpp_authkit::repo; using namespace oatpp_authkit::db; using namespace oatpp_authkit::dto; std::vector sqls; SqlExec exec = [&](const std::string& sql) { sqls.push_back(sql); }; SchemaBuilder< RoleTemplateSchema, TemporalRepository>::create("role_templates", exec); // Two sidecars (role_template_fields + user_role_assignments) + // one entity table + one entity_id index + one composite UNIQUE index // = 5 REQUIRE(sqls.size() == 5); // Sidecar 1: role_template_fields with composite FK REQUIRE(contains(sqls[0], "CREATE TABLE IF NOT EXISTS role_template_fields")); REQUIRE(contains(sqls[0], "template_id TEXT NOT NULL")); REQUIRE(contains(sqls[0], "template_valid_until TEXT NOT NULL DEFAULT '9999-12-31T23:59:59Z'")); REQUIRE(contains(sqls[0], "FOREIGN KEY (template_id, template_valid_until) REFERENCES " "role_templates(entity_id, valid_until) ON UPDATE CASCADE")); // Sidecar 2: user_role_assignments with composite FK REQUIRE(contains(sqls[1], "CREATE TABLE IF NOT EXISTS user_role_assignments")); REQUIRE(contains(sqls[1], "user_id TEXT NOT NULL")); REQUIRE(contains(sqls[1], "FOREIGN KEY (template_id, template_valid_until) REFERENCES " "role_templates(entity_id, valid_until) ON UPDATE CASCADE")); // Entity table: role_templates with all RoleTemplateSchema columns + // valid_until from TemporalRepository. REQUIRE(contains(sqls[2], "CREATE TABLE IF NOT EXISTS role_templates")); REQUIRE(contains(sqls[2], "id TEXT PRIMARY KEY")); REQUIRE(contains(sqls[2], "entity_id TEXT NOT NULL")); REQUIRE(contains(sqls[2], "name TEXT NOT NULL")); REQUIRE(contains(sqls[2], "is_system INTEGER NOT NULL DEFAULT 0")); REQUIRE(contains(sqls[2], "valid_from TEXT NOT NULL DEFAULT (datetime('now'))")); REQUIRE(contains(sqls[2], "valid_until TEXT NOT NULL DEFAULT '9999-12-31T23:59:59Z'")); // Indexes: ix_role_templates_entity_id (RoleTemplateSchema) // ux_role_templates_entity_valid_until (TemporalRepository) REQUIRE(contains(sqls[3], "CREATE INDEX IF NOT EXISTS ix_role_templates_entity_id")); REQUIRE(contains(sqls[3], "ON role_templates (entity_id)")); REQUIRE(contains(sqls[4], "CREATE UNIQUE INDEX IF NOT EXISTS ux_role_templates_entity_valid_until")); REQUIRE(contains(sqls[4], "ON role_templates (entity_id, valid_until)")); } // Verify that ConcreteRoleTemplateRepository contributes nothing to the // schema — RoleTemplateSchema owns the table declarations, the concrete // repo only adapts queries. Stacking the concrete repo into the builder // must not duplicate columns. void test_concrete_repo_contributes_no_schema() { using namespace oatpp_authkit::repo; using namespace oatpp_authkit::db; using namespace oatpp_authkit::dto; std::vector sqls_with; std::vector sqls_without; SchemaBuilder< RoleTemplateSchema, ConcreteRoleTemplateRepository, TemporalRepository>::create( "role_templates", [&](const std::string& s){ sqls_with.push_back(s); }); SchemaBuilder< RoleTemplateSchema, TemporalRepository>::create( "role_templates", [&](const std::string& s){ sqls_without.push_back(s); }); // Including ConcreteRoleTemplateRepository in the pack changes nothing // — empty kSchema contributes no DDL. REQUIRE(sqls_with == sqls_without); } } // namespace int main() { test_role_templates_full_create(); test_concrete_repo_contributes_no_schema(); std::printf("test_role_template_schema: OK\n"); return 0; }