refactor: Clio Config (#1544)

Implementation of new config definition + methods + UT

Steps that still need to be implemented: 
- Make ClioConfigDefinition and it's method to be as constexpr as
possible
- Getting User Config file and populating the values in ConfigDefinition
while checking for constraints on user values
- Replacing all the places where we fetch config values (by using
config.valueOr/MaybeValue) to instead get it from Config Definition
- Generate markdown file using Clio Config Description
This commit is contained in:
Peter Chen
2024-08-06 11:07:25 -04:00
committed by GitHub
parent 5abf912b5a
commit 2bd7ac346c
27 changed files with 2421 additions and 20 deletions

View File

@@ -131,6 +131,13 @@ target_sources(
web/ServerTests.cpp
web/SweepHandlerTests.cpp
web/WhitelistHandlerTests.cpp
# New Config
util/newconfig/ArrayViewTests.cpp
util/newconfig/ObjectViewTests.cpp
util/newconfig/ValueViewTests.cpp
util/newconfig/ArrayTests.cpp
util/newconfig/ConfigValueTests.cpp
util/newconfig/ClioConfigDefinitionTests.cpp
)
configure_file(test_data/cert.pem ${CMAKE_BINARY_DIR}/tests/unit/test_data/cert.pem COPYONLY)

View File

@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "util/newconfig/Array.hpp"
#include "util/newconfig/ConfigValue.hpp"
#include "util/newconfig/ValueView.hpp"
#include <gtest/gtest.h>
using namespace util::config;
TEST(ArrayTest, testConfigArray)
{
auto arr = Array{
ConfigValue{ConfigType::Boolean}.defaultValue(false),
ConfigValue{ConfigType::Integer}.defaultValue(1234),
ConfigValue{ConfigType::Double}.defaultValue(22.22),
};
auto cv = arr.at(0);
ValueView vv{cv};
EXPECT_EQ(vv.asBool(), false);
auto cv2 = arr.at(1);
ValueView vv2{cv2};
EXPECT_EQ(vv2.asIntType<int>(), 1234);
EXPECT_EQ(arr.size(), 3);
arr.emplaceBack(ConfigValue{ConfigType::String}.defaultValue("false"));
EXPECT_EQ(arr.size(), 4);
auto cv4 = arr.at(3);
ValueView vv4{cv4};
EXPECT_EQ(vv4.asString(), "false");
}

View File

@@ -0,0 +1,139 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "util/newconfig/ArrayView.hpp"
#include "util/newconfig/ConfigDefinition.hpp"
#include "util/newconfig/ConfigValue.hpp"
#include "util/newconfig/FakeConfigData.hpp"
#include "util/newconfig/ObjectView.hpp"
#include "util/newconfig/ValueView.hpp"
#include <gtest/gtest.h>
#include <cstddef>
using namespace util::config;
struct ArrayViewTest : testing::Test {
ClioConfigDefinition const configData = generateConfig();
};
TEST_F(ArrayViewTest, ArrayValueTest)
{
ArrayView const arrVals = configData.getArray("array.[].sub");
auto valIt = arrVals.begin<ValueView>();
auto const precision = 1e-9;
EXPECT_NEAR((*valIt++).asDouble(), 111.11, precision);
EXPECT_NEAR((*valIt++).asDouble(), 4321.55, precision);
EXPECT_EQ(valIt, arrVals.end<ValueView>());
EXPECT_NEAR(111.11, arrVals.valueAt(0).asDouble(), precision);
EXPECT_NEAR(4321.55, arrVals.valueAt(1).asDouble(), precision);
ArrayView const arrVals2 = configData.getArray("array.[].sub2");
auto val2It = arrVals2.begin<ValueView>();
EXPECT_EQ((*val2It++).asString(), "subCategory");
EXPECT_EQ((*val2It++).asString(), "temporary");
EXPECT_EQ(val2It, arrVals2.end<ValueView>());
ValueView const tempVal = arrVals2.valueAt(0);
EXPECT_EQ(tempVal.type(), ConfigType::String);
EXPECT_EQ("subCategory", tempVal.asString());
}
TEST_F(ArrayViewTest, ArrayWithObjTest)
{
ArrayView const arrVals = configData.getArray("array.[]");
ArrayView const arrValAlt = configData.getArray("array");
auto const precision = 1e-9;
auto const obj1 = arrVals.objectAt(0);
auto const obj2 = arrValAlt.objectAt(0);
EXPECT_NEAR(obj1.getValue("sub").asDouble(), obj2.getValue("sub").asDouble(), precision);
EXPECT_NEAR(obj1.getValue("sub").asDouble(), 111.11, precision);
}
TEST_F(ArrayViewTest, IterateArray)
{
auto arr = configData.getArray("dosguard.whitelist");
EXPECT_EQ(2, arr.size());
EXPECT_EQ(arr.valueAt(0).asString(), "125.5.5.2");
EXPECT_EQ(arr.valueAt(1).asString(), "204.2.2.2");
auto it = arr.begin<ValueView>();
EXPECT_EQ((*it++).asString(), "125.5.5.2");
EXPECT_EQ((*it++).asString(), "204.2.2.2");
EXPECT_EQ((it), arr.end<ValueView>());
}
TEST_F(ArrayViewTest, DifferentArrayIterators)
{
auto const subArray = configData.getArray("array.[].sub");
auto const dosguardArray = configData.getArray("dosguard.whitelist.[]");
ASSERT_EQ(subArray.size(), dosguardArray.size());
auto itArray = subArray.begin<ValueView>();
auto itDosguard = dosguardArray.begin<ValueView>();
for (std::size_t i = 0; i < subArray.size(); i++)
EXPECT_NE(itArray++, itDosguard++);
}
TEST_F(ArrayViewTest, IterateObject)
{
auto arr = configData.getArray("array");
EXPECT_EQ(2, arr.size());
auto it = arr.begin<ObjectView>();
EXPECT_EQ(111.11, (*it).getValue("sub").asDouble());
EXPECT_EQ("subCategory", (*it++).getValue("sub2").asString());
EXPECT_EQ(4321.55, (*it).getValue("sub").asDouble());
EXPECT_EQ("temporary", (*it++).getValue("sub2").asString());
EXPECT_EQ(it, arr.end<ObjectView>());
}
struct ArrayViewDeathTest : ArrayViewTest {};
TEST_F(ArrayViewDeathTest, IncorrectAccess)
{
ArrayView const arr = configData.getArray("higher");
// dies because higher only has 1 object
EXPECT_DEATH({ [[maybe_unused]] auto _ = arr.objectAt(1); }, ".*");
ArrayView const arrVals2 = configData.getArray("array.[].sub2");
ValueView const tempVal = arrVals2.valueAt(0);
// dies because array.[].sub2 only has 2 config values
EXPECT_DEATH([[maybe_unused]] auto _ = arrVals2.valueAt(2), ".*");
// dies as value is not of type int
EXPECT_DEATH({ [[maybe_unused]] auto _ = tempVal.asIntType<int>(); }, ".*");
}
TEST_F(ArrayViewDeathTest, IncorrectIterateAccess)
{
ArrayView const arr = configData.getArray("higher");
EXPECT_DEATH({ [[maybe_unused]] auto _ = arr.begin<ValueView>(); }, ".*");
ArrayView const dosguardWhitelist = configData.getArray("dosguard.whitelist");
EXPECT_DEATH({ [[maybe_unused]] auto _ = dosguardWhitelist.begin<ObjectView>(); }, ".*");
}

View File

@@ -0,0 +1,167 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "util/newconfig/ArrayView.hpp"
#include "util/newconfig/ConfigDefinition.hpp"
#include "util/newconfig/ConfigDescription.hpp"
#include "util/newconfig/ConfigValue.hpp"
#include "util/newconfig/FakeConfigData.hpp"
#include <boost/json/object.hpp>
#include <boost/json/parse.hpp>
#include <boost/json/value.hpp>
#include <boost/json/value_to.hpp>
#include <gtest/gtest.h>
#include <string_view>
#include <unordered_set>
using namespace util::config;
// TODO: parsing config file and populating into config will be here once implemented
struct NewConfigTest : testing::Test {
ClioConfigDefinition const configData = generateConfig();
};
TEST_F(NewConfigTest, fetchValues)
{
auto const v = configData.getValue("header.port");
EXPECT_EQ(v.type(), ConfigType::Integer);
EXPECT_EQ("value", configData.getValue("header.text1").asString());
EXPECT_EQ(123, configData.getValue("header.port").asIntType<int>());
EXPECT_EQ(true, configData.getValue("header.admin").asBool());
EXPECT_EQ("TSM", configData.getValue("header.sub.sub2Value").asString());
EXPECT_EQ(444.22, configData.getValue("ip").asDouble());
auto const v2 = configData.getValueInArray("dosguard.whitelist", 0);
EXPECT_EQ(v2.asString(), "125.5.5.2");
}
TEST_F(NewConfigTest, fetchObject)
{
auto const obj = configData.getObject("header");
EXPECT_TRUE(obj.containsKey("sub.sub2Value"));
auto const obj2 = obj.getObject("sub");
EXPECT_TRUE(obj2.containsKey("sub2Value"));
EXPECT_EQ(obj2.getValue("sub2Value").asString(), "TSM");
auto const objInArr = configData.getObject("array", 0);
auto const obj2InArr = configData.getObject("array", 1);
EXPECT_EQ(objInArr.getValue("sub").asDouble(), 111.11);
EXPECT_EQ(objInArr.getValue("sub2").asString(), "subCategory");
EXPECT_EQ(obj2InArr.getValue("sub").asDouble(), 4321.55);
EXPECT_EQ(obj2InArr.getValue("sub2").asString(), "temporary");
}
TEST_F(NewConfigTest, fetchArray)
{
auto const obj = configData.getObject("dosguard");
EXPECT_TRUE(obj.containsKey("whitelist.[]"));
auto const arr = obj.getArray("whitelist");
EXPECT_EQ(2, arr.size());
auto const sameArr = configData.getArray("dosguard.whitelist");
EXPECT_EQ(2, sameArr.size());
EXPECT_EQ(sameArr.valueAt(0).asString(), arr.valueAt(0).asString());
EXPECT_EQ(sameArr.valueAt(1).asString(), arr.valueAt(1).asString());
}
TEST_F(NewConfigTest, CheckKeys)
{
EXPECT_TRUE(configData.contains("header.port"));
EXPECT_TRUE(configData.contains("array.[].sub"));
EXPECT_TRUE(configData.contains("dosguard.whitelist.[]"));
EXPECT_FALSE(configData.contains("dosguard.whitelist"));
EXPECT_TRUE(configData.hasItemsWithPrefix("dosguard"));
EXPECT_TRUE(configData.hasItemsWithPrefix("ip"));
EXPECT_EQ(configData.arraySize("array"), 2);
EXPECT_EQ(configData.arraySize("higher"), 1);
EXPECT_EQ(configData.arraySize("dosguard.whitelist"), 2);
}
TEST_F(NewConfigTest, CheckAllKeys)
{
auto expected = std::unordered_set<std::string_view>{};
auto const actual = std::unordered_set<std::string_view>{
"header.text1",
"header.port",
"header.admin",
"header.sub.sub2Value",
"ip",
"array.[].sub",
"array.[].sub2",
"higher.[].low.section",
"higher.[].low.admin",
"dosguard.whitelist.[]",
"dosguard.port"
};
for (auto i = configData.begin(); i != configData.end(); ++i) {
expected.emplace((i->first));
}
EXPECT_EQ(expected, actual);
}
struct NewConfigDeathTest : NewConfigTest {};
TEST_F(NewConfigDeathTest, IncorrectGetValues)
{
EXPECT_DEATH({ [[maybe_unused]] auto a_ = configData.getValue("head"); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto a_ = configData.getValue("head."); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto a_ = configData.getValue("asdf"); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto a_ = configData.getValue("dosguard.whitelist"); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto a_ = configData.getValue("dosguard.whitelist.[]"); }, ".*");
}
TEST_F(NewConfigDeathTest, IncorrectGetObject)
{
ASSERT_FALSE(configData.contains("head"));
EXPECT_DEATH({ [[maybe_unused]] auto a_ = configData.getObject("head"); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto a_ = configData.getObject("array"); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto a_ = configData.getObject("array", 2); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto a_ = configData.getObject("doesNotExist"); }, ".*");
}
TEST_F(NewConfigDeathTest, IncorrectGetArray)
{
EXPECT_DEATH({ [[maybe_unused]] auto a_ = configData.getArray("header.text1"); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto a_ = configData.getArray("asdf"); }, ".*");
}
TEST(ConfigDescription, getValues)
{
ClioConfigDescription definition{};
EXPECT_EQ(definition.get("database.type"), "Type of database to use.");
EXPECT_EQ(definition.get("etl_source.[].ip"), "IP address of the ETL source.");
EXPECT_EQ(definition.get("prometheus.enabled"), "Enable or disable Prometheus metrics.");
}
TEST(ConfigDescriptionAssertDeathTest, nonExistingKeyTest)
{
ClioConfigDescription definition{};
EXPECT_DEATH({ [[maybe_unused]] auto a = definition.get("data"); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto a = definition.get("etl_source.[]"); }, ".*");
}

View File

@@ -0,0 +1,40 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "util/newconfig/ConfigValue.hpp"
#include <gtest/gtest.h>
using namespace util::config;
TEST(ConfigValue, testConfigValue)
{
auto cvStr = ConfigValue{ConfigType::String}.defaultValue("12345");
EXPECT_EQ(cvStr.type(), ConfigType::String);
EXPECT_TRUE(cvStr.hasValue());
EXPECT_FALSE(cvStr.isOptional());
auto cvInt = ConfigValue{ConfigType::Integer}.defaultValue(543);
EXPECT_EQ(cvInt.type(), ConfigType::Integer);
EXPECT_TRUE(cvStr.hasValue());
EXPECT_FALSE(cvStr.isOptional());
auto cvOpt = ConfigValue{ConfigType::Integer}.optional();
EXPECT_TRUE(cvOpt.isOptional());
}

View File

@@ -0,0 +1,107 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "util/newconfig/ArrayView.hpp"
#include "util/newconfig/ConfigDefinition.hpp"
#include "util/newconfig/FakeConfigData.hpp"
#include "util/newconfig/ObjectView.hpp"
#include <gtest/gtest.h>
using namespace util::config;
struct ObjectViewTest : testing::Test {
ClioConfigDefinition const configData = generateConfig();
};
TEST_F(ObjectViewTest, ObjectValueTest)
{
auto const headerObj = configData.getObject("header");
EXPECT_FALSE(headerObj.containsKey("header"));
EXPECT_TRUE(headerObj.containsKey("text1"));
EXPECT_TRUE(headerObj.containsKey("port"));
EXPECT_TRUE(headerObj.containsKey("admin"));
EXPECT_EQ("value", headerObj.getValue("text1").asString());
EXPECT_EQ(123, headerObj.getValue("port").asIntType<int>());
EXPECT_EQ(true, headerObj.getValue("admin").asBool());
}
TEST_F(ObjectViewTest, ObjectInArray)
{
ArrayView const arr = configData.getArray("array");
EXPECT_EQ(arr.size(), 2);
ObjectView const firstObj = arr.objectAt(0);
ObjectView const secondObj = arr.objectAt(1);
EXPECT_TRUE(firstObj.containsKey("sub"));
EXPECT_TRUE(firstObj.containsKey("sub2"));
// object's key is only "sub" and "sub2"
EXPECT_FALSE(firstObj.containsKey("array.[].sub"));
EXPECT_EQ(firstObj.getValue("sub").asDouble(), 111.11);
EXPECT_EQ(firstObj.getValue("sub2").asString(), "subCategory");
EXPECT_EQ(secondObj.getValue("sub").asDouble(), 4321.55);
EXPECT_EQ(secondObj.getValue("sub2").asString(), "temporary");
}
TEST_F(ObjectViewTest, ObjectInArrayMoreComplex)
{
ArrayView const arr = configData.getArray("higher");
ASSERT_EQ(1, arr.size());
ObjectView const firstObj = arr.objectAt(0);
// this returns the 1st object inside "low"
ObjectView const sameObjFromConfigData = configData.getObject("higher.[].low", 0);
EXPECT_EQ(sameObjFromConfigData.getValue("admin").asBool(), firstObj.getValue("low.admin").asBool());
EXPECT_FALSE(firstObj.containsKey("low"));
EXPECT_TRUE(firstObj.containsKey("low.admin"));
ObjectView const objLow = firstObj.getObject("low");
EXPECT_TRUE(objLow.containsKey("section"));
EXPECT_TRUE(objLow.containsKey("admin"));
EXPECT_EQ(objLow.getValue("section").asString(), "true");
EXPECT_EQ(objLow.getValue("admin").asBool(), false);
}
TEST_F(ObjectViewTest, getArrayInObject)
{
auto const obj = configData.getObject("dosguard");
EXPECT_TRUE(obj.containsKey("whitelist.[]"));
auto const arr = obj.getArray("whitelist");
EXPECT_EQ(2, arr.size());
EXPECT_EQ("125.5.5.2", arr.valueAt(0).asString());
EXPECT_EQ("204.2.2.2", arr.valueAt(1).asString());
}
struct ObjectViewDeathTest : ObjectViewTest {};
TEST_F(ObjectViewDeathTest, incorrectKeys)
{
EXPECT_DEATH({ [[maybe_unused]] auto _ = configData.getObject("header.text1"); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto _ = configData.getObject("head"); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto _ = configData.getArray("header"); }, ".*");
// dies because only 1 object in higher.[].low
EXPECT_DEATH({ [[maybe_unused]] auto _ = configData.getObject("higher.[].low", 1); }, ".*");
}

View File

@@ -0,0 +1,90 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "util/newconfig/ConfigDefinition.hpp"
#include "util/newconfig/ConfigValue.hpp"
#include "util/newconfig/FakeConfigData.hpp"
#include "util/newconfig/ValueView.hpp"
#include <gtest/gtest.h>
#include <cstdint>
using namespace util::config;
struct ValueViewTest : testing::Test {
ClioConfigDefinition const configData = generateConfig();
};
TEST_F(ValueViewTest, ValueView)
{
ConfigValue const cv = ConfigValue{ConfigType::String}.defaultValue("value");
ValueView const vv = ValueView(cv);
EXPECT_EQ("value", vv.asString());
EXPECT_EQ(ConfigType::String, vv.type());
EXPECT_EQ(true, vv.hasValue());
EXPECT_EQ(false, vv.isOptional());
}
TEST_F(ValueViewTest, DifferentIntegerTest)
{
auto const vv = configData.getValue("header.port");
auto const uint32 = vv.asIntType<uint32_t>();
auto const uint64 = vv.asIntType<uint64_t>();
auto const int32 = vv.asIntType<int32_t>();
auto const int64 = vv.asIntType<int64_t>();
EXPECT_EQ(vv.asIntType<int>(), uint32);
EXPECT_EQ(vv.asIntType<int>(), uint64);
EXPECT_EQ(vv.asIntType<int>(), int32);
EXPECT_EQ(vv.asIntType<int>(), int64);
auto const doubleVal = vv.asIntType<double>();
auto const floatVal = vv.asIntType<float>();
auto const sameDouble = vv.asDouble();
auto const sameFloat = vv.asFloat();
auto const precision = 1e-9;
EXPECT_NEAR(doubleVal, sameDouble, precision);
EXPECT_NEAR(floatVal, sameFloat, precision);
auto const ipVal = configData.getValue("ip");
auto const ipDouble = ipVal.asDouble();
auto const ipFloat = ipVal.asFloat();
EXPECT_NEAR(ipDouble, 444.22, precision);
EXPECT_NEAR(ipFloat, 444.22f, precision);
}
struct ValueDeathTest : ValueViewTest {};
TEST_F(ValueDeathTest, WrongTypes)
{
auto const vv = configData.getValue("header.port");
EXPECT_DEATH({ [[maybe_unused]] auto a_ = vv.asBool(); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto a_ = vv.asString(); }, ".*");
auto const cv = ConfigValue{ConfigType::Integer}.defaultValue(-5);
auto const vv2 = ValueView(cv);
EXPECT_DEATH({ [[maybe_unused]] auto a_ = vv2.asIntType<uint32_t>(); }, ".*");
auto const cv2 = ConfigValue{ConfigType::String}.defaultValue("asdf");
auto const vv3 = ValueView(cv2);
EXPECT_DEATH({ [[maybe_unused]] auto a_ = vv3.asDouble(); }, ".*");
EXPECT_DEATH({ [[maybe_unused]] auto a_ = vv3.asFloat(); }, ".*");
}