mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-08 18:48:04 +00:00
test: finish the temp-file cleanup (#14976)
Follow-up to #14785. Routes the tests that still hand-rolled temp paths through the shared helpers and unifies the temp guards. - Add ScopedTemporaryDir and a shared ScopedTemporaryPath base under it and ScopedTemporaryFile. - Move test_3mf's round-trip .3mf output out of the TEST_DATA_DIR source tree (a fixed-name leak) and test_toolordering's fixed-name temp .gcode (a sharding collision) onto ScopedTemporaryFile. - Move test_config, test_slicing_pipeline_bindings, the test_3mf backup dirs, and test_preset_bundle_loading onto the guards. - Make slic3rutils ScopedDataDir compose ScopedTemporaryDir; dedupe test_network_versions' fixture and delete test_plugin_lifecycle's duplicate.
This commit is contained in:
@@ -155,10 +155,8 @@ SCENARIO("H2C multi-nozzle .3mf round-trip", "[3mf][MultiNozzle]") {
|
|||||||
|
|
||||||
// store_bbs_3mf stages Metadata/project_settings.config through the model's backup path;
|
// store_bbs_3mf stages Metadata/project_settings.config through the model's backup path;
|
||||||
// point it at a writable temp dir (the default lives under a read-only root in CI).
|
// point it at a writable temp dir (the default lives under a read-only root in CI).
|
||||||
std::string backup_dir =
|
ScopedTemporaryDir backup_dir("orca_mn");
|
||||||
(boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("orca_mn_%%%%%%%%")).string();
|
model.set_backup_path(backup_dir.string());
|
||||||
boost::filesystem::create_directories(backup_dir);
|
|
||||||
model.set_backup_path(backup_dir);
|
|
||||||
|
|
||||||
// Global (printer) config: give nozzle_volume_type a non-default value so the slice_info
|
// Global (printer) config: give nozzle_volume_type a non-default value so the slice_info
|
||||||
// read-back is a meaningful assertion (High Flow == 1).
|
// read-back is a meaningful assertion (High Flow == 1).
|
||||||
@@ -180,7 +178,8 @@ SCENARIO("H2C multi-nozzle .3mf round-trip", "[3mf][MultiNozzle]") {
|
|||||||
plate->config.set_key_value("enable_filament_dynamic_map", new ConfigOptionBool(true));
|
plate->config.set_key_value("enable_filament_dynamic_map", new ConfigOptionBool(true));
|
||||||
|
|
||||||
WHEN("stored to and reloaded from a .3mf") {
|
WHEN("stored to and reloaded from a .3mf") {
|
||||||
std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/mn_roundtrip.3mf";
|
ScopedTemporaryFile temp(".3mf");
|
||||||
|
const std::string test_file = temp.string();
|
||||||
|
|
||||||
StoreParams store_params;
|
StoreParams store_params;
|
||||||
store_params.path = test_file.c_str();
|
store_params.path = test_file.c_str();
|
||||||
@@ -202,8 +201,6 @@ SCENARIO("H2C multi-nozzle .3mf round-trip", "[3mf][MultiNozzle]") {
|
|||||||
bool loaded = load_bbs_3mf(test_file.c_str(), &dst_config, &ctxt, &dst_model, &dst_plates,
|
bool loaded = load_bbs_3mf(test_file.c_str(), &dst_config, &ctxt, &dst_model, &dst_plates,
|
||||||
&project_presets, &is_bbl_3mf, &is_orca_3mf, &file_version, nullptr,
|
&project_presets, &is_bbl_3mf, &is_orca_3mf, &file_version, nullptr,
|
||||||
LoadStrategy::LoadModel | LoadStrategy::LoadConfig);
|
LoadStrategy::LoadModel | LoadStrategy::LoadConfig);
|
||||||
boost::filesystem::remove(test_file);
|
|
||||||
|
|
||||||
THEN("every multi-nozzle key round-trips as expected") {
|
THEN("every multi-nozzle key round-trips as expected") {
|
||||||
REQUIRE(loaded);
|
REQUIRE(loaded);
|
||||||
REQUIRE(dst_plates.size() >= 1);
|
REQUIRE(dst_plates.size() >= 1);
|
||||||
@@ -233,7 +230,6 @@ SCENARIO("H2C multi-nozzle .3mf round-trip", "[3mf][MultiNozzle]") {
|
|||||||
release_PlateData_list(dst_plates);
|
release_PlateData_list(dst_plates);
|
||||||
}
|
}
|
||||||
delete plate; // store_bbs_3mf does not take ownership of the source plate
|
delete plate; // store_bbs_3mf does not take ownership of the source plate
|
||||||
boost::filesystem::remove_all(backup_dir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,10 +246,8 @@ SCENARIO("Non-standard nozzle diameter survives .3mf save on a single-nozzle pri
|
|||||||
REQUIRE(load_stl(src_file.c_str(), &model));
|
REQUIRE(load_stl(src_file.c_str(), &model));
|
||||||
model.add_default_instances();
|
model.add_default_instances();
|
||||||
|
|
||||||
std::string backup_dir =
|
ScopedTemporaryDir backup_dir("orca_nd");
|
||||||
(boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("orca_nd_%%%%%%%%")).string();
|
model.set_backup_path(backup_dir.string());
|
||||||
boost::filesystem::create_directories(backup_dir);
|
|
||||||
model.set_backup_path(backup_dir);
|
|
||||||
|
|
||||||
// Single extruder with a non-standard 0.5 mm nozzle; extruder_max_nozzle_count stays at its
|
// Single extruder with a non-standard 0.5 mm nozzle; extruder_max_nozzle_count stays at its
|
||||||
// default (no nozzle cluster), so the writer must emit the exact config diameter.
|
// default (no nozzle cluster), so the writer must emit the exact config diameter.
|
||||||
@@ -276,7 +270,8 @@ SCENARIO("Non-standard nozzle diameter survives .3mf save on a single-nozzle pri
|
|||||||
plate->slice_filaments_info.push_back(fi);
|
plate->slice_filaments_info.push_back(fi);
|
||||||
|
|
||||||
WHEN("stored to and reloaded from a .3mf") {
|
WHEN("stored to and reloaded from a .3mf") {
|
||||||
std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/nd_roundtrip.3mf";
|
ScopedTemporaryFile temp(".3mf");
|
||||||
|
const std::string test_file = temp.string();
|
||||||
|
|
||||||
StoreParams store_params;
|
StoreParams store_params;
|
||||||
store_params.path = test_file.c_str();
|
store_params.path = test_file.c_str();
|
||||||
@@ -296,8 +291,6 @@ SCENARIO("Non-standard nozzle diameter survives .3mf save on a single-nozzle pri
|
|||||||
bool loaded = load_bbs_3mf(test_file.c_str(), &dst_config, &ctxt, &dst_model, &dst_plates,
|
bool loaded = load_bbs_3mf(test_file.c_str(), &dst_config, &ctxt, &dst_model, &dst_plates,
|
||||||
&project_presets, &is_bbl_3mf, &is_orca_3mf, &file_version, nullptr,
|
&project_presets, &is_bbl_3mf, &is_orca_3mf, &file_version, nullptr,
|
||||||
LoadStrategy::LoadModel | LoadStrategy::LoadConfig);
|
LoadStrategy::LoadModel | LoadStrategy::LoadConfig);
|
||||||
boost::filesystem::remove(test_file);
|
|
||||||
|
|
||||||
THEN("the saved nozzle diameter is the exact 0.5, not the rounded 0.4") {
|
THEN("the saved nozzle diameter is the exact 0.5, not the rounded 0.4") {
|
||||||
REQUIRE(loaded);
|
REQUIRE(loaded);
|
||||||
REQUIRE(dst_plates.size() >= 1);
|
REQUIRE(dst_plates.size() >= 1);
|
||||||
@@ -315,7 +308,6 @@ SCENARIO("Non-standard nozzle diameter survives .3mf save on a single-nozzle pri
|
|||||||
release_PlateData_list(dst_plates);
|
release_PlateData_list(dst_plates);
|
||||||
}
|
}
|
||||||
delete plate; // store_bbs_3mf does not take ownership of the source plate
|
delete plate; // store_bbs_3mf does not take ownership of the source plate
|
||||||
boost::filesystem::remove_all(backup_dir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,10 +428,8 @@ SCENARIO("Nozzle-group metadata .3mf round-trip", "[3mf][MultiNozzle]") {
|
|||||||
REQUIRE(load_stl(src_file.c_str(), &model));
|
REQUIRE(load_stl(src_file.c_str(), &model));
|
||||||
model.add_default_instances();
|
model.add_default_instances();
|
||||||
|
|
||||||
std::string backup_dir =
|
ScopedTemporaryDir backup_dir("orca_ng");
|
||||||
(boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("orca_ng_%%%%%%%%")).string();
|
model.set_backup_path(backup_dir.string());
|
||||||
boost::filesystem::create_directories(backup_dir);
|
|
||||||
model.set_backup_path(backup_dir);
|
|
||||||
|
|
||||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||||
|
|
||||||
@@ -459,7 +449,8 @@ SCENARIO("Nozzle-group metadata .3mf round-trip", "[3mf][MultiNozzle]") {
|
|||||||
plate->config.set_key_value("filament_map", new ConfigOptionInts({ 1, 2, 1 }));
|
plate->config.set_key_value("filament_map", new ConfigOptionInts({ 1, 2, 1 }));
|
||||||
|
|
||||||
WHEN("stored to and reloaded from a .3mf") {
|
WHEN("stored to and reloaded from a .3mf") {
|
||||||
std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/ng_roundtrip.3mf";
|
ScopedTemporaryFile temp(".3mf");
|
||||||
|
const std::string test_file = temp.string();
|
||||||
|
|
||||||
StoreParams store_params;
|
StoreParams store_params;
|
||||||
store_params.path = test_file.c_str();
|
store_params.path = test_file.c_str();
|
||||||
@@ -479,8 +470,6 @@ SCENARIO("Nozzle-group metadata .3mf round-trip", "[3mf][MultiNozzle]") {
|
|||||||
bool loaded = load_bbs_3mf(test_file.c_str(), &dst_config, &ctxt, &dst_model, &dst_plates,
|
bool loaded = load_bbs_3mf(test_file.c_str(), &dst_config, &ctxt, &dst_model, &dst_plates,
|
||||||
&project_presets, &is_bbl_3mf, &is_orca_3mf, &file_version, nullptr,
|
&project_presets, &is_bbl_3mf, &is_orca_3mf, &file_version, nullptr,
|
||||||
LoadStrategy::LoadModel | LoadStrategy::LoadConfig);
|
LoadStrategy::LoadModel | LoadStrategy::LoadConfig);
|
||||||
boost::filesystem::remove(test_file);
|
|
||||||
|
|
||||||
THEN("the <nozzle> tags round-trip into the loaded plate's nozzles_info") {
|
THEN("the <nozzle> tags round-trip into the loaded plate's nozzles_info") {
|
||||||
REQUIRE(loaded);
|
REQUIRE(loaded);
|
||||||
REQUIRE(dst_plates.size() >= 1);
|
REQUIRE(dst_plates.size() >= 1);
|
||||||
@@ -506,6 +495,5 @@ SCENARIO("Nozzle-group metadata .3mf round-trip", "[3mf][MultiNozzle]") {
|
|||||||
release_PlateData_list(dst_plates);
|
release_PlateData_list(dst_plates);
|
||||||
}
|
}
|
||||||
delete plate;
|
delete plate;
|
||||||
boost::filesystem::remove_all(backup_dir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include "libslic3r/PrintConfigConstants.hpp"
|
#include "libslic3r/PrintConfigConstants.hpp"
|
||||||
#include "libslic3r/LocalesUtils.hpp"
|
#include "libslic3r/LocalesUtils.hpp"
|
||||||
|
|
||||||
|
#include "test_utils.hpp"
|
||||||
|
|
||||||
#include <cereal/types/polymorphic.hpp>
|
#include <cereal/types/polymorphic.hpp>
|
||||||
#include <cereal/types/string.hpp>
|
#include <cereal/types/string.hpp>
|
||||||
#include <cereal/types/vector.hpp>
|
#include <cereal/types/vector.hpp>
|
||||||
@@ -407,8 +409,7 @@ SCENARIO("update_diff_values_to_child_config tolerates legacy machine-limit vect
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
TEST_CASE("save_to_json round-trips plugin capability references as strings", "[Config][plugins]") {
|
TEST_CASE("save_to_json round-trips plugin capability references as strings", "[Config][plugins]") {
|
||||||
namespace fs = boost::filesystem;
|
ScopedTemporaryFile tmp(".json");
|
||||||
const fs::path tmp = fs::temp_directory_path() / fs::unique_path("orca_plugins_%%%%-%%%%.json");
|
|
||||||
const std::vector<std::string> refs = {
|
const std::vector<std::string> refs = {
|
||||||
"local_plugin;;inset",
|
"local_plugin;;inset",
|
||||||
"cloud_plugin;550e8400-e29b-41d4-a716-446655440000;inset"
|
"cloud_plugin;550e8400-e29b-41d4-a716-446655440000;inset"
|
||||||
@@ -435,8 +436,6 @@ TEST_CASE("save_to_json round-trips plugin capability references as strings", "[
|
|||||||
REQUIRE(reloaded.load_from_json(tmp.string(), substitutions, true, key_values, reason) == 0);
|
REQUIRE(reloaded.load_from_json(tmp.string(), substitutions, true, key_values, reason) == 0);
|
||||||
CHECK(reason.empty());
|
CHECK(reason.empty());
|
||||||
CHECK(reloaded.option<ConfigOptionStrings>("slicing_pipeline_plugin")->values == refs);
|
CHECK(reloaded.option<ConfigOptionStrings>("slicing_pipeline_plugin")->values == refs);
|
||||||
|
|
||||||
fs::remove(tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("plugin capability references survive string-map serialization", "[Config][plugins]") {
|
TEST_CASE("plugin capability references survive string-map serialization", "[Config][plugins]") {
|
||||||
|
|||||||
@@ -5,28 +5,14 @@
|
|||||||
#include "libslic3r/PresetBundle.hpp"
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
#include "libslic3r/AppConfig.hpp"
|
#include "libslic3r/AppConfig.hpp"
|
||||||
|
|
||||||
|
#include "test_utils.hpp"
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
struct TempPresetDir {
|
|
||||||
fs::path path;
|
|
||||||
|
|
||||||
TempPresetDir()
|
|
||||||
{
|
|
||||||
path = fs::temp_directory_path() / fs::unique_path("orcaslicer-preset-%%%%-%%%%-%%%%");
|
|
||||||
fs::create_directories(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
~TempPresetDir()
|
|
||||||
{
|
|
||||||
boost::system::error_code ec;
|
|
||||||
fs::remove_all(path, ec);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void write_print_preset(const DynamicPrintConfig &default_config, const fs::path &file, const std::string &name, const std::string &inherits = {})
|
void write_print_preset(const DynamicPrintConfig &default_config, const fs::path &file, const std::string &name, const std::string &inherits = {})
|
||||||
{
|
{
|
||||||
DynamicPrintConfig config(default_config);
|
DynamicPrintConfig config(default_config);
|
||||||
@@ -82,17 +68,17 @@ struct RenameTestCollection : public PresetCollection
|
|||||||
|
|
||||||
TEST_CASE("Preset identity is canonicalized from load path", "[Preset][Identity]")
|
TEST_CASE("Preset identity is canonicalized from load path", "[Preset][Identity]")
|
||||||
{
|
{
|
||||||
TempPresetDir temp_dir;
|
ScopedTemporaryDir temp_dir;
|
||||||
PresetBundle bundle;
|
PresetBundle bundle;
|
||||||
PresetsConfigSubstitutions substitutions;
|
PresetsConfigSubstitutions substitutions;
|
||||||
|
|
||||||
write_print_preset(bundle.prints.default_preset().config, temp_dir.path / PRESET_PRINT_NAME / "User.json", "User");
|
write_print_preset(bundle.prints.default_preset().config, temp_dir.path() / PRESET_PRINT_NAME / "User.json", "User");
|
||||||
write_print_preset(bundle.prints.default_preset().config, temp_dir.path / PRESET_LOCAL_DIR / "bundle-1" / PRESET_PRINT_NAME / "LocalBundle.json", "LocalBundle");
|
write_print_preset(bundle.prints.default_preset().config, temp_dir.path() / PRESET_LOCAL_DIR / "bundle-1" / PRESET_PRINT_NAME / "LocalBundle.json", "LocalBundle");
|
||||||
write_print_preset(bundle.prints.default_preset().config, temp_dir.path / PRESET_SUBSCRIBED_DIR / "remote-1" / PRESET_PRINT_NAME / "Subscribed.json", "Subscribed");
|
write_print_preset(bundle.prints.default_preset().config, temp_dir.path() / PRESET_SUBSCRIBED_DIR / "remote-1" / PRESET_PRINT_NAME / "Subscribed.json", "Subscribed");
|
||||||
|
|
||||||
bundle.prints.load_presets(temp_dir.path.string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable);
|
bundle.prints.load_presets(temp_dir.path().string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable);
|
||||||
bundle.prints.load_presets((temp_dir.path / PRESET_LOCAL_DIR / "bundle-1").string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable);
|
bundle.prints.load_presets((temp_dir.path() / PRESET_LOCAL_DIR / "bundle-1").string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable);
|
||||||
bundle.prints.load_presets((temp_dir.path / PRESET_SUBSCRIBED_DIR / "remote-1").string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable);
|
bundle.prints.load_presets((temp_dir.path() / PRESET_SUBSCRIBED_DIR / "remote-1").string(), PRESET_PRINT_NAME, substitutions, ForwardCompatibilitySubstitutionRule::Disable);
|
||||||
|
|
||||||
const Preset *root_user = bundle.prints.find_preset("User");
|
const Preset *root_user = bundle.prints.find_preset("User");
|
||||||
REQUIRE(root_user != nullptr);
|
REQUIRE(root_user != nullptr);
|
||||||
@@ -112,14 +98,14 @@ TEST_CASE("Preset identity is canonicalized from load path", "[Preset][Identity]
|
|||||||
|
|
||||||
TEST_CASE("Legacy bundle import without bundle metadata stays in the user preset directory", "[Preset][Identity]")
|
TEST_CASE("Legacy bundle import without bundle metadata stays in the user preset directory", "[Preset][Identity]")
|
||||||
{
|
{
|
||||||
TempPresetDir temp_dir;
|
ScopedTemporaryDir temp_dir;
|
||||||
PresetBundle bundle;
|
PresetBundle bundle;
|
||||||
|
|
||||||
PresetsConfigSubstitutions substitutions;
|
PresetsConfigSubstitutions substitutions;
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
int overwrite = 0;
|
int overwrite = 0;
|
||||||
std::string file = (temp_dir.path / "legacy-bundle" / "Imported.json").string();
|
std::string file = (temp_dir.path() / "legacy-bundle" / "Imported.json").string();
|
||||||
const fs::path user_root = temp_dir.path / "user";
|
const fs::path user_root = temp_dir.path() / "user";
|
||||||
|
|
||||||
write_print_preset(bundle.prints.default_preset().config, file, "Imported");
|
write_print_preset(bundle.prints.default_preset().config, file, "Imported");
|
||||||
fs::create_directories(user_root);
|
fs::create_directories(user_root);
|
||||||
@@ -252,7 +238,7 @@ TEST_CASE("find_preset2 auto-matches removed Generic vendor profiles to the libr
|
|||||||
|
|
||||||
TEST_CASE("Renamed parent is normalized into a loaded preset's inherits", "[Preset][Rename]")
|
TEST_CASE("Renamed parent is normalized into a loaded preset's inherits", "[Preset][Rename]")
|
||||||
{
|
{
|
||||||
TempPresetDir temp_dir;
|
ScopedTemporaryDir temp_dir;
|
||||||
RenameTestCollection coll;
|
RenameTestCollection coll;
|
||||||
|
|
||||||
// Current parent, renamed from "Old Process".
|
// Current parent, renamed from "Old Process".
|
||||||
@@ -262,10 +248,10 @@ TEST_CASE("Renamed parent is normalized into a loaded preset's inherits", "[Pres
|
|||||||
|
|
||||||
// A user preset on disk that still inherits the OLD name.
|
// A user preset on disk that still inherits the OLD name.
|
||||||
write_preset_with_inherits(coll.default_preset().config,
|
write_preset_with_inherits(coll.default_preset().config,
|
||||||
temp_dir.path / PRESET_PRINT_NAME / "Child.json", "Child", "Old Process");
|
temp_dir.path() / PRESET_PRINT_NAME / "Child.json", "Child", "Old Process");
|
||||||
|
|
||||||
PresetsConfigSubstitutions substitutions;
|
PresetsConfigSubstitutions substitutions;
|
||||||
coll.load_presets(temp_dir.path.string(), PRESET_PRINT_NAME, substitutions,
|
coll.load_presets(temp_dir.path().string(), PRESET_PRINT_NAME, substitutions,
|
||||||
ForwardCompatibilitySubstitutionRule::Disable);
|
ForwardCompatibilitySubstitutionRule::Disable);
|
||||||
|
|
||||||
const Preset *child = coll.find_preset("Child");
|
const Preset *child = coll.find_preset("Child");
|
||||||
@@ -279,17 +265,17 @@ TEST_CASE("Renamed parent is normalized into a loaded preset's inherits", "[Pres
|
|||||||
|
|
||||||
TEST_CASE("Removed Generic parent is normalized into a loaded filament's inherits", "[Preset][Rename]")
|
TEST_CASE("Removed Generic parent is normalized into a loaded filament's inherits", "[Preset][Rename]")
|
||||||
{
|
{
|
||||||
TempPresetDir temp_dir;
|
ScopedTemporaryDir temp_dir;
|
||||||
PresetBundle bundle;
|
PresetBundle bundle;
|
||||||
|
|
||||||
add_inmemory_preset(bundle.filaments, "Generic PLA @System");
|
add_inmemory_preset(bundle.filaments, "Generic PLA @System");
|
||||||
|
|
||||||
// A user filament that still inherits a removed "<vendor> Generic PLA" profile.
|
// A user filament that still inherits a removed "<vendor> Generic PLA" profile.
|
||||||
write_preset_with_inherits(bundle.filaments.default_preset().config,
|
write_preset_with_inherits(bundle.filaments.default_preset().config,
|
||||||
temp_dir.path / PRESET_FILAMENT_NAME / "MyPLA.json", "MyPLA", "Voron Generic PLA");
|
temp_dir.path() / PRESET_FILAMENT_NAME / "MyPLA.json", "MyPLA", "Voron Generic PLA");
|
||||||
|
|
||||||
PresetsConfigSubstitutions substitutions;
|
PresetsConfigSubstitutions substitutions;
|
||||||
bundle.filaments.load_presets(temp_dir.path.string(), PRESET_FILAMENT_NAME, substitutions,
|
bundle.filaments.load_presets(temp_dir.path().string(), PRESET_FILAMENT_NAME, substitutions,
|
||||||
ForwardCompatibilitySubstitutionRule::Disable);
|
ForwardCompatibilitySubstitutionRule::Disable);
|
||||||
|
|
||||||
const Preset *child = bundle.filaments.find_preset("MyPLA");
|
const Preset *child = bundle.filaments.find_preset("MyPLA");
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/TriangleMesh.hpp"
|
#include "libslic3r/TriangleMesh.hpp"
|
||||||
|
|
||||||
|
#include "test_utils.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
@@ -708,10 +710,9 @@ TEST_CASE("Sequential selector prints publish a stitched result and cache the pl
|
|||||||
REQUIRE(print.config().filament_self_index.values.size() >= print.config().filament_map.values.size());
|
REQUIRE(print.config().filament_self_index.values.size() >= print.config().filament_map.values.size());
|
||||||
|
|
||||||
// Export must consume the cached plans and produce g-code without throwing.
|
// Export must consume the cached plans and produce g-code without throwing.
|
||||||
boost::filesystem::path gcode_path = boost::filesystem::temp_directory_path() / "orca_seq_dynamic_publish_test.gcode";
|
ScopedTemporaryFile gcode(".gcode");
|
||||||
REQUIRE_NOTHROW(print.export_gcode(gcode_path.string(), nullptr, nullptr));
|
REQUIRE_NOTHROW(print.export_gcode(gcode.string(), nullptr, nullptr));
|
||||||
REQUIRE(boost::filesystem::exists(gcode_path));
|
REQUIRE(boost::filesystem::exists(gcode.path()));
|
||||||
boost::filesystem::remove(gcode_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Per-variant expansion gives migrating filaments one slot per variant", "[PrintConfig][H2C][Dynamic]")
|
TEST_CASE("Per-variant expansion gives migrating filaments one slot per variant", "[PrintConfig][H2C][Dynamic]")
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "test_utils.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
// Point data_dir() at a throwaway directory for the lifetime of a test and
|
// Point data_dir() at a throwaway directory for the lifetime of a test and
|
||||||
@@ -13,24 +15,20 @@ namespace Slic3r {
|
|||||||
// disposable tree and tests don't leak state into each other.
|
// disposable tree and tests don't leak state into each other.
|
||||||
struct ScopedDataDir
|
struct ScopedDataDir
|
||||||
{
|
{
|
||||||
|
ScopedTemporaryDir tmp; // owns the temp dir (create + recursive remove)
|
||||||
|
boost::filesystem::path dir; // = tmp.path(); kept as a member for callers
|
||||||
std::string previous;
|
std::string previous;
|
||||||
boost::filesystem::path dir;
|
|
||||||
|
|
||||||
explicit ScopedDataDir(const std::string& tag)
|
explicit ScopedDataDir(const std::string& tag)
|
||||||
|
: tmp("orca-" + tag), dir(tmp.path()), previous(data_dir())
|
||||||
{
|
{
|
||||||
namespace fs = boost::filesystem;
|
|
||||||
previous = data_dir();
|
|
||||||
dir = fs::temp_directory_path() / fs::unique_path("orca-" + tag + "-%%%%-%%%%");
|
|
||||||
fs::create_directories(dir);
|
|
||||||
set_data_dir(dir.string());
|
set_data_dir(dir.string());
|
||||||
}
|
}
|
||||||
|
|
||||||
~ScopedDataDir()
|
~ScopedDataDir() { set_data_dir(previous); } // tmp removes the directory
|
||||||
{
|
|
||||||
set_data_dir(previous);
|
// The plugin manager scans {data_dir}/orca_plugins.
|
||||||
boost::system::error_code ec;
|
boost::filesystem::path plugins_dir() const { return dir / "orca_plugins"; }
|
||||||
boost::filesystem::remove_all(dir, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedDataDir(const ScopedDataDir&) = delete;
|
ScopedDataDir(const ScopedDataDir&) = delete;
|
||||||
ScopedDataDir& operator=(const ScopedDataDir&) = delete;
|
ScopedDataDir& operator=(const ScopedDataDir&) = delete;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "slic3r/Utils/bambu_networking.hpp"
|
#include "slic3r/Utils/bambu_networking.hpp"
|
||||||
|
|
||||||
|
#include "plugin_test_utils.hpp"
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
@@ -25,27 +27,16 @@ static const char* PLUGIN_EXT = ".so";
|
|||||||
|
|
||||||
struct PluginFolderFixture
|
struct PluginFolderFixture
|
||||||
{
|
{
|
||||||
fs::path root;
|
ScopedDataDir data{"netver"};
|
||||||
std::string previous_data_dir;
|
|
||||||
|
|
||||||
PluginFolderFixture()
|
PluginFolderFixture()
|
||||||
{
|
{
|
||||||
previous_data_dir = data_dir();
|
fs::create_directories(data.dir / "plugins");
|
||||||
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)
|
void add_plugin(const std::string& version)
|
||||||
{
|
{
|
||||||
boost::nowide::ofstream f((root / "plugins" / (PLUGIN_PREFIX + version + PLUGIN_EXT)).string());
|
boost::nowide::ofstream f((data.dir / "plugins" / (PLUGIN_PREFIX + version + PLUGIN_EXT)).string());
|
||||||
f << "stub";
|
f << "stub";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#include <slic3r/plugin/PluginFsUtils.hpp>
|
#include <slic3r/plugin/PluginFsUtils.hpp>
|
||||||
#include <slic3r/plugin/PythonInterpreter.hpp>
|
#include <slic3r/plugin/PythonInterpreter.hpp>
|
||||||
|
|
||||||
|
#include "plugin_test_utils.hpp"
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -25,32 +27,6 @@ namespace fs = boost::filesystem;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Point data_dir() at a throwaway directory for the lifetime of a test and restore the previous
|
|
||||||
// value afterwards, so discovery scans a disposable {data_dir}/orca_plugins tree and tests don't
|
|
||||||
// leak state into each other.
|
|
||||||
struct ScopedDataDir
|
|
||||||
{
|
|
||||||
std::string previous;
|
|
||||||
fs::path dir;
|
|
||||||
|
|
||||||
explicit ScopedDataDir(const std::string& tag)
|
|
||||||
{
|
|
||||||
previous = data_dir();
|
|
||||||
dir = fs::temp_directory_path() / fs::unique_path("orca-" + tag + "-%%%%-%%%%");
|
|
||||||
fs::create_directories(dir);
|
|
||||||
set_data_dir(dir.string());
|
|
||||||
}
|
|
||||||
|
|
||||||
~ScopedDataDir()
|
|
||||||
{
|
|
||||||
set_data_dir(previous);
|
|
||||||
boost::system::error_code ec;
|
|
||||||
fs::remove_all(dir, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::path plugins_dir() const { return dir / "orca_plugins"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Brings the plugin system up, and tears it down explicitly at the end of the test.
|
// Brings the plugin system up, and tears it down explicitly at the end of the test.
|
||||||
//
|
//
|
||||||
// Shutting the interpreter down here, rather than leaving it to PythonInterpreter's static
|
// Shutting the interpreter down here, rather than leaving it to PythonInterpreter's static
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ TEST_CASE("SlicingPipeline capability-type string maps round-trip", "[slicing_pi
|
|||||||
#include "libslic3r/Point.hpp"
|
#include "libslic3r/Point.hpp"
|
||||||
#include "libslic3r/ExPolygon.hpp"
|
#include "libslic3r/ExPolygon.hpp"
|
||||||
#include "libslic3r/Surface.hpp"
|
#include "libslic3r/Surface.hpp"
|
||||||
|
|
||||||
|
#include "test_utils.hpp"
|
||||||
#include "libslic3r/Layer.hpp"
|
#include "libslic3r/Layer.hpp"
|
||||||
#include "libslic3r/ExtrusionEntity.hpp"
|
#include "libslic3r/ExtrusionEntity.hpp"
|
||||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
||||||
@@ -142,7 +144,7 @@ TEST_CASE("orca.slicing psGCodePostProcess context: file edit in place + config
|
|||||||
import_orca_module();
|
import_orca_module();
|
||||||
py::gil_scoped_acquire gil;
|
py::gil_scoped_acquire gil;
|
||||||
|
|
||||||
const fs::path gpath = fs::temp_directory_path() / fs::unique_path("orca_pp_%%%%-%%%%.gcode");
|
ScopedTemporaryFile gpath(".gcode");
|
||||||
{
|
{
|
||||||
boost::nowide::ofstream ofs(gpath.string());
|
boost::nowide::ofstream ofs(gpath.string());
|
||||||
ofs << "; header\nG1 X0 Y0\n";
|
ofs << "; header\nG1 X0 Y0\n";
|
||||||
@@ -196,9 +198,7 @@ _pp_result = Stamp().execute(_pp_ctx)
|
|||||||
boost::nowide::ifstream ifs(gpath.string());
|
boost::nowide::ifstream ifs(gpath.string());
|
||||||
std::stringstream ss; ss << ifs.rdbuf(); contents = ss.str();
|
std::stringstream ss; ss << ifs.rdbuf(); contents = ss.str();
|
||||||
}
|
}
|
||||||
CHECK(contents.find("; stamped by File") != std::string::npos);
|
CHECK(contents.find("; stamped by File") != std::string::npos);}
|
||||||
fs::remove(gpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Toolpath helpers for the raw-graph tests.
|
// Toolpath helpers for the raw-graph tests.
|
||||||
|
|||||||
@@ -27,26 +27,47 @@ inline Slic3r::TriangleMesh load_model(const std::string &obj_filename)
|
|||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RAII holder for a unique temporary file path, removed when the guard goes out
|
// ---------------------------------------------------------------------------
|
||||||
// of scope so a failing assertion never leaks it. Uses the system temp dir with
|
// Scoped temporary paths
|
||||||
// a unique name (parallel-safe, cross-platform). The file itself is created by
|
// ---------------------------------------------------------------------------
|
||||||
// whoever writes to path()/string(); this only reserves the name and cleans up.
|
|
||||||
class ScopedTemporaryFile
|
// Owns a unique path under the system temp dir, "<prefix>-<unique>[<extension>]"
|
||||||
|
// (parallel-safe, cross-platform). Shared base for the two RAII temp guards below.
|
||||||
|
class ScopedTemporaryPath
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const boost::filesystem::path &path() const { return m_path; }
|
||||||
|
std::string string() const { return m_path.string(); }
|
||||||
|
ScopedTemporaryPath(const ScopedTemporaryPath &) = delete;
|
||||||
|
ScopedTemporaryPath &operator=(const ScopedTemporaryPath &) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ScopedTemporaryPath(const std::string &prefix, const std::string &extension)
|
||||||
|
: m_path(boost::filesystem::temp_directory_path()
|
||||||
|
/ boost::filesystem::unique_path(prefix + "-%%%%-%%%%-%%%%" + extension))
|
||||||
|
{}
|
||||||
|
~ScopedTemporaryPath() = default; // non-virtual: never deleted through a base pointer
|
||||||
|
|
||||||
|
boost::filesystem::path m_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A temp file the caller creates by writing to path()/string(); the guard only
|
||||||
|
// reserves the name and removes the file on scope exit.
|
||||||
|
class ScopedTemporaryFile : public ScopedTemporaryPath
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ScopedTemporaryFile(const std::string &extension = ".tmp")
|
explicit ScopedTemporaryFile(const std::string &extension = ".tmp")
|
||||||
: m_path(boost::filesystem::temp_directory_path()
|
: ScopedTemporaryPath("orca", extension) {}
|
||||||
/ boost::filesystem::unique_path("orca-%%%%-%%%%-%%%%" + extension))
|
|
||||||
{}
|
|
||||||
~ScopedTemporaryFile() { boost::system::error_code ec; boost::filesystem::remove(m_path, ec); }
|
~ScopedTemporaryFile() { boost::system::error_code ec; boost::filesystem::remove(m_path, ec); }
|
||||||
ScopedTemporaryFile(const ScopedTemporaryFile &) = delete;
|
};
|
||||||
ScopedTemporaryFile &operator=(const ScopedTemporaryFile &) = delete;
|
|
||||||
|
|
||||||
const boost::filesystem::path &path() const { return m_path; }
|
// A temp directory created on construction and removed recursively on scope exit.
|
||||||
std::string string() const { return m_path.string(); }
|
class ScopedTemporaryDir : public ScopedTemporaryPath
|
||||||
|
{
|
||||||
private:
|
public:
|
||||||
boost::filesystem::path m_path;
|
explicit ScopedTemporaryDir(const std::string &prefix = "orca")
|
||||||
|
: ScopedTemporaryPath(prefix, "") { boost::filesystem::create_directories(m_path); }
|
||||||
|
~ScopedTemporaryDir() { boost::system::error_code ec; boost::filesystem::remove_all(m_path, ec); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -66,7 +87,7 @@ inline std::string debug_artifact_path(const std::string &name)
|
|||||||
boost::filesystem::path dir = boost::filesystem::temp_directory_path()
|
boost::filesystem::path dir = boost::filesystem::temp_directory_path()
|
||||||
/ boost::filesystem::unique_path("orca-test-artifacts-%%%%-%%%%");
|
/ boost::filesystem::unique_path("orca-test-artifacts-%%%%-%%%%");
|
||||||
boost::filesystem::create_directories(dir);
|
boost::filesystem::create_directories(dir);
|
||||||
std::printf("Debug test artifacts will be written to %s\n", dir.string().c_str());
|
std::fprintf(stderr, "Debug test artifacts will be written to %s\n", dir.string().c_str());
|
||||||
return dir;
|
return dir;
|
||||||
}();
|
}();
|
||||||
boost::filesystem::path full = root / name;
|
boost::filesystem::path full = root / name;
|
||||||
@@ -75,57 +96,52 @@ inline std::string debug_artifact_path(const std::string &name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Dump a mesh as OBJ.
|
// Dump a mesh as OBJ.
|
||||||
inline void write_debug_obj(const std::string &name, const Slic3r::TriangleMesh &mesh)
|
inline void write_debug_obj([[maybe_unused]] const std::string &name,
|
||||||
|
[[maybe_unused]] const Slic3r::TriangleMesh &mesh)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
mesh.WriteOBJFile(debug_artifact_path(name).c_str());
|
mesh.WriteOBJFile(debug_artifact_path(name).c_str());
|
||||||
#else
|
|
||||||
(void) name; (void) mesh;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void write_debug_obj(const std::string &name, const indexed_triangle_set &its)
|
inline void write_debug_obj([[maybe_unused]] const std::string &name,
|
||||||
|
[[maybe_unused]] const indexed_triangle_set &its)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
its_write_obj(its, debug_artifact_path(name).c_str());
|
its_write_obj(its, debug_artifact_path(name).c_str());
|
||||||
#else
|
|
||||||
(void) name; (void) its;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump a mesh as ASCII STL.
|
// Dump a mesh as ASCII STL.
|
||||||
inline void write_debug_stl(const std::string &name, const Slic3r::TriangleMesh &mesh)
|
inline void write_debug_stl([[maybe_unused]] const std::string &name,
|
||||||
|
[[maybe_unused]] const Slic3r::TriangleMesh &mesh)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
mesh.write_ascii(debug_artifact_path(name).c_str());
|
mesh.write_ascii(debug_artifact_path(name).c_str());
|
||||||
#else
|
|
||||||
(void) name; (void) mesh;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw an SVG artifact through a callback that receives the open SVG. Second
|
// Draw an SVG artifact through a callback that receives the open SVG. Second
|
||||||
// overload takes a BoundingBox when the drawing needs one.
|
// overload takes a BoundingBox when the drawing needs one.
|
||||||
template<class Draw>
|
template<class Draw>
|
||||||
inline void write_debug_svg(const std::string &name, Draw &&draw)
|
inline void write_debug_svg([[maybe_unused]] const std::string &name, [[maybe_unused]] Draw &&draw)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
Slic3r::SVG svg(debug_artifact_path(name));
|
Slic3r::SVG svg(debug_artifact_path(name));
|
||||||
draw(svg);
|
draw(svg);
|
||||||
svg.Close();
|
svg.Close();
|
||||||
#else
|
|
||||||
(void) name; (void) draw;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Draw>
|
template<class Draw>
|
||||||
inline void write_debug_svg(const std::string &name, const Slic3r::BoundingBox &bbox, Draw &&draw)
|
inline void write_debug_svg([[maybe_unused]] const std::string &name,
|
||||||
|
[[maybe_unused]] const Slic3r::BoundingBox &bbox,
|
||||||
|
[[maybe_unused]] Draw &&draw)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
Slic3r::SVG svg(debug_artifact_path(name), bbox);
|
Slic3r::SVG svg(debug_artifact_path(name), bbox);
|
||||||
draw(svg);
|
draw(svg);
|
||||||
svg.Close();
|
svg.Close();
|
||||||
#else
|
|
||||||
(void) name; (void) bbox; (void) draw;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,13 +149,11 @@ inline void write_debug_svg(const std::string &name, const Slic3r::BoundingBox &
|
|||||||
// artifact. operator<< is resolved by ADL at the call site, so this header needn't
|
// artifact. operator<< is resolved by ADL at the call site, so this header needn't
|
||||||
// include the producer's headers.
|
// include the producer's headers.
|
||||||
template<class Produce>
|
template<class Produce>
|
||||||
inline void write_debug_stream(const std::string &name, Produce &&produce)
|
inline void write_debug_stream([[maybe_unused]] const std::string &name, [[maybe_unused]] Produce &&produce)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::ofstream out(debug_artifact_path(name), std::ios::out | std::ios::binary);
|
std::ofstream out(debug_artifact_path(name), std::ios::out | std::ios::binary);
|
||||||
out << produce();
|
out << produce();
|
||||||
#else
|
|
||||||
(void) name; (void) produce;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user