mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
fix: Array parsing in new config (#1896)
Improving array parsing in config: - Allow null values in arrays for optional fields - Allow empty array even for required field - Allow to not put an empty array in config even if array contains required fields
This commit is contained in:
@@ -17,10 +17,13 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "util/LoggerFixtures.hpp"
|
||||
#include "util/newconfig/Array.hpp"
|
||||
#include "util/newconfig/ArrayView.hpp"
|
||||
#include "util/newconfig/ConfigDefinition.hpp"
|
||||
#include "util/newconfig/ConfigDescription.hpp"
|
||||
#include "util/newconfig/ConfigFileJson.hpp"
|
||||
#include "util/newconfig/ConfigValue.hpp"
|
||||
#include "util/newconfig/FakeConfigData.hpp"
|
||||
#include "util/newconfig/Types.hpp"
|
||||
#include "util/newconfig/ValueView.hpp"
|
||||
@@ -29,10 +32,12 @@
|
||||
#include <boost/json/parse.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_set>
|
||||
@@ -304,19 +309,144 @@ TEST_F(IncorrectOverrideValues, InvalidJsonErrors)
|
||||
EXPECT_TRUE(errors.has_value());
|
||||
|
||||
// Expected error messages
|
||||
std::unordered_set<std::string_view> const expectedErrors{
|
||||
std::set<std::string_view> const expectedErrors{
|
||||
"dosguard.whitelist.[] value does not match type string",
|
||||
"higher.[].low.section key is required in user Config",
|
||||
"higher.[].low.admin key is required in user Config",
|
||||
"array.[].sub key is required in user Config",
|
||||
"header.port value does not match type integer",
|
||||
"header.admin value does not match type boolean",
|
||||
"optional.withDefault value does not match type double"
|
||||
};
|
||||
|
||||
std::unordered_set<std::string_view> actualErrors;
|
||||
std::set<std::string_view> actualErrors;
|
||||
for (auto const& error : errors.value()) {
|
||||
actualErrors.insert(error.error);
|
||||
}
|
||||
EXPECT_EQ(expectedErrors, actualErrors);
|
||||
}
|
||||
|
||||
struct ClioConfigDefinitionParseArrayTest : NoLoggerFixture {
|
||||
ClioConfigDefinition config{
|
||||
{"array.[].int", Array{ConfigValue{ConfigType::Integer}}},
|
||||
{"array.[].string", Array{ConfigValue{ConfigType::String}.optional()}}
|
||||
};
|
||||
};
|
||||
|
||||
TEST_F(ClioConfigDefinitionParseArrayTest, emptyArray)
|
||||
{
|
||||
auto const configJson = boost::json::parse(R"json({
|
||||
"array": []
|
||||
})json").as_object();
|
||||
|
||||
auto const result = config.parse(ConfigFileJson{configJson});
|
||||
EXPECT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(ClioConfigDefinitionParseArrayTest, emptyJson)
|
||||
{
|
||||
auto const configJson = boost::json::object{};
|
||||
|
||||
auto const result = config.parse(ConfigFileJson{configJson});
|
||||
EXPECT_FALSE(result.has_value());
|
||||
}
|
||||
|
||||
TEST_F(ClioConfigDefinitionParseArrayTest, fullArray)
|
||||
{
|
||||
auto const configJson = boost::json::parse(R"json({
|
||||
"array": [
|
||||
{"int": 1, "string": "one"},
|
||||
{"int": 2, "string": "two"}
|
||||
]
|
||||
})json").as_object();
|
||||
|
||||
auto const result = config.parse(ConfigFileJson{configJson});
|
||||
EXPECT_FALSE(result.has_value());
|
||||
EXPECT_EQ(config.arraySize("array.[]"), 2);
|
||||
}
|
||||
|
||||
TEST_F(ClioConfigDefinitionParseArrayTest, onlyRequiredFields) {
|
||||
auto const configJson = boost::json::parse(R"json({
|
||||
"array": [
|
||||
{"int": 1},
|
||||
{"int": 2}
|
||||
]
|
||||
})json").as_object();
|
||||
|
||||
auto const configFile = ConfigFileJson{configJson};
|
||||
auto const result = config.parse(configFile);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
EXPECT_EQ(config.arraySize("array.[]"), 2);
|
||||
|
||||
EXPECT_EQ(config.getArray("array.[].int").valueAt(0).asIntType<int>(), 1);
|
||||
EXPECT_EQ(config.getArray("array.[].int").valueAt(1).asIntType<int>(), 2);
|
||||
EXPECT_FALSE(config.getArray("array.[].string").valueAt(0).hasValue());
|
||||
EXPECT_FALSE(config.getArray("array.[].string").valueAt(1).hasValue());
|
||||
}
|
||||
|
||||
TEST_F(ClioConfigDefinitionParseArrayTest, someOptionalFieldsMissing)
|
||||
{
|
||||
auto const configJson = boost::json::parse(R"json({
|
||||
"array": [
|
||||
{"int": 1, "string": "one"},
|
||||
{"int": 2}
|
||||
]
|
||||
})json").as_object();
|
||||
|
||||
auto const configFile = ConfigFileJson{configJson};
|
||||
auto const result = config.parse(configFile);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
EXPECT_EQ(config.arraySize("array.[]"), 2);
|
||||
|
||||
EXPECT_EQ(config.getArray("array.[].int").valueAt(0).asIntType<int>(), 1);
|
||||
EXPECT_EQ(config.getArray("array.[].int").valueAt(1).asIntType<int>(), 2);
|
||||
EXPECT_EQ(config.getArray("array.[].string").valueAt(0).asString(), "one");
|
||||
EXPECT_FALSE(config.getArray("array.[].string").valueAt(1).hasValue());
|
||||
}
|
||||
|
||||
TEST_F(ClioConfigDefinitionParseArrayTest, optionalFieldMissingAtFirstPosition) {
|
||||
auto const configJson = boost::json::parse(R"json({
|
||||
"array": [
|
||||
{"int": 1},
|
||||
{"int": 2, "string": "two"}
|
||||
]
|
||||
})json").as_object();
|
||||
|
||||
auto const configFile = ConfigFileJson{configJson};
|
||||
auto const result = config.parse(configFile);
|
||||
ASSERT_FALSE(result.has_value());
|
||||
EXPECT_EQ(config.arraySize("array.[]"), 2);
|
||||
|
||||
EXPECT_EQ(config.getArray("array.[].int").valueAt(0).asIntType<int>(), 1);
|
||||
EXPECT_EQ(config.getArray("array.[].int").valueAt(1).asIntType<int>(), 2);
|
||||
|
||||
EXPECT_FALSE(config.getArray("array.[].string").valueAt(0).hasValue());
|
||||
EXPECT_EQ(config.getArray("array.[].string").valueAt(1).asString(), "two");
|
||||
}
|
||||
|
||||
TEST_F(ClioConfigDefinitionParseArrayTest, missingRequiredFields) {
|
||||
auto const configJson = boost::json::parse(R"json({
|
||||
"array": [
|
||||
{"int": 1},
|
||||
{"string": "two"}
|
||||
]
|
||||
})json").as_object();
|
||||
|
||||
auto const configFile = ConfigFileJson{configJson};
|
||||
auto const result = config.parse(configFile);
|
||||
ASSERT_TRUE(result.has_value());
|
||||
EXPECT_EQ(result->size(), 1);
|
||||
EXPECT_THAT(result->at(0).error, testing::StartsWith("array.[].int"));
|
||||
}
|
||||
|
||||
TEST_F(ClioConfigDefinitionParseArrayTest, missingAllRequiredFields) {
|
||||
auto const configJson = boost::json::parse(R"json({
|
||||
"array": [
|
||||
{"string": "one"},
|
||||
{"string": "two"}
|
||||
]
|
||||
})json").as_object();
|
||||
|
||||
auto const configFile = ConfigFileJson{configJson};
|
||||
auto const result = config.parse(configFile);
|
||||
ASSERT_TRUE(result.has_value());
|
||||
EXPECT_EQ(result->size(), 1);
|
||||
EXPECT_THAT(result->at(0).error, testing::StartsWith("array.[].int"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user