1 #include <catch2/catch.hpp> 2 3 #include "libslic3r/PrintConfig.hpp" 4 5 using namespace Slic3r; 6 7 SCENARIO("Generic config validation performs as expected.", "[Config]") { 8 GIVEN("A config generated from default options") { 9 Slic3r::DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); 10 WHEN( "perimeter_extrusion_width is set to 250%, a valid value") { 11 config.set_deserialize_strict("perimeter_extrusion_width", "250%"); 12 THEN( "The config is read as valid.") { 13 REQUIRE(config.validate().empty()); 14 } 15 } 16 WHEN( "perimeter_extrusion_width is set to -10, an invalid value") { 17 config.set("perimeter_extrusion_width", -10); 18 THEN( "Validate returns error") { 19 REQUIRE(! config.validate().empty()); 20 } 21 } 22 23 WHEN( "perimeters is set to -10, an invalid value") { 24 config.set("perimeters", -10); 25 THEN( "Validate returns error") { 26 REQUIRE(! config.validate().empty()); 27 } 28 } 29 } 30 } 31 32 SCENARIO("Config accessor functions perform as expected.", "[Config]") { 33 GIVEN("A config generated from default options") { 34 Slic3r::DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); 35 WHEN("A boolean option is set to a boolean value") { 36 REQUIRE_NOTHROW(config.set("gcode_comments", true)); 37 THEN("The underlying value is set correctly.") { 38 REQUIRE(config.opt<ConfigOptionBool>("gcode_comments")->getBool() == true); 39 } 40 } 41 WHEN("A boolean option is set to a string value representing a 0 or 1") { 42 CHECK_NOTHROW(config.set_deserialize_strict("gcode_comments", "1")); 43 THEN("The underlying value is set correctly.") { 44 REQUIRE(config.opt<ConfigOptionBool>("gcode_comments")->getBool() == true); 45 } 46 } 47 WHEN("A boolean option is set to a string value representing something other than 0 or 1") { 48 THEN("A BadOptionTypeException exception is thrown.") { 49 REQUIRE_THROWS_AS(config.set("gcode_comments", "Z"), BadOptionTypeException); 50 } 51 AND_THEN("Value is unchanged.") { 52 REQUIRE(config.opt<ConfigOptionBool>("gcode_comments")->getBool() == false); 53 } 54 } 55 WHEN("A boolean option is set to an int value") { 56 THEN("A BadOptionTypeException exception is thrown.") { 57 REQUIRE_THROWS_AS(config.set("gcode_comments", 1), BadOptionTypeException); 58 } 59 } 60 WHEN("A numeric option is set from serialized string") { 61 config.set_deserialize_strict("bed_temperature", "100"); 62 THEN("The underlying value is set correctly.") { 63 REQUIRE(config.opt<ConfigOptionInts>("bed_temperature")->get_at(0) == 100); 64 } 65 } 66 #if 0 67 //FIXME better design accessors for vector elements. 68 WHEN("An integer-based option is set through the integer interface") { 69 config.set("bed_temperature", 100); 70 THEN("The underlying value is set correctly.") { 71 REQUIRE(config.opt<ConfigOptionInts>("bed_temperature")->get_at(0) == 100); 72 } 73 } 74 #endif 75 WHEN("An floating-point option is set through the integer interface") { 76 config.set("perimeter_speed", 10); 77 THEN("The underlying value is set correctly.") { 78 REQUIRE(config.opt<ConfigOptionFloat>("perimeter_speed")->getFloat() == 10.0); 79 } 80 } 81 WHEN("A floating-point option is set through the double interface") { 82 config.set("perimeter_speed", 5.5); 83 THEN("The underlying value is set correctly.") { 84 REQUIRE(config.opt<ConfigOptionFloat>("perimeter_speed")->getFloat() == 5.5); 85 } 86 } 87 WHEN("An integer-based option is set through the double interface") { 88 THEN("A BadOptionTypeException exception is thrown.") { 89 REQUIRE_THROWS_AS(config.set("bed_temperature", 5.5), BadOptionTypeException); 90 } 91 } 92 WHEN("A numeric option is set to a non-numeric value.") { 93 THEN("A BadOptionTypeException exception is thown.") { 94 REQUIRE_THROWS_AS(config.set_deserialize_strict("perimeter_speed", "zzzz"), BadOptionValueException); 95 } 96 THEN("The value does not change.") { 97 REQUIRE(config.opt<ConfigOptionFloat>("perimeter_speed")->getFloat() == 60.0); 98 } 99 } 100 WHEN("A string option is set through the string interface") { 101 config.set("end_gcode", "100"); 102 THEN("The underlying value is set correctly.") { 103 REQUIRE(config.opt<ConfigOptionString>("end_gcode")->value == "100"); 104 } 105 } 106 WHEN("A string option is set through the integer interface") { 107 config.set("end_gcode", 100); 108 THEN("The underlying value is set correctly.") { 109 REQUIRE(config.opt<ConfigOptionString>("end_gcode")->value == "100"); 110 } 111 } 112 WHEN("A string option is set through the double interface") { 113 config.set("end_gcode", 100.5); 114 THEN("The underlying value is set correctly.") { 115 REQUIRE(config.opt<ConfigOptionString>("end_gcode")->value == std::to_string(100.5)); 116 } 117 } 118 WHEN("A float or percent is set as a percent through the string interface.") { 119 config.set_deserialize_strict("first_layer_extrusion_width", "100%"); 120 THEN("Value and percent flag are 100/true") { 121 auto tmp = config.opt<ConfigOptionFloatOrPercent>("first_layer_extrusion_width"); 122 REQUIRE(tmp->percent == true); 123 REQUIRE(tmp->value == 100); 124 } 125 } 126 WHEN("A float or percent is set as a float through the string interface.") { 127 config.set_deserialize_strict("first_layer_extrusion_width", "100"); 128 THEN("Value and percent flag are 100/false") { 129 auto tmp = config.opt<ConfigOptionFloatOrPercent>("first_layer_extrusion_width"); 130 REQUIRE(tmp->percent == false); 131 REQUIRE(tmp->value == 100); 132 } 133 } 134 WHEN("A float or percent is set as a float through the int interface.") { 135 config.set("first_layer_extrusion_width", 100); 136 THEN("Value and percent flag are 100/false") { 137 auto tmp = config.opt<ConfigOptionFloatOrPercent>("first_layer_extrusion_width"); 138 REQUIRE(tmp->percent == false); 139 REQUIRE(tmp->value == 100); 140 } 141 } 142 WHEN("A float or percent is set as a float through the double interface.") { 143 config.set("first_layer_extrusion_width", 100.5); 144 THEN("Value and percent flag are 100.5/false") { 145 auto tmp = config.opt<ConfigOptionFloatOrPercent>("first_layer_extrusion_width"); 146 REQUIRE(tmp->percent == false); 147 REQUIRE(tmp->value == 100.5); 148 } 149 } 150 WHEN("An invalid option is requested during set.") { 151 THEN("A BadOptionTypeException exception is thrown.") { 152 REQUIRE_THROWS_AS(config.set("deadbeef_invalid_option", 1), UnknownOptionException); 153 REQUIRE_THROWS_AS(config.set("deadbeef_invalid_option", 1.0), UnknownOptionException); 154 REQUIRE_THROWS_AS(config.set("deadbeef_invalid_option", "1"), UnknownOptionException); 155 REQUIRE_THROWS_AS(config.set("deadbeef_invalid_option", true), UnknownOptionException); 156 } 157 } 158 159 WHEN("An invalid option is requested during get.") { 160 THEN("A UnknownOptionException exception is thrown.") { 161 REQUIRE_THROWS_AS(config.option_throw<ConfigOptionString>("deadbeef_invalid_option", false), UnknownOptionException); 162 REQUIRE_THROWS_AS(config.option_throw<ConfigOptionFloat>("deadbeef_invalid_option", false), UnknownOptionException); 163 REQUIRE_THROWS_AS(config.option_throw<ConfigOptionInt>("deadbeef_invalid_option", false), UnknownOptionException); 164 REQUIRE_THROWS_AS(config.option_throw<ConfigOptionBool>("deadbeef_invalid_option", false), UnknownOptionException); 165 } 166 } 167 WHEN("An invalid option is requested during opt.") { 168 THEN("A UnknownOptionException exception is thrown.") { 169 REQUIRE_THROWS_AS(config.option_throw<ConfigOptionString>("deadbeef_invalid_option", false), UnknownOptionException); 170 REQUIRE_THROWS_AS(config.option_throw<ConfigOptionFloat>("deadbeef_invalid_option", false), UnknownOptionException); 171 REQUIRE_THROWS_AS(config.option_throw<ConfigOptionInt>("deadbeef_invalid_option", false), UnknownOptionException); 172 REQUIRE_THROWS_AS(config.option_throw<ConfigOptionBool>("deadbeef_invalid_option", false), UnknownOptionException); 173 } 174 } 175 176 WHEN("getX called on an unset option.") { 177 THEN("The default is returned.") { 178 REQUIRE(config.opt_float("layer_height") == 0.3); 179 REQUIRE(config.opt_int("raft_layers") == 0); 180 REQUIRE(config.opt_bool("support_material") == false); 181 } 182 } 183 184 WHEN("getFloat called on an option that has been set.") { 185 config.set("layer_height", 0.5); 186 THEN("The set value is returned.") { 187 REQUIRE(config.opt_float("layer_height") == 0.5); 188 } 189 } 190 } 191 } 192 193 SCENARIO("Config ini load/save interface", "[Config]") { 194 WHEN("new_from_ini is called") { 195 Slic3r::DynamicPrintConfig config; 196 std::string path = std::string(TEST_DATA_DIR) + "/test_config/new_from_ini.ini"; 197 config.load_from_ini(path, ForwardCompatibilitySubstitutionRule::Disable); 198 THEN("Config object contains ini file options.") { 199 REQUIRE(config.option_throw<ConfigOptionStrings>("filament_colour", false)->values.size() == 1); 200 REQUIRE(config.option_throw<ConfigOptionStrings>("filament_colour", false)->values.front() == "#ABCD"); 201 } 202 } 203 } 204