Skip to content

Commit 9f3b2ef

Browse files
committed
CharReader: Add Structured Error
Add getStructuredError to CharReader
1 parent 8190e06 commit 9f3b2ef

File tree

3 files changed

+92
-20
lines changed

3 files changed

+92
-20
lines changed

include/json/reader.h

+26-1
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,12 @@ class JSON_API Reader {
244244
*/
245245
class JSON_API CharReader {
246246
public:
247+
struct JSON_API StructuredError {
248+
ptrdiff_t offset_start;
249+
ptrdiff_t offset_limit;
250+
String message;
251+
};
252+
247253
virtual ~CharReader() = default;
248254
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
249255
* document. The document must be a UTF-8 encoded string containing the
@@ -262,7 +268,12 @@ class JSON_API CharReader {
262268
* error occurred.
263269
*/
264270
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
265-
String* errs) = 0;
271+
String* errs);
272+
273+
/** \brief Returns a vector of structured errors encountered while parsing.
274+
* Each parse call resets the stored list of errors.
275+
*/
276+
std::vector<StructuredError> getStructuredErrors() const;
266277

267278
class JSON_API Factory {
268279
public:
@@ -272,6 +283,20 @@ class JSON_API CharReader {
272283
*/
273284
virtual CharReader* newCharReader() const = 0;
274285
}; // Factory
286+
287+
protected:
288+
class Impl {
289+
public:
290+
virtual ~Impl() = default;
291+
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
292+
String* errs) = 0;
293+
virtual std::vector<StructuredError> getStructuredErrors() const = 0;
294+
};
295+
296+
explicit CharReader(std::unique_ptr<Impl> impl) : _impl(std::move(impl)) { }
297+
298+
private:
299+
std::unique_ptr<Impl> _impl;
275300
}; // CharReader
276301

277302
/** \brief Build a CharReader implementation.

src/lib_json/json_reader.cpp

+37-19
Original file line numberDiff line numberDiff line change
@@ -890,17 +890,12 @@ class OurReader {
890890
public:
891891
using Char = char;
892892
using Location = const Char*;
893-
struct StructuredError {
894-
ptrdiff_t offset_start;
895-
ptrdiff_t offset_limit;
896-
String message;
897-
};
898893

899894
explicit OurReader(OurFeatures const& features);
900895
bool parse(const char* beginDoc, const char* endDoc, Value& root,
901896
bool collectComments = true);
902897
String getFormattedErrorMessages() const;
903-
std::vector<StructuredError> getStructuredErrors() const;
898+
std::vector<CharReader::StructuredError> getStructuredErrors() const;
904899

905900
private:
906901
OurReader(OurReader const&); // no impl
@@ -1860,10 +1855,10 @@ String OurReader::getFormattedErrorMessages() const {
18601855
return formattedMessage;
18611856
}
18621857

1863-
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
1864-
std::vector<OurReader::StructuredError> allErrors;
1858+
std::vector<CharReader::StructuredError> OurReader::getStructuredErrors() const {
1859+
std::vector<CharReader::StructuredError> allErrors;
18651860
for (const auto& error : errors_) {
1866-
OurReader::StructuredError structured;
1861+
CharReader::StructuredError structured;
18671862
structured.offset_start = error.token_.start_ - begin_;
18681863
structured.offset_limit = error.token_.end_ - begin_;
18691864
structured.message = error.message_;
@@ -1873,20 +1868,34 @@ std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
18731868
}
18741869

18751870
class OurCharReader : public CharReader {
1876-
bool const collectComments_;
1877-
OurReader reader_;
18781871

18791872
public:
18801873
OurCharReader(bool collectComments, OurFeatures const& features)
1881-
: collectComments_(collectComments), reader_(features) {}
1882-
bool parse(char const* beginDoc, char const* endDoc, Value* root,
1883-
String* errs) override {
1884-
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1885-
if (errs) {
1886-
*errs = reader_.getFormattedErrorMessages();
1874+
: CharReader(std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}
1875+
1876+
protected:
1877+
class OurImpl : public Impl {
1878+
public:
1879+
OurImpl(bool collectComments, OurFeatures const& features)
1880+
: collectComments_(collectComments), reader_(features) {}
1881+
1882+
bool parse(char const* beginDoc, char const* endDoc, Value* root,
1883+
String* errs) override {
1884+
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1885+
if (errs) {
1886+
*errs = reader_.getFormattedErrorMessages();
1887+
}
1888+
return ok;
18871889
}
1888-
return ok;
1889-
}
1890+
1891+
std::vector<CharReader::StructuredError> getStructuredErrors() const override {
1892+
return reader_.getStructuredErrors();
1893+
}
1894+
1895+
private:
1896+
bool const collectComments_;
1897+
OurReader reader_;
1898+
};
18901899
};
18911900

18921901
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
@@ -1976,6 +1985,15 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
19761985
//! [CharReaderBuilderDefaults]
19771986
}
19781987

1988+
std::vector<CharReader::StructuredError> CharReader::getStructuredErrors() const {
1989+
return _impl->getStructuredErrors();
1990+
}
1991+
1992+
bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root,
1993+
String* errs) {
1994+
return _impl->parse(beginDoc, endDoc, root, errs);
1995+
}
1996+
19791997
//////////////////////////////////
19801998
// global functions
19811999

src/test_lib_json/main.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -3903,6 +3903,35 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) {
39033903
example.size()));
39043904
}
39053905

3906+
struct ParseWithStructuredErrorsTest : JsonTest::TestCase {
3907+
void testErrors(const std::string& doc, bool success,
3908+
const std::vector<Json::CharReader::StructuredError>& expectedErrors) {
3909+
Json::CharReaderBuilder b;
3910+
CharReaderPtr reader(b.newCharReader());
3911+
Json::Value root;
3912+
JSONTEST_ASSERT_EQUAL(
3913+
reader->parse(doc.data(), doc.data() + doc.length(), &root, nullptr),
3914+
success);
3915+
auto actualErrors = reader->getStructuredErrors();
3916+
JSONTEST_ASSERT_EQUAL(expectedErrors.size(), actualErrors.size());
3917+
for (std::size_t i = 0; i < actualErrors.size(); i++) {
3918+
const auto& a = actualErrors[i];
3919+
const auto& e = expectedErrors[i];
3920+
JSONTEST_ASSERT_EQUAL(a.offset_start, e.offset_start);
3921+
JSONTEST_ASSERT_EQUAL(a.offset_limit, e.offset_limit);
3922+
JSONTEST_ASSERT_STRING_EQUAL(a.message, e.message);
3923+
}
3924+
}
3925+
};
3926+
3927+
JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, success) {
3928+
testErrors("{}", true, {});
3929+
}
3930+
3931+
JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, singleError) {
3932+
testErrors("{ 1 : 2 }", false, {{2, 3, "Missing '}' or object member name"}});
3933+
}
3934+
39063935
int main(int argc, const char* argv[]) {
39073936
JsonTest::Runner runner;
39083937

0 commit comments

Comments
 (0)