summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2014-09-12 18:56:09 +0000
committerrandomdan <randomdan@localhost>2014-09-12 18:56:09 +0000
commit53c4105ae5d96da8031e548dc1380e8b38c4e38f (patch)
tree0d92aaf55c7eb8851b956d98c60fb9696cd7f80d
parentStandalone json library (diff)
downloadlibjsonpp-53c4105ae5d96da8031e548dc1380e8b38c4e38f.tar.bz2
libjsonpp-53c4105ae5d96da8031e548dc1380e8b38c4e38f.tar.xz
libjsonpp-53c4105ae5d96da8031e548dc1380e8b38c4e38f.zip
Fixes parser bug with escape sequences, improves error reporting (slightly) and adds some covering unit testslibjsonpp-0.8.1
-rw-r--r--libjsonpp/Jamfile.jam14
-rw-r--r--libjsonpp/initial/sample1.json57
-rw-r--r--libjsonpp/jsonpp.h6
-rw-r--r--libjsonpp/parse.cpp58
-rw-r--r--libjsonpp/test1.cpp114
-rw-r--r--libjsonpp/testpch.hpp12
6 files changed, 234 insertions, 27 deletions
diff --git a/libjsonpp/Jamfile.jam b/libjsonpp/Jamfile.jam
index f3d0c6c..da6de95 100644
--- a/libjsonpp/Jamfile.jam
+++ b/libjsonpp/Jamfile.jam
@@ -1,4 +1,5 @@
import package ;
+import testing ;
alias glibmm : : : :
<cflags>"`pkg-config --cflags glibmm-2.4`"
@@ -9,7 +10,7 @@ cpp-pch pch : pch.hpp :
<library>glibmm
;
lib jsonpp :
- pch [ glob *.cpp ]
+ pch [ glob *.cpp : test*.cpp ]
:
<include>.
<library>glibmm
@@ -17,4 +18,15 @@ lib jsonpp :
<include>.
;
+cpp-pch testpch : testpch.hpp :
+ <library>glibmm
+ <library>jsonpp
+ ;
+unit-test test1 :
+ testpch
+ test1.cpp
+ :
+ <library>jsonpp
+ ;
+
package.install install : <install-source-root>. : : jsonpp : [ glob *.h ] ;
diff --git a/libjsonpp/initial/sample1.json b/libjsonpp/initial/sample1.json
new file mode 100644
index 0000000..dd68064
--- /dev/null
+++ b/libjsonpp/initial/sample1.json
@@ -0,0 +1,57 @@
+{
+ "adult": false,
+ "backdrop_path": "/8uO0gUM8aNqYLs1OsTBQiXu0fEv.jpg",
+ "belongs_to_collection": null,
+ "budget": 63000000,
+ "genres": [
+ {
+ "id": 28,
+ "name": "Action"
+ },
+ {
+ "id": 18,
+ "name": "Drama"
+ },
+ {
+ "id": 53,
+ "name": "Thriller"
+ }
+ ],
+ "homepage": "",
+ "id": 550,
+ "imdb_id": "tt0137523",
+ "original_title": "Fight Club",
+ "overview": "A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground \"fight clubs\" forming in every town, until an eccentric gets in the way and ignites an out-of-control spiral toward oblivion.",
+ "popularity": 61151.745000000003,
+ "poster_path": "/2lECpi35Hnbpa4y46JX0aY3AWTy.jpg",
+ "production_companies": [
+ {
+ "name": "20th Century Fox",
+ "id": 25
+ }
+ ],
+ "production_countries": [
+ {
+ "iso_3166_1": "DE",
+ "name": "Germany"
+ },
+ {
+ "iso_3166_1": "US",
+ "name": "United States of America"
+ }
+ ],
+ "release_date": "1999-10-15",
+ "revenue": 100853753,
+ "runtime": 139,
+ "spoken_languages": [
+ {
+ "iso_639_1": "en",
+ "name": "English"
+ }
+ ],
+ "status": "Released",
+ "tagline": "How much can you know about yourself if you've never been in a fight?",
+ "title": "Fight Club",
+ "vote_average": 9.0999999999999996,
+ "vote_count": 174
+}
diff --git a/libjsonpp/jsonpp.h b/libjsonpp/jsonpp.h
index 33f5dab..a872fd9 100644
--- a/libjsonpp/jsonpp.h
+++ b/libjsonpp/jsonpp.h
@@ -6,8 +6,14 @@
#include <boost/variant.hpp>
#include <map>
#include <list>
+#include <stdexcept>
namespace json {
+ class ParseError : public std::invalid_argument {
+ public:
+ ParseError(gunichar);
+ };
+
typedef Glib::ustring String;
typedef double Number;
typedef bool Boolean;
diff --git a/libjsonpp/parse.cpp b/libjsonpp/parse.cpp
index 565c9e1..f127e9d 100644
--- a/libjsonpp/parse.cpp
+++ b/libjsonpp/parse.cpp
@@ -2,13 +2,17 @@
#include "jsonpp.h"
namespace json {
- class ParseError { };
+ ParseError::ParseError(gunichar c) :
+ std::invalid_argument(Glib::ustring("Parse error at or near ") + Glib::ustring(1, c))
+ {
+ }
String parseString(Glib::ustring::const_iterator & s) {
while (Glib::Unicode::isspace(*s)) s++;
- if (*s++ != '"') throw ParseError();
+ if (*s++ != '"') throw ParseError(*--s);
String str;
while (*s != '"') {
if (*s == '\\') {
+ ++s;
switch (*s) {
case '"':
str += '"';
@@ -49,7 +53,7 @@ namespace json {
c += (*s - 'A');
}
else {
- throw ParseError();
+ throw ParseError(*s);
}
s++;
}
@@ -58,7 +62,7 @@ namespace json {
}
break;
default:
- throw ParseError();
+ throw ParseError(*s);
}
}
else {
@@ -66,7 +70,7 @@ namespace json {
}
s++;
}
- if (*s++ != '"') throw ParseError();
+ if (*s++ != '"') throw ParseError(*--s);
return str;
}
Number parseNumber(Glib::ustring::const_iterator & s) {
@@ -93,7 +97,7 @@ namespace json {
}
}
else if (*s == '.') {
- if (dot || e) throw ParseError();
+ if (dot || e) throw ParseError(*s);
dot = true;
}
else if (*s == 'e' || *s == 'E') {
@@ -127,7 +131,7 @@ namespace json {
}
s++;
}
- if (digits < 1) throw ParseError();
+ if (digits < 1) throw ParseError(*s);
return neg ? -v : v;
}
Value parseValue(Glib::ustring::const_iterator & s) {
@@ -151,21 +155,21 @@ namespace json {
Object parseObject(const Glib::ustring & s) {
Glib::ustring::const_iterator i = s.begin();
Object o = parseObject(i);
- if (i != s.end()) throw ParseError();
+ 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();
+ 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();
- if (!o.insert(Object::value_type(key, ValuePtr(new Value(parseValue(s))))).second) throw ParseError();
+ 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 == '}') {
@@ -173,12 +177,12 @@ namespace json {
while (Glib::Unicode::isspace(*s)) s++;
return o;
}
- throw ParseError();
+ throw ParseError(*s);
}
Array parseArray(Glib::ustring::const_iterator & s) {
Array a;
while (Glib::Unicode::isspace(*s)) s++;
- if (*s != '[') throw ParseError();
+ if (*s != '[') throw ParseError(*s);
do {
s++;
while (Glib::Unicode::isspace(*s)) s++;
@@ -193,31 +197,33 @@ namespace json {
s++;
return a;
}
- throw ParseError();
+ throw ParseError(*s);
}
Null parseNull(Glib::ustring::const_iterator & s) {
- if (*s++ != 'n') throw ParseError();
- if (*s++ != 'u') throw ParseError();
- if (*s++ != 'l') throw ParseError();
- if (*s++ != 'l') throw ParseError();
+ 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();
- if (*s++ != 'u') throw ParseError();
- if (*s++ != 'e') throw ParseError();
+ 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();
- if (*s++ != 'l') throw ParseError();
- if (*s++ != 's') throw ParseError();
- if (*s++ != 'e') throw ParseError();
+ 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();
+ throw ParseError(*s);
}
}
diff --git a/libjsonpp/test1.cpp b/libjsonpp/test1.cpp
new file mode 100644
index 0000000..eaeccf7
--- /dev/null
+++ b/libjsonpp/test1.cpp
@@ -0,0 +1,114 @@
+#define BOOST_TEST_MODULE parsing
+#include <boost/test/included/unit_test.hpp>
+
+#include "jsonpp.h"
+
+BOOST_AUTO_TEST_CASE( parse_bool_true )
+{
+ const Glib::ustring val(" true ");
+ auto itr = val.begin();
+ BOOST_REQUIRE_EQUAL(true, json::parseBoolean(itr));
+}
+
+BOOST_AUTO_TEST_CASE( parse_bool_false )
+{
+ const Glib::ustring val(" false ");
+ auto itr = val.begin();
+ BOOST_REQUIRE_EQUAL(false, json::parseBoolean(itr));
+}
+
+BOOST_AUTO_TEST_CASE( parse_bool_invalid )
+{
+ const Glib::ustring val(" meh ");
+ auto itr = val.begin();
+ BOOST_CHECK_THROW(json::parseBoolean(itr), json::ParseError );
+}
+
+BOOST_AUTO_TEST_CASE( parse_int_48 )
+{
+ const Glib::ustring val(" 48 ");
+ auto itr = val.begin();
+ BOOST_REQUIRE_EQUAL(48, json::parseNumber(itr));
+}
+
+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_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());
+}
+
+BOOST_AUTO_TEST_CASE( parse_null )
+{
+ const Glib::ustring val(" null ");
+ auto itr = val.begin();
+ json::parseNull(itr);
+}
+
+BOOST_AUTO_TEST_CASE( parse_null_invalid )
+{
+ const Glib::ustring val(" meh ");
+ auto itr = val.begin();
+ BOOST_CHECK_THROW(json::parseBoolean(itr), 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);
+ 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"]));
+}
+
+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_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);
+ 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"]));
+ BOOST_REQUIRE_EQUAL(3, boost::get<json::Number>(*obj["key3"]));
+}
+
+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_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_AUTO_TEST_CASE( parse_sample_complexFile )
+{
+ std::ifstream inFile("initial/sample1.json");
+ std::stringstream buffer;
+ buffer << inFile.rdbuf();
+ Glib::ustring doc(buffer.str());
+ Glib::ustring::const_iterator itr = doc.begin();
+ json::Value obj = json::parseValue(itr);
+}
+
diff --git a/libjsonpp/testpch.hpp b/libjsonpp/testpch.hpp
new file mode 100644
index 0000000..442c866
--- /dev/null
+++ b/libjsonpp/testpch.hpp
@@ -0,0 +1,12 @@
+#ifdef BOOST_BUILD_PCH_ENABLED
+#ifndef JSON_TESTPCH
+#define JSON_TESTPCH
+
+#define BOOST_TEST_MODULE example
+#include <boost/test/included/unit_test.hpp>
+#include "jsonpp.h"
+
+#endif
+#endif
+
+