Files
libconfig/tests/config/configTest.cpp
Emily Boudreaux d4bbd9cb3a feat(loading): robust error reporting and mutation
cfg now reports which fields are missing when loading. Further, the mutate method has been added for easier mutation of the underlying configuration struct
2026-04-07 09:28:27 -04:00

177 lines
5.6 KiB
C++

#include <gtest/gtest.h>
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <sstream>
#include <algorithm>
#include "fourdst/config/config.h"
#include "test_schema.h"
std::string get_good_example_file() {
const char* source_root = getenv("MESON_SOURCE_ROOT");
if (source_root == nullptr) {
throw std::runtime_error("MESON_SOURCE_ROOT environment variable is not set.");
}
return std::string(source_root) + "/tests/config/example_config_files/example.good.toml";
}
std::string get_good_missing_keys_example_file() {
const char* source_root = getenv("MESON_SOURCE_ROOT");
if (source_root == nullptr) {
throw std::runtime_error("MESON_SOURCE_ROOT environment variable is not set.");
}
return std::string(source_root) + "/tests/config/example_config_files/example.good.missing.field.toml";
}
enum class BAD_FILES {
UNKNOWN_KEY,
INVALID_TYPE,
INCORRECT_ARRAY_SIZE,
MISSING_NONDEFAULT_KEY
};
std::string get_bad_example_file(BAD_FILES type) {
const char* source_root = getenv("MESON_SOURCE_ROOT");
if (source_root == nullptr) {
throw std::runtime_error("MESON_SOURCE_ROOT environment variable is not set.");
}
switch (type) {
case BAD_FILES::UNKNOWN_KEY:
return std::string(source_root) + "/tests/config/example_config_files/example.unknownkey.toml";
case BAD_FILES::INVALID_TYPE:
return std::string(source_root) + "/tests/config/example_config_files/example.invalidtype.toml";
case BAD_FILES::INCORRECT_ARRAY_SIZE:
return std::string(source_root) + "/tests/config/example_config_files/example.incorrectarraysize.toml";
case BAD_FILES::MISSING_NONDEFAULT_KEY:
return std::string(source_root) + "/tests/config/example_config_files/example.missing.nondefault.field.toml";
}
throw std::runtime_error("Invalid BAD_FILES type.");
}
// std::string EXAMPLE_FILENAME = std::string(getenv("MESON_SOURCE_ROOT")) + "/tests/config/example.toml";
/**
* @file configTest.cpp
* @brief Unit tests for the Config class.
*/
/**
* @brief Test suite for the Config class.
*/
class configTest : public ::testing::Test {};
/**
* @brief Test the constructor of the Config class.
*/
TEST_F(configTest, constructor) {
EXPECT_NO_THROW(fourdst::config::Config<TestConfigSchema>());
}
TEST_F(configTest, load_good_file) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_NO_THROW(cfg.load(get_good_example_file()));
}
TEST_F(configTest, load_unknown_key_file) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_THROW(cfg.load(get_bad_example_file(BAD_FILES::UNKNOWN_KEY)), exceptions::ConfigParseError);
}
TEST_F(configTest, load_invalid_type_file) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_THROW(cfg.load(get_bad_example_file(BAD_FILES::INVALID_TYPE)), exceptions::ConfigParseError);
}
TEST_F(configTest, load_incorrect_array_size_file) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_THROW(cfg.load(get_bad_example_file(BAD_FILES::INCORRECT_ARRAY_SIZE)), exceptions::ConfigParseError);
}
TEST_F(configTest, check_value) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_NO_THROW(cfg.load(get_good_example_file()));
EXPECT_EQ(cfg->author, "Example Author");
}
TEST_F(configTest, nested_values) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_NO_THROW(cfg.load(get_good_example_file()));
EXPECT_EQ(cfg->physics.convection, false);
}
TEST_F(configTest, override_default) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_NO_THROW(cfg.load(get_good_example_file()));
EXPECT_EQ(cfg->simulation.time_step, 0.01);
}
TEST_F(configTest, array_values) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_NO_THROW(cfg.load(get_good_example_file()));
constexpr std::array<int, 3> expected = {1, 0, 1};
EXPECT_EQ(cfg->physics.flags, expected);
}
TEST_F(configTest, string_values) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_NO_THROW(cfg.load(get_good_example_file()));
EXPECT_EQ(cfg->output.format, "csv");
}
TEST_F(configTest, save_default) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_NO_THROW(cfg.save("TestConfigSchema.toml"));
}
TEST_F(configTest, save_schema) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_NO_THROW(cfg.save_schema("TestConfigSchema.schema.json"));
}
TEST_F(configTest, missing_default_keys) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_NO_THROW(cfg.load(get_good_example_file()));
}
TEST_F(configTest, missing_nondefault_keys) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_THROW(cfg.load(get_bad_example_file(BAD_FILES::MISSING_NONDEFAULT_KEY)), exceptions::ConfigParseError);
}
TEST_F(configTest, mutate_and_reset) {
using namespace fourdst::config;
Config<TestConfigSchema> cfg;
EXPECT_NO_THROW(cfg.load(get_good_example_file()));
EXPECT_TRUE(cfg->physics.diffusion);
EXPECT_EQ(cfg.get_state(), ConfigState::LOADED_FROM_FILE);
EXPECT_NO_THROW(
cfg.mutate([](auto& data) {
data.physics.diffusion = false;
});
);
EXPECT_FALSE(cfg->physics.diffusion);
EXPECT_EQ(cfg.get_state(), ConfigState::MODIFIED);
EXPECT_NO_THROW(cfg.reset());
EXPECT_TRUE(cfg->physics.diffusion);
EXPECT_EQ(cfg.get_state(), ConfigState::LOADED_FROM_FILE);
}