Utils/t/json_test.cpp
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// See accompanying file COPYING.TXT file for licensing details.
//
///////////////////////////////////////////////////////////////////////////////
#include <cppcms/json.h>
#include "test.h"
#include <iostream>
#include <limits>
#include <stdlib.h>
#include <sstream>
#include <iomanip>
using namespace cppcms;
using namespace std;
char const *jsn_str=
"{ \"t\" : [{},{},{},{ \"x\":1},[]],\"x\" : { \"o\" : { \"test\" : [ 10,20,true ], \"post\" : 13.01 }, \"yes\" : \"\\u05d0א\" }}";
class parsing_error : public std::runtime_error {
public:
parsing_error(std::string s) : std::runtime_error(s) {}
};
#define THROWS(X) do{ try { X; }catch(cppcms::json::bad_value_cast const &e){}\
catch(parsing_error const &e){}\
catch(...){\
std::ostringstream tmp; \
tmp << __FILE__ << " " << __LINE__ << " "#X " not throwed"; \
throw std::runtime_error(tmp.str()); } }while(0)
json::value Parse(std::string s,int line)
{
std::istringstream ss(s);
json::value v;
if(!v.load(ss,true)) {
std::ostringstream tmp;
tmp << "Parsing error of " << s << " in line " << line;
throw parsing_error(tmp.str());
}
return v;
}
std::string format(json::value const &v)
{
std::ostringstream ss;
ss<<v;
return ss.str();
}
#define parse(X) Parse(X,__LINE__)
int main()
{
try {
json::value v;
json::value const &vc=v;
TEST(v.type()==json::is_undefined);
TEST(v.is_undefined());
v=10;
TEST(v.type()==json::is_number);
TEST(v.number()==10);
TEST(v.get_value<int>()==10);
TEST(v.get_value<double>()==10);
THROWS(v.get_value<std::string>());
v="test";
TEST(v.type()==json::is_string);
TEST(v.str()=="test");
v=true;
TEST(v.type()==json::is_boolean);
TEST(v.boolean()==true);
v=json::null();
TEST(v.is_null());
TEST(v.type()==json::is_null);
v=json::array();
TEST(v.type()==json::is_array);
v=json::object();
TEST(v.type()==json::is_object);
TEST(v.find("x")==json::value());
TEST(v.type("x")==json::is_undefined);
TEST(v.get<std::string>("x","y")=="y");
THROWS(v.get<std::string>("x"));
THROWS(v.at("x"));
v["x"]=10;
TEST(v.find("x")==json::value(10));
TEST(v.at("x")==json::value(10));
TEST(v.type("x")==json::is_number);
TEST(v.get<std::string>("x","y")=="y");
THROWS(v.get<std::string>("x"));
v.set("x.y.z",10);
TEST(v["x"]["y"]["z"].number()==10);
TEST(v.get<int>("x.y.z")==10);
TEST(parse("[]")==json::array());
TEST(parse("{}")==json::object());
TEST(parse("true")==json::value(true));
TEST(parse("false")==json::value(false));
TEST(parse("10")==json::value(10));
TEST(parse("\"hello\"")==json::value("hello"));
TEST(parse("null")==json::null());
char const *s=
"{ \"t\" : [{},{},{},{ \"x\":1},[]],\"x\" : { \"o\" : { \"test\" : [ 10,20,true ], \"post\" : 13.01 }, \"yes\" : \"\\u05d0א\" }}";
v=parse(s);
TEST(v.type("t")==json::is_array);
TEST(v["t"].array().size()==5);
TEST(v["t"][0]==json::object());
TEST(v["t"][1]==json::object());
TEST(v["t"][2]==json::object());
TEST(v["t"][4]==json::array());
TEST(v["t"][3]["x"].number()==1);
TEST(v.type("x")==json::is_object);
TEST(v.get<std::string>("x.yes")=="אא");
// Test correct handing of surrogates
THROWS(parse("\"\\ud834\""));
THROWS(parse("\"\\udd1e\""));
THROWS(parse("\"\\ud834 \\udd1e\""));
TEST(parse("\"\\u05d0\\ud834\\udd1e x\"")=="א\xf0\x9d\x84\x9e x");
THROWS(parse("\"\xFF\xFF\"")); // Invalid UTF-8
TEST(parse("\"\\u05d0 x\"")=="א x"); // Correct read of 4 bytes
THROWS(parse("\"\\u05dx x\"")); // Correct read of 4 bytes
TEST(parse("[//Hello\n]")==json::array());
TEST(format("test")=="\"test\"");
TEST(format(10)=="10");
TEST(format(true)=="true");
TEST(format(false)=="false");
TEST(format(json::null())=="null");
TEST(format(json::object())=="{}");
TEST(format(json::array())=="[]");
v=json::value();
v["x"]="yes";
TEST(vc["x"].str()=="yes");
THROWS(vc["y"]);
THROWS(vc[1]);
v[2]="yes";
TEST(v[0]==json::null());
TEST(v[1]==json::null());
TEST(vc[2].str()=="yes");
TEST(v[2]=="yes");
TEST(v[3]==json::null());
THROWS(vc[4]);
THROWS(vc["x"]);
v=json::value();
v["x"]=10;
v["y"][1]="test";
v["y"][2]=json::array();
TEST(format(v)=="{\"x\":10,\"y\":[null,\"test\",[]]}");
std::string fl="123456789123456789123456789123456789";
fl = fl.substr(0,std::numeric_limits<double>::digits10);
double big_int=atof(fl.c_str());
TEST(format(big_int)==fl);
TEST(format(1277880000)=="1277880000");
TEST(format(-1277880000)=="-1277880000");
TEST(atoi(format(std::numeric_limits<int>::max()).c_str()) == std::numeric_limits<int>::max());
TEST(atoi(format(std::numeric_limits<int>::min()).c_str()) == std::numeric_limits<int>::min());
std::string fl2=fl.substr(0,1)+'.'+fl.substr(1);
big_int=atof(fl2.c_str());
TEST(format(big_int)==fl2);
TEST(format(-big_int)=="-" + fl2);
{
std::string tmp;
tmp = format(1.35e30);
TEST(tmp.substr(0,5)=="1.35e");
TEST(tmp.substr(tmp.size()-2)=="30");
tmp = format(big_int * 1e30);
TEST(tmp.substr(0,fl2.size()+1) == fl2+"e");
TEST(tmp.substr(tmp.size()-2)=="30");
}
v["x"]=10000000;
THROWS(v.get<short>("x"));
TEST(v.get<int>("x")==10000000);
v["x"]=-1;
THROWS(v.get<unsigned>("x"));
THROWS(v.get<unsigned short>("x"));
THROWS(v.get<unsigned long >("x"));
TEST(v.get<int>("x")==-1);
TEST(v.get<short>("x")==-1);
TEST(v.get<long>("x")==-1);
if(sizeof(long long) >= sizeof(double)) {
THROWS(v["x"]=std::numeric_limits<long long>::max());
}
if(std::numeric_limits<double>::max() != std::numeric_limits<float>::max()) {
double val = std::numeric_limits<double>::max() / 100;
v["x"]=val;
THROWS(v.get<float>("x"));
TEST(v.get<double>("x")==val);
TEST(v.get<long double>("x")==val);
}
if(std::numeric_limits<long double>::max() != std::numeric_limits<double>::max()) {
long double val = std::numeric_limits<long double>::max() / 100;
THROWS(v["x"]=val);
}
}
catch(std::exception const &e)
{
cerr<<"Failed:"<<e.what()<<endl;
return 1;
}
std::cout << "Passed" << std::endl;
return 0;
}