Browse Source
This merge commit bumps the univalue subtree and also updates the whitespace for some failing tests.0.16
MarcoFalke
7 years ago
31 changed files with 851 additions and 297 deletions
@ -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,32 @@ |
|||||||
|
|
||||||
|
# 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). |
||||||
|
|
||||||
|
## Installation |
||||||
|
|
||||||
|
This project is a standard GNU |
||||||
|
[autotools](https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html) |
||||||
|
project. Build and install instructions are available in the `INSTALL` |
||||||
|
file provided with GNU autotools. |
||||||
|
|
||||||
|
``` |
||||||
|
$ ./autogen.sh |
||||||
|
$ ./configure |
||||||
|
$ make |
||||||
|
``` |
||||||
|
|
||||||
|
## Design |
||||||
|
|
||||||
|
UniValue provides a single dynamic RAII C++ object class, |
||||||
|
and minimizes template use (contra json_spirit). |
||||||
|
|
@ -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 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(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
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; |
||||||
|
} |
||||||
|
|
@ -1,4 +1,8 @@ |
|||||||
|
|
||||||
|
object |
||||||
unitester |
unitester |
||||||
|
test_json |
||||||
|
no_nul |
||||||
|
|
||||||
*.trs |
*.trs |
||||||
*.log |
*.log |
||||||
|
@ -1 +1 @@ |
|||||||
"A JSON payload should be an object or array, not a string." |
"This is a string that never ends, yes it goes on and on, my friends. |
||||||
|
Binary file not shown.
@ -0,0 +1 @@ |
|||||||
|
"This file ends without a newline or close-quote. |
@ -0,0 +1,8 @@ |
|||||||
|
#include "univalue.h" |
||||||
|
|
||||||
|
int main (int argc, char *argv[]) |
||||||
|
{ |
||||||
|
char buf[] = "___[1,2,3]___"; |
||||||
|
UniValue val; |
||||||
|
return val.read(buf + 3, 7) ? 0 : 1; |
||||||
|
} |
@ -0,0 +1,395 @@ |
|||||||
|
// 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); \ |
||||||
|
} catch (excMatch & e) { \ |
||||||
|
} catch (...) { \ |
||||||
|
assert(0); \ |
||||||
|
} \ |
||||||
|
} |
||||||
|
#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_EQUAL(arr.empty(), false); |
||||||
|
BOOST_CHECK_EQUAL(arr.size(), 9); |
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023"); |
||||||
|
BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy"); |
||||||
|
BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy"); |
||||||
|
BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing"); |
||||||
|
BOOST_CHECK_EQUAL(arr[4].getValStr(), "going"); |
||||||
|
BOOST_CHECK_EQUAL(arr[5].getValStr(), "400"); |
||||||
|
BOOST_CHECK_EQUAL(arr[6].getValStr(), "-400"); |
||||||
|
BOOST_CHECK_EQUAL(arr[7].getValStr(), "-401"); |
||||||
|
BOOST_CHECK_EQUAL(arr[8].getValStr(), "-40.1"); |
||||||
|
|
||||||
|
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)); |
||||||
|
|
||||||
|
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(), 9); |
||||||
|
|
||||||
|
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["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("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["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,24 @@ |
|||||||
|
// Test program that can be called by the JSON test suite at
|
||||||
|
// https://github.com/nst/JSONTestSuite.
|
||||||
|
//
|
||||||
|
// It reads JSON input from stdin and exits with code 0 if it can be parsed
|
||||||
|
// successfully. It also pretty prints the parsed JSON value to stdout.
|
||||||
|
|
||||||
|
#include <iostream> |
||||||
|
#include <string> |
||||||
|
#include "univalue.h" |
||||||
|
|
||||||
|
using namespace std; |
||||||
|
|
||||||
|
int main (int argc, char *argv[]) |
||||||
|
{ |
||||||
|
UniValue val; |
||||||
|
if (val.read(string(istreambuf_iterator<char>(cin), |
||||||
|
istreambuf_iterator<char>()))) { |
||||||
|
cout << val.write(1 /* prettyIndent */, 4 /* indentLevel */) << endl; |
||||||
|
return 0; |
||||||
|
} else { |
||||||
|
cerr << "JSON Parse Error." << endl; |
||||||
|
return 1; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue