mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
JSON
- Replaced old Tree-based parser with a faster, leaner parser. Currently lacking good error handling and a large test suite. - Integrated new parser into Task object, for encode/decode. - Replicated same basic unit tests. Needs more. - Fixed bug in handleShell that failed to call the new Context::initialize2. - Removed debugging code from CmdInstall. - Implemented format() that does not require width and precision args.
This commit is contained in:
parent
05b3fa0bb6
commit
690fa6e206
8 changed files with 517 additions and 297 deletions
576
src/JSON.cpp
576
src/JSON.cpp
|
@ -1,7 +1,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// taskwarrior - a command line task list manager.
|
||||
//
|
||||
// Copyright 2010 - 2011, Paul Beckingham, Federico Hernandez.
|
||||
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
|
@ -25,35 +25,361 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iostream> // TODO Remove.
|
||||
#include <text.h>
|
||||
#include <utf8.h>
|
||||
#include <JSON.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
JSON::JSON ()
|
||||
: root ("root")
|
||||
json::value* json::value::parse (Nibbler& nibbler)
|
||||
{
|
||||
json::value* v;
|
||||
if ((v = json::object::parse (nibbler)) ||
|
||||
(v = json::array::parse (nibbler)) ||
|
||||
(v = json::string::parse (nibbler)) ||
|
||||
(v = json::number::parse (nibbler)) ||
|
||||
(v = json::literal::parse (nibbler)))
|
||||
return v;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
JSON::JSON (const std::string& input)
|
||||
: root ("root")
|
||||
json::jtype json::value::type ()
|
||||
{
|
||||
return json::j_value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string json::value::dump ()
|
||||
{
|
||||
return "<value>";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::string::string (const std::string& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::string* json::string::parse (Nibbler& nibbler)
|
||||
{
|
||||
std::string value;
|
||||
if (nibbler.getQuoted ('"', value, false))
|
||||
{
|
||||
json::string* s = new json::string ();
|
||||
*(std::string*)s = value;
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::jtype json::string::type ()
|
||||
{
|
||||
return json::j_string;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string json::string::dump ()
|
||||
{
|
||||
return std::string ("\"") + (std::string) *this + "\"";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::number* json::number::parse (Nibbler& nibbler)
|
||||
{
|
||||
int i;
|
||||
double d;
|
||||
if (nibbler.getNumber (d))
|
||||
{
|
||||
json::number* s = new json::number ();
|
||||
s->_dvalue = d;
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::jtype json::number::type ()
|
||||
{
|
||||
return json::j_number;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string json::number::dump ()
|
||||
{
|
||||
return format (_dvalue);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::number::operator double () const
|
||||
{
|
||||
return _dvalue;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::literal* json::literal::parse (Nibbler& nibbler)
|
||||
{
|
||||
if (nibbler.getLiteral ("null"))
|
||||
{
|
||||
json::literal* s = new json::literal ();
|
||||
s->_lvalue = nullvalue;
|
||||
return s;
|
||||
}
|
||||
else if (nibbler.getLiteral ("false"))
|
||||
{
|
||||
json::literal* s = new json::literal ();
|
||||
s->_lvalue = falsevalue;
|
||||
return s;
|
||||
}
|
||||
else if (nibbler.getLiteral ("true"))
|
||||
{
|
||||
json::literal* s = new json::literal ();
|
||||
s->_lvalue = truevalue;
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::jtype json::literal::type ()
|
||||
{
|
||||
return json::j_literal;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string json::literal::dump ()
|
||||
{
|
||||
if (_lvalue == nullvalue) return "null";
|
||||
else if (_lvalue == falsevalue) return "false";
|
||||
else return "true";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::array::~array ()
|
||||
{
|
||||
std::vector <json::value*>::iterator i;
|
||||
for (i = ((std::vector <json::value*>*)this)->begin ();
|
||||
i != ((std::vector <json::value*>*)this)->end ();
|
||||
++i)
|
||||
delete *i;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::array* json::array::parse (Nibbler& nibbler)
|
||||
{
|
||||
Nibbler n (nibbler);
|
||||
n.skipWS ();
|
||||
if (n.skip ('['))
|
||||
{
|
||||
n.skipWS ();
|
||||
|
||||
json::array* arr = new json::array ();
|
||||
|
||||
json::value* value;
|
||||
if (value = json::value::parse (n))
|
||||
{
|
||||
arr->push_back (value);
|
||||
value = NULL; // Not a leak. Looks like a leak.
|
||||
n.skipWS ();
|
||||
while (n.skip (','))
|
||||
{
|
||||
n.skipWS ();
|
||||
|
||||
if (value = json::value::parse (n))
|
||||
{
|
||||
arr->push_back (value);
|
||||
n.skipWS ();
|
||||
}
|
||||
else
|
||||
{
|
||||
delete arr;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n.skip (']'))
|
||||
{
|
||||
nibbler = n;
|
||||
return arr;
|
||||
}
|
||||
|
||||
delete arr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::jtype json::array::type ()
|
||||
{
|
||||
return json::j_array;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string json::array::dump ()
|
||||
{
|
||||
std::string output;
|
||||
output += "[";
|
||||
|
||||
std::vector <json::value*>::iterator i;
|
||||
for (i = ((std::vector <json::value*>*)this)->begin ();
|
||||
i != ((std::vector <json::value*>*)this)->end ();
|
||||
++i)
|
||||
{
|
||||
if (i != ((std::vector <json::value*>*)this)->begin ())
|
||||
output += ",";
|
||||
|
||||
output += (*i)->dump ();
|
||||
}
|
||||
|
||||
output += "]";
|
||||
return output;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::object::~object ()
|
||||
{
|
||||
std::map <std::string, json::value*>::iterator i;
|
||||
for (i = ((std::map <std::string, json::value*>*)this)->begin ();
|
||||
i != ((std::map <std::string, json::value*>*)this)->end ();
|
||||
++i)
|
||||
delete i->second;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::object* json::object::parse (Nibbler& nibbler)
|
||||
{
|
||||
Nibbler n (nibbler);
|
||||
n.skipWS ();
|
||||
if (n.skip ('{'))
|
||||
{
|
||||
n.skipWS ();
|
||||
|
||||
json::object* obj = new json::object ();
|
||||
|
||||
std::string name;
|
||||
json::value* value;
|
||||
if (json::object::parse_pair (n, name, value))
|
||||
{
|
||||
obj->insert (std::pair <std::string, json::value*> (name, value));
|
||||
value = NULL; // Not a leak. Looks like a leak.
|
||||
|
||||
n.skipWS ();
|
||||
while (n.skip (','))
|
||||
{
|
||||
n.skipWS ();
|
||||
|
||||
if (json::object::parse_pair (n, name, value))
|
||||
{
|
||||
obj->insert (std::pair <std::string, json::value*> (name, value));
|
||||
n.skipWS ();
|
||||
}
|
||||
else
|
||||
{
|
||||
delete obj;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n.skip ('}'))
|
||||
{
|
||||
nibbler = n;
|
||||
return obj;
|
||||
}
|
||||
|
||||
delete obj;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool json::object::parse_pair (
|
||||
Nibbler& nibbler,
|
||||
std::string& name,
|
||||
json::value*& val)
|
||||
{
|
||||
Nibbler n (nibbler);
|
||||
|
||||
if (n.getQuoted ('"', name, false))
|
||||
{
|
||||
n.skipWS ();
|
||||
if (n.skip (':'))
|
||||
{
|
||||
n.skipWS ();
|
||||
if (val = json::value::parse (n))
|
||||
{
|
||||
nibbler = n;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::jtype json::object::type ()
|
||||
{
|
||||
return json::j_object;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string json::object::dump ()
|
||||
{
|
||||
std::string output;
|
||||
output += "{";
|
||||
|
||||
std::map <std::string, json::value*>::iterator i;
|
||||
for (i = ((std::map <std::string, json::value*>*)this)->begin ();
|
||||
i != ((std::map <std::string, json::value*>*)this)->end ();
|
||||
++i)
|
||||
{
|
||||
if (i != ((std::map <std::string, json::value*>*)this)->begin ())
|
||||
output += ",";
|
||||
|
||||
output += "\"" + i->first + "\":";
|
||||
output += i->second->dump ();
|
||||
}
|
||||
|
||||
output += "}";
|
||||
return output;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
json::value* json::parse (const std::string& input)
|
||||
{
|
||||
json::value* root = NULL;
|
||||
|
||||
Nibbler n (input);
|
||||
if (!parseObject (&root, n))
|
||||
throw std::string ("Syntax error in request.");
|
||||
n.skipWS ();
|
||||
|
||||
if (n.next () == '{') root = json::object::parse (n);
|
||||
else if (n.next () == '[') root = json::array::parse (n);
|
||||
else
|
||||
throw std::string ("Error: expected '{' or '[' at position ") +
|
||||
format ((int)n.cursor ());
|
||||
|
||||
// Check for end condition.
|
||||
n.skipWS ();
|
||||
if (!n.depleted ())
|
||||
{
|
||||
delete root;
|
||||
throw std::string ("Error: extra characters found: ") + n.dump ();
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
JSON::~JSON ()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// \n -> "\\n"
|
||||
// \t -> "\\t"
|
||||
std::string JSON::encode (const std::string& input)
|
||||
std::string json::encode (const std::string& input)
|
||||
{
|
||||
std::string output;
|
||||
|
||||
|
@ -80,7 +406,7 @@ std::string JSON::encode (const std::string& input)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string JSON::decode (const std::string& input)
|
||||
std::string json::decode (const std::string& input)
|
||||
{
|
||||
std::string output;
|
||||
|
||||
|
@ -122,217 +448,3 @@ std::string JSON::decode (const std::string& input)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Tree* JSON::tree ()
|
||||
{
|
||||
return &root;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// object
|
||||
// {}
|
||||
// { pair , ... }
|
||||
bool JSON::parseObject (Tree* t, Nibbler& nibbler)
|
||||
{
|
||||
Nibbler n (nibbler);
|
||||
n.skipWS ();
|
||||
|
||||
if (n.skip ('{'))
|
||||
{
|
||||
n.skipWS ();
|
||||
|
||||
Tree* node = new Tree ("node");
|
||||
if (parsePair (node, n))
|
||||
{
|
||||
t->addBranch (node);
|
||||
|
||||
n.skipWS ();
|
||||
while (n.skip (','))
|
||||
{
|
||||
n.skipWS ();
|
||||
|
||||
node = new Tree ("node");
|
||||
if (!parsePair (node, n))
|
||||
{
|
||||
delete node;
|
||||
return false;
|
||||
}
|
||||
|
||||
t->addBranch (node);
|
||||
n.skipWS ();
|
||||
}
|
||||
}
|
||||
else
|
||||
delete node;
|
||||
|
||||
if (n.skip ('}'))
|
||||
{
|
||||
n.skipWS ();
|
||||
nibbler = n;
|
||||
t->attribute ("type", "collection");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// pair
|
||||
// string : value
|
||||
bool JSON::parsePair (Tree* t, Nibbler& nibbler)
|
||||
{
|
||||
Nibbler n (nibbler);
|
||||
|
||||
std::string value;
|
||||
if (n.getQuoted ('"', value))
|
||||
{
|
||||
n.skipWS ();
|
||||
if (n.skip (':'))
|
||||
{
|
||||
n.skipWS ();
|
||||
if (parseValue (t, n))
|
||||
{
|
||||
nibbler = n;
|
||||
t->name (value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// array
|
||||
// []
|
||||
// [ value , ... ]
|
||||
bool JSON::parseArray (Tree* t, Nibbler& nibbler)
|
||||
{
|
||||
Nibbler n (nibbler);
|
||||
n.skipWS ();
|
||||
|
||||
if (n.skip ('['))
|
||||
{
|
||||
n.skipWS ();
|
||||
|
||||
Tree* node = new Tree ("node");
|
||||
if (parseValue (node, n))
|
||||
{
|
||||
t->addBranch (node);
|
||||
|
||||
n.skipWS ();
|
||||
while (n.skip (','))
|
||||
{
|
||||
n.skipWS ();
|
||||
|
||||
node = new Tree ("node");
|
||||
if (!parseValue (node, n))
|
||||
{
|
||||
delete node;
|
||||
return false;
|
||||
}
|
||||
|
||||
t->addBranch (node);
|
||||
n.skipWS ();
|
||||
}
|
||||
}
|
||||
else
|
||||
delete node;
|
||||
|
||||
if (n.skip (']'))
|
||||
{
|
||||
n.skipWS ();
|
||||
nibbler = n;
|
||||
t->attribute ("type", "list");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// value
|
||||
// string
|
||||
// number
|
||||
// object
|
||||
// array
|
||||
// true
|
||||
// false
|
||||
// null
|
||||
bool JSON::parseValue (Tree* t, Nibbler& nibbler)
|
||||
{
|
||||
if (parseString (t, nibbler) ||
|
||||
parseNumber (t, nibbler) ||
|
||||
parseObject (t, nibbler) ||
|
||||
parseArray (t, nibbler) ||
|
||||
nibbler.getLiteral ("true") ||
|
||||
nibbler.getLiteral ("false") ||
|
||||
nibbler.getLiteral ("null"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// string
|
||||
// ""
|
||||
// " chars "
|
||||
//
|
||||
// chars
|
||||
// char
|
||||
// char chars
|
||||
//
|
||||
// char
|
||||
// any-Unicode-character-except-"-or-\-or-control-character
|
||||
// \"
|
||||
// \\ [extra text to de-confuse gcc]
|
||||
// \/
|
||||
// \b
|
||||
// \f
|
||||
// \n
|
||||
// \r
|
||||
// \t
|
||||
// \u four-hex-digits
|
||||
bool JSON::parseString (Tree* t, Nibbler& nibbler)
|
||||
{
|
||||
std::string value;
|
||||
if (nibbler.getQuoted ('"', value, false))
|
||||
{
|
||||
t->attribute ("type", "string");
|
||||
t->attribute ("value", value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// number
|
||||
// int frac exp
|
||||
// int frac
|
||||
// int exp
|
||||
// int
|
||||
bool JSON::parseNumber (Tree* t, Nibbler& nibbler)
|
||||
{
|
||||
int i;
|
||||
double d;
|
||||
if (nibbler.getNumber (d))
|
||||
{
|
||||
t->attribute ("type", "number");
|
||||
t->attribute ("value", d);
|
||||
return true;
|
||||
}
|
||||
else if (nibbler.getInt (i))
|
||||
{
|
||||
t->attribute ("type", "number");
|
||||
t->attribute ("value", i);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
108
src/JSON.h
108
src/JSON.h
|
@ -1,7 +1,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// taskwarrior - a command line task list manager.
|
||||
//
|
||||
// Copyright 2010 - 2011, Paul Beckingham, Federico Hernandez.
|
||||
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
|
@ -24,38 +24,102 @@
|
|||
// USA
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_JSON
|
||||
#define INCLUDED_JSON
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <Tree.h>
|
||||
#include <Nibbler.h>
|
||||
|
||||
class JSON
|
||||
namespace json
|
||||
{
|
||||
public:
|
||||
JSON (); // Default constructor
|
||||
JSON (const std::string&); // Constructor
|
||||
JSON (const JSON&); // Copy constructor
|
||||
JSON& operator= (const JSON&); // Assignment operator
|
||||
~JSON (); // Destructor
|
||||
enum jtype
|
||||
{
|
||||
j_value,
|
||||
j_object,
|
||||
j_array,
|
||||
j_string,
|
||||
j_number,
|
||||
j_literal
|
||||
};
|
||||
|
||||
static std::string encode (const std::string&);
|
||||
static std::string decode (const std::string&);
|
||||
class value
|
||||
{
|
||||
public:
|
||||
value () {}
|
||||
virtual ~value () {}
|
||||
static value* parse (Nibbler&);
|
||||
virtual jtype type ();
|
||||
virtual std::string dump ();
|
||||
};
|
||||
|
||||
Tree* tree ();
|
||||
class string : public value, public std::string
|
||||
{
|
||||
public:
|
||||
string () {}
|
||||
string (const std::string&);
|
||||
~string () {}
|
||||
static string* parse (Nibbler&);
|
||||
jtype type ();
|
||||
std::string dump ();
|
||||
};
|
||||
|
||||
private:
|
||||
bool parseObject (Tree*, Nibbler&);
|
||||
bool parsePair (Tree*, Nibbler&);
|
||||
bool parseArray (Tree*, Nibbler&);
|
||||
bool parseValue (Tree*, Nibbler&);
|
||||
bool parseString (Tree*, Nibbler&);
|
||||
bool parseNumber (Tree*, Nibbler&);
|
||||
class number : public value, public std::string
|
||||
{
|
||||
public:
|
||||
number () : _dvalue (0.0) {}
|
||||
~number () {}
|
||||
static number* parse (Nibbler&);
|
||||
jtype type ();
|
||||
std::string dump ();
|
||||
operator double () const;
|
||||
|
||||
private:
|
||||
Tree root;
|
||||
};
|
||||
double _dvalue;
|
||||
};
|
||||
|
||||
class literal : public value
|
||||
{
|
||||
public:
|
||||
literal () : _lvalue (none) {}
|
||||
~literal () {}
|
||||
static literal* parse (Nibbler&);
|
||||
jtype type ();
|
||||
std::string dump ();
|
||||
|
||||
enum literal_value {none, nullvalue, falsevalue, truevalue};
|
||||
literal_value _lvalue;
|
||||
};
|
||||
|
||||
class array : public value, public std::vector <value*>
|
||||
{
|
||||
public:
|
||||
array () {}
|
||||
~array ();
|
||||
static array* parse (Nibbler&);
|
||||
jtype type ();
|
||||
std::string dump ();
|
||||
};
|
||||
|
||||
class object : public value, public std::map <std::string, value*>
|
||||
{
|
||||
public:
|
||||
object () {}
|
||||
~object ();
|
||||
static object* parse (Nibbler&);
|
||||
static bool parse_pair (Nibbler&, std::string&, value*&);
|
||||
jtype type ();
|
||||
std::string dump ();
|
||||
};
|
||||
|
||||
// Parser entry point.
|
||||
value* parse (const std::string&);
|
||||
|
||||
// Encode/decode for JSON entities.
|
||||
std::string encode (const std::string&);
|
||||
std::string decode (const std::string&);
|
||||
}
|
||||
|
||||
#endif
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -505,7 +505,7 @@ std::string Task::composeJSON (bool include_id /*= false*/) const
|
|||
out << "\""
|
||||
<< i->second.name ()
|
||||
<< "\":\""
|
||||
<< JSON::encode (i->second.value ())
|
||||
<< json::encode (i->second.value ())
|
||||
<< "\"";
|
||||
|
||||
++attributes_written;
|
||||
|
@ -530,7 +530,7 @@ std::string Task::composeJSON (bool include_id /*= false*/) const
|
|||
out << "{\"entry\":\""
|
||||
<< d.toISO ()
|
||||
<< "\",\"description\":\""
|
||||
<< JSON::encode (i->second.value ())
|
||||
<< json::encode (i->second.value ())
|
||||
<< "\"}";
|
||||
|
||||
++annotations_written;
|
||||
|
|
|
@ -2250,6 +2250,7 @@ int handleIds (std::string& outs)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TODO Obsolete.
|
||||
void handleShell ()
|
||||
{
|
||||
// Display some kind of welcome message.
|
||||
|
@ -2291,11 +2292,11 @@ void handleShell ()
|
|||
try
|
||||
{
|
||||
context.clear ();
|
||||
|
||||
std::vector <std::string> args;
|
||||
split (args, decoratedCommand, ' ');
|
||||
foreach (arg, args) context.args.push_back (*arg);
|
||||
|
||||
context.initialize2 (0, NULL);
|
||||
context.initialize ();
|
||||
context.run ();
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ CmdInstall::CmdInstall ()
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CmdInstall::implements (const std::string& command_line)
|
||||
{
|
||||
std::cout << "# CmdInstall::implements '" << command_line << "'\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -55,7 +54,6 @@ bool CmdInstall::implements (const std::string& command_line)
|
|||
// extension.<uuid>=<JSON>
|
||||
int CmdInstall::execute (const std::string& commandLine, std::string& output)
|
||||
{
|
||||
std::cout << "# CmdInstall::execute\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -760,6 +760,14 @@ std::string format (double value, int width, int precision)
|
|||
return s.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string format (double value)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << value;
|
||||
return s.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string leftJustify (const int input, const int width)
|
||||
{
|
||||
|
|
|
@ -68,6 +68,7 @@ std::string format (int);
|
|||
std::string formatHex (int);
|
||||
std::string format (float, int, int);
|
||||
std::string format (double, int, int);
|
||||
std::string format (double);
|
||||
std::string leftJustify (const int, const int);
|
||||
std::string leftJustify (const std::string&, const int);
|
||||
std::string rightJustify (const int, const int);
|
||||
|
|
112
test/json.t.cpp
112
test/json.t.cpp
|
@ -35,30 +35,53 @@ Context context;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (14);
|
||||
UnitTest t (19);
|
||||
|
||||
try
|
||||
{
|
||||
// Basic parsing tests.
|
||||
// j1
|
||||
std::string input = "{}";
|
||||
std::cout << "-- j1 -------------------\n"
|
||||
<< "input: " << input << "\n";
|
||||
JSON j1 (input);
|
||||
j1.tree ()->dump ();
|
||||
std::cout << "# -- j1 -------------------\n"
|
||||
<< "# input: " << input << "\n";
|
||||
json::value* root = json::parse (input);
|
||||
t.ok (root, "j1 parse ok");
|
||||
if (root)
|
||||
{
|
||||
t.diag ("output: " + root->dump ());
|
||||
delete root;
|
||||
}
|
||||
else
|
||||
t.fail ("j1 parse error");
|
||||
|
||||
// j2
|
||||
input = "{\"name\":123}";
|
||||
std::cout << "-- j2 -------------------\n"
|
||||
<< "input: " << input << "\n";
|
||||
JSON j2 (input);
|
||||
j2.tree ()->dump ();
|
||||
std::cout << "# -- j2 -------------------\n"
|
||||
<< "# input: " << input << "\n";
|
||||
root = json::parse (input);
|
||||
t.ok (root, "j2 parse ok");
|
||||
if (root)
|
||||
{
|
||||
t.diag ("output: " + root->dump ());
|
||||
delete root;
|
||||
}
|
||||
else
|
||||
t.fail ("j2 parse error");
|
||||
|
||||
// j3
|
||||
input = "{\"name\":123, \"array\":[1,2,3.4], \"map\":{\"m1\":\"v1\", \"m2\":\"v2\"}}";
|
||||
std::cout << "-- j3 -------------------\n"
|
||||
<< "input: " << input << "\n";
|
||||
JSON j3 (input);
|
||||
j3.tree ()->dump ();
|
||||
std::cout << "# -- j3 -------------------\n"
|
||||
<< "# input: " << input << "\n";
|
||||
root = json::parse (input);
|
||||
t.ok (root, "j3 parse ok");
|
||||
if (root)
|
||||
{
|
||||
t.diag ("output: " + root->dump ());
|
||||
delete root;
|
||||
}
|
||||
else
|
||||
t.fail ("j3 parse error");
|
||||
|
||||
// Sample ticket as a parsing test.
|
||||
// j4
|
||||
input = "{\n"
|
||||
"\"ticket\": { \"type\":\"add\", \"client\":\"taskwarrior 2.x\"},\n"
|
||||
"\"auth\": { \"user\":\"paul\", \"org\":\"gbf\", \"key\":\".........\",\n"
|
||||
|
@ -68,33 +91,39 @@ int main (int argc, char** argv)
|
|||
" \"project\":\"home\",\n"
|
||||
" \"due\":\"20101101T000000Z\" }\n"
|
||||
"}";
|
||||
std::cout << "-- j4 -------------------\n"
|
||||
<< "input: " << input << "\n";
|
||||
JSON j4 (input);
|
||||
j4.tree ()->dump ();
|
||||
std::cout << "-------------------------\n";
|
||||
std::cout << "# -- j4 -------------------\n"
|
||||
<< "# input: " << input << "\n";
|
||||
root = json::parse (input);
|
||||
t.ok (root, "j4 parse ok");
|
||||
if (root)
|
||||
{
|
||||
t.diag ("output: " + root->dump ());
|
||||
delete root;
|
||||
}
|
||||
else
|
||||
t.fail ("j4 parse error");
|
||||
|
||||
// Regular unit tests.
|
||||
t.is (JSON::encode ("1\b2"), "1\\b2", "JSON::encode \\b -> \\\\b");
|
||||
t.is (JSON::decode ("1\\b2"), "1\b2", "JSON::decode \\\\b -> \\b");
|
||||
t.is (json::encode ("1\b2"), "1\\b2", "json::encode \\b -> \\\\b");
|
||||
t.is (json::decode ("1\\b2"), "1\b2", "json::decode \\\\b -> \\b");
|
||||
|
||||
t.is (JSON::encode ("1\n2"), "1\\n2", "JSON::encode \\n -> \\\\n");
|
||||
t.is (JSON::decode ("1\\n2"), "1\n2", "JSON::decode \\\\n -> \\n");
|
||||
t.is (json::encode ("1\n2"), "1\\n2", "json::encode \\n -> \\\\n");
|
||||
t.is (json::decode ("1\\n2"), "1\n2", "json::decode \\\\n -> \\n");
|
||||
|
||||
t.is (JSON::encode ("1\r2"), "1\\r2", "JSON::encode \\r -> \\\\r");
|
||||
t.is (JSON::decode ("1\\r2"), "1\r2", "JSON::decode \\\\r -> \\r");
|
||||
t.is (json::encode ("1\r2"), "1\\r2", "json::encode \\r -> \\\\r");
|
||||
t.is (json::decode ("1\\r2"), "1\r2", "json::decode \\\\r -> \\r");
|
||||
|
||||
t.is (JSON::encode ("1\t2"), "1\\t2", "JSON::encode \\t -> \\\\t");
|
||||
t.is (JSON::decode ("1\\t2"), "1\t2", "JSON::decode \\\\t -> \\t");
|
||||
t.is (json::encode ("1\t2"), "1\\t2", "json::encode \\t -> \\\\t");
|
||||
t.is (json::decode ("1\\t2"), "1\t2", "json::decode \\\\t -> \\t");
|
||||
|
||||
t.is (JSON::encode ("1\\2"), "1\\\\2", "JSON::encode \\ -> \\\\");
|
||||
t.is (JSON::decode ("1\\\\2"), "1\\2", "JSON::decode \\\\ -> \\");
|
||||
t.is (json::encode ("1\\2"), "1\\\\2", "json::encode \\ -> \\\\");
|
||||
t.is (json::decode ("1\\\\2"), "1\\2", "json::decode \\\\ -> \\");
|
||||
|
||||
t.is (JSON::encode ("1\x2"), "1\x2", "JSON::encode \\x -> \\x (NOP)");
|
||||
t.is (JSON::decode ("1\x2"), "1\x2", "JSON::decode \\x -> \\x (NOP)");
|
||||
t.is (json::encode ("1\x2"), "1\x2", "json::encode \\x -> \\x (NOP)");
|
||||
t.is (json::decode ("1\x2"), "1\x2", "json::decode \\x -> \\x (NOP)");
|
||||
|
||||
t.is (JSON::encode ("1€2"), "1€2", "JSON::encode € -> €");
|
||||
t.is (JSON::decode ("1\\u20ac2"), "1€2", "JSON::decode \\u20ac -> €");
|
||||
t.is (json::encode ("1€2"), "1€2", "json::encode € -> €");
|
||||
t.is (json::decode ("1\\u20ac2"), "1€2", "json::decode \\u20ac -> €");
|
||||
|
||||
/*
|
||||
{
|
||||
|
@ -131,10 +160,17 @@ int main (int argc, char** argv)
|
|||
}
|
||||
*/
|
||||
input = "{\"ticket\":{\"type\":\"synch\",\"client\":\"taskd-test-suite 1.0\"},\"synch\":{\"user\":{\"data\":[{\"uuid\":\"11111111-1111-1111-1111-111111111111\",\"status\":\"pending\",\"description\":\"This is a test\",\"entry\":\"20110111T124000Z\"}],\"synch\":\"key\"}},\"auth\":{\"org\":\"gbf\",\"user\":\"Paul Beckingham\",\"key\":\"K\",\"locale\":\"en-US\"}}";
|
||||
std::cout << "-- j4 -------------------\n"
|
||||
<< "input: " << input << "\n";
|
||||
JSON j5 (input);
|
||||
j5.tree ()->dump ();
|
||||
std::cout << "# -- j5 -------------------\n"
|
||||
<< "# input: " << input << "\n";
|
||||
root = json::parse (input);
|
||||
t.ok (root, "j5 parse ok");
|
||||
if (root)
|
||||
{
|
||||
t.diag ("output: " + root->dump ());
|
||||
delete root;
|
||||
}
|
||||
else
|
||||
t.fail ("j5 parse error");
|
||||
}
|
||||
|
||||
catch (std::string& e) {t.diag (e);}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue