Files
EVEngine/test/editor_procgen_script_editor.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

124 lines
5.3 KiB
C++

#include "procgen/editor/ProcgenScriptEditor.h"
#include "editor/EditorWorkspace.h"
#include "procgen/PointSet.h"
#include "zeroerr/assert.h"
#include "zeroerr/unittest.h"
#include <cmath>
using eve::procgen_editor::ProcgenScriptEditor;
using eve::editor::EditorWorkspace;
using eve::procgen_editing::EditorValue;
using eve::procgen_editing::ProcgenScriptModuleSpec;
static ProcgenScriptModuleSpec forestSpec(std::string extraKey = {}) {
ProcgenScriptModuleSpec spec;
spec.uri = "game:/generators/forest.nut";
spec.id = "forest";
spec.displayName = "Forest scatter";
spec.kind = "points";
spec.params.push_back(eve::procgen::ParamDescriptor::integer("seed", "Seed", 42, 1, 9999, 1));
spec.params.push_back(eve::procgen::ParamDescriptor::floating("density", "Density", 0.8f, 0.1f, 1.0f, 0.05f));
spec.params.push_back(eve::procgen::ParamDescriptor::floating("pruneRadius", "Prune", 32.f, 4.f, 80.f, 1.f));
if (!extraKey.empty())
spec.params.push_back(eve::procgen::ParamDescriptor::integer(extraKey, extraKey, 1, 1, 8, 1));
return spec;
}
static eve::procgen::PointSet makePoints(int count) {
eve::procgen::PointSet points;
for (int i = 0; i < count; ++i) points.add(static_cast<float>(i), 0.f, static_cast<float>(i * 2));
return points;
}
TEST_CASE("editor.procgen.script_editor_installs_workspace_and_commits_params") {
ProcgenScriptEditor editor("preview.forest");
EditorWorkspace workspace("procgen.preview", "Procgen Editor");
REQUIRE(editor.configureWorkspace(workspace).ok());
CHECK_EQ(workspace.getPanelCount(), 4);
CHECK_EQ(workspace.getPanelId(0), std::string("procgen.modules"));
CHECK_EQ(workspace.getPanelCapability(0), std::string("procgen.script"));
CHECK_EQ(workspace.getPanelContext(0), std::string("list"));
CHECK_EQ(workspace.getPanelContext(1), std::string("preview"));
CHECK_EQ(workspace.getPanelContext(2), std::string("inspector"));
CHECK_EQ(workspace.getPanelContext(3), std::string("stages"));
REQUIRE(editor.loadModule(forestSpec()).ok());
CHECK_EQ(editor.paramCount(), 3);
CHECK_EQ(editor.getFloat("density"), 0.8f);
CHECK(editor.isDirty());
eve::procgen::PointSet first = makePoints(4);
REQUIRE(editor.publishPreview(&first, "trees", editor.revision()).ok());
CHECK_EQ(editor.pointCount(), 4);
CHECK_EQ(editor.previewRevision(), editor.revision());
CHECK(!editor.isDirty());
const auto revision = editor.revision();
REQUIRE(editor.setFloat("density", 0.5).ok());
CHECK(editor.isDirty());
CHECK_EQ(editor.pointCount(), 4);
CHECK_EQ(editor.previewRevision(), revision);
CHECK(std::abs(editor.getFloat("density") - 0.5f) < 0.0001f);
REQUIRE(editor.undo().ok());
CHECK(std::abs(editor.getFloat("density") - 0.8f) < 0.0001f);
CHECK(editor.isDirty());
}
TEST_CASE("editor.procgen.script_editor_keeps_preview_on_failed_rebuild_and_stale_publish") {
ProcgenScriptEditor editor("preview.forest");
REQUIRE(editor.loadModule(forestSpec()).ok());
eve::procgen::PointSet first = makePoints(3);
REQUIRE(editor.publishPreview(&first, "trees", editor.revision()).ok());
const int before = editor.pointCount();
const auto previewRevision = editor.previewRevision();
REQUIRE(editor.setFloat("density", 0.4).ok());
REQUIRE(editor.failPreview("generate exploded", editor.revision()).ok());
CHECK_EQ(editor.pointCount(), before);
CHECK_EQ(editor.previewRevision(), previewRevision);
CHECK(!editor.isDirty());
CHECK_EQ(editor.previewFailureSummary(), std::string("generate exploded"));
eve::procgen::PointSet next = makePoints(8);
auto stale = editor.publishPreview(&next, "trees", previewRevision);
CHECK(!stale.ok());
CHECK_EQ(editor.pointCount(), before);
}
TEST_CASE("editor.procgen.script_editor_reload_drops_unknown_and_fills_defaults") {
ProcgenScriptEditor editor("preview.forest");
auto first = forestSpec("scatter");
REQUIRE(editor.loadModule(first).ok());
REQUIRE(editor.setInt("scatter", 4).ok());
CHECK_EQ(editor.getInt("scatter"), 4);
auto second = forestSpec();
second.params.push_back(eve::procgen::ParamDescriptor::floating("spacing", "Spacing", 28.f, 8.f, 64.f, 1.f));
REQUIRE(editor.loadModule(second).ok());
CHECK_EQ(editor.paramCount(), 4);
CHECK_EQ(editor.getInt("scatter"), 0);
CHECK(std::abs(editor.getFloat("spacing") - 28.f) < 0.0001f);
CHECK(std::abs(editor.getFloat("density") - 0.8f) < 0.0001f);
}
TEST_CASE("editor.procgen.script_editor_rejects_out_of_range_and_over_budget") {
ProcgenScriptEditor editor("preview.forest");
REQUIRE(editor.loadModule(forestSpec()).ok());
eve::procgen::PointSet first = makePoints(2);
REQUIRE(editor.publishPreview(&first, "trees", editor.revision()).ok());
const auto revision = editor.previewRevision();
auto rejected = editor.setFloat("density", 2.0);
CHECK(!rejected.ok());
CHECK_EQ(editor.previewRevision(), revision);
CHECK_EQ(editor.pointCount(), 2);
REQUIRE(editor.setPointBudget(1).ok());
eve::procgen::PointSet huge = makePoints(3);
REQUIRE(editor.setFloat("density", 0.2).ok());
auto over = editor.publishPreview(&huge, "trees", editor.revision());
CHECK(!over.ok());
CHECK_EQ(editor.pointCount(), 2);
}