Squashed 'src/univalue/' changes from 9ef5b78c1..98fadc090
98fadc090 Merge #24: Push bool into array correctly 5f03f1f39 Push bool into array correctly 98261b1e7 Merge #22: Clamp JSON object depth to PHP limit 54c401541 Clamp JSON object depth to PHP limit 5a58a4667 Merge #21: Remove hand-coded UniValue destructor. b4cdfc4f4 Remove hand-coded UniValue destructor. 7fba60b5a Merge #17: [docs] Update readme 4577454e7 Merge #13: Fix typo ac7e73cda [docs] Update readme 7890db99d Merge #11: Remove deprecated std pair wrappers 40e34852a Merge #14: Cleaned up namespace imports to reduce symbol collisions 4a4964729 Fix typo 85052a481 Remove deprecated std::pair wrappers 51d3ab34b Merge #10: Add pushKV(key, boolean) function (replaces #5) 129bad96d [tests] test pushKV for boolean values b3c44c947 Pushing boolean value to univalue correctly 07947ff2d Merge #9: [tests] Fix BOOST_CHECK_THROW macro ec849d9a2 [tests] Fix BOOST_CHECK_THROW macro d208f986d Cleaned up namespace imports to reduce symbol collisions 31bc9f5a4 Merge #8: Remove unused Homebrew workaround fa042093d Remove HomeBrew workaround a523e08ae Merge #7: Declare single-argument (non-converting) constructors "explicit" a9e53b38b Merge #4: Pull upstream fe805ea74 Declare single-argument (non-converting) constructors "explicit" 8a2d6f1e3 Merge pull request #41 from jgarzik/get-obj-map ba341a20d Add getObjMap() helper method. Also, constify checkObject(). ceb119413 Handle .pushKV() and .checkObject() edge cases. 107db9829 Add ::push_back(double) method for feature parity. d41530031 Move one-line implementation of UniValue::read() to header. 52e85b35b Move exception-throwing get_* methods into separate implementation module. dac529675 README.md: update code quotes 3e31dcffb README.md: close code quote d09b8429d Update README.md f1b86edb4 Convert README to markdown style. 1dfe464ef Import UniValue class unit tests from bitcoin project. 0d3e74dd1 operator[] takes size_t index parameter (versus unsigned int) 640158fa2 Private findKey() method becomes size_t clean, and returns bool on failure. 709913585 Merge pull request #36 from ryanofsky/pr/end-str 4fd5444d1 Reject unterminated strings 16a1f7f6e Merge #3: Pull upstream daf1285af Merge pull request #2 from jgarzik/master f32df99e9 Merge branch '2016_04_unicode' into bitcoin 280b191cb Merge remote-tracking branch 'jgarzik/master' into bitcoin 2740c4f71 Merge branch '2015_11_escape_plan' into bitcoin REVERT: 9ef5b78c1 Use size_t for UniValue array indexing git-subtree-dir: src/univalue git-subtree-split: 98fadc090984fa7e070b6c41ccb514f69a371c85
This commit is contained in:
parent
a4071034f6
commit
9e26ae1c78
|
@ -25,7 +25,6 @@ addons:
|
|||
- pkg-config
|
||||
|
||||
before_script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall libtool; brew install libtool; fi
|
||||
- if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi
|
||||
- test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh
|
||||
|
||||
|
|
11
Makefile.am
11
Makefile.am
|
@ -12,6 +12,7 @@ pkgconfig_DATA = pc/libunivalue.pc
|
|||
|
||||
libunivalue_la_SOURCES = \
|
||||
lib/univalue.cpp \
|
||||
lib/univalue_get.cpp \
|
||||
lib/univalue_read.cpp \
|
||||
lib/univalue_write.cpp
|
||||
|
||||
|
@ -20,7 +21,7 @@ libunivalue_la_LDFLAGS = \
|
|||
-no-undefined
|
||||
libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include
|
||||
|
||||
TESTS = test/unitester test/no_nul
|
||||
TESTS = test/object test/unitester test/no_nul
|
||||
|
||||
GENBIN = gen/gen$(BUILD_EXEEXT)
|
||||
GEN_SRCS = gen/gen.cpp
|
||||
|
@ -52,6 +53,11 @@ test_no_nul_LDADD = libunivalue.la
|
|||
test_no_nul_CXXFLAGS = -I$(top_srcdir)/include
|
||||
test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
|
||||
|
||||
test_object_SOURCES = test/object.cpp
|
||||
test_object_LDADD = libunivalue.la
|
||||
test_object_CXXFLAGS = -I$(top_srcdir)/include
|
||||
test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
|
||||
|
||||
TEST_FILES = \
|
||||
$(TEST_DATA_DIR)/fail10.json \
|
||||
$(TEST_DATA_DIR)/fail11.json \
|
||||
|
@ -88,6 +94,8 @@ TEST_FILES = \
|
|||
$(TEST_DATA_DIR)/fail40.json \
|
||||
$(TEST_DATA_DIR)/fail41.json \
|
||||
$(TEST_DATA_DIR)/fail42.json \
|
||||
$(TEST_DATA_DIR)/fail44.json \
|
||||
$(TEST_DATA_DIR)/fail45.json \
|
||||
$(TEST_DATA_DIR)/fail3.json \
|
||||
$(TEST_DATA_DIR)/fail4.json \
|
||||
$(TEST_DATA_DIR)/fail5.json \
|
||||
|
@ -98,6 +106,7 @@ TEST_FILES = \
|
|||
$(TEST_DATA_DIR)/pass1.json \
|
||||
$(TEST_DATA_DIR)/pass2.json \
|
||||
$(TEST_DATA_DIR)/pass3.json \
|
||||
$(TEST_DATA_DIR)/pass4.json \
|
||||
$(TEST_DATA_DIR)/round1.json \
|
||||
$(TEST_DATA_DIR)/round2.json \
|
||||
$(TEST_DATA_DIR)/round3.json \
|
||||
|
|
7
README
7
README
|
@ -1,7 +0,0 @@
|
|||
|
||||
UniValue
|
||||
|
||||
A universal value object, with JSON encoding (output) and decoding (input).
|
||||
|
||||
Built as a single dynamic RAII C++ object class, and no templates.
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
# UniValue
|
||||
|
||||
## Summary
|
||||
|
||||
A universal value class, with JSON encoding and decoding.
|
||||
|
||||
UniValue is an abstract data type that may be a null, boolean, string,
|
||||
number, array container, or a key/value dictionary container, nested to
|
||||
an arbitrary depth.
|
||||
|
||||
This class is aligned with the JSON standard, [RFC
|
||||
7159](https://tools.ietf.org/html/rfc7159.html).
|
||||
|
||||
## Library usage
|
||||
|
||||
This is a fork of univalue used by Bitcoin Core. It is not maintained for usage
|
||||
by other projects. Notably, the API may break in non-backward-compatible ways.
|
||||
|
||||
Other projects looking for a maintained library should use the upstream
|
||||
univalue at https://github.com/jgarzik/univalue.
|
|
@ -12,8 +12,6 @@
|
|||
#include <string.h>
|
||||
#include "univalue.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static bool initEscapes;
|
||||
static std::string escapes[256];
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define __UNIVALUE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -14,7 +15,6 @@
|
|||
#include <cassert>
|
||||
|
||||
#include <sstream> // .get_int64()
|
||||
#include <utility> // std::pair
|
||||
|
||||
class UniValue {
|
||||
public:
|
||||
|
@ -47,7 +47,6 @@ public:
|
|||
std::string s(val_);
|
||||
setStr(s);
|
||||
}
|
||||
~UniValue() {}
|
||||
|
||||
void clear();
|
||||
|
||||
|
@ -69,7 +68,8 @@ public:
|
|||
size_t size() const { return values.size(); }
|
||||
|
||||
bool getBool() const { return isTrue(); }
|
||||
bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes);
|
||||
void getObjMap(std::map<std::string,UniValue>& kv) const;
|
||||
bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes) const;
|
||||
const UniValue& operator[](const std::string& key) const;
|
||||
const UniValue& operator[](size_t index) const;
|
||||
bool exists(const std::string& key) const { size_t i; return findKey(key, i); }
|
||||
|
@ -100,12 +100,21 @@ public:
|
|||
UniValue tmpVal(val_);
|
||||
return push_back(tmpVal);
|
||||
}
|
||||
bool push_back(bool val_) {
|
||||
UniValue tmpVal(val_);
|
||||
return push_back(tmpVal);
|
||||
}
|
||||
bool push_back(int val_) {
|
||||
UniValue tmpVal(val_);
|
||||
return push_back(tmpVal);
|
||||
}
|
||||
bool push_back(double val_) {
|
||||
UniValue tmpVal(val_);
|
||||
return push_back(tmpVal);
|
||||
}
|
||||
bool push_backV(const std::vector<UniValue>& vec);
|
||||
|
||||
void __pushKV(const std::string& key, const UniValue& val);
|
||||
bool pushKV(const std::string& key, const UniValue& val);
|
||||
bool pushKV(const std::string& key, const std::string& val_) {
|
||||
UniValue tmpVal(VSTR, val_);
|
||||
|
@ -123,6 +132,10 @@ public:
|
|||
UniValue tmpVal(val_);
|
||||
return pushKV(key, tmpVal);
|
||||
}
|
||||
bool pushKV(const std::string& key, bool val_) {
|
||||
UniValue tmpVal(val_);
|
||||
return pushKV(key, tmpVal);
|
||||
}
|
||||
bool pushKV(const std::string& key, int val_) {
|
||||
UniValue tmpVal((int64_t)val_);
|
||||
return pushKV(key, tmpVal);
|
||||
|
@ -137,7 +150,7 @@ public:
|
|||
unsigned int indentLevel = 0) const;
|
||||
|
||||
bool read(const char *raw, size_t len);
|
||||
bool read(const char *raw);
|
||||
bool read(const char *raw) { return read(raw, strlen(raw)); }
|
||||
bool read(const std::string& rawStr) {
|
||||
return read(rawStr.data(), rawStr.size());
|
||||
}
|
||||
|
@ -148,7 +161,7 @@ private:
|
|||
std::vector<std::string> keys;
|
||||
std::vector<UniValue> values;
|
||||
|
||||
bool findKey(const std::string& key, size_t& ret) const;
|
||||
bool findKey(const std::string& key, size_t& retIdx) const;
|
||||
void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
|
||||
void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
|
||||
|
||||
|
@ -166,76 +179,9 @@ public:
|
|||
const UniValue& get_array() const;
|
||||
|
||||
enum VType type() const { return getType(); }
|
||||
bool push_back(std::pair<std::string,UniValue> pear) {
|
||||
return pushKV(pear.first, pear.second);
|
||||
}
|
||||
friend const UniValue& find_value( const UniValue& obj, const std::string& name);
|
||||
};
|
||||
|
||||
//
|
||||
// The following were added for compatibility with json_spirit.
|
||||
// Most duplicate other methods, and should be removed.
|
||||
//
|
||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, const char *cVal)
|
||||
{
|
||||
std::string key(cKey);
|
||||
UniValue uVal(cVal);
|
||||
return std::make_pair(key, uVal);
|
||||
}
|
||||
|
||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, std::string strVal)
|
||||
{
|
||||
std::string key(cKey);
|
||||
UniValue uVal(strVal);
|
||||
return std::make_pair(key, uVal);
|
||||
}
|
||||
|
||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, uint64_t u64Val)
|
||||
{
|
||||
std::string key(cKey);
|
||||
UniValue uVal(u64Val);
|
||||
return std::make_pair(key, uVal);
|
||||
}
|
||||
|
||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, int64_t i64Val)
|
||||
{
|
||||
std::string key(cKey);
|
||||
UniValue uVal(i64Val);
|
||||
return std::make_pair(key, uVal);
|
||||
}
|
||||
|
||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, bool iVal)
|
||||
{
|
||||
std::string key(cKey);
|
||||
UniValue uVal(iVal);
|
||||
return std::make_pair(key, uVal);
|
||||
}
|
||||
|
||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, int iVal)
|
||||
{
|
||||
std::string key(cKey);
|
||||
UniValue uVal(iVal);
|
||||
return std::make_pair(key, uVal);
|
||||
}
|
||||
|
||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, double dVal)
|
||||
{
|
||||
std::string key(cKey);
|
||||
UniValue uVal(dVal);
|
||||
return std::make_pair(key, uVal);
|
||||
}
|
||||
|
||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, const UniValue& uVal)
|
||||
{
|
||||
std::string key(cKey);
|
||||
return std::make_pair(key, uVal);
|
||||
}
|
||||
|
||||
static inline std::pair<std::string,UniValue> Pair(std::string key, const UniValue& uVal)
|
||||
{
|
||||
return std::make_pair(key, uVal);
|
||||
}
|
||||
|
||||
enum jtokentype {
|
||||
JTOK_ERR = -1,
|
||||
JTOK_NONE = 0, // eof
|
||||
|
|
193
lib/univalue.cpp
193
lib/univalue.cpp
|
@ -4,77 +4,12 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "univalue.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
static bool ParsePrechecks(const std::string& str)
|
||||
{
|
||||
if (str.empty()) // No empty string allowed
|
||||
return false;
|
||||
if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed
|
||||
return false;
|
||||
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseInt32(const std::string& str, int32_t *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
char *endp = NULL;
|
||||
errno = 0; // strtol will not set errno if valid
|
||||
long int n = strtol(str.c_str(), &endp, 10);
|
||||
if(out) *out = (int32_t)n;
|
||||
// Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
|
||||
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
|
||||
// platforms the size of these types may be different.
|
||||
return endp && *endp == 0 && !errno &&
|
||||
n >= std::numeric_limits<int32_t>::min() &&
|
||||
n <= std::numeric_limits<int32_t>::max();
|
||||
}
|
||||
|
||||
bool ParseInt64(const std::string& str, int64_t *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
char *endp = NULL;
|
||||
errno = 0; // strtoll will not set errno if valid
|
||||
long long int n = strtoll(str.c_str(), &endp, 10);
|
||||
if(out) *out = (int64_t)n;
|
||||
// Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
|
||||
// we still have to check that the returned value is within the range of an *int64_t*.
|
||||
return endp && *endp == 0 && !errno &&
|
||||
n >= std::numeric_limits<int64_t>::min() &&
|
||||
n <= std::numeric_limits<int64_t>::max();
|
||||
}
|
||||
|
||||
bool ParseDouble(const std::string& str, double *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
|
||||
return false;
|
||||
std::istringstream text(str);
|
||||
text.imbue(std::locale::classic());
|
||||
double result;
|
||||
text >> result;
|
||||
if(out) *out = result;
|
||||
return text.eof() && !text.fail();
|
||||
}
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
const UniValue NullUniValue;
|
||||
|
||||
void UniValue::clear()
|
||||
|
@ -100,15 +35,15 @@ bool UniValue::setBool(bool val_)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool validNumStr(const string& s)
|
||||
static bool validNumStr(const std::string& s)
|
||||
{
|
||||
string tokenVal;
|
||||
std::string tokenVal;
|
||||
unsigned int consumed;
|
||||
enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size());
|
||||
return (tt == JTOK_NUMBER);
|
||||
}
|
||||
|
||||
bool UniValue::setNumStr(const string& val_)
|
||||
bool UniValue::setNumStr(const std::string& val_)
|
||||
{
|
||||
if (!validNumStr(val_))
|
||||
return false;
|
||||
|
@ -121,7 +56,7 @@ bool UniValue::setNumStr(const string& val_)
|
|||
|
||||
bool UniValue::setInt(uint64_t val_)
|
||||
{
|
||||
ostringstream oss;
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << val_;
|
||||
|
||||
|
@ -130,7 +65,7 @@ bool UniValue::setInt(uint64_t val_)
|
|||
|
||||
bool UniValue::setInt(int64_t val_)
|
||||
{
|
||||
ostringstream oss;
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << val_;
|
||||
|
||||
|
@ -139,7 +74,7 @@ bool UniValue::setInt(int64_t val_)
|
|||
|
||||
bool UniValue::setFloat(double val_)
|
||||
{
|
||||
ostringstream oss;
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << std::setprecision(16) << val_;
|
||||
|
||||
|
@ -148,7 +83,7 @@ bool UniValue::setFloat(double val_)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool UniValue::setStr(const string& val_)
|
||||
bool UniValue::setStr(const std::string& val_)
|
||||
{
|
||||
clear();
|
||||
typ = VSTR;
|
||||
|
@ -189,13 +124,22 @@ bool UniValue::push_backV(const std::vector<UniValue>& vec)
|
|||
return true;
|
||||
}
|
||||
|
||||
void UniValue::__pushKV(const std::string& key, const UniValue& val_)
|
||||
{
|
||||
keys.push_back(key);
|
||||
values.push_back(val_);
|
||||
}
|
||||
|
||||
bool UniValue::pushKV(const std::string& key, const UniValue& val_)
|
||||
{
|
||||
if (typ != VOBJ)
|
||||
return false;
|
||||
|
||||
keys.push_back(key);
|
||||
values.push_back(val_);
|
||||
size_t idx;
|
||||
if (findKey(key, idx))
|
||||
values[idx] = val_;
|
||||
else
|
||||
__pushKV(key, val_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -204,19 +148,27 @@ bool UniValue::pushKVs(const UniValue& obj)
|
|||
if (typ != VOBJ || obj.typ != VOBJ)
|
||||
return false;
|
||||
|
||||
for (unsigned int i = 0; i < obj.keys.size(); i++) {
|
||||
keys.push_back(obj.keys[i]);
|
||||
values.push_back(obj.values.at(i));
|
||||
}
|
||||
for (size_t i = 0; i < obj.keys.size(); i++)
|
||||
__pushKV(obj.keys[i], obj.values.at(i));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UniValue::findKey(const std::string& key, size_t& ret) const
|
||||
void UniValue::getObjMap(std::map<std::string,UniValue>& kv) const
|
||||
{
|
||||
if (typ != VOBJ)
|
||||
return;
|
||||
|
||||
kv.clear();
|
||||
for (size_t i = 0; i < keys.size(); i++)
|
||||
kv[keys[i]] = values[i];
|
||||
}
|
||||
|
||||
bool UniValue::findKey(const std::string& key, size_t& retIdx) const
|
||||
{
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
if (keys[i] == key) {
|
||||
ret = i;
|
||||
retIdx = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -224,11 +176,14 @@ bool UniValue::findKey(const std::string& key, size_t& ret) const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t)
|
||||
bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t) const
|
||||
{
|
||||
if (typ != VOBJ)
|
||||
return false;
|
||||
|
||||
for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin();
|
||||
it != t.end(); ++it) {
|
||||
size_t idx;
|
||||
size_t idx = 0;
|
||||
if (!findKey(it->first, idx))
|
||||
return false;
|
||||
|
||||
|
@ -244,7 +199,7 @@ const UniValue& UniValue::operator[](const std::string& key) const
|
|||
if (typ != VOBJ)
|
||||
return NullUniValue;
|
||||
|
||||
size_t index;
|
||||
size_t index = 0;
|
||||
if (!findKey(key, index))
|
||||
return NullUniValue;
|
||||
|
||||
|
@ -285,75 +240,3 @@ const UniValue& find_value(const UniValue& obj, const std::string& name)
|
|||
return NullUniValue;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& UniValue::getKeys() const
|
||||
{
|
||||
if (typ != VOBJ)
|
||||
throw std::runtime_error("JSON value is not an object as expected");
|
||||
return keys;
|
||||
}
|
||||
|
||||
const std::vector<UniValue>& UniValue::getValues() const
|
||||
{
|
||||
if (typ != VOBJ && typ != VARR)
|
||||
throw std::runtime_error("JSON value is not an object or array as expected");
|
||||
return values;
|
||||
}
|
||||
|
||||
bool UniValue::get_bool() const
|
||||
{
|
||||
if (typ != VBOOL)
|
||||
throw std::runtime_error("JSON value is not a boolean as expected");
|
||||
return getBool();
|
||||
}
|
||||
|
||||
const std::string& UniValue::get_str() const
|
||||
{
|
||||
if (typ != VSTR)
|
||||
throw std::runtime_error("JSON value is not a string as expected");
|
||||
return getValStr();
|
||||
}
|
||||
|
||||
int UniValue::get_int() const
|
||||
{
|
||||
if (typ != VNUM)
|
||||
throw std::runtime_error("JSON value is not an integer as expected");
|
||||
int32_t retval;
|
||||
if (!ParseInt32(getValStr(), &retval))
|
||||
throw std::runtime_error("JSON integer out of range");
|
||||
return retval;
|
||||
}
|
||||
|
||||
int64_t UniValue::get_int64() const
|
||||
{
|
||||
if (typ != VNUM)
|
||||
throw std::runtime_error("JSON value is not an integer as expected");
|
||||
int64_t retval;
|
||||
if (!ParseInt64(getValStr(), &retval))
|
||||
throw std::runtime_error("JSON integer out of range");
|
||||
return retval;
|
||||
}
|
||||
|
||||
double UniValue::get_real() const
|
||||
{
|
||||
if (typ != VNUM)
|
||||
throw std::runtime_error("JSON value is not a number as expected");
|
||||
double retval;
|
||||
if (!ParseDouble(getValStr(), &retval))
|
||||
throw std::runtime_error("JSON double out of range");
|
||||
return retval;
|
||||
}
|
||||
|
||||
const UniValue& UniValue::get_obj() const
|
||||
{
|
||||
if (typ != VOBJ)
|
||||
throw std::runtime_error("JSON value is not an object as expected");
|
||||
return *this;
|
||||
}
|
||||
|
||||
const UniValue& UniValue::get_array() const
|
||||
{
|
||||
if (typ != VARR)
|
||||
throw std::runtime_error("JSON value is not an array as expected");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright 2014 BitPay Inc.
|
||||
// Copyright 2015 Bitcoin Core Developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "univalue.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
static bool ParsePrechecks(const std::string& str)
|
||||
{
|
||||
if (str.empty()) // No empty string allowed
|
||||
return false;
|
||||
if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed
|
||||
return false;
|
||||
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseInt32(const std::string& str, int32_t *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
char *endp = NULL;
|
||||
errno = 0; // strtol will not set errno if valid
|
||||
long int n = strtol(str.c_str(), &endp, 10);
|
||||
if(out) *out = (int32_t)n;
|
||||
// Note that strtol returns a *long int*, so even if strtol doesn't report an over/underflow
|
||||
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
|
||||
// platforms the size of these types may be different.
|
||||
return endp && *endp == 0 && !errno &&
|
||||
n >= std::numeric_limits<int32_t>::min() &&
|
||||
n <= std::numeric_limits<int32_t>::max();
|
||||
}
|
||||
|
||||
bool ParseInt64(const std::string& str, int64_t *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
char *endp = NULL;
|
||||
errno = 0; // strtoll will not set errno if valid
|
||||
long long int n = strtoll(str.c_str(), &endp, 10);
|
||||
if(out) *out = (int64_t)n;
|
||||
// Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
|
||||
// we still have to check that the returned value is within the range of an *int64_t*.
|
||||
return endp && *endp == 0 && !errno &&
|
||||
n >= std::numeric_limits<int64_t>::min() &&
|
||||
n <= std::numeric_limits<int64_t>::max();
|
||||
}
|
||||
|
||||
bool ParseDouble(const std::string& str, double *out)
|
||||
{
|
||||
if (!ParsePrechecks(str))
|
||||
return false;
|
||||
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
|
||||
return false;
|
||||
std::istringstream text(str);
|
||||
text.imbue(std::locale::classic());
|
||||
double result;
|
||||
text >> result;
|
||||
if(out) *out = result;
|
||||
return text.eof() && !text.fail();
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::string>& UniValue::getKeys() const
|
||||
{
|
||||
if (typ != VOBJ)
|
||||
throw std::runtime_error("JSON value is not an object as expected");
|
||||
return keys;
|
||||
}
|
||||
|
||||
const std::vector<UniValue>& UniValue::getValues() const
|
||||
{
|
||||
if (typ != VOBJ && typ != VARR)
|
||||
throw std::runtime_error("JSON value is not an object or array as expected");
|
||||
return values;
|
||||
}
|
||||
|
||||
bool UniValue::get_bool() const
|
||||
{
|
||||
if (typ != VBOOL)
|
||||
throw std::runtime_error("JSON value is not a boolean as expected");
|
||||
return getBool();
|
||||
}
|
||||
|
||||
const std::string& UniValue::get_str() const
|
||||
{
|
||||
if (typ != VSTR)
|
||||
throw std::runtime_error("JSON value is not a string as expected");
|
||||
return getValStr();
|
||||
}
|
||||
|
||||
int UniValue::get_int() const
|
||||
{
|
||||
if (typ != VNUM)
|
||||
throw std::runtime_error("JSON value is not an integer as expected");
|
||||
int32_t retval;
|
||||
if (!ParseInt32(getValStr(), &retval))
|
||||
throw std::runtime_error("JSON integer out of range");
|
||||
return retval;
|
||||
}
|
||||
|
||||
int64_t UniValue::get_int64() const
|
||||
{
|
||||
if (typ != VNUM)
|
||||
throw std::runtime_error("JSON value is not an integer as expected");
|
||||
int64_t retval;
|
||||
if (!ParseInt64(getValStr(), &retval))
|
||||
throw std::runtime_error("JSON integer out of range");
|
||||
return retval;
|
||||
}
|
||||
|
||||
double UniValue::get_real() const
|
||||
{
|
||||
if (typ != VNUM)
|
||||
throw std::runtime_error("JSON value is not a number as expected");
|
||||
double retval;
|
||||
if (!ParseDouble(getValStr(), &retval))
|
||||
throw std::runtime_error("JSON double out of range");
|
||||
return retval;
|
||||
}
|
||||
|
||||
const UniValue& UniValue::get_obj() const
|
||||
{
|
||||
if (typ != VOBJ)
|
||||
throw std::runtime_error("JSON value is not an object as expected");
|
||||
return *this;
|
||||
}
|
||||
|
||||
const UniValue& UniValue::get_array() const
|
||||
{
|
||||
if (typ != VARR)
|
||||
throw std::runtime_error("JSON value is not an array as expected");
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -8,7 +8,13 @@
|
|||
#include "univalue.h"
|
||||
#include "univalue_utffilter.h"
|
||||
|
||||
using namespace std;
|
||||
/*
|
||||
* According to stackexchange, the original json test suite wanted
|
||||
* to limit depth to 22. Widely-deployed PHP bails at depth 512,
|
||||
* so we will follow PHP's lead, which should be more than sufficient
|
||||
* (further stackexchange comments indicate depth > 32 rarely occurs).
|
||||
*/
|
||||
static const size_t MAX_JSON_DEPTH = 512;
|
||||
|
||||
static bool json_isdigit(int ch)
|
||||
{
|
||||
|
@ -42,7 +48,7 @@ static const char *hatoui(const char *first, const char *last,
|
|||
return first;
|
||||
}
|
||||
|
||||
enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
||||
enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed,
|
||||
const char *raw, const char *end)
|
||||
{
|
||||
tokenVal.clear();
|
||||
|
@ -114,7 +120,7 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
|||
case '8':
|
||||
case '9': {
|
||||
// part 1: int
|
||||
string numStr;
|
||||
std::string numStr;
|
||||
|
||||
const char *first = raw;
|
||||
|
||||
|
@ -174,11 +180,11 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
|||
case '"': {
|
||||
raw++; // skip "
|
||||
|
||||
string valStr;
|
||||
std::string valStr;
|
||||
JSONUTF8StringFilter writer(valStr);
|
||||
|
||||
while (raw < end) {
|
||||
if ((unsigned char)*raw < 0x20)
|
||||
while (true) {
|
||||
if (raw >= end || (unsigned char)*raw < 0x20)
|
||||
return JTOK_ERR;
|
||||
|
||||
else if (*raw == '\\') {
|
||||
|
@ -255,9 +261,9 @@ bool UniValue::read(const char *raw, size_t size)
|
|||
clear();
|
||||
|
||||
uint32_t expectMask = 0;
|
||||
vector<UniValue*> stack;
|
||||
std::vector<UniValue*> stack;
|
||||
|
||||
string tokenVal;
|
||||
std::string tokenVal;
|
||||
unsigned int consumed;
|
||||
enum jtokentype tok = JTOK_NONE;
|
||||
enum jtokentype last_tok = JTOK_NONE;
|
||||
|
@ -325,6 +331,9 @@ bool UniValue::read(const char *raw, size_t size)
|
|||
stack.push_back(newTop);
|
||||
}
|
||||
|
||||
if (stack.size() > MAX_JSON_DEPTH)
|
||||
return false;
|
||||
|
||||
if (utyp == VOBJ)
|
||||
setExpect(OBJ_NAME);
|
||||
else
|
||||
|
@ -449,6 +458,3 @@ bool UniValue::read(const char *raw, size_t size)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool UniValue::read(const char *raw) {
|
||||
return read(raw, strlen(raw));
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
class JSONUTF8StringFilter
|
||||
{
|
||||
public:
|
||||
JSONUTF8StringFilter(std::string &s):
|
||||
explicit JSONUTF8StringFilter(std::string &s):
|
||||
str(s), is_valid(true), codepoint(0), state(0), surpair(0)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -8,11 +8,9 @@
|
|||
#include "univalue.h"
|
||||
#include "univalue_escapes.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static string json_escape(const string& inS)
|
||||
static std::string json_escape(const std::string& inS)
|
||||
{
|
||||
string outS;
|
||||
std::string outS;
|
||||
outS.reserve(inS.size() * 2);
|
||||
|
||||
for (unsigned int i = 0; i < inS.size(); i++) {
|
||||
|
@ -28,10 +26,10 @@ static string json_escape(const string& inS)
|
|||
return outS;
|
||||
}
|
||||
|
||||
string UniValue::write(unsigned int prettyIndent,
|
||||
unsigned int indentLevel) const
|
||||
std::string UniValue::write(unsigned int prettyIndent,
|
||||
unsigned int indentLevel) const
|
||||
{
|
||||
string s;
|
||||
std::string s;
|
||||
s.reserve(1024);
|
||||
|
||||
unsigned int modIndent = indentLevel;
|
||||
|
@ -62,12 +60,12 @@ string UniValue::write(unsigned int prettyIndent,
|
|||
return s;
|
||||
}
|
||||
|
||||
static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, string& s)
|
||||
static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, std::string& s)
|
||||
{
|
||||
s.append(prettyIndent * indentLevel, ' ');
|
||||
}
|
||||
|
||||
void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, string& s) const
|
||||
void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const
|
||||
{
|
||||
s += "[";
|
||||
if (prettyIndent)
|
||||
|
@ -89,7 +87,7 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s
|
|||
s += "]";
|
||||
}
|
||||
|
||||
void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, string& s) const
|
||||
void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const
|
||||
{
|
||||
s += "{";
|
||||
if (prettyIndent)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
object
|
||||
unitester
|
||||
test_json
|
||||
no_nul
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
"This file ends without a newline or close-quote.
|
|
@ -0,0 +1 @@
|
|||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
|
|
@ -0,0 +1,420 @@
|
|||
// Copyright (c) 2014 BitPay Inc.
|
||||
// Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <univalue.h>
|
||||
|
||||
#define BOOST_FIXTURE_TEST_SUITE(a, b)
|
||||
#define BOOST_AUTO_TEST_CASE(funcName) void funcName()
|
||||
#define BOOST_AUTO_TEST_SUITE_END()
|
||||
#define BOOST_CHECK(expr) assert(expr)
|
||||
#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2))
|
||||
#define BOOST_CHECK_THROW(stmt, excMatch) { \
|
||||
try { \
|
||||
(stmt); \
|
||||
assert(0 && "No exception caught"); \
|
||||
} catch (excMatch & e) { \
|
||||
} catch (...) { \
|
||||
assert(0 && "Wrong exception caught"); \
|
||||
} \
|
||||
}
|
||||
#define BOOST_CHECK_NO_THROW(stmt) { \
|
||||
try { \
|
||||
(stmt); \
|
||||
} catch (...) { \
|
||||
assert(0); \
|
||||
} \
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(univalue_constructor)
|
||||
{
|
||||
UniValue v1;
|
||||
BOOST_CHECK(v1.isNull());
|
||||
|
||||
UniValue v2(UniValue::VSTR);
|
||||
BOOST_CHECK(v2.isStr());
|
||||
|
||||
UniValue v3(UniValue::VSTR, "foo");
|
||||
BOOST_CHECK(v3.isStr());
|
||||
BOOST_CHECK_EQUAL(v3.getValStr(), "foo");
|
||||
|
||||
UniValue numTest;
|
||||
BOOST_CHECK(numTest.setNumStr("82"));
|
||||
BOOST_CHECK(numTest.isNum());
|
||||
BOOST_CHECK_EQUAL(numTest.getValStr(), "82");
|
||||
|
||||
uint64_t vu64 = 82;
|
||||
UniValue v4(vu64);
|
||||
BOOST_CHECK(v4.isNum());
|
||||
BOOST_CHECK_EQUAL(v4.getValStr(), "82");
|
||||
|
||||
int64_t vi64 = -82;
|
||||
UniValue v5(vi64);
|
||||
BOOST_CHECK(v5.isNum());
|
||||
BOOST_CHECK_EQUAL(v5.getValStr(), "-82");
|
||||
|
||||
int vi = -688;
|
||||
UniValue v6(vi);
|
||||
BOOST_CHECK(v6.isNum());
|
||||
BOOST_CHECK_EQUAL(v6.getValStr(), "-688");
|
||||
|
||||
double vd = -7.21;
|
||||
UniValue v7(vd);
|
||||
BOOST_CHECK(v7.isNum());
|
||||
BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
|
||||
|
||||
std::string vs("yawn");
|
||||
UniValue v8(vs);
|
||||
BOOST_CHECK(v8.isStr());
|
||||
BOOST_CHECK_EQUAL(v8.getValStr(), "yawn");
|
||||
|
||||
const char *vcs = "zappa";
|
||||
UniValue v9(vcs);
|
||||
BOOST_CHECK(v9.isStr());
|
||||
BOOST_CHECK_EQUAL(v9.getValStr(), "zappa");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(univalue_typecheck)
|
||||
{
|
||||
UniValue v1;
|
||||
BOOST_CHECK(v1.setNumStr("1"));
|
||||
BOOST_CHECK(v1.isNum());
|
||||
BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error);
|
||||
|
||||
UniValue v2;
|
||||
BOOST_CHECK(v2.setBool(true));
|
||||
BOOST_CHECK_EQUAL(v2.get_bool(), true);
|
||||
BOOST_CHECK_THROW(v2.get_int(), std::runtime_error);
|
||||
|
||||
UniValue v3;
|
||||
BOOST_CHECK(v3.setNumStr("32482348723847471234"));
|
||||
BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error);
|
||||
BOOST_CHECK(v3.setNumStr("1000"));
|
||||
BOOST_CHECK_EQUAL(v3.get_int64(), 1000);
|
||||
|
||||
UniValue v4;
|
||||
BOOST_CHECK(v4.setNumStr("2147483648"));
|
||||
BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648);
|
||||
BOOST_CHECK_THROW(v4.get_int(), std::runtime_error);
|
||||
BOOST_CHECK(v4.setNumStr("1000"));
|
||||
BOOST_CHECK_EQUAL(v4.get_int(), 1000);
|
||||
BOOST_CHECK_THROW(v4.get_str(), std::runtime_error);
|
||||
BOOST_CHECK_EQUAL(v4.get_real(), 1000);
|
||||
BOOST_CHECK_THROW(v4.get_array(), std::runtime_error);
|
||||
BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error);
|
||||
BOOST_CHECK_THROW(v4.getValues(), std::runtime_error);
|
||||
BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error);
|
||||
|
||||
UniValue v5;
|
||||
BOOST_CHECK(v5.read("[true, 10]"));
|
||||
BOOST_CHECK_NO_THROW(v5.get_array());
|
||||
std::vector<UniValue> vals = v5.getValues();
|
||||
BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error);
|
||||
BOOST_CHECK_EQUAL(vals[0].get_bool(), true);
|
||||
|
||||
BOOST_CHECK_EQUAL(vals[1].get_int(), 10);
|
||||
BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(univalue_set)
|
||||
{
|
||||
UniValue v(UniValue::VSTR, "foo");
|
||||
v.clear();
|
||||
BOOST_CHECK(v.isNull());
|
||||
BOOST_CHECK_EQUAL(v.getValStr(), "");
|
||||
|
||||
BOOST_CHECK(v.setObject());
|
||||
BOOST_CHECK(v.isObject());
|
||||
BOOST_CHECK_EQUAL(v.size(), 0);
|
||||
BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
|
||||
BOOST_CHECK(v.empty());
|
||||
|
||||
BOOST_CHECK(v.setArray());
|
||||
BOOST_CHECK(v.isArray());
|
||||
BOOST_CHECK_EQUAL(v.size(), 0);
|
||||
|
||||
BOOST_CHECK(v.setStr("zum"));
|
||||
BOOST_CHECK(v.isStr());
|
||||
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
|
||||
|
||||
BOOST_CHECK(v.setFloat(-1.01));
|
||||
BOOST_CHECK(v.isNum());
|
||||
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
|
||||
|
||||
BOOST_CHECK(v.setInt((int)1023));
|
||||
BOOST_CHECK(v.isNum());
|
||||
BOOST_CHECK_EQUAL(v.getValStr(), "1023");
|
||||
|
||||
BOOST_CHECK(v.setInt((int64_t)-1023LL));
|
||||
BOOST_CHECK(v.isNum());
|
||||
BOOST_CHECK_EQUAL(v.getValStr(), "-1023");
|
||||
|
||||
BOOST_CHECK(v.setInt((uint64_t)1023ULL));
|
||||
BOOST_CHECK(v.isNum());
|
||||
BOOST_CHECK_EQUAL(v.getValStr(), "1023");
|
||||
|
||||
BOOST_CHECK(v.setNumStr("-688"));
|
||||
BOOST_CHECK(v.isNum());
|
||||
BOOST_CHECK_EQUAL(v.getValStr(), "-688");
|
||||
|
||||
BOOST_CHECK(v.setBool(false));
|
||||
BOOST_CHECK_EQUAL(v.isBool(), true);
|
||||
BOOST_CHECK_EQUAL(v.isTrue(), false);
|
||||
BOOST_CHECK_EQUAL(v.isFalse(), true);
|
||||
BOOST_CHECK_EQUAL(v.getBool(), false);
|
||||
|
||||
BOOST_CHECK(v.setBool(true));
|
||||
BOOST_CHECK_EQUAL(v.isBool(), true);
|
||||
BOOST_CHECK_EQUAL(v.isTrue(), true);
|
||||
BOOST_CHECK_EQUAL(v.isFalse(), false);
|
||||
BOOST_CHECK_EQUAL(v.getBool(), true);
|
||||
|
||||
BOOST_CHECK(!v.setNumStr("zombocom"));
|
||||
|
||||
BOOST_CHECK(v.setNull());
|
||||
BOOST_CHECK(v.isNull());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(univalue_array)
|
||||
{
|
||||
UniValue arr(UniValue::VARR);
|
||||
|
||||
UniValue v((int64_t)1023LL);
|
||||
BOOST_CHECK(arr.push_back(v));
|
||||
|
||||
std::string vStr("zippy");
|
||||
BOOST_CHECK(arr.push_back(vStr));
|
||||
|
||||
const char *s = "pippy";
|
||||
BOOST_CHECK(arr.push_back(s));
|
||||
|
||||
std::vector<UniValue> vec;
|
||||
v.setStr("boing");
|
||||
vec.push_back(v);
|
||||
|
||||
v.setStr("going");
|
||||
vec.push_back(v);
|
||||
|
||||
BOOST_CHECK(arr.push_backV(vec));
|
||||
|
||||
BOOST_CHECK(arr.push_back((uint64_t) 400ULL));
|
||||
BOOST_CHECK(arr.push_back((int64_t) -400LL));
|
||||
BOOST_CHECK(arr.push_back((int) -401));
|
||||
BOOST_CHECK(arr.push_back(-40.1));
|
||||
BOOST_CHECK(arr.push_back(true));
|
||||
|
||||
BOOST_CHECK_EQUAL(arr.empty(), false);
|
||||
BOOST_CHECK_EQUAL(arr.size(), 10);
|
||||
|
||||
BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
|
||||
BOOST_CHECK_EQUAL(arr[0].getType(), UniValue::VNUM);
|
||||
BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
|
||||
BOOST_CHECK_EQUAL(arr[1].getType(), UniValue::VSTR);
|
||||
BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy");
|
||||
BOOST_CHECK_EQUAL(arr[2].getType(), UniValue::VSTR);
|
||||
BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing");
|
||||
BOOST_CHECK_EQUAL(arr[3].getType(), UniValue::VSTR);
|
||||
BOOST_CHECK_EQUAL(arr[4].getValStr(), "going");
|
||||
BOOST_CHECK_EQUAL(arr[4].getType(), UniValue::VSTR);
|
||||
BOOST_CHECK_EQUAL(arr[5].getValStr(), "400");
|
||||
BOOST_CHECK_EQUAL(arr[5].getType(), UniValue::VNUM);
|
||||
BOOST_CHECK_EQUAL(arr[6].getValStr(), "-400");
|
||||
BOOST_CHECK_EQUAL(arr[6].getType(), UniValue::VNUM);
|
||||
BOOST_CHECK_EQUAL(arr[7].getValStr(), "-401");
|
||||
BOOST_CHECK_EQUAL(arr[7].getType(), UniValue::VNUM);
|
||||
BOOST_CHECK_EQUAL(arr[8].getValStr(), "-40.1");
|
||||
BOOST_CHECK_EQUAL(arr[8].getType(), UniValue::VNUM);
|
||||
BOOST_CHECK_EQUAL(arr[9].getValStr(), "1");
|
||||
BOOST_CHECK_EQUAL(arr[9].getType(), UniValue::VBOOL);
|
||||
|
||||
BOOST_CHECK_EQUAL(arr[999].getValStr(), "");
|
||||
|
||||
arr.clear();
|
||||
BOOST_CHECK(arr.empty());
|
||||
BOOST_CHECK_EQUAL(arr.size(), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(univalue_object)
|
||||
{
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
std::string strKey, strVal;
|
||||
UniValue v;
|
||||
|
||||
strKey = "age";
|
||||
v.setInt(100);
|
||||
BOOST_CHECK(obj.pushKV(strKey, v));
|
||||
|
||||
strKey = "first";
|
||||
strVal = "John";
|
||||
BOOST_CHECK(obj.pushKV(strKey, strVal));
|
||||
|
||||
strKey = "last";
|
||||
const char *cVal = "Smith";
|
||||
BOOST_CHECK(obj.pushKV(strKey, cVal));
|
||||
|
||||
strKey = "distance";
|
||||
BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25));
|
||||
|
||||
strKey = "time";
|
||||
BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600));
|
||||
|
||||
strKey = "calories";
|
||||
BOOST_CHECK(obj.pushKV(strKey, (int) 12));
|
||||
|
||||
strKey = "temperature";
|
||||
BOOST_CHECK(obj.pushKV(strKey, (double) 90.012));
|
||||
|
||||
strKey = "moon";
|
||||
BOOST_CHECK(obj.pushKV(strKey, true));
|
||||
|
||||
strKey = "spoon";
|
||||
BOOST_CHECK(obj.pushKV(strKey, false));
|
||||
|
||||
UniValue obj2(UniValue::VOBJ);
|
||||
BOOST_CHECK(obj2.pushKV("cat1", 9000));
|
||||
BOOST_CHECK(obj2.pushKV("cat2", 12345));
|
||||
|
||||
BOOST_CHECK(obj.pushKVs(obj2));
|
||||
|
||||
BOOST_CHECK_EQUAL(obj.empty(), false);
|
||||
BOOST_CHECK_EQUAL(obj.size(), 11);
|
||||
|
||||
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100");
|
||||
BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John");
|
||||
BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith");
|
||||
BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25");
|
||||
BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600");
|
||||
BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12");
|
||||
BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012");
|
||||
BOOST_CHECK_EQUAL(obj["moon"].getValStr(), "1");
|
||||
BOOST_CHECK_EQUAL(obj["spoon"].getValStr(), "");
|
||||
BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000");
|
||||
BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345");
|
||||
|
||||
BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), "");
|
||||
|
||||
BOOST_CHECK(obj.exists("age"));
|
||||
BOOST_CHECK(obj.exists("first"));
|
||||
BOOST_CHECK(obj.exists("last"));
|
||||
BOOST_CHECK(obj.exists("distance"));
|
||||
BOOST_CHECK(obj.exists("time"));
|
||||
BOOST_CHECK(obj.exists("calories"));
|
||||
BOOST_CHECK(obj.exists("temperature"));
|
||||
BOOST_CHECK(obj.exists("moon"));
|
||||
BOOST_CHECK(obj.exists("spoon"));
|
||||
BOOST_CHECK(obj.exists("cat1"));
|
||||
BOOST_CHECK(obj.exists("cat2"));
|
||||
|
||||
BOOST_CHECK(!obj.exists("nyuknyuknyuk"));
|
||||
|
||||
std::map<std::string, UniValue::VType> objTypes;
|
||||
objTypes["age"] = UniValue::VNUM;
|
||||
objTypes["first"] = UniValue::VSTR;
|
||||
objTypes["last"] = UniValue::VSTR;
|
||||
objTypes["distance"] = UniValue::VNUM;
|
||||
objTypes["time"] = UniValue::VNUM;
|
||||
objTypes["calories"] = UniValue::VNUM;
|
||||
objTypes["temperature"] = UniValue::VNUM;
|
||||
objTypes["moon"] = UniValue::VBOOL;
|
||||
objTypes["spoon"] = UniValue::VBOOL;
|
||||
objTypes["cat1"] = UniValue::VNUM;
|
||||
objTypes["cat2"] = UniValue::VNUM;
|
||||
BOOST_CHECK(obj.checkObject(objTypes));
|
||||
|
||||
objTypes["cat2"] = UniValue::VSTR;
|
||||
BOOST_CHECK(!obj.checkObject(objTypes));
|
||||
|
||||
obj.clear();
|
||||
BOOST_CHECK(obj.empty());
|
||||
BOOST_CHECK_EQUAL(obj.size(), 0);
|
||||
BOOST_CHECK_EQUAL(obj.getType(), UniValue::VNULL);
|
||||
|
||||
BOOST_CHECK_EQUAL(obj.setObject(), true);
|
||||
UniValue uv;
|
||||
uv.setInt(42);
|
||||
obj.__pushKV("age", uv);
|
||||
BOOST_CHECK_EQUAL(obj.size(), 1);
|
||||
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "42");
|
||||
|
||||
uv.setInt(43);
|
||||
obj.pushKV("age", uv);
|
||||
BOOST_CHECK_EQUAL(obj.size(), 1);
|
||||
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "43");
|
||||
|
||||
obj.pushKV("name", "foo bar");
|
||||
|
||||
std::map<std::string,UniValue> kv;
|
||||
obj.getObjMap(kv);
|
||||
BOOST_CHECK_EQUAL(kv["age"].getValStr(), "43");
|
||||
BOOST_CHECK_EQUAL(kv["name"].getValStr(), "foo bar");
|
||||
|
||||
}
|
||||
|
||||
static const char *json1 =
|
||||
"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]";
|
||||
|
||||
BOOST_AUTO_TEST_CASE(univalue_readwrite)
|
||||
{
|
||||
UniValue v;
|
||||
BOOST_CHECK(v.read(json1));
|
||||
|
||||
std::string strJson1(json1);
|
||||
BOOST_CHECK(v.read(strJson1));
|
||||
|
||||
BOOST_CHECK(v.isArray());
|
||||
BOOST_CHECK_EQUAL(v.size(), 2);
|
||||
|
||||
BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000");
|
||||
|
||||
UniValue obj = v[1];
|
||||
BOOST_CHECK(obj.isObject());
|
||||
BOOST_CHECK_EQUAL(obj.size(), 3);
|
||||
|
||||
BOOST_CHECK(obj["key1"].isStr());
|
||||
std::string correctValue("str");
|
||||
correctValue.push_back('\0');
|
||||
BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue);
|
||||
BOOST_CHECK(obj["key2"].isNum());
|
||||
BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800");
|
||||
BOOST_CHECK(obj["key3"].isObject());
|
||||
|
||||
BOOST_CHECK_EQUAL(strJson1, v.write());
|
||||
|
||||
/* Check for (correctly reporting) a parsing error if the initial
|
||||
JSON construct is followed by more stuff. Note that whitespace
|
||||
is, of course, exempt. */
|
||||
|
||||
BOOST_CHECK(v.read(" {}\n "));
|
||||
BOOST_CHECK(v.isObject());
|
||||
BOOST_CHECK(v.read(" []\n "));
|
||||
BOOST_CHECK(v.isArray());
|
||||
|
||||
BOOST_CHECK(!v.read("@{}"));
|
||||
BOOST_CHECK(!v.read("{} garbage"));
|
||||
BOOST_CHECK(!v.read("[]{}"));
|
||||
BOOST_CHECK(!v.read("{}[]"));
|
||||
BOOST_CHECK(!v.read("{} 42"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
univalue_constructor();
|
||||
univalue_typecheck();
|
||||
univalue_set();
|
||||
univalue_array();
|
||||
univalue_object();
|
||||
univalue_readwrite();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
|
|
@ -17,8 +17,7 @@
|
|||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
string srcdir(JSON_TEST_SRC);
|
||||
std::string srcdir(JSON_TEST_SRC);
|
||||
static bool test_failed = false;
|
||||
|
||||
#define d_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", filename.c_str()); } }
|
||||
|
@ -30,9 +29,9 @@ static std::string rtrim(std::string s)
|
|||
return s;
|
||||
}
|
||||
|
||||
static void runtest(string filename, const string& jdata)
|
||||
static void runtest(std::string filename, const std::string& jdata)
|
||||
{
|
||||
string prefix = filename.substr(0, 4);
|
||||
std::string prefix = filename.substr(0, 4);
|
||||
|
||||
bool wantPass = (prefix == "pass") || (prefix == "roun");
|
||||
bool wantFail = (prefix == "fail");
|
||||
|
@ -56,19 +55,19 @@ static void runtest(string filename, const string& jdata)
|
|||
|
||||
static void runtest_file(const char *filename_)
|
||||
{
|
||||
string basename(filename_);
|
||||
string filename = srcdir + "/" + basename;
|
||||
std::string basename(filename_);
|
||||
std::string filename = srcdir + "/" + basename;
|
||||
FILE *f = fopen(filename.c_str(), "r");
|
||||
assert(f != NULL);
|
||||
|
||||
string jdata;
|
||||
std::string jdata;
|
||||
|
||||
char buf[4096];
|
||||
while (!feof(f)) {
|
||||
int bread = fread(buf, 1, sizeof(buf), f);
|
||||
assert(!ferror(f));
|
||||
|
||||
string s(buf, bread);
|
||||
std::string s(buf, bread);
|
||||
jdata += s;
|
||||
}
|
||||
|
||||
|
@ -114,6 +113,8 @@ static const char *filenames[] = {
|
|||
"fail40.json", // invalid unicode: broken UTF-8
|
||||
"fail41.json", // invalid unicode: unfinished UTF-8
|
||||
"fail42.json", // valid json with garbage following a nul byte
|
||||
"fail44.json", // unterminated string
|
||||
"fail45.json", // nested beyond max depth
|
||||
"fail3.json",
|
||||
"fail4.json", // extra comma
|
||||
"fail5.json",
|
||||
|
@ -124,6 +125,7 @@ static const char *filenames[] = {
|
|||
"pass1.json",
|
||||
"pass2.json",
|
||||
"pass3.json",
|
||||
"pass4.json",
|
||||
"round1.json", // round-trip test
|
||||
"round2.json", // unicode
|
||||
"round3.json", // bare string
|
||||
|
|
Loading…
Reference in New Issue