diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-05-31 01:15:44 +0100 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2015-05-31 01:15:44 +0100 |
commit | 78faf65a4b0cea4e245d897a955b4336d14bebf1 (patch) | |
tree | 82f523697ba67b6fcc1fcaf39fd6db2eee41f4f2 | |
parent | Switch to run rule, intead of test (diff) | |
download | libjsonpp-0.9.tar.bz2 libjsonpp-0.9.tar.xz libjsonpp-0.9.zip |
Switch to using a flex based parser, not a hand-rolled character consumerlibjsonpp-0.9
-rw-r--r-- | libjsonpp/Jamfile.jam | 4 | ||||
-rw-r--r-- | libjsonpp/json.ll | 153 | ||||
-rw-r--r-- | libjsonpp/jsonFlexLexer.cpp | 102 | ||||
-rw-r--r-- | libjsonpp/jsonFlexLexer.h | 44 | ||||
-rw-r--r-- | libjsonpp/jsonpp.h | 10 | ||||
-rw-r--r-- | libjsonpp/parse.cpp | 240 | ||||
-rw-r--r-- | libjsonpp/pch.hpp | 4 | ||||
-rw-r--r-- | libjsonpp/test1.cpp | 139 |
8 files changed, 437 insertions, 259 deletions
diff --git a/libjsonpp/Jamfile.jam b/libjsonpp/Jamfile.jam index ce6a1f7..2983e68 100644 --- a/libjsonpp/Jamfile.jam +++ b/libjsonpp/Jamfile.jam @@ -1,5 +1,6 @@ import package ; import testing ; +import lex ; alias glibmm : : : : <cflags>"`pkg-config --cflags glibmm-2.4`" @@ -15,10 +16,11 @@ cpp-pch pch : pch.hpp : <library>glibmm ; lib jsonpp : - pch [ glob *.cpp : test*.cpp ] + pch [ glob *.cpp *.ll : test*.cpp ] : <include>. <library>glibmm + <cflags>-Wno-error=sign-compare : : <include>. ; diff --git a/libjsonpp/json.ll b/libjsonpp/json.ll new file mode 100644 index 0000000..94be11f --- /dev/null +++ b/libjsonpp/json.ll @@ -0,0 +1,153 @@ +%option batch +%option c++ +%option noyywrap +%option 8bit +%option stack +%option yylineno +%option yyclass="json::jsonFlexLexer" + +%{ +#include "jsonFlexLexer.h" +#include <boost/lexical_cast.hpp> +#include <boost/bind.hpp> +%} + +beginobj "{" +endobj "}" +beginarray "[" +endarray "]" +beginstr "\"" +endstr "\"" +true "true" +false "false" +bool {true|false} +null "null" +number [-+]?[0-9]+(\.[0-9]+)? +colon ":" +separator "," +escape "\\" + +%x OBJECT_ITEM +%x OBJECT_NEXT +%x ARRAY_ITEM +%x ARRAY_NEXT +%x COLON +%x TEXT +%x VALUE +%x STRING +%x ESCAPE + +%% + +<ARRAY_ITEM,VALUE>{true} { + PushBoolean(true); + yy_pop_state(); +} + +<ARRAY_ITEM,VALUE>{false} { + PushBoolean(false); + yy_pop_state(); +} + +<ARRAY_ITEM,VALUE>{number} { + PushNumber(boost::lexical_cast<double>(YYText())); + yy_pop_state(); +} + +<ARRAY_ITEM,VALUE>{null} { + PushNull(); + yy_pop_state(); +} + +<ARRAY_ITEM,VALUE,OBJECT_ITEM>{beginstr} { + yy_push_state(STRING); +} + +<ARRAY_ITEM,VALUE>{beginobj} { + BeginObject(); + BEGIN(OBJECT_ITEM); +} + +<ARRAY_ITEM,VALUE>{beginarray} { + BeginArray(); + BEGIN(ARRAY_NEXT); + yy_push_state(ARRAY_ITEM); +} + +<STRING>{endstr} { + yy_pop_state(); + switch (YY_START) { + case ARRAY_ITEM: + case VALUE: + PushText(encodeBuf()); + yy_pop_state(); + break; + case OBJECT_ITEM: + name = encodeBuf(); + BEGIN(COLON); + break; + } + buf.clear(); +} + +<OBJECT_NEXT>{endobj} { + PushObject(); + yy_pop_state(); +} + +<ARRAY_ITEM,ARRAY_NEXT>{endarray} { + PushArray(); + yy_pop_state(); +} + +<COLON>{colon} { + BEGIN(OBJECT_NEXT); + yy_push_state(VALUE); +} + +<OBJECT_NEXT>{separator} { + BEGIN(OBJECT_ITEM); +} + +<ARRAY_NEXT>{separator} { + yy_push_state(VALUE); +} + +<STRING>{escape} { + yy_push_state(ESCAPE); +} + +<ESCAPE>"\"" { buf += "\""; yy_pop_state(); } +<ESCAPE>"\\" { buf += "\\"; yy_pop_state(); } +<ESCAPE>"/" { buf += "/"; yy_pop_state(); } +<ESCAPE>"b" { buf += "\b"; yy_pop_state(); } +<ESCAPE>"f" { buf += "\f"; yy_pop_state(); } +<ESCAPE>"n" { buf += "\n"; yy_pop_state(); } +<ESCAPE>"r" { buf += "\r"; yy_pop_state(); } +<ESCAPE>"t" { buf += "\t"; yy_pop_state(); } + +<ESCAPE>"u"[0-9a-fA-Z]{4} { + buf += Glib::ustring(1, gunichar(strtol(YYText() + 1, NULL, 16))); + yy_pop_state(); +} + +<STRING>. { + buf += YYText(); +} + +<*>[ \t\r\n\f] { +} + +<*>. { + throw ParseError(YYText(), yylineno, YY_START); +} + +%% + +json::jsonFlexLexer::jsonFlexLexer(std::istream & in, const std::string &) : + yyFlexLexer(&in, NULL) +{ + yy_push_state(VALUE); + acceptValues.push(boost::bind(&jsonFlexLexer::RootValue, this, _1)); +} + diff --git a/libjsonpp/jsonFlexLexer.cpp b/libjsonpp/jsonFlexLexer.cpp new file mode 100644 index 0000000..ec924c4 --- /dev/null +++ b/libjsonpp/jsonFlexLexer.cpp @@ -0,0 +1,102 @@ +#include <FlexLexer.h> +#include "jsonFlexLexer.h" +#include <boost/bind.hpp> +#include <glibmm/convert.h> + +namespace json { + ValuePtr + jsonFlexLexer::getValue() const + { + return values.top(); + } + + Value * + jsonFlexLexer::RootValue(const Value & value) + { + auto v = ValuePtr(new Value(value)); + values.push(v); + return v.get(); + } + + Value * + jsonFlexLexer::ArrayAppend(Array * array, const Value & value) + { + auto v = ValuePtr(new Value(value)); + array->push_back(v); + return v.get(); + } + + Value * + jsonFlexLexer::ObjectMember(Object * object, const Value & value) + { + auto v = ValuePtr(new Value(value)); + (*object)[name] = v; + return v.get(); + } + + std::string + jsonFlexLexer::encodeBuf() const + { + if (!encoding.empty()) { + return Glib::convert(buf, "utf-8", encoding); + } + return buf; + } + + void + jsonFlexLexer::BeginObject() + { + auto object = boost::get<Object>(acceptValues.top()(Object())); + acceptValues.push(boost::bind(&jsonFlexLexer::ObjectMember, this, object, _1)); + } + + void + jsonFlexLexer::BeginArray() + { + auto array = boost::get<Array>(acceptValues.top()(Array())); + acceptValues.push(boost::bind(&jsonFlexLexer::ArrayAppend, this, array, _1)); + } + + void + jsonFlexLexer::PushNull() + { + acceptValues.top()(Null()); + } + + void + jsonFlexLexer::PushBoolean(bool value) + { + acceptValues.top()(value); + } + + void + jsonFlexLexer::PushNumber(double value) + { + acceptValues.top()(value); + } + + void + jsonFlexLexer::PushText(const std::string & value) + { + acceptValues.top()(value); + } + + void + jsonFlexLexer::PushArray() + { + acceptValues.pop(); + } + + void + jsonFlexLexer::PushObject() + { + acceptValues.pop(); + } + + void + jsonFlexLexer::LexerError(const char * msg) + { + throw ParseError(msg, 0, 0); + } +} + diff --git a/libjsonpp/jsonFlexLexer.h b/libjsonpp/jsonFlexLexer.h new file mode 100644 index 0000000..e3be204 --- /dev/null +++ b/libjsonpp/jsonFlexLexer.h @@ -0,0 +1,44 @@ +#ifndef JSONFLEXLEXER_H +#define JSONFLEXLEXER_H + +#include <string> +#include "jsonpp.h" +#include <stack> +#include <boost/function.hpp> + +namespace json { + class jsonFlexLexer : public yyFlexLexer { + public: + jsonFlexLexer(std::istream &, const std::string & enc); + + int yylex(); + ValuePtr getValue() const; + void LexerError(const char * msg) override; + + void BeginObject(); + void BeginArray(); + + void PushBoolean(bool); + void PushNumber(double); + void PushNull(); + void PushText(const std::string &); + void PushArray(); + void PushObject(); + + private: + Value * RootValue(const Value &); + Value * ArrayAppend(Array *, const Value &); + Value * ObjectMember(Object *, const Value &); + + std::string encodeBuf() const; + + std::string buf, name, encoding; + std::stack<ValuePtr> values; + + typedef boost::function<Value *(const Value &)> AcceptValue; + std::stack<AcceptValue> acceptValues; + }; +} + +#endif + diff --git a/libjsonpp/jsonpp.h b/libjsonpp/jsonpp.h index a872fd9..f105bea 100644 --- a/libjsonpp/jsonpp.h +++ b/libjsonpp/jsonpp.h @@ -11,7 +11,7 @@ namespace json { class ParseError : public std::invalid_argument { public: - ParseError(gunichar); + ParseError(const char *, int, int); }; typedef Glib::ustring String; @@ -33,12 +33,10 @@ namespace json { Object parseObject(Glib::ustring::const_iterator &); Object parseObject(const Glib::ustring &); - String parseString(Glib::ustring::const_iterator & s); - Number parseNumber(Glib::ustring::const_iterator & s); - Boolean parseBoolean(Glib::ustring::const_iterator & s); - Null parseNull(Glib::ustring::const_iterator & s); + Value parseValue(std::istream &); + Value parseValue(std::istream &, const std::string & encoding); + Value parseValue(const Glib::ustring & s); Value parseValue(Glib::ustring::const_iterator & s); - Array parseArray(Glib::ustring::const_iterator &); void serializeObject(const Object &, std::ostream & s, const std::string & encoding); void serializeValue(const Value &, std::ostream & s, const std::string & encoding); diff --git a/libjsonpp/parse.cpp b/libjsonpp/parse.cpp index f127e9d..d74d8f0 100644 --- a/libjsonpp/parse.cpp +++ b/libjsonpp/parse.cpp @@ -1,229 +1,37 @@ #include <pch.hpp> #include "jsonpp.h" +#include <FlexLexer.h> +#include "jsonFlexLexer.h" namespace json { - ParseError::ParseError(gunichar c) : - std::invalid_argument(Glib::ustring("Parse error at or near ") + Glib::ustring(1, c)) + ParseError::ParseError(const char * at, int l, int s) : + std::invalid_argument(Glib::ustring::compose("Parse error at or near %1 (line %2, state %3)", at, l, s)) { } - String parseString(Glib::ustring::const_iterator & s) { - while (Glib::Unicode::isspace(*s)) s++; - if (*s++ != '"') throw ParseError(*--s); - String str; - while (*s != '"') { - if (*s == '\\') { - ++s; - switch (*s) { - case '"': - str += '"'; - break; - case '\\': - str += '\\'; - break; - case '/': - str += '/'; - break; - case 'b': - str += gunichar(8); - break; - case 'f': - str += gunichar(12); - break; - case 'n': - str += gunichar(10); - break; - case 'r': - str += gunichar(13); - break; - case 't': - str += gunichar(9); - break; - case 'u': - { - unsigned int c = 0; - for (int n = 0; n < 4; n += 1) { - c *= 16; - if (*s >= '0' && *s <= '9') { - c += (*s - '0'); - } - else if (*s >= 'a' && *s <= 'f') { - c += (*s - 'a'); - } - else if (*s >= 'A' && *s <= 'F') { - c += (*s - 'A'); - } - else { - throw ParseError(*s); - } - s++; - } - str += gunichar(c); - s--; - } - break; - default: - throw ParseError(*s); - } - } - else { - str += *s; - } - s++; - } - if (*s++ != '"') throw ParseError(*--s); - return str; + + Value parseValue(std::istream & s) { + return parseValue(s, std::string()); } - Number parseNumber(Glib::ustring::const_iterator & s) { - while (Glib::Unicode::isspace(*s)) s++; - bool neg = false; - double v = 0; - if (*s == '-') { - neg = true; - s++; - } - bool dot = false, e = false; - double frac = 1; - unsigned int digits = 0; - while (true) { - if (Glib::Unicode::isdigit(*s)) { - if (dot) { - frac /= 10; - v += (frac * (*s - '0')); - } - else { - v *= 10; - v += (*s - '0'); - digits += 1; - } - } - else if (*s == '.') { - if (dot || e) throw ParseError(*s); - dot = true; - } - else if (*s == 'e' || *s == 'E') { - e = true; - s++; - bool eneg = false; - if (*s == '+') { - } - else if (*s == '-') { - eneg = true; - s++; - } - int ev = 0; - while (Glib::Unicode::isdigit(*s)) { - ev *= 10; - ev += (*s - '0'); - s++; - } - while (ev--) { - if (eneg) { - v /= 10; - } - else { - v *= 10; - } - } - break; - } - else { - break; - } - s++; - } - if (digits < 1) throw ParseError(*s); - return neg ? -v : v; + + Value parseValue(std::istream & s, const std::string & enc) { + jsonFlexLexer jfl(s, enc); + while (jfl.yylex()) ; + return *jfl.getValue(); } - Value parseValue(Glib::ustring::const_iterator & s) { - while (Glib::Unicode::isspace(*s)) s++; - switch (*s) { - case '"': - return parseString(s); - case '{': - return parseObject(s); - case '[': - return parseArray(s); - case 'n': - return parseNull(s); - case 't': - case 'f': - return parseBoolean(s); - default: - return parseNumber(s); - } + + Value parseValue(const Glib::ustring & s) { + std::stringstream stream(s); + return parseValue(stream); } + Object parseObject(const Glib::ustring & s) { - Glib::ustring::const_iterator i = s.begin(); - Object o = parseObject(i); - if (i != s.end()) throw ParseError(*i); - return o; - } - Object parseObject(Glib::ustring::const_iterator & s) { - Object o; - while (Glib::Unicode::isspace(*s)) s++; - if (*s != '{') throw ParseError(*s); - do { - s++; - while (Glib::Unicode::isspace(*s)) s++; - if (*s == '}') return o; - String key = parseString(s); - while (Glib::Unicode::isspace(*s)) s++; - if (*s++ != ':') throw ParseError(*--s); - if (!o.insert(Object::value_type(key, ValuePtr(new Value(parseValue(s))))).second) throw ParseError(*s); - while (Glib::Unicode::isspace(*s)) s++; - } while (*s == ','); - if (*s == '}') { - s++; - while (Glib::Unicode::isspace(*s)) s++; - return o; - } - throw ParseError(*s); + return boost::get<Object>(parseValue(s)); } - Array parseArray(Glib::ustring::const_iterator & s) { - Array a; - while (Glib::Unicode::isspace(*s)) s++; - if (*s != '[') throw ParseError(*s); - do { - s++; - while (Glib::Unicode::isspace(*s)) s++; - if (*s == ']') { - s++; - return a; - } - a.push_back(ValuePtr(new Value(parseValue(s)))); - while (Glib::Unicode::isspace(*s)) s++; - } while (*s == ','); - if (*s == ']') { - s++; - return a; - } - throw ParseError(*s); - } - Null parseNull(Glib::ustring::const_iterator & s) { - while (Glib::Unicode::isspace(*s)) s++; - if (*s++ != 'n') throw ParseError(*--s); - if (*s++ != 'u') throw ParseError(*--s); - if (*s++ != 'l') throw ParseError(*--s); - if (*s++ != 'l') throw ParseError(*--s); - return Null(); - } - Boolean parseBoolean(Glib::ustring::const_iterator & s) { - while (Glib::Unicode::isspace(*s)) s++; - if (*s == 't') { - s++; - if (*s++ != 'r') throw ParseError(*--s); - if (*s++ != 'u') throw ParseError(*--s); - if (*s++ != 'e') throw ParseError(*--s); - return true; - } - else if (*s == 'f') { - s++; - if (*s++ != 'a') throw ParseError(*--s); - if (*s++ != 'l') throw ParseError(*--s); - if (*s++ != 's') throw ParseError(*--s); - if (*s++ != 'e') throw ParseError(*--s); - return false; - } - throw ParseError(*s); + + Value parseValue(Glib::ustring::const_iterator & s) { + Glib::ustring::const_iterator start = s; + while (*s++) ; + return parseValue(Glib::ustring(start, --s)); } } + diff --git a/libjsonpp/pch.hpp b/libjsonpp/pch.hpp index c0123d3..97eb890 100644 --- a/libjsonpp/pch.hpp +++ b/libjsonpp/pch.hpp @@ -3,9 +3,13 @@ #define JSON_PCH #include <boost/variant.hpp> +#include <boost/bind.hpp> +#include <boost/function.hpp> #include <glibmm/ustring.h> +#include <glibmm/convert.h> #include <map> #include <list> +#include <stack> #endif #endif diff --git a/libjsonpp/test1.cpp b/libjsonpp/test1.cpp index e0bdf8f..8b18e3b 100644 --- a/libjsonpp/test1.cpp +++ b/libjsonpp/test1.cpp @@ -14,65 +14,97 @@ const boost::filesystem::path root(XSTR(ROOT)); BOOST_AUTO_TEST_CASE( parse_bool_true ) { const Glib::ustring val(" true "); - auto itr = val.begin(); - BOOST_REQUIRE_EQUAL(true, json::parseBoolean(itr)); + BOOST_REQUIRE_EQUAL(true, boost::get<bool>(json::parseValue(val))); } BOOST_AUTO_TEST_CASE( parse_bool_false ) { const Glib::ustring val(" false "); - auto itr = val.begin(); - BOOST_REQUIRE_EQUAL(false, json::parseBoolean(itr)); + BOOST_REQUIRE_EQUAL(false, boost::get<bool>(json::parseValue(val))); } -BOOST_AUTO_TEST_CASE( parse_bool_invalid ) +BOOST_AUTO_TEST_CASE( parse_invalid_value ) { const Glib::ustring val(" meh "); - auto itr = val.begin(); - BOOST_CHECK_THROW(json::parseBoolean(itr), json::ParseError ); + BOOST_CHECK_THROW(json::parseValue(val), json::ParseError ); +} + +BOOST_AUTO_TEST_CASE( parse_int_1 ) +{ + const Glib::ustring val(" 1 "); + BOOST_REQUIRE_EQUAL(1, boost::get<json::Number>(json::parseValue(val))); +} + +BOOST_AUTO_TEST_CASE( parse_int_neg48 ) +{ + const Glib::ustring val(" -48 "); + BOOST_REQUIRE_EQUAL(-48, boost::get<json::Number>(json::parseValue(val))); } BOOST_AUTO_TEST_CASE( parse_int_48 ) { const Glib::ustring val(" 48 "); - auto itr = val.begin(); - BOOST_REQUIRE_EQUAL(48, json::parseNumber(itr)); + BOOST_REQUIRE_EQUAL(48, boost::get<json::Number>(json::parseValue(val))); } BOOST_AUTO_TEST_CASE( parse_float_pi ) { const Glib::ustring val(" 3.14159265359 "); - auto itr = val.begin(); - BOOST_REQUIRE_CLOSE(3.14159, json::parseNumber(itr), 0.001); + BOOST_REQUIRE_CLOSE(3.14159, boost::get<json::Number>(json::parseValue(val)), 0.001); } BOOST_AUTO_TEST_CASE( parse_array ) { - const Glib::ustring val(" [ 1, 2, 3, [ 4, 5 ], {\"val\": 6} ] "); - auto itr = val.begin(); - auto arr = json::parseArray(itr); - BOOST_REQUIRE_EQUAL(5, arr.size()); + const Glib::ustring val(" [ 1, 2, 3, [ 4, 5 ], {\"val1\": 6, \"val2\": [7, 8]}, 9, 10 ] "); + auto arr = boost::get<json::Array>(json::parseValue(val)); + BOOST_REQUIRE_EQUAL(7, arr.size()); + auto itr = arr.begin(); + BOOST_REQUIRE_EQUAL(1, boost::get<json::Number>(**itr++)); + BOOST_REQUIRE_EQUAL(2, boost::get<json::Number>(**itr++)); + BOOST_REQUIRE_EQUAL(3, boost::get<json::Number>(**itr++)); + boost::get<json::Array>(**itr++); + boost::get<json::Object>(**itr++); + BOOST_REQUIRE_EQUAL(9, boost::get<json::Number>(**itr++)); + BOOST_REQUIRE_EQUAL(10, boost::get<json::Number>(**itr++)); +} + +BOOST_AUTO_TEST_CASE( parse_array_of_strings ) +{ + const Glib::ustring val(" [ \"en\", \"de\", \"ro\", \"es\", \"fa\" ] "); + boost::get<json::Array>(json::parseValue(val)); } BOOST_AUTO_TEST_CASE( parse_null ) { const Glib::ustring val(" null "); - auto itr = val.begin(); - json::parseNull(itr); + boost::get<json::Null>(json::parseValue(val)); } -BOOST_AUTO_TEST_CASE( parse_null_invalid ) +BOOST_AUTO_TEST_CASE( parse_empty_array ) { - const Glib::ustring val(" meh "); - auto itr = val.begin(); - BOOST_CHECK_THROW(json::parseBoolean(itr), json::ParseError); + const Glib::ustring val(" [ ] "); + BOOST_REQUIRE(boost::get<json::Array>(json::parseValue(val)).empty()); + +} + +BOOST_AUTO_TEST_CASE( parse_broken_array ) +{ + const Glib::ustring val(" [ 1, 2, ] "); + BOOST_CHECK_THROW(json::parseValue(val), json::ParseError ); +} + +BOOST_AUTO_TEST_CASE( parse_nonsense_in_array ) +{ + const Glib::ustring val(" [ 1, 2, nonsense ] "); + BOOST_CHECK_THROW(json::parseValue(val), json::ParseError ); } BOOST_AUTO_TEST_CASE( parse_object ) { const Glib::ustring val(" { \"a\": 1, \"b\": 2 } "); - auto itr = val.begin(); - auto obj = json::parseObject(itr); + auto value = json::parseValue(val); + BOOST_REQUIRE_EQUAL(3, value.which()); + auto obj = boost::get<json::Object>(value); BOOST_REQUIRE_EQUAL(2, obj.size()); BOOST_REQUIRE_EQUAL(1, boost::get<json::Number>(*obj["a"])); BOOST_REQUIRE_EQUAL(2, boost::get<json::Number>(*obj["b"])); @@ -81,15 +113,13 @@ BOOST_AUTO_TEST_CASE( parse_object ) BOOST_AUTO_TEST_CASE( parse_string_simple ) { const Glib::ustring val(" \"simple string\" "); - auto itr = val.begin(); - BOOST_REQUIRE_EQUAL("simple string", json::parseString(itr)); + BOOST_REQUIRE_EQUAL("simple string", boost::get<json::String>(json::parseValue(val))); } BOOST_AUTO_TEST_CASE( parse_object_withStringContainingQuote ) { const Glib::ustring val(" { \"key1\": \"value1\", \"key2\": \"value\\\"2\\\"\", \"key3\": 3 } "); - auto itr = val.begin(); - auto obj = json::parseObject(itr); + auto obj = json::parseObject(val); BOOST_REQUIRE_EQUAL(3, obj.size()); BOOST_REQUIRE_EQUAL("value1", boost::get<json::String>(*obj["key1"])); BOOST_REQUIRE_EQUAL("value\"2\"", boost::get<json::String>(*obj["key2"])); @@ -99,24 +129,61 @@ BOOST_AUTO_TEST_CASE( parse_object_withStringContainingQuote ) BOOST_AUTO_TEST_CASE( parse_string_invalid_missingOpeningQuote ) { const Glib::ustring val(" simple string\" "); - auto itr = val.begin(); - BOOST_CHECK_THROW(json::parseString(itr), json::ParseError); + BOOST_CHECK_THROW(json::parseValue(val), json::ParseError); } BOOST_AUTO_TEST_CASE( parse_string_escapedQuote ) { const Glib::ustring val(" \"A \\\"quoted\\\" string.\" "); - auto itr = val.begin(); - BOOST_REQUIRE_EQUAL("A \"quoted\" string.", json::parseString(itr)); + BOOST_REQUIRE_EQUAL("A \"quoted\" string.", boost::get<json::String>(json::parseValue(val))); +} + +BOOST_AUTO_TEST_CASE( parse_string_escapedWhitespace ) +{ + const Glib::ustring val(" \"A whitespace\\t\\r\\n\\b\\f string.\" "); + BOOST_REQUIRE_EQUAL("A whitespace\t\r\n\b\f string.", boost::get<json::String>(json::parseValue(val))); +} + +BOOST_AUTO_TEST_CASE( parse_string_escapedSlashes ) +{ + const Glib::ustring val(" \"A whitespace\\\\ \\/ string.\" "); + BOOST_REQUIRE_EQUAL("A whitespace\\ / string.", boost::get<json::String>(json::parseValue(val))); +} + +BOOST_AUTO_TEST_CASE( parse_string_literalUnicode ) +{ + const Glib::ustring val(" \"A Űņĩćőđē string.\" "); + BOOST_REQUIRE_EQUAL("A Űņĩćőđē string.", boost::get<json::String>(json::parseValue(val))); +} + +BOOST_AUTO_TEST_CASE( parse_string_unknownEscape ) +{ + const Glib::ustring val(" \"A \\z string.\" "); + BOOST_CHECK_THROW(json::parseValue(val), json::ParseError); +} + +BOOST_AUTO_TEST_CASE( parse_string_shortUnicodeEscape ) +{ + const Glib::ustring val(" \"A \\u017 string.\" "); + BOOST_CHECK_THROW(json::parseValue(val), json::ParseError); +} + +BOOST_AUTO_TEST_CASE( parse_string_escapedUnicode ) +{ + const Glib::ustring val(" \"A \\u0170\\u0146\\u0129\\u0107\\u0151\\u0111\\u0113 string.\" "); + BOOST_REQUIRE_EQUAL("A Űņĩćőđē string.", boost::get<json::String>(json::parseValue(val))); } BOOST_AUTO_TEST_CASE( parse_sample_complexFile ) { std::ifstream inFile((root / "initial" / "sample1.json").string()); - std::stringstream buffer; - buffer << inFile.rdbuf(); - Glib::ustring doc(buffer.str()); - Glib::ustring::const_iterator itr = doc.begin(); - json::Value obj = json::parseValue(itr); + json::Value obj = json::parseValue(inFile, "utf-8"); +} + +BOOST_AUTO_TEST_CASE( parse_from_itr ) +{ + const Glib::ustring val(" \"A \\u0170\\u0146\\u0129\\u0107\\u0151\\u0111\\u0113 string.\" "); + auto itr = val.begin(); + BOOST_REQUIRE_EQUAL("A Űņĩćőđē string.", boost::get<json::String>(json::parseValue(itr))); } |