Compare commits

..
2 Commits
Author SHA1 Message Date
Kris Austin d1d14329d9 fix: exporting a sliced print again gives different G-code (#16025)
extrude_infill() and extrude_support() reversed the layer's extrusion
entities in place while chaining them, so each export started from the
previous one's reversed toolpaths, and each copy of an object from the
copy before it. The export-time region lists now hold const pointers,
and chaining reverses a clone instead.
2026-10-01 08:08:03 -03:00
HanifKoh 236a8786ef Keep the Orca Cloud Agent Tests Out of the System Keychain (#15980)
The display-name tests call set_user_session(), which persists the session.
The agent they built was in keychain mode, so every run saved a fake
OrcaSlicer/Auth session into the system keychain of whoever ran the tests,
replacing their real Orca Cloud login on any desktop with a working keychain.

Move them next to the other agent tests and build the agent the same way:
encrypted-file mode with a throwaway config directory.
2026-10-01 16:58:52 +08:00
10 changed files with 214 additions and 186 deletions
-48
View File
@@ -1301,54 +1301,6 @@ if (WIN32)
endif()
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
include(InstallRequiredSystemLibraries)
# CMake 3.31 does not recognize the v145 toolset shipped with VS 2026.
# The Windows ARM64 build is pinned to CMake 3.31 for its assembler
# support, so the runtime collector can leave this list without the CRT.
# Pick up the target-architecture redistributable directly in that case.
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
set(_orca_has_msvcp140 FALSE)
set(_orca_has_vcruntime140 FALSE)
foreach (_runtime IN LISTS CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
get_filename_component(_runtime_name "${_runtime}" NAME)
if (_runtime_name STREQUAL "msvcp140.dll")
set(_orca_has_msvcp140 TRUE)
elseif (_runtime_name STREQUAL "vcruntime140.dll")
set(_orca_has_vcruntime140 TRUE)
endif ()
endforeach ()
if (NOT _orca_has_msvcp140 OR NOT _orca_has_vcruntime140)
file(GLOB _orca_arm64_crt_dirs
"$ENV{ProgramFiles}/Microsoft Visual Studio/*/*/VC/Redist/MSVC/*/arm64/Microsoft.VC*.CRT")
if (NOT _orca_arm64_crt_dirs)
message(FATAL_ERROR
"CMake did not collect the ARM64 MSVC runtime, and no ARM64 CRT redistributable directory was found.")
endif ()
# Multiple Visual Studio servicing versions can coexist; take the
# newest matching redistributable directory.
list(SORT _orca_arm64_crt_dirs ORDER DESCENDING)
list(GET _orca_arm64_crt_dirs 0 _orca_arm64_crt_dir)
file(GLOB _orca_arm64_crt_dlls "${_orca_arm64_crt_dir}/*.dll")
list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${_orca_arm64_crt_dlls})
endif ()
# Catch a bad VS layout or an incomplete redistributable before CPack
# can silently emit an installer that fails on a clean ARM64 machine.
set(_orca_has_msvcp140 FALSE)
set(_orca_has_vcruntime140 FALSE)
foreach (_runtime IN LISTS CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
get_filename_component(_runtime_name "${_runtime}" NAME)
if (_runtime_name STREQUAL "msvcp140.dll")
set(_orca_has_msvcp140 TRUE)
elseif (_runtime_name STREQUAL "vcruntime140.dll")
set(_orca_has_vcruntime140 TRUE)
endif ()
endforeach ()
if (NOT _orca_has_msvcp140 OR NOT _orca_has_vcruntime140)
message(FATAL_ERROR "The ARM64 installer must contain msvcp140.dll and vcruntime140.dll.")
endif ()
endif ()
install (PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ".")
elseif (SLIC3R_FHS)
# CMAKE_INSTALL_FULL_DATAROOTDIR: read-only architecture-independent data root (share)
+34 -24
View File
@@ -7310,12 +7310,12 @@ static std::unique_ptr<EdgeGrid::Grid> calculate_layer_edge_grid(const Layer& la
return out;
}
std::string GCode::extrude_loop(const ExtrusionLoop& loop_ref,
const std::string& description,
double speed,
const ExtrusionEntitiesPtr& region_perimeters,
const Point* start_point,
const WipeInwardSupport* wipe_support)
std::string GCode::extrude_loop(const ExtrusionLoop& loop_ref,
const std::string& description,
double speed,
const std::vector<const ExtrusionEntity*>& region_perimeters,
const Point* start_point,
const WipeInwardSupport* wipe_support)
{
// get a copy; don't modify the orientation of the original loop object otherwise
// next copies (if any) would not detect the correct orientation
@@ -7659,11 +7659,11 @@ std::string GCode::extrude_multi_path(const ExtrusionMultiPath& multipath, const
return gcode;
}
std::string GCode::extrude_entity(const ExtrusionEntity& entity,
const std::string& description,
double speed,
const ExtrusionEntitiesPtr& region_perimeters,
const WipeInwardSupport* wipe_support)
std::string GCode::extrude_entity(const ExtrusionEntity& entity,
const std::string& description,
double speed,
const std::vector<const ExtrusionEntity*>& region_perimeters,
const WipeInwardSupport* wipe_support)
{
if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity))
return this->extrude_path(*path, description, speed);
@@ -7754,23 +7754,32 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje
// Chain the paths hierarchically by a greedy algorithm to minimize a travel distance.
std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, bool ironing)
{
std::string gcode;
ExtrusionEntitiesPtr extrusions;
const char* extrusion_name = ironing ? "ironing" : "infill";
std::string gcode;
std::vector<const ExtrusionEntity*> extrusions;
std::vector<std::unique_ptr<ExtrusionEntity>> reversed;
const char* extrusion_name = ironing ? "ironing" : "infill";
for (const ObjectByExtruder::Island::Region &region : by_region)
if (! region.infills.empty()) {
extrusions.clear();
extrusions.reserve(region.infills.size());
for (ExtrusionEntity *ee : region.infills)
for (const ExtrusionEntity *ee : region.infills)
if ((ee->role() == erIroning) == ironing)
extrusions.emplace_back(ee);
if (! extrusions.empty()) {
m_config.apply(print.get_print_region(&region - &by_region.front()).config());
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point());
reversed.clear();
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point(), reversed);
// The reversed copies are in chain order.
auto next_reversed = reversed.begin();
for (const ExtrusionEntity *fill : extrusions) {
ExtrusionEntity *own_copy = next_reversed != reversed.end() && next_reversed->get() == fill ? (next_reversed++)->get() : nullptr;
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
if (eec) {
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos.to_point()).entities)
// A reversed copy is owned here and can be moved from.
ExtrusionEntityCollection chained = own_copy ? std::move(static_cast<ExtrusionEntityCollection&>(*own_copy)) : ExtrusionEntityCollection(*eec);
if (!chained.no_sort)
chain_and_reorder_extrusion_entities(chained.entities, m_last_pos.to_point());
for (ExtrusionEntity *ee : chained.entities)
gcode += this->extrude_entity(*ee, extrusion_name);
} else
gcode += this->extrude_entity(*fill, extrusion_name);
@@ -7808,9 +7817,9 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
std::string gcode;
if (!support_fills.entities.empty()) {
ExtrusionEntitiesPtr extrusions;
std::vector<const ExtrusionEntity*> extrusions;
extrusions.reserve(support_fills.entities.size());
for (ExtrusionEntity* ee : support_fills.entities) {
for (const ExtrusionEntity* ee : support_fills.entities) {
const auto role = ee->role();
if ((role == support_extrusion_role) || (support_extrusion_role == erMixed && role != erIroning)) {
extrusions.emplace_back(ee);
@@ -7819,9 +7828,10 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
if (extrusions.empty())
return gcode;
std::vector<std::unique_ptr<ExtrusionEntity>> reversed;
//ORCA: Respect no_sort to preserve support base outline->fill order.
if (!support_fills.no_sort)
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point());
chain_and_reorder_extrusion_entities(extrusions, m_last_pos.to_point(), reversed);
for (const ExtrusionEntity *ee : extrusions) {
ExtrusionRole role = ee->role();
@@ -10054,8 +10064,8 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
// Now we are going to iterate through perimeters and infills and pick ones that are supposed to be printed
// References are used so that we don't have to repeat the same code
for (int iter = 0; iter < 2; ++iter) {
const ExtrusionEntitiesPtr& entities = (iter ? reg.infills : reg.perimeters);
ExtrusionEntitiesPtr& target_eec = (iter ? by_region_per_copy_cache.back().infills : by_region_per_copy_cache.back().perimeters);
const std::vector<const ExtrusionEntity*>& entities = (iter ? reg.infills : reg.perimeters);
std::vector<const ExtrusionEntity*>& target_eec = (iter ? by_region_per_copy_cache.back().infills : by_region_per_copy_cache.back().perimeters);
const std::vector<const WipingExtrusions::ExtruderPerCopy*>& overrides = (iter ? reg.infills_overrides : reg.perimeters_overrides);
// Now the most important thing - which extrusion should we print.
@@ -10090,7 +10100,7 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
void GCode::ObjectByExtruder::Island::Region::append(const Type type, const ExtrusionEntityCollection* eec, const WipingExtrusions::ExtruderPerCopy* copies_extruder)
{
// We are going to manipulate either perimeters or infills, exactly in the same way. Let's create pointers to the proper structure to not repeat ourselves:
ExtrusionEntitiesPtr* perimeters_or_infills;
std::vector<const ExtrusionEntity*>* perimeters_or_infills;
std::vector<const WipingExtrusions::ExtruderPerCopy*>* perimeters_or_infills_overrides;
switch (type) {
@@ -10114,7 +10124,7 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
for (auto* ee : eec->entities)
perimeters_or_infills->emplace_back(ee);
} else
perimeters_or_infills->emplace_back(const_cast<ExtrusionEntityCollection*>(eec));
perimeters_or_infills->emplace_back(eec);
if (copies_extruder != nullptr) {
// Don't reallocate overrides if not needed.
+13 -14
View File
@@ -450,19 +450,19 @@ private:
double &y_acceleration_limit_res, double &accumulated_mass_res);
// Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop
// should be executed
std::string extrude_entity(const ExtrusionEntity& entity,
const std::string& description = "",
double speed = -1.,
const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr(),
const WipeInwardSupport* wipe_support = nullptr);
std::string extrude_entity(const ExtrusionEntity& entity,
const std::string& description = "",
double speed = -1.,
const std::vector<const ExtrusionEntity*>& region_perimeters = {},
const WipeInwardSupport* wipe_support = nullptr);
// Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop
// should be executed
std::string extrude_loop(const ExtrusionLoop& loop,
const std::string& description,
double speed = -1.,
const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr(),
const Point* start_point = nullptr,
const WipeInwardSupport* wipe_support = nullptr);
std::string extrude_loop(const ExtrusionLoop& loop,
const std::string& description,
double speed = -1.,
const std::vector<const ExtrusionEntity*>& region_perimeters = {},
const Point* start_point = nullptr,
const WipeInwardSupport* wipe_support = nullptr);
std::string extrude_multi_path(const ExtrusionMultiPath& multipath, const std::string& description = "", double speed = -1.);
std::string extrude_path(const ExtrusionPath& path, const std::string& description = "", double speed = -1.);
@@ -493,10 +493,9 @@ private:
{
struct Region {
// Non-owned references to LayerRegion::perimeters::entities
// std::vector<const ExtrusionEntity*> would be better here, but there is no way in C++ to convert from std::vector<T*> std::vector<const T*> without copying.
ExtrusionEntitiesPtr perimeters;
std::vector<const ExtrusionEntity*> perimeters;
// Non-owned references to LayerRegion::fills::entities
ExtrusionEntitiesPtr infills;
std::vector<const ExtrusionEntity*> infills;
std::vector<const WipingExtrusions::ExtruderPerCopy*> infills_overrides;
std::vector<const WipingExtrusions::ExtruderPerCopy*> perimeters_overrides;
+35 -7
View File
@@ -1024,13 +1024,14 @@ std::vector<std::pair<size_t, bool>> chain_segments_greedy2(SegmentEndPointFunc
return chain_segments_greedy_constrained_reversals2_<PointType, SegmentEndPointFunc, false, decltype(could_reverse_func)>(end_point_func, could_reverse_func, num_segments, start_near);
}
std::vector<std::pair<size_t, bool>> chain_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point *start_near)
template<typename EntityPtr>
static std::vector<std::pair<size_t, bool>> chain_extrusion_entities_impl(const std::vector<EntityPtr> &entities, const Point *start_near)
{
auto segment_end_point = [&entities](size_t idx, bool first_point) -> Point { return first_point ? entities[idx]->first_point() : entities[idx]->last_point(); };
auto could_reverse = [&entities](size_t idx) { const ExtrusionEntity *ee = entities[idx]; return ee->is_loop() || ee->can_reverse(); };
std::vector<std::pair<size_t, bool>> out = chain_segments_greedy_constrained_reversals<Point, decltype(segment_end_point), decltype(could_reverse)>(segment_end_point, could_reverse, entities.size(), start_near);
for (std::pair<size_t, bool> &segment : out) {
ExtrusionEntity *ee = entities[segment.first];
const ExtrusionEntity *ee = entities[segment.first];
if (ee->is_loop())
// Ignore reversals for loops, as the start point equals the end point.
segment.second = false;
@@ -1040,6 +1041,20 @@ std::vector<std::pair<size_t, bool>> chain_extrusion_entities(std::vector<Extrus
return out;
}
std::vector<std::pair<size_t, bool>> chain_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point *start_near)
{
return chain_extrusion_entities_impl(entities, start_near);
}
// Orca: Reordering queries first_point() / last_point(); drop entities that cannot provide valid endpoints.
template<typename EntityPtr>
static void remove_entities_without_endpoints(std::vector<EntityPtr> &entities)
{
entities.erase(std::remove_if(entities.begin(), entities.end(),
[](const ExtrusionEntity *entity) { return !extrusion_entity_has_endpoints(entity); }),
entities.end());
}
void reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const std::vector<std::pair<size_t, bool>> &chain)
{
assert(entities.size() == chain.size());
@@ -1061,14 +1076,27 @@ void chain_and_reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entitie
void chain_and_reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point *start_near)
{
// Orca: Reordering queries first_point() / last_point(); drop entities that cannot provide valid endpoints.
entities.erase(std::remove_if(entities.begin(), entities.end(), [](ExtrusionEntity *entity) {
return !extrusion_entity_has_endpoints(entity);
}),
entities.end());
remove_entities_without_endpoints(entities);
reorder_extrusion_entities(entities, chain_extrusion_entities(entities, start_near));
}
void chain_and_reorder_extrusion_entities(std::vector<const ExtrusionEntity*> &entities, const Point &start_near,
std::vector<std::unique_ptr<ExtrusionEntity>> &reversed_clones)
{
remove_entities_without_endpoints(entities);
std::vector<const ExtrusionEntity*> out;
out.reserve(entities.size());
for (const auto &[idx, reverse] : chain_extrusion_entities_impl(entities, &start_near)) {
if (reverse) {
ExtrusionEntity *clone = reversed_clones.emplace_back(entities[idx]->clone()).get();
clone->reverse();
out.emplace_back(clone);
} else
out.emplace_back(entities[idx]);
}
entities.swap(out);
}
std::vector<std::pair<size_t, bool>> chain_extrusion_paths(std::vector<ExtrusionPath> &extrusion_paths, const Point *start_near)
{
auto segment_end_point = [&extrusion_paths](size_t idx, bool first_point) -> Point { return first_point ? extrusion_paths[idx].first_point() : extrusion_paths[idx].last_point(); };
+4
View File
@@ -5,6 +5,7 @@
#include "ExtrusionEntity.hpp"
#include "Point.hpp"
#include <memory>
#include <utility>
#include <vector>
@@ -24,6 +25,9 @@ std::vector<std::pair<size_t, bool>> chain_extrusion_entities(std::vector<Extrus
void reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const std::vector<std::pair<size_t, bool>> &chain);
void chain_and_reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point &start_near);
void chain_and_reorder_extrusion_entities(std::vector<ExtrusionEntity*> &entities, const Point *start_near = nullptr);
// Each entity the chain reverses is replaced by a reversed clone that reversed_clones owns, so the originals stay unchanged.
void chain_and_reorder_extrusion_entities(std::vector<const ExtrusionEntity*> &entities, const Point &start_near,
std::vector<std::unique_ptr<ExtrusionEntity>> &reversed_clones);
std::vector<std::pair<size_t, bool>> chain_extrusion_paths(std::vector<ExtrusionPath> &extrusion_paths, const Point *start_near = nullptr);
void reorder_extrusion_paths(std::vector<ExtrusionPath> &extrusion_paths, std::vector<std::pair<size_t, bool>> &chain);
+3 -2
View File
@@ -225,7 +225,7 @@ DynamicPrintConfig multifilament_config(unsigned int filaments, std::initializer
}
void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in,
const std::vector<std::vector<ConfigBase::SetDeserializeItem>> *per_object_overrides, bool arrange)
const std::vector<std::vector<ConfigBase::SetDeserializeItem>> *per_object_overrides, bool arrange, size_t instances)
{
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
config.apply(config_in);
@@ -236,7 +236,8 @@ void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r
ModelObject *object = model.add_object();
object->name += "object.stl";
object->add_volume(std::move(t));
object->add_instance();
for (size_t i = 0; i < instances; ++i)
object->add_instance();
if (per_object_overrides && object_idx < per_object_overrides->size() && !(*per_object_overrides)[object_idx].empty()) {
DynamicPrintConfig oc;
+4 -2
View File
@@ -72,9 +72,11 @@ Slic3r::Model model(const std::string& model_name, TriangleMesh&& _mesh);
DynamicPrintConfig multifilament_config(unsigned int filaments,
std::initializer_list<Slic3r::ConfigBase::SetDeserializeItem> extra = {});
// Apply `meshes` and config to `print`/`model`; optional per-object overrides, auto-arranged unless `arrange` is false.
// Apply `meshes` and config to `print`/`model`, each object with `instances` copies; optional per-object overrides,
// auto-arranged unless `arrange` is false.
void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in,
const std::vector<std::vector<Slic3r::ConfigBase::SetDeserializeItem>> *per_object_overrides = nullptr, bool arrange = true);
const std::vector<std::vector<Slic3r::ConfigBase::SetDeserializeItem>> *per_object_overrides = nullptr, bool arrange = true,
size_t instances = 1);
void init_print(std::initializer_list<TestMesh> meshes, Slic3r::Print &print, Slic3r::Model &model, const Slic3r::DynamicPrintConfig &config_in = Slic3r::DynamicPrintConfig::full_print_config());
void init_print(std::initializer_list<TriangleMesh> meshes, Slic3r::Print &print, Slic3r::Model &model, const Slic3r::DynamicPrintConfig &config_in = Slic3r::DynamicPrintConfig::full_print_config());
void init_print(std::initializer_list<TestMesh> meshes, Slic3r::Print &print, Slic3r::Model &model, std::initializer_list<Slic3r::ConfigBase::SetDeserializeItem> config_items);
+34
View File
@@ -561,6 +561,40 @@ TEST_CASE("export_gcode writes G-code without a result pointer", "[Print][export
REQUIRE_FALSE(gcode.empty());
}
TEST_CASE("Exporting a sliced print again gives the same G-code", "[Print][export_gcode][Regression]")
{
const int instances = GENERATE(1, 3);
CAPTURE(instances);
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
TestMesh mesh = TestMesh::ipadstand;
SECTION("infill reversed by chaining") { config.set_deserialize_strict({{"sparse_infill_pattern", "gyroid"}}); }
SECTION("support reversed by chaining") {
mesh = TestMesh::overhang;
config.set_deserialize_strict({{"enable_support", true}, {"support_interface_pattern", "concentric"}});
}
Print print;
Model model;
Slic3r::Test::init_print({Slic3r::Test::mesh(mesh)}, print, model, config, nullptr, true, instances);
const auto export_without_timestamp = [&print]() {
std::string gcode = Slic3r::Test::gcode(print);
const size_t line = gcode.find("; generated by ");
REQUIRE(line != std::string::npos);
gcode.erase(line, gcode.find('\n', line) - line);
return gcode;
};
const std::string first = export_without_timestamp();
const std::string second = export_without_timestamp();
// Shows the first differing line on failure.
const size_t diff = std::mismatch(first.begin(), first.end(), second.begin(), second.end()).first - first.begin();
const size_t line_start = diff == 0 ? 0 : first.rfind('\n', diff - 1) + 1;
INFO("first export: " << first.substr(line_start, first.find('\n', diff) - line_start));
INFO("second export: " << second.substr(line_start, second.find('\n', diff) - line_start));
CHECK(diff == first.size());
CHECK(first.size() == second.size());
}
TEST_CASE("Sequential printing follows model order", "[Print]")
{
// Two objects of different heights, taller one added first. Orca prints
@@ -1,39 +1,6 @@
#include <catch2/catch_all.hpp>
#include "slic3r/Utils/Http.hpp"
#include "slic3r/Utils/OrcaCloudServiceAgent.hpp"
namespace {
nlohmann::json flat_session_json(const nlohmann::json& fields)
{
nlohmann::json session = {
{"access_token", "test-token"},
{"user_id", "test-user-id"}
};
session.update(fields);
return session;
}
nlohmann::json nested_session_json(const nlohmann::json& metadata)
{
return {
{"access_token", "test-token"},
{"user", {
{"id", "test-user-id"},
{"user_metadata", metadata}
}}
};
}
std::string resolved_display_name(const nlohmann::json& session)
{
Slic3r::OrcaCloudServiceAgent agent("");
REQUIRE(agent.set_user_session(session, false));
return agent.get_user_nickname();
}
} // namespace
TEST_CASE("Check SSL certificates paths", "[Http][NotWorking]") {
@@ -53,62 +20,6 @@ TEST_CASE("Check SSL certificates paths", "[Http][NotWorking]") {
REQUIRE(status == 200);
}
TEST_CASE("Orca cloud flat session resolves display name consistently", "[OrcaCloudServiceAgent]")
{
CHECK(resolved_display_name(flat_session_json({
{"username", "orca_username"},
{"display_name", "Display Name"},
{"nickname", "Nickname"}
})) == "Display Name");
CHECK(resolved_display_name(flat_session_json({
{"username", "orca_username"},
{"nickname", "Nickname"}
})) == "Nickname");
CHECK(resolved_display_name(flat_session_json({
{"username", "orca_username"},
{"full_name", "Full Name"}
})) == "Full Name");
CHECK(resolved_display_name(flat_session_json({
{"username", "orca_username"},
{"name", "Provider Name"}
})) == "Provider Name");
CHECK(resolved_display_name(flat_session_json({
{"username", "orca_username"}
})) == "orca_username");
}
TEST_CASE("Orca cloud nested session resolves display name consistently", "[OrcaCloudServiceAgent]")
{
CHECK(resolved_display_name(nested_session_json({
{"username", "orca_username"},
{"display_name", "Display Name"},
{"nickname", "Nickname"}
})) == "Display Name");
CHECK(resolved_display_name(nested_session_json({
{"username", "orca_username"},
{"nickname", "Nickname"}
})) == "Nickname");
CHECK(resolved_display_name(nested_session_json({
{"username", "orca_username"},
{"full_name", "Full Name"}
})) == "Full Name");
CHECK(resolved_display_name(nested_session_json({
{"username", "orca_username"},
{"name", "Provider Name"}
})) == "Provider Name");
CHECK(resolved_display_name(nested_session_json({
{"username", "orca_username"}
})) == "orca_username");
}
TEST_CASE("Http digest authentication", "[Http][NotWorking]") {
Slic3r::Http g = Slic3r::Http::get("https://httpbingo.org/digest-auth/auth/guest/guest");
@@ -27,6 +27,37 @@ std::unique_ptr<OrcaCloudServiceAgent> make_file_backed_agent(const fs::path& di
fs::path secret_file(const fs::path& dir) { return dir / secret_constants::USER_SECRET_FILENAME; }
nlohmann::json flat_session_json(const nlohmann::json& fields)
{
nlohmann::json session = {
{"access_token", "test-token"},
{"user_id", "test-user-id"}
};
session.update(fields);
return session;
}
nlohmann::json nested_session_json(const nlohmann::json& metadata)
{
return {
{"access_token", "test-token"},
{"user", {
{"id", "test-user-id"},
{"user_metadata", metadata}
}}
};
}
// set_user_session() persists the session, so it goes to a throwaway token file rather than the
// system keychain of whoever runs the tests.
std::string resolved_display_name(const nlohmann::json& session)
{
ScopedTemporaryDir dir("orca-secret");
auto agent = make_file_backed_agent(dir.path());
REQUIRE(agent->set_user_session(session, false));
return agent->get_user_nickname();
}
} // namespace
TEST_CASE("Logging out removes the secret this instance saved", "[OrcaCloudServiceAgent]")
@@ -84,3 +115,59 @@ TEST_CASE("Logging out leaves a secret this instance could not read alone", "[Or
agent->user_logout(false);
CHECK(fs::exists(secret_file(dir.path())));
}
TEST_CASE("Orca cloud flat session resolves display name consistently", "[OrcaCloudServiceAgent]")
{
CHECK(resolved_display_name(flat_session_json({
{"username", "orca_username"},
{"display_name", "Display Name"},
{"nickname", "Nickname"}
})) == "Display Name");
CHECK(resolved_display_name(flat_session_json({
{"username", "orca_username"},
{"nickname", "Nickname"}
})) == "Nickname");
CHECK(resolved_display_name(flat_session_json({
{"username", "orca_username"},
{"full_name", "Full Name"}
})) == "Full Name");
CHECK(resolved_display_name(flat_session_json({
{"username", "orca_username"},
{"name", "Provider Name"}
})) == "Provider Name");
CHECK(resolved_display_name(flat_session_json({
{"username", "orca_username"}
})) == "orca_username");
}
TEST_CASE("Orca cloud nested session resolves display name consistently", "[OrcaCloudServiceAgent]")
{
CHECK(resolved_display_name(nested_session_json({
{"username", "orca_username"},
{"display_name", "Display Name"},
{"nickname", "Nickname"}
})) == "Display Name");
CHECK(resolved_display_name(nested_session_json({
{"username", "orca_username"},
{"nickname", "Nickname"}
})) == "Nickname");
CHECK(resolved_display_name(nested_session_json({
{"username", "orca_username"},
{"full_name", "Full Name"}
})) == "Full Name");
CHECK(resolved_display_name(nested_session_json({
{"username", "orca_username"},
{"name", "Provider Name"}
})) == "Provider Name");
CHECK(resolved_display_name(nested_session_json({
{"username", "orca_username"}
})) == "orca_username");
}