summaryrefslogtreecommitdiffstats
path: root/Source/CTest
diff options
context:
space:
mode:
authorMartin Duffy <martin.duffy@kitware.com>2023-03-22 17:11:21 (GMT)
committerBrad King <brad.king@kitware.com>2023-03-29 14:41:19 (GMT)
commit19305afd8a2a46925b1a880de68f7be0ad1f3091 (patch)
treecdef4417cd852c2a5dd85886df4ff61d7fd2e653 /Source/CTest
parent6b08358e17f5b85ad04ab512e4b6e39e989cea35 (diff)
downloadCMake-19305afd8a2a46925b1a880de68f7be0ad1f3091.zip
CMake-19305afd8a2a46925b1a880de68f7be0ad1f3091.tar.gz
CMake-19305afd8a2a46925b1a880de68f7be0ad1f3091.tar.bz2
presets: Improve JSON parser and error messages
Diffstat (limited to 'Source/CTest')
-rw-r--r--Source/CTest/cmCTestResourceSpec.cxx148
-rw-r--r--Source/CTest/cmCTestResourceSpec.h59
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx6
3 files changed, 88 insertions, 125 deletions
diff --git a/Source/CTest/cmCTestResourceSpec.cxx b/Source/CTest/cmCTestResourceSpec.cxx
index 142b07d..0e81fa9 100644
--- a/Source/CTest/cmCTestResourceSpec.cxx
+++ b/Source/CTest/cmCTestResourceSpec.cxx
@@ -10,17 +10,14 @@
#include <cmext/string_view>
-#include <cm3p/json/reader.h>
#include <cm3p/json/value.h>
-#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
#include "cmJSONHelpers.h"
namespace {
-using JSONHelperBuilder =
- cmJSONHelperBuilder<cmCTestResourceSpec::ReadFileResult>;
+using JSONHelperBuilder = cmJSONHelperBuilder;
const cmsys::RegularExpression IdentifierRegex{ "^[a-z_][a-z0-9_]*$" };
const cmsys::RegularExpression IdRegex{ "^[a-z0-9_]+$" };
@@ -36,165 +33,104 @@ struct TopVersion
};
auto const VersionFieldHelper =
- JSONHelperBuilder::Int(cmCTestResourceSpec::ReadFileResult::READ_OK,
- cmCTestResourceSpec::ReadFileResult::INVALID_VERSION);
+ JSONHelperBuilder::Int(cmCTestResourceSpecErrors::INVALID_VERSION);
auto const VersionHelper = JSONHelperBuilder::Required<Version>(
- cmCTestResourceSpec::ReadFileResult::NO_VERSION,
- JSONHelperBuilder::Object<Version>(
- cmCTestResourceSpec::ReadFileResult::READ_OK,
- cmCTestResourceSpec::ReadFileResult::INVALID_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>(
- cmCTestResourceSpec::ReadFileResult::READ_OK,
- cmCTestResourceSpec::ReadFileResult::INVALID_ROOT)
- .Bind("version"_s, &TopVersion::Version, VersionHelper, false);
+auto const RootVersionHelper = JSONHelperBuilder::Object<TopVersion>().Bind(
+ "version"_s, &TopVersion::Version, VersionHelper, false);
-cmCTestResourceSpec::ReadFileResult ResourceIdHelper(std::string& out,
- const Json::Value* value)
+bool ResourceIdHelper(std::string& out, const Json::Value* value,
+ cmJSONState* state)
{
- auto result = JSONHelperBuilder::String(
- cmCTestResourceSpec::ReadFileResult::READ_OK,
- cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE)(out, value);
- if (result != cmCTestResourceSpec::ReadFileResult::READ_OK) {
- return result;
+ if (!JSONHelperBuilder::String(cmCTestResourceSpecErrors::INVALID_RESOURCE)(
+ out, value, state)) {
+ return false;
}
cmsys::RegularExpressionMatch match;
if (!IdRegex.find(out.c_str(), match)) {
- return cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE;
+ cmCTestResourceSpecErrors::INVALID_RESOURCE(value, state);
+ return false;
}
- return cmCTestResourceSpec::ReadFileResult::READ_OK;
+ return true;
}
auto const ResourceHelper =
- JSONHelperBuilder::Object<cmCTestResourceSpec::Resource>(
- cmCTestResourceSpec::ReadFileResult::READ_OK,
- cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE)
+ JSONHelperBuilder::Object<cmCTestResourceSpec::Resource>()
.Bind("id"_s, &cmCTestResourceSpec::Resource::Id, ResourceIdHelper)
- .Bind("slots"_s, &cmCTestResourceSpec::Resource::Capacity,
- JSONHelperBuilder::UInt(
- cmCTestResourceSpec::ReadFileResult::READ_OK,
- cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE, 1),
- false);
+ .Bind(
+ "slots"_s, &cmCTestResourceSpec::Resource::Capacity,
+ JSONHelperBuilder::UInt(cmCTestResourceSpecErrors::INVALID_RESOURCE, 1),
+ false);
auto const ResourceListHelper =
JSONHelperBuilder::Vector<cmCTestResourceSpec::Resource>(
- cmCTestResourceSpec::ReadFileResult::READ_OK,
- cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE_TYPE,
- ResourceHelper);
+ cmCTestResourceSpecErrors::INVALID_RESOURCE_TYPE, ResourceHelper);
auto const ResourceMapHelper =
JSONHelperBuilder::MapFilter<std::vector<cmCTestResourceSpec::Resource>>(
- cmCTestResourceSpec::ReadFileResult::READ_OK,
- cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC,
- ResourceListHelper, [](const std::string& key) -> bool {
+ 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>>>(
- cmCTestResourceSpec::ReadFileResult::READ_OK,
- cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC, ResourceMapHelper);
+ cmCTestResourceSpecErrors::INVALID_SOCKET_SPEC, ResourceMapHelper);
-cmCTestResourceSpec::ReadFileResult SocketHelper(
- cmCTestResourceSpec::Socket& out, const Json::Value* value)
+bool SocketHelper(cmCTestResourceSpec::Socket& out, const Json::Value* value,
+ cmJSONState* state)
{
std::vector<
std::map<std::string, std::vector<cmCTestResourceSpec::Resource>>>
sockets;
- cmCTestResourceSpec::ReadFileResult result = SocketSetHelper(sockets, value);
- if (result != cmCTestResourceSpec::ReadFileResult::READ_OK) {
- return result;
+ if (!SocketSetHelper(sockets, value, state)) {
+ return false;
}
if (sockets.size() > 1) {
- return cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC;
+ cmCTestResourceSpecErrors::INVALID_SOCKET_SPEC(value, state);
+ return false;
}
if (sockets.empty()) {
out.Resources.clear();
} else {
out.Resources = std::move(sockets[0]);
}
- return cmCTestResourceSpec::ReadFileResult::READ_OK;
+ return true;
}
auto const LocalRequiredHelper =
JSONHelperBuilder::Required<cmCTestResourceSpec::Socket>(
- cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC, SocketHelper);
+ cmCTestResourceSpecErrors::INVALID_SOCKET_SPEC, SocketHelper);
-auto const RootHelper = JSONHelperBuilder::Object<cmCTestResourceSpec>(
- cmCTestResourceSpec::ReadFileResult::READ_OK,
- cmCTestResourceSpec::ReadFileResult::INVALID_ROOT)
- .Bind("local", &cmCTestResourceSpec::LocalSocket,
- LocalRequiredHelper, false);
+auto const RootHelper = JSONHelperBuilder::Object<cmCTestResourceSpec>().Bind(
+ "local", &cmCTestResourceSpec::LocalSocket, LocalRequiredHelper, false);
}
-cmCTestResourceSpec::ReadFileResult cmCTestResourceSpec::ReadFromJSONFile(
- const std::string& filename)
+bool 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;
+
+ this->parseState = cmJSONState(filename, &root);
+ if (!this->parseState.errors.empty()) {
+ return false;
}
TopVersion version;
- ReadFileResult result;
- if ((result = RootVersionHelper(version, &root)) !=
- ReadFileResult::READ_OK) {
+ bool result;
+ if ((result = RootVersionHelper(version, &root, &parseState)) != true) {
return result;
}
if (version.Version.Major != 1 || version.Version.Minor != 0) {
- return ReadFileResult::UNSUPPORTED_VERSION;
+ return false;
}
- return RootHelper(*this, &root);
-}
-
-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";
- }
+ return RootHelper(*this, &root, &parseState);
}
bool cmCTestResourceSpec::operator==(const cmCTestResourceSpec& other) const
diff --git a/Source/CTest/cmCTestResourceSpec.h b/Source/CTest/cmCTestResourceSpec.h
index 72628a3..37ccd72 100644
--- a/Source/CTest/cmCTestResourceSpec.h
+++ b/Source/CTest/cmCTestResourceSpec.h
@@ -8,6 +8,12 @@
#include <string>
#include <vector>
+#include "cmJSONState.h"
+
+namespace Json {
+class Value;
+}
+
class cmCTestResourceSpec
{
public:
@@ -31,24 +37,45 @@ public:
};
Socket LocalSocket;
+ cmJSONState parseState;
- enum class ReadFileResult
- {
- READ_OK,
- FILE_NOT_FOUND,
- JSON_PARSE_ERROR,
- INVALID_ROOT,
- NO_VERSION,
- INVALID_VERSION,
- UNSUPPORTED_VERSION,
- INVALID_SOCKET_SPEC, // Can't be INVALID_SOCKET due to a Windows macro
- INVALID_RESOURCE_TYPE,
- INVALID_RESOURCE,
- };
-
- ReadFileResult ReadFromJSONFile(const std::string& filename);
- static const char* ResultToString(ReadFileResult result);
+ bool ReadFromJSONFile(const std::string& filename);
bool operator==(const cmCTestResourceSpec& other) const;
bool operator!=(const cmCTestResourceSpec& other) const;
};
+
+namespace cmCTestResourceSpecErrors {
+const auto FILE_NOT_FOUND = [](const Json::Value*, cmJSONState* state) {
+ state->AddError("File not found");
+};
+const auto JSON_PARSE_ERROR = [](const Json::Value* value,
+ cmJSONState* state) {
+ state->AddErrorAtValue("JSON parse error", value);
+};
+const auto INVALID_ROOT = [](const Json::Value* value, cmJSONState* state) {
+ state->AddErrorAtValue("Invalid root object", value);
+};
+const auto NO_VERSION = [](const Json::Value* value, cmJSONState* state) {
+ state->AddErrorAtValue("No version specified", value);
+};
+const auto INVALID_VERSION = [](const Json::Value* value, cmJSONState* state) {
+ state->AddErrorAtValue("Invalid version object", value);
+};
+const auto UNSUPPORTED_VERSION = [](const Json::Value* value,
+ cmJSONState* state) {
+ state->AddErrorAtValue("Unsupported version", value);
+};
+const auto INVALID_SOCKET_SPEC = [](const Json::Value* value,
+ cmJSONState* state) {
+ state->AddErrorAtValue("Invalid socket object", value);
+};
+const auto INVALID_RESOURCE_TYPE = [](const Json::Value* value,
+ cmJSONState* state) {
+ state->AddErrorAtValue("Invalid resource type object", value);
+};
+const auto INVALID_RESOURCE = [](const Json::Value* value,
+ cmJSONState* state) {
+ state->AddErrorAtValue("Invalid resource object", value);
+};
+}
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 1d509cf..f693ace 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -37,6 +37,7 @@
#include "cmExecutionStatus.h"
#include "cmGeneratedFileStream.h"
#include "cmGlobalGenerator.h"
+#include "cmJSONState.h"
#include "cmMakefile.h"
#include "cmState.h"
#include "cmStateSnapshot.h"
@@ -1346,12 +1347,11 @@ bool cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed,
}
if (!this->ResourceSpecFile.empty()) {
this->UseResourceSpec = true;
- auto result = this->ResourceSpec.ReadFromJSONFile(this->ResourceSpecFile);
- if (result != cmCTestResourceSpec::ReadFileResult::READ_OK) {
+ if (!this->ResourceSpec.ReadFromJSONFile(this->ResourceSpecFile)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Could not read/parse resource spec file "
<< this->ResourceSpecFile << ": "
- << cmCTestResourceSpec::ResultToString(result)
+ << this->ResourceSpec.parseState.GetErrorMessage()
<< std::endl);
return false;
}