* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
*/
#include "util/config/ConfigBase.h"
#include "util/config/QueryConfig.h"
#include "util/format.h"
#include "gtest/gtest.h"
namespace omniruntime::config {
enum TestEnum { ENUM_0 = 0, ENUM_1 = 1, ENUM_2 = 2, UNKNOWN = 3 };
class TestConfig : public ConfigBase {
public:
template <typename T>
using Entry = ConfigBase::Entry<T>;
static Entry<int32_t> kInt32Entry;
static Entry<uint64_t> kUint64Entry;
static Entry<bool> kBoolEntry;
static Entry<std::string> kStringEntry;
static Entry<TestEnum> kEnumEntry;
TestConfig(std::unordered_map<std::string, std::string> &&configs, bool _mutable)
: ConfigBase(std::move(configs), _mutable) {}
};
TestConfig::Entry<int32_t> TestConfig::kInt32Entry("int32_entry", -32);
TestConfig::Entry<uint64_t> TestConfig::kUint64Entry("uint64_entry", 64);
TestConfig::Entry<bool> TestConfig::kBoolEntry("bool_entry", true);
TestConfig::Entry<std::string> TestConfig::kStringEntry("string_entry", "default.string.value");
TestConfig::Entry<TestEnum> TestConfig::kEnumEntry("enum_entry", TestEnum::ENUM_0, [](const TestEnum &value) {
if (value == TestEnum::ENUM_0) {
return "ENUM_0";
}
if (value == TestEnum::ENUM_1) {
return "ENUM_1";
}
if (value == TestEnum::ENUM_2) {
return "ENUM_2";
}
return "UNKNOWN";
}, [](const std::string & , const std::string &v) {
if (v == "ENUM_0") {
return TestEnum::ENUM_0;
}
if (v == "ENUM_1") {
return TestEnum::ENUM_1;
}
if (v == "ENUM_2") {
return TestEnum::ENUM_2;
}
return TestEnum::UNKNOWN;
});
TEST(ConfigTest, immutableConfig)
{
auto config = std::make_shared<TestConfig>(std::unordered_map<std::string, std::string>(), false);
ASSERT_EQ(config->Get(TestConfig::kInt32Entry), -32);
ASSERT_EQ(config->Get(TestConfig::kUint64Entry), 64);
ASSERT_EQ(config->Get(TestConfig::kBoolEntry), true);
ASSERT_EQ(config->Get(TestConfig::kStringEntry), "default.string.value");
ASSERT_EQ(config->Get(TestConfig::kEnumEntry), TestEnum::ENUM_0);
std::unordered_map<std::string, std::string> rawConfigs{
{TestConfig::kInt32Entry.key, "-3200"}, {TestConfig::kUint64Entry.key, "6400"},
{TestConfig::kStringEntry.key, "not.default.string.value"}, {TestConfig::kBoolEntry.key, "false"},
{TestConfig::kEnumEntry.key, "ENUM_2"}};
auto expectedRawConfigs = rawConfigs;
config = std::make_shared<TestConfig>(std::move(rawConfigs), false);
ASSERT_EQ(config->Get(TestConfig::kInt32Entry), -3200);
ASSERT_EQ(config->Get(TestConfig::kUint64Entry), 6400);
ASSERT_EQ(config->Get(TestConfig::kBoolEntry), false);
ASSERT_EQ(config->Get(TestConfig::kStringEntry), "not.default.string.value");
ASSERT_EQ(config->Get(TestConfig::kEnumEntry), TestEnum::ENUM_2);
ASSERT_EQ(config->Get(TestConfig::kInt32Entry.key, TestConfig::kInt32Entry.defaultVal), -3200);
ASSERT_EQ(config->Get(TestConfig::kUint64Entry.key, TestConfig::kUint64Entry.defaultVal), 6400);
ASSERT_EQ(config->Get(TestConfig::kBoolEntry.key, TestConfig::kBoolEntry.defaultVal), false);
ASSERT_EQ(config->Get(TestConfig::kStringEntry.key, TestConfig::kStringEntry.defaultVal),
"not.default.string.value");
ASSERT_TRUE(config->Get<int32_t>(TestConfig::kInt32Entry.key).has_value());
ASSERT_EQ(config->Get<int32_t>(TestConfig::kInt32Entry.key).value(), -3200);
ASSERT_FALSE(config->Get<int32_t>("wrong_int32_key").has_value());
ASSERT_TRUE(config->ValueExists(TestConfig::kInt32Entry.key));
ASSERT_FALSE(config->ValueExists("non_existent_entry"));
}
TEST(ConfigTest, mutableConfig)
{
std::unordered_map<std::string, std::string> initialConfigs{
{TestConfig::kInt32Entry.key, "-3200"}, {TestConfig::kUint64Entry.key, "6400"},
{TestConfig::kStringEntry.key, "initial.string.value"}, {TestConfig::kBoolEntry.key, "false"},
{TestConfig::kEnumEntry.key, "ENUM_2"}};
auto config = std::make_shared<TestConfig>(std::move(initialConfigs), true);
(*config).Set(TestConfig::kInt32Entry, 123).Set(TestConfig::kStringEntry, std::string("modified.string.value")).
Set(TestConfig::kBoolEntry.key, "true").Set(TestConfig::kEnumEntry.key, "ENUM_1");
ASSERT_EQ(config->Get(TestConfig::kInt32Entry), 123);
ASSERT_EQ(config->Get(TestConfig::kStringEntry), "modified.string.value");
ASSERT_EQ(config->Get(TestConfig::kBoolEntry), true);
ASSERT_EQ(config->Get(TestConfig::kEnumEntry), TestEnum::ENUM_1);
ASSERT_EQ(config->Get(TestConfig::kUint64Entry), 6400);
config->Unset(TestConfig::kUint64Entry);
ASSERT_EQ(config->Get(TestConfig::kUint64Entry), TestConfig::kUint64Entry.defaultVal);
config->Reset();
ASSERT_FALSE(config->ValueExists(TestConfig::kUint64Entry.key));
}
TEST(ConfigTest, emptyConfig)
{
QueryConfig config{};
ASSERT_FALSE(config.spillEnabled());
}
TEST(ConfigTest, setConfig)
{
const std::unordered_map<std::string, std::string> configData({{QueryConfig::kSpillEnabled, "true"}});
const QueryConfig config(configData);
ASSERT_TRUE(config.spillEnabled());
}
TEST(ConfigTest, maxRowCount)
{
struct {
std::optional<int> maxRowCount;;
int expectedMaxRowCount;
} testSettings[] = {{std::nullopt, 12UL << 20}, {2, 2}, {4, 4}, {6, 6}};
for (const auto &testConfig : testSettings) {
std::unordered_map<std::string, std::string> configData;
if (testConfig.maxRowCount.has_value()) {
configData.emplace(QueryConfig::KMaxRowCount, std::to_string(testConfig.maxRowCount.value()));
}
const QueryConfig config(configData);
ASSERT_EQ(config.maxRowCount(), testConfig.expectedMaxRowCount);
}
}
}