Remove the nType and nVersion as parameters to all serialization methods and functions. There is only one place where it's read and has an impact (in CAddress), and even there it does not impact any of the recursively invoked serializers. Instead, the few places that need nType or nVersion are changed to read it directly from the stream object, through GetType() and GetVersion() methods which are added to all stream classes.
235 lines
7.0 KiB
C++
235 lines
7.0 KiB
C++
// Copyright (c) 2018 The Zcash developers
|
|
// Copyright (c) 2012-2017 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 "dbwrapper.h"
|
|
#include "uint256.h"
|
|
#include "random.h"
|
|
#include "test/test_bitcoin.h"
|
|
|
|
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
|
|
#include <boost/assert.hpp>
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
using namespace std;
|
|
using namespace boost::assign; // bring 'operator+=()' into scope
|
|
using namespace boost::filesystem;
|
|
|
|
// Test if a string consists entirely of null characters
|
|
bool is_null_key(const vector<unsigned char>& key) {
|
|
bool isnull = true;
|
|
|
|
for (unsigned int i = 0; i < key.size(); i++)
|
|
isnull &= (key[i] == '\x00');
|
|
|
|
return isnull;
|
|
}
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)
|
|
|
|
BOOST_AUTO_TEST_CASE(dbwrapper)
|
|
{
|
|
{
|
|
path ph = temp_directory_path() / unique_path();
|
|
CDBWrapper dbw(ph, (1 << 20), true, false);
|
|
char key = 'k';
|
|
uint256 in = GetRandHash();
|
|
uint256 res;
|
|
|
|
BOOST_CHECK(dbw.Write(key, in));
|
|
BOOST_CHECK(dbw.Read(key, res));
|
|
BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
|
|
}
|
|
}
|
|
|
|
// Test batch operations
|
|
BOOST_AUTO_TEST_CASE(dbwrapper_batch)
|
|
{
|
|
{
|
|
path ph = temp_directory_path() / unique_path();
|
|
CDBWrapper dbw(ph, (1 << 20), true, false);
|
|
|
|
char key = 'i';
|
|
uint256 in = GetRandHash();
|
|
char key2 = 'j';
|
|
uint256 in2 = GetRandHash();
|
|
char key3 = 'k';
|
|
uint256 in3 = GetRandHash();
|
|
|
|
uint256 res;
|
|
CDBBatch batch(dbw);
|
|
|
|
batch.Write(key, in);
|
|
batch.Write(key2, in2);
|
|
batch.Write(key3, in3);
|
|
|
|
// Remove key3 before it's even been written
|
|
batch.Erase(key3);
|
|
|
|
dbw.WriteBatch(batch);
|
|
|
|
BOOST_CHECK(dbw.Read(key, res));
|
|
BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
|
|
BOOST_CHECK(dbw.Read(key2, res));
|
|
BOOST_CHECK_EQUAL(res.ToString(), in2.ToString());
|
|
|
|
// key3 should've never been written
|
|
BOOST_CHECK(dbw.Read(key3, res) == false);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
|
|
{
|
|
{
|
|
path ph = temp_directory_path() / unique_path();
|
|
CDBWrapper dbw(ph, (1 << 20), true, false);
|
|
|
|
// The two keys are intentionally chosen for ordering
|
|
char key = 'j';
|
|
uint256 in = GetRandHash();
|
|
BOOST_CHECK(dbw.Write(key, in));
|
|
char key2 = 'k';
|
|
uint256 in2 = GetRandHash();
|
|
BOOST_CHECK(dbw.Write(key2, in2));
|
|
|
|
boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
|
|
|
|
// Be sure to seek past any earlier key (if it exists)
|
|
it->Seek(key);
|
|
|
|
char key_res;
|
|
uint256 val_res;
|
|
|
|
it->GetKey(key_res);
|
|
it->GetValue(val_res);
|
|
BOOST_CHECK_EQUAL(key_res, key);
|
|
BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString());
|
|
|
|
it->Next();
|
|
|
|
it->GetKey(key_res);
|
|
it->GetValue(val_res);
|
|
BOOST_CHECK_EQUAL(key_res, key2);
|
|
BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString());
|
|
|
|
it->Next();
|
|
BOOST_CHECK_EQUAL(it->Valid(), false);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(iterator_ordering)
|
|
{
|
|
path ph = temp_directory_path() / unique_path();
|
|
CDBWrapper dbw(ph, (1 << 20), true, false);
|
|
for (int x=0x00; x<256; ++x) {
|
|
uint8_t key = x;
|
|
uint32_t value = x*x;
|
|
BOOST_CHECK(dbw.Write(key, value));
|
|
}
|
|
|
|
boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
|
|
for (int seek_start : {0x00, 0x80}) {
|
|
it->Seek((uint8_t)seek_start);
|
|
for (int x=seek_start; x<256; ++x) {
|
|
uint8_t key;
|
|
uint32_t value;
|
|
BOOST_CHECK(it->Valid());
|
|
if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
|
|
break;
|
|
BOOST_CHECK(it->GetKey(key));
|
|
BOOST_CHECK(it->GetValue(value));
|
|
BOOST_CHECK_EQUAL(key, x);
|
|
BOOST_CHECK_EQUAL(value, x*x);
|
|
it->Next();
|
|
}
|
|
BOOST_CHECK(!it->Valid());
|
|
}
|
|
}
|
|
|
|
struct StringContentsSerializer {
|
|
// Used to make two serialized objects the same while letting them have different lengths
|
|
// This is a terrible idea
|
|
string str;
|
|
StringContentsSerializer() {}
|
|
StringContentsSerializer(const string& inp) : str(inp) {}
|
|
|
|
StringContentsSerializer& operator+=(const string& s) {
|
|
str += s;
|
|
return *this;
|
|
}
|
|
StringContentsSerializer& operator+=(const StringContentsSerializer& s) { return *this += s.str; }
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
template <typename Stream, typename Operation>
|
|
inline void SerializationOp(Stream& s, Operation ser_action) {
|
|
if (ser_action.ForRead()) {
|
|
str.clear();
|
|
char c = 0;
|
|
while (true) {
|
|
try {
|
|
READWRITE(c);
|
|
str.push_back(c);
|
|
} catch (const std::ios_base::failure& e) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for (size_t i = 0; i < str.size(); i++)
|
|
READWRITE(str[i]);
|
|
}
|
|
}
|
|
};
|
|
|
|
BOOST_AUTO_TEST_CASE(iterator_string_ordering)
|
|
{
|
|
char buf[10];
|
|
|
|
path ph = temp_directory_path() / unique_path();
|
|
CDBWrapper dbw(ph, (1 << 20), true, false);
|
|
for (int x=0x00; x<10; ++x) {
|
|
for (int y = 0; y < 10; y++) {
|
|
int n = snprintf(buf, sizeof(buf), "%d", x);
|
|
assert(n > 0 && n < sizeof(buf));
|
|
StringContentsSerializer key(buf);
|
|
for (int z = 0; z < y; z++)
|
|
key += key;
|
|
uint32_t value = x*x;
|
|
BOOST_CHECK(dbw.Write(key, value));
|
|
}
|
|
}
|
|
|
|
boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
|
|
for (int seek_start : {0, 5}) {
|
|
int n = snprintf(buf, sizeof(buf), "%d", seek_start);
|
|
assert(n > 0 && n < sizeof(buf));
|
|
StringContentsSerializer seek_key(buf);
|
|
it->Seek(seek_key);
|
|
for (int x=seek_start; x<10; ++x) {
|
|
for (int y = 0; y < 10; y++) {
|
|
int n = snprintf(buf, sizeof(buf), "%d", x);
|
|
assert(n > 0 && n < sizeof(buf));
|
|
string exp_key(buf);
|
|
for (int z = 0; z < y; z++)
|
|
exp_key += exp_key;
|
|
StringContentsSerializer key;
|
|
uint32_t value;
|
|
BOOST_CHECK(it->Valid());
|
|
if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
|
|
break;
|
|
BOOST_CHECK(it->GetKey(key));
|
|
BOOST_CHECK(it->GetValue(value));
|
|
BOOST_CHECK_EQUAL(key.str, exp_key);
|
|
BOOST_CHECK_EQUAL(value, x*x);
|
|
it->Next();
|
|
}
|
|
}
|
|
BOOST_CHECK(!it->Valid());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|