Files
OrcaSlicer/tests/libslic3r/test_step.cpp
T
HanifKoh 84657ff11e Add Missing Includes Across the Remaining Sources and Tests (#16071)
* Ignore Clipper, libpng, mcut and Boost.Polygon Internals in clang-tidy

Each only works through a wrapper or umbrella header: libslic3r/clipper.hpp or clipper_z.hpp configure Clipper before including it, png.h pulls in libpng's config headers, and Boost.Polygon's headers only compile through polygon.hpp or voronoi.hpp.

* Ignore minilzo's Config Headers in clang-tidy

lzoconf.h and lzodefs.h are internal to minilzo.h, which is what the code includes.

* Add Missing Includes Across the Remaining Sources and Tests

Covers src/slic3r/Utils, src/slic3r/plugin, src/slic3r/Config, src/libvgcode, src/dev-utils, src/OrcaSlicer.cpp and tests/, the directories left after src/slic3r/GUI and src/libslic3r. Generated with clang-tidy misc-include-cleaner. libvgcode's own headers are included by relative path as in the rest of that library, and Catch2 and pybind11 with angle brackets as elsewhere in the repo.

* Make the GUI and Test Headers Compile on Their Own

Each now includes, or forward-declares, what it uses instead of relying on what its includers happened to include first. Headers that only compile on one platform, or that nothing built includes, are left alone.

* Keep Windows and nanosvg Setup Ahead of the Added Includes

OrcaSlicer.cpp and several tests set _WIN32_WINNT, WIN32_LEAN_AND_MEAN or NOMINMAX before including Windows.h, and the profile validator defines NANOSVG_IMPLEMENTATION before any libslic3r header. The added includes had landed above those blocks, which broke the Windows build.

* Add the GUI Includes the First Pass Missed

Covers headers that only became editable once they compiled on their own, and wx symbols whose suggested header changed as the clang-tidy ignore list grew after the src/slic3r/GUI pass.

* Keep the Added Test Includes Below the NOMINMAX Guard

test_marchingsquares.cpp and test_texture_displacement.cpp had includes inside #ifndef NOMINMAX, which the tests inherit as defined on Windows from libslic3r, so those were skipped there. .clang-tidy also ignores the MSVC STL and UCRT internals, Boost.Multiprecision's fwd.hpp and CPython's Windows include directory, as in #16068.
2026-10-03 13:45:21 +08:00

98 lines
3.8 KiB
C++

#include <catch2/catch_all.hpp>
#include <boost/nowide/fstream.hpp>
#include <string>
#include <ios>
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>
#include "libslic3r/Model.hpp"
#include "libslic3r/Format/STEP.hpp"
#include "test_utils.hpp"
using namespace Slic3r;
static void write_step_line(const std::string &path, const std::string &line)
{
boost::nowide::ofstream file(path, std::ios::binary);
file << "ISO-10303-21;\n" << line << "\nEND-ISO-10303-21;\n";
}
// preprocess() hands back the input path unless it transcoded into a temporary.
static std::string preprocess_result(const std::string &line)
{
ScopedSlic3rTemporaryDir scratch;
ScopedTemporaryFile step(".step");
write_step_line(step.string(), line);
std::string output_path;
StepPreProcessor preprocessor;
REQUIRE(preprocessor.preprocess(step.string().c_str(), output_path));
return output_path == step.string() ? "untouched" : "transcoded";
}
// data/utf8_part_names.step is three boxes written by OCCT's own STEP writer, whose
// PRODUCT names were then patched to raw UTF-8. Most CAD exporters write non-ASCII names
// that way rather than in the \X2\ escape form. The third part is ASCII, as a control.
TEST_CASE("Part names with multi-byte UTF-8 survive import", "[Step]")
{
// getNamedSolids() replaces a name that isUtf8() rejects with a running number.
const std::string path = TEST_DATA_DIR PATH_SEPARATOR "utf8_part_names.step";
Model model;
bool cancel = false;
Step step(path); // no isUtf8Fn, matching how Model::read_from_step builds it
REQUIRE(step.load() == Step::Step_Status::LOAD_SUCCESS);
REQUIRE(step.mesh(&model, cancel, false) == Step::Step_Status::MESH_SUCCESS);
REQUIRE(model.objects.size() == 1);
const ModelObject *object = model.objects.front();
REQUIRE(object->volumes.size() == 3);
// "ce" is split off, or the hex escape would swallow it as further hex digits.
CHECK(object->volumes[0]->name == "pi\xC3\xA8" "ce");
CHECK(object->volumes[1]->name == "Geh\xC3\xA4use");
CHECK(object->volumes[2]->name == "bracket");
}
TEST_CASE("isUtf8 recognises two, three and four byte sequences", "[Step]")
{
CHECK(StepPreProcessor::isUtf8("\xC3\xA9")); // U+00E9
CHECK(StepPreProcessor::isUtf8("\xE4\xB8\xAD")); // U+4E2D
CHECK(StepPreProcessor::isUtf8("\xF0\x9F\x94\xA9")); // U+1F529
CHECK_FALSE(StepPreProcessor::isUtf8("\x81\x30")); // 0x81 is not a lead byte
CHECK_FALSE(StepPreProcessor::isUtf8("\xC3")); // truncated sequence
}
// The only caller of isGBK is preprocess(), which nothing calls today.
TEST_CASE("Encoding detection decides whether a step file is transcoded", "[Step]")
{
SECTION("UTF-8, so left alone")
{
// A two byte sequence also satisfies every GBK range, so misdetecting it as
// not-UTF-8 sends it to be transcoded.
const std::string sequence = GENERATE(std::string("\xC3\xA9"), // U+00E9
std::string("\xE4\xB8\xAD"), // U+4E2D
std::string("\xF0\x9F\x94\xA9")); // U+1F529
CHECK(preprocess_result("NAME('" + sequence + "');") == "untouched");
}
SECTION("neither UTF-8 nor GBK, so left alone")
{
// 0x81 is not a UTF-8 lead byte, and 0x30 is below the 0x40 floor for a GBK trail.
CHECK(preprocess_result("NAME('\x81\x30');") == "untouched");
}
SECTION("GBK, so transcoded")
{
// U+554A in GBK, whose lead byte is not valid UTF-8. Pins the other direction,
// since a detector that never reports GBK would pass every case above.
CHECK(preprocess_result("NAME('\xB0\xA1');") == "transcoded");
}
SECTION("plain ASCII, so left alone") { CHECK(preprocess_result("NAME('bracket');") == "untouched"); }
}