Merge remote-tracking branch 'origin/yaml-config' into integration_2024_w36

This commit is contained in:
Raphael Defosseux
2024-09-06 14:27:06 +02:00
24 changed files with 1078 additions and 15 deletions
+1
View File
@@ -1,3 +1,4 @@
add_subdirectory(utils)
add_subdirectory(config/yaml)
configure_file(oai_version.h.in oai_version.h @ONLY)
+6 -2
View File
@@ -293,8 +293,12 @@ configmodule_interface_t *load_configmodule(int argc,
} else if ( i == 1 ) {
/* -O argument doesn't contain ":" separator, assume -O <conf file> option, default cfgmode to libconfig
with one parameter, the path to the configuration file cfgmode must not be NULL */
modeparams=cfgmode;
cfgmode=strdup(CONFIG_LIBCONFIGFILE);
modeparams = cfgmode;
if (strstr(modeparams, ".yaml") != NULL || strstr(modeparams, ".yml") != NULL) {
cfgmode = strdup("yaml");
} else {
cfgmode = strdup(CONFIG_LIBCONFIGFILE);
}
}
static configmodule_interface_t *cfgptr;
if (cfgptr)
+25
View File
@@ -0,0 +1,25 @@
find_package(yaml-cpp REQUIRED PATHS /usr/lib/aarch64-linux-gnu/pkgconfig/)
# include(FetchContent)
# FetchContent_Declare(
# yaml-cpp
# GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
# GIT_TAG 0.8.0
# )
# FetchContent_GetProperties(yaml-cpp)
# if(NOT yaml-cpp_POPULATED)
# message(STATUS "Fetching yaml-cpp...")
# FetchContent_Populate(yaml-cpp)
# add_subdirectory(${yaml-cpp_SOURCE_DIR} ${yaml-cpp_BINARY_DIR})
# endif()
add_library(params_yaml_static config_yaml.cpp)
target_link_libraries(params_yaml_static PUBLIC UTIL yaml-cpp)
if (ENABLE_TESTS)
add_subdirectory(tests)
endif()
add_library(params_yaml MODULE config_yaml.cpp)
target_link_libraries(params_yaml PUBLIC UTIL yaml-cpp)
set_target_properties(params_yaml PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+327
View File
@@ -0,0 +1,327 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "yaml-cpp/yaml.h"
extern "C" {
#include "common/config/config_load_configmodule.h"
#include "common/config/config_userapi.h"
void *config_allocate_new(configmodule_interface_t *cfg, int sz, bool autoFree);
void config_check_valptr(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int elt_sz, int nb_elt);
}
#include <cstring>
#include <string>
#include <sstream>
#include <algorithm>
#include <iostream>
namespace config_yaml {
class YamlConfig {
public:
YAML::Node config;
YamlConfig(std::string filename)
{
config = YAML::LoadFile(filename);
}
};
void SetDefault(configmodule_interface_t *cfg, paramdef_t *param)
{
switch (param->type) {
case TYPE_INT:
*param->iptr = param->defintval;
break;
case TYPE_UINT:
*param->uptr = param->defuintval;
break;
case TYPE_STRING:
if (param->defstrval != nullptr) {
if (param->numelt == 0) {
config_check_valptr(cfg, param, 1, strlen(param->defstrval) + 1);
}
sprintf(*param->strptr, "%s", param->defstrval);
}
break;
case TYPE_INT8:
*param->i8ptr = param->defintval;
break;
case TYPE_UINT8:
*param->i8ptr = param->defuintval;
break;
case TYPE_INT16:
*param->i16ptr = param->defintval;
break;
case TYPE_UINT16:
*param->u16ptr = param->defuintval;
break;
case TYPE_INT64:
*param->i64ptr = param->defint64val;
break;
case TYPE_UINT64:
*param->u64ptr = param->defint64val;
break;
case TYPE_DOUBLE:
*param->dblptr = param->defdblval;
break;
case TYPE_MASK:
*param->uptr = param->defuintval;
break;
case TYPE_STRINGLIST:
if (param->defstrlistval != nullptr) {
param->strlistptr = param->defstrlistval;
}
break;
case TYPE_INTARRAY:
if (param->defintarrayval) {
param->iptr = param->defintarrayval;
}
break;
case TYPE_UINTARRAY:
if (param->defintarrayval) {
param->uptr = (uint32_t *)param->defintarrayval;
}
break;
default:
AssertFatal(false, "Unhandled type %d", param->type);
}
param->paramflags |= PARAMFLAG_PARAMSETDEF;
}
void SetNonDefault(configmodule_interface_t *cfg, const YAML::Node &node, paramdef_t *param)
{
auto optname = std::string(param->optname);
switch (param->type) {
case TYPE_INT:
*param->iptr = node[optname].as<int>();
break;
case TYPE_UINT:
*param->uptr = node[optname].as<uint>();
break;
case TYPE_STRING: {
std::string setting = node[optname].as<std::string>();
config_check_valptr(cfg, param, 1, setting.length() + 1);
sprintf(*param->strptr, "%s", setting.c_str());
break;
}
case TYPE_UINT8:
*param->i8ptr = node[optname].as<uint8_t>();
break;
case TYPE_INT16:
*param->i16ptr = node[optname].as<int16_t>();
break;
case TYPE_UINT16:
*param->u16ptr = node[optname].as<uint16_t>();
break;
case TYPE_INT64:
*param->i64ptr = node[optname].as<int64_t>();
break;
case TYPE_UINT64:
*param->u64ptr = node[optname].as<uint64_t>();
break;
case TYPE_DOUBLE:
*param->dblptr = node[optname].as<double>();
break;
case TYPE_MASK:
*param->uptr = node[optname].as<uint>();
break;
case TYPE_STRINGLIST: {
if (node[optname].IsSequence()) {
config_check_valptr(cfg, param, sizeof(char *), node[optname].size());
int i = 0;
for (const auto &elem : node[optname]) {
sprintf(param->strlistptr[i], "%s", elem.as<std::string>().c_str());
i++;
}
param->numelt = i;
} else {
param->numelt = 0;
}
break;
}
case TYPE_INTARRAY: {
if (node[optname].IsSequence() && node[optname].size() > 0) {
param->numelt = node[optname].size();
param->iptr =
(int32_t *)config_allocate_new(cfg, param->numelt * sizeof(*param->iptr), !(param->paramflags & PARAMFLAG_NOFREE));
for (int i = 0; i < param->numelt; i++) {
param->iptr[i] = node[optname][i].as<int32_t>();
}
} else {
param->numelt = 0;
}
break;
}
case TYPE_UINTARRAY: {
if (node[optname].IsSequence() && node[optname].size() > 0) {
param->numelt = node[optname].size();
param->uptr =
(uint32_t *)config_allocate_new(cfg, param->numelt * sizeof(*param->uptr), !(param->paramflags & PARAMFLAG_NOFREE));
for (int i = 0; i < param->numelt; i++) {
param->uptr[i] = node[optname][i].as<uint32_t>();
}
} else {
param->numelt = 0;
}
break;
}
default:
AssertFatal(false, "Unhandled type %d", param->type);
}
param->paramflags |= PARAMFLAG_PARAMSET;
}
void GetParams(configmodule_interface_t *cfg, const YAML::Node &node, paramdef_t *params, int num_params)
{
for (auto i = 0; i < num_params; i++) {
if (node && node[std::string(params[i].optname)]) {
SetNonDefault(cfg, node, &params[i]);
} else {
SetDefault(cfg, &params[i]);
}
}
}
static YamlConfig *config;
static YAML::Node invalid_node;
} // namespace config_yaml
extern "C" int config_yaml_init(configmodule_interface_t *cfg)
{
char **cfgP = cfg->cfgP;
cfg->numptrs = 0;
pthread_mutex_init(&cfg->memBlocks_mutex, NULL);
memset(cfg->oneBlock, 0, sizeof(cfg->oneBlock));
config_yaml::config = new config_yaml::YamlConfig(std::string(cfgP[0]));
return 0;
}
extern "C" void config_yaml_end(configmodule_interface_t *cfg)
{
delete config_yaml::config;
}
YAML::Node find_node(const std::string &prefix, YAML::Node node)
{
// Iterate through each key in the prefix
std::stringstream ss(prefix);
std::string key;
YAML::Node current = node;
while (std::getline(ss, key, '.')) {
if (key.at(0) == '[' && key.back() == ']') {
// The key is an index to a sequence
if (!current.IsSequence()) {
throw std::invalid_argument("Incorrect yaml file structure");
}
int index = std::stoi(key.substr(1, key.size() - 2));
current = current[index];
continue;
}
if (!current.IsMap()) {
throw std::invalid_argument("Incorrect yaml file structure");
}
if (!current[key]) {
return config_yaml::invalid_node;
}
current = current[key];
}
return current;
}
extern "C" int config_yaml_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix)
{
std::string p;
if (prefix != nullptr) {
p = std::string(prefix);
}
auto node = find_node(p, YAML::Clone(config_yaml::config->config));
if (node == config_yaml::invalid_node) {
return -1;
}
for (auto i = 0; i < numoptions; i++) {
if (cfgoptions[i].type != TYPE_STRING && cfgoptions[i].type != TYPE_INTARRAY && cfgoptions[i].type != TYPE_UINTARRAY
&& cfgoptions[i].voidptr == nullptr) {
config_check_valptr(cfg, &cfgoptions[i], sizeof(void *), 1);
}
}
config_yaml::GetParams(cfg, node, cfgoptions, numoptions);
return 0;
}
extern "C" int config_yaml_getlist(configmodule_interface_t *cfg,
paramlist_def_t *ParamList,
paramdef_t *params,
int numparams,
char *prefix)
{
char path[512];
if (prefix != nullptr) {
sprintf(path, "%s.%s", prefix, ParamList->listname);
} else {
sprintf(path, "%s", ParamList->listname);
}
ParamList->numelt = 0;
auto node = find_node(path, YAML::Clone(config_yaml::config->config));
if (node == config_yaml::invalid_node) {
return -1;
}
if (!node.IsSequence()) {
return -1;
}
ParamList->numelt = node.size();
if (ParamList->numelt > 0 && params != NULL) {
ParamList->paramarray = static_cast<paramdef_t **>(config_allocate_new(cfg, ParamList->numelt * sizeof(paramdef_t *), true));
for (int i = 0; i < ParamList->numelt; i++) {
ParamList->paramarray[i] = static_cast<paramdef *>(config_allocate_new(cfg, numparams * sizeof(paramdef_t), true));
memcpy(ParamList->paramarray[i], params, sizeof(paramdef_t) * numparams);
for (int j = 0; j < numparams; j++) {
ParamList->paramarray[i][j].strptr = NULL;
if (ParamList->paramarray[i][j].type != TYPE_STRING) {
config_check_valptr(cfg, &ParamList->paramarray[i][j], sizeof(void *), 1);
}
}
config_yaml::GetParams(cfg, node[i], ParamList->paramarray[i], numparams);
}
}
return ParamList->numelt;
}
extern "C" void config_yaml_write_parsedcfg(configmodule_interface_t *cfg)
{
(void)cfg;
}
extern "C" int config_yaml_set(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix)
{
(void)cfg;
(void)cfgoptions;
(void)numoptions;
(void)prefix;
return 0;
}
+11
View File
@@ -0,0 +1,11 @@
add_executable(test_yaml_config test_yaml_config.cpp)
target_link_libraries(test_yaml_config PRIVATE params_yaml_static GTest::gtest)
add_dependencies(tests test_yaml_config)
add_test(NAME test_yaml_config
COMMAND ./test_yaml_config)
configure_file(test1.yaml test1.yaml COPYONLY)
configure_file(test_recursion.yaml test_recursion.yaml COPYONLY)
configure_file(test_list.yaml test_list.yaml COPYONLY)
configure_file(test_string.yaml test_string.yaml COPYONLY)
configure_file(test_list_of_mappings.yml test_list_of_mappings.yml COPYONLY)
configure_file(test_int_array.yaml test_int_array.yaml COPYONLY)
+4
View File
@@ -0,0 +1,4 @@
test:
value1: 1
value2: 2
value3: 3
@@ -0,0 +1,6 @@
test:
array: [1, 2, 3, 4]
array2:
- 1
- 2
- 3
+13
View File
@@ -0,0 +1,13 @@
test:
-
value1: 1
value2: 2
value3: 3
-
value1: 4
value2: 5
value3: 6
-
value1: 7
value2: 8
value3: 9
@@ -0,0 +1,14 @@
test:
list:
- value1: 1
value2: 3
list:
- value1
- value2
- value3
- value: 2
value2: 6
list:
- value4
- value5
- value6
@@ -0,0 +1,8 @@
test:
test1:
test2:
test3:
test4:
value1: 1
value2: 2
value3: 3
@@ -0,0 +1,6 @@
test:
stringvalue: testvalue
stringlist:
- testvalue1
- testvalue2
- testvalue3
@@ -0,0 +1,373 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "gtest/gtest.h"
extern "C" {
#include "common/config/config_paramdesc.h"
// TODO: Should use minimal_lib for this but for some reason it doesn't link properly
uint64_t get_softmodem_optmask(void)
{
return 0;
}
configmodule_interface_t *uniqCfg;
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
if (assert) {
abort();
} else {
exit(EXIT_SUCCESS);
}
}
#include "common/utils/LOG/log.h"
#include "common/config/config_load_configmodule.h"
#include "common/config/config_userapi.h"
}
#include <cstdio>
#include <cstring>
#include <string>
#include <sstream>
#include <algorithm>
extern "C" {
int config_yaml_init(configmodule_interface_t *cfg);
void config_yaml_end(configmodule_interface_t *cfg);
int config_yaml_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix);
int config_yaml_getlist(configmodule_interface_t *cfg, paramlist_def_t *ParamList, paramdef_t *params, int numparams, char *prefix);
void config_yaml_write_parsedcfg(configmodule_interface_t *cfg);
int config_yaml_set(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix);
}
TEST(yaml_config, yaml_basic) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test1.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, yaml_get_existing_values) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test1.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
// Testing paremters present in the test node
paramdef_t p = {0};
for (auto i = 1; i <= 3; i++) {
sprintf(p.optname, "%s%d", "value", i);
uint16_t value;
p.type = TYPE_UINT16;
p.u16ptr = &value;
char prefix[] = "test";
config_yaml_get(cfg, &p, 1, prefix);
EXPECT_EQ(value, i);
}
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, yaml_get_non_existing_values) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test1.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
// Testing paremters present in the test node
paramdef_t p = {0};
for (auto i = 4; i <= 5; i++) {
sprintf(p.optname, "%s%d", "value", i);
uint16_t value;
p.type = TYPE_UINT16;
p.u16ptr = &value;
p.defuintval = i;
char prefix[] = "test";
config_yaml_get(cfg, &p, 1, prefix);
EXPECT_EQ(value, i);
}
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_high_recusion) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_recursion.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
// Testing paremters present in the test node
paramdef_t p = {0};
for (auto i = 1; i <= 3; i++) {
sprintf(p.optname, "%s%d", "value", i);
uint16_t value;
p.type = TYPE_UINT16;
p.u16ptr = &value;
char prefix[] = "test.test1.test2.test3.test4";
EXPECT_EQ(config_yaml_get(cfg, &p, 1, prefix), 0);
EXPECT_EQ(value, i);
}
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_list) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_list.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramlist_def_t param_list = {0};
sprintf(param_list.listname, "%s", "test");
paramdef_t params[3] = {0};
uint16_t value[3];
for (auto i = 0; i < 3; i++) {
sprintf(params[i].optname, "%s%d", "value", i+1);
params[i].type = TYPE_UINT16;
params[i].u16ptr = &value[i];
}
config_yaml_getlist(cfg, &param_list, params, 3, nullptr);
for (auto i = 0; i < 3; i++) {
for (auto j = 0; j < 3; j++) {
EXPECT_EQ(*param_list.paramarray[i][j].u16ptr, i * 3 + j + 1);
}
}
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_string_auto_alloc) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_string.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRING;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringvalue");
param.defstrval = nullptr;
// Test automatic allocation of strings
char prefix[] = "test";
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_NE(param.strptr, nullptr);
EXPECT_EQ(strcmp(*param.strptr, "testvalue"), 0);
EXPECT_EQ(cfg->numptrs, 2);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_string_no_realloc) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_string.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRING;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringvalue");
param.defstrval = nullptr;
// check that if we at least have a non-null pointer to pointer, only one buffer is allocated
char prefix[] = "test";
char* non_null_pointer_to_pointer = nullptr;
param.strptr = &non_null_pointer_to_pointer;
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_EQ(param.strptr, &non_null_pointer_to_pointer);
EXPECT_EQ(strcmp(*param.strptr, "testvalue"), 0);
EXPECT_EQ(cfg->numptrs, 1);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_string_pointer_available) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_string.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRING;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringvalue");
param.defstrval = nullptr;
// Test that if a strptr is provided, config module doesnt reallocate it
char prefix[] = "test";
char *container = (char *)malloc(sizeof(char) * 30);
param.strptr = &container;
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_EQ(param.strptr, &container);
EXPECT_EQ(strcmp(*param.strptr, "testvalue"), 0);
EXPECT_EQ(cfg->numptrs, 0);
free(container);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_string_default_value) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_string.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRING;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringvalue");
param.defstrval = nullptr;
// Test that if defstrval is not null and value is missing in yaml defstrval is set
char prefix[] = "test";
char default_value[] = "default";
param.defstrval = default_value;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringvalue_missing");
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_NE(param.strptr, nullptr);
EXPECT_EQ(strcmp(*param.strptr, "default"), 0);
EXPECT_EQ(cfg->numptrs, 2) << " 2 pointers required, 1 for the string, one for the pointer-to string";
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_stringlist) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_string.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRINGLIST;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringlist");
param.defstrval = nullptr;
// Test automatic allocation of string lists
char prefix[] = "test";
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_NE(param.strptr, nullptr);
for (auto i = 0; i < param.numelt; i++) {
std::cout << (param.strlistptr)[i] << std::endl;
}
// config_check_valptr allocates maximum list size regardless of the number of elements in list
EXPECT_EQ(cfg->numptrs, MAX_LIST_SIZE + 1);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_list_of_mappings) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_list_of_mappings.yml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRINGLIST;
param.strlistptr = nullptr;
sprintf(param.optname, "%s", "list");
param.defstrval = nullptr;
// Test automatic allocation of string lists
char prefix1[] = "test.list.[0]";
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix1), 0);
EXPECT_NE(param.strptr, nullptr);
EXPECT_STREQ("value1", param.strlistptr[0]);
EXPECT_STREQ("value2", param.strlistptr[1]);
EXPECT_STREQ("value3", param.strlistptr[2]);
char prefix2[] = "test.list.[1]";
param.strlistptr = nullptr;
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix2), 0);
EXPECT_NE(param.strptr, nullptr);
EXPECT_STREQ("value4", param.strlistptr[0]);
EXPECT_STREQ("value5", param.strlistptr[1]);
EXPECT_STREQ("value6", param.strlistptr[2]);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_int_array) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_int_array.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_INTARRAY;
param.iptr = nullptr;
sprintf(param.optname, "%s", "array");
param.defintarrayval = nullptr;
// Test automatic allocation of int arrays
char prefix[] = "test";
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_NE(param.iptr, nullptr);
ASSERT_EQ(param.numelt, 4);
EXPECT_EQ(1, param.iptr[0]);
EXPECT_EQ(2, param.iptr[1]);
EXPECT_EQ(3, param.iptr[2]);
EXPECT_EQ(4, param.iptr[3]);
param.uptr = nullptr;
param.numelt = 0;
sprintf(param.optname, "%s", "array2");
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_NE(param.uptr, nullptr);
ASSERT_EQ(param.numelt, 3);
EXPECT_EQ(1U, param.uptr[0]);
EXPECT_EQ(2U, param.uptr[1]);
EXPECT_EQ(3U, param.uptr[2]);
param.uptr = nullptr;
param.numelt = 0;
sprintf(param.optname, "%s", "non-existent-array");
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_EQ(param.uptr, nullptr);
ASSERT_EQ(param.numelt, 0);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
int main(int argc, char** argv)
{
logInit();
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}