summaryrefslogtreecommitdiff
path: root/Source/CTest/cmCTestResourceSpec.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/CTest/cmCTestResourceSpec.cxx')
-rw-r--r--Source/CTest/cmCTestResourceSpec.cxx198
1 files changed, 198 insertions, 0 deletions
diff --git a/Source/CTest/cmCTestResourceSpec.cxx b/Source/CTest/cmCTestResourceSpec.cxx
new file mode 100644
index 000000000..8f91efb45
--- /dev/null
+++ b/Source/CTest/cmCTestResourceSpec.cxx
@@ -0,0 +1,198 @@
+/* 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 <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmsys/FStream.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cm_jsoncpp_reader.h"
+#include "cm_jsoncpp_value.h"
+
+static const cmsys::RegularExpression IdentifierRegex{ "^[a-z_][a-z0-9_]*$" };
+static const cmsys::RegularExpression IdRegex{ "^[a-z0-9_]+$" };
+
+cmCTestResourceSpec::ReadFileResult cmCTestResourceSpec::ReadFromJSONFile(
+ const std::string& filename)
+{
+ cmsys::ifstream fin(filename.c_str());
+ if (!fin) {
+ return ReadFileResult::FILE_NOT_FOUND;
+ }
+
+ Json::Value root;
+ Json::CharReaderBuilder builder;
+ if (!Json::parseFromStream(builder, fin, &root, nullptr)) {
+ return ReadFileResult::JSON_PARSE_ERROR;
+ }
+
+ if (!root.isObject()) {
+ return ReadFileResult::INVALID_ROOT;
+ }
+
+ int majorVersion = 1;
+ int minorVersion = 0;
+ if (root.isMember("version")) {
+ auto const& version = root["version"];
+ if (version.isObject()) {
+ if (!version.isMember("major") || !version.isMember("minor")) {
+ return ReadFileResult::INVALID_VERSION;
+ }
+ auto const& major = version["major"];
+ auto const& minor = version["minor"];
+ if (!major.isInt() || !minor.isInt()) {
+ return ReadFileResult::INVALID_VERSION;
+ }
+ majorVersion = major.asInt();
+ minorVersion = minor.asInt();
+ } else {
+ return ReadFileResult::INVALID_VERSION;
+ }
+ } else {
+ return ReadFileResult::NO_VERSION;
+ }
+
+ if (majorVersion != 1 || minorVersion != 0) {
+ return ReadFileResult::UNSUPPORTED_VERSION;
+ }
+
+ auto const& local = root["local"];
+ if (!local.isArray()) {
+ return ReadFileResult::INVALID_SOCKET_SPEC;
+ }
+ if (local.size() > 1) {
+ return ReadFileResult::INVALID_SOCKET_SPEC;
+ }
+
+ if (local.empty()) {
+ this->LocalSocket.Resources.clear();
+ return ReadFileResult::READ_OK;
+ }
+
+ auto const& localSocket = local[0];
+ if (!localSocket.isObject()) {
+ return ReadFileResult::INVALID_SOCKET_SPEC;
+ }
+ std::map<std::string, std::vector<cmCTestResourceSpec::Resource>> resources;
+ cmsys::RegularExpressionMatch match;
+ for (auto const& key : localSocket.getMemberNames()) {
+ if (IdentifierRegex.find(key.c_str(), match)) {
+ auto const& value = localSocket[key];
+ auto& r = resources[key];
+ if (value.isArray()) {
+ for (auto const& item : value) {
+ if (item.isObject()) {
+ cmCTestResourceSpec::Resource resource;
+
+ if (!item.isMember("id")) {
+ return ReadFileResult::INVALID_RESOURCE;
+ }
+ auto const& id = item["id"];
+ if (!id.isString()) {
+ return ReadFileResult::INVALID_RESOURCE;
+ }
+ resource.Id = id.asString();
+ if (!IdRegex.find(resource.Id.c_str(), match)) {
+ return ReadFileResult::INVALID_RESOURCE;
+ }
+
+ if (item.isMember("slots")) {
+ auto const& capacity = item["slots"];
+ if (!capacity.isConvertibleTo(Json::uintValue)) {
+ return ReadFileResult::INVALID_RESOURCE;
+ }
+ resource.Capacity = capacity.asUInt();
+ } else {
+ resource.Capacity = 1;
+ }
+
+ r.push_back(resource);
+ } else {
+ return ReadFileResult::INVALID_RESOURCE;
+ }
+ }
+ } else {
+ return ReadFileResult::INVALID_RESOURCE_TYPE;
+ }
+ }
+ }
+
+ this->LocalSocket.Resources = std::move(resources);
+ return ReadFileResult::READ_OK;
+}
+
+const char* cmCTestResourceSpec::ResultToString(ReadFileResult result)
+{
+ switch (result) {
+ case ReadFileResult::READ_OK:
+ return "OK";
+
+ case ReadFileResult::FILE_NOT_FOUND:
+ return "File not found";
+
+ case ReadFileResult::JSON_PARSE_ERROR:
+ return "JSON parse error";
+
+ case ReadFileResult::INVALID_ROOT:
+ return "Invalid root object";
+
+ case ReadFileResult::NO_VERSION:
+ return "No version specified";
+
+ case ReadFileResult::INVALID_VERSION:
+ return "Invalid version object";
+
+ case ReadFileResult::UNSUPPORTED_VERSION:
+ return "Unsupported version";
+
+ case ReadFileResult::INVALID_SOCKET_SPEC:
+ return "Invalid socket object";
+
+ case ReadFileResult::INVALID_RESOURCE_TYPE:
+ return "Invalid resource type object";
+
+ case ReadFileResult::INVALID_RESOURCE:
+ return "Invalid resource object";
+
+ default:
+ return "Unknown";
+ }
+}
+
+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);
+}