aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.test.include10
-rw-r--r--src/bitcoin-tx.cpp28
-rw-r--r--src/qt/forms/overviewpage.ui6
-rw-r--r--src/rpcserver.cpp5
-rw-r--r--src/serialize.h10
-rw-r--r--src/test/bctest.py43
-rwxr-xr-xsrc/test/bitcoin-util-test.py12
-rw-r--r--src/test/data/bitcoin-util-test.json9
-rw-r--r--src/test/data/blanktx.hex1
-rw-r--r--src/test/rpc_tests.cpp32
-rw-r--r--src/test/univalue_tests.cpp275
-rw-r--r--src/univalue/univalue.cpp2
-rw-r--r--src/univalue/univalue_write.cpp11
13 files changed, 409 insertions, 35 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index b54c9be66..bf6534cf3 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -1,8 +1,15 @@
-TESTS += test/test_bitcoin
+TESTS += test/test_bitcoin test/bitcoin-util-test.py
bin_PROGRAMS += test/test_bitcoin
TEST_SRCDIR = test
TEST_BINARY=test/test_bitcoin$(EXEEXT)
+
+EXTRA_DIST += \
+ test/bctest.py \
+ test/bitcoin-util-test.py \
+ test/data/bitcoin-util-test.json \
+ test/data/blanktx.hex
+
JSON_TEST_FILES = \
test/data/script_valid.json \
test/data/base58_keys_valid.json \
@@ -51,6 +58,7 @@ BITCOIN_TESTS =\
test/test_bitcoin.cpp \
test/transaction_tests.cpp \
test/uint256_tests.cpp \
+ test/univalue_tests.cpp \
test/util_tests.cpp \
test/scriptnum_tests.cpp \
test/sighash_tests.cpp
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index ffe87298f..6cd2768d7 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -13,6 +13,7 @@
#include <stdio.h>
#include <boost/assign/list_of.hpp>
+#include <boost/algorithm/string.hpp>
using namespace std;
using namespace boost::assign;
@@ -501,13 +502,34 @@ static void OutputTx(const CTransaction& tx)
OutputTxHex(tx);
}
+static string readStdin()
+{
+ char buf[4096];
+ string ret;
+
+ while (!feof(stdin)) {
+ size_t bread = fread(buf, 1, sizeof(buf), stdin);
+ ret.append(buf, bread);
+ if (bread < sizeof(buf))
+ break;
+ }
+
+ if (ferror(stdin))
+ throw runtime_error("error reading stdin");
+
+ boost::algorithm::trim_right(ret);
+
+ return ret;
+}
+
static int CommandLineRawTx(int argc, char* argv[])
{
string strPrint;
int nRet = 0;
try {
- // Skip switches
- while (argc > 1 && IsSwitchChar(argv[1][0])) {
+ // Skip switches; Permit common stdin convention "-"
+ while (argc > 1 && IsSwitchChar(argv[1][0]) &&
+ (argv[1][1] != 0)) {
argc--;
argv++;
}
@@ -522,6 +544,8 @@ static int CommandLineRawTx(int argc, char* argv[])
// param: hex-encoded bitcoin transaction
string strHexTx(argv[1]);
+ if (strHexTx == "-") // "-" implies standard input
+ strHexTx = readStdin();
if (!DecodeHexTx(txDecodeTmp, strHexTx))
throw runtime_error("invalid transaction encoding");
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 7784a862d..53d416ef3 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -13,8 +13,8 @@
<property name="windowTitle">
<string>Form</string>
</property>
- <layout class="QFormLayout" name="formLayout_3">
- <item row="0" column="0" colspan="2">
+ <layout class="QVBoxLayout" name="topLayout">
+ <item>
<widget class="QLabel" name="labelAlerts">
<property name="visible">
<bool>false</bool>
@@ -30,7 +30,7 @@
</property>
</widget>
</item>
- <item row="1" column="1">
+ <item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 3b51c91e7..524627e2d 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -849,11 +849,10 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
if (!HTTPAuthorized(mapHeaders))
{
LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
- /* Deter brute-forcing short passwords.
+ /* Deter brute-forcing
If this results in a DoS the user really
shouldn't have their RPC port exposed. */
- if (mapArgs["-rpcpassword"].size() < 20)
- MilliSleep(250);
+ MilliSleep(250);
conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;
return false;
diff --git a/src/serialize.h b/src/serialize.h
index 2eb69b3ec..3e5eff469 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -68,7 +68,7 @@ inline const T* end_ptr(const std::vector<T,TAl>& v)
/////////////////////////////////////////////////////////////////
//
// Templates for serializing to anything that looks like a stream,
-// i.e. anything that supports .read(char*, int) and .write(char*, int)
+// i.e. anything that supports .read(char*, size_t) and .write(char*, size_t)
//
enum
@@ -876,7 +876,7 @@ public:
CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {}
- CSizeComputer& write(const char *psz, int nSize)
+ CSizeComputer& write(const char *psz, size_t nSize)
{
this->nSize += nSize;
return *this;
@@ -1105,10 +1105,9 @@ public:
void ReadVersion() { *this >> nVersion; }
void WriteVersion() { *this << nVersion; }
- CDataStream& read(char* pch, int nSize)
+ CDataStream& read(char* pch, size_t nSize)
{
// Read from the beginning of the buffer
- assert(nSize >= 0);
unsigned int nReadPosNext = nReadPos + nSize;
if (nReadPosNext >= vch.size())
{
@@ -1145,10 +1144,9 @@ public:
return (*this);
}
- CDataStream& write(const char* pch, int nSize)
+ CDataStream& write(const char* pch, size_t nSize)
{
// Write to the end of the buffer
- assert(nSize >= 0);
vch.insert(vch.end(), pch, pch + nSize);
return (*this);
}
diff --git a/src/test/bctest.py b/src/test/bctest.py
new file mode 100644
index 000000000..b12647908
--- /dev/null
+++ b/src/test/bctest.py
@@ -0,0 +1,43 @@
+# Copyright 2014 BitPay, Inc.
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+import subprocess
+import os
+import json
+import sys
+
+def bctest(testDir, testObj):
+ execargs = testObj['exec']
+
+ stdinCfg = None
+ inputData = None
+ if "input" in testObj:
+ filename = testDir + "/" + testObj['input']
+ inputData = open(filename).read()
+ stdinCfg = subprocess.PIPE
+
+ outputFn = testObj['output_cmp']
+ outputData = open(testDir + "/" + outputFn).read()
+
+ proc = subprocess.Popen(execargs, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ try:
+ outs = proc.communicate(input=inputData)
+ except OSError:
+ print("OSError, Failed to execute " + execargs[0])
+ sys.exit(1)
+
+ if outs[0] != outputData:
+ print("Output data mismatch for " + outputFn)
+ sys.exit(1)
+
+def bctester(testDir, input_basename):
+ input_filename = testDir + "/" + input_basename
+ raw_data = open(input_filename).read()
+ input_data = json.loads(raw_data)
+
+ for testObj in input_data:
+ bctest(testDir, testObj)
+
+ sys.exit(0)
+
diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py
new file mode 100755
index 000000000..40690c2fe
--- /dev/null
+++ b/src/test/bitcoin-util-test.py
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+# Copyright 2014 BitPay, Inc.
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+import os
+import bctest
+
+if __name__ == '__main__':
+ bctest.bctester(os.environ["srcdir"] + "/test/data",
+ "bitcoin-util-test.json")
+
diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json
new file mode 100644
index 000000000..16bcb4489
--- /dev/null
+++ b/src/test/data/bitcoin-util-test.json
@@ -0,0 +1,9 @@
+[
+ { "exec": ["./bitcoin-tx", "-create"],
+ "output_cmp": "blanktx.hex"
+ },
+ { "exec": ["./bitcoin-tx", "-"],
+ "input": "blanktx.hex",
+ "output_cmp": "blanktx.hex"
+ }
+]
diff --git a/src/test/data/blanktx.hex b/src/test/data/blanktx.hex
new file mode 100644
index 000000000..36b6f00fb
--- /dev/null
+++ b/src/test/data/blanktx.hex
@@ -0,0 +1 @@
+01000000000000000000
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 107c0f06e..d5475a92b 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -110,14 +110,14 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign)
BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
{
- BOOST_CHECK(write_string(ValueFromAmount(0LL), false) == "0.00000000");
- BOOST_CHECK(write_string(ValueFromAmount(1LL), false) == "0.00000001");
- BOOST_CHECK(write_string(ValueFromAmount(17622195LL), false) == "0.17622195");
- BOOST_CHECK(write_string(ValueFromAmount(50000000LL), false) == "0.50000000");
- BOOST_CHECK(write_string(ValueFromAmount(89898989LL), false) == "0.89898989");
- BOOST_CHECK(write_string(ValueFromAmount(100000000LL), false) == "1.00000000");
- BOOST_CHECK(write_string(ValueFromAmount(2099999999999990LL), false) == "20999999.99999990");
- BOOST_CHECK(write_string(ValueFromAmount(2099999999999999LL), false) == "20999999.99999999");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(0LL), false), "0.00000000");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(1LL), false), "0.00000001");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(17622195LL), false), "0.17622195");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(50000000LL), false), "0.50000000");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(89898989LL), false), "0.89898989");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(100000000LL), false), "1.00000000");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999990LL), false), "20999999.99999990");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999999LL), false), "20999999.99999999");
}
static Value ValueFromString(const std::string &str)
@@ -129,14 +129,14 @@ static Value ValueFromString(const std::string &str)
BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
{
- BOOST_CHECK(AmountFromValue(ValueFromString("0.00000001")) == 1LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("0.17622195")) == 17622195LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("0.5")) == 50000000LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("0.50000000")) == 50000000LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("0.89898989")) == 89898989LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("1.00000000")) == 100000000LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("20999999.9999999")) == 2099999999999990LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("20999999.99999999")) == 2099999999999999LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.50000000")), 50000000LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.89898989")), 89898989LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1.00000000")), 100000000LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.9999999")), 2099999999999990LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.99999999")), 2099999999999999LL);
}
BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr)
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
new file mode 100644
index 000000000..23bc5f6b1
--- /dev/null
+++ b/src/test/univalue_tests.cpp
@@ -0,0 +1,275 @@
+// Copyright 2014 BitPay, Inc.
+// Distributed under the MIT/X11 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 "univalue/univalue.h"
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(univalue_tests)
+
+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");
+
+ 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_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.count(), 0);
+ BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
+ BOOST_CHECK(v.empty());
+
+ BOOST_CHECK(v.setArray());
+ BOOST_CHECK(v.isArray());
+ BOOST_CHECK_EQUAL(v.count(), 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));
+
+ string vStr("zippy");
+ BOOST_CHECK(arr.push_back(vStr));
+
+ const char *s = "pippy";
+ BOOST_CHECK(arr.push_back(s));
+
+ 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_EQUAL(arr.empty(), false);
+ BOOST_CHECK_EQUAL(arr.count(), 5);
+
+ 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[999].getValStr(), "");
+
+ arr.clear();
+ BOOST_CHECK(arr.empty());
+ BOOST_CHECK_EQUAL(arr.count(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(univalue_object)
+{
+ UniValue obj(UniValue::VOBJ);
+ 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.count(), 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"));
+
+ map<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.count(), 0);
+}
+
+static const char *json1 =
+"[1.1,{\"key1\":\"str\",\"key2\":800,\"key3\":{\"name\":\"martian\"}}]";
+
+BOOST_AUTO_TEST_CASE(univalue_readwrite)
+{
+ UniValue v;
+ BOOST_CHECK(v.read(json1));
+
+ string strJson1(json1);
+ BOOST_CHECK(v.read(strJson1));
+
+ BOOST_CHECK(v.isArray());
+ BOOST_CHECK_EQUAL(v.count(), 2);
+
+ BOOST_CHECK_EQUAL(v[0].getValStr(), "1.1");
+
+ UniValue obj = v[1];
+ BOOST_CHECK(obj.isObject());
+ BOOST_CHECK_EQUAL(obj.count(), 3);
+
+ BOOST_CHECK(obj["key1"].isStr());
+ BOOST_CHECK_EQUAL(obj["key1"].getValStr(), "str");
+ BOOST_CHECK(obj["key2"].isNum());
+ BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800");
+ BOOST_CHECK(obj["key3"].isObject());
+
+ BOOST_CHECK_EQUAL(strJson1, v.write());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp
index afc208bff..b0171e48c 100644
--- a/src/univalue/univalue.cpp
+++ b/src/univalue/univalue.cpp
@@ -44,7 +44,7 @@ static bool validNumStr(const string& s)
bool UniValue::setNumStr(const string& val_)
{
- if (!validNumStr(val))
+ if (!validNumStr(val_))
return false;
clear();
diff --git a/src/univalue/univalue_write.cpp b/src/univalue/univalue_write.cpp
index 70762a1ef..042091a82 100644
--- a/src/univalue/univalue_write.cpp
+++ b/src/univalue/univalue_write.cpp
@@ -91,8 +91,11 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s
if (prettyIndent)
s += indentStr(prettyIndent, indentLevel);
s += values[i].write(prettyIndent, indentLevel + 1);
- if (i != (values.size() - 1))
- s += ", ";
+ if (i != (values.size() - 1)) {
+ s += ",";
+ if (prettyIndent)
+ s += " ";
+ }
if (prettyIndent)
s += "\n";
}
@@ -111,7 +114,9 @@ void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel,
for (unsigned int i = 0; i < keys.size(); i++) {
if (prettyIndent)
s += indentStr(prettyIndent, indentLevel);
- s += "\"" + json_escape(keys[i]) + "\": ";
+ s += "\"" + json_escape(keys[i]) + "\":";
+ if (prettyIndent)
+ s += " ";
s += values[i].write(prettyIndent, indentLevel + 1);
if (i != (values.size() - 1))
s += ",";