167 lines
7.9 KiB
C++
167 lines
7.9 KiB
C++
|
|
// Step 477: Architecture Templates Tests (12 tests)
|
||
|
|
|
||
|
|
#include "ArchitectTemplates.h"
|
||
|
|
|
||
|
|
#include <iostream>
|
||
|
|
|
||
|
|
static int passed = 0, failed = 0;
|
||
|
|
#define TEST(name) { std::cout << " " << #name << "... "; }
|
||
|
|
#define PASS() { std::cout << "PASS\n"; ++passed; }
|
||
|
|
#define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; }
|
||
|
|
#define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } else {}
|
||
|
|
|
||
|
|
static TemplateInput sampleInput() {
|
||
|
|
TemplateInput in;
|
||
|
|
in.projectName = "bookstore";
|
||
|
|
in.primaryEntity = "Book";
|
||
|
|
in.fields = {"id", "title", "author"};
|
||
|
|
in.authMethod = "jwt";
|
||
|
|
return in;
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_rest_api_template_contains_expected_modules() {
|
||
|
|
TEST(rest_api_template_contains_expected_modules);
|
||
|
|
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
|
||
|
|
CHECK(out.skeleton.hasModule("routes"), "missing routes");
|
||
|
|
CHECK(out.skeleton.hasModule("handlers"), "missing handlers");
|
||
|
|
CHECK(out.skeleton.hasModule("models"), "missing models");
|
||
|
|
CHECK(out.skeleton.hasModule("middleware"), "missing middleware");
|
||
|
|
CHECK(out.skeleton.hasModule("database"), "missing database");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_cli_template_contains_cli_command_output_modules() {
|
||
|
|
TEST(cli_template_contains_cli_command_output_modules);
|
||
|
|
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::CliTool, sampleInput());
|
||
|
|
CHECK(out.skeleton.hasModule("cli"), "missing cli");
|
||
|
|
CHECK(out.skeleton.hasModule("commands"), "missing commands");
|
||
|
|
CHECK(out.skeleton.hasModule("output"), "missing output");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_library_template_contains_api_internal_tests_docs() {
|
||
|
|
TEST(library_template_contains_api_internal_tests_docs);
|
||
|
|
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::Library, sampleInput());
|
||
|
|
CHECK(out.skeleton.hasModule("public_api"), "missing public_api");
|
||
|
|
CHECK(out.skeleton.hasModule("internal"), "missing internal");
|
||
|
|
CHECK(out.skeleton.hasModule("tests"), "missing tests");
|
||
|
|
CHECK(out.skeleton.hasModule("docs"), "missing docs");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_microservice_template_contains_service_transport_storage_health() {
|
||
|
|
TEST(microservice_template_contains_service_transport_storage_health);
|
||
|
|
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::Microservice, sampleInput());
|
||
|
|
CHECK(out.skeleton.hasModule("service"), "missing service");
|
||
|
|
CHECK(out.skeleton.hasModule("transport"), "missing transport");
|
||
|
|
CHECK(out.skeleton.hasModule("storage"), "missing storage");
|
||
|
|
CHECK(out.skeleton.hasModule("health"), "missing health");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_fullstack_template_contains_frontend_backend_database_deploy() {
|
||
|
|
TEST(fullstack_template_contains_frontend_backend_database_deploy);
|
||
|
|
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::FullStack, sampleInput());
|
||
|
|
CHECK(out.skeleton.hasModule("frontend"), "missing frontend");
|
||
|
|
CHECK(out.skeleton.hasModule("backend"), "missing backend");
|
||
|
|
CHECK(out.skeleton.hasModule("database"), "missing database");
|
||
|
|
CHECK(out.skeleton.hasModule("deploy"), "missing deploy");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_template_functions_are_annotated() {
|
||
|
|
TEST(template_functions_are_annotated);
|
||
|
|
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
|
||
|
|
auto m = out.skeleton.getModule("handlers");
|
||
|
|
CHECK(!m.functions.empty(), "missing handler functions");
|
||
|
|
bool hasIntent = false, hasContract = false;
|
||
|
|
for (const auto& a : m.functions[0].annotations) {
|
||
|
|
if (a.key == "@Intent") hasIntent = true;
|
||
|
|
if (a.key == "@Contract") hasContract = true;
|
||
|
|
}
|
||
|
|
CHECK(hasIntent && hasContract, "missing expected annotations");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_template_is_parameterized_by_primary_entity() {
|
||
|
|
TEST(template_is_parameterized_by_primary_entity);
|
||
|
|
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
|
||
|
|
auto handlers = out.skeleton.getModule("handlers");
|
||
|
|
bool hasCreateBook = false;
|
||
|
|
for (const auto& f : handlers.functions) if (f.name == "createBook") hasCreateBook = true;
|
||
|
|
CHECK(hasCreateBook, "expected entity-parameterized function name");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_template_module_dependencies_present() {
|
||
|
|
TEST(template_module_dependencies_present);
|
||
|
|
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
|
||
|
|
auto routes = out.skeleton.getModule("routes");
|
||
|
|
bool hasHandlersDep = false;
|
||
|
|
for (const auto& d : routes.dependencies) if (d == "handlers") hasHandlersDep = true;
|
||
|
|
CHECK(hasHandlersDep, "expected routes->handlers dependency");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_template_output_contains_template_note() {
|
||
|
|
TEST(template_output_contains_template_note);
|
||
|
|
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::CliTool, sampleInput());
|
||
|
|
CHECK(!out.notes.empty(), "expected template note");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_template_module_languages_match_expected_defaults() {
|
||
|
|
TEST(template_module_languages_match_expected_defaults);
|
||
|
|
auto rest = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
|
||
|
|
auto micro = ArchitectTemplates::instantiate(ArchitectureTemplateKind::Microservice, sampleInput());
|
||
|
|
auto full = ArchitectTemplates::instantiate(ArchitectureTemplateKind::FullStack, sampleInput());
|
||
|
|
CHECK(rest.skeleton.getModule("handlers").language == "typescript", "rest handlers language mismatch");
|
||
|
|
CHECK(micro.skeleton.getModule("service").language == "go", "microservice language mismatch");
|
||
|
|
CHECK(full.skeleton.getModule("backend").language == "python", "fullstack backend language mismatch");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_template_outputs_are_nonempty_across_all_kinds() {
|
||
|
|
TEST(template_outputs_are_nonempty_across_all_kinds);
|
||
|
|
auto in = sampleInput();
|
||
|
|
auto a = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, in);
|
||
|
|
auto b = ArchitectTemplates::instantiate(ArchitectureTemplateKind::CliTool, in);
|
||
|
|
auto c = ArchitectTemplates::instantiate(ArchitectureTemplateKind::Library, in);
|
||
|
|
auto d = ArchitectTemplates::instantiate(ArchitectureTemplateKind::Microservice, in);
|
||
|
|
auto e = ArchitectTemplates::instantiate(ArchitectureTemplateKind::FullStack, in);
|
||
|
|
CHECK(!a.skeleton.modules.empty(), "rest template empty");
|
||
|
|
CHECK(!b.skeleton.modules.empty(), "cli template empty");
|
||
|
|
CHECK(!c.skeleton.modules.empty(), "library template empty");
|
||
|
|
CHECK(!d.skeleton.modules.empty(), "microservice template empty");
|
||
|
|
CHECK(!e.skeleton.modules.empty(), "fullstack template empty");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_templates_include_auth_module_for_rest_api() {
|
||
|
|
TEST(templates_include_auth_module_for_rest_api);
|
||
|
|
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
|
||
|
|
CHECK(out.skeleton.hasModule("auth"), "expected auth module in REST template");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
int main() {
|
||
|
|
std::cout << "Step 477: Architecture Templates Tests\n";
|
||
|
|
|
||
|
|
test_rest_api_template_contains_expected_modules(); // 1
|
||
|
|
test_cli_template_contains_cli_command_output_modules(); // 2
|
||
|
|
test_library_template_contains_api_internal_tests_docs(); // 3
|
||
|
|
test_microservice_template_contains_service_transport_storage_health(); // 4
|
||
|
|
test_fullstack_template_contains_frontend_backend_database_deploy(); // 5
|
||
|
|
test_template_functions_are_annotated(); // 6
|
||
|
|
test_template_is_parameterized_by_primary_entity(); // 7
|
||
|
|
test_template_module_dependencies_present(); // 8
|
||
|
|
test_template_output_contains_template_note(); // 9
|
||
|
|
test_template_module_languages_match_expected_defaults(); // 10
|
||
|
|
test_template_outputs_are_nonempty_across_all_kinds(); // 11
|
||
|
|
test_templates_include_auth_module_for_rest_api(); // 12
|
||
|
|
|
||
|
|
std::cout << "\nResults: " << passed << "/" << (passed + failed)
|
||
|
|
<< " passed\n";
|
||
|
|
return failed == 0 ? 0 : 1;
|
||
|
|
}
|