mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-24 13:44:58 +00:00
ROADMAP.md
This commit is contained in:
@@ -289,8 +289,11 @@ set(WORKFLOW_SOURCES
|
||||
src/services/impl/workflow_step_registry.cpp
|
||||
src/services/impl/workflow_executor.cpp
|
||||
src/services/impl/workflow_definition_parser.cpp
|
||||
src/services/impl/workflow_template_resolver.cpp
|
||||
src/services/impl/workflow_config_pipeline.cpp
|
||||
src/services/impl/workflow_config_load_step.cpp
|
||||
src/services/impl/workflow_config_version_step.cpp
|
||||
src/services/impl/workflow_config_migration_step.cpp
|
||||
src/services/impl/workflow_config_schema_step.cpp
|
||||
src/services/impl/workflow_default_step_registrar.cpp
|
||||
)
|
||||
@@ -579,6 +582,7 @@ add_executable(vulkan_shader_linking_test
|
||||
src/services/impl/bgfx_gui_service.cpp
|
||||
src/services/impl/bgfx_shader_compiler.cpp
|
||||
${JSON_CONFIG_SOURCES}
|
||||
${WORKFLOW_SOURCES}
|
||||
src/services/impl/materialx_shader_generator.cpp
|
||||
src/services/impl/shader_pipeline_validator.cpp
|
||||
src/services/impl/platform_service.cpp
|
||||
@@ -767,6 +771,7 @@ add_test(NAME render_graph_service_test COMMAND render_graph_service_test)
|
||||
add_executable(json_config_merge_test
|
||||
tests/json_config_merge_test.cpp
|
||||
${JSON_CONFIG_SOURCES}
|
||||
${WORKFLOW_SOURCES}
|
||||
)
|
||||
target_include_directories(json_config_merge_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
target_link_libraries(json_config_merge_test PRIVATE
|
||||
@@ -780,6 +785,7 @@ add_test(NAME json_config_merge_test COMMAND json_config_merge_test)
|
||||
add_executable(json_config_schema_validation_test
|
||||
tests/json_config_schema_validation_test.cpp
|
||||
${JSON_CONFIG_SOURCES}
|
||||
${WORKFLOW_SOURCES}
|
||||
)
|
||||
target_include_directories(json_config_schema_validation_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
target_link_libraries(json_config_schema_validation_test PRIVATE
|
||||
|
||||
@@ -237,11 +237,12 @@ Option B: per-shader only
|
||||
### Status
|
||||
- [~] Workflow core: step registry + executor + JSON definition parser.
|
||||
- [~] Default step package: `config.load`, `config.version.validate`, `config.schema.validate`.
|
||||
- [~] Boot config workflow execution (load/version/migrate/schema); runtime config parsing still outside workflow.
|
||||
- [x] Workflow schema: `config/schema/workflow_v1.schema.json`.
|
||||
- [x] Template package: `config/workflows/templates/boot_default.json`.
|
||||
|
||||
### Next Steps
|
||||
- Wire boot pipeline to use workflow executor (config load/validate/migrate).
|
||||
- Move RuntimeConfig parsing into a workflow step.
|
||||
- Add frame workflow template (BeginFrame → RenderGraph → Capture → Validate).
|
||||
|
||||
## Feature Matrix (What You Get, When You Get It)
|
||||
|
||||
@@ -22,6 +22,19 @@
|
||||
"version": "config.version"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "migrate_version",
|
||||
"plugin": "config.migrate",
|
||||
"inputs": {
|
||||
"document": "config.document",
|
||||
"path": "config.path",
|
||||
"version": "config.version"
|
||||
},
|
||||
"outputs": {
|
||||
"document": "config.document",
|
||||
"version": "config.version"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "validate_schema",
|
||||
"plugin": "config.schema.validate",
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#include "json_config_service.hpp"
|
||||
#include "json_config_document_loader.hpp"
|
||||
#include "json_config_migration_service.hpp"
|
||||
#include "json_config_schema_validator.hpp"
|
||||
#include "json_config_schema_version.hpp"
|
||||
#include "json_config_version_validator.hpp"
|
||||
#include "workflow_config_pipeline.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
@@ -120,27 +117,12 @@ RuntimeConfig JsonConfigService::LoadFromJson(std::shared_ptr<ILogger> logger,
|
||||
", dumpConfig=" + (dumpConfig ? "true" : "false");
|
||||
logger->Trace("JsonConfigService", "LoadFromJson", args);
|
||||
|
||||
json_config::JsonConfigDocumentLoader documentLoader(logger);
|
||||
rapidjson::Document document = documentLoader.Load(configPath);
|
||||
|
||||
json_config::JsonConfigVersionValidator versionValidator(logger);
|
||||
const auto activeVersion = versionValidator.Validate(document, configPath);
|
||||
if (activeVersion && *activeVersion != json_config::kRuntimeConfigSchemaVersion) {
|
||||
json_config::JsonConfigMigrationService migrationService(logger, probeService);
|
||||
const bool migrated = migrationService.Apply(document,
|
||||
*activeVersion,
|
||||
json_config::kRuntimeConfigSchemaVersion,
|
||||
configPath);
|
||||
if (!migrated) {
|
||||
throw std::runtime_error("Unsupported schema version " + std::to_string(*activeVersion) +
|
||||
" in " + configPath.string() +
|
||||
"; expected " + std::to_string(json_config::kRuntimeConfigSchemaVersion) +
|
||||
" (see config/schema/MIGRATIONS.md)");
|
||||
}
|
||||
WorkflowConfigPipeline pipeline(logger, probeService);
|
||||
std::shared_ptr<rapidjson::Document> documentHandle = pipeline.Execute(configPath, nullptr);
|
||||
if (!documentHandle) {
|
||||
throw std::runtime_error("JsonConfigService::LoadFromJson: workflow pipeline returned null document");
|
||||
}
|
||||
|
||||
json_config::JsonConfigSchemaValidator schemaValidator(logger, probeService);
|
||||
schemaValidator.ValidateOrThrow(document, configPath);
|
||||
const rapidjson::Document& document = *documentHandle;
|
||||
|
||||
if (dumpConfig || configJson) {
|
||||
rapidjson::StringBuffer buffer;
|
||||
|
||||
92
src/services/impl/workflow_config_migration_step.cpp
Normal file
92
src/services/impl/workflow_config_migration_step.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "workflow_config_migration_step.hpp"
|
||||
|
||||
#include "json_config_migration_service.hpp"
|
||||
#include "json_config_schema_version.hpp"
|
||||
#include "workflow_step_io_resolver.hpp"
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
WorkflowConfigMigrationStep::WorkflowConfigMigrationStep(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IProbeService> probeService)
|
||||
: logger_(std::move(logger)),
|
||||
probeService_(std::move(probeService)) {}
|
||||
|
||||
std::string WorkflowConfigMigrationStep::GetPluginId() const {
|
||||
return "config.migrate";
|
||||
}
|
||||
|
||||
void WorkflowConfigMigrationStep::Execute(const WorkflowStepDefinition& step, WorkflowContext& context) {
|
||||
WorkflowStepIoResolver resolver;
|
||||
const std::string documentKey = resolver.GetRequiredInputKey(step, "document");
|
||||
const std::string pathKey = resolver.GetRequiredInputKey(step, "path");
|
||||
const std::string versionKey = resolver.GetRequiredInputKey(step, "version");
|
||||
const std::string outputDocumentKey = resolver.GetRequiredOutputKey(step, "document");
|
||||
const std::string outputVersionKey = resolver.GetRequiredOutputKey(step, "version");
|
||||
|
||||
const auto* documentHandle = context.TryGet<std::shared_ptr<rapidjson::Document>>(documentKey);
|
||||
if (!documentHandle || !(*documentHandle)) {
|
||||
throw std::runtime_error("Workflow config.migrate missing document input '" + documentKey + "'");
|
||||
}
|
||||
std::shared_ptr<rapidjson::Document> document = *documentHandle;
|
||||
|
||||
const auto* versionHandle = context.TryGet<std::optional<int>>(versionKey);
|
||||
if (!versionHandle) {
|
||||
throw std::runtime_error("Workflow config.migrate missing version input '" + versionKey + "'");
|
||||
}
|
||||
std::optional<int> version = *versionHandle;
|
||||
|
||||
std::filesystem::path pathValue;
|
||||
if (const auto* path = context.TryGet<std::filesystem::path>(pathKey)) {
|
||||
pathValue = *path;
|
||||
} else if (const auto* pathString = context.TryGet<std::string>(pathKey)) {
|
||||
pathValue = *pathString;
|
||||
} else {
|
||||
throw std::runtime_error("Workflow config.migrate missing path input '" + pathKey + "'");
|
||||
}
|
||||
|
||||
if (!version) {
|
||||
if (logger_) {
|
||||
logger_->Trace("WorkflowConfigMigrationStep", "Execute",
|
||||
"configPath=" + pathValue.string(),
|
||||
"No schema version provided; skipping migration");
|
||||
}
|
||||
} else if (*version == json_config::kRuntimeConfigSchemaVersion) {
|
||||
if (logger_) {
|
||||
logger_->Trace("WorkflowConfigMigrationStep", "Execute",
|
||||
"version=" + std::to_string(*version),
|
||||
"Schema version matches runtime; skipping migration");
|
||||
}
|
||||
} else {
|
||||
if (logger_) {
|
||||
logger_->Info("WorkflowConfigMigrationStep: Migrating config from version " +
|
||||
std::to_string(*version) + " to " +
|
||||
std::to_string(json_config::kRuntimeConfigSchemaVersion));
|
||||
}
|
||||
json_config::JsonConfigMigrationService migrationService(logger_, probeService_);
|
||||
const bool migrated = migrationService.Apply(*document,
|
||||
*version,
|
||||
json_config::kRuntimeConfigSchemaVersion,
|
||||
pathValue);
|
||||
if (!migrated) {
|
||||
throw std::runtime_error("Unsupported schema version " + std::to_string(*version) +
|
||||
" in " + pathValue.string() +
|
||||
"; expected " + std::to_string(json_config::kRuntimeConfigSchemaVersion) +
|
||||
" (see config/schema/MIGRATIONS.md)");
|
||||
}
|
||||
version = json_config::kRuntimeConfigSchemaVersion;
|
||||
}
|
||||
|
||||
context.Set(outputDocumentKey, document);
|
||||
context.Set(outputVersionKey, version);
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
24
src/services/impl/workflow_config_migration_step.hpp
Normal file
24
src/services/impl/workflow_config_migration_step.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "../interfaces/i_workflow_step.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../interfaces/i_probe_service.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
class WorkflowConfigMigrationStep final : public IWorkflowStep {
|
||||
public:
|
||||
WorkflowConfigMigrationStep(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IProbeService> probeService);
|
||||
|
||||
std::string GetPluginId() const override;
|
||||
void Execute(const WorkflowStepDefinition& step, WorkflowContext& context) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
std::shared_ptr<IProbeService> probeService_;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
68
src/services/impl/workflow_config_pipeline.cpp
Normal file
68
src/services/impl/workflow_config_pipeline.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "workflow_config_pipeline.hpp"
|
||||
|
||||
#include "workflow_default_step_registrar.hpp"
|
||||
#include "workflow_definition_parser.hpp"
|
||||
#include "workflow_executor.hpp"
|
||||
#include "workflow_step_registry.hpp"
|
||||
#include "workflow_template_resolver.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../interfaces/i_probe_service.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
WorkflowConfigPipeline::WorkflowConfigPipeline(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IProbeService> probeService)
|
||||
: logger_(std::move(logger)),
|
||||
probeService_(std::move(probeService)) {}
|
||||
|
||||
std::shared_ptr<rapidjson::Document> WorkflowConfigPipeline::Execute(
|
||||
const std::filesystem::path& configPath,
|
||||
std::optional<int>* versionOut) const {
|
||||
if (logger_) {
|
||||
logger_->Trace("WorkflowConfigPipeline", "Execute",
|
||||
"configPath=" + configPath.string(),
|
||||
"Starting boot workflow");
|
||||
}
|
||||
|
||||
WorkflowTemplateResolver resolver;
|
||||
const std::filesystem::path templatePath = resolver.ResolveBootTemplate(configPath);
|
||||
if (templatePath.empty()) {
|
||||
throw std::runtime_error("WorkflowConfigPipeline: boot workflow template not found for " +
|
||||
configPath.string());
|
||||
}
|
||||
|
||||
WorkflowDefinitionParser parser;
|
||||
const WorkflowDefinition workflow = parser.ParseFile(templatePath);
|
||||
|
||||
auto registry = std::make_shared<WorkflowStepRegistry>();
|
||||
WorkflowDefaultStepRegistrar registrar(logger_, probeService_);
|
||||
registrar.RegisterUsedSteps(workflow, registry);
|
||||
|
||||
WorkflowExecutor executor(registry, logger_);
|
||||
WorkflowContext context;
|
||||
context.Set("config.path", configPath);
|
||||
executor.Execute(workflow, context);
|
||||
|
||||
const auto* documentHandle = context.TryGet<std::shared_ptr<rapidjson::Document>>("config.document");
|
||||
if (!documentHandle || !(*documentHandle)) {
|
||||
throw std::runtime_error("WorkflowConfigPipeline: boot workflow did not provide config.document");
|
||||
}
|
||||
if (versionOut) {
|
||||
const auto* versionHandle = context.TryGet<std::optional<int>>("config.version");
|
||||
*versionOut = versionHandle ? *versionHandle : std::nullopt;
|
||||
}
|
||||
|
||||
if (logger_) {
|
||||
logger_->Trace("WorkflowConfigPipeline", "Execute",
|
||||
"templatePath=" + templatePath.string(),
|
||||
"Boot workflow complete");
|
||||
}
|
||||
|
||||
return *documentHandle;
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
29
src/services/impl/workflow_config_pipeline.hpp
Normal file
29
src/services/impl/workflow_config_pipeline.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
namespace sdl3cpp::services {
|
||||
class ILogger;
|
||||
class IProbeService;
|
||||
}
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
class WorkflowConfigPipeline {
|
||||
public:
|
||||
WorkflowConfigPipeline(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IProbeService> probeService);
|
||||
|
||||
std::shared_ptr<rapidjson::Document> Execute(const std::filesystem::path& configPath,
|
||||
std::optional<int>* versionOut) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
std::shared_ptr<IProbeService> probeService_;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "workflow_default_step_registrar.hpp"
|
||||
#include "workflow_config_load_step.hpp"
|
||||
#include "workflow_config_migration_step.hpp"
|
||||
#include "workflow_config_schema_step.hpp"
|
||||
#include "workflow_config_version_step.hpp"
|
||||
|
||||
@@ -32,6 +33,9 @@ void WorkflowDefaultStepRegistrar::RegisterUsedSteps(
|
||||
if (plugins.contains("config.version.validate")) {
|
||||
registry->RegisterStep(std::make_shared<WorkflowConfigVersionStep>(logger_));
|
||||
}
|
||||
if (plugins.contains("config.migrate")) {
|
||||
registry->RegisterStep(std::make_shared<WorkflowConfigMigrationStep>(logger_, probeService_));
|
||||
}
|
||||
if (plugins.contains("config.schema.validate")) {
|
||||
registry->RegisterStep(std::make_shared<WorkflowConfigSchemaStep>(logger_, probeService_));
|
||||
}
|
||||
|
||||
26
src/services/impl/workflow_template_resolver.cpp
Normal file
26
src/services/impl/workflow_template_resolver.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "workflow_template_resolver.hpp"
|
||||
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
std::filesystem::path WorkflowTemplateResolver::ResolveBootTemplate(
|
||||
const std::filesystem::path& configPath) const {
|
||||
const std::filesystem::path templateRelative = "workflows/templates/boot_default.json";
|
||||
std::vector<std::filesystem::path> candidates;
|
||||
if (!configPath.empty()) {
|
||||
candidates.push_back(configPath.parent_path() / templateRelative);
|
||||
}
|
||||
candidates.push_back(std::filesystem::current_path() / "config" / templateRelative);
|
||||
|
||||
std::error_code ec;
|
||||
for (const auto& candidate : candidates) {
|
||||
if (!candidate.empty() && std::filesystem::exists(candidate, ec)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
12
src/services/impl/workflow_template_resolver.hpp
Normal file
12
src/services/impl/workflow_template_resolver.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
class WorkflowTemplateResolver {
|
||||
public:
|
||||
std::filesystem::path ResolveBootTemplate(const std::filesystem::path& configPath) const;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
@@ -3,10 +3,12 @@
|
||||
#include "services/impl/json_config_service.hpp"
|
||||
#include "services/interfaces/i_logger.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -67,15 +69,22 @@ void WriteFile(const std::filesystem::path& path, const std::string& contents) {
|
||||
output << contents;
|
||||
}
|
||||
|
||||
void CopySchema(const std::filesystem::path& targetDir) {
|
||||
auto schemaSource = GetRepoRoot() / "config" / "schema" / "runtime_config_v2.schema.json";
|
||||
auto schemaTarget = targetDir / "schema" / "runtime_config_v2.schema.json";
|
||||
std::filesystem::create_directories(schemaTarget.parent_path());
|
||||
std::ifstream input(schemaSource);
|
||||
ASSERT_TRUE(input.is_open()) << "Missing schema source: " << schemaSource;
|
||||
std::ofstream output(schemaTarget);
|
||||
ASSERT_TRUE(output.is_open()) << "Failed to write schema target: " << schemaTarget;
|
||||
output << input.rdbuf();
|
||||
void CopyConfigAssets(const std::filesystem::path& targetDir) {
|
||||
const auto repoRoot = GetRepoRoot();
|
||||
const std::array<std::pair<std::filesystem::path, std::filesystem::path>, 2> assets = {
|
||||
std::make_pair(repoRoot / "config" / "schema" / "runtime_config_v2.schema.json",
|
||||
targetDir / "schema" / "runtime_config_v2.schema.json"),
|
||||
std::make_pair(repoRoot / "config" / "workflows" / "templates" / "boot_default.json",
|
||||
targetDir / "workflows" / "templates" / "boot_default.json")
|
||||
};
|
||||
for (const auto& asset : assets) {
|
||||
std::filesystem::create_directories(asset.second.parent_path());
|
||||
std::ifstream input(asset.first);
|
||||
ASSERT_TRUE(input.is_open()) << "Missing config asset: " << asset.first;
|
||||
std::ofstream output(asset.second);
|
||||
ASSERT_TRUE(output.is_open()) << "Failed to write config asset: " << asset.second;
|
||||
output << input.rdbuf();
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path WriteLuaScript(const std::filesystem::path& rootDir) {
|
||||
@@ -86,7 +95,7 @@ std::filesystem::path WriteLuaScript(const std::filesystem::path& rootDir) {
|
||||
|
||||
TEST(JsonConfigMergeTest, OverlayOverridesBaseFields) {
|
||||
ScopedTempDir tempDir;
|
||||
CopySchema(tempDir.Path());
|
||||
CopyConfigAssets(tempDir.Path());
|
||||
WriteLuaScript(tempDir.Path());
|
||||
auto logger = std::make_shared<NullLogger>();
|
||||
|
||||
@@ -117,7 +126,7 @@ TEST(JsonConfigMergeTest, OverlayOverridesBaseFields) {
|
||||
|
||||
TEST(JsonConfigMergeTest, DeleteDirectiveRemovesObject) {
|
||||
ScopedTempDir tempDir;
|
||||
CopySchema(tempDir.Path());
|
||||
CopyConfigAssets(tempDir.Path());
|
||||
WriteLuaScript(tempDir.Path());
|
||||
auto logger = std::make_shared<NullLogger>();
|
||||
|
||||
@@ -154,7 +163,7 @@ TEST(JsonConfigMergeTest, DeleteDirectiveRemovesObject) {
|
||||
|
||||
TEST(JsonConfigMergeTest, ExtendsArrayAppliesInOrder) {
|
||||
ScopedTempDir tempDir;
|
||||
CopySchema(tempDir.Path());
|
||||
CopyConfigAssets(tempDir.Path());
|
||||
WriteLuaScript(tempDir.Path());
|
||||
auto logger = std::make_shared<NullLogger>();
|
||||
|
||||
@@ -190,7 +199,7 @@ TEST(JsonConfigMergeTest, ExtendsArrayAppliesInOrder) {
|
||||
|
||||
TEST(JsonConfigMergeTest, ExtendsCycleThrows) {
|
||||
ScopedTempDir tempDir;
|
||||
CopySchema(tempDir.Path());
|
||||
CopyConfigAssets(tempDir.Path());
|
||||
WriteLuaScript(tempDir.Path());
|
||||
auto logger = std::make_shared<NullLogger>();
|
||||
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
#include "services/impl/json_config_service.hpp"
|
||||
#include "services/interfaces/i_logger.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -67,15 +69,22 @@ void WriteFile(const std::filesystem::path& path, const std::string& contents) {
|
||||
output << contents;
|
||||
}
|
||||
|
||||
void CopySchema(const std::filesystem::path& targetDir) {
|
||||
auto schemaSource = GetRepoRoot() / "config" / "schema" / "runtime_config_v2.schema.json";
|
||||
auto schemaTarget = targetDir / "schema" / "runtime_config_v2.schema.json";
|
||||
std::filesystem::create_directories(schemaTarget.parent_path());
|
||||
std::ifstream input(schemaSource);
|
||||
ASSERT_TRUE(input.is_open()) << "Missing schema source: " << schemaSource;
|
||||
std::ofstream output(schemaTarget);
|
||||
ASSERT_TRUE(output.is_open()) << "Failed to write schema target: " << schemaTarget;
|
||||
output << input.rdbuf();
|
||||
void CopyConfigAssets(const std::filesystem::path& targetDir) {
|
||||
const auto repoRoot = GetRepoRoot();
|
||||
const std::array<std::pair<std::filesystem::path, std::filesystem::path>, 2> assets = {
|
||||
std::make_pair(repoRoot / "config" / "schema" / "runtime_config_v2.schema.json",
|
||||
targetDir / "schema" / "runtime_config_v2.schema.json"),
|
||||
std::make_pair(repoRoot / "config" / "workflows" / "templates" / "boot_default.json",
|
||||
targetDir / "workflows" / "templates" / "boot_default.json")
|
||||
};
|
||||
for (const auto& asset : assets) {
|
||||
std::filesystem::create_directories(asset.second.parent_path());
|
||||
std::ifstream input(asset.first);
|
||||
ASSERT_TRUE(input.is_open()) << "Missing config asset: " << asset.first;
|
||||
std::ofstream output(asset.second);
|
||||
ASSERT_TRUE(output.is_open()) << "Failed to write config asset: " << asset.second;
|
||||
output << input.rdbuf();
|
||||
}
|
||||
}
|
||||
|
||||
void WriteLuaScript(const std::filesystem::path& rootDir) {
|
||||
@@ -84,7 +93,7 @@ void WriteLuaScript(const std::filesystem::path& rootDir) {
|
||||
|
||||
TEST(JsonConfigSchemaValidationTest, RejectsInvalidWindowWidthType) {
|
||||
ScopedTempDir tempDir;
|
||||
CopySchema(tempDir.Path());
|
||||
CopyConfigAssets(tempDir.Path());
|
||||
WriteLuaScript(tempDir.Path());
|
||||
auto logger = std::make_shared<NullLogger>();
|
||||
|
||||
@@ -104,7 +113,7 @@ TEST(JsonConfigSchemaValidationTest, RejectsInvalidWindowWidthType) {
|
||||
|
||||
TEST(JsonConfigSchemaValidationTest, RejectsInvalidSceneSourceEnum) {
|
||||
ScopedTempDir tempDir;
|
||||
CopySchema(tempDir.Path());
|
||||
CopyConfigAssets(tempDir.Path());
|
||||
WriteLuaScript(tempDir.Path());
|
||||
auto logger = std::make_shared<NullLogger>();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user