blob: 0e81fa9423b5fa6c00a97a56502efc1b20939255 [file] [log] [blame]
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestResourceSpec.h"
#include <functional>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include <cmext/string_view>
#include <cm3p/json/value.h>
#include "cmsys/RegularExpression.hxx"
#include "cmJSONHelpers.h"
namespace {
using JSONHelperBuilder = cmJSONHelperBuilder;
const cmsys::RegularExpression IdentifierRegex{ "^[a-z_][a-z0-9_]*$" };
const cmsys::RegularExpression IdRegex{ "^[a-z0-9_]+$" };
struct Version
{
int Major = 1;
int Minor = 0;
};
struct TopVersion
{
struct Version Version;
};
auto const VersionFieldHelper =
JSONHelperBuilder::Int(cmCTestResourceSpecErrors::INVALID_VERSION);
auto const VersionHelper = JSONHelperBuilder::Required<Version>(
cmCTestResourceSpecErrors::NO_VERSION,
JSONHelperBuilder::Object<Version>()
.Bind("major"_s, &Version::Major, VersionFieldHelper)
.Bind("minor"_s, &Version::Minor, VersionFieldHelper));
auto const RootVersionHelper = JSONHelperBuilder::Object<TopVersion>().Bind(
"version"_s, &TopVersion::Version, VersionHelper, false);
bool ResourceIdHelper(std::string& out, const Json::Value* value,
cmJSONState* state)
{
if (!JSONHelperBuilder::String(cmCTestResourceSpecErrors::INVALID_RESOURCE)(
out, value, state)) {
return false;
}
cmsys::RegularExpressionMatch match;
if (!IdRegex.find(out.c_str(), match)) {
cmCTestResourceSpecErrors::INVALID_RESOURCE(value, state);
return false;
}
return true;
}
auto const ResourceHelper =
JSONHelperBuilder::Object<cmCTestResourceSpec::Resource>()
.Bind("id"_s, &cmCTestResourceSpec::Resource::Id, ResourceIdHelper)
.Bind(
"slots"_s, &cmCTestResourceSpec::Resource::Capacity,
JSONHelperBuilder::UInt(cmCTestResourceSpecErrors::INVALID_RESOURCE, 1),
false);
auto const ResourceListHelper =
JSONHelperBuilder::Vector<cmCTestResourceSpec::Resource>(
cmCTestResourceSpecErrors::INVALID_RESOURCE_TYPE, ResourceHelper);
auto const ResourceMapHelper =
JSONHelperBuilder::MapFilter<std::vector<cmCTestResourceSpec::Resource>>(
cmCTestResourceSpecErrors::INVALID_SOCKET_SPEC, ResourceListHelper,
[](const std::string& key) -> bool {
cmsys::RegularExpressionMatch match;
return IdentifierRegex.find(key.c_str(), match);
});
auto const SocketSetHelper = JSONHelperBuilder::Vector<
std::map<std::string, std::vector<cmCTestResourceSpec::Resource>>>(
cmCTestResourceSpecErrors::INVALID_SOCKET_SPEC, ResourceMapHelper);
bool SocketHelper(cmCTestResourceSpec::Socket& out, const Json::Value* value,
cmJSONState* state)
{
std::vector<
std::map<std::string, std::vector<cmCTestResourceSpec::Resource>>>
sockets;
if (!SocketSetHelper(sockets, value, state)) {
return false;
}
if (sockets.size() > 1) {
cmCTestResourceSpecErrors::INVALID_SOCKET_SPEC(value, state);
return false;
}
if (sockets.empty()) {
out.Resources.clear();
} else {
out.Resources = std::move(sockets[0]);
}
return true;
}
auto const LocalRequiredHelper =
JSONHelperBuilder::Required<cmCTestResourceSpec::Socket>(
cmCTestResourceSpecErrors::INVALID_SOCKET_SPEC, SocketHelper);
auto const RootHelper = JSONHelperBuilder::Object<cmCTestResourceSpec>().Bind(
"local", &cmCTestResourceSpec::LocalSocket, LocalRequiredHelper, false);
}
bool cmCTestResourceSpec::ReadFromJSONFile(const std::string& filename)
{
Json::Value root;
this->parseState = cmJSONState(filename, &root);
if (!this->parseState.errors.empty()) {
return false;
}
TopVersion version;
bool result;
if ((result = RootVersionHelper(version, &root, &parseState)) != true) {
return result;
}
if (version.Version.Major != 1 || version.Version.Minor != 0) {
return false;
}
return RootHelper(*this, &root, &parseState);
}
bool cmCTestResourceSpec::operator==(const cmCTestResourceSpec& other) const
{
return this->LocalSocket == other.LocalSocket;
}
bool cmCTestResourceSpec::operator!=(const cmCTestResourceSpec& other) const
{
return !(*this == other);
}
bool cmCTestResourceSpec::Socket::operator==(
const cmCTestResourceSpec::Socket& other) const
{
return this->Resources == other.Resources;
}
bool cmCTestResourceSpec::Socket::operator!=(
const cmCTestResourceSpec::Socket& other) const
{
return !(*this == other);
}
bool cmCTestResourceSpec::Resource::operator==(
const cmCTestResourceSpec::Resource& other) const
{
return this->Id == other.Id && this->Capacity == other.Capacity;
}
bool cmCTestResourceSpec::Resource::operator!=(
const cmCTestResourceSpec::Resource& other) const
{
return !(*this == other);
}