Show and configure safe Editor autosave
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int test_main(int argc, char** argv) {
|
||||
using namespace faset;
|
||||
if (argc >= 3 && std::string_view(argv[1]) == "--editor-probe") {
|
||||
Json arguments = Json::array();
|
||||
@@ -36,6 +36,8 @@ int main(int argc, char** argv) {
|
||||
require(!session.play_pending() && !session.playing(), "test",
|
||||
"Stop must cancel a pending Play build");
|
||||
const auto initial = commands.call("faset_project_settings_get", Json::object());
|
||||
require(initial.at("settings").at("editor").at("autosave") == true, "test",
|
||||
"Missing autosave setting must read as enabled");
|
||||
auto changed = commands.call("faset_project_settings_set",
|
||||
{{"revision", initial.at("revision")},
|
||||
{"settings",
|
||||
@@ -75,15 +77,57 @@ int main(int argc, char** argv) {
|
||||
atomic_write_json(root / "project.faset.json", external);
|
||||
rejects({{"revision", changed.at("revision")}, {"settings", {{"name", "Race"}}}},
|
||||
"revision.conflict");
|
||||
const auto reloaded = commands.call("faset_project_settings_get", Json::object());
|
||||
auto reloaded = commands.call("faset_project_settings_get", Json::object());
|
||||
auto explicit_default = external;
|
||||
explicit_default["editor"]["autosave"] = true;
|
||||
atomic_write_json(root / "project.faset.json", explicit_default);
|
||||
rejects({{"revision", reloaded.at("revision")},
|
||||
{"settings", {{"name", "Lost external write"}}}},
|
||||
"revision.conflict");
|
||||
reloaded = commands.call("faset_project_settings_get", Json::object());
|
||||
changed =
|
||||
commands.call("faset_project_settings_set", {{"revision", reloaded.at("revision")},
|
||||
{"settings", {{"name", "Preserved"}}}});
|
||||
require(changed.at("settings").at("custom_tool").at("keep") == true, "test",
|
||||
"Saving settings erased unknown project metadata");
|
||||
require(changed.at("settings").at("scripting") == external.at("scripting") &&
|
||||
changed.at("settings").at("editor") == external.at("editor"),
|
||||
changed.at("settings").at("editor").at("script_editor") ==
|
||||
external.at("editor").at("script_editor"),
|
||||
"test", "Project settings erased Lua configuration or external editor command");
|
||||
const auto autosave_off = commands.call(
|
||||
"faset_project_settings_set",
|
||||
{{"revision", changed.at("revision")},
|
||||
{"settings", {{"editor", {{"autosave", false}}}}}});
|
||||
require(autosave_off.at("settings").at("editor").at("autosave") == false &&
|
||||
session.project().at("editor").at("script_editor") ==
|
||||
external.at("editor").at("script_editor"),
|
||||
"test", "Autosave setting must merge without erasing the editor command");
|
||||
session.poll();
|
||||
require(commands.call("faset_autosave_status", Json::object()).at("enabled") == false,
|
||||
"test", "Autosave disable must take effect in the current session");
|
||||
{
|
||||
editor::Session reopened({root, path_from_utf8(FASET_TEST_ENGINE), {}});
|
||||
reopened.poll();
|
||||
require(reopened.commands()
|
||||
.call("faset_autosave_status", Json::object())
|
||||
.at("enabled") == false,
|
||||
"test", "Autosave setting must survive Editor reopen");
|
||||
}
|
||||
rejects({{"revision", changed.at("revision")},
|
||||
{"settings", {{"editor", {{"autosave", true}}}}}},
|
||||
"revision.conflict");
|
||||
rejects({{"revision", autosave_off.at("revision")},
|
||||
{"settings", {{"editor", {{"autosave", "sometimes"}}}}}},
|
||||
"project.autosave");
|
||||
rejects({{"revision", autosave_off.at("revision")},
|
||||
{"settings", {{"editor", {{"script_editor", {"other"}}}}}}},
|
||||
"project.setting");
|
||||
changed = commands.call("faset_project_settings_set",
|
||||
{{"revision", autosave_off.at("revision")},
|
||||
{"settings", {{"editor", {{"autosave", true}}}}}});
|
||||
session.poll();
|
||||
require(commands.call("faset_autosave_status", Json::object()).at("enabled") == true,
|
||||
"test", "Autosave enable must take effect in the current session");
|
||||
const auto setup = commands.call("faset_lua_setup", Json::object());
|
||||
require(setup.at("configuration_created") == true &&
|
||||
setup.at("scripts_configuration_created") == true &&
|
||||
@@ -193,3 +237,12 @@ int main(int argc, char** argv) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
int wmain(int argc, wchar_t** argv) {
|
||||
return run_utf8_main(argc, argv, test_main);
|
||||
}
|
||||
#else
|
||||
int main(int argc, char** argv) {
|
||||
return test_main(argc, argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <faset/core/io.hpp>
|
||||
#include <faset/editor/editor_ui.hpp>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
using namespace faset;
|
||||
namespace {
|
||||
void check(bool value, const std::string& message) {
|
||||
@@ -50,6 +52,7 @@ int main() {
|
||||
{"id", new_id()},
|
||||
{"name", "Original project"},
|
||||
{"dimension", 3},
|
||||
{"editor", {{"script_editor", {"zed", "{file}"}}}},
|
||||
{"custom_metadata", {{"preserve", true}}}});
|
||||
editor::Session session({root, path_from_utf8(FASET_TEST_ENGINE), root});
|
||||
render::Renderer renderer({1280, 800, "Project settings acceptance", true, true});
|
||||
@@ -73,6 +76,13 @@ int main() {
|
||||
open(ui);
|
||||
check(ui.widgets().find("project-settings-name")->text == "Original project",
|
||||
"Opening settings reloads current saved values");
|
||||
check(ui.widgets().find("project-settings-autosave")->checked,
|
||||
"Missing autosave setting appears enabled in Project settings");
|
||||
check(ui.widgets().focus("project-settings-autosave"),
|
||||
"Keyboard focus reaches the Autosave toggle");
|
||||
ui.frame({key("Space")});
|
||||
check(!ui.widgets().find("project-settings-autosave")->checked,
|
||||
"Space toggles Autosave from the keyboard");
|
||||
text(ui, "project-settings-name", "Новый проект");
|
||||
click(ui, "project-settings-2d");
|
||||
click(ui, "project-scene-choice-1");
|
||||
@@ -81,11 +91,25 @@ int main() {
|
||||
click(ui, "project-settings-save");
|
||||
auto saved = read_json(project_file);
|
||||
check(saved["name"] == "Новый проект" && saved["dimension"] == 2 &&
|
||||
saved["start_scene"] == "Scenes/Другая.scene.json",
|
||||
saved["start_scene"] == "Scenes/Другая.scene.json" &&
|
||||
saved["editor"]["autosave"] == false,
|
||||
"Explicit Save project persists typed settings");
|
||||
check(saved["custom_metadata"] == project_before["custom_metadata"] &&
|
||||
saved["id"] == project_before["id"],
|
||||
saved["id"] == project_before["id"] &&
|
||||
saved["editor"]["script_editor"] ==
|
||||
project_before["editor"]["script_editor"],
|
||||
"Project settings preserve unknown metadata and project identity");
|
||||
ui.frame({});
|
||||
check(ui.widgets().find("autosave-status")->text == "Autosave off",
|
||||
"Disabling Autosave is visible in the Editor status bar");
|
||||
open(ui);
|
||||
check(!ui.widgets().find("project-settings-autosave")->checked,
|
||||
"Autosave preference is restored when reopening Project settings");
|
||||
click(ui, "project-settings-autosave");
|
||||
click(ui, "project-settings-save");
|
||||
saved = read_json(project_file);
|
||||
check(saved["editor"]["autosave"] == true,
|
||||
"Autosave can be enabled again through Project settings");
|
||||
check(session.authoring().query(ui.current_document()) == document_before,
|
||||
"Project settings do not change current document, dimension, revision or Undo");
|
||||
open(ui);
|
||||
@@ -118,6 +142,51 @@ int main() {
|
||||
"Save after explicit reload uses new content revision");
|
||||
check(session.authoring().query(ui.current_document()) == document_before,
|
||||
"Project settings remain outside scene Undo throughout conflicts");
|
||||
const auto original_document = ui.current_document();
|
||||
const auto revision =
|
||||
session.authoring().query(original_document).at("revision").get<std::uint64_t>();
|
||||
session.authoring().transact(
|
||||
original_document, revision,
|
||||
Json::array({{{"op", "scene.rename"}, {"name", "Pending autosave"}}}));
|
||||
ui.frame({});
|
||||
check(ui.widgets().find("autosave-status")->text == "Pending autosave",
|
||||
"Status bar shows pending scene save after edit");
|
||||
session.authoring().save(original_document);
|
||||
ui.frame({});
|
||||
check(ui.widgets().find("autosave-status")->text == "Saved",
|
||||
"Status bar returns to Saved after the scene reaches disk");
|
||||
session.authoring().transact(
|
||||
original_document,
|
||||
session.authoring().query(original_document).at("revision"),
|
||||
Json::array({{{"op", "scene.rename"}, {"name", "Conflicting autosave"}}}));
|
||||
ui.frame({});
|
||||
auto disk_scene = read_json(root / "Scenes/Главная.scene.json");
|
||||
disk_scene["name"] = "External scene edit";
|
||||
atomic_write_json(root / "Scenes/Главная.scene.json", disk_scene);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(2100));
|
||||
ui.frame({});
|
||||
check(ui.widgets().find("autosave-status")->text == "Save conflict" &&
|
||||
ui.widgets().find("autosave-status")->tooltip.find("Save As") !=
|
||||
std::string::npos,
|
||||
"Disk conflict remains visible with Save As guidance");
|
||||
renderer.render(ui.snapshot());
|
||||
renderer.capture(root / "autosave-conflict.ppm");
|
||||
check(ui.widgets().focus("autosave-save-as"),
|
||||
"Keyboard focus reaches the recovery Save As action");
|
||||
ui.frame({key("Return")});
|
||||
check(ui.widgets().find("menu-popup")->visible &&
|
||||
ui.widgets().find("save-path")->visible,
|
||||
"Recovery action opens an editable Save As path");
|
||||
ui.frame({key("Escape")});
|
||||
const auto unnamed = session.authoring().create("Unsaved", 2);
|
||||
session.authoring().transact(
|
||||
unnamed.at("id"), unnamed.at("revision"),
|
||||
Json::array({{{"op", "scene.rename"}, {"name", "Needs a path"}}}));
|
||||
ui.select_document(unnamed.at("id"));
|
||||
ui.frame({});
|
||||
check(ui.widgets().find("autosave-status")->text == "Save As required" &&
|
||||
ui.widgets().find("autosave-save-as")->visible,
|
||||
"Unnamed dirty scene is never assigned an implicit path");
|
||||
open(ui);
|
||||
renderer.render(ui.snapshot());
|
||||
renderer.capture(root / "project-settings.ppm");
|
||||
|
||||
Reference in New Issue
Block a user