mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-31 19:00:54 -06:00
JSON: Add helpers
This commit is contained in:
@@ -336,6 +336,7 @@ set(SRCS
|
||||
cmInstallTargetGenerator.cxx
|
||||
cmInstallDirectoryGenerator.h
|
||||
cmInstallDirectoryGenerator.cxx
|
||||
cmJSONHelpers.h
|
||||
cmLDConfigLDConfigTool.cxx
|
||||
cmLDConfigLDConfigTool.h
|
||||
cmLDConfigTool.cxx
|
||||
|
||||
304
Source/cmJSONHelpers.h
Normal file
304
Source/cmJSONHelpers.h
Normal file
@@ -0,0 +1,304 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
#include <cm/string_view>
|
||||
|
||||
#include <cm3p/json/value.h>
|
||||
|
||||
template <typename T, typename E>
|
||||
using cmJSONHelper = std::function<E(T& out, const Json::Value* value)>;
|
||||
|
||||
template <typename T, typename E>
|
||||
class cmJSONObjectHelper
|
||||
{
|
||||
public:
|
||||
cmJSONObjectHelper(E&& success, E&& fail, bool allowExtra = true);
|
||||
|
||||
template <typename U, typename M, typename F>
|
||||
cmJSONObjectHelper& Bind(const cm::string_view& name, M U::*member, F func,
|
||||
bool required = true);
|
||||
template <typename M, typename F>
|
||||
cmJSONObjectHelper& Bind(const cm::string_view& name, std::nullptr_t, F func,
|
||||
bool required = true);
|
||||
|
||||
E operator()(T& out, const Json::Value* value) const;
|
||||
|
||||
private:
|
||||
// Not a true cmJSONHelper, it just happens to match the signature
|
||||
using MemberFunction = std::function<E(T& out, const Json::Value* value)>;
|
||||
struct Member
|
||||
{
|
||||
cm::string_view Name;
|
||||
MemberFunction Function;
|
||||
bool Required;
|
||||
};
|
||||
std::vector<Member> Members;
|
||||
bool AnyRequired = false;
|
||||
E Success;
|
||||
E Fail;
|
||||
bool AllowExtra;
|
||||
|
||||
cmJSONObjectHelper& BindPrivate(const cm::string_view& name,
|
||||
MemberFunction&& func, bool required);
|
||||
};
|
||||
|
||||
template <typename T, typename E>
|
||||
cmJSONObjectHelper<T, E>::cmJSONObjectHelper(E&& success, E&& fail,
|
||||
bool allowExtra)
|
||||
: Success(std::move(success))
|
||||
, Fail(std::move(fail))
|
||||
, AllowExtra(allowExtra)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename E>
|
||||
template <typename U, typename M, typename F>
|
||||
cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::Bind(
|
||||
const cm::string_view& name, M U::*member, F func, bool required)
|
||||
{
|
||||
return this->BindPrivate(
|
||||
name,
|
||||
[func, member](T& out, const Json::Value* value) -> E {
|
||||
return func(out.*member, value);
|
||||
},
|
||||
required);
|
||||
}
|
||||
|
||||
template <typename T, typename E>
|
||||
template <typename M, typename F>
|
||||
cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::Bind(
|
||||
const cm::string_view& name, std::nullptr_t, F func, bool required)
|
||||
{
|
||||
return this->BindPrivate(name,
|
||||
[func](T& /*out*/, const Json::Value* value) -> E {
|
||||
M dummy;
|
||||
return func(dummy, value);
|
||||
},
|
||||
required);
|
||||
}
|
||||
|
||||
template <typename T, typename E>
|
||||
cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::BindPrivate(
|
||||
const cm::string_view& name, MemberFunction&& func, bool required)
|
||||
{
|
||||
Member m;
|
||||
m.Name = name;
|
||||
m.Function = std::move(func);
|
||||
m.Required = required;
|
||||
this->Members.push_back(std::move(m));
|
||||
if (required) {
|
||||
this->AnyRequired = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename E>
|
||||
E cmJSONObjectHelper<T, E>::operator()(T& out, const Json::Value* value) const
|
||||
{
|
||||
if (!value && this->AnyRequired) {
|
||||
return this->Fail;
|
||||
}
|
||||
if (value && !value->isObject()) {
|
||||
return this->Fail;
|
||||
}
|
||||
Json::Value::Members extraFields;
|
||||
if (value) {
|
||||
extraFields = value->getMemberNames();
|
||||
}
|
||||
|
||||
for (auto const& m : this->Members) {
|
||||
std::string name(m.Name.data(), m.Name.size());
|
||||
if (value && value->isMember(name)) {
|
||||
E result = m.Function(out, &(*value)[name]);
|
||||
if (result != this->Success) {
|
||||
return result;
|
||||
}
|
||||
extraFields.erase(
|
||||
std::find(extraFields.begin(), extraFields.end(), name));
|
||||
} else if (!m.Required) {
|
||||
E result = m.Function(out, nullptr);
|
||||
if (result != this->Success) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
return this->Fail;
|
||||
}
|
||||
}
|
||||
|
||||
return this->AllowExtra || extraFields.empty() ? this->Success : this->Fail;
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
cmJSONHelper<std::string, E> cmJSONStringHelper(E success, E fail,
|
||||
const std::string& defval = "")
|
||||
{
|
||||
return
|
||||
[success, fail, defval](std::string& out, const Json::Value* value) -> E {
|
||||
if (!value) {
|
||||
out = defval;
|
||||
return success;
|
||||
}
|
||||
if (!value->isString()) {
|
||||
return fail;
|
||||
}
|
||||
out = value->asString();
|
||||
return success;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
cmJSONHelper<int, E> cmJSONIntHelper(E success, E fail, int defval = 0)
|
||||
{
|
||||
return [success, fail, defval](int& out, const Json::Value* value) -> E {
|
||||
if (!value) {
|
||||
out = defval;
|
||||
return success;
|
||||
}
|
||||
if (!value->isInt()) {
|
||||
return fail;
|
||||
}
|
||||
out = value->asInt();
|
||||
return success;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
cmJSONHelper<unsigned int, E> cmJSONUIntHelper(E success, E fail,
|
||||
unsigned int defval = 0)
|
||||
{
|
||||
return
|
||||
[success, fail, defval](unsigned int& out, const Json::Value* value) -> E {
|
||||
if (!value) {
|
||||
out = defval;
|
||||
return success;
|
||||
}
|
||||
if (!value->isUInt()) {
|
||||
return fail;
|
||||
}
|
||||
out = value->asUInt();
|
||||
return success;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
cmJSONHelper<bool, E> cmJSONBoolHelper(E success, E fail, bool defval = false)
|
||||
{
|
||||
return [success, fail, defval](bool& out, const Json::Value* value) -> E {
|
||||
if (!value) {
|
||||
out = defval;
|
||||
return success;
|
||||
}
|
||||
if (!value->isBool()) {
|
||||
return fail;
|
||||
}
|
||||
out = value->asBool();
|
||||
return success;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T, typename E, typename F, typename Filter>
|
||||
cmJSONHelper<std::vector<T>, E> cmJSONVectorFilterHelper(E success, E fail,
|
||||
F func, Filter filter)
|
||||
{
|
||||
return [success, fail, func, filter](std::vector<T>& out,
|
||||
const Json::Value* value) -> E {
|
||||
if (!value) {
|
||||
out.clear();
|
||||
return success;
|
||||
}
|
||||
if (!value->isArray()) {
|
||||
return fail;
|
||||
}
|
||||
out.clear();
|
||||
for (auto const& item : *value) {
|
||||
T t;
|
||||
E result = func(t, &item);
|
||||
if (result != success) {
|
||||
return result;
|
||||
}
|
||||
if (!filter(t)) {
|
||||
continue;
|
||||
}
|
||||
out.push_back(t);
|
||||
}
|
||||
return success;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T, typename E, typename F>
|
||||
cmJSONHelper<std::vector<T>, E> cmJSONVectorHelper(E success, E fail, F func)
|
||||
{
|
||||
return cmJSONVectorFilterHelper<T, E, F>(success, fail, func,
|
||||
[](const T&) { return true; });
|
||||
}
|
||||
|
||||
template <typename T, typename E, typename F, typename Filter>
|
||||
cmJSONHelper<std::map<std::string, T>, E> cmJSONMapFilterHelper(E success,
|
||||
E fail, F func,
|
||||
Filter filter)
|
||||
{
|
||||
return [success, fail, func, filter](std::map<std::string, T>& out,
|
||||
const Json::Value* value) -> E {
|
||||
if (!value) {
|
||||
out.clear();
|
||||
return success;
|
||||
}
|
||||
if (!value->isObject()) {
|
||||
return fail;
|
||||
}
|
||||
out.clear();
|
||||
for (auto const& key : value->getMemberNames()) {
|
||||
if (!filter(key)) {
|
||||
continue;
|
||||
}
|
||||
T t;
|
||||
E result = func(t, &(*value)[key]);
|
||||
if (result != success) {
|
||||
return result;
|
||||
}
|
||||
out[key] = std::move(t);
|
||||
}
|
||||
return success;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T, typename E, typename F>
|
||||
cmJSONHelper<std::map<std::string, T>, E> cmJSONMapHelper(E success, E fail,
|
||||
F func)
|
||||
{
|
||||
return cmJSONMapFilterHelper<T, E, F>(
|
||||
success, fail, func, [](const std::string&) { return true; });
|
||||
}
|
||||
|
||||
template <typename T, typename E, typename F>
|
||||
cmJSONHelper<cm::optional<T>, E> cmJSONOptionalHelper(E success, F func)
|
||||
{
|
||||
return [success, func](cm::optional<T>& out, const Json::Value* value) -> E {
|
||||
if (!value) {
|
||||
out.reset();
|
||||
return success;
|
||||
}
|
||||
out.emplace();
|
||||
return func(*out, value);
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T, typename E, typename F>
|
||||
cmJSONHelper<T, E> cmJSONRequiredHelper(E fail, F func)
|
||||
{
|
||||
return [fail, func](T& out, const Json::Value* value) -> E {
|
||||
if (!value) {
|
||||
return fail;
|
||||
}
|
||||
return func(out, value);
|
||||
};
|
||||
}
|
||||
@@ -13,6 +13,7 @@ set(CMakeLib_TESTS
|
||||
testCTestResourceGroups.cxx
|
||||
testGccDepfileReader.cxx
|
||||
testGeneratedFileStream.cxx
|
||||
testJSONHelpers.cxx
|
||||
testRST.cxx
|
||||
testRange.cxx
|
||||
testOptional.cxx
|
||||
|
||||
493
Tests/CMakeLib/testJSONHelpers.cxx
Normal file
493
Tests/CMakeLib/testJSONHelpers.cxx
Normal file
@@ -0,0 +1,493 @@
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include <cm3p/json/value.h>
|
||||
|
||||
#include "cmJSONHelpers.h"
|
||||
|
||||
#define ASSERT_TRUE(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
std::cout << "ASSERT_TRUE(" #x ") failed on line " << __LINE__ << "\n"; \
|
||||
return false; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
namespace {
|
||||
struct ObjectStruct
|
||||
{
|
||||
std::string Field1;
|
||||
int Field2;
|
||||
};
|
||||
|
||||
struct InheritedStruct : public ObjectStruct
|
||||
{
|
||||
std::string Field3;
|
||||
};
|
||||
|
||||
enum class ErrorCode
|
||||
{
|
||||
Success,
|
||||
InvalidInt,
|
||||
InvalidBool,
|
||||
InvalidString,
|
||||
InvalidObject,
|
||||
InvalidArray,
|
||||
MissingRequired,
|
||||
};
|
||||
|
||||
auto const IntHelper =
|
||||
cmJSONIntHelper<ErrorCode>(ErrorCode::Success, ErrorCode::InvalidInt, 1);
|
||||
auto const RequiredIntHelper =
|
||||
cmJSONRequiredHelper<int, ErrorCode>(ErrorCode::MissingRequired, IntHelper);
|
||||
auto const UIntHelper =
|
||||
cmJSONUIntHelper<ErrorCode>(ErrorCode::Success, ErrorCode::InvalidInt, 1);
|
||||
auto const BoolHelper = cmJSONBoolHelper<ErrorCode>(
|
||||
ErrorCode::Success, ErrorCode::InvalidBool, false);
|
||||
auto const StringHelper = cmJSONStringHelper<ErrorCode>(
|
||||
ErrorCode::Success, ErrorCode::InvalidString, "default");
|
||||
auto const RequiredStringHelper = cmJSONRequiredHelper<std::string, ErrorCode>(
|
||||
ErrorCode::MissingRequired, StringHelper);
|
||||
auto const StringVectorHelper = cmJSONVectorHelper<std::string, ErrorCode>(
|
||||
ErrorCode::Success, ErrorCode::InvalidArray, StringHelper);
|
||||
auto const StringVectorFilterHelper =
|
||||
cmJSONVectorFilterHelper<std::string, ErrorCode>(
|
||||
ErrorCode::Success, ErrorCode::InvalidArray, StringHelper,
|
||||
[](const std::string& value) { return value != "ignore"; });
|
||||
auto const StringMapHelper = cmJSONMapHelper<std::string, ErrorCode>(
|
||||
ErrorCode::Success, ErrorCode::InvalidObject, StringHelper);
|
||||
auto const StringMapFilterHelper =
|
||||
cmJSONMapFilterHelper<std::string, ErrorCode>(
|
||||
ErrorCode::Success, ErrorCode::InvalidObject, StringHelper,
|
||||
[](const std::string& key) { return key != "ignore"; });
|
||||
auto const OptionalStringHelper =
|
||||
cmJSONOptionalHelper<std::string>(ErrorCode::Success, StringHelper);
|
||||
|
||||
bool testInt()
|
||||
{
|
||||
Json::Value v(2);
|
||||
int i = 0;
|
||||
ASSERT_TRUE(IntHelper(i, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(i == 2);
|
||||
|
||||
i = 0;
|
||||
v = Json::nullValue;
|
||||
ASSERT_TRUE(IntHelper(i, &v) == ErrorCode::InvalidInt);
|
||||
|
||||
i = 0;
|
||||
ASSERT_TRUE(IntHelper(i, nullptr) == ErrorCode::Success);
|
||||
ASSERT_TRUE(i == 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testUInt()
|
||||
{
|
||||
Json::Value v(2);
|
||||
unsigned int i = 0;
|
||||
ASSERT_TRUE(UIntHelper(i, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(i == 2);
|
||||
|
||||
i = 0;
|
||||
v = Json::nullValue;
|
||||
ASSERT_TRUE(UIntHelper(i, &v) == ErrorCode::InvalidInt);
|
||||
|
||||
i = 0;
|
||||
ASSERT_TRUE(UIntHelper(i, nullptr) == ErrorCode::Success);
|
||||
ASSERT_TRUE(i == 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testBool()
|
||||
{
|
||||
Json::Value v(true);
|
||||
bool b = false;
|
||||
ASSERT_TRUE(BoolHelper(b, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(b);
|
||||
|
||||
b = false;
|
||||
v = false;
|
||||
ASSERT_TRUE(BoolHelper(b, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(!b);
|
||||
|
||||
b = false;
|
||||
v = 4;
|
||||
ASSERT_TRUE(BoolHelper(b, &v) == ErrorCode::InvalidBool);
|
||||
|
||||
b = true;
|
||||
ASSERT_TRUE(BoolHelper(b, nullptr) == ErrorCode::Success);
|
||||
ASSERT_TRUE(!b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testString()
|
||||
{
|
||||
Json::Value v("str");
|
||||
std::string str = "";
|
||||
ASSERT_TRUE(StringHelper(str, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(str == "str");
|
||||
|
||||
str = "";
|
||||
v = Json::nullValue;
|
||||
ASSERT_TRUE(StringHelper(str, &v) == ErrorCode::InvalidString);
|
||||
|
||||
str = "";
|
||||
ASSERT_TRUE(StringHelper(str, nullptr) == ErrorCode::Success);
|
||||
ASSERT_TRUE(str == "default");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testObject()
|
||||
{
|
||||
auto const helper = cmJSONObjectHelper<ObjectStruct, ErrorCode>(
|
||||
ErrorCode::Success, ErrorCode::InvalidObject)
|
||||
.Bind("field1"_s, &ObjectStruct::Field1, StringHelper)
|
||||
.Bind("field2"_s, &ObjectStruct::Field2, IntHelper)
|
||||
.Bind<std::string>("field3"_s, nullptr, StringHelper);
|
||||
|
||||
Json::Value v(Json::objectValue);
|
||||
v["field1"] = "Hello";
|
||||
v["field2"] = 2;
|
||||
v["field3"] = "world!";
|
||||
v["extra"] = "extra";
|
||||
|
||||
ObjectStruct s1;
|
||||
ASSERT_TRUE(helper(s1, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(s1.Field1 == "Hello");
|
||||
ASSERT_TRUE(s1.Field2 == 2);
|
||||
|
||||
v["field2"] = "wrong";
|
||||
ObjectStruct s2;
|
||||
ASSERT_TRUE(helper(s2, &v) == ErrorCode::InvalidInt);
|
||||
|
||||
v.removeMember("field2");
|
||||
ObjectStruct s3;
|
||||
ASSERT_TRUE(helper(s3, &v) == ErrorCode::InvalidObject);
|
||||
|
||||
v["field2"] = 2;
|
||||
v["field3"] = 3;
|
||||
ObjectStruct s4;
|
||||
ASSERT_TRUE(helper(s4, &v) == ErrorCode::InvalidString);
|
||||
|
||||
v.removeMember("field3");
|
||||
ObjectStruct s5;
|
||||
ASSERT_TRUE(helper(s5, &v) == ErrorCode::InvalidObject);
|
||||
|
||||
v = "Hello";
|
||||
ObjectStruct s6;
|
||||
ASSERT_TRUE(helper(s6, &v) == ErrorCode::InvalidObject);
|
||||
|
||||
ObjectStruct s7;
|
||||
ASSERT_TRUE(helper(s7, nullptr) == ErrorCode::InvalidObject);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testObjectInherited()
|
||||
{
|
||||
auto const helper =
|
||||
cmJSONObjectHelper<InheritedStruct, ErrorCode>(ErrorCode::Success,
|
||||
ErrorCode::InvalidObject)
|
||||
.Bind("field1"_s, &InheritedStruct::Field1, StringHelper)
|
||||
.Bind("field2"_s, &InheritedStruct::Field2, IntHelper)
|
||||
.Bind("field3"_s, &InheritedStruct::Field3, StringHelper);
|
||||
|
||||
Json::Value v(Json::objectValue);
|
||||
v["field1"] = "Hello";
|
||||
v["field2"] = 2;
|
||||
v["field3"] = "world!";
|
||||
v["extra"] = "extra";
|
||||
|
||||
InheritedStruct s1;
|
||||
ASSERT_TRUE(helper(s1, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(s1.Field1 == "Hello");
|
||||
ASSERT_TRUE(s1.Field2 == 2);
|
||||
ASSERT_TRUE(s1.Field3 == "world!");
|
||||
|
||||
v["field2"] = "wrong";
|
||||
InheritedStruct s2;
|
||||
ASSERT_TRUE(helper(s2, &v) == ErrorCode::InvalidInt);
|
||||
|
||||
v.removeMember("field2");
|
||||
InheritedStruct s3;
|
||||
ASSERT_TRUE(helper(s3, &v) == ErrorCode::InvalidObject);
|
||||
|
||||
v["field2"] = 2;
|
||||
v["field3"] = 3;
|
||||
InheritedStruct s4;
|
||||
ASSERT_TRUE(helper(s4, &v) == ErrorCode::InvalidString);
|
||||
|
||||
v.removeMember("field3");
|
||||
InheritedStruct s5;
|
||||
ASSERT_TRUE(helper(s5, &v) == ErrorCode::InvalidObject);
|
||||
|
||||
v = "Hello";
|
||||
InheritedStruct s6;
|
||||
ASSERT_TRUE(helper(s6, &v) == ErrorCode::InvalidObject);
|
||||
|
||||
InheritedStruct s7;
|
||||
ASSERT_TRUE(helper(s7, nullptr) == ErrorCode::InvalidObject);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testObjectNoExtra()
|
||||
{
|
||||
auto const helper = cmJSONObjectHelper<ObjectStruct, ErrorCode>(
|
||||
ErrorCode::Success, ErrorCode::InvalidObject, false)
|
||||
.Bind("field1"_s, &ObjectStruct::Field1, StringHelper)
|
||||
.Bind("field2"_s, &ObjectStruct::Field2, IntHelper);
|
||||
|
||||
Json::Value v(Json::objectValue);
|
||||
v["field1"] = "Hello";
|
||||
v["field2"] = 2;
|
||||
|
||||
ObjectStruct s1;
|
||||
ASSERT_TRUE(helper(s1, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(s1.Field1 == "Hello");
|
||||
ASSERT_TRUE(s1.Field2 == 2);
|
||||
|
||||
v["extra"] = "world!";
|
||||
ObjectStruct s2;
|
||||
ASSERT_TRUE(helper(s2, &v) == ErrorCode::InvalidObject);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testObjectOptional()
|
||||
{
|
||||
auto const helper =
|
||||
cmJSONObjectHelper<ObjectStruct, ErrorCode>(ErrorCode::Success,
|
||||
ErrorCode::InvalidObject)
|
||||
.Bind("field1"_s, &ObjectStruct::Field1, StringHelper, false)
|
||||
.Bind("field2"_s, &ObjectStruct::Field2, IntHelper, false)
|
||||
.Bind<std::string>("field3_s", nullptr, StringHelper, false);
|
||||
|
||||
Json::Value v(Json::objectValue);
|
||||
v["field1"] = "Hello";
|
||||
v["field2"] = 2;
|
||||
v["field3"] = "world!";
|
||||
v["extra"] = "extra";
|
||||
|
||||
ObjectStruct s1;
|
||||
ASSERT_TRUE(helper(s1, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(s1.Field1 == "Hello");
|
||||
ASSERT_TRUE(s1.Field2 == 2);
|
||||
|
||||
v = Json::objectValue;
|
||||
ObjectStruct s2;
|
||||
ASSERT_TRUE(helper(s2, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(s2.Field1 == "default");
|
||||
ASSERT_TRUE(s2.Field2 == 1);
|
||||
|
||||
ObjectStruct s3;
|
||||
ASSERT_TRUE(helper(s3, nullptr) == ErrorCode::Success);
|
||||
ASSERT_TRUE(s3.Field1 == "default");
|
||||
ASSERT_TRUE(s3.Field2 == 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testVector()
|
||||
{
|
||||
Json::Value v(Json::arrayValue);
|
||||
v.append("Hello");
|
||||
v.append("world!");
|
||||
v.append("ignore");
|
||||
|
||||
std::vector<std::string> l{ "default" };
|
||||
std::vector<std::string> expected{ "Hello", "world!", "ignore" };
|
||||
ASSERT_TRUE(StringVectorHelper(l, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(l == expected);
|
||||
|
||||
v[1] = 2;
|
||||
l = { "default" };
|
||||
ASSERT_TRUE(StringVectorHelper(l, &v) == ErrorCode::InvalidString);
|
||||
|
||||
v = "Hello";
|
||||
l = { "default" };
|
||||
ASSERT_TRUE(StringVectorHelper(l, &v) == ErrorCode::InvalidArray);
|
||||
|
||||
l = { "default" };
|
||||
ASSERT_TRUE(StringVectorHelper(l, nullptr) == ErrorCode::Success);
|
||||
ASSERT_TRUE(l.empty());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testVectorFilter()
|
||||
{
|
||||
Json::Value v(Json::arrayValue);
|
||||
v.append("Hello");
|
||||
v.append("world!");
|
||||
v.append("ignore");
|
||||
|
||||
std::vector<std::string> l{ "default" };
|
||||
std::vector<std::string> expected{
|
||||
"Hello",
|
||||
"world!",
|
||||
};
|
||||
ASSERT_TRUE(StringVectorFilterHelper(l, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(l == expected);
|
||||
|
||||
v[1] = 2;
|
||||
l = { "default" };
|
||||
ASSERT_TRUE(StringVectorFilterHelper(l, &v) == ErrorCode::InvalidString);
|
||||
|
||||
v = "Hello";
|
||||
l = { "default" };
|
||||
ASSERT_TRUE(StringVectorFilterHelper(l, &v) == ErrorCode::InvalidArray);
|
||||
|
||||
l = { "default" };
|
||||
ASSERT_TRUE(StringVectorFilterHelper(l, nullptr) == ErrorCode::Success);
|
||||
ASSERT_TRUE(l.empty());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testMap()
|
||||
{
|
||||
Json::Value v(Json::objectValue);
|
||||
v["field1"] = "Hello";
|
||||
v["field2"] = "world!";
|
||||
v["ignore"] = "ignore";
|
||||
|
||||
std::map<std::string, std::string> m{ { "key", "default" } };
|
||||
std::map<std::string, std::string> expected{ { "field1", "Hello" },
|
||||
{ "field2", "world!" },
|
||||
{ "ignore", "ignore" } };
|
||||
ASSERT_TRUE(StringMapHelper(m, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(m == expected);
|
||||
|
||||
v = Json::arrayValue;
|
||||
m = { { "key", "default" } };
|
||||
ASSERT_TRUE(StringMapHelper(m, &v) == ErrorCode::InvalidObject);
|
||||
|
||||
m = { { "key", "default" } };
|
||||
ASSERT_TRUE(StringMapHelper(m, nullptr) == ErrorCode::Success);
|
||||
ASSERT_TRUE(m.empty());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testMapFilter()
|
||||
{
|
||||
Json::Value v(Json::objectValue);
|
||||
v["field1"] = "Hello";
|
||||
v["field2"] = "world!";
|
||||
v["ignore"] = "ignore";
|
||||
|
||||
std::map<std::string, std::string> m{ { "key", "default" } };
|
||||
std::map<std::string, std::string> expected{ { "field1", "Hello" },
|
||||
{ "field2", "world!" } };
|
||||
ASSERT_TRUE(StringMapFilterHelper(m, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(m == expected);
|
||||
|
||||
v = Json::arrayValue;
|
||||
m = { { "key", "default" } };
|
||||
ASSERT_TRUE(StringMapFilterHelper(m, &v) == ErrorCode::InvalidObject);
|
||||
|
||||
m = { { "key", "default" } };
|
||||
ASSERT_TRUE(StringMapFilterHelper(m, nullptr) == ErrorCode::Success);
|
||||
ASSERT_TRUE(m.empty());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testOptional()
|
||||
{
|
||||
Json::Value v = "Hello";
|
||||
|
||||
cm::optional<std::string> str{ "default" };
|
||||
ASSERT_TRUE(OptionalStringHelper(str, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(str == "Hello");
|
||||
|
||||
str.emplace("default");
|
||||
ASSERT_TRUE(OptionalStringHelper(str, nullptr) == ErrorCode::Success);
|
||||
ASSERT_TRUE(str == cm::nullopt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool testRequired()
|
||||
{
|
||||
Json::Value v = "Hello";
|
||||
|
||||
std::string str = "default";
|
||||
int i = 1;
|
||||
ASSERT_TRUE(RequiredStringHelper(str, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(str == "Hello");
|
||||
ASSERT_TRUE(RequiredIntHelper(i, &v) == ErrorCode::InvalidInt);
|
||||
|
||||
v = 2;
|
||||
str = "default";
|
||||
i = 1;
|
||||
ASSERT_TRUE(RequiredStringHelper(str, &v) == ErrorCode::InvalidString);
|
||||
ASSERT_TRUE(RequiredIntHelper(i, &v) == ErrorCode::Success);
|
||||
ASSERT_TRUE(i == 2);
|
||||
|
||||
str = "default";
|
||||
i = 1;
|
||||
ASSERT_TRUE(RequiredStringHelper(str, nullptr) ==
|
||||
ErrorCode::MissingRequired);
|
||||
ASSERT_TRUE(RequiredIntHelper(i, nullptr) == ErrorCode::MissingRequired);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int testJSONHelpers(int /*unused*/, char* /*unused*/ [])
|
||||
{
|
||||
if (!testInt()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testUInt()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testBool()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testString()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testObject()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testObjectInherited()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testObjectNoExtra()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testObjectOptional()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testVector()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testVectorFilter()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testMap()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testMapFilter()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testOptional()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testRequired()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user