Project
Loading...
Searching...
No Matches
testConfigurableParam.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#include <boost/test/tools/old/interface.hpp>
13#include <stdexcept>
14#define BOOST_TEST_MODULE Test ConfigurableParams
15#define BOOST_TEST_MAIN
16#define BOOST_TEST_DYN_LINK
17
18#include <boost/test/unit_test.hpp>
19#include <boost/property_tree/ptree.hpp>
20#include <cstdlib>
21#include <deque>
22#include <filesystem>
23#include <list>
24#include <set>
25#include <unordered_set>
26#include <vector>
27
29
30using namespace o2::conf;
31using namespace o2::conf::test;
32
33BOOST_AUTO_TEST_CASE(ConfigurableParam_Basic)
34{
35 // Tests the default parameters and also getter helpers.
36 auto& param = TestParam::Instance();
37 BOOST_CHECK_EQUAL(param.iValue, 42);
38 BOOST_CHECK_EQUAL(param.dValue, 3.14);
39 BOOST_CHECK_EQUAL(param.bValue, true);
40 BOOST_CHECK_EQUAL(param.sValue, "default");
41 BOOST_CHECK_EQUAL(static_cast<int>(param.eValue), 2);
42
43 BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs<int>("TestParam.iValue"), 42);
44 BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs<double>("TestParam.dValue"), 3.14);
45 BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs<bool>("TestParam.bValue"), true);
46 BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs<std::string>("TestParam.sValue"), "default");
47}
48
49BOOST_AUTO_TEST_CASE(ConfigurableParam_SG_Fundamental)
50{
51 // tests runtime setting and getting for fundamental types
52 ConfigurableParam::setValue("TestParam.iValue", "100");
53 ConfigurableParam::setValue("TestParam.dValue", "2.718");
54 ConfigurableParam::setValue("TestParam.bValue", "0");
55 ConfigurableParam::setValue("TestParam.sValue", "modified");
56 ConfigurableParam::setValue("TestParam.eValue", "0");
57
58 auto& param = TestParam::Instance();
59 BOOST_CHECK_EQUAL(param.iValue, 100);
60 BOOST_CHECK_EQUAL(param.dValue, 2.718);
61 BOOST_CHECK_EQUAL(param.bValue, false);
62 BOOST_CHECK_EQUAL(param.sValue, "modified");
63 BOOST_CHECK_EQUAL(static_cast<int>(param.eValue), 0);
64}
65
66BOOST_AUTO_TEST_CASE(ConfigurableParam_SG_CArray)
67{
68 // tests setting and getting for a c-style array type
69 auto& param = TestParam::Instance();
70 BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs<int>("TestParam.caValue[0]"), 0);
71 BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs<int>("TestParam.caValue[1]"), 1);
72 BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs<int>("TestParam.caValue[2]"), 2);
73
74 ConfigurableParam::setValue("TestParam.caValue[1]", "99");
75 BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs<int>("TestParam.caValue[1]"), 99);
76}
77
78BOOST_AUTO_TEST_CASE(ConfigurableParam_SG_STD)
79{
80 // tests setting and getting for a std type
81 ConfigurableParam::setValue("TestParam.vec", "[10,20,30,40]");
82 auto& param = TestParam::Instance();
83 BOOST_CHECK_EQUAL(param.vec.size(), 4);
84 BOOST_CHECK_EQUAL(param.vec[0], 10);
85 BOOST_CHECK_EQUAL(param.vec[1], 20);
86 BOOST_CHECK_EQUAL(param.vec[2], 30);
87 BOOST_CHECK_EQUAL(param.vec[3], 40);
88 BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs<std::string>("TestParam.vec"), "[10,20,30,40]");
89
90 ConfigurableParam::setValue("TestParam.u8vec", "[1,2,255]");
91 BOOST_CHECK_EQUAL(param.u8vec.size(), 3);
92 BOOST_CHECK_EQUAL(static_cast<unsigned int>(param.u8vec[0]), 1);
93 BOOST_CHECK_EQUAL(static_cast<unsigned int>(param.u8vec[1]), 2);
94 BOOST_CHECK_EQUAL(static_cast<unsigned int>(param.u8vec[2]), 255);
95 BOOST_CHECK_EQUAL(ConfigurableParam::getValueAs<std::string>("TestParam.u8vec"), "[1,2,255]");
96
97 ConfigurableParam::setValues({{"TestParam.map", "{0:1,10:42}"}});
98 BOOST_CHECK_EQUAL(param.map.size(), 2);
99 BOOST_CHECK(param.map.contains(0));
100 BOOST_CHECK_EQUAL(param.map.at(0), 1);
101 BOOST_CHECK(param.map.contains(10));
102 BOOST_CHECK_EQUAL(param.map.at(10), 42);
103 BOOST_CHECK_THROW(param.map.at(33), std::out_of_range);
104}
105
106BOOST_AUTO_TEST_CASE(ConfigurableParam_Provenance)
107{
108 // tests correct setting of provenance
109 BOOST_CHECK_EQUAL(ConfigurableParam::getProvenance("TestParam.iValueProvenanceTest"), ConfigurableParam::EParamProvenance::kCODE);
110 ConfigurableParam::setValue("TestParam.iValueProvenanceTest", "123");
111 BOOST_CHECK_EQUAL(ConfigurableParam::getProvenance("TestParam.iValueProvenanceTest"), ConfigurableParam::EParamProvenance::kRT);
112}
113
114BOOST_AUTO_TEST_CASE(ConfigurableParam_FileIO_Ini)
115{
116 // test for ini file serialization
117 const std::string testFileName = "test_config.ini";
118 auto iValueBefore = TestParam::Instance().iValue;
119 auto sValueBefore = TestParam::Instance().sValue;
120 ConfigurableParam::setValue("TestParam.vec", "[7,8]");
121 const std::vector<int> vecBefore = TestParam::Instance().vec;
122 ConfigurableParam::writeINI(testFileName);
123 ConfigurableParam::setValue("TestParam.iValue", "999");
124 ConfigurableParam::setValue("TestParam.sValue", testFileName);
125 ConfigurableParam::setValue("TestParam.vec", "[1]");
127 BOOST_CHECK_EQUAL(TestParam::Instance().iValue, iValueBefore);
128 BOOST_CHECK_EQUAL(TestParam::Instance().sValue, sValueBefore);
129 BOOST_CHECK_EQUAL_COLLECTIONS(TestParam::Instance().vec.begin(), TestParam::Instance().vec.end(), vecBefore.begin(), vecBefore.end());
130 std::remove(testFileName.c_str());
131}
132
133BOOST_AUTO_TEST_CASE(ConfigurableParam_FileIO_Json)
134{
135 // test for json file serialization
136 const std::string testFileName = "test_config.json";
137 auto iValueBefore = TestParam::Instance().iValue;
138 auto sValueBefore = TestParam::Instance().sValue;
139 ConfigurableParam::setValues({{"TestParam.map", "{3:4,5:6}"}});
140 const std::map<int, unsigned int> mapBefore = TestParam::Instance().map;
141 ConfigurableParam::writeJSON(testFileName);
142 ConfigurableParam::setValue("TestParam.iValue", "999");
143 ConfigurableParam::setValue("TestParam.sValue", testFileName);
144 ConfigurableParam::setValues({{"TestParam.map", "{1:2}"}});
146 BOOST_CHECK_EQUAL(TestParam::Instance().iValue, iValueBefore);
147 BOOST_CHECK_EQUAL(TestParam::Instance().sValue, sValueBefore);
148 BOOST_CHECK_EQUAL(TestParam::Instance().map.size(), mapBefore.size());
149 BOOST_CHECK_EQUAL(TestParam::Instance().map.at(3), mapBefore.at(3));
150 BOOST_CHECK_EQUAL(TestParam::Instance().map.at(5), mapBefore.at(5));
151 std::remove(testFileName.c_str());
152}
153
154BOOST_AUTO_TEST_CASE(ConfigurableParam_JSONString_UnchangedOnly)
155{
156 ConfigurableParam::setValue("TestParam.ulValue", "2");
159 ConfigurableParam::updateFromJSONString(R"json({"TestParam":{"lValue":"77","ulValue":"88"}})json", "TestParam", true);
160
161 BOOST_CHECK_EQUAL(TestParam::Instance().lValue, 77);
162 BOOST_CHECK_EQUAL(TestParam::Instance().ulValue, 2);
163}
164
165BOOST_AUTO_TEST_CASE(ConfigurableParam_JSONString_FromAsJSON)
166{
167 ConfigurableParam::setValue("TestParam.iValue", "321");
168 ConfigurableParam::setValue("TestParam.sValue", "json-source");
169 ConfigurableParam::setValues({{"TestParam.map", "{7:8,9:10}"}});
170 const auto mapBefore = TestParam::Instance().map;
171 const auto json = ConfigurableParam::asJSON("TestParam");
172
173 ConfigurableParam::setValue("TestParam.iValue", "999");
174 ConfigurableParam::setValue("TestParam.sValue", "json-modified");
175 ConfigurableParam::setValues({{"TestParam.map", "{1:2}"}});
177
178 BOOST_CHECK_EQUAL(TestParam::Instance().iValue, 321);
179 BOOST_CHECK_EQUAL(TestParam::Instance().sValue, "json-source");
180 BOOST_CHECK_EQUAL(TestParam::Instance().map.size(), mapBefore.size());
181 BOOST_CHECK_EQUAL(TestParam::Instance().map.at(7), mapBefore.at(7));
182 BOOST_CHECK_EQUAL(TestParam::Instance().map.at(9), mapBefore.at(9));
183}
184
185BOOST_AUTO_TEST_CASE(ConfigurableParam_JSONString_ParamsListMissing)
186{
187 BOOST_CHECK_THROW(ConfigurableParam::updateFromJSONString(ConfigurableParam::asJSON("TestParam"), "MissingParam"), std::runtime_error);
188}
189
190BOOST_AUTO_TEST_CASE(ConfigurableParam_FileIO_ROOT)
191{
192 // test for root file serialization
193 const std::string testFileName = "test_config.root";
194 auto iValueBefore = TestParam::Instance().iValue;
195 auto sValueBefore = TestParam::Instance().sValue;
196 TFile* testFile = TFile::Open(testFileName.c_str(), "RECREATE");
197 TestParam::Instance().serializeTo(testFile);
198 testFile->Close();
199 ConfigurableParam::setValue("TestParam.iValue", "999");
200 ConfigurableParam::setValue("TestParam.sValue", testFileName);
201 ConfigurableParam::fromCCDB(testFileName);
202 BOOST_CHECK_EQUAL(TestParam::Instance().iValue, iValueBefore);
203 BOOST_CHECK_EQUAL(TestParam::Instance().sValue, sValueBefore);
204 std::remove(testFileName.c_str());
205}
206
207BOOST_AUTO_TEST_CASE(ConfigurableParam_Cli)
208{
209 // test setting values from as a cli arg string
210 ConfigurableParam::updateFromString("TestParam.iValue=55;TestParam.sValue=cli");
211 BOOST_CHECK_EQUAL(TestParam::Instance().iValue, 55);
212 BOOST_CHECK_EQUAL(TestParam::Instance().sValue, "cli");
213}
214
215BOOST_AUTO_TEST_CASE(ConfigurableParam_LiteralSuffix)
216{
217 // test setting values with the correct literal suffix
218 ConfigurableParam::updateFromString("TestParam.fValue=42.f");
219 BOOST_CHECK_EQUAL(TestParam::Instance().fValue, 42.f);
220
221 ConfigurableParam::setValue("TestParam.ullValue", "999ull");
222 BOOST_CHECK_EQUAL(TestParam::Instance().ullValue, 999ULL);
223 // check using wrong literal suffix fails, prints error to std
224 ConfigurableParam::setValue("TestParam.ullValue", "888u");
225 BOOST_CHECK_NE(TestParam::Instance().ullValue, 888);
226}
227
228BOOST_AUTO_TEST_CASE(ConfigurableParam_ContainerParserVector)
229{
230 auto v = ContainerParser::parse<std::vector<int>>("[1,2,3,4,5]");
231 BOOST_CHECK_EQUAL(v.size(), 5);
232 BOOST_CHECK_EQUAL(v[0], 1);
233 BOOST_CHECK_EQUAL(v[4], 5);
234}
235
236BOOST_AUTO_TEST_CASE(ConfigurableParam_ContainerParserMap)
237{
238 auto m = ContainerParser::parse<std::map<std::string, double>>("{alpha:0.5,beta:0.3,gamma:0.2}");
239 BOOST_CHECK_EQUAL(m.size(), 3);
240 BOOST_CHECK_EQUAL(m["alpha"], 0.5);
241 BOOST_CHECK_EQUAL(m["beta"], 0.3);
242}
243
244BOOST_AUTO_TEST_CASE(ConfigurableParam_ContainerParserSetAndSequenceTypes)
245{
246 // All non-map containers go through the single parseSequence path. Verify the
247 // set containers (which previously took a separate, doubly-parsing parseSet
248 // branch) still parse and de-duplicate correctly.
249 auto se = ContainerParser::parse<std::set<int>>("[2,3,2,3,2,5]");
250 BOOST_CHECK_EQUAL(se.size(), 3);
251 BOOST_CHECK(se == (std::set<int>{2, 3, 5}));
252
253 auto us = ContainerParser::parse<std::unordered_set<int>>("[1,2,3,3]");
254 BOOST_CHECK_EQUAL(us.size(), 3);
255 BOOST_CHECK(us.count(1) && us.count(2) && us.count(3));
256
257 auto li = ContainerParser::parse<std::list<int>>("[7,8]");
258 BOOST_CHECK(li == (std::list<int>{7, 8}));
259
260 auto dq = ContainerParser::parse<std::deque<int>>("[9,10]");
261 BOOST_CHECK(dq == (std::deque<int>{9, 10}));
262}
263
264BOOST_AUTO_TEST_CASE(ConfigurableParam_ContainerParserRejectsEmptyToken)
265{
266 // A stray delimiter must be reported, not silently swallowed: "[1,,3]" used to
267 // parse to a 2-element vector with no error, masking malformed configuration.
268 BOOST_CHECK_THROW(ContainerParser::parse<std::vector<int>>("[1,,3]"), std::exception);
269 BOOST_CHECK_THROW(ContainerParser::parse<std::vector<int>>("[1,2,]"), std::exception);
270 // ... and on the map side, an empty value/entry is rejected too.
271 BOOST_CHECK_THROW((ContainerParser::parse<std::map<int, int>>("{1:2,,3:4}")), std::exception);
272 BOOST_CHECK_THROW((ContainerParser::parse<std::map<int, int>>("{1:}")), std::exception);
273 // Well-formed input is unaffected.
274 auto v = ContainerParser::parse<std::vector<int>>("[1,2,3]");
275 BOOST_CHECK_EQUAL(v.size(), 3);
276}
277
278BOOST_AUTO_TEST_CASE(ConfigurableParam_DamerauLevenshteinDistance)
279{
280 BOOST_CHECK_EQUAL(damerauLevenshteinDistance("TestParam.iValue", "TestParam.iValue"), 0);
281 BOOST_CHECK_EQUAL(damerauLevenshteinDistance("TestParam.iValu", "TestParam.iValue"), 1);
282 BOOST_CHECK_EQUAL(damerauLevenshteinDistance("TestParam.jValue", "TestParam.iValue"), 1);
283 BOOST_CHECK_EQUAL(damerauLevenshteinDistance("TestParam.iVaule", "TestParam.iValue"), 1);
284}
285
286BOOST_AUTO_TEST_CASE(ConfigurableParam_UnknownKeySuggestionsNonFatal)
287{
288 setenv("ALICEO2_CONFIGURABLEPARAM_WRONGKEYISNONFATAL", "1", 1);
289 ConfigurableParam::setValue("TestParam.iValue", "222");
290 ConfigurableParam::setValue("TestParam.caValue[1]", "33");
291 ConfigurableParam::setValues({{"TestParam.iValu", "777"},
292 {"TstParam.iValue", "888"},
293 {"TestParam.caValue[", "999"}});
294 BOOST_CHECK_EQUAL(TestParam::Instance().iValue, 222);
295 BOOST_CHECK_EQUAL(TestParam::Instance().caValue[1], 33);
296 unsetenv("ALICEO2_CONFIGURABLEPARAM_WRONGKEYISNONFATAL");
297}
298
299BOOST_AUTO_TEST_CASE(ConfigurableParam_Container_FileIO_ROOT)
300{
301 // test for root file serialization
302 const std::string testFileName = "test_config.root";
303 TFile* testFile = TFile::Open(testFileName.c_str(), "RECREATE");
304 ConfigurableParam::setValue("TestParam.vec", "[1,2,3]");
305 ConfigurableParam::setValue("TestParam.u8vec", "[4,5,6]");
306 ConfigurableParam::setValue("TestParam.map", "{1:16,2:9,3:23456}");
307 ConfigurableParam::setValue("TestParam.smap", "{a:16,b:9,c:23456}");
308 ConfigurableParam::setValue("TestParam.set", "[2,3,2,3,2,5]");
309 TestParam::Instance().serializeTo(testFile);
310 testFile->Close();
311 ConfigurableParam::setValue("TestParam.vec", "[9]");
312 ConfigurableParam::fromCCDB(testFileName);
313 const auto& tp = TestParam::Instance();
314 const std::vector<int> v = {1, 2, 3};
315 BOOST_CHECK_EQUAL_COLLECTIONS(tp.vec.begin(), tp.vec.end(), v.begin(), v.end());
316 const std::vector<uint8_t> v8 = {4, 5, 6};
317 BOOST_CHECK_EQUAL_COLLECTIONS(tp.u8vec.begin(), tp.u8vec.end(), v8.begin(), v8.end());
318 std::map<int, uint32_t> map{{1, 16}, {2, 9}, {3, 23456}};
319 auto testMapEqual = [](const auto& m1, const auto& m2) {
320 for (const auto& [k, v] : m1) {
321 BOOST_CHECK(m2.find(k) != m2.end());
322 BOOST_CHECK_EQUAL(v, m2.at(k));
323 }
324 };
325 testMapEqual(map, tp.map);
326 std::map<std::string, uint32_t> smap{{"a", 16}, {"b", 9}, {"c", 23456}};
327 testMapEqual(smap, tp.smap);
328 std::set<uint16_t> set{2, 3, 5};
329 BOOST_CHECK_EQUAL(set.size(), tp.set.size());
330 for (const auto& s : set) {
331 BOOST_CHECK(tp.set.contains(s));
332 }
333 std::remove(testFileName.c_str());
334}
nlohmann::json json
static void writeINI(std::string const &filename, std::string const &keyOnly="")
static void setValues(std::vector< std::pair< std::string, std::string > > const &keyValues)
static void setProvenance(std::string const &mainkey, std::string const &subkey, EParamProvenance p)
static std::string asJSON(std::string const &keyOnly="")
static void updateFromFile(std::string const &, std::string const &paramsList="", bool unchangedOnly=false)
static void setValue(std::string const &mainkey, std::string const &subkey, T x)
static EParamProvenance getProvenance(const std::string &key)
static void writeJSON(std::string const &filename, std::string const &keyOnly="")
static void updateFromJSONString(std::string const &, std::string const &paramsList="", bool unchangedOnly=false)
static void fromCCDB(std::string filename)
static void updateFromString(std::string const &)
static T parse(const std::string &str)
const GLfloat * m
Definition glcorearb.h:4066
const GLdouble * v
Definition glcorearb.h:832
GLenum GLfloat param
Definition glcorearb.h:271
std::size_t damerauLevenshteinDistance(std::string_view a, std::string_view b)
BOOST_AUTO_TEST_CASE(ConfigurableParam_Basic)
std::vector< o2::ctf::BufferType > vec
BOOST_CHECK(tree)
BOOST_CHECK_EQUAL(triggersD.size(), triggers.size())