mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-21 18:02:09 +00:00
fix: old preset names should resolved renamed_from field (#14429)
* fix: old preset names should resolved renamed_from field * chore: remove misleading comments * Merge branch 'main' into fix/consider_renamed_from * normalize_inherits * improve find_preset2 performace
This commit is contained in:
@@ -36,6 +36,47 @@ void write_print_preset(const DynamicPrintConfig &default_config, const fs::path
|
||||
config.save_to_json(file.string(), name, "User", "1.0.0");
|
||||
}
|
||||
|
||||
// Write a preset json carrying a name and an "inherits" value, using the given collection's
|
||||
// default config so it loads back into that collection. Works for any preset type.
|
||||
void write_preset_with_inherits(const DynamicPrintConfig &default_config, const fs::path &file,
|
||||
const std::string &name, const std::string &inherits)
|
||||
{
|
||||
DynamicPrintConfig config(default_config);
|
||||
config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS, true)->value = inherits;
|
||||
|
||||
fs::create_directories(file.parent_path());
|
||||
config.save_to_json(file.string(), name, "User", "1.0.0");
|
||||
}
|
||||
|
||||
// Add an in-memory preset (no file) with the given inherits value (empty => root preset).
|
||||
Preset &add_inmemory_preset(PresetCollection &coll, const std::string &name, const std::string &inherits = {})
|
||||
{
|
||||
DynamicPrintConfig config(coll.default_preset().config);
|
||||
config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS, true)->value = inherits;
|
||||
return coll.load_preset(std::string(), name, config, /*select=*/false);
|
||||
}
|
||||
|
||||
// Mark an already-loaded preset as renamed from one or more former names.
|
||||
void set_renamed_from(PresetCollection &coll, const std::string &preset_name, std::vector<std::string> old_names)
|
||||
{
|
||||
for (auto it = coll.begin(); it != coll.end(); ++it)
|
||||
if (it->name == preset_name)
|
||||
it->renamed_from = std::move(old_names);
|
||||
}
|
||||
|
||||
// A standalone print preset collection that exposes the protected rename-map builder, so a
|
||||
// renamed_from scenario can be set up without the full system-profile load pipeline.
|
||||
// (PresetCollection is non-copyable - it holds a mutex - so it is constructed directly with
|
||||
// the same type/keys/defaults PresetBundle uses for its print collection.)
|
||||
struct RenameTestCollection : public PresetCollection
|
||||
{
|
||||
RenameTestCollection()
|
||||
: PresetCollection(Preset::TYPE_PRINT, Preset::print_options(),
|
||||
static_cast<const PrintRegionConfig &>(FullPrintConfig::defaults()))
|
||||
{}
|
||||
using PresetCollection::update_map_system_profile_renamed;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Preset identity is canonicalized from load path", "[Preset][Identity]")
|
||||
@@ -130,3 +171,130 @@ TEST_CASE("Printer extruder count tolerates missing nozzle diameter", "[Preset][
|
||||
CHECK(bundle.get_printer_extruder_count() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("find_preset resolves a system preset's renamed_from", "[Preset][Rename]")
|
||||
{
|
||||
RenameTestCollection coll;
|
||||
|
||||
// "New Process" is the current preset; it was renamed from "Old Process".
|
||||
add_inmemory_preset(coll, "New Process");
|
||||
set_renamed_from(coll, "New Process", { "Old Process" });
|
||||
coll.update_map_system_profile_renamed();
|
||||
|
||||
// The rename map knows the old name...
|
||||
const std::string *renamed = coll.get_preset_name_renamed("Old Process");
|
||||
REQUIRE(renamed != nullptr);
|
||||
CHECK(*renamed == "New Process");
|
||||
|
||||
// ...and plain find_preset() now follows it (the core of this PR; previously this
|
||||
// resolution lived only in find_preset2 and a few call sites).
|
||||
const Preset *resolved = coll.find_preset("Old Process");
|
||||
REQUIRE(resolved != nullptr);
|
||||
CHECK(resolved->name == "New Process");
|
||||
|
||||
// A genuinely unknown name still returns null (no spurious match).
|
||||
CHECK(coll.find_preset("Totally Unknown") == nullptr);
|
||||
|
||||
// A child that still inherits the OLD name resolves through the runtime walker,
|
||||
// which uses plain find_preset().
|
||||
Preset &child = add_inmemory_preset(coll, "Child Process", "Old Process");
|
||||
const Preset *parent = coll.get_preset_parent(child);
|
||||
REQUIRE(parent != nullptr);
|
||||
CHECK(parent->name == "New Process");
|
||||
}
|
||||
|
||||
TEST_CASE("find_preset resolves a preset renamed more than once", "[Preset][Rename]")
|
||||
{
|
||||
RenameTestCollection coll;
|
||||
|
||||
// "New Process" was renamed twice, so it carries both former names in renamed_from.
|
||||
add_inmemory_preset(coll, "New Process");
|
||||
set_renamed_from(coll, "New Process", { "Original Process", "Old Process" });
|
||||
coll.update_map_system_profile_renamed();
|
||||
|
||||
// Each historical name resolves to the current preset.
|
||||
for (const char *old_name : { "Original Process", "Old Process" }) {
|
||||
INFO("resolving old name: " << old_name);
|
||||
const std::string *renamed = coll.get_preset_name_renamed(old_name);
|
||||
REQUIRE(renamed != nullptr);
|
||||
CHECK(*renamed == "New Process");
|
||||
|
||||
const Preset *resolved = coll.find_preset(old_name);
|
||||
REQUIRE(resolved != nullptr);
|
||||
CHECK(resolved->name == "New Process");
|
||||
}
|
||||
|
||||
// A child inheriting either former name resolves through the runtime walker.
|
||||
Preset &child = add_inmemory_preset(coll, "Child Process", "Original Process");
|
||||
REQUIRE(coll.get_preset_parent(child) != nullptr);
|
||||
CHECK(coll.get_preset_parent(child)->name == "New Process");
|
||||
}
|
||||
|
||||
TEST_CASE("find_preset2 auto-matches removed Generic vendor profiles to the library", "[Preset][Rename]")
|
||||
{
|
||||
PresetBundle bundle;
|
||||
|
||||
// The OrcaFilamentLibrary replacement that removed empty "<vendor> Generic" profiles map to.
|
||||
add_inmemory_preset(bundle.filaments, "Generic PLA @System");
|
||||
|
||||
// Plain lookups do NOT fuzzy-match a removed vendor profile.
|
||||
CHECK(bundle.filaments.find_preset("Voron Generic PLA") == nullptr);
|
||||
CHECK(bundle.filaments.find_preset2("Voron Generic PLA", /*auto_match=*/false) == nullptr);
|
||||
|
||||
// With auto_match, the removed "Voron Generic PLA" resolves to "Generic PLA @System".
|
||||
const Preset *matched = bundle.filaments.find_preset2("Voron Generic PLA", /*auto_match=*/true);
|
||||
REQUIRE(matched != nullptr);
|
||||
CHECK(matched->name == "Generic PLA @System");
|
||||
|
||||
// No library preset exists for an unrelated material => still no match.
|
||||
CHECK(bundle.filaments.find_preset2("BrandX Generic PETG", /*auto_match=*/true) == nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE("Renamed parent is normalized into a loaded preset's inherits", "[Preset][Rename]")
|
||||
{
|
||||
TempPresetDir temp_dir;
|
||||
RenameTestCollection coll;
|
||||
|
||||
// Current parent, renamed from "Old Process".
|
||||
add_inmemory_preset(coll, "New Process");
|
||||
set_renamed_from(coll, "New Process", { "Old Process" });
|
||||
coll.update_map_system_profile_renamed();
|
||||
|
||||
// A user preset on disk that still inherits the OLD name.
|
||||
write_preset_with_inherits(coll.default_preset().config,
|
||||
temp_dir.path / PRESET_PRINT_NAME / "Child.json", "Child", "Old Process");
|
||||
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
coll.load_presets(temp_dir.path.string(), PRESET_PRINT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::Disable);
|
||||
|
||||
const Preset *child = coll.find_preset("Child");
|
||||
REQUIRE(child != nullptr);
|
||||
// The dangling "Old Process" was rewritten to the resolved parent name at load time,
|
||||
// so the runtime walker (plain find_preset) can resolve the chain.
|
||||
CHECK(child->inherits() == "New Process");
|
||||
REQUIRE(coll.get_preset_parent(*child) != nullptr);
|
||||
CHECK(coll.get_preset_parent(*child)->name == "New Process");
|
||||
}
|
||||
|
||||
TEST_CASE("Removed Generic parent is normalized into a loaded filament's inherits", "[Preset][Rename]")
|
||||
{
|
||||
TempPresetDir temp_dir;
|
||||
PresetBundle bundle;
|
||||
|
||||
add_inmemory_preset(bundle.filaments, "Generic PLA @System");
|
||||
|
||||
// A user filament that still inherits a removed "<vendor> Generic PLA" profile.
|
||||
write_preset_with_inherits(bundle.filaments.default_preset().config,
|
||||
temp_dir.path / PRESET_FILAMENT_NAME / "MyPLA.json", "MyPLA", "Voron Generic PLA");
|
||||
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
bundle.filaments.load_presets(temp_dir.path.string(), PRESET_FILAMENT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::Disable);
|
||||
|
||||
const Preset *child = bundle.filaments.find_preset("MyPLA");
|
||||
REQUIRE(child != nullptr);
|
||||
CHECK(child->inherits() == "Generic PLA @System");
|
||||
REQUIRE(bundle.filaments.get_preset_parent(*child) != nullptr);
|
||||
CHECK(bundle.filaments.get_preset_parent(*child)->name == "Generic PLA @System");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user