#include #include "libslic3r/PlaceholderParser.hpp" #include "libslic3r/PrintConfig.hpp" using namespace Slic3r; SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") { PlaceholderParser parser; auto config = DynamicPrintConfig::full_print_config(); config.set_deserialize_strict( { { "printer_notes", " PRINTER_VENDOR_PRUSA3D PRINTER_MODEL_MK2 " }, { "nozzle_diameter", "0.6;0.6;0.6;0.6" }, { "nozzle_temperature", "357;359;363;378" } }); // To let the PlaceholderParser throw when referencing initial_layer_line_width if it is set to percent, as the PlaceholderParser does not know // a percent to what. config.option("initial_layer_line_width")->value = 50.; config.option("initial_layer_line_width")->percent = true; parser.apply_config(config); parser.set("foo", 0); parser.set("bar", 2); parser.set("num_extruders", 4); SECTION("nested config options (legacy syntax)") { REQUIRE(parser.process("[nozzle_temperature_[foo]]") == "357"); } SECTION("array reference") { REQUIRE(parser.process("{nozzle_temperature[foo]}") == "357"); } SECTION("whitespaces and newlines are maintained") { REQUIRE(parser.process("test [ nozzle_temperature_ [foo] ] \n hu") == "test 357 \n hu"); } // Test the "coFloatOrPercent" and "xxx_width" substitutions. // FIXME: Don't know what exactly this referred to in Prusaslicer or // whether it should apply to Orca or not. // {outer_wall_line_width} returns as its default value, 0. // SECTION("outer_wall_line_width") { REQUIRE(std::stod(parser.process("{outer_wall_line_width}")) == Catch::Approx(0.67500001192092896)); } SECTION("support_object_xy_distance") { REQUIRE(std::stod(parser.process("{support_object_xy_distance}")) == Catch::Approx(0.35)); } // initial_layer_line_width ratio over nozzle_diameter. // FIXME: either something else which correctly calculates a ratio should be here, // or something else should be found for for the REQUIRE_THROWS // SECTION("initial_layer_line_width") { REQUIRE(std::stod(parser.process("{initial_layer_line_width}")) == Catch::Approx(0.9)); } // small_perimeter_speed ratio over outer_wall_speed SECTION("small_perimeter_speed") { REQUIRE(std::stod(parser.process("{small_perimeter_speed}")) == Catch::Approx(30.)); } // infill_wall_overlap over inner_wall_line_width // FIXME: Shouldn't this return the calculated value and not the percentage 15? // SECTION("infill_wall_overlap") { REQUIRE(std::stod(parser.process("{infill_wall_overlap}")) == Catch::Approx(0.16875)); } // If initial_layer_line_width is set to percent, then it is applied over respective extrusion types by overriding their respective speeds. // The PlaceholderParser has no way to know which extrusion type the caller has in mind, therefore it throws. SECTION("initial_layer_line_width throws failed to resolve the ratio_over dependencies") { REQUIRE_THROWS(parser.process("{initial_layer_line_width}")); } // Test the math expressions. SECTION("math: 2*3") { REQUIRE(parser.process("{2*3}") == "6"); } SECTION("math: 2*3/6") { REQUIRE(parser.process("{2*3/6}") == "1"); } SECTION("math: 2*3/12") { REQUIRE(parser.process("{2*3/12}") == "0"); } SECTION("math: 2.*3/12") { REQUIRE(std::stod(parser.process("{2.*3/12}")) == Catch::Approx(0.5)); } SECTION("math: 10 % 2.5") { REQUIRE(std::stod(parser.process("{10%2.5}")) == Catch::Approx(0.)); } SECTION("math: 11 % 2.5") { REQUIRE(std::stod(parser.process("{11%2.5}")) == Catch::Approx(1.)); } SECTION("math: 2*(3-12)") { REQUIRE(parser.process("{2*(3-12)}") == "-18"); } SECTION("math: 2*foo*(3-12)") { REQUIRE(parser.process("{2*foo*(3-12)}") == "0"); } SECTION("math: 2*bar*(3-12)") { REQUIRE(parser.process("{2*bar*(3-12)}") == "-36"); } SECTION("math: 2.5*bar*(3-12)") { REQUIRE(std::stod(parser.process("{2.5*bar*(3-12)}")) == Catch::Approx(-45)); } SECTION("math: min(12, 14)") { REQUIRE(parser.process("{min(12, 14)}") == "12"); } SECTION("math: max(12, 14)") { REQUIRE(parser.process("{max(12, 14)}") == "14"); } SECTION("math: min(13.4, -1238.1)") { REQUIRE(std::stod(parser.process("{min(13.4, -1238.1)}")) == Catch::Approx(-1238.1)); } SECTION("math: max(13.4, -1238.1)") { REQUIRE(std::stod(parser.process("{max(13.4, -1238.1)}")) == Catch::Approx(13.4)); } SECTION("math: int(13.4)") { REQUIRE(parser.process("{int(13.4)}") == "13"); } SECTION("math: int(-13.4)") { REQUIRE(parser.process("{int(-13.4)}") == "-13"); } SECTION("math: round(13.4)") { REQUIRE(parser.process("{round(13.4)}") == "13"); } SECTION("math: round(-13.4)") { REQUIRE(parser.process("{round(-13.4)}") == "-13"); } SECTION("math: round(13.6)") { REQUIRE(parser.process("{round(13.6)}") == "14"); } SECTION("math: round(-13.6)") { REQUIRE(parser.process("{round(-13.6)}") == "-14"); } SECTION("math: digits(5, 15)") { REQUIRE(parser.process("{digits(5, 15)}") == " 5"); } SECTION("math: digits(5., 15)") { REQUIRE(parser.process("{digits(5., 15)}") == " 5"); } SECTION("math: zdigits(5, 15)") { REQUIRE(parser.process("{zdigits(5, 15)}") == "000000000000005"); } SECTION("math: zdigits(5., 15)") { REQUIRE(parser.process("{zdigits(5., 15)}") == "000000000000005"); } SECTION("math: digits(5, 15, 8)") { REQUIRE(parser.process("{digits(5, 15, 8)}") == " 5.00000000"); } SECTION("math: digits(5., 15, 8)") { REQUIRE(parser.process("{digits(5, 15, 8)}") == " 5.00000000"); } SECTION("math: zdigits(5, 15, 8)") { REQUIRE(parser.process("{zdigits(5, 15, 8)}") == "000005.00000000"); } SECTION("math: zdigits(5., 15, 8)") { REQUIRE(parser.process("{zdigits(5, 15, 8)}") == "000005.00000000"); } SECTION("math: digits(13.84375892476, 15, 8)") { REQUIRE(parser.process("{digits(13.84375892476, 15, 8)}") == " 13.84375892"); } SECTION("math: zdigits(13.84375892476, 15, 8)") { REQUIRE(parser.process("{zdigits(13.84375892476, 15, 8)}") == "000013.84375892"); } SECTION("math: interpolate_table(13.84375892476, (0, 0), (20, 20))") { REQUIRE(std::stod(parser.process("{interpolate_table(13.84375892476, (0, 0), (20, 20))}")) == Catch::Approx(13.84375892476)); } SECTION("math: interpolate_table(13, (0, 0), (20, 20), (30, 20))") { REQUIRE(std::stod(parser.process("{interpolate_table(13, (0, 0), (20, 20), (30, 20))}")) == Catch::Approx(13.)); } SECTION("math: interpolate_table(25, (0, 0), (20, 20), (30, 20))") { REQUIRE(std::stod(parser.process("{interpolate_table(25, (0, 0), (20, 20), (30, 20))}")) == Catch::Approx(20.)); } // Test the boolean expression parser. auto boolean_expression = [&parser](const std::string& templ) { return parser.evaluate_boolean_expression(templ, parser.config()); }; SECTION("boolean expression parser: 12 == 12") { REQUIRE(boolean_expression("12 == 12")); } SECTION("boolean expression parser: 12 != 12") { REQUIRE(! boolean_expression("12 != 12")); } SECTION("boolean expression parser: regex matches") { REQUIRE(boolean_expression("\"has some PATTERN embedded\" =~ /.*PATTERN.*/")); } SECTION("boolean expression parser: regex does not match") { REQUIRE(! boolean_expression("\"has some PATTERN embedded\" =~ /.*PTRN.*/")); } SECTION("boolean expression parser: accessing variables, equal") { REQUIRE(boolean_expression("foo + 2 == bar")); } SECTION("boolean expression parser: accessing variables, not equal") { REQUIRE(! boolean_expression("foo + 3 == bar")); } SECTION("boolean expression parser: (12 == 12) and (13 != 14)") { REQUIRE(boolean_expression("(12 == 12) and (13 != 14)")); } SECTION("boolean expression parser: (12 == 12) && (13 != 14)") { REQUIRE(boolean_expression("(12 == 12) && (13 != 14)")); } SECTION("boolean expression parser: (12 == 12) or (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) or (13 == 14)")); } SECTION("boolean expression parser: (12 == 12) || (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) || (13 == 14)")); } SECTION("boolean expression parser: (12 == 12) and not (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) and not (13 == 14)")); } SECTION("boolean expression parser: ternary true") { REQUIRE(boolean_expression("(12 == 12) ? (1 - 1 == 0) : (2 * 2 == 3)")); } SECTION("boolean expression parser: ternary false") { REQUIRE(! boolean_expression("(12 == 21/2) ? (1 - 1 == 0) : (2 * 2 == 3)")); } SECTION("boolean expression parser: ternary false 2") { REQUIRE(boolean_expression("(12 == 13) ? (1 - 1 == 3) : (2 * 2 == 4)")); } SECTION("boolean expression parser: ternary true 2") { REQUIRE(! boolean_expression("(12 == 2 * 6) ? (1 - 1 == 3) : (2 * 2 == 4)")); } SECTION("boolean expression parser: lower than - false") { REQUIRE(! boolean_expression("12 < 3")); } SECTION("boolean expression parser: lower than - true") { REQUIRE(boolean_expression("12 < 22")); } SECTION("boolean expression parser: greater than - true") { REQUIRE(boolean_expression("12 > 3")); } SECTION("boolean expression parser: greater than - false") { REQUIRE(! boolean_expression("12 > 22")); } SECTION("boolean expression parser: lower than or equal- false") { REQUIRE(! boolean_expression("12 <= 3")); } SECTION("boolean expression parser: lower than or equal - true") { REQUIRE(boolean_expression("12 <= 22")); } SECTION("boolean expression parser: greater than or equal - true") { REQUIRE(boolean_expression("12 >= 3")); } SECTION("boolean expression parser: greater than or equal - false") { REQUIRE(! boolean_expression("12 >= 22")); } SECTION("boolean expression parser: lower than or equal (same values) - true") { REQUIRE(boolean_expression("12 <= 12")); } SECTION("boolean expression parser: greater than or equal (same values) - true") { REQUIRE(boolean_expression("12 >= 12")); } SECTION("complex expression") { REQUIRE(boolean_expression("printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1")); } SECTION("complex expression2") { REQUIRE(boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.6 and num_extruders>1)")); } SECTION("complex expression3") { REQUIRE(! boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.3 and num_extruders>1)")); } }