Add assets settings document tests

This commit is contained in:
2026-06-01 08:32:29 +02:00
parent 6c435dafb7
commit cc377b5eb5
9 changed files with 374 additions and 9 deletions

View File

@@ -0,0 +1,183 @@
#include "assets/settings_document.h"
#include <algorithm>
#include <cctype>
#include <cmath>
namespace pp::assets {
namespace {
[[nodiscard]] bool is_valid_key_char(char value) noexcept
{
const auto ch = static_cast<unsigned char>(value);
return std::isalnum(ch) != 0 || value == '_' || value == '-' || value == '.';
}
}
std::size_t SettingsDocument::size() const noexcept
{
return entries_.size();
}
bool SettingsDocument::empty() const noexcept
{
return entries_.empty();
}
bool SettingsDocument::has(std::string_view key) const noexcept
{
return find_entry(key) != entries_.end();
}
const std::vector<SettingsEntry>& SettingsDocument::entries() const noexcept
{
return entries_;
}
pp::foundation::Status SettingsDocument::set(std::string_view key, SettingsValue value)
{
const auto key_status = validate_settings_key(key);
if (!key_status.ok()) {
return key_status;
}
const auto value_status = validate_settings_value(value);
if (!value_status.ok()) {
return value_status;
}
auto found = find_entry(key);
if (found != entries_.end()) {
found->value = value;
return pp::foundation::Status::success();
}
if (entries_.size() >= max_settings_entries) {
return pp::foundation::Status::out_of_range("settings entry count exceeds the configured limit");
}
entries_.push_back(SettingsEntry {
.key = std::string(key),
.value = value,
});
return pp::foundation::Status::success();
}
pp::foundation::Result<SettingsValue> SettingsDocument::get(std::string_view key) const
{
const auto key_status = validate_settings_key(key);
if (!key_status.ok()) {
return pp::foundation::Result<SettingsValue>::failure(key_status);
}
const auto found = find_entry(key);
if (found == entries_.end()) {
return pp::foundation::Result<SettingsValue>::failure(
pp::foundation::Status::out_of_range("settings key was not found"));
}
return pp::foundation::Result<SettingsValue>::success(found->value);
}
pp::foundation::Status SettingsDocument::unset(std::string_view key) noexcept
{
const auto key_status = validate_settings_key(key);
if (!key_status.ok()) {
return key_status;
}
const auto found = find_entry(key);
if (found == entries_.end()) {
return pp::foundation::Status::out_of_range("settings key was not found");
}
entries_.erase(found);
return pp::foundation::Status::success();
}
void SettingsDocument::clear() noexcept
{
entries_.clear();
}
std::vector<SettingsEntry>::iterator SettingsDocument::find_entry(std::string_view key) noexcept
{
return std::find_if(
entries_.begin(),
entries_.end(),
[key](const SettingsEntry& entry) {
return entry.key == key;
});
}
std::vector<SettingsEntry>::const_iterator SettingsDocument::find_entry(std::string_view key) const noexcept
{
return std::find_if(
entries_.begin(),
entries_.end(),
[key](const SettingsEntry& entry) {
return entry.key == key;
});
}
pp::foundation::Status validate_settings_key(std::string_view key) noexcept
{
if (key.empty()) {
return pp::foundation::Status::invalid_argument("settings key must not be empty");
}
if (key.size() > max_settings_key_length) {
return pp::foundation::Status::out_of_range("settings key length exceeds the configured limit");
}
if (key.front() == '.' || key.back() == '.') {
return pp::foundation::Status::invalid_argument("settings key must not start or end with a dot");
}
for (const auto ch : key) {
if (!is_valid_key_char(ch)) {
return pp::foundation::Status::invalid_argument("settings key contains an unsupported character");
}
}
return pp::foundation::Status::success();
}
pp::foundation::Status validate_settings_value(const SettingsValue& value) noexcept
{
if (const auto* string_value = std::get_if<std::string>(&value)) {
if (string_value->size() > max_settings_string_length) {
return pp::foundation::Status::out_of_range("settings string length exceeds the configured limit");
}
}
if (const auto* double_value = std::get_if<double>(&value)) {
if (!std::isfinite(*double_value)) {
return pp::foundation::Status::invalid_argument("settings floating point value must be finite");
}
}
return pp::foundation::Status::success();
}
const char* settings_value_type_name(const SettingsValue& value) noexcept
{
if (std::holds_alternative<bool>(value)) {
return "bool";
}
if (std::holds_alternative<std::int64_t>(value)) {
return "int64";
}
if (std::holds_alternative<double>(value)) {
return "double";
}
if (std::holds_alternative<std::string>(value)) {
return "string";
}
return "unknown";
}
}