mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2024-12-13 10:22:55 +01:00
CharReader: Add StructuredError (#1409)
* CharReader: Add Structured Error Add getStructuredError to CharReader * run clang format --------- Co-authored-by: Jordan Bayles <bayles.jordan@gmail.com> Co-authored-by: Jordan Bayles <jophba@chromium.org>
This commit is contained in:
parent
c857395951
commit
c04c0c2131
@ -244,6 +244,12 @@ private:
|
|||||||
*/
|
*/
|
||||||
class JSON_API CharReader {
|
class JSON_API CharReader {
|
||||||
public:
|
public:
|
||||||
|
struct JSON_API StructuredError {
|
||||||
|
ptrdiff_t offset_start;
|
||||||
|
ptrdiff_t offset_limit;
|
||||||
|
String message;
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~CharReader() = default;
|
virtual ~CharReader() = default;
|
||||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||||
* document. The document must be a UTF-8 encoded string containing the
|
* document. The document must be a UTF-8 encoded string containing the
|
||||||
@ -262,7 +268,12 @@ public:
|
|||||||
* error occurred.
|
* error occurred.
|
||||||
*/
|
*/
|
||||||
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||||
String* errs) = 0;
|
String* errs);
|
||||||
|
|
||||||
|
/** \brief Returns a vector of structured errors encountered while parsing.
|
||||||
|
* Each parse call resets the stored list of errors.
|
||||||
|
*/
|
||||||
|
std::vector<StructuredError> getStructuredErrors() const;
|
||||||
|
|
||||||
class JSON_API Factory {
|
class JSON_API Factory {
|
||||||
public:
|
public:
|
||||||
@ -272,6 +283,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual CharReader* newCharReader() const = 0;
|
virtual CharReader* newCharReader() const = 0;
|
||||||
}; // Factory
|
}; // Factory
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class Impl {
|
||||||
|
public:
|
||||||
|
virtual ~Impl() = default;
|
||||||
|
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||||
|
String* errs) = 0;
|
||||||
|
virtual std::vector<StructuredError> getStructuredErrors() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit CharReader(std::unique_ptr<Impl> impl) : _impl(std::move(impl)) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Impl> _impl;
|
||||||
}; // CharReader
|
}; // CharReader
|
||||||
|
|
||||||
/** \brief Build a CharReader implementation.
|
/** \brief Build a CharReader implementation.
|
||||||
|
@ -878,17 +878,12 @@ class OurReader {
|
|||||||
public:
|
public:
|
||||||
using Char = char;
|
using Char = char;
|
||||||
using Location = const Char*;
|
using Location = const Char*;
|
||||||
struct StructuredError {
|
|
||||||
ptrdiff_t offset_start;
|
|
||||||
ptrdiff_t offset_limit;
|
|
||||||
String message;
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit OurReader(OurFeatures const& features);
|
explicit OurReader(OurFeatures const& features);
|
||||||
bool parse(const char* beginDoc, const char* endDoc, Value& root,
|
bool parse(const char* beginDoc, const char* endDoc, Value& root,
|
||||||
bool collectComments = true);
|
bool collectComments = true);
|
||||||
String getFormattedErrorMessages() const;
|
String getFormattedErrorMessages() const;
|
||||||
std::vector<StructuredError> getStructuredErrors() const;
|
std::vector<CharReader::StructuredError> getStructuredErrors() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OurReader(OurReader const&); // no impl
|
OurReader(OurReader const&); // no impl
|
||||||
@ -1836,10 +1831,11 @@ String OurReader::getFormattedErrorMessages() const {
|
|||||||
return formattedMessage;
|
return formattedMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
|
std::vector<CharReader::StructuredError>
|
||||||
std::vector<OurReader::StructuredError> allErrors;
|
OurReader::getStructuredErrors() const {
|
||||||
|
std::vector<CharReader::StructuredError> allErrors;
|
||||||
for (const auto& error : errors_) {
|
for (const auto& error : errors_) {
|
||||||
OurReader::StructuredError structured;
|
CharReader::StructuredError structured;
|
||||||
structured.offset_start = error.token_.start_ - begin_;
|
structured.offset_start = error.token_.start_ - begin_;
|
||||||
structured.offset_limit = error.token_.end_ - begin_;
|
structured.offset_limit = error.token_.end_ - begin_;
|
||||||
structured.message = error.message_;
|
structured.message = error.message_;
|
||||||
@ -1849,20 +1845,36 @@ std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class OurCharReader : public CharReader {
|
class OurCharReader : public CharReader {
|
||||||
bool const collectComments_;
|
|
||||||
OurReader reader_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OurCharReader(bool collectComments, OurFeatures const& features)
|
OurCharReader(bool collectComments, OurFeatures const& features)
|
||||||
: collectComments_(collectComments), reader_(features) {}
|
: CharReader(
|
||||||
bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}
|
||||||
String* errs) override {
|
|
||||||
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
|
protected:
|
||||||
if (errs) {
|
class OurImpl : public Impl {
|
||||||
*errs = reader_.getFormattedErrorMessages();
|
public:
|
||||||
|
OurImpl(bool collectComments, OurFeatures const& features)
|
||||||
|
: collectComments_(collectComments), reader_(features) {}
|
||||||
|
|
||||||
|
bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||||
|
String* errs) override {
|
||||||
|
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
|
||||||
|
if (errs) {
|
||||||
|
*errs = reader_.getFormattedErrorMessages();
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
return ok;
|
|
||||||
}
|
std::vector<CharReader::StructuredError>
|
||||||
|
getStructuredErrors() const override {
|
||||||
|
return reader_.getStructuredErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool const collectComments_;
|
||||||
|
OurReader reader_;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
|
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
|
||||||
@ -1952,6 +1964,16 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
|
|||||||
//! [CharReaderBuilderDefaults]
|
//! [CharReaderBuilderDefaults]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<CharReader::StructuredError>
|
||||||
|
CharReader::getStructuredErrors() const {
|
||||||
|
return _impl->getStructuredErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||||
|
String* errs) {
|
||||||
|
return _impl->parse(beginDoc, endDoc, root, errs);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
// global functions
|
// global functions
|
||||||
|
|
||||||
|
@ -3917,6 +3917,36 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) {
|
|||||||
example.size()));
|
example.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ParseWithStructuredErrorsTest : JsonTest::TestCase {
|
||||||
|
void testErrors(
|
||||||
|
const std::string& doc, bool success,
|
||||||
|
const std::vector<Json::CharReader::StructuredError>& expectedErrors) {
|
||||||
|
Json::CharReaderBuilder b;
|
||||||
|
CharReaderPtr reader(b.newCharReader());
|
||||||
|
Json::Value root;
|
||||||
|
JSONTEST_ASSERT_EQUAL(
|
||||||
|
reader->parse(doc.data(), doc.data() + doc.length(), &root, nullptr),
|
||||||
|
success);
|
||||||
|
auto actualErrors = reader->getStructuredErrors();
|
||||||
|
JSONTEST_ASSERT_EQUAL(expectedErrors.size(), actualErrors.size());
|
||||||
|
for (std::size_t i = 0; i < actualErrors.size(); i++) {
|
||||||
|
const auto& a = actualErrors[i];
|
||||||
|
const auto& e = expectedErrors[i];
|
||||||
|
JSONTEST_ASSERT_EQUAL(a.offset_start, e.offset_start);
|
||||||
|
JSONTEST_ASSERT_EQUAL(a.offset_limit, e.offset_limit);
|
||||||
|
JSONTEST_ASSERT_STRING_EQUAL(a.message, e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, success) {
|
||||||
|
testErrors("{}", true, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, singleError) {
|
||||||
|
testErrors("{ 1 : 2 }", false, {{2, 3, "Missing '}' or object member name"}});
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
JsonTest::Runner runner;
|
JsonTest::Runner runner;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user