diff options
| -rw-r--r-- | libjsonpp/Jamfile.jam | 14 | ||||
| -rw-r--r-- | libjsonpp/initial/sample1.json | 57 | ||||
| -rw-r--r-- | libjsonpp/jsonpp.h | 6 | ||||
| -rw-r--r-- | libjsonpp/parse.cpp | 58 | ||||
| -rw-r--r-- | libjsonpp/test1.cpp | 114 | ||||
| -rw-r--r-- | libjsonpp/testpch.hpp | 12 | 
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 + +  | 
