diff options
author | Martin Duffy <martin.duffy@kitware.com> | 2023-03-22 17:11:21 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2023-03-29 14:41:19 (GMT) |
commit | 19305afd8a2a46925b1a880de68f7be0ad1f3091 (patch) | |
tree | cdef4417cd852c2a5dd85886df4ff61d7fd2e653 /Source/CTest | |
parent | 6b08358e17f5b85ad04ab512e4b6e39e989cea35 (diff) | |
download | CMake-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.cxx | 148 | ||||
-rw-r--r-- | Source/CTest/cmCTestResourceSpec.h | 59 | ||||
-rw-r--r-- | Source/CTest/cmCTestTestHandler.cxx | 6 |
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; } |