test_placeholder_parser.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #include <catch2/catch.hpp>
  2. #include "libslic3r/PlaceholderParser.hpp"
  3. #include "libslic3r/PrintConfig.hpp"
  4. using namespace Slic3r;
  5. SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
  6. PlaceholderParser parser;
  7. auto config = DynamicPrintConfig::full_print_config();
  8. // To test the "first_layer_extrusion_width" over "nozzle_diameter" chain.
  9. config.set_deserialize_strict( {
  10. { "printer_notes", " PRINTER_VENDOR_PRUSA3D PRINTER_MODEL_MK2 " },
  11. { "nozzle_diameter", "0.6;0.6;0.6;0.6" },
  12. { "temperature", "357;359;363;378" }
  13. });
  14. // To test the "first_layer_extrusion_width" over "first_layer_heigth". <- not supported anymore
  15. // "first_layer_heigth" over "layer_height" is no more supported after first_layer_height was moved from PrintObjectConfig to PrintConfig.
  16. // config.option<ConfigOptionFloatOrPercent>("first_layer_height")->value = 150.;
  17. // config.option<ConfigOptionFloatOrPercent>("first_layer_height")->percent = true;
  18. config.option<ConfigOptionFloatOrPercent>("first_layer_height")->value = 1.5 * config.opt_float("layer_height");
  19. config.option<ConfigOptionFloatOrPercent>("first_layer_height")->percent = false;
  20. // To let the PlaceholderParser throw when referencing first_layer_speed if it is set to percent, as the PlaceholderParser does not know
  21. // a percent to what.
  22. config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->value = 50.;
  23. config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->percent = true;
  24. config.option<ConfigOptionFloatOrPercent>("first_layer_extrusion_width")->value = 150.;
  25. config.option<ConfigOptionFloatOrPercent>("first_layer_extrusion_width")->percent = true;
  26. config.option<ConfigOptionFloatOrPercent>("support_material_xy_spacing")->value = 50.;
  27. config.option<ConfigOptionFloatOrPercent>("support_material_xy_spacing")->percent = true;
  28. parser.apply_config(config);
  29. parser.set("foo", 0);
  30. parser.set("bar", 2);
  31. parser.set("num_extruders", 4);
  32. SECTION("nested config options (legacy syntax)") { REQUIRE(parser.process("[temperature_[foo]]") == "357"); }
  33. SECTION("array reference") { REQUIRE(parser.process("{temperature[foo]}") == "357"); }
  34. SECTION("whitespaces and newlines are maintained") { REQUIRE(parser.process("test [ temperature_ [foo] ] \n hu") == "test 357 \n hu"); }
  35. // Test the math expressions.
  36. SECTION("math: 2*3") { REQUIRE(parser.process("{2*3}") == "6"); }
  37. SECTION("math: 2*3/6") { REQUIRE(parser.process("{2*3/6}") == "1"); }
  38. SECTION("math: 2*3/12") { REQUIRE(parser.process("{2*3/12}") == "0"); }
  39. SECTION("math: 2.*3/12") { REQUIRE(std::stod(parser.process("{2.*3/12}")) == Approx(0.5)); }
  40. SECTION("math: 10 % 2.5") { REQUIRE(std::stod(parser.process("{10%2.5}")) == Approx(0.)); }
  41. SECTION("math: 11 % 2.5") { REQUIRE(std::stod(parser.process("{11%2.5}")) == Approx(1.)); }
  42. SECTION("math: 2*(3-12)") { REQUIRE(parser.process("{2*(3-12)}") == "-18"); }
  43. SECTION("math: 2*foo*(3-12)") { REQUIRE(parser.process("{2*foo*(3-12)}") == "0"); }
  44. SECTION("math: 2*bar*(3-12)") { REQUIRE(parser.process("{2*bar*(3-12)}") == "-36"); }
  45. SECTION("math: 2.5*bar*(3-12)") { REQUIRE(std::stod(parser.process("{2.5*bar*(3-12)}")) == Approx(-45)); }
  46. SECTION("math: min(12, 14)") { REQUIRE(parser.process("{min(12, 14)}") == "12"); }
  47. SECTION("math: max(12, 14)") { REQUIRE(parser.process("{max(12, 14)}") == "14"); }
  48. SECTION("math: min(13.4, -1238.1)") { REQUIRE(std::stod(parser.process("{min(13.4, -1238.1)}")) == Approx(-1238.1)); }
  49. SECTION("math: max(13.4, -1238.1)") { REQUIRE(std::stod(parser.process("{max(13.4, -1238.1)}")) == Approx(13.4)); }
  50. SECTION("math: int(13.4)") { REQUIRE(parser.process("{int(13.4)}") == "13"); }
  51. SECTION("math: int(-13.4)") { REQUIRE(parser.process("{int(-13.4)}") == "-13"); }
  52. SECTION("math: round(13.4)") { REQUIRE(parser.process("{round(13.4)}") == "13"); }
  53. SECTION("math: round(-13.4)") { REQUIRE(parser.process("{round(-13.4)}") == "-13"); }
  54. SECTION("math: round(13.6)") { REQUIRE(parser.process("{round(13.6)}") == "14"); }
  55. SECTION("math: round(-13.6)") { REQUIRE(parser.process("{round(-13.6)}") == "-14"); }
  56. SECTION("math: digits(5, 15)") { REQUIRE(parser.process("{digits(5, 15)}") == " 5"); }
  57. SECTION("math: digits(5., 15)") { REQUIRE(parser.process("{digits(5., 15)}") == " 5"); }
  58. SECTION("math: zdigits(5, 15)") { REQUIRE(parser.process("{zdigits(5, 15)}") == "000000000000005"); }
  59. SECTION("math: zdigits(5., 15)") { REQUIRE(parser.process("{zdigits(5., 15)}") == "000000000000005"); }
  60. SECTION("math: digits(5, 15, 8)") { REQUIRE(parser.process("{digits(5, 15, 8)}") == " 5.00000000"); }
  61. SECTION("math: digits(5., 15, 8)") { REQUIRE(parser.process("{digits(5, 15, 8)}") == " 5.00000000"); }
  62. SECTION("math: zdigits(5, 15, 8)") { REQUIRE(parser.process("{zdigits(5, 15, 8)}") == "000005.00000000"); }
  63. SECTION("math: zdigits(5., 15, 8)") { REQUIRE(parser.process("{zdigits(5, 15, 8)}") == "000005.00000000"); }
  64. SECTION("math: digits(13.84375892476, 15, 8)") { REQUIRE(parser.process("{digits(13.84375892476, 15, 8)}") == " 13.84375892"); }
  65. SECTION("math: zdigits(13.84375892476, 15, 8)") { REQUIRE(parser.process("{zdigits(13.84375892476, 15, 8)}") == "000013.84375892"); }
  66. // Test the "coFloatOrPercent" and "xxx_extrusion_width" substitutions.
  67. SECTION("perimeter_extrusion_width") { REQUIRE(std::stod(parser.process("{perimeter_extrusion_width}")) == Approx(0.67500001192092896)); }
  68. // first_layer_extrusion_width ratio_over nozzle_diameter, 150% of 0.6 is 0.9
  69. SECTION("first_layer_extrusion_width") { REQUIRE(std::stod(parser.process("{first_layer_extrusion_width}")) == Approx(0.9)); }
  70. // support_material_xy_spacing is ratio over external_perimeter_extrusion_width
  71. // external_perimeter_extrusion_width is at 0 by default, and so will be 1.05f * nozzle = 0.63 do 50% of that is 0.315
  72. SECTION("support_material_xy_spacing") { REQUIRE(std::stod(parser.process("{support_material_xy_spacing}")) == Approx(0.315)); }
  73. // external_perimeter_speed over perimeter_speed
  74. SECTION("external_perimeter_speed") { REQUIRE(std::stod(parser.process("{external_perimeter_speed}")) == Approx(30.)); }
  75. // infill_overlap over perimeter_extrusion_width
  76. SECTION("infill_overlap") { REQUIRE(std::stod(parser.process("{infill_overlap}")) == Approx(0.16875)); }
  77. // If first_layer_speed is set to percent, then it is applied over respective extrusion types by overriding their respective speeds.
  78. // The PlaceholderParser has no way to know which extrusion type the caller has in mind, therefore it throws.
  79. SECTION("first_layer_speed") { REQUIRE_THROWS(parser.process("{first_layer_speed}")); }
  80. // Test the boolean expression parser.
  81. auto boolean_expression = [&parser](const std::string& templ) { return parser.evaluate_boolean_expression(templ, parser.config()); };
  82. SECTION("boolean expression parser: 12 == 12") { REQUIRE(boolean_expression("12 == 12")); }
  83. SECTION("boolean expression parser: 12 != 12") { REQUIRE(! boolean_expression("12 != 12")); }
  84. SECTION("boolean expression parser: regex matches") { REQUIRE(boolean_expression("\"has some PATTERN embedded\" =~ /.*PATTERN.*/")); }
  85. SECTION("boolean expression parser: regex does not match") { REQUIRE(! boolean_expression("\"has some PATTERN embedded\" =~ /.*PTRN.*/")); }
  86. SECTION("boolean expression parser: accessing variables, equal") { REQUIRE(boolean_expression("foo + 2 == bar")); }
  87. SECTION("boolean expression parser: accessing variables, not equal") { REQUIRE(! boolean_expression("foo + 3 == bar")); }
  88. SECTION("boolean expression parser: (12 == 12) and (13 != 14)") { REQUIRE(boolean_expression("(12 == 12) and (13 != 14)")); }
  89. SECTION("boolean expression parser: (12 == 12) && (13 != 14)") { REQUIRE(boolean_expression("(12 == 12) && (13 != 14)")); }
  90. SECTION("boolean expression parser: (12 == 12) or (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) or (13 == 14)")); }
  91. SECTION("boolean expression parser: (12 == 12) || (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) || (13 == 14)")); }
  92. SECTION("boolean expression parser: (12 == 12) and not (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) and not (13 == 14)")); }
  93. SECTION("boolean expression parser: ternary true") { REQUIRE(boolean_expression("(12 == 12) ? (1 - 1 == 0) : (2 * 2 == 3)")); }
  94. SECTION("boolean expression parser: ternary false") { REQUIRE(! boolean_expression("(12 == 21/2) ? (1 - 1 == 0) : (2 * 2 == 3)")); }
  95. SECTION("boolean expression parser: ternary false 2") { REQUIRE(boolean_expression("(12 == 13) ? (1 - 1 == 3) : (2 * 2 == 4)")); }
  96. SECTION("boolean expression parser: ternary true 2") { REQUIRE(! boolean_expression("(12 == 2 * 6) ? (1 - 1 == 3) : (2 * 2 == 4)")); }
  97. SECTION("boolean expression parser: lower than - false") { REQUIRE(! boolean_expression("12 < 3")); }
  98. SECTION("boolean expression parser: lower than - true") { REQUIRE(boolean_expression("12 < 22")); }
  99. SECTION("boolean expression parser: greater than - true") { REQUIRE(boolean_expression("12 > 3")); }
  100. SECTION("boolean expression parser: greater than - false") { REQUIRE(! boolean_expression("12 > 22")); }
  101. SECTION("boolean expression parser: lower than or equal- false") { REQUIRE(! boolean_expression("12 <= 3")); }
  102. SECTION("boolean expression parser: lower than or equal - true") { REQUIRE(boolean_expression("12 <= 22")); }
  103. SECTION("boolean expression parser: greater than or equal - true") { REQUIRE(boolean_expression("12 >= 3")); }
  104. SECTION("boolean expression parser: greater than or equal - false") { REQUIRE(! boolean_expression("12 >= 22")); }
  105. SECTION("boolean expression parser: lower than or equal (same values) - true") { REQUIRE(boolean_expression("12 <= 12")); }
  106. SECTION("boolean expression parser: greater than or equal (same values) - true") { REQUIRE(boolean_expression("12 >= 12")); }
  107. 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")); }
  108. 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)")); }
  109. 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)")); }
  110. }