2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Michal Witanowski <m.witanowski@samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
22 * @author Michal Witanowski (m.witanowski@samsung.com)
23 * @brief Unit test of Configuration
28 #include "testconfig-example.hpp"
29 #include "config/manager.hpp"
30 #include "utils/scoped-dir.hpp"
31 #include <sys/types.h>
37 using namespace config;
39 const std::string UT_PATH = "/tmp/ut-config/";
40 const std::string DB_PATH = UT_PATH + "kvstore.db3";
41 const std::string DB_PREFIX = "ut";
43 // Floating point tolerance as a number of rounding errors
44 const int TOLERANCE = 1;
47 vasum::utils::ScopedDir mUTDirGuard;
48 Fixture() : mUTDirGuard(UT_PATH) {}
53 BOOST_FIXTURE_TEST_SUITE(ConfigurationSuite, Fixture)
55 BOOST_AUTO_TEST_CASE(FromJsonString)
57 TestConfig testConfig;
59 BOOST_REQUIRE_NO_THROW(loadFromJsonString(jsonTestString, testConfig));
61 BOOST_CHECK_EQUAL(12345, testConfig.intVal);
62 BOOST_CHECK_EQUAL(-1234567890123456789ll, testConfig.int64Val);
63 BOOST_CHECK_EQUAL(123456, testConfig.uint32Val);
64 BOOST_CHECK_EQUAL(1234567890123456789ll, testConfig.uint64Val);
65 BOOST_CHECK_EQUAL("blah", testConfig.stringVal);
66 BOOST_CHECK_CLOSE(-1.234, testConfig.doubleVal, TOLERANCE);
67 BOOST_CHECK_EQUAL(true, testConfig.boolVal);
69 BOOST_REQUIRE_EQUAL(0, testConfig.emptyIntVector.size());
71 BOOST_REQUIRE_EQUAL(3, testConfig.intVector.size());
72 BOOST_CHECK_EQUAL(1, testConfig.intVector[0]);
73 BOOST_CHECK_EQUAL(2, testConfig.intVector[1]);
74 BOOST_CHECK_EQUAL(3, testConfig.intVector[2]);
76 BOOST_REQUIRE_EQUAL(2, testConfig.stringVector.size());
77 BOOST_CHECK_EQUAL("a", testConfig.stringVector[0]);
78 BOOST_CHECK_EQUAL("b", testConfig.stringVector[1]);
80 BOOST_REQUIRE_EQUAL(3, testConfig.doubleVector.size());
81 BOOST_CHECK_CLOSE(0.0, testConfig.doubleVector[0], TOLERANCE);
82 BOOST_CHECK_CLOSE(1.0, testConfig.doubleVector[1], TOLERANCE);
83 BOOST_CHECK_CLOSE(2.0, testConfig.doubleVector[2], TOLERANCE);
85 BOOST_CHECK_EQUAL(54321, testConfig.subObj.intVal);
86 BOOST_CHECK_EQUAL(2, testConfig.subObj.intVector.size());
87 BOOST_CHECK_EQUAL(1, testConfig.subObj.intVector[0]);
88 BOOST_CHECK_EQUAL(2, testConfig.subObj.intVector[1]);
89 BOOST_CHECK_EQUAL(234, testConfig.subObj.subSubObj.intVal);
91 BOOST_REQUIRE_EQUAL(2, testConfig.subVector.size());
92 BOOST_CHECK_EQUAL(123, testConfig.subVector[0].intVal);
93 BOOST_CHECK_EQUAL(456, testConfig.subVector[1].intVal);
94 BOOST_CHECK_EQUAL(345, testConfig.subVector[0].subSubObj.intVal);
95 BOOST_CHECK_EQUAL(567, testConfig.subVector[1].subSubObj.intVal);
96 BOOST_CHECK_EQUAL(3, testConfig.subVector[0].intVector[0]);
97 BOOST_CHECK_EQUAL(5, testConfig.subVector[1].intVector[0]);
98 BOOST_CHECK_EQUAL(4, testConfig.subVector[0].intVector[1]);
99 BOOST_CHECK_EQUAL(6, testConfig.subVector[1].intVector[1]);
101 BOOST_CHECK(testConfig.union1.is<int>());
102 BOOST_CHECK_EQUAL(2, testConfig.union1.as<int>());
104 BOOST_CHECK(testConfig.union2.is<TestConfig::SubConfig>());
105 BOOST_CHECK_EQUAL(54321, testConfig.union2.as<TestConfig::SubConfig>().intVal);
106 BOOST_REQUIRE_EQUAL(1, testConfig.union2.as<TestConfig::SubConfig>().intVector.size());
107 BOOST_CHECK_EQUAL(1, testConfig.union2.as<TestConfig::SubConfig>().intVector[0]);
108 BOOST_CHECK_EQUAL(234, testConfig.union2.as<TestConfig::SubConfig>().subSubObj.intVal);
110 BOOST_REQUIRE_EQUAL(2, testConfig.unions.size());
111 BOOST_CHECK(testConfig.unions[0].is<int>());
112 BOOST_CHECK_EQUAL(2, testConfig.unions[0].as<int>());
114 BOOST_CHECK(testConfig.unions[1].is<TestConfig::SubConfig>());
115 BOOST_CHECK_EQUAL(54321, testConfig.unions[1].as<TestConfig::SubConfig>().intVal);
116 BOOST_REQUIRE_EQUAL(1, testConfig.unions[1].as<TestConfig::SubConfig>().intVector.size());
117 BOOST_CHECK_EQUAL(1, testConfig.unions[1].as<TestConfig::SubConfig>().intVector[0]);
118 BOOST_CHECK_EQUAL(234, testConfig.unions[1].as<TestConfig::SubConfig>().subSubObj.intVal);
122 BOOST_AUTO_TEST_CASE(ToJsonString)
124 TestConfig testConfig;
125 BOOST_REQUIRE_NO_THROW(loadFromJsonString(jsonTestString, testConfig));
127 std::string out = saveToJsonString(testConfig);
128 BOOST_CHECK_EQUAL(out, jsonTestString);
130 TestConfig::SubConfigOption unionConfig;
131 BOOST_CHECK_THROW(saveToJsonString(unionConfig), ConfigException);
134 namespace loadErrorsTest {
136 #define DECLARE_CONFIG(name, type) \
139 CONFIG_REGISTER(field) \
141 DECLARE_CONFIG(IntConfig, int)
142 DECLARE_CONFIG(StringConfig, std::string)
143 DECLARE_CONFIG(DoubleConfig, double)
144 DECLARE_CONFIG(BoolConfig, bool)
145 DECLARE_CONFIG(ArrayConfig, std::vector<int>)
146 DECLARE_CONFIG(ObjectConfig, IntConfig)
147 #undef DECLARE_CONFIG
156 } // namespace loadErrorsTest
158 BOOST_AUTO_TEST_CASE(JsonLoadErrors)
160 using namespace loadErrorsTest;
163 BOOST_REQUIRE_NO_THROW(loadFromJsonString("{\"field\":1}", config));
165 BOOST_CHECK_THROW(loadFromJsonString("", config), ConfigException);
166 BOOST_CHECK_THROW(loadFromJsonString("{", config), ConfigException); // invalid json
167 BOOST_CHECK_THROW(loadFromJsonString("{}", config), ConfigException); // missing field
172 BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": 1}", intConfig));
173 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": \"1\"}", intConfig), ConfigException);
174 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1.0}", intConfig), ConfigException);
175 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": true}", intConfig), ConfigException);
176 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": []}", intConfig), ConfigException);
177 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", intConfig), ConfigException);
178 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1234567890123456789}", intConfig), ConfigException);
179 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": -1234567890123456789}", intConfig), ConfigException);
181 StringConfig stringConfig;
182 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1}", stringConfig), ConfigException);
183 BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": \"1\"}", stringConfig));
184 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1.0}", stringConfig), ConfigException);
185 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": true}", stringConfig), ConfigException);
186 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": []}", stringConfig), ConfigException);
187 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", stringConfig), ConfigException);
189 DoubleConfig doubleConfig;
190 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1}", doubleConfig), ConfigException);
191 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": \"1\"}", doubleConfig), ConfigException);
192 BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": 1.0}", doubleConfig));
193 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": true}", doubleConfig), ConfigException);
194 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": []}", doubleConfig), ConfigException);
195 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", doubleConfig), ConfigException);
197 BoolConfig boolConfig;
198 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1}", boolConfig), ConfigException);
199 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": \"1\"}", boolConfig), ConfigException);
200 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1.0}", boolConfig), ConfigException);
201 BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": true}", boolConfig));
202 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": []}", boolConfig), ConfigException);
203 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", boolConfig), ConfigException);
205 ArrayConfig arrayConfig;
206 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1}", arrayConfig), ConfigException);
207 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": \"1\"}", arrayConfig), ConfigException);
208 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1.0}", arrayConfig), ConfigException);
209 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": true}", arrayConfig), ConfigException);
210 BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": []}", arrayConfig));
211 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", arrayConfig), ConfigException);
213 ObjectConfig objectConfig;
214 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1}", objectConfig), ConfigException);
215 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": \"1\"}", objectConfig), ConfigException);
216 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": 1.0}", objectConfig), ConfigException);
217 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": true}", objectConfig), ConfigException);
218 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": []}", objectConfig), ConfigException);
219 BOOST_CHECK_THROW(loadFromJsonString("{\"field\": {}}", objectConfig), ConfigException);
220 BOOST_CHECK_NO_THROW(loadFromJsonString("{\"field\": {\"field\": 1}}", objectConfig));
222 UnionConfig unionConfig;
223 BOOST_CHECK_THROW(loadFromJsonString("{\"type\": \"long\", \"value\": 1}", unionConfig), ConfigException);
224 BOOST_CHECK_THROW(loadFromJsonString("{\"type\": \"int\"}", unionConfig), ConfigException);
225 BOOST_CHECK_NO_THROW(loadFromJsonString("{\"type\": \"int\", \"value\": 1}", unionConfig));
226 BOOST_CHECK_NO_THROW(loadFromJsonString("{\"type\": \"bool\", \"value\": true}", unionConfig));
229 namespace hasVisitableTest {
231 struct NotVisitable {};
236 struct ConstVisitable {
238 void accept(V v) const;
240 struct FullVisitable {
244 void accept(V v) const;
246 struct DerivedVisitable : FullVisitable {};
259 } // namespace hasVisitableTest
261 BOOST_AUTO_TEST_CASE(HasVisibleInternalHelper)
263 using namespace hasVisitableTest;
265 static_assert(isVisitable<Visitable>::value, "");
266 static_assert(isVisitable<ConstVisitable>::value, "");
267 static_assert(isVisitable<FullVisitable>::value, "");
268 static_assert(isVisitable<DerivedVisitable>::value, "");
270 static_assert(!isVisitable<NotVisitable>::value, "");
271 static_assert(!isVisitable<MissingArg>::value, "");
272 static_assert(!isVisitable<WrongArg>::value, "");
273 static_assert(!isVisitable<NotFunction>::value, "");
275 BOOST_CHECK(isVisitable<Visitable>());
278 BOOST_AUTO_TEST_CASE(FromToKVStore)
281 loadFromJsonString(jsonTestString, config);
283 saveToKVStore(DB_PATH, config, DB_PREFIX);
284 TestConfig outConfig;
285 loadFromKVStore(DB_PATH, outConfig, DB_PREFIX);
287 std::string out = saveToJsonString(outConfig);
288 BOOST_CHECK_EQUAL(out, jsonTestString);
291 BOOST_AUTO_TEST_CASE(FromToFD)
294 loadFromJsonString(jsonTestString, config);
296 std::string fifoPath = UT_PATH + "fdstore";
297 BOOST_CHECK(::mkfifo(fifoPath.c_str(), S_IWUSR | S_IRUSR) >= 0);
298 int fd = ::open(fifoPath.c_str(), O_RDWR);
299 BOOST_REQUIRE(fd >= 0);
302 saveToFD(fd, config);
303 TestConfig outConfig;
304 loadFromFD(fd, outConfig);
305 std::string out = saveToJsonString(outConfig);
306 BOOST_CHECK_EQUAL(out, jsonTestString);
309 BOOST_CHECK(::close(fd) >= 0);
312 BOOST_AUTO_TEST_CASE(FromKVWithDefaults)
315 loadFromJsonString(jsonTestString, config);
318 TestConfig outConfig1;
319 loadFromKVStoreWithJson(DB_PATH, jsonTestString, outConfig1, DB_PREFIX);
321 std::string out1 = saveToJsonString(outConfig1);
322 BOOST_CHECK_EQUAL(out1, jsonTestString);
325 saveToKVStore(DB_PATH, config, DB_PREFIX);
326 TestConfig outConfig2;
327 loadFromKVStoreWithJson(DB_PATH, jsonEmptyTestString, outConfig2, DB_PREFIX);
329 std::string out2 = saveToJsonString(outConfig2);
330 BOOST_CHECK_EQUAL(out2, jsonTestString);
333 BOOST_AUTO_TEST_CASE(PartialConfig)
335 // check if partial config is fully supported
337 loadFromJsonString(jsonTestString, config);
341 PartialTestConfig partialConfig;
342 loadFromJsonString(jsonTestString, partialConfig);
344 BOOST_CHECK_EQUAL(config.stringVal, partialConfig.stringVal);
345 BOOST_CHECK(config.intVector == partialConfig.intVector);
350 PartialTestConfig partialConfig;
351 saveToKVStore(DB_PATH, config, DB_PREFIX);
352 loadFromKVStore(DB_PATH, partialConfig, DB_PREFIX);
354 BOOST_CHECK_EQUAL(config.stringVal, partialConfig.stringVal);
355 BOOST_CHECK(config.intVector == partialConfig.intVector);
358 // from kv with defaults
360 PartialTestConfig partialConfig;
361 loadFromKVStoreWithJson(DB_PATH, jsonTestString, partialConfig, DB_PREFIX);
363 BOOST_CHECK_EQUAL(config.stringVal, partialConfig.stringVal);
364 BOOST_CHECK(config.intVector == partialConfig.intVector);
369 PartialTestConfig partialConfig;
370 partialConfig.stringVal = "partial";
371 partialConfig.intVector = {7};
372 config::saveToKVStore(DB_PATH, partialConfig, DB_PREFIX);
375 // from gvariant (partial is not supported!)
377 PartialTestConfig partialConfig;
378 std::unique_ptr<GVariant, decltype(&g_variant_unref)> v(saveToGVariant(config),
380 BOOST_CHECK_THROW(loadFromGVariant(v.get(), partialConfig), ConfigException);
384 BOOST_AUTO_TEST_CASE(ConfigUnion)
386 TestConfig testConfig;
387 BOOST_REQUIRE_NO_THROW(loadFromJsonString(jsonTestString, testConfig));
389 BOOST_CHECK(testConfig.union1.is<int>());
390 BOOST_CHECK(!testConfig.union1.is<TestConfig::SubConfig>());
391 BOOST_CHECK_EQUAL(testConfig.union1.as<int>(), 2);
392 BOOST_CHECK(!testConfig.union2.is<int>());
393 BOOST_CHECK(testConfig.union2.is<TestConfig::SubConfig>());
394 TestConfig::SubConfig& subConfig = testConfig.union2.as<TestConfig::SubConfig>();
395 BOOST_CHECK_EQUAL(subConfig.intVal, 54321);
396 BOOST_CHECK(testConfig.unions[0].is<int>());
397 BOOST_CHECK(testConfig.unions[1].is<TestConfig::SubConfig>());
398 std::string out = saveToJsonString(testConfig);
399 BOOST_CHECK_EQUAL(out, jsonTestString);
403 std::vector<TestConfig::SubConfigOption> unions(2);
404 unions[0].set<int>(2);
405 //set from const lvalue reference (copy)
406 unions[1].set(testConfig.unions[1].as<const TestConfig::SubConfig>());
407 BOOST_CHECK(!testConfig.unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
408 //set from lvalue reference (copy)
409 unions[1].set(testConfig.unions[1].as<TestConfig::SubConfig>());
410 BOOST_CHECK(!testConfig.unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
411 //set from const rvalue reference (copy)
412 unions[1].set(std::move(testConfig.unions[1].as<const TestConfig::SubConfig>()));
413 BOOST_CHECK(!testConfig.unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
414 //set rvalue reference (copy -- move is disabled)
415 unions[1].set(std::move(testConfig.unions[1].as<TestConfig::SubConfig>()));
416 BOOST_CHECK(!testConfig.unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
417 //assign lvalue reference (copy)
418 testConfig.unions[1] = unions[1];
419 BOOST_CHECK(!unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
420 //assign rvalue reference (copy -- move is disabled)
421 testConfig.unions[1] = std::move(unions[1]);
422 BOOST_CHECK(!unions[1].as<TestConfig::SubConfig>().subSubObj.isMoved());
424 testConfig.unions.clear();
425 testConfig.unions = unions;
426 out = saveToJsonString(testConfig);
427 BOOST_CHECK_EQUAL(out, jsonTestString);
431 BOOST_AUTO_TEST_CASE(GVariantVisitor)
433 TestConfig testConfig;
434 BOOST_REQUIRE_NO_THROW(loadFromJsonString(jsonTestString, testConfig));
435 std::unique_ptr<GVariant, decltype(&g_variant_unref)> v(saveToGVariant(testConfig),
437 TestConfig testConfig2;
438 loadFromGVariant(v.get(), testConfig2);
439 std::string out = saveToJsonString(testConfig2);
440 BOOST_CHECK_EQUAL(out, jsonTestString);
442 PartialTestConfig partialConfig;
443 partialConfig.stringVal = testConfig.stringVal;
444 partialConfig.intVector = testConfig.intVector;
445 v.reset(saveToGVariant(partialConfig));
446 BOOST_CHECK_THROW(loadFromGVariant(v.get(), testConfig), ConfigException);
449 BOOST_AUTO_TEST_SUITE_END()