test_gcodefindreplace.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #include <catch2/catch.hpp>
  2. #include <memory>
  3. #include "libslic3r/GCode/FindReplace.hpp"
  4. using namespace Slic3r;
  5. SCENARIO("Find/Replace with plain text", "[GCodeFindReplace]") {
  6. GIVEN("G-code") {
  7. const std::string gcode =
  8. "G1 Z0; home\n"
  9. "G1 Z1; move up\n"
  10. "G1 X0 Y1 Z1; perimeter\n"
  11. "G1 X13 Y32 Z1; infill\n"
  12. "G1 X13 Y32 Z1; wipe\n";
  13. WHEN("Replace \"move up\" with \"move down\", case sensitive") {
  14. GCodeFindReplace find_replace({ "move up", "move down", "", "" });
  15. REQUIRE(find_replace.process_layer(gcode) ==
  16. "G1 Z0; home\n"
  17. // substituted
  18. "G1 Z1; move down\n"
  19. "G1 X0 Y1 Z1; perimeter\n"
  20. "G1 X13 Y32 Z1; infill\n"
  21. "G1 X13 Y32 Z1; wipe\n");
  22. }
  23. WHEN("Replace \"move up\" with \"move down\", case insensitive") {
  24. GCodeFindReplace find_replace({ "move up", "move down", "i", "" });
  25. REQUIRE(find_replace.process_layer(gcode) ==
  26. "G1 Z0; home\n"
  27. // substituted
  28. "G1 Z1; move down\n"
  29. "G1 X0 Y1 Z1; perimeter\n"
  30. "G1 X13 Y32 Z1; infill\n"
  31. "G1 X13 Y32 Z1; wipe\n");
  32. }
  33. WHEN("Replace \"move UP\" with \"move down\", case insensitive") {
  34. GCodeFindReplace find_replace({ "move UP", "move down", "i", "" });
  35. REQUIRE(find_replace.process_layer(gcode) ==
  36. "G1 Z0; home\n"
  37. // substituted
  38. "G1 Z1; move down\n"
  39. "G1 X0 Y1 Z1; perimeter\n"
  40. "G1 X13 Y32 Z1; infill\n"
  41. "G1 X13 Y32 Z1; wipe\n");
  42. }
  43. WHEN("Replace \"move up\" with \"move down\", case sensitive") {
  44. GCodeFindReplace find_replace({ "move UP", "move down", "", "" });
  45. REQUIRE(find_replace.process_layer(gcode) == gcode);
  46. }
  47. // Whole word
  48. WHEN("Replace \"move up\" with \"move down\", whole word") {
  49. GCodeFindReplace find_replace({ "move up", "move down", "w", "" });
  50. REQUIRE(find_replace.process_layer(gcode) ==
  51. "G1 Z0; home\n"
  52. // substituted
  53. "G1 Z1; move down\n"
  54. "G1 X0 Y1 Z1; perimeter\n"
  55. "G1 X13 Y32 Z1; infill\n"
  56. "G1 X13 Y32 Z1; wipe\n");
  57. }
  58. WHEN("Replace \"move u\" with \"move down\", whole word") {
  59. GCodeFindReplace find_replace({ "move u", "move down", "w", "" });
  60. REQUIRE(find_replace.process_layer(gcode) == gcode);
  61. }
  62. WHEN("Replace \"ove up\" with \"move down\", whole word") {
  63. GCodeFindReplace find_replace({ "move u", "move down", "w", "" });
  64. REQUIRE(find_replace.process_layer(gcode) == gcode);
  65. }
  66. // Multi-line replace
  67. WHEN("Replace \"move up\\nG1 X0 \" with \"move down\\nG0 X1 \"") {
  68. GCodeFindReplace find_replace({ "move up\\nG1 X0 ", "move down\\nG0 X1 ", "", "" });
  69. REQUIRE(find_replace.process_layer(gcode) ==
  70. "G1 Z0; home\n"
  71. // substituted
  72. "G1 Z1; move down\n"
  73. "G0 X1 Y1 Z1; perimeter\n"
  74. "G1 X13 Y32 Z1; infill\n"
  75. "G1 X13 Y32 Z1; wipe\n");
  76. }
  77. // Multi-line replace, whole word.
  78. WHEN("Replace \"move up\\nG1 X0\" with \"move down\\nG0 X1\", whole word") {
  79. GCodeFindReplace find_replace({ "move up\\nG1 X0", "move down\\nG0 X1", "w", "" });
  80. REQUIRE(find_replace.process_layer(gcode) ==
  81. "G1 Z0; home\n"
  82. // substituted
  83. "G1 Z1; move down\n"
  84. "G0 X1 Y1 Z1; perimeter\n"
  85. "G1 X13 Y32 Z1; infill\n"
  86. "G1 X13 Y32 Z1; wipe\n");
  87. }
  88. // Multi-line replace, whole word, fails.
  89. WHEN("Replace \"move up\\nG1 X\" with \"move down\\nG0 X\", whole word") {
  90. GCodeFindReplace find_replace({ "move up\\nG1 X", "move down\\nG0 X", "w", "" });
  91. REQUIRE(find_replace.process_layer(gcode) == gcode);
  92. }
  93. }
  94. GIVEN("G-code with decimals") {
  95. const std::string gcode =
  96. "G1 Z0.123; home\n"
  97. "G1 Z1.21; move up\n"
  98. "G1 X0 Y.33 Z.431 E1.2; perimeter\n";
  99. WHEN("Regular expression NOT processed in non-regex mode") {
  100. GCodeFindReplace find_replace({ "( [XYZEF]-?)\\.([0-9]+)", "\\10.\\2", "", "" });
  101. REQUIRE(find_replace.process_layer(gcode) == gcode);
  102. }
  103. }
  104. }
  105. SCENARIO("Find/Replace with regexp", "[GCodeFindReplace]") {
  106. GIVEN("G-code") {
  107. const std::string gcode =
  108. "G1 Z0; home\n"
  109. "G1 Z1; move up\n"
  110. "G1 X0 Y1 Z1; perimeter\n"
  111. "G1 X13 Y32 Z1; infill\n"
  112. "G1 X13 Y32 Z1; wipe\n";
  113. WHEN("Replace \"move up\" with \"move down\", case sensitive") {
  114. GCodeFindReplace find_replace({ "move up", "move down", "r", "" });
  115. REQUIRE(find_replace.process_layer(gcode) ==
  116. "G1 Z0; home\n"
  117. // substituted
  118. "G1 Z1; move down\n"
  119. "G1 X0 Y1 Z1; perimeter\n"
  120. "G1 X13 Y32 Z1; infill\n"
  121. "G1 X13 Y32 Z1; wipe\n");
  122. }
  123. WHEN("Replace \"move up\" with \"move down\", case insensitive") {
  124. GCodeFindReplace find_replace({ "move up", "move down", "ri", "" });
  125. REQUIRE(find_replace.process_layer(gcode) ==
  126. "G1 Z0; home\n"
  127. // substituted
  128. "G1 Z1; move down\n"
  129. "G1 X0 Y1 Z1; perimeter\n"
  130. "G1 X13 Y32 Z1; infill\n"
  131. "G1 X13 Y32 Z1; wipe\n");
  132. }
  133. WHEN("Replace \"move UP\" with \"move down\", case insensitive") {
  134. GCodeFindReplace find_replace({ "move UP", "move down", "ri", "" });
  135. REQUIRE(find_replace.process_layer(gcode) ==
  136. "G1 Z0; home\n"
  137. // substituted
  138. "G1 Z1; move down\n"
  139. "G1 X0 Y1 Z1; perimeter\n"
  140. "G1 X13 Y32 Z1; infill\n"
  141. "G1 X13 Y32 Z1; wipe\n");
  142. }
  143. WHEN("Replace \"move up\" with \"move down\", case sensitive") {
  144. GCodeFindReplace find_replace({ "move UP", "move down", "r", "" });
  145. REQUIRE(find_replace.process_layer(gcode) == gcode);
  146. }
  147. // Whole word
  148. WHEN("Replace \"move up\" with \"move down\", whole word") {
  149. GCodeFindReplace find_replace({ "move up", "move down", "rw", "" });
  150. REQUIRE(find_replace.process_layer(gcode) ==
  151. "G1 Z0; home\n"
  152. // substituted
  153. "G1 Z1; move down\n"
  154. "G1 X0 Y1 Z1; perimeter\n"
  155. "G1 X13 Y32 Z1; infill\n"
  156. "G1 X13 Y32 Z1; wipe\n");
  157. }
  158. WHEN("Replace \"move u\" with \"move down\", whole word") {
  159. GCodeFindReplace find_replace({ "move u", "move down", "rw", "" });
  160. REQUIRE(find_replace.process_layer(gcode) == gcode);
  161. }
  162. WHEN("Replace \"ove up\" with \"move down\", whole word") {
  163. GCodeFindReplace find_replace({ "move u", "move down", "rw", "" });
  164. REQUIRE(find_replace.process_layer(gcode) == gcode);
  165. }
  166. // Multi-line replace
  167. WHEN("Replace \"move up\\nG1 X0 \" with \"move down\\nG0 X1 \"") {
  168. GCodeFindReplace find_replace({ "move up\\nG1 X0 ", "move down\\nG0 X1 ", "r", "" });
  169. REQUIRE(find_replace.process_layer(gcode) ==
  170. "G1 Z0; home\n"
  171. // substituted
  172. "G1 Z1; move down\n"
  173. "G0 X1 Y1 Z1; perimeter\n"
  174. "G1 X13 Y32 Z1; infill\n"
  175. "G1 X13 Y32 Z1; wipe\n");
  176. }
  177. // Multi-line replace, whole word.
  178. WHEN("Replace \"move up\\nG1 X0\" with \"move down\\nG0 X1\", whole word") {
  179. GCodeFindReplace find_replace({ "move up\\nG1 X0", "move down\\nG0 X1", "rw", "" });
  180. REQUIRE(find_replace.process_layer(gcode) ==
  181. "G1 Z0; home\n"
  182. // substituted
  183. "G1 Z1; move down\n"
  184. "G0 X1 Y1 Z1; perimeter\n"
  185. "G1 X13 Y32 Z1; infill\n"
  186. "G1 X13 Y32 Z1; wipe\n");
  187. }
  188. // Multi-line replace, whole word, fails.
  189. WHEN("Replace \"move up\\nG1 X\" with \"move down\\nG0 X\", whole word") {
  190. GCodeFindReplace find_replace({ "move up\\nG1 X", "move down\\nG0 X", "rw", "" });
  191. REQUIRE(find_replace.process_layer(gcode) == gcode);
  192. }
  193. }
  194. GIVEN("G-code with decimals") {
  195. const std::string gcode =
  196. "G1 Z0.123; home\n"
  197. "G1 Z1.21; move up\n"
  198. "G1 X0 Y.33 Z.431 E1.2; perimeter\n";
  199. WHEN("Missing zeros before dot filled in") {
  200. GCodeFindReplace find_replace({ "( [XYZEF]-?)\\.([0-9]+)", "\\10.\\2", "r", "" });
  201. REQUIRE(find_replace.process_layer(gcode) ==
  202. "G1 Z0.123; home\n"
  203. "G1 Z1.21; move up\n"
  204. "G1 X0 Y0.33 Z0.431 E1.2; perimeter\n");
  205. }
  206. }
  207. GIVEN("Single layer G-code block with extrusion types") {
  208. const std::string gcode =
  209. // Start of a layer.
  210. "G1 Z1.21; move up\n"
  211. ";TYPE:Infill\n"
  212. "G1 X0 Y.33 Z.431 E1.2\n"
  213. ";TYPE:Solid infill\n"
  214. "G1 X1 Y.3 Z.431 E0.1\n"
  215. ";TYPE:Top solid infill\n"
  216. "G1 X1 Y.3 Z.431 E0.1\n"
  217. ";TYPE:Top solid infill\n"
  218. "G1 X1 Y.3 Z.431 E0.1\n"
  219. ";TYPE:Perimeter\n"
  220. "G1 X0 Y.2 Z.431 E0.2\n"
  221. ";TYPE:External perimeter\n"
  222. "G1 X1 Y.3 Z.431 E0.1\n"
  223. ";TYPE:Top solid infill\n"
  224. "G1 X1 Y.3 Z.431 E0.1\n"
  225. ";TYPE:External perimeter\n"
  226. "G1 X1 Y.3 Z.431 E0.1\n";
  227. WHEN("Change extrusion rate of top solid infill, single line modifier") {
  228. GCodeFindReplace find_replace({ "(;TYPE:Top solid infill\\n)(.*?)(;TYPE:[^T][^o][^p][^ ][^s]|$)", "${1}M221 S98\\n${2}M221 S95\\n${3}", "rs", "" });
  229. REQUIRE(find_replace.process_layer(gcode) ==
  230. "G1 Z1.21; move up\n"
  231. ";TYPE:Infill\n"
  232. "G1 X0 Y.33 Z.431 E1.2\n"
  233. ";TYPE:Solid infill\n"
  234. "G1 X1 Y.3 Z.431 E0.1\n"
  235. ";TYPE:Top solid infill\n"
  236. "M221 S98\n"
  237. "G1 X1 Y.3 Z.431 E0.1\n"
  238. ";TYPE:Top solid infill\n"
  239. "G1 X1 Y.3 Z.431 E0.1\n"
  240. "M221 S95\n"
  241. ";TYPE:Perimeter\n"
  242. "G1 X0 Y.2 Z.431 E0.2\n"
  243. ";TYPE:External perimeter\n"
  244. "G1 X1 Y.3 Z.431 E0.1\n"
  245. ";TYPE:Top solid infill\n"
  246. "M221 S98\n"
  247. "G1 X1 Y.3 Z.431 E0.1\n"
  248. "M221 S95\n"
  249. ";TYPE:External perimeter\n"
  250. "G1 X1 Y.3 Z.431 E0.1\n");
  251. }
  252. WHEN("Change extrusion rate of top solid infill, no single line modifier (incorrect)") {
  253. GCodeFindReplace find_replace({ "(;TYPE:Top solid infill\\n)(.*?)(;TYPE:[^T][^o][^p][^ ][^s]|$)", "${1}M221 S98\\n${2}\\nM221 S95${3}", "r", "" });
  254. REQUIRE(find_replace.process_layer(gcode) ==
  255. "G1 Z1.21; move up\n"
  256. ";TYPE:Infill\n"
  257. "G1 X0 Y.33 Z.431 E1.2\n"
  258. ";TYPE:Solid infill\n"
  259. "G1 X1 Y.3 Z.431 E0.1\n"
  260. ";TYPE:Top solid infill\n"
  261. "M221 S98\n"
  262. "G1 X1 Y.3 Z.431 E0.1\n"
  263. "M221 S95\n"
  264. ";TYPE:Top solid infill\n"
  265. "M221 S98\n"
  266. "G1 X1 Y.3 Z.431 E0.1\n"
  267. "M221 S95\n"
  268. ";TYPE:Perimeter\n"
  269. "G1 X0 Y.2 Z.431 E0.2\n"
  270. ";TYPE:External perimeter\n"
  271. "G1 X1 Y.3 Z.431 E0.1\n"
  272. ";TYPE:Top solid infill\n"
  273. "M221 S98\n"
  274. "G1 X1 Y.3 Z.431 E0.1\n"
  275. "M221 S95\n"
  276. ";TYPE:External perimeter\n"
  277. "G1 X1 Y.3 Z.431 E0.1\n");
  278. }
  279. }
  280. }