@@ -196,3 +196,64 @@ TEST_CASE("TestConfigParamRegistryOverride")
196196 registry.override (" aString" , std::vector<std::string>{" now" , " an" , " array" });
197197 REQUIRE (registry.get <std::vector<std::string>>(" aString" ) == std::vector<std::string>{" now" , " an" , " array" });
198198}
199+
200+ TEST_CASE (" TestConfigParamRegistryErase" )
201+ {
202+ int l[2 ][2 ] = {{1 , 2 }, {3 , 4 }};
203+ // a Variant cannot be created from a temporary vector, so the defaults are named
204+ std::vector<int > defaultVector{1 , 2 , 3 , 4 , 5 };
205+ std::vector<std::string> defaultStringVector{" a" , " b" , " c" };
206+ std::vector<double > defaultNestedVector{0.5 , 1.5 };
207+ // the store keeps a reference to the specs, which have to outlive it
208+ std::vector<ConfigParamSpec> specs{
209+ ConfigParamSpec{" anInt" , VariantType::Int, 1 , {" an int option" }},
210+ ConfigParamSpec{" aString" , VariantType::String, " foo" , {" a string option" }},
211+ ConfigParamSpec{" aVector" , VariantType::ArrayInt, defaultVector, {" an int array option" }},
212+ ConfigParamSpec{" aStringVector" , VariantType::ArrayString, defaultStringVector, {" a string array option" }},
213+ ConfigParamSpec{" aLabeledArray" , VariantType::LabeledArrayInt, LabeledArray<int >{&l[0 ][0 ], 2 , 2 , {" r1" , " r2" }, {" c1" , " c2" }}, {" a labeled array option" }},
214+ ConfigParamSpec{" aNested.x" , VariantType::Int, 2 , {" an int option, nested in an object" }},
215+ ConfigParamSpec{" aNested.vec" , VariantType::ArrayDouble, defaultNestedVector, {" a double array option, nested in an object" }},
216+ };
217+ auto store = std::make_unique<ConfigParamStore>(specs, std::vector<std::unique_ptr<ParamRetriever>>{});
218+ store->preload ();
219+ store->activate ();
220+ ConfigParamRegistry registry (std::move (store));
221+
222+ // a leaf value is removed
223+ REQUIRE (registry.hasOption (" anInt" ));
224+ registry.erase (" anInt" );
225+ REQUIRE (registry.hasOption (" anInt" ) == false );
226+ REQUIRE (registry.isSet (" anInt" ) == false );
227+ REQUIRE (registry.isDefault (" anInt" ) == false );
228+ REQUIRE_THROWS_AS (registry.get <int >(" anInt" ), std::invalid_argument);
229+
230+ // arrays are removed as whole subtrees
231+ registry.erase (" aVector" );
232+ REQUIRE (registry.hasOption (" aVector" ) == false );
233+ REQUIRE (registry.isSet (" aVector" ) == false );
234+ registry.erase (" aLabeledArray" );
235+ REQUIRE (registry.hasOption (" aLabeledArray" ) == false );
236+ REQUIRE (registry.isSet (" aLabeledArray" ) == false );
237+
238+ // a nested key is removed without touching its siblings
239+ registry.erase (" aNested.vec" );
240+ REQUIRE (registry.hasOption (" aNested.vec" ) == false );
241+ REQUIRE (registry.get <int >(" aNested.x" ) == 2 );
242+
243+ // other options are untouched
244+ REQUIRE (registry.get <std::string>(" aString" ) == " foo" );
245+ REQUIRE (registry.get <std::vector<std::string>>(" aStringVector" ) == std::vector<std::string>{" a" , " b" , " c" });
246+
247+ // missing keys are ignored
248+ REQUIRE_NOTHROW (registry.erase (" anInt" ));
249+ REQUIRE_NOTHROW (registry.erase (" noSuchKey" ));
250+ REQUIRE_NOTHROW (registry.erase (" noSuchParent.x" ));
251+ REQUIRE_NOTHROW (registry.erase (" aNested.noSuchKey" ));
252+ REQUIRE (registry.get <int >(" aNested.x" ) == 2 );
253+
254+ // an erased key can be stored again
255+ registry.override (" anInt" , 3 );
256+ REQUIRE (registry.get <int >(" anInt" ) == 3 );
257+ registry.override (" aVector" , std::vector<int >{7 , 8 });
258+ REQUIRE (registry.get <std::vector<int >>(" aVector" ) == std::vector<int >{7 , 8 });
259+ }
0 commit comments