mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-25 03:42:05 +00:00
Support the 02.08.01 network plug-in and resync the Bambu device workflow (#14837)
# Description Support the 02.08.01 network plug-in and resync the Bambu device workflow Brings the Bambu network plug-in up to the 02.08.01 series and reworks the plug-in lifecycle around it (ABI gating, OTA install, hot reload), then catches the device and monitor side up to what that plug-in and current firmware expose — AMS mapping, send-flow checks, print options, and the device status pages. **Included:** _Network plug-in_ - Default to the 02.08.01 series and bind its new ABI symbols; bump the reported `SLIC3R_VERSION` to 02.08.01.55 - Gate loading to ABI-compatible `AA.BB.CC` series, and store plug-in identity by series rather than by exact build - Fix the OTA update flow: install immediately, hot-reload without a restart, and destroy the agent before unloading the DLL - Version selector lists same-series OTA builds newest first, with dynamic "(Latest)" / "(installed)" labels - Restart printer discovery and reload saved LAN printers after a hot reload _Device layer_ - Move axis, calibration, chamber, status and upgrade handling into DeviceCore; drop the transitional shims - Resync the DeviceCore state models, accessory firmware versions, cold-pull state and filament checks _Device UI_ - Resync the AMS control/item widgets, device dialogs, device tab widgets and status pages - Add the AMS best-position popup, filament-change stop button, hub version row and HMS fallback - Device error dialog: print-failure snapshot, purification and don't-remind actions _Send flow_ - Resync the send flow and port the remaining pre-send checks and advisories - Warn when a filament will switch extruders mid-print; block TPU on the l without firmware support (O1D/O1E) - Map switch-bound AMS trays to both extruders and show combined nozzle mapping - Add the shared-PA-profile toggle _Print options / timelapse_ - Restructure DevPrintOptions around a detection-option map and parse the bits on the live push path - Add firmware print-option toggles, plus timelapse storage-location selection with a free-space check _Fixes_ - Inverted MQTT jog on i3-architecture printers, plus assorted popup, mapping and status-parse defects _Tests_ - New Catch2 coverage for network version selection and device filament mapping Printers that don't advertise the new capabilities are unaffected — every added behavior is gated on a firmware or plug-in capability flag, and the only profile chang `support_print_check_firmware_for_tpu_left` to O1D/O1E. # Screenshots/Recordings/Graphs <img width="714" height="500" alt="image" src="https://github.com/user-attachments/assets/33e54581-3fb0-4a3e-b80c-afa8adfabe4c" /> <img width="530" height="212" alt="image" src="https://github.com/user-attachments/assets/d0c55fd5-74c3-4aab-81a5-786d0aaf8828" /> <img width="483" height="527" alt="image" src="https://github.com/user-attachments/assets/71ceaad1-a082-41cb-aa1a-4b9abb30d9db" /> ## Tests <!-- > Please describe the tests that you have conducted to verify the changes made in this PR. --> <!-- > A guide for users on how to download the artifacts from this PR. --> [How to Download Pull Requests Artifacts for Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
This commit is contained in:
@@ -59,7 +59,9 @@ TEST_CASE("NetworkLibraryVersionInfo::from_static", "[BambuNetworking]") {
|
||||
REQUIRE(info.suffix == "");
|
||||
REQUIRE(info.display_name == "02.03.00.62");
|
||||
REQUIRE(info.url_override == "");
|
||||
REQUIRE(info.is_latest == true);
|
||||
// from_static no longer propagates the static is_latest flag; it is a placeholder
|
||||
// that get_all_available_versions() assigns once the list is sorted newest-first.
|
||||
REQUIRE(info.is_latest == false);
|
||||
REQUIRE(info.warning == "");
|
||||
REQUIRE(info.is_discovered == false);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
|
||||
add_executable(${_TEST_NAME}_tests
|
||||
${_TEST_NAME}_tests_main.cpp
|
||||
test_dev_mapping.cpp
|
||||
test_network_versions.cpp
|
||||
test_action_source.cpp
|
||||
test_plugin_host_api.cpp
|
||||
test_plugin_capability_config.cpp
|
||||
|
||||
195
tests/slic3rutils/test_dev_mapping.cpp
Normal file
195
tests/slic3rutils/test_dev_mapping.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
// Match the include environment that libslic3r_gui TUs get from pchheader.hpp: Windows.h with
|
||||
// WIN32_LEAN_AND_MEAN/NOMINMAX must come first so rpcndr.h's `byte` is processed before <cstddef>
|
||||
// makes std::byte a competing candidate (otherwise the Windows COM headers pulled in via
|
||||
// DeviceManager.hpp error with an ambiguous `byte`). wx/timer.h must precede DeviceManager.hpp,
|
||||
// which includes DeviceErrorDialog.hpp (uses wxTimerEvent) before its own wx/timer.h include.
|
||||
#ifdef WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <wx/timer.h>
|
||||
|
||||
#include "slic3r/GUI/DeviceManager.hpp"
|
||||
#include "slic3r/GUI/DeviceCore/DevMapping.h"
|
||||
#include "slic3r/GUI/DeviceCore/DevFilaSystem.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
using namespace Slic3r;
|
||||
|
||||
TEST_CASE("Switch-bound AMS trays map to the left extruder", "[DevMapping]")
|
||||
{
|
||||
MachineObject obj(nullptr, nullptr, "test", "test_dev", "127.0.0.1");
|
||||
|
||||
// aux bit 29 = Filament Track Switch installed (DevFilaSwitch.cpp:69-77)
|
||||
obj.GetFilaSwitch()->ParseFilaSwitchInfo(json::parse(R"({"aux":"20000000"})"));
|
||||
REQUIRE(obj.GetFilaSwitch()->IsInstalled());
|
||||
|
||||
// info bits: 0-3 type(1=AMS), 8-11 extruder(0xE=switch-bound), 24-27 bind_switch_in(0)
|
||||
// tray_exist_bits bit 0 marks AMS 0 / tray 0 present so the mapping result survives the
|
||||
// is_exists check in is_valid_mapping_result (DevFilaSystem.cpp:769).
|
||||
// tray_info_idx/tray_type are intentionally omitted: the tray parse resolves the display
|
||||
// filament type via MachineObject::setting_id_to_type(), which reads the GUI preset bundle
|
||||
// (wxGetApp().preset_bundle) — unavailable in this headless unit test. The tray filament
|
||||
// type (only needed for the type-match below) is set directly after the parse instead.
|
||||
json print_push = json::parse(R"({
|
||||
"ams": {
|
||||
"tray_exist_bits": "1",
|
||||
"ams": [ {
|
||||
"id": "0",
|
||||
"info": "00000E01",
|
||||
"tray": [ { "id": "0", "tray_color": "FF0000FF" } ]
|
||||
} ]
|
||||
}
|
||||
})");
|
||||
DevFilaSystemParser::ParseV1_0(print_push, &obj, obj.GetFilaSystem().get(), false);
|
||||
|
||||
const auto& ams_list = obj.GetFilaSystem()->GetAmsList();
|
||||
REQUIRE(ams_list.count("0") == 1);
|
||||
REQUIRE(ams_list.at("0")->GetBindedExtruderSet().count(MAIN_EXTRUDER_ID) == 1);
|
||||
REQUIRE(ams_list.at("0")->GetBindedExtruderSet().count(DEPUTY_EXTRUDER_ID) == 1);
|
||||
|
||||
DevAmsTray* tray = obj.GetFilaSystem()->GetAmsTray("0", "0");
|
||||
REQUIRE(tray != nullptr);
|
||||
tray->m_fila_type = "PLA";
|
||||
|
||||
FilamentInfo fila;
|
||||
fila.id = 0;
|
||||
fila.type = "PLA";
|
||||
fila.color = "FF0000FF";
|
||||
|
||||
std::vector<FilamentInfo> result;
|
||||
std::vector<bool> map_opt(4, false); // MappingOption: LEFT_AMS,RIGHT_AMS,LEFT_EXT,RIGHT_EXT (DevMapping.h:13-19)
|
||||
map_opt[MappingOption::USE_LEFT_AMS] = true;
|
||||
|
||||
DevMappingUtil::ams_filament_mapping(&obj, {fila}, result, map_opt, {}, false);
|
||||
|
||||
// A switch-bound AMS feeds BOTH extruders, so a left-only mapping request
|
||||
// must still land the filament on the AMS tray.
|
||||
REQUIRE(result.size() == 1);
|
||||
CHECK(result[0].tray_id == 0);
|
||||
CHECK(result[0].ams_id == "0");
|
||||
}
|
||||
|
||||
TEST_CASE("Without a switch the binding set equals the single bound extruder", "[DevMapping]")
|
||||
{
|
||||
MachineObject obj(nullptr, nullptr, "test", "test_dev", "127.0.0.1");
|
||||
REQUIRE_FALSE(obj.GetFilaSwitch()->IsInstalled());
|
||||
|
||||
// AMS 0: info extruder nibble = MAIN (right). AMS 1: nibble = DEPUTY (left).
|
||||
// AMS 2: no "info" key at all (old X1/P1 firmware) -> must default to MAIN.
|
||||
// tray_exist_bits: bit ams_id*4+tray_id -> 0x111 marks tray 0 of each AMS.
|
||||
json print_push = json::parse(R"({
|
||||
"ams": {
|
||||
"tray_exist_bits": "111",
|
||||
"ams": [
|
||||
{ "id": "0", "info": "00000001", "tray": [ { "id": "0", "tray_color": "FF0000FF" } ] },
|
||||
{ "id": "1", "info": "00000101", "tray": [ { "id": "0", "tray_color": "00FF00FF" } ] },
|
||||
{ "id": "2", "tray": [ { "id": "0", "tray_color": "0000FFFF" } ] }
|
||||
]
|
||||
}
|
||||
})");
|
||||
DevFilaSystemParser::ParseV1_0(print_push, &obj, obj.GetFilaSystem().get(), false);
|
||||
|
||||
// The invariant that keeps the binding-set mapping filter behavior-preserving for
|
||||
// ordinary printers: GetBindedExtruderSet() == { GetExtruderId() }, info key or not.
|
||||
const auto& ams_list = obj.GetFilaSystem()->GetAmsList();
|
||||
REQUIRE(ams_list.count("0") == 1);
|
||||
REQUIRE(ams_list.count("1") == 1);
|
||||
REQUIRE(ams_list.count("2") == 1);
|
||||
for (const char* id : {"0", "1", "2"}) {
|
||||
const auto& ams = ams_list.at(id);
|
||||
INFO("ams " << id);
|
||||
REQUIRE(ams->GetBindedExtruderSet().size() == 1);
|
||||
REQUIRE(ams->GetBindedExtruderSet().count(ams->GetExtruderId()) == 1);
|
||||
}
|
||||
REQUIRE(ams_list.at("0")->GetExtruderId() == MAIN_EXTRUDER_ID);
|
||||
REQUIRE(ams_list.at("1")->GetExtruderId() == DEPUTY_EXTRUDER_ID);
|
||||
REQUIRE(ams_list.at("2")->GetExtruderId() == MAIN_EXTRUDER_ID);
|
||||
|
||||
for (const char* id : {"0", "1", "2"}) {
|
||||
DevAmsTray* tray = obj.GetFilaSystem()->GetAmsTray(id, "0");
|
||||
REQUIRE(tray != nullptr);
|
||||
tray->m_fila_type = "PLA";
|
||||
}
|
||||
|
||||
// A left-only request must exclude the MAIN-bound AMSes: the red filament exactly
|
||||
// matches AMS 0's red tray, so landing anywhere but AMS 1 (or unmapped) means the
|
||||
// exclusion is broken.
|
||||
FilamentInfo fila;
|
||||
fila.id = 0;
|
||||
fila.type = "PLA";
|
||||
fila.color = "FF0000FF";
|
||||
|
||||
std::vector<FilamentInfo> result;
|
||||
std::vector<bool> map_opt(4, false);
|
||||
map_opt[MappingOption::USE_LEFT_AMS] = true;
|
||||
DevMappingUtil::ams_filament_mapping(&obj, {fila}, result, map_opt, {}, false);
|
||||
REQUIRE(result.size() == 1);
|
||||
CHECK(result[0].ams_id != "0");
|
||||
CHECK(result[0].ams_id != "2");
|
||||
|
||||
// The mirrored right-only request maps to the exact-match MAIN-bound AMS.
|
||||
result.clear();
|
||||
map_opt[MappingOption::USE_LEFT_AMS] = false;
|
||||
map_opt[MappingOption::USE_RIGHT_AMS] = true;
|
||||
DevMappingUtil::ams_filament_mapping(&obj, {fila}, result, map_opt, {}, false);
|
||||
REQUIRE(result.size() == 1);
|
||||
CHECK(result[0].ams_id == "0");
|
||||
}
|
||||
|
||||
TEST_CASE("Switch-bound AMS with an invalid track is excluded from mapping", "[DevMapping]")
|
||||
{
|
||||
MachineObject obj(nullptr, nullptr, "test", "test_dev", "127.0.0.1");
|
||||
obj.GetFilaSwitch()->ParseFilaSwitchInfo(json::parse(R"({"aux":"20000000"})"));
|
||||
REQUIRE(obj.GetFilaSwitch()->IsInstalled());
|
||||
|
||||
// info bits 24-27 = 0xF: switch-bound (0xE) but the input track is not yet valid -
|
||||
// the transient while the device is still homing the switch. The AMS must survive
|
||||
// (display keeps working) with an EMPTY binding set that excludes it from mapping.
|
||||
json print_push = json::parse(R"({
|
||||
"ams": {
|
||||
"tray_exist_bits": "1",
|
||||
"ams": [ { "id": "0", "info": "0F000E01", "tray": [ { "id": "0", "tray_color": "FF0000FF" } ] } ]
|
||||
}
|
||||
})");
|
||||
DevFilaSystemParser::ParseV1_0(print_push, &obj, obj.GetFilaSystem().get(), false);
|
||||
|
||||
const auto& ams_list = obj.GetFilaSystem()->GetAmsList();
|
||||
REQUIRE(ams_list.count("0") == 1);
|
||||
REQUIRE(ams_list.at("0")->GetBindedExtruderSet().empty());
|
||||
REQUIRE_FALSE(ams_list.at("0")->GetSwitcherPos().has_value());
|
||||
REQUIRE_FALSE(obj.GetFilaSwitch()->IsReady());
|
||||
|
||||
DevAmsTray* tray = obj.GetFilaSystem()->GetAmsTray("0", "0");
|
||||
REQUIRE(tray != nullptr);
|
||||
tray->m_fila_type = "PLA";
|
||||
|
||||
FilamentInfo fila;
|
||||
fila.id = 0;
|
||||
fila.type = "PLA";
|
||||
fila.color = "FF0000FF";
|
||||
|
||||
std::vector<FilamentInfo> result;
|
||||
std::vector<bool> map_opt(4, false);
|
||||
map_opt[MappingOption::USE_LEFT_AMS] = true;
|
||||
map_opt[MappingOption::USE_RIGHT_AMS] = true;
|
||||
DevMappingUtil::ams_filament_mapping(&obj, {fila}, result, map_opt, {}, false);
|
||||
REQUIRE(result.size() == 1);
|
||||
CHECK(result[0].tray_id == -1);
|
||||
|
||||
// Without the switch, the same 0xE AMS is dropped from the list entirely.
|
||||
MachineObject obj_no_switch(nullptr, nullptr, "test", "test_dev", "127.0.0.1");
|
||||
REQUIRE_FALSE(obj_no_switch.GetFilaSwitch()->IsInstalled());
|
||||
DevFilaSystemParser::ParseV1_0(print_push, &obj_no_switch, obj_no_switch.GetFilaSystem().get(), false);
|
||||
REQUIRE(obj_no_switch.GetFilaSystem()->GetAmsList().count("0") == 0);
|
||||
}
|
||||
199
tests/slic3rutils/test_network_versions.cpp
Normal file
199
tests/slic3rutils/test_network_versions.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "slic3r/Utils/bambu_networking.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace {
|
||||
|
||||
// Platform naming used by BBLNetworkPlugin::scan_plugin_versions().
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
static const char* PLUGIN_PREFIX = "bambu_networking_";
|
||||
static const char* PLUGIN_EXT = ".dll";
|
||||
#elif defined(__WXMAC__) || defined(__APPLE__)
|
||||
static const char* PLUGIN_PREFIX = "libbambu_networking_";
|
||||
static const char* PLUGIN_EXT = ".dylib";
|
||||
#else
|
||||
static const char* PLUGIN_PREFIX = "libbambu_networking_";
|
||||
static const char* PLUGIN_EXT = ".so";
|
||||
#endif
|
||||
|
||||
struct PluginFolderFixture
|
||||
{
|
||||
fs::path root;
|
||||
std::string previous_data_dir;
|
||||
|
||||
PluginFolderFixture()
|
||||
{
|
||||
previous_data_dir = data_dir();
|
||||
root = fs::temp_directory_path() / fs::unique_path("orca-netver-%%%%%%%%");
|
||||
fs::create_directories(root / "plugins");
|
||||
set_data_dir(root.string());
|
||||
}
|
||||
|
||||
~PluginFolderFixture()
|
||||
{
|
||||
set_data_dir(previous_data_dir);
|
||||
boost::system::error_code ec;
|
||||
fs::remove_all(root, ec);
|
||||
}
|
||||
|
||||
void add_plugin(const std::string& version)
|
||||
{
|
||||
boost::nowide::ofstream f((root / "plugins" / (PLUGIN_PREFIX + version + PLUGIN_EXT)).string());
|
||||
f << "stub";
|
||||
}
|
||||
};
|
||||
|
||||
int count_version(const std::vector<NetworkLibraryVersionInfo>& versions, const std::string& v)
|
||||
{
|
||||
int n = 0;
|
||||
for (const auto& info : versions)
|
||||
if (info.version == v)
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Series and managed classification", "[NetworkVersions]")
|
||||
{
|
||||
// The AA.BB.CC series is the stored identity of every modern build.
|
||||
CHECK(network_plugin_series("02.08.01.53") == "02.08.01");
|
||||
CHECK(network_plugin_series("02.08.01") == "02.08.01"); // idempotent
|
||||
CHECK(network_plugin_series("02.08.01_custom") == "02.08.01");
|
||||
CHECK(network_plugin_series("02.08.01.52-dev") == "02.08.01");
|
||||
CHECK(network_plugin_series(BAMBU_NETWORK_AGENT_VERSION_LEGACY) == BAMBU_NETWORK_AGENT_VERSION_LEGACY);
|
||||
CHECK(network_plugin_series("").empty());
|
||||
|
||||
// Only pure dotted-numeric builds collapse into their series entry; legacy and any
|
||||
// custom-named build keep their own identity.
|
||||
CHECK(is_series_managed_version("02.08.01"));
|
||||
CHECK(is_series_managed_version("02.08.01.53"));
|
||||
CHECK_FALSE(is_series_managed_version("02.08.01_custom"));
|
||||
CHECK_FALSE(is_series_managed_version("02.08.01.52-dev"));
|
||||
CHECK_FALSE(is_series_managed_version(BAMBU_NETWORK_AGENT_VERSION_LEGACY));
|
||||
CHECK_FALSE(is_series_managed_version(""));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(PluginFolderFixture, "Managed builds fold into the series; customs are surfaced", "[NetworkVersions]")
|
||||
{
|
||||
add_plugin("02.08.01.55"); // managed, same series -> folded into the 02.08.01 row
|
||||
add_plugin("02.09.00.10"); // managed, unknown series -> not listed
|
||||
add_plugin("02.03.00.62"); // managed, series no longer whitelisted -> not listed
|
||||
add_plugin("02.08.01_custom"); // custom, whitelisted series -> listed under it
|
||||
add_plugin("02.08.01.52-dev"); // custom (dash-suffixed), whitelisted series -> listed
|
||||
|
||||
auto versions = get_all_available_versions();
|
||||
|
||||
// The specific managed build never gets its own row - the series represents it.
|
||||
REQUIRE(count_version(versions, "02.08.01.55") == 0);
|
||||
REQUIRE(count_version(versions, "02.08.01") == 1);
|
||||
REQUIRE(count_version(versions, "02.09.00.10") == 0);
|
||||
REQUIRE(count_version(versions, "02.03.00.62") == 0);
|
||||
// Custom-named builds are distinct files kept under their own name.
|
||||
REQUIRE(count_version(versions, "02.08.01_custom") == 1);
|
||||
REQUIRE(count_version(versions, "02.08.01.52-dev") == 1);
|
||||
|
||||
// Newest series first, its customs nested under it (suffix sort: "" < ".52-dev" < "_custom"),
|
||||
// legacy last.
|
||||
REQUIRE(versions[0].version == "02.08.01");
|
||||
REQUIRE(versions[1].version == "02.08.01.52-dev");
|
||||
REQUIRE(versions[2].version == "02.08.01_custom");
|
||||
REQUIRE(versions.back().version == BAMBU_NETWORK_AGENT_VERSION_LEGACY);
|
||||
|
||||
// Customs sort/render nested under their series (non-empty suffix, base = the series).
|
||||
REQUIRE(versions[1].base_version == "02.08.01");
|
||||
REQUIRE_FALSE(versions[1].suffix.empty());
|
||||
REQUIRE(versions[2].base_version == "02.08.01");
|
||||
REQUIRE_FALSE(versions[2].suffix.empty());
|
||||
|
||||
// "(Latest)" is the series row, never a nested custom build.
|
||||
REQUIRE(versions[0].suffix.empty());
|
||||
REQUIRE(versions[0].is_latest);
|
||||
REQUIRE_FALSE(versions[1].is_latest);
|
||||
REQUIRE_FALSE(versions[2].is_latest);
|
||||
|
||||
// The stored default that drives download and update-check decisions is now the series.
|
||||
REQUIRE(std::string(get_latest_network_version()) == "02.08.01");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(PluginFolderFixture, "Only the loaded series is marked installed", "[NetworkVersions]")
|
||||
{
|
||||
add_plugin("02.08.01.55");
|
||||
add_plugin("02.08.01_custom");
|
||||
|
||||
// The loaded plug-in reports its full build (02.08.01.55); the series row is what gets marked.
|
||||
{
|
||||
auto versions = get_all_available_versions("02.08.01.55");
|
||||
int marked = 0;
|
||||
for (const auto& info : versions)
|
||||
if (info.is_loaded) { ++marked; REQUIRE(info.version == "02.08.01"); }
|
||||
REQUIRE(marked == 1);
|
||||
}
|
||||
|
||||
// A loaded custom build matches its own row, never the bare series.
|
||||
{
|
||||
auto versions = get_all_available_versions("02.08.01_custom");
|
||||
int marked = 0;
|
||||
for (const auto& info : versions)
|
||||
if (info.is_loaded) { ++marked; REQUIRE(info.version == "02.08.01_custom"); }
|
||||
REQUIRE(marked == 1);
|
||||
}
|
||||
|
||||
// Nothing loaded marks nothing, even though libraries are on disk.
|
||||
for (const auto& info : get_all_available_versions(""))
|
||||
REQUIRE_FALSE(info.is_loaded);
|
||||
}
|
||||
|
||||
TEST_CASE("Only whitelisted series pass the load gate", "[NetworkVersions]")
|
||||
{
|
||||
// The whitelisted series, its builds, and custom-named builds of that series.
|
||||
REQUIRE(is_supported_network_version("02.08.01"));
|
||||
REQUIRE(is_supported_network_version("02.08.01.52"));
|
||||
REQUIRE(is_supported_network_version("02.08.01.55"));
|
||||
REQUIRE(is_supported_network_version("02.08.01_custom"));
|
||||
REQUIRE(is_supported_network_version("02.08.01.52-dev"));
|
||||
REQUIRE(is_supported_network_version(BAMBU_NETWORK_AGENT_VERSION_LEGACY));
|
||||
|
||||
// Series whitelisted by previous Orca releases - their ABI no longer matches.
|
||||
REQUIRE_FALSE(is_supported_network_version("02.03.00.62"));
|
||||
REQUIRE_FALSE(is_supported_network_version("02.01.01.52"));
|
||||
REQUIRE_FALSE(is_supported_network_version("02.00.02.50"));
|
||||
|
||||
// Unknown series, legacy siblings, and malformed values.
|
||||
REQUIRE_FALSE(is_supported_network_version("02.09.00.10"));
|
||||
std::string legacy = BAMBU_NETWORK_AGENT_VERSION_LEGACY;
|
||||
std::string legacy_sibling = legacy.substr(0, 9) + (legacy.substr(9) == "99" ? "98" : "99");
|
||||
REQUIRE_FALSE(is_supported_network_version(legacy_sibling));
|
||||
REQUIRE_FALSE(is_supported_network_version(""));
|
||||
REQUIRE_FALSE(is_supported_network_version("02.08"));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(PluginFolderFixture, "Legacy series never adopts discovered builds", "[NetworkVersions]")
|
||||
{
|
||||
// A different build of the legacy series must not be surfaced: is_legacy_version()
|
||||
// matches exactly, so it would be loaded with the modern struct layout.
|
||||
std::string legacy = BAMBU_NETWORK_AGENT_VERSION_LEGACY;
|
||||
std::string legacy_sibling = legacy.substr(0, 9) + (legacy.substr(9) == "99" ? "98" : "99");
|
||||
add_plugin(legacy_sibling);
|
||||
|
||||
auto versions = get_all_available_versions();
|
||||
|
||||
REQUIRE(count_version(versions, legacy_sibling) == 0);
|
||||
REQUIRE(count_version(versions, legacy) == 1);
|
||||
|
||||
// With nothing else on disk, the series holds "(Latest)" even though its library is
|
||||
// not installed.
|
||||
for (const auto& info : versions) {
|
||||
if (info.version == "02.08.01") {
|
||||
REQUIRE(info.is_latest);
|
||||
REQUIRE_FALSE(info.is_loaded);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user