Files
EVEngine/test/editor_texture_recipe_target.cpp
西风逍遥游andCursor 24502babef Nest satellite packages under their host modules.
Keep CMake module names and trim switches, but stop flattening editing/editor and runtime bridges as top-level src/modules directories. Parent scans skip nested facets so runtime-3d can drop authoring by directory leaf.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-06 17:56:12 +08:00

62 lines
3.1 KiB
C++

#include "procgen/editing/TextureRecipeTarget.h"
#include "zeroerr/assert.h"
#include "zeroerr/unittest.h"
using namespace eve::procgen_editing;
using namespace eve::editing;
namespace {
SelectionSnapshot select(const TextureRecipeTarget& target) {
SelectionSnapshot selection;
selection.channel = "texture-recipe";
selection.items.push_back({SelectionDomain::Asset, TargetId(target.targetId()),
StableId(target.targetId().value()), "texture-recipe"});
return selection;
}
void apply(TextureRecipeTarget& target, EditorResult<DomainOperation> operation) {
REQUIRE(operation.ok());
REQUIRE(target.applyDomainOperation(operation.value()).ok());
}
}
TEST_CASE("editor.texture_recipe.reflects_schema_and_reverses_parameters") {
TextureRecipeTarget target("cloud.asset", "tex.cloud");
const auto selection = select(target);
const auto schema = target.schema(selection);
REQUIRE(schema.find(PropertyPath("param.width")));
REQUIRE(schema.find(PropertyPath("param.seamless")));
auto width = target.makeSet(selection, PropertyPath("param.width"), int64_t{16},
PropertySetMode::Absolute);
REQUIRE(width.ok());
REQUIRE(target.applyDomainOperation(width.value()).ok());
CHECK_EQ(*target.read(selection, PropertyPath("param.width")).value.getIf<int64_t>(), int64_t{16});
DomainOperation undo = width.value();
undo.payload = width.value().inverse;
REQUIRE(target.applyDomainOperation(undo).ok());
CHECK_NE(*target.read(selection, PropertyPath("param.width")).value.getIf<int64_t>(), int64_t{16});
CHECK_EQ(static_cast<int>(target.makeSet(selection, PropertyPath("param.width"), int64_t{5000},
PropertySetMode::Absolute).code()),
static_cast<int>(EditorStatus::Rejected));
}
TEST_CASE("editor.texture_recipe_snapshot_is_atomic_and_preview_is_deterministic") {
TextureRecipeTarget target("cloud.asset", "tex.cloud");
const auto selection = select(target);
apply(target, target.makeSet(selection, PropertyPath("param.width"), int64_t{16}, PropertySetMode::Absolute));
apply(target, target.makeSet(selection, PropertyPath("param.height"), int64_t{12}, PropertySetMode::Absolute));
const auto before = target.snapshotValue();
EditorValue invalid = before;
auto* root = invalid.getIf<EditorValue::Object>();
auto* content = (*root)["content"].getIf<EditorValue::Object>();
auto* values = (*content)["values"].getIf<EditorValue::Object>();
(*values)["width"] = int64_t{0};
CHECK_EQ(static_cast<int>(target.loadSnapshot(invalid).code()), static_cast<int>(EditorStatus::Rejected));
CHECK_EQ(target.snapshotValue(), before);
TextureRecipePreviewRuntime runtime;
auto first = runtime.generate(target);
REQUIRE(first.ok());
CHECK_EQ(first.value().width, 16);
CHECK_EQ(first.value().height, 12);
CHECK_NE(first.value().checksum, std::uint64_t{0});
auto second = runtime.generate(target);
REQUIRE(second.ok());
CHECK_EQ(second.value().checksum, first.value().checksum);
CHECK_EQ(runtime.revision(), target.revision());
}