118 lines
5.5 KiB
C++
118 lines
5.5 KiB
C++
#include "MetaCoreRuntimeUi/MetaCoreRuntimeUiSystem.h"
|
|
#include "MetaCoreFoundation/MetaCoreGeneratedReflection.h"
|
|
#include "MetaCoreScene/MetaCoreSceneSerializer.h"
|
|
|
|
#include <cstdlib>
|
|
#include <filesystem>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
namespace {
|
|
|
|
void Expect(bool value, const char* message) {
|
|
if (!value) {
|
|
std::cerr << "MetaCoreRuntimeUiTests: " << message << '\n';
|
|
std::exit(1);
|
|
}
|
|
}
|
|
|
|
MetaCore::MetaCoreUiDocument BuildDocument() {
|
|
using namespace MetaCore;
|
|
MetaCoreUiDocument document;
|
|
document.Name = "Controls";
|
|
document.ReferenceWidth = 1920;
|
|
document.ReferenceHeight = 1080;
|
|
document.ScaleMode = MetaCoreUiCanvasScaleMode::ScaleWithScreenSize;
|
|
document.MatchWidthOrHeight = 0.5F;
|
|
|
|
MetaCoreUiNodeDocument root;
|
|
root.Id = "Root";
|
|
root.Name = "Root";
|
|
root.Type = MetaCoreUiNodeType::Panel;
|
|
root.RectTransform.AnchorMin = {0.0F, 0.0F, 0.0F};
|
|
root.RectTransform.AnchorMax = {1.0F, 1.0F, 0.0F};
|
|
root.RectTransform.Size = {0.0F, 0.0F, 0.0F};
|
|
|
|
const std::vector<MetaCoreUiNodeType> types{
|
|
MetaCoreUiNodeType::Text, MetaCoreUiNodeType::Image, MetaCoreUiNodeType::Button,
|
|
MetaCoreUiNodeType::Input, MetaCoreUiNodeType::List, MetaCoreUiNodeType::Scroll
|
|
};
|
|
for (std::size_t index = 0; index < types.size(); ++index) {
|
|
MetaCoreUiNodeDocument node;
|
|
node.Id = "Node" + std::to_string(index);
|
|
node.Name = node.Id;
|
|
node.ParentId = root.Id;
|
|
node.Type = types[index];
|
|
node.Text = "Safe <text>";
|
|
node.Interactable = types[index] == MetaCoreUiNodeType::Button || types[index] == MetaCoreUiNodeType::Input;
|
|
node.NavigationOrder = static_cast<std::int32_t>(index);
|
|
node.RectTransform.AnchorMin = {0.25F, 0.25F, 0.0F};
|
|
node.RectTransform.AnchorMax = {0.75F, 0.25F, 0.0F};
|
|
node.RectTransform.Position = {10.0F, 20.0F + static_cast<float>(index) * 50.0F, 0.0F};
|
|
if (types[index] == MetaCoreUiNodeType::Input) {
|
|
node.Placeholder = "Value";
|
|
node.MaxLength = 32;
|
|
node.Bindings.push_back({"script.form.value", MetaCoreUiBindingTarget::Value,
|
|
MetaCoreUiBindingMode::TwoWay, {}, {}, "default"});
|
|
}
|
|
if (types[index] == MetaCoreUiNodeType::List) {
|
|
node.Bindings.push_back({"script.rows", MetaCoreUiBindingTarget::Items,
|
|
MetaCoreUiBindingMode::OneWay, {}, {}, {}});
|
|
}
|
|
root.Children.push_back(node.Id);
|
|
document.Nodes.push_back(std::move(node));
|
|
}
|
|
document.Nodes.insert(document.Nodes.begin(), root);
|
|
document.RootNodeIds.push_back(root.Id);
|
|
return document;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main() {
|
|
using namespace MetaCore;
|
|
const MetaCoreUiDocument document = BuildDocument();
|
|
Expect(MetaCoreValidateUiDocument(document).empty(), "valid document was rejected");
|
|
const MetaCoreCompiledUiDocument first = MetaCoreCompileUiDocument(document);
|
|
const MetaCoreCompiledUiDocument second = MetaCoreCompileUiDocument(document);
|
|
Expect(first.Succeeded, "document compilation failed");
|
|
Expect(first.Rml == second.Rml && first.Rcss == second.Rcss, "compiler output is not deterministic");
|
|
Expect(first.Rml.find("<input") != std::string::npos, "Input control was not compiled");
|
|
Expect(first.Rml.find("role=\"listbox\"") != std::string::npos, "List control was not compiled");
|
|
Expect(first.Rml.find("mcui-scroll") != std::string::npos, "Scroll control was not compiled");
|
|
Expect(first.Rml.find("Safe <text>") != std::string::npos, "text was not escaped");
|
|
Expect(first.Rcss.find("left:calc(25") != std::string::npos, "anchors were not compiled");
|
|
Expect(first.Rml.find("data-metacore-bind-mode-value=\"two-way\"") != std::string::npos, "two-way binding was not compiled");
|
|
|
|
MetaCoreUiDocument invalid = document;
|
|
invalid.Nodes.back().Id = invalid.Nodes.front().Id;
|
|
Expect(!MetaCoreValidateUiDocument(invalid).empty(), "duplicate stable ID was accepted");
|
|
invalid = document;
|
|
invalid.Nodes[1].Bindings.push_back({"unknown.path", MetaCoreUiBindingTarget::Text,
|
|
MetaCoreUiBindingMode::OneWay, {}, {}, {}});
|
|
Expect(!MetaCoreValidateUiDocument(invalid).empty(), "invalid binding namespace was accepted");
|
|
|
|
MetaCoreUiDocument legacy = document;
|
|
legacy.SchemaVersion = 1;
|
|
legacy.Nodes[1].Bindings.clear();
|
|
legacy.Nodes[1].DataBinding = "runtime.temperature";
|
|
legacy.Nodes[1].DataFormat = "1";
|
|
const MetaCoreUiDocument migrated = MetaCoreMigrateUiDocument(legacy);
|
|
Expect(migrated.SchemaVersion == METACORE_UI_SCHEMA_VERSION, "legacy schema was not migrated");
|
|
Expect(migrated.Nodes[1].Bindings.size() == 1, "legacy binding was not migrated");
|
|
|
|
const std::filesystem::path jsonPath = std::filesystem::temp_directory_path() / "MetaCoreRuntimeUiV2.mcui.json";
|
|
MetaCoreTypeRegistry registry;
|
|
MetaCoreRegisterFoundationGeneratedTypes(registry);
|
|
MetaCoreRegisterSceneGeneratedTypes(registry);
|
|
Expect(MetaCoreSerializeToBytes(document, registry).has_value(), "v2 binary serialization failed");
|
|
Expect(MetaCoreSceneSerializer::SaveUiToJson(jsonPath, document, registry), "v2 JSON write failed");
|
|
const auto loaded = MetaCoreSceneSerializer::LoadUiFromJson(jsonPath, registry);
|
|
Expect(loaded.has_value() && loaded->SchemaVersion == 2, "v2 JSON schema did not round-trip");
|
|
Expect(loaded->Nodes[4].Placeholder == "Value", "Input settings did not round-trip");
|
|
std::filesystem::remove(jsonPath);
|
|
|
|
std::cout << "MetaCoreRuntimeUiTests passed\n";
|
|
return 0;
|
|
}
|