aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/alert_tests.cpp65
-rw-r--r--src/test/base58_tests.cpp58
-rw-r--r--src/test/checkblock_tests.cpp9
-rw-r--r--src/test/coins_tests.cpp27
-rw-r--r--src/test/main_tests.cpp39
-rw-r--r--src/test/miner_tests.cpp14
-rw-r--r--src/test/netbase_tests.cpp5
-rw-r--r--src/test/policyestimator_tests.cpp186
-rw-r--r--src/test/rpc_tests.cpp64
-rw-r--r--src/test/rpc_wallet_tests.cpp15
-rw-r--r--src/test/scheduler_tests.cpp119
-rw-r--r--src/test/script_tests.cpp56
-rw-r--r--src/test/sighash_tests.cpp24
-rw-r--r--src/test/transaction_tests.cpp56
-rw-r--r--src/test/univalue_tests.cpp68
-rw-r--r--src/test/util_tests.cpp109
16 files changed, 729 insertions, 185 deletions
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index 6b6df5199a..22cb475e02 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -7,10 +7,12 @@
//
#include "alert.h"
+#include "chain.h"
+#include "chainparams.h"
#include "clientversion.h"
#include "data/alertTests.raw.h"
-#include "chainparams.h"
+#include "main.h"
#include "serialize.h"
#include "streams.h"
#include "util.h"
@@ -193,4 +195,65 @@ BOOST_AUTO_TEST_CASE(AlertNotify)
SetMockTime(0);
}
+static bool falseFunc() { return false; }
+
+BOOST_AUTO_TEST_CASE(PartitionAlert)
+{
+ // Test PartitionCheck
+ CCriticalSection csDummy;
+ CChain chainDummy;
+ CBlockIndex indexDummy[100];
+ CChainParams& params = Params(CBaseChainParams::MAIN);
+ int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing;
+
+ // Generate fake blockchain timestamps relative to
+ // an arbitrary time:
+ int64_t now = 1427379054;
+ SetMockTime(now);
+ for (int i = 0; i < 100; i++)
+ {
+ indexDummy[i].phashBlock = NULL;
+ if (i == 0) indexDummy[i].pprev = NULL;
+ else indexDummy[i].pprev = &indexDummy[i-1];
+ indexDummy[i].nHeight = i;
+ indexDummy[i].nTime = now - (100-i)*nPowTargetSpacing;
+ // Other members don't matter, the partition check code doesn't
+ // use them
+ }
+ chainDummy.SetTip(&indexDummy[99]);
+
+ // Test 1: chain with blocks every nPowTargetSpacing seconds,
+ // as normal, no worries:
+ PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ BOOST_CHECK(strMiscWarning.empty());
+
+ // Test 2: go 3.5 hours without a block, expect a warning:
+ now += 3*60*60+30*60;
+ SetMockTime(now);
+ PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ BOOST_CHECK(!strMiscWarning.empty());
+ BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
+ strMiscWarning = "";
+
+ // Test 3: test the "partition alerts only go off once per day"
+ // code:
+ now += 60*10;
+ SetMockTime(now);
+ PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ BOOST_CHECK(strMiscWarning.empty());
+
+ // Test 4: get 2.5 times as many blocks as expected:
+ now += 60*60*24; // Pretend it is a day later
+ SetMockTime(now);
+ int64_t quickSpacing = nPowTargetSpacing*2/5;
+ for (int i = 0; i < 100; i++) // Tweak chain timestamps:
+ indexDummy[i].nTime = now - (100-i)*quickSpacing;
+ PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ BOOST_CHECK(!strMiscWarning.empty());
+ BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
+ strMiscWarning = "";
+
+ SetMockTime(0);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index f07dd7a7db..9e74f5f427 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -17,23 +17,20 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
-using namespace json_spirit;
-extern Array read_json(const std::string& jsondata);
+#include "univalue/univalue.h"
+
+extern UniValue read_json(const std::string& jsondata);
BOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup)
// Goal: test low-level base58 encoding functionality
BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
{
- Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 2) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -50,13 +47,12 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
// Goal: test low-level base58 decoding functionality
BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
{
- Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
+ UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
std::vector<unsigned char> result;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 2) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -124,16 +120,15 @@ public:
// Goal: check that parsed keys match test payload
BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
- Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
+ UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
SelectParams(CBaseChainParams::MAIN);
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 3) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -141,7 +136,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
}
std::string exp_base58string = test[0].get_str();
std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
- const Object &metadata = test[2].get_obj();
+ const UniValue &metadata = test[2].get_obj();
bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
bool isTestnet = find_value(metadata, "isTestnet").get_bool();
if (isTestnet)
@@ -183,12 +178,12 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
// Goal: check that generated keys match test vectors
BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
{
- Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
+ UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
std::vector<unsigned char> result;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 3) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -196,7 +191,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
}
std::string exp_base58string = test[0].get_str();
std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
- const Object &metadata = test[2].get_obj();
+ const UniValue &metadata = test[2].get_obj();
bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
bool isTestnet = find_value(metadata, "isTestnet").get_bool();
if (isTestnet)
@@ -251,15 +246,14 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
// Goal: check that base58 parsing code is robust against a variety of corrupted data
BOOST_AUTO_TEST_CASE(base58_keys_invalid)
{
- Array tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
+ UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 1) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp
index 7abfad151e..51530c4de5 100644
--- a/src/test/checkblock_tests.cpp
+++ b/src/test/checkblock_tests.cpp
@@ -2,16 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-//
-// Unit tests for block.CheckBlock()
-//
-
-
-
#include "clientversion.h"
+#include "consensus/validation.h"
#include "main.h"
-#include "utiltime.h"
#include "test/test_bitcoin.h"
+#include "utiltime.h"
#include <cstdio>
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 2e2cc2214b..34b311b804 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -59,6 +59,24 @@ public:
bool GetStats(CCoinsStats& stats) const { return false; }
};
+
+class CCoinsViewCacheTest : public CCoinsViewCache
+{
+public:
+ CCoinsViewCacheTest(CCoinsView* base) : CCoinsViewCache(base) {}
+
+ void SelfTest() const
+ {
+ // Manually recompute the dynamic usage of the whole data, and compare it.
+ size_t ret = memusage::DynamicUsage(cacheCoins);
+ for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
+ ret += memusage::DynamicUsage(it->second.coins);
+ }
+ BOOST_CHECK_EQUAL(memusage::DynamicUsage(*this), ret);
+ }
+
+};
+
}
BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
@@ -90,8 +108,8 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
// The cache stack.
CCoinsViewTest base; // A CCoinsViewTest at the bottom.
- std::vector<CCoinsViewCache*> stack; // A stack of CCoinsViewCaches on top.
- stack.push_back(new CCoinsViewCache(&base)); // Start with one cache.
+ std::vector<CCoinsViewCacheTest*> stack; // A stack of CCoinsViewCaches on top.
+ stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache.
// Use a limited set of random transaction ids, so we do test overwriting entries.
std::vector<uint256> txids;
@@ -136,6 +154,9 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
missed_an_entry = true;
}
}
+ BOOST_FOREACH(const CCoinsViewCacheTest *test, stack) {
+ test->SelfTest();
+ }
}
if (insecure_rand() % 100 == 0) {
@@ -152,7 +173,7 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
} else {
removed_all_caches = true;
}
- stack.push_back(new CCoinsViewCache(tip));
+ stack.push_back(new CCoinsViewCacheTest(tip));
if (stack.size() == 4) {
reached_4_caches = true;
}
diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp
index 9ec533bcca..21ae46d6e9 100644
--- a/src/test/main_tests.cpp
+++ b/src/test/main_tests.cpp
@@ -2,25 +2,58 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "primitives/transaction.h"
+#include "chainparams.h"
#include "main.h"
#include "test/test_bitcoin.h"
+#include <boost/signals2/signal.hpp>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup)
+static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams)
+{
+ int maxHalvings = 64;
+ CAmount nInitialSubsidy = 50 * COIN;
+
+ CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 0
+ BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2);
+ for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) {
+ int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval;
+ CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
+ BOOST_CHECK(nSubsidy <= nInitialSubsidy);
+ BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2);
+ nPreviousSubsidy = nSubsidy;
+ }
+ BOOST_CHECK_EQUAL(GetBlockSubsidy(maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), 0);
+}
+
+static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval)
+{
+ Consensus::Params consensusParams;
+ consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval;
+ TestBlockSubsidyHalvings(consensusParams);
+}
+
+BOOST_AUTO_TEST_CASE(block_subsidy_test)
+{
+ TestBlockSubsidyHalvings(Params(CBaseChainParams::MAIN).GetConsensus()); // As in main
+ TestBlockSubsidyHalvings(150); // As in regtest
+ TestBlockSubsidyHalvings(1000); // Just another interval
+}
+
BOOST_AUTO_TEST_CASE(subsidy_limit_test)
{
+ const Consensus::Params& consensusParams = Params(CBaseChainParams::MAIN).GetConsensus();
CAmount nSum = 0;
for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) {
- CAmount nSubsidy = GetBlockValue(nHeight, 0);
+ CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
BOOST_CHECK(nSubsidy <= 50 * COIN);
nSum += nSubsidy * 1000;
BOOST_CHECK(MoneyRange(nSum));
}
- BOOST_CHECK(nSum == 2099999997690000ULL);
+ BOOST_CHECK_EQUAL(nSum, 2099999997690000ULL);
}
bool ReturnFalse() { return false; }
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index d7ea91607c..212be0d2d6 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "consensus/validation.h"
#include "main.h"
#include "miner.h"
#include "pubkey.h"
@@ -73,6 +74,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->nVersion = 1;
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
CMutableTransaction txCoinbase(pblock->vtx[0]);
+ txCoinbase.nVersion = 1;
txCoinbase.vin[0].scriptSig = CScript();
txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
@@ -83,7 +85,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
pblock->nNonce = blockinfo[i].nonce;
CValidationState state;
- BOOST_CHECK(ProcessNewBlock(state, NULL, pblock));
+ BOOST_CHECK(ProcessNewBlock(state, NULL, pblock, true, NULL));
BOOST_CHECK(state.IsValid());
pblock->hashPrevBlock = pblock->GetHash();
}
@@ -222,7 +224,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.nLockTime = chainActive.Tip()->nHeight+1;
hash = tx.GetHash();
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
- BOOST_CHECK(!IsFinalTx(tx, chainActive.Tip()->nHeight + 1));
+ BOOST_CHECK(!CheckFinalTx(tx));
// time locked
tx2.vin.resize(1);
@@ -236,7 +238,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1;
hash = tx2.GetHash();
mempool.addUnchecked(hash, CTxMemPoolEntry(tx2, 11, GetTime(), 111.0, 11));
- BOOST_CHECK(!IsFinalTx(tx2));
+ BOOST_CHECK(!CheckFinalTx(tx2));
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
@@ -248,8 +250,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
chainActive.Tip()->nHeight++;
SetMockTime(chainActive.Tip()->GetMedianTimePast()+2);
- BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 1));
- BOOST_CHECK(IsFinalTx(tx2));
+ // FIXME: we should *actually* create a new block so the following test
+ // works; CheckFinalTx() isn't fooled by monkey-patching nHeight.
+ //BOOST_CHECK(CheckFinalTx(tx));
+ //BOOST_CHECK(CheckFinalTx(tx2));
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3);
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index cb357d295c..0f5e1615c6 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -117,6 +117,11 @@ BOOST_AUTO_TEST_CASE(subnet_test)
BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:8")));
BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:9")));
BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:0/112").Match(CNetAddr("1:2:3:4:5:6:7:1234")));
+ BOOST_CHECK(CSubNet("192.168.0.1/24").Match(CNetAddr("192.168.0.2")));
+ BOOST_CHECK(CSubNet("192.168.0.20/29").Match(CNetAddr("192.168.0.18")));
+ BOOST_CHECK(CSubNet("1.2.2.1/24").Match(CNetAddr("1.2.2.4")));
+ BOOST_CHECK(CSubNet("1.2.2.110/31").Match(CNetAddr("1.2.2.111")));
+ BOOST_CHECK(CSubNet("1.2.2.20/26").Match(CNetAddr("1.2.2.63")));
// All-Matching IPv6 Matches arbitrary IPv4 and IPv6
BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1:2:3:4:5:6:7:1234")));
BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1.2.3.4")));
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
new file mode 100644
index 0000000000..cb64ee7c69
--- /dev/null
+++ b/src/test/policyestimator_tests.cpp
@@ -0,0 +1,186 @@
+// Copyright (c) 2011-2015 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 "policy/fees.h"
+#include "txmempool.h"
+#include "uint256.h"
+#include "util.h"
+
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
+{
+ CTxMemPool mpool(CFeeRate(1000));
+ CAmount basefee(2000);
+ double basepri = 1e6;
+ CAmount deltaFee(100);
+ double deltaPri=5e5;
+ std::vector<CAmount> feeV[2];
+ std::vector<double> priV[2];
+
+ // Populate vectors of increasing fees or priorities
+ for (int j = 0; j < 10; j++) {
+ //V[0] is for fee transactions
+ feeV[0].push_back(basefee * (j+1));
+ priV[0].push_back(0);
+ //V[1] is for priority transactions
+ feeV[1].push_back(CAmount(0));
+ priV[1].push_back(basepri * pow(10, j+1));
+ }
+
+ // Store the hashes of transactions that have been
+ // added to the mempool by their associate fee/pri
+ // txHashes[j] is populated with transactions either of
+ // fee = basefee * (j+1) OR pri = 10^6 * 10^(j+1)
+ std::vector<uint256> txHashes[10];
+
+ // Create a transaction template
+ CScript garbage;
+ for (unsigned int i = 0; i < 128; i++)
+ garbage.push_back('X');
+ CMutableTransaction tx;
+ std::list<CTransaction> dummyConflicted;
+ tx.vin.resize(1);
+ tx.vin[0].scriptSig = garbage;
+ tx.vout.resize(1);
+ tx.vout[0].nValue=0LL;
+ CFeeRate baseRate(basefee, ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION));
+
+ // Create a fake block
+ std::vector<CTransaction> block;
+ int blocknum = 0;
+
+ // Loop through 200 blocks
+ // At a decay .998 and 4 fee transactions per block
+ // This makes the tx count about 1.33 per bucket, above the 1 threshold
+ while (blocknum < 200) {
+ for (int j = 0; j < 10; j++) { // For each fee/pri multiple
+ for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
+ uint256 hash = tx.GetHash();
+ mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx)));
+ txHashes[j].push_back(hash);
+ }
+ }
+ //Create blocks where higher fee/pri txs are included more often
+ for (int h = 0; h <= blocknum%10; h++) {
+ // 10/10 blocks add highest fee/pri transactions
+ // 9/10 blocks add 2nd highest and so on until ...
+ // 1/10 blocks add lowest fee/pri transactions
+ while (txHashes[9-h].size()) {
+ CTransaction btx;
+ if (mpool.lookup(txHashes[9-h].back(), btx))
+ block.push_back(btx);
+ txHashes[9-h].pop_back();
+ }
+ }
+ mpool.removeForBlock(block, ++blocknum, dummyConflicted);
+ block.clear();
+ if (blocknum == 30) {
+ // At this point we should need to combine 5 buckets to get enough data points
+ // So estimateFee(1) should fail and estimateFee(2) should return somewhere around
+ // 8*baserate
+ BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
+ BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee);
+ BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee);
+ }
+ }
+
+ std::vector<CAmount> origFeeEst;
+ std::vector<double> origPriEst;
+ // Highest feerate is 10*baseRate and gets in all blocks,
+ // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%,
+ // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%,
+ // so estimateFee(1) should return 9*baseRate.
+ // Third highest feerate has 90% chance of being included by 2 blocks,
+ // so estimateFee(2) should return 8*baseRate etc...
+ for (int i = 1; i < 10;i++) {
+ origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
+ origPriEst.push_back(mpool.estimatePriority(i));
+ if (i > 1) { // Fee estimates should be monotonically decreasing
+ BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
+ BOOST_CHECK(origPriEst[i-1] <= origPriEst[i-2]);
+ }
+ BOOST_CHECK(origFeeEst[i-1] < (10-i)*baseRate.GetFeePerK() + deltaFee);
+ BOOST_CHECK(origFeeEst[i-1] > (10-i)*baseRate.GetFeePerK() - deltaFee);
+ BOOST_CHECK(origPriEst[i-1] < pow(10,10-i) * basepri + deltaPri);
+ BOOST_CHECK(origPriEst[i-1] > pow(10,10-i) * basepri - deltaPri);
+ }
+
+ // Mine 50 more blocks with no transactions happening, estimates shouldn't change
+ // We haven't decayed the moving average enough so we still have enough data points in every bucket
+ while (blocknum < 250)
+ mpool.removeForBlock(block, ++blocknum, dummyConflicted);
+
+ for (int i = 1; i < 10;i++) {
+ BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
+ BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] + deltaPri);
+ BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
+ }
+
+
+ // Mine 15 more blocks with lots of transactions happening and not getting mined
+ // Estimates should go up
+ while (blocknum < 265) {
+ for (int j = 0; j < 10; j++) { // For each fee/pri multiple
+ for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
+ uint256 hash = tx.GetHash();
+ mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx)));
+ txHashes[j].push_back(hash);
+ }
+ }
+ mpool.removeForBlock(block, ++blocknum, dummyConflicted);
+ }
+
+ for (int i = 1; i < 10;i++) {
+ BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
+ }
+
+ // Mine all those transactions
+ // Estimates should still not be below original
+ for (int j = 0; j < 10; j++) {
+ while(txHashes[j].size()) {
+ CTransaction btx;
+ if (mpool.lookup(txHashes[j].back(), btx))
+ block.push_back(btx);
+ txHashes[j].pop_back();
+ }
+ }
+ mpool.removeForBlock(block, 265, dummyConflicted);
+ block.clear();
+ for (int i = 1; i < 10;i++) {
+ BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
+ }
+
+ // Mine 100 more blocks where everything is mined every block
+ // Estimates should be below original estimates (not possible for last estimate)
+ while (blocknum < 365) {
+ for (int j = 0; j < 10; j++) { // For each fee/pri multiple
+ for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
+ uint256 hash = tx.GetHash();
+ mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx)));
+ CTransaction btx;
+ if (mpool.lookup(hash, btx))
+ block.push_back(btx);
+ }
+ }
+ mpool.removeForBlock(block, ++blocknum, dummyConflicted);
+ block.clear();
+ }
+ for (int i = 1; i < 9; i++) {
+ BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] - deltaPri);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 45cb551d04..08f988fdbf 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -13,35 +13,36 @@
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
+#include "univalue/univalue.h"
+
using namespace std;
-using namespace json_spirit;
-Array
+UniValue
createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
{
- Array result;
+ UniValue result(UniValue::VARR);
result.push_back(nRequired);
- Array addresses;
+ UniValue addresses(UniValue::VARR);
if (address1) addresses.push_back(address1);
if (address2) addresses.push_back(address2);
result.push_back(addresses);
return result;
}
-Value CallRPC(string args)
+UniValue CallRPC(string args)
{
vector<string> vArgs;
boost::split(vArgs, args, boost::is_any_of(" \t"));
string strMethod = vArgs[0];
vArgs.erase(vArgs.begin());
- Array params = RPCConvertValues(strMethod, vArgs);
+ UniValue params = RPCConvertValues(strMethod, vArgs);
rpcfn_type method = tableRPC[strMethod]->actor;
try {
- Value result = (*method)(params, false);
+ UniValue result = (*method)(params, false);
return result;
}
- catch (const Object& objError) {
+ catch (const UniValue& objError) {
throw runtime_error(find_value(objError, "message").get_str());
}
}
@@ -52,7 +53,7 @@ BOOST_FIXTURE_TEST_SUITE(rpc_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(rpc_rawparams)
{
// Test raw transaction API argument handling
- Value r;
+ UniValue r;
BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error);
BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error);
@@ -92,7 +93,7 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams)
BOOST_AUTO_TEST_CASE(rpc_rawsign)
{
- Value r;
+ UniValue r;
// input is a 1-of-2 multisig (so is output):
string prevout =
"[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\","
@@ -111,25 +112,28 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign)
BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
{
- 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");
+ BOOST_CHECK(ValueFromAmount(0LL).write() == "0.00000000");
+ BOOST_CHECK(ValueFromAmount(1LL).write() == "0.00000001");
+ BOOST_CHECK(ValueFromAmount(17622195LL).write() == "0.17622195");
+ BOOST_CHECK(ValueFromAmount(50000000LL).write() == "0.50000000");
+ BOOST_CHECK(ValueFromAmount(89898989LL).write() == "0.89898989");
+ BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000");
+ BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990");
+ BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999");
}
-static Value ValueFromString(const std::string &str)
+static UniValue ValueFromString(const std::string &str)
{
- Value value;
- BOOST_CHECK(read_string(str, value));
+ UniValue value;
+ BOOST_CHECK(value.setNumStr(str));
return value;
}
BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
{
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("-0.00000001")), UniValue);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0")), 0LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000000")), 0LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL);
@@ -140,6 +144,24 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.99999999")), 2099999999999999LL);
}
+BOOST_AUTO_TEST_CASE(json_parse_errors)
+{
+ // Valid
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0").get_real(), 1.0);
+ // Valid, with leading or trailing whitespace
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0);
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0);
+ // Invalid, initial garbage
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("[1.0"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("a1.0"), std::runtime_error);
+ // Invalid, trailing garbage
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0sds"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0]"), std::runtime_error);
+ // BTC addresses should fail parsing
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), std::runtime_error);
+}
+
BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr)
{
// Check IPv4 addresses
diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp
index 4d5e92cbd4..a72b656100 100644
--- a/src/test/rpc_wallet_tests.cpp
+++ b/src/test/rpc_wallet_tests.cpp
@@ -14,11 +14,12 @@
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
+#include "univalue/univalue.h"
+
using namespace std;
-using namespace json_spirit;
-extern Array createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL);
-extern Value CallRPC(string args);
+extern UniValue createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL);
+extern UniValue CallRPC(string args);
extern CWallet* pwalletMain;
@@ -35,7 +36,7 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig)
// new, compressed:
const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
- Value v;
+ UniValue v;
CBitcoinAddress address;
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
address.SetString(v.get_str());
@@ -66,13 +67,13 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig)
BOOST_AUTO_TEST_CASE(rpc_wallet)
{
// Test RPC calls for various wallet statistics
- Value r;
+ UniValue r;
LOCK2(cs_main, pwalletMain->cs_wallet);
CPubKey demoPubkey = pwalletMain->GenerateNewKey();
CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID()));
- Value retValue;
+ UniValue retValue;
string strAccount = "walletDemoAccount";
string strPurpose = "receive";
BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
@@ -213,7 +214,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
*********************************/
BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
- Array arr = retValue.get_array();
+ UniValue arr = retValue.get_array();
BOOST_CHECK(arr.size() > 0);
BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
}
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
new file mode 100644
index 0000000000..cb1a427db0
--- /dev/null
+++ b/src/test/scheduler_tests.cpp
@@ -0,0 +1,119 @@
+// Copyright (c) 2012-2013 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 "random.h"
+#include "scheduler.h"
+
+#include "test/test_bitcoin.h"
+
+#include <boost/bind.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int_distribution.hpp>
+#include <boost/thread.hpp>
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(scheduler_tests)
+
+static void microTask(CScheduler& s, boost::mutex& mutex, int& counter, int delta, boost::chrono::system_clock::time_point rescheduleTime)
+{
+ {
+ boost::unique_lock<boost::mutex> lock(mutex);
+ counter += delta;
+ }
+ boost::chrono::system_clock::time_point noTime = boost::chrono::system_clock::time_point::min();
+ if (rescheduleTime != noTime) {
+ CScheduler::Function f = boost::bind(&microTask, boost::ref(s), boost::ref(mutex), boost::ref(counter), -delta + 1, noTime);
+ s.schedule(f, rescheduleTime);
+ }
+}
+
+static void MicroSleep(uint64_t n)
+{
+#if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
+ boost::this_thread::sleep_for(boost::chrono::microseconds(n));
+#elif defined(HAVE_WORKING_BOOST_SLEEP)
+ boost::this_thread::sleep(boost::posix_time::microseconds(n));
+#else
+ //should never get here
+ #error missing boost sleep implementation
+#endif
+}
+
+BOOST_AUTO_TEST_CASE(manythreads)
+{
+ seed_insecure_rand(false);
+
+ // Stress test: hundreds of microsecond-scheduled tasks,
+ // serviced by 10 threads.
+ //
+ // So... ten shared counters, which if all the tasks execute
+ // properly will sum to the number of tasks done.
+ // Each task adds or subtracts from one of the counters a
+ // random amount, and then schedules another task 0-1000
+ // microseconds in the future to subtract or add from
+ // the counter -random_amount+1, so in the end the shared
+ // counters should sum to the number of initial tasks performed.
+ CScheduler microTasks;
+
+ boost::mutex counterMutex[10];
+ int counter[10] = { 0 };
+ boost::random::mt19937 rng(insecure_rand());
+ boost::random::uniform_int_distribution<> zeroToNine(0, 9);
+ boost::random::uniform_int_distribution<> randomMsec(-11, 1000);
+ boost::random::uniform_int_distribution<> randomDelta(-1000, 1000);
+
+ boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();
+ boost::chrono::system_clock::time_point now = start;
+ boost::chrono::system_clock::time_point first, last;
+ size_t nTasks = microTasks.getQueueInfo(first, last);
+ BOOST_CHECK(nTasks == 0);
+
+ for (int i = 0; i < 100; i++) {
+ boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
+ boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
+ int whichCounter = zeroToNine(rng);
+ CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
+ boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
+ randomDelta(rng), tReschedule);
+ microTasks.schedule(f, t);
+ }
+ nTasks = microTasks.getQueueInfo(first, last);
+ BOOST_CHECK(nTasks == 100);
+ BOOST_CHECK(first < last);
+ BOOST_CHECK(last > now);
+
+ // As soon as these are created they will start running and servicing the queue
+ boost::thread_group microThreads;
+ for (int i = 0; i < 5; i++)
+ microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
+
+ MicroSleep(600);
+ now = boost::chrono::system_clock::now();
+
+ // More threads and more tasks:
+ for (int i = 0; i < 5; i++)
+ microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
+ for (int i = 0; i < 100; i++) {
+ boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
+ boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
+ int whichCounter = zeroToNine(rng);
+ CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
+ boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
+ randomDelta(rng), tReschedule);
+ microTasks.schedule(f, t);
+ }
+
+ // Drain the task queue then exit threads
+ microTasks.stop(true);
+ microThreads.join_all(); // ... wait until all the threads are done
+
+ int counterSum = 0;
+ for (int i = 0; i < 10; i++) {
+ BOOST_CHECK(counter[i] != 0);
+ counterSum += counter[i];
+ }
+ BOOST_CHECK_EQUAL(counterSum, 200);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index c0614cca43..3733425699 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -26,12 +26,10 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
+
+#include "univalue/univalue.h"
using namespace std;
-using namespace json_spirit;
// Uncomment if you want to output updated JSON tests.
// #define UPDATE_JSON_TESTS
@@ -41,15 +39,15 @@ static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
unsigned int ParseScriptFlags(string strFlags);
string FormatScriptFlags(unsigned int flags);
-Array
+UniValue
read_json(const std::string& jsondata)
{
- Value v;
+ UniValue v;
- if (!read_string(jsondata, v) || v.type() != array_type)
+ if (!v.read(jsondata) || !v.isArray())
{
BOOST_ERROR("Parse error.");
- return Array();
+ return UniValue(UniValue::VARR);
}
return v.get_array();
}
@@ -295,10 +293,10 @@ public:
return *this;
}
- Array GetJSON()
+ UniValue GetJSON()
{
DoPush();
- Array array;
+ UniValue array(UniValue::VARR);
array.push_back(FormatScript(spendTx.vin[0].scriptSig));
array.push_back(FormatScript(creditTx.vout[0].scriptPubKey));
array.push_back(FormatScriptFlags(flags));
@@ -582,14 +580,16 @@ BOOST_AUTO_TEST_CASE(script_build)
std::set<std::string> tests_bad;
{
- Array json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
- Array json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
+ UniValue json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
+ UniValue json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
- BOOST_FOREACH(Value& tv, json_good) {
- tests_good.insert(write_string(Value(tv.get_array()), true));
+ for (unsigned int idx = 0; idx < json_good.size(); idx++) {
+ const UniValue& tv = json_good[idx];
+ tests_good.insert(tv.get_array().write());
}
- BOOST_FOREACH(Value& tv, json_bad) {
- tests_bad.insert(write_string(Value(tv.get_array()), true));
+ for (unsigned int idx = 0; idx < json_bad.size(); idx++) {
+ const UniValue& tv = json_bad[idx];
+ tests_bad.insert(tv.get_array().write());
}
}
@@ -598,7 +598,7 @@ BOOST_AUTO_TEST_CASE(script_build)
BOOST_FOREACH(TestBuilder& test, good) {
test.Test(true);
- std::string str = write_string(Value(test.GetJSON()), true);
+ std::string str = test.GetJSON().write();
#ifndef UPDATE_JSON_TESTS
if (tests_good.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment());
@@ -608,7 +608,7 @@ BOOST_AUTO_TEST_CASE(script_build)
}
BOOST_FOREACH(TestBuilder& test, bad) {
test.Test(false);
- std::string str = write_string(Value(test.GetJSON()), true);
+ std::string str = test.GetJSON().write();
#ifndef UPDATE_JSON_TESTS
if (tests_bad.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_invalid test: " + test.GetComment());
@@ -634,12 +634,11 @@ BOOST_AUTO_TEST_CASE(script_valid)
// Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ]
// ... where scriptSig and scriptPubKey are stringified
// scripts.
- Array tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
+ UniValue tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments)
{
if (test.size() != 1) {
@@ -660,13 +659,12 @@ BOOST_AUTO_TEST_CASE(script_valid)
BOOST_AUTO_TEST_CASE(script_invalid)
{
// Scripts that should evaluate as invalid
- Array tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
+ UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
- if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments)
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
+ if (test.size() < 3) // Allow size > 2; extra stuff ignored (useful for comments)
{
if (test.size() != 1) {
BOOST_ERROR("Bad test: " << strTest);
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index afb7a41bbd..a0797d5f3f 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -2,25 +2,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "consensus/validation.h"
#include "data/sighash.json.h"
#include "main.h"
#include "random.h"
-#include "serialize.h"
-#include "script/script.h"
#include "script/interpreter.h"
+#include "script/script.h"
+#include "serialize.h"
+#include "test/test_bitcoin.h"
#include "util.h"
#include "version.h"
-#include "test/test_bitcoin.h"
#include <iostream>
#include <boost/test/unit_test.hpp>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
-using namespace json_spirit;
-extern Array read_json(const std::string& jsondata);
+#include "univalue/univalue.h"
+
+extern UniValue read_json(const std::string& jsondata);
// Old script.cpp SignatureHash function
uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
@@ -167,12 +166,11 @@ BOOST_AUTO_TEST_CASE(sighash_test)
// Goal: check that SignatureHash generates correct hash
BOOST_AUTO_TEST_CASE(sighash_from_data)
{
- Array tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash)));
+ UniValue tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 1) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 2a3083316e..4cfdec1267 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -7,27 +7,29 @@
#include "test/test_bitcoin.h"
#include "clientversion.h"
+#include "consensus/validation.h"
+#include "core_io.h"
#include "key.h"
#include "keystore.h"
#include "main.h"
#include "script/script.h"
#include "script/script_error.h"
-#include "core_io.h"
#include <map>
#include <string>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
+#include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/assign/list_of.hpp>
-#include "json/json_spirit_writer_template.h"
+
+#include "univalue/univalue.h"
using namespace std;
-using namespace json_spirit;
// In script_tests.cpp
-extern Array read_json(const std::string& jsondata);
+extern UniValue read_json(const std::string& jsondata);
static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
(string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE)
@@ -87,32 +89,31 @@ BOOST_AUTO_TEST_CASE(tx_valid)
// ... where all scripts are stringified scripts.
//
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
- Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
+ UniValue tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
ScriptError err;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
- if (test[0].type() == array_type)
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
+ if (test[0].isArray())
{
- if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type)
+ if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
{
BOOST_ERROR("Bad test: " << strTest);
continue;
}
map<COutPoint, CScript> mapprevOutScriptPubKeys;
- Array inputs = test[0].get_array();
+ UniValue inputs = test[0].get_array();
bool fValid = true;
- BOOST_FOREACH(Value& input, inputs)
- {
- if (input.type() != array_type)
+ for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
+ const UniValue& input = inputs[inpIdx];
+ if (!input.isArray())
{
fValid = false;
break;
}
- Array vinput = input.get_array();
+ UniValue vinput = input.get_array();
if (vinput.size() != 3)
{
fValid = false;
@@ -163,32 +164,31 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
// ... where all scripts are stringified scripts.
//
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
- Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
+ UniValue tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
ScriptError err;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
- if (test[0].type() == array_type)
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
+ if (test[0].isArray())
{
- if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type)
+ if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
{
BOOST_ERROR("Bad test: " << strTest);
continue;
}
map<COutPoint, CScript> mapprevOutScriptPubKeys;
- Array inputs = test[0].get_array();
+ UniValue inputs = test[0].get_array();
bool fValid = true;
- BOOST_FOREACH(Value& input, inputs)
- {
- if (input.type() != array_type)
+ for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
+ const UniValue& input = inputs[inpIdx];
+ if (!input.isArray())
{
fValid = false;
break;
}
- Array vinput = input.get_array();
+ UniValue vinput = input.get_array();
if (vinput.size() != 3)
{
fValid = false;
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
index 8cecfbf651..de84faca23 100644
--- a/src/test/univalue_tests.cpp
+++ b/src/test/univalue_tests.cpp
@@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
double vd = -7.21;
UniValue v7(vd);
- BOOST_CHECK(v7.isNum());
+ BOOST_CHECK(v7.isReal());
BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
string vs("yawn");
@@ -63,6 +63,48 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
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(), runtime_error);
+
+ UniValue v2;
+ BOOST_CHECK(v2.setBool(true));
+ BOOST_CHECK_EQUAL(v2.get_bool(), true);
+ BOOST_CHECK_THROW(v2.get_int(), runtime_error);
+
+ UniValue v3;
+ BOOST_CHECK(v3.setNumStr("32482348723847471234"));
+ BOOST_CHECK_THROW(v3.get_int64(), 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(), runtime_error);
+ BOOST_CHECK(v4.setNumStr("1000"));
+ BOOST_CHECK_EQUAL(v4.get_int(), 1000);
+ BOOST_CHECK_THROW(v4.get_str(), runtime_error);
+ BOOST_CHECK_EQUAL(v4.get_real(), 1000);
+ BOOST_CHECK_THROW(v4.get_array(), runtime_error);
+ BOOST_CHECK_THROW(v4.getKeys(), runtime_error);
+ BOOST_CHECK_THROW(v4.getValues(), runtime_error);
+ BOOST_CHECK_THROW(v4.get_obj(), 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(), 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(), runtime_error);
+}
+
BOOST_AUTO_TEST_CASE(univalue_set)
{
UniValue v(UniValue::VSTR, "foo");
@@ -72,20 +114,20 @@ BOOST_AUTO_TEST_CASE(univalue_set)
BOOST_CHECK(v.setObject());
BOOST_CHECK(v.isObject());
- BOOST_CHECK_EQUAL(v.count(), 0);
+ 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.count(), 0);
+ 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(v.isReal());
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
BOOST_CHECK(v.setInt((int)1023));
@@ -145,7 +187,7 @@ BOOST_AUTO_TEST_CASE(univalue_array)
BOOST_CHECK(arr.push_backV(vec));
BOOST_CHECK_EQUAL(arr.empty(), false);
- BOOST_CHECK_EQUAL(arr.count(), 5);
+ BOOST_CHECK_EQUAL(arr.size(), 5);
BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
@@ -157,7 +199,7 @@ BOOST_AUTO_TEST_CASE(univalue_array)
arr.clear();
BOOST_CHECK(arr.empty());
- BOOST_CHECK_EQUAL(arr.count(), 0);
+ BOOST_CHECK_EQUAL(arr.size(), 0);
}
BOOST_AUTO_TEST_CASE(univalue_object)
@@ -197,7 +239,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
BOOST_CHECK(obj.pushKVs(obj2));
BOOST_CHECK_EQUAL(obj.empty(), false);
- BOOST_CHECK_EQUAL(obj.count(), 9);
+ BOOST_CHECK_EQUAL(obj.size(), 9);
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100");
BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John");
@@ -230,7 +272,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
objTypes["distance"] = UniValue::VNUM;
objTypes["time"] = UniValue::VNUM;
objTypes["calories"] = UniValue::VNUM;
- objTypes["temperature"] = UniValue::VNUM;
+ objTypes["temperature"] = UniValue::VREAL;
objTypes["cat1"] = UniValue::VNUM;
objTypes["cat2"] = UniValue::VNUM;
BOOST_CHECK(obj.checkObject(objTypes));
@@ -240,11 +282,11 @@ BOOST_AUTO_TEST_CASE(univalue_object)
obj.clear();
BOOST_CHECK(obj.empty());
- BOOST_CHECK_EQUAL(obj.count(), 0);
+ BOOST_CHECK_EQUAL(obj.size(), 0);
}
static const char *json1 =
-"[1.1,{\"key1\":\"str\",\"key2\":800,\"key3\":{\"name\":\"martian\"}}]";
+"[1.10000000,{\"key1\":\"str\",\"key2\":800,\"key3\":{\"name\":\"martian\"}}]";
BOOST_AUTO_TEST_CASE(univalue_readwrite)
{
@@ -255,13 +297,13 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite)
BOOST_CHECK(v.read(strJson1));
BOOST_CHECK(v.isArray());
- BOOST_CHECK_EQUAL(v.count(), 2);
+ BOOST_CHECK_EQUAL(v.size(), 2);
- BOOST_CHECK_EQUAL(v[0].getValStr(), "1.1");
+ BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000");
UniValue obj = v[1];
BOOST_CHECK(obj.isObject());
- BOOST_CHECK_EQUAL(obj.count(), 3);
+ BOOST_CHECK_EQUAL(obj.size(), 3);
BOOST_CHECK(obj["key1"].isStr());
BOOST_CHECK_EQUAL(obj["key1"].getValStr(), "str");
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 3309e2e387..5cb5894251 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -146,29 +146,27 @@ BOOST_AUTO_TEST_CASE(util_GetArg)
BOOST_AUTO_TEST_CASE(util_FormatMoney)
{
- BOOST_CHECK_EQUAL(FormatMoney(0, false), "0.00");
- BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789, false), "12345.6789");
- BOOST_CHECK_EQUAL(FormatMoney(COIN, true), "+1.00");
- BOOST_CHECK_EQUAL(FormatMoney(-COIN, false), "-1.00");
- BOOST_CHECK_EQUAL(FormatMoney(-COIN, true), "-1.00");
-
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000, false), "100000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000, false), "10000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000, false), "1000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100000, false), "100000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10000, false), "10000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*1000, false), "1000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100, false), "100.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10, false), "10.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN, false), "1.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10, false), "0.10");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100, false), "0.01");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/1000, false), "0.001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10000, false), "0.0001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100000, false), "0.00001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000, false), "0.000001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000, false), "0.0000001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000, false), "0.00000001");
+ BOOST_CHECK_EQUAL(FormatMoney(0), "0.00");
+ BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789), "12345.6789");
+ BOOST_CHECK_EQUAL(FormatMoney(-COIN), "-1.00");
+
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000), "100000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000), "10000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000), "1000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100000), "100000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10000), "10000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*1000), "1000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100), "100.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10), "10.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN), "1.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10), "0.10");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100), "0.01");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/1000), "0.001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10000), "0.0001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100000), "0.00001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000), "0.000001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000), "0.0000001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000), "0.00000001");
}
BOOST_AUTO_TEST_CASE(util_ParseMoney)
@@ -322,9 +320,16 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648);
BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234);
// Invalid values
+ BOOST_CHECK(!ParseInt32("", &n));
+ BOOST_CHECK(!ParseInt32(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseInt32("1 ", &n));
BOOST_CHECK(!ParseInt32("1a", &n));
BOOST_CHECK(!ParseInt32("aap", &n));
BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
+ BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
+ const char test_bytes[] = {'1', 0, '1'};
+ std::string teststr(test_bytes, sizeof(test_bytes));
+ BOOST_CHECK(!ParseInt32(teststr, &n)); // no embedded NULs
// Overflow and underflow
BOOST_CHECK(!ParseInt32("-2147483649", NULL));
BOOST_CHECK(!ParseInt32("2147483648", NULL));
@@ -332,6 +337,64 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
BOOST_CHECK(!ParseInt32("32482348723847471234", NULL));
}
+BOOST_AUTO_TEST_CASE(test_ParseInt64)
+{
+ int64_t n;
+ // Valid values
+ BOOST_CHECK(ParseInt64("1234", NULL));
+ BOOST_CHECK(ParseInt64("0", &n) && n == 0LL);
+ BOOST_CHECK(ParseInt64("1234", &n) && n == 1234LL);
+ BOOST_CHECK(ParseInt64("01234", &n) && n == 1234LL); // no octal
+ BOOST_CHECK(ParseInt64("2147483647", &n) && n == 2147483647LL);
+ BOOST_CHECK(ParseInt64("-2147483648", &n) && n == -2147483648LL);
+ BOOST_CHECK(ParseInt64("9223372036854775807", &n) && n == (int64_t)9223372036854775807);
+ BOOST_CHECK(ParseInt64("-9223372036854775808", &n) && n == (int64_t)-9223372036854775807-1);
+ BOOST_CHECK(ParseInt64("-1234", &n) && n == -1234LL);
+ // Invalid values
+ BOOST_CHECK(!ParseInt64("", &n));
+ BOOST_CHECK(!ParseInt64(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseInt64("1 ", &n));
+ BOOST_CHECK(!ParseInt64("1a", &n));
+ BOOST_CHECK(!ParseInt64("aap", &n));
+ BOOST_CHECK(!ParseInt64("0x1", &n)); // no hex
+ const char test_bytes[] = {'1', 0, '1'};
+ std::string teststr(test_bytes, sizeof(test_bytes));
+ BOOST_CHECK(!ParseInt64(teststr, &n)); // no embedded NULs
+ // Overflow and underflow
+ BOOST_CHECK(!ParseInt64("-9223372036854775809", NULL));
+ BOOST_CHECK(!ParseInt64("9223372036854775808", NULL));
+ BOOST_CHECK(!ParseInt64("-32482348723847471234", NULL));
+ BOOST_CHECK(!ParseInt64("32482348723847471234", NULL));
+}
+
+BOOST_AUTO_TEST_CASE(test_ParseDouble)
+{
+ double n;
+ // Valid values
+ BOOST_CHECK(ParseDouble("1234", NULL));
+ BOOST_CHECK(ParseDouble("0", &n) && n == 0.0);
+ BOOST_CHECK(ParseDouble("1234", &n) && n == 1234.0);
+ BOOST_CHECK(ParseDouble("01234", &n) && n == 1234.0); // no octal
+ BOOST_CHECK(ParseDouble("2147483647", &n) && n == 2147483647.0);
+ BOOST_CHECK(ParseDouble("-2147483648", &n) && n == -2147483648.0);
+ BOOST_CHECK(ParseDouble("-1234", &n) && n == -1234.0);
+ BOOST_CHECK(ParseDouble("1e6", &n) && n == 1e6);
+ BOOST_CHECK(ParseDouble("-1e6", &n) && n == -1e6);
+ // Invalid values
+ BOOST_CHECK(!ParseDouble("", &n));
+ BOOST_CHECK(!ParseDouble(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseDouble("1 ", &n));
+ BOOST_CHECK(!ParseDouble("1a", &n));
+ BOOST_CHECK(!ParseDouble("aap", &n));
+ BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex
+ const char test_bytes[] = {'1', 0, '1'};
+ std::string teststr(test_bytes, sizeof(test_bytes));
+ BOOST_CHECK(!ParseDouble(teststr, &n)); // no embedded NULs
+ // Overflow and underflow
+ BOOST_CHECK(!ParseDouble("-1e10000", NULL));
+ BOOST_CHECK(!ParseDouble("1e10000", NULL));
+}
+
BOOST_AUTO_TEST_CASE(test_FormatParagraph)
{
BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), "");