mirror of https://github.com/oxen-io/oxen-core.git
Merge pull request #1465 from jagerman/snode-net-revision
Add mandatory upgrade "snode revisions" and start enforcing lokinet/ss versions
This commit is contained in:
commit
2e7e47a005
|
@ -51,7 +51,7 @@ message(STATUS "CMake version ${CMAKE_VERSION}")
|
|||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12 CACHE STRING "macOS deployment target (Apple clang only)")
|
||||
|
||||
project(oxen
|
||||
VERSION 9.1.3
|
||||
VERSION 9.2.0
|
||||
LANGUAGES CXX C)
|
||||
set(OXEN_RELEASE_CODENAME "Audacious Aurochs")
|
||||
|
||||
|
|
|
@ -519,6 +519,7 @@ else()
|
|||
endif()
|
||||
build_external(hidapi
|
||||
DEPENDS ${maybe_eudev} libusb_external
|
||||
PATCH_COMMAND patch -p1 -i ${PROJECT_SOURCE_DIR}/utils/build_scripts/hidapi-autoconf-duplicate-macro-dir.patch
|
||||
CONFIGURE_COMMAND autoreconf -ivf && ./configure ${cross_host} --prefix=${DEPS_DESTDIR} --disable-shared --enable-static --with-pic
|
||||
"CC=${deps_cc}" "CXX=${deps_cxx}" "CFLAGS=${deps_CFLAGS}" "CXXFLAGS=${deps_CXXFLAGS}"
|
||||
${cross_extra}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 703bd9caab50b139428cea1aaff9974ebee5742e
|
||||
Subproject commit e2239ee6043f73722e7aa812a459f54a28552929
|
|
@ -27,6 +27,7 @@
|
|||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "cryptonote_core/service_node_rules.h"
|
||||
#include "checkpoints/checkpoints.h"
|
||||
#include "epee/string_tools.h"
|
||||
|
@ -222,18 +223,11 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
|||
TIME_MEASURE_FINISH(time1);
|
||||
time_add_block1 += time1;
|
||||
|
||||
m_hardfork->add(blk, prev_height);
|
||||
|
||||
++num_calls;
|
||||
|
||||
return prev_height;
|
||||
}
|
||||
|
||||
void BlockchainDB::set_hard_fork(HardFork* hf)
|
||||
{
|
||||
m_hardfork = hf;
|
||||
}
|
||||
|
||||
void BlockchainDB::pop_block(block& blk, std::vector<transaction>& txs)
|
||||
{
|
||||
blk = get_top_block();
|
||||
|
@ -438,8 +432,7 @@ void BlockchainDB::fill_timestamps_and_difficulties_for_pow(cryptonote::network_
|
|||
return;
|
||||
|
||||
uint64_t const top_block_height = chain_height - 1;
|
||||
static const uint64_t hf16_height = HardFork::get_hardcoded_hard_fork_height(nettype, cryptonote::network_version_16_pulse);
|
||||
bool const before_hf16 = chain_height < hf16_height;
|
||||
bool const before_hf16 = !is_hard_fork_at_least(nettype, network_version_16_pulse, chain_height);
|
||||
uint64_t const block_count = DIFFICULTY_BLOCKS_COUNT(before_hf16);
|
||||
|
||||
timestamps.reserve(block_count);
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include "cryptonote_basic/blobdatatype.h"
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/difficulty.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
|
||||
/** \file
|
||||
* Cryptonote Blockchain Database Interface
|
||||
|
@ -549,14 +548,12 @@ protected:
|
|||
uint64_t time_commit1 = 0; //!< a performance metric
|
||||
bool m_auto_remove_logs = true; //!< whether or not to automatically remove old logs
|
||||
|
||||
HardFork* m_hardfork;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief An empty constructor.
|
||||
*/
|
||||
BlockchainDB(): m_hardfork(NULL), m_open(false) { }
|
||||
BlockchainDB() = default;
|
||||
|
||||
/**
|
||||
* @brief An empty destructor.
|
||||
|
@ -796,8 +793,6 @@ public:
|
|||
virtual void block_rtxn_stop() const = 0;
|
||||
virtual void block_rtxn_abort() const = 0;
|
||||
|
||||
virtual void set_hard_fork(HardFork* hf);
|
||||
|
||||
// adds a block with the given metadata to the top of the blockchain, returns the new height
|
||||
/**
|
||||
* @brief handles the addition of a new block to BlockchainDB
|
||||
|
@ -1775,38 +1770,6 @@ public:
|
|||
*/
|
||||
virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *block_blob, const cryptonote::blobdata *checkpoint_blob)> f, bool include_blob = false) const = 0;
|
||||
|
||||
|
||||
//
|
||||
// Hard fork related storage
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief sets which hardfork version a height is on
|
||||
*
|
||||
* @param height the height
|
||||
* @param version the version
|
||||
*/
|
||||
virtual void set_hard_fork_version(uint64_t height, uint8_t version) = 0;
|
||||
|
||||
/**
|
||||
* @brief checks which hardfork version a height is on
|
||||
*
|
||||
* @param height the height
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
virtual uint8_t get_hard_fork_version(uint64_t height) const = 0;
|
||||
|
||||
/**
|
||||
* @brief verify hard fork info in database
|
||||
*/
|
||||
virtual void check_hard_fork_info() = 0;
|
||||
|
||||
/**
|
||||
* @brief delete hard fork info from database
|
||||
*/
|
||||
virtual void drop_hard_fork_info() = 0;
|
||||
|
||||
/**
|
||||
* @brief return a histogram of outputs on the blockchain
|
||||
*
|
||||
|
@ -1897,7 +1860,7 @@ public:
|
|||
*/
|
||||
void set_auto_remove_logs(bool auto_remove) { m_auto_remove_logs = auto_remove; }
|
||||
|
||||
bool m_open; //!< Whether or not the BlockchainDB is open/ready for use
|
||||
bool m_open = false; //!< Whether or not the BlockchainDB is open/ready for use
|
||||
|
||||
}; // class BlockchainDB
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "epee/string_tools.h"
|
||||
#include "common/file.h"
|
||||
#include "common/pruning.h"
|
||||
|
@ -49,7 +50,6 @@
|
|||
#include "cryptonote_core/service_node_rules.h"
|
||||
#include "cryptonote_core/service_node_list.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
|
||||
#undef OXEN_DEFAULT_LOG_CATEGORY
|
||||
#define OXEN_DEFAULT_LOG_CATEGORY "blockchain.db.lmdb"
|
||||
|
@ -359,17 +359,17 @@ void setup_cursor(const MDB_dbi& db, MDB_cursor*& cursor, MDB_txn* txn)
|
|||
}
|
||||
}
|
||||
|
||||
void setup_rcursor(const MDB_dbi& db, MDB_cursor*& cursor, MDB_txn* txn, bool& rflag, bool using_wcursor)
|
||||
void setup_rcursor(const MDB_dbi& db, MDB_cursor*& cursor, MDB_txn* txn, bool* rflag, bool using_wcursor)
|
||||
{
|
||||
if (!cursor) {
|
||||
setup_cursor(db, cursor, txn);
|
||||
if (!using_wcursor)
|
||||
rflag = true;
|
||||
} else if (!using_wcursor && !rflag) {
|
||||
*rflag = true;
|
||||
} else if (!using_wcursor && !*rflag) {
|
||||
int result = mdb_cursor_renew(txn, cursor);
|
||||
if (result)
|
||||
throw0(cryptonote::DB_ERROR(lmdb_error("Failed to renew cursor: ", result)));
|
||||
rflag = true;
|
||||
*rflag = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,7 +377,7 @@ void setup_rcursor(const MDB_dbi& db, MDB_cursor*& cursor, MDB_txn* txn, bool& r
|
|||
|
||||
#define CURSOR(name) setup_cursor(m_##name, m_cursors->name, *m_write_txn);
|
||||
|
||||
#define RCURSOR(name) setup_rcursor(m_##name, m_cursors->name, m_txn, m_tinfo->m_ti_rflags.m_rf_##name, m_cursors == &m_wcursors);
|
||||
#define RCURSOR(name) setup_rcursor(m_##name, m_cursors->name, m_txn, m_tinfo.get() ? &m_tinfo->m_ti_rflags.m_rf_##name : nullptr, m_cursors == &m_wcursors);
|
||||
|
||||
#define m_cur_blocks m_cursors->blocks
|
||||
#define m_cur_block_heights m_cursors->block_heights
|
||||
|
@ -1392,8 +1392,6 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB()
|
|||
m_cum_count = 0;
|
||||
|
||||
// reset may also need changing when initialize things here
|
||||
|
||||
m_hardfork = nullptr;
|
||||
}
|
||||
|
||||
void BlockchainLMDB::open(const fs::path& filename, cryptonote::network_type nettype, const int db_flags)
|
||||
|
@ -4573,64 +4571,6 @@ void BlockchainLMDB::add_output_blacklist(std::vector<uint64_t> const &blacklist
|
|||
throw0(DB_ERROR(lmdb_error("Failed to add blacklisted output to db transaction: ", ret).c_str()));
|
||||
}
|
||||
|
||||
void BlockchainLMDB::check_hard_fork_info()
|
||||
{
|
||||
}
|
||||
|
||||
void BlockchainLMDB::drop_hard_fork_info()
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
TXN_PREFIX(0);
|
||||
|
||||
auto result = mdb_drop(*txn_ptr, m_hf_starting_heights, 1);
|
||||
if (result)
|
||||
throw1(DB_ERROR(lmdb_error("Error dropping hard fork starting heights db: ", result).c_str()));
|
||||
result = mdb_drop(*txn_ptr, m_hf_versions, 1);
|
||||
if (result)
|
||||
throw1(DB_ERROR(lmdb_error("Error dropping hard fork versions db: ", result).c_str()));
|
||||
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
}
|
||||
|
||||
void BlockchainLMDB::set_hard_fork_version(uint64_t height, uint8_t version)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
TXN_BLOCK_PREFIX(0);
|
||||
|
||||
MDB_val_copy<uint64_t> val_key(height);
|
||||
MDB_val_copy<uint8_t> val_value(version);
|
||||
int result;
|
||||
result = mdb_put(*txn_ptr, m_hf_versions, &val_key, &val_value, MDB_APPEND);
|
||||
if (result == MDB_KEYEXIST)
|
||||
result = mdb_put(*txn_ptr, m_hf_versions, &val_key, &val_value, 0);
|
||||
if (result)
|
||||
throw1(DB_ERROR(lmdb_error("Error adding hard fork version to db transaction: ", result).c_str()));
|
||||
|
||||
TXN_BLOCK_POSTFIX_SUCCESS();
|
||||
}
|
||||
|
||||
uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
TXN_PREFIX_RDONLY();
|
||||
RCURSOR(hf_versions);
|
||||
|
||||
MDB_val_copy<uint64_t> val_key(height);
|
||||
MDB_val val_ret;
|
||||
auto result = mdb_cursor_get(m_cur_hf_versions, &val_key, &val_ret, MDB_SET);
|
||||
if (result == MDB_NOTFOUND || result)
|
||||
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve a hard fork version at height " + std::to_string(height) + " from the db: ", result).c_str()));
|
||||
|
||||
uint8_t ret = *(const uint8_t*)val_ret.mv_data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BlockchainLMDB::add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &block, cryptonote::blobdata const *checkpoint)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
|
@ -4805,8 +4745,8 @@ void BlockchainLMDB::fixup(cryptonote::network_type nettype)
|
|||
add_timestamp_and_difficulty(nettype, curr_chain_height, timestamps, difficulties, curr_timestamp, curr_cumulative_diff);
|
||||
|
||||
// NOTE: Calculate next block difficulty
|
||||
uint8_t const hf_version = get_hard_fork_version(curr_height);
|
||||
if (hf_version >= cryptonote::network_version_16_pulse && block_header_has_pulse_components(get_block_header_from_height(curr_height)))
|
||||
if (is_hard_fork_at_least(nettype, cryptonote::network_version_16_pulse, curr_height)
|
||||
&& block_header_has_pulse_components(get_block_header_from_height(curr_height)))
|
||||
{
|
||||
diff = PULSE_FIXED_DIFFICULTY;
|
||||
}
|
||||
|
@ -4815,7 +4755,7 @@ void BlockchainLMDB::fixup(cryptonote::network_type nettype)
|
|||
diff = next_difficulty_v2(timestamps,
|
||||
difficulties,
|
||||
tools::to_seconds(TARGET_BLOCK_TIME),
|
||||
difficulty_mode(nettype, hf_version, curr_height + 1));
|
||||
difficulty_mode(nettype, curr_height + 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -403,12 +403,6 @@ private:
|
|||
|
||||
uint64_t num_outputs() const;
|
||||
|
||||
// Hard fork
|
||||
void set_hard_fork_version(uint64_t height, uint8_t version) override;
|
||||
uint8_t get_hard_fork_version(uint64_t height) const override;
|
||||
void check_hard_fork_info() override;
|
||||
void drop_hard_fork_info() override;
|
||||
|
||||
inline void check_open() const;
|
||||
|
||||
bool prune_worker(int mode, uint32_t pruning_seed);
|
||||
|
|
|
@ -65,7 +65,6 @@ public:
|
|||
virtual void block_rtxn_stop() const override {}
|
||||
virtual void block_rtxn_abort() const override {}
|
||||
|
||||
virtual void drop_hard_fork_info() override {}
|
||||
virtual bool block_exists(const crypto::hash& h, uint64_t *height) const override { return false; }
|
||||
virtual cryptonote::blobdata get_block_blob_from_height(uint64_t height) const override { return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); }
|
||||
virtual cryptonote::blobdata get_block_blob(const crypto::hash& h) const override { return cryptonote::blobdata(); }
|
||||
|
@ -147,9 +146,6 @@ public:
|
|||
, const crypto::hash& blk_hash
|
||||
) override { }
|
||||
virtual cryptonote::block get_block_from_height(uint64_t height) const override { return cryptonote::block(); }
|
||||
virtual void set_hard_fork_version(uint64_t height, uint8_t version) override {}
|
||||
virtual uint8_t get_hard_fork_version(uint64_t height) const override { return 0; }
|
||||
virtual void check_hard_fork_info() override {}
|
||||
|
||||
virtual uint32_t get_blockchain_pruning_seed() const override { return 0; }
|
||||
virtual bool prune_blockchain(uint32_t pruning_seed = 0) override { return true; }
|
||||
|
|
|
@ -549,7 +549,6 @@ int main(int argc, char* argv[])
|
|||
const command_line::arg_descriptor<uint64_t> arg_block_stop = {"block-stop", "Stop at block number", block_stop};
|
||||
const command_line::arg_descriptor<uint64_t> arg_batch_size = {"batch-size", "", db_batch_size};
|
||||
const command_line::arg_descriptor<uint64_t> arg_pop_blocks = {"pop-blocks", "Remove blocks from end of blockchain", num_blocks};
|
||||
const command_line::arg_descriptor<bool> arg_drop_hf = {"drop-hard-fork", "Drop hard fork subdbs", false};
|
||||
const command_line::arg_descriptor<bool> arg_count_blocks = {
|
||||
"count-blocks"
|
||||
, "Count blocks in bootstrap file and exit"
|
||||
|
@ -569,7 +568,6 @@ int main(int argc, char* argv[])
|
|||
|
||||
command_line::add_arg(desc_cmd_only, arg_count_blocks);
|
||||
command_line::add_arg(desc_cmd_only, arg_pop_blocks);
|
||||
command_line::add_arg(desc_cmd_only, arg_drop_hf);
|
||||
command_line::add_arg(desc_cmd_only, command_line::arg_help);
|
||||
|
||||
command_line::add_arg(desc_cmd_only, arg_recalculate_difficulty);
|
||||
|
@ -722,14 +720,6 @@ int main(int argc, char* argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!command_line::is_arg_defaulted(vm, arg_drop_hf))
|
||||
{
|
||||
MINFO("Dropping hard fork tables...");
|
||||
core.get_blockchain_storage().get_db().drop_hard_fork_info();
|
||||
core.deinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (command_line::get_arg(vm, arg_recalculate_difficulty))
|
||||
core.get_blockchain_storage().get_db().fixup(core.get_nettype());
|
||||
|
||||
|
|
|
@ -55,8 +55,6 @@ namespace cryptonote
|
|||
KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(m_encryption_iv, default_iv)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
account_keys& operator=(account_keys const&) = default;
|
||||
|
||||
void encrypt(const crypto::chacha_key &key);
|
||||
void decrypt(const crypto::chacha_key &key);
|
||||
void encrypt_viewkey(const crypto::chacha_key &key);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "common/oxen.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "epee/int-util.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "difficulty.h"
|
||||
|
@ -127,8 +128,7 @@ namespace cryptonote {
|
|||
timestamps.push_back(timestamp);
|
||||
difficulties.push_back(cumulative_difficulty);
|
||||
|
||||
static const uint64_t hf16_height = HardFork::get_hardcoded_hard_fork_height(nettype, cryptonote::network_version_16_pulse);
|
||||
bool const before_hf16 = chain_height < hf16_height;
|
||||
bool before_hf16 = !is_hard_fork_at_least(nettype, network_version_16_pulse, chain_height);
|
||||
|
||||
// Trim down arrays
|
||||
while (timestamps.size() > DIFFICULTY_BLOCKS_COUNT(before_hf16))
|
||||
|
@ -163,27 +163,20 @@ namespace cryptonote {
|
|||
// be reduced from 60*60*2 to 500 seconds to prevent timestamp manipulation from miner's with
|
||||
// > 50% hash power. If this is too small, it can be increased to 1000 at a cost in protection.
|
||||
|
||||
difficulty_calc_mode difficulty_mode(cryptonote::network_type nettype, uint8_t hf_version, uint64_t height)
|
||||
difficulty_calc_mode difficulty_mode(cryptonote::network_type nettype, uint64_t height)
|
||||
{
|
||||
static const uint64_t hf12_height = cryptonote::HardFork::get_hardcoded_hard_fork_height(nettype, cryptonote::network_version_12_checkpointing);
|
||||
static const uint64_t hf16_height = cryptonote::HardFork::get_hardcoded_hard_fork_height(nettype, cryptonote::network_version_16_pulse);
|
||||
auto result = difficulty_calc_mode::normal;
|
||||
|
||||
if (hf_version <= cryptonote::network_version_9_service_nodes)
|
||||
{
|
||||
if (!is_hard_fork_at_least(nettype, cryptonote::network_version_10_bulletproofs, height))
|
||||
result = difficulty_calc_mode::use_old_lwma;
|
||||
}
|
||||
// HF12 switches to RandomX with a likely drastically reduced hashrate versus Turtle, so override
|
||||
// difficulty for the first difficulty window blocks:
|
||||
else if (height >= hf12_height &&
|
||||
height < hf12_height + (DIFFICULTY_WINDOW + 1))
|
||||
{
|
||||
else if (auto randomx_start_height = get_hard_fork_heights(nettype, network_version_12_checkpointing).first;
|
||||
randomx_start_height && height >= *randomx_start_height && height <= *randomx_start_height + DIFFICULTY_WINDOW)
|
||||
result = difficulty_calc_mode::hf12_override;
|
||||
}
|
||||
else if (nettype == MAINNET && height >= hf16_height && height < hf16_height + (DIFFICULTY_WINDOW + 1))
|
||||
{
|
||||
else if (auto pulse_start_height = get_hard_fork_heights(nettype, network_version_16_pulse).first;
|
||||
nettype == MAINNET && pulse_start_height && height >= *pulse_start_height && height <= *pulse_start_height + DIFFICULTY_WINDOW)
|
||||
result = difficulty_calc_mode::hf16_override;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace cryptonote
|
|||
normal,
|
||||
};
|
||||
|
||||
difficulty_calc_mode difficulty_mode(network_type nettype, uint8_t hf_version, uint64_t height);
|
||||
difficulty_calc_mode difficulty_mode(network_type nettype, uint64_t height);
|
||||
|
||||
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps,
|
||||
std::vector<difficulty_type> cumulative_difficulties,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// Copyright (c) 2014-2019, The Monero Project
|
||||
// Copyright (c) 2018, The Loki Project
|
||||
// Copyright (c) 2018-2021, The Loki Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -27,468 +26,145 @@
|
|||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <array>
|
||||
|
||||
#include "common/oxen.h"
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "hardfork.h"
|
||||
|
||||
#undef OXEN_DEFAULT_LOG_CATEGORY
|
||||
#define OXEN_DEFAULT_LOG_CATEGORY "hardfork"
|
||||
|
||||
using namespace cryptonote;
|
||||
|
||||
static uint8_t get_block_vote(const cryptonote::block &b)
|
||||
{
|
||||
// Pre-hardfork blocks have a minor version hardcoded to 0.
|
||||
// For the purposes of voting, we consider 0 to refer to
|
||||
// version number 1, which is what all blocks from the genesis
|
||||
// block are. It makes things simpler.
|
||||
if (b.minor_version == 0)
|
||||
return 1;
|
||||
return b.minor_version;
|
||||
}
|
||||
|
||||
static uint8_t get_block_version(const cryptonote::block &b)
|
||||
{
|
||||
return b.major_version;
|
||||
}
|
||||
|
||||
// TODO(oxen): Re-evaluate Hardfork as a class. Originally designed to
|
||||
// handle voting, hardforks are now locked in, maybe we just need helper
|
||||
// functions on the hardcoded table instead of hiding everything behind
|
||||
// a class.
|
||||
namespace cryptonote {
|
||||
|
||||
// version 7 from the start of the blockchain, inhereted from Monero mainnet
|
||||
static constexpr HardFork::Params mainnet_hard_forks[] =
|
||||
static constexpr std::array mainnet_hard_forks =
|
||||
{
|
||||
{ network_version_7, 1, 0, 1503046577 },
|
||||
{ network_version_8, 64324, 0, 1533006000 },
|
||||
{ network_version_9_service_nodes, 101250, 0, 1537444800 },
|
||||
{ network_version_10_bulletproofs, 161849, 0, 1544743800 }, // 2018-12-13 23:30UTC
|
||||
{ network_version_11_infinite_staking, 234767, 0, 1554170400 }, // 2019-03-26 13:00AEDT
|
||||
{ network_version_12_checkpointing, 321467, 0, 1563940800 }, // 2019-07-24 14:00AEDT
|
||||
{ network_version_13_enforce_checkpoints, 385824, 0, 1571850000 }, // 2019-10-23 19:00AEDT
|
||||
{ network_version_14_blink, 442333, 0, 1578528000 }, // 2020-01-09 00:00UTC
|
||||
{ network_version_15_ons, 496969, 0, 1585105200 }, // 2020-03-25 14:00AEDT (03:00UTC)
|
||||
{ network_version_16_pulse, 641111, 0, 1602464400 }, // 2020-10-12 12:00AEDT (01:00UTC)
|
||||
{ network_version_17, 770711, 0, 1618016400 }, // Saturday, April 10, 2021 1:00:00 UTC
|
||||
{ network_version_18, 785000, 0, 1619736143 }, // Thursday, April 29, 2021 22:42:23 UTC
|
||||
hard_fork{7, 0, 0, 1503046577 }, // Loki 0.1: Loki is born
|
||||
hard_fork{8, 0, 64324, 1533006000 /*2018-07-31 03:00 UTC*/ }, // Loki 0.2: New emissions schedule
|
||||
hard_fork{9, 0, 101250, 1537444800 /*2018-09-20 12:00 UTC*/ }, // Loki 1: Service nodes launched
|
||||
hard_fork{10, 0, 161849, 1544743800 /*2018-12-13 23:30 UTC*/ }, // Loki 2: Bulletproofs, gov fee batching
|
||||
hard_fork{11, 0, 234767, 1554170400 /*2019-03-26 13:00 AEDT*/ }, // Loki 3: Infinite staking, CN-Turtle
|
||||
hard_fork{12, 0, 321467, 1563940800 /*2019-07-24 14:00 AEDT*/ }, // Loki 4: Checkpointing, RandomXL, decommissioning, Storage Server launched
|
||||
hard_fork{13, 0, 385824, 1571850000 /*2019-10-23 19:00 AEDT*/ }, // Loki 5: Checkpointing enforced
|
||||
hard_fork{14, 0, 442333, 1578528000 /*2020-01-09 00:00 UTC*/ }, // Loki 6: Blink, Lokinet launched on mainnet
|
||||
hard_fork{15, 0, 496969, 1585105200 /*2020-03-25 14:00 AEDT (03:00 UTC)*/ }, // Loki 7: ONS (Session)
|
||||
hard_fork{16, 0, 641111, 1602464400 /*2020-10-12 12:00 AEDT (01:00 UTC)*/ }, // Loki 8: Pulse
|
||||
hard_fork{17, 0, 770711, 1618016400 /*Saturday, April 10, 2021 1:00:00 UTC*/ }, // Oxen 8: Eliminate 6/block emissions after 180 days (not a separate release)
|
||||
hard_fork{18, 0, 785000, 1619736143 /*Thursday, April 29, 2021 22:42:23 UTC*/ }, // Oxen 9: Timesync, new proofs, reasons, wallet ONS
|
||||
hard_fork{18, 1, 839009, 1626217200 /*Tuesday, July 13, 2021 23:00 UTC */ }, // Oxen 9.2: mandatory SS 2.2.0 & lokinet 0.9.5 updates
|
||||
};
|
||||
|
||||
static constexpr HardFork::Params testnet_hard_forks[] =
|
||||
static constexpr std::array testnet_hard_forks =
|
||||
{
|
||||
{ network_version_7, 1, 0, 1533631121 },
|
||||
{ network_version_8, 2, 0, 1533631122 },
|
||||
{ network_version_9_service_nodes, 3, 0, 1533631123 },
|
||||
{ network_version_10_bulletproofs, 4, 0, 1542681077 },
|
||||
{ network_version_11_infinite_staking, 5, 0, 1551223964 },
|
||||
{ network_version_12_checkpointing, 75471, 0, 1561608000 }, // 2019-06-28 14:00AEDT
|
||||
{ network_version_13_enforce_checkpoints, 127028, 0, 1568440800 }, // 2019-09-13 16:00AEDT
|
||||
{ network_version_14_blink, 174630, 0, 1575075600 }, // 2019-11-30 07:00UTC
|
||||
{ network_version_15_ons, 244777, 0, 1583940000 }, // 2020-03-11 15:20UTC
|
||||
{ network_version_16_pulse, 382222, 0, 1600468200 }, // 2020-09-18 22:30UTC
|
||||
{ network_version_17, 447275, 0, 1608276840 }, // 2020-12-18 05:34UTC
|
||||
{ network_version_18, 501750, 0, 1616631051 }, // 2021-03-25 12:10UTC
|
||||
hard_fork{7, 0, 0, 1533631121 }, // Testnet was rebooted during Loki 3 development
|
||||
hard_fork{8, 0, 2, 1533631122 },
|
||||
hard_fork{9, 0, 3, 1533631123 },
|
||||
hard_fork{10, 0, 4, 1542681077 },
|
||||
hard_fork{11, 0, 5, 1551223964 },
|
||||
hard_fork{12, 0, 75471, 1561608000 }, // 2019-06-28 14:00 AEDT
|
||||
hard_fork{13, 0, 127028, 1568440800 }, // 2019-09-13 16:00 AEDT
|
||||
hard_fork{14, 0, 174630, 1575075600 }, // 2019-11-30 07:00 UTC
|
||||
hard_fork{15, 0, 244777, 1583940000 }, // 2020-03-11 15:20 UTC
|
||||
hard_fork{16, 0, 382222, 1600468200 }, // 2020-09-18 22:30 UTC
|
||||
hard_fork{17, 0, 447275, 1608276840 }, // 2020-12-18 05:34 UTC
|
||||
hard_fork{18, 0, 501750, 1616631051 }, // 2021-03-25 12:10 UTC
|
||||
hard_fork{18, 1, 578637, 1624040400 }, // 2021-06-18 18:20 UTC
|
||||
};
|
||||
|
||||
static constexpr HardFork::Params devnet_hard_forks[] =
|
||||
static constexpr std::array devnet_hard_forks =
|
||||
{
|
||||
{ network_version_7, 1, 0, 1599848400 },
|
||||
{ network_version_11_infinite_staking, 2, 0, 1599848400 },
|
||||
{ network_version_12_checkpointing, 3, 0, 1599848400 },
|
||||
{ network_version_13_enforce_checkpoints, 4, 0, 1599848400 },
|
||||
{ network_version_15_ons, 5, 0, 1599848400 },
|
||||
{ network_version_16_pulse, 99, 0, 1599848400 }, // 2020-09-11 18:20 UTC
|
||||
hard_fork{ 7, 0, 0, 1599848400 },
|
||||
hard_fork{ 11, 0, 2, 1599848400 },
|
||||
hard_fork{ 12, 0, 3, 1599848400 },
|
||||
hard_fork{ 13, 0, 4, 1599848400 },
|
||||
hard_fork{ 15, 0, 5, 1599848400 },
|
||||
hard_fork{ 16, 0, 99, 1599848400 },
|
||||
};
|
||||
|
||||
uint64_t HardFork::get_hardcoded_hard_fork_height(network_type nettype, cryptonote::network_version version)
|
||||
{
|
||||
uint64_t result = INVALID_HF_VERSION_HEIGHT;
|
||||
for (const auto &record : cryptonote::HardFork::get_hardcoded_hard_forks(nettype))
|
||||
{
|
||||
if (record.version >= version)
|
||||
{
|
||||
result = record.height;
|
||||
break;
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
static constexpr bool is_ordered(const std::array<hard_fork, N>& forks) {
|
||||
if (N == 0 || forks[0].version < 7)
|
||||
return false;
|
||||
for (size_t i = 1; i < N; i++) {
|
||||
auto& hf = forks[i];
|
||||
auto& prev = forks[i-1];
|
||||
if ( // [major,snoderevision] pair must be strictly increasing (lexicographically)
|
||||
std::make_pair(hf.version, hf.snode_revision) <= std::make_pair(prev.version, prev.snode_revision)
|
||||
// height must be strictly increasing; time must be weakly increasing
|
||||
|| hf.height <= prev.height || hf.time < prev.time)
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
HardFork::ParamsIterator HardFork::get_hardcoded_hard_forks(network_type nettype)
|
||||
static_assert(is_ordered(mainnet_hard_forks),
|
||||
"Invalid mainnet hard forks: version must start at 7, major versions and heights must be strictly increasing, and timestamps must be non-decreasing");
|
||||
static_assert(is_ordered(testnet_hard_forks),
|
||||
"Invalid testnet hard forks: version must start at 7, versions and heights must be strictly increasing, and timestamps must be non-decreasing");
|
||||
static_assert(is_ordered(devnet_hard_forks),
|
||||
"Invalid devnet hard forks: version must start at 7, versions and heights must be strictly increasing, and timestamps must be non-decreasing");
|
||||
|
||||
std::vector<hard_fork> fakechain_hardforks;
|
||||
|
||||
std::pair<const hard_fork*, const hard_fork*> get_hard_forks(network_type type)
|
||||
{
|
||||
if (nettype == MAINNET) return {mainnet_hard_forks, std::end(mainnet_hard_forks)};
|
||||
else if (nettype == TESTNET) return {testnet_hard_forks, std::end(testnet_hard_forks)};
|
||||
else if (nettype == DEVNET) return {devnet_hard_forks, std::end(devnet_hard_forks)};
|
||||
if (type == network_type::MAINNET) return {&mainnet_hard_forks[0], &mainnet_hard_forks[mainnet_hard_forks.size()]};
|
||||
if (type == network_type::TESTNET) return {&testnet_hard_forks[0], &testnet_hard_forks[testnet_hard_forks.size()]};
|
||||
if (type == network_type::DEVNET) return {&devnet_hard_forks[0], &devnet_hard_forks[devnet_hard_forks.size()]};
|
||||
if (type == network_type::FAKECHAIN) return {fakechain_hardforks.data(), fakechain_hardforks.data() + fakechain_hardforks.size()};
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
HardFork::HardFork(cryptonote::BlockchainDB &db, uint8_t original_version, time_t forked_time, time_t update_time, uint64_t window_size, uint8_t default_threshold_percent):
|
||||
db(db),
|
||||
original_version(original_version),
|
||||
forked_time(forked_time),
|
||||
update_time(update_time),
|
||||
window_size(window_size),
|
||||
default_threshold_percent(default_threshold_percent),
|
||||
current_fork_index(0)
|
||||
{
|
||||
if (window_size == 0)
|
||||
throw std::logic_error{"window_size needs to be strictly positive"};
|
||||
if (default_threshold_percent > 100)
|
||||
throw std::logic_error{"default_threshold_percent needs to be between 0 and 100"};
|
||||
}
|
||||
|
||||
void HardFork::add_fork(uint8_t version, uint64_t height, uint8_t threshold, time_t time)
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
|
||||
// add in order
|
||||
if (version == 0)
|
||||
throw std::runtime_error{"Cannot add a hard fork with HF version 0"};
|
||||
if (!heights.empty()) {
|
||||
const auto& [v, h, _thresh, t] = heights.back();
|
||||
if (version <= v)
|
||||
throw std::runtime_error{"Cannot add hard fork: version(" + std::to_string(version) + ") must be > previous HF version(" + std::to_string(v) + ")"};
|
||||
if (height <= h)
|
||||
throw std::runtime_error{"Cannot add hard fork: height(" + std::to_string(height) + ") must be > previous HF height(" + std::to_string(h) + ")"};
|
||||
if (time < t)
|
||||
throw std::runtime_error{"Cannot add hard fork: timestamp(" + std::to_string(time) + ") must be >= previous HF timestamp(" + std::to_string(t) + ")"};
|
||||
}
|
||||
if (threshold > 100)
|
||||
throw std::runtime_error{"Cannot add hard fork: invalid threshold (" + std::to_string(threshold) + ")"};
|
||||
|
||||
heights.push_back({version, height, threshold, time});
|
||||
}
|
||||
|
||||
void HardFork::add_fork(uint8_t version, uint64_t height, time_t time)
|
||||
{
|
||||
add_fork(version, height, default_threshold_percent, time);
|
||||
}
|
||||
|
||||
uint8_t HardFork::get_effective_version(uint8_t voting_version) const
|
||||
{
|
||||
if (!heights.empty()) {
|
||||
uint8_t max_version = heights.back().version;
|
||||
if (voting_version > max_version)
|
||||
voting_version = max_version;
|
||||
}
|
||||
return voting_version;
|
||||
}
|
||||
|
||||
bool HardFork::do_check(uint8_t block_version, uint8_t voting_version) const
|
||||
{
|
||||
return block_version == heights[current_fork_index].version
|
||||
&& voting_version >= heights[current_fork_index].version;
|
||||
}
|
||||
|
||||
bool HardFork::check(const cryptonote::block &block) const
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
return do_check(::get_block_version(block), ::get_block_vote(block));
|
||||
}
|
||||
|
||||
bool HardFork::do_check_for_height(uint8_t block_version, uint8_t voting_version, uint64_t height) const
|
||||
{
|
||||
int fork_index = get_voted_fork_index(height);
|
||||
return block_version == heights[fork_index].version
|
||||
&& voting_version >= heights[fork_index].version;
|
||||
}
|
||||
|
||||
bool HardFork::check_for_height(const cryptonote::block &block, uint64_t height) const
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
return do_check_for_height(::get_block_version(block), ::get_block_vote(block), height);
|
||||
}
|
||||
|
||||
bool HardFork::add(uint8_t block_version, uint8_t voting_version, uint64_t height)
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
|
||||
if (!do_check(block_version, voting_version))
|
||||
return false;
|
||||
|
||||
db.set_hard_fork_version(height, heights[current_fork_index].version);
|
||||
|
||||
voting_version = get_effective_version(voting_version);
|
||||
|
||||
while (versions.size() >= window_size) {
|
||||
const uint8_t old_version = versions.front();
|
||||
assert(last_versions[old_version] >= 1);
|
||||
last_versions[old_version]--;
|
||||
versions.pop_front();
|
||||
}
|
||||
|
||||
last_versions[voting_version]++;
|
||||
versions.push_back(voting_version);
|
||||
|
||||
uint8_t voted = get_voted_fork_index(height + 1);
|
||||
if (voted > current_fork_index) {
|
||||
current_fork_index = voted;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HardFork::add(const cryptonote::block &block, uint64_t height)
|
||||
{
|
||||
return add(::get_block_version(block), ::get_block_vote(block), height);
|
||||
}
|
||||
|
||||
void HardFork::init()
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
|
||||
// add a placeholder for the default version, to avoid special cases
|
||||
if (heights.empty())
|
||||
heights.push_back({original_version, 0, 0, 0});
|
||||
|
||||
versions.clear();
|
||||
for (size_t n = 0; n < 256; ++n)
|
||||
last_versions[n] = 0;
|
||||
current_fork_index = 0;
|
||||
|
||||
// restore state from DB
|
||||
uint64_t height = db.height();
|
||||
if (height > window_size)
|
||||
height -= window_size - 1;
|
||||
else
|
||||
height = 1;
|
||||
|
||||
rescan_from_chain_height(height);
|
||||
MDEBUG("init done");
|
||||
}
|
||||
|
||||
uint8_t HardFork::get_block_version(uint64_t height) const
|
||||
{
|
||||
const cryptonote::block &block = db.get_block_from_height(height);
|
||||
return ::get_block_version(block);
|
||||
}
|
||||
|
||||
bool HardFork::reorganize_from_block_height(uint64_t height)
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
if (height >= db.height())
|
||||
return false;
|
||||
|
||||
bool stop_batch = db.batch_start();
|
||||
|
||||
versions.clear();
|
||||
|
||||
for (size_t n = 0; n < 256; ++n)
|
||||
last_versions[n] = 0;
|
||||
const uint64_t rescan_height = height >= (window_size - 1) ? height - (window_size -1) : 0;
|
||||
const uint8_t start_version = height == 0 ? original_version : db.get_hard_fork_version(height);
|
||||
while (current_fork_index > 0 && heights[current_fork_index].version > start_version) {
|
||||
--current_fork_index;
|
||||
}
|
||||
for (uint64_t h = rescan_height; h <= height; ++h) {
|
||||
cryptonote::block b = db.get_block_from_height(h);
|
||||
const uint8_t v = get_effective_version(get_block_vote(b));
|
||||
last_versions[v]++;
|
||||
versions.push_back(v);
|
||||
}
|
||||
|
||||
uint8_t voted = get_voted_fork_index(height + 1);
|
||||
if (voted > current_fork_index) {
|
||||
current_fork_index = voted;
|
||||
}
|
||||
|
||||
const uint64_t bc_height = db.height();
|
||||
for (uint64_t h = height + 1; h < bc_height; ++h) {
|
||||
add(db.get_block_from_height(h), h);
|
||||
}
|
||||
|
||||
if (stop_batch)
|
||||
db.batch_stop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HardFork::reorganize_from_chain_height(uint64_t height)
|
||||
{
|
||||
if (height == 0)
|
||||
return false;
|
||||
return reorganize_from_block_height(height - 1);
|
||||
}
|
||||
|
||||
bool HardFork::rescan_from_block_height(uint64_t height)
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
db_rtxn_guard rtxn_guard(&db);
|
||||
if (height >= db.height())
|
||||
return false;
|
||||
|
||||
versions.clear();
|
||||
|
||||
for (size_t n = 0; n < 256; ++n)
|
||||
last_versions[n] = 0;
|
||||
for (uint64_t h = height; h < db.height(); ++h) {
|
||||
cryptonote::block b = db.get_block_from_height(h);
|
||||
const uint8_t v = get_effective_version(get_block_vote(b));
|
||||
last_versions[v]++;
|
||||
versions.push_back(v);
|
||||
}
|
||||
|
||||
uint8_t lastv = db.get_hard_fork_version(db.height() - 1);
|
||||
current_fork_index = 0;
|
||||
while (current_fork_index + 1 < heights.size() && heights[current_fork_index].version != lastv)
|
||||
++current_fork_index;
|
||||
|
||||
uint8_t voted = get_voted_fork_index(db.height());
|
||||
if (voted > current_fork_index) {
|
||||
current_fork_index = voted;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HardFork::rescan_from_chain_height(uint64_t height)
|
||||
{
|
||||
if (height == 0)
|
||||
return false;
|
||||
return rescan_from_block_height(height - 1);
|
||||
}
|
||||
|
||||
void HardFork::on_block_popped(uint64_t nblocks)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(nblocks > 0, "nblocks must be greater than 0");
|
||||
|
||||
std::unique_lock l{lock};
|
||||
|
||||
const uint64_t new_chain_height = db.height();
|
||||
const uint64_t old_chain_height = new_chain_height + nblocks;
|
||||
uint8_t version;
|
||||
for (uint64_t height = old_chain_height - 1; height >= new_chain_height; --height)
|
||||
{
|
||||
version = versions.back();
|
||||
last_versions[version]--;
|
||||
versions.pop_back();
|
||||
version = db.get_hard_fork_version(height);
|
||||
versions.push_front(version);
|
||||
last_versions[version]++;
|
||||
}
|
||||
|
||||
// does not take voting into account
|
||||
for (current_fork_index = heights.size() - 1; current_fork_index > 0; --current_fork_index)
|
||||
if (new_chain_height >= heights[current_fork_index].height)
|
||||
std::pair<std::optional<uint64_t>, std::optional<uint64_t>>
|
||||
get_hard_fork_heights(network_type nettype, uint8_t version) {
|
||||
std::pair<std::optional<uint64_t>, std::optional<uint64_t>> found;
|
||||
for (auto [it, end] = get_hard_forks(nettype); it != end; it++) {
|
||||
if (it->version > version) { // This (and anything else) are in the future
|
||||
if (found.first) // Found something suitable in the previous iteration, so one before this hf is the max
|
||||
found.second = it->height - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
int HardFork::get_voted_fork_index(uint64_t height) const
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
uint32_t accumulated_votes = 0;
|
||||
for (int n = heights.size() - 1; n >= 0; --n) {
|
||||
uint8_t v = heights[n].version;
|
||||
accumulated_votes += last_versions[v];
|
||||
uint32_t threshold = (window_size * heights[n].threshold + 99) / 100;
|
||||
if (height >= heights[n].height && accumulated_votes >= threshold) {
|
||||
return n;
|
||||
} else if (it->version == version) {
|
||||
found.first = it->height;
|
||||
}
|
||||
}
|
||||
return current_fork_index;
|
||||
return found;
|
||||
}
|
||||
|
||||
HardFork::State HardFork::get_state(time_t t) const
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
uint8_t hard_fork_ceil(network_type nettype, uint8_t version) {
|
||||
auto [it, end] = get_hard_forks(nettype);
|
||||
for (; it != end; it++)
|
||||
if (it->version >= version)
|
||||
return it->version;
|
||||
|
||||
// no hard forks setup yet
|
||||
if (heights.size() <= 1)
|
||||
return Ready;
|
||||
|
||||
time_t t_last_fork = heights.back().time;
|
||||
if (t >= t_last_fork + forked_time)
|
||||
return LikelyForked;
|
||||
if (t >= t_last_fork + update_time)
|
||||
return UpdateNeeded;
|
||||
return Ready;
|
||||
return version;
|
||||
}
|
||||
|
||||
HardFork::State HardFork::get_state() const
|
||||
{
|
||||
return get_state(time(NULL));
|
||||
}
|
||||
|
||||
uint8_t HardFork::get(uint64_t height) const
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
if (height > db.height()) {
|
||||
assert(false);
|
||||
return INVALID_HF_VERSION;
|
||||
}
|
||||
if (height == db.height()) {
|
||||
return get_current_version();
|
||||
}
|
||||
return db.get_hard_fork_version(height);
|
||||
}
|
||||
|
||||
uint8_t HardFork::get_current_version() const
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
return heights[current_fork_index].version;
|
||||
}
|
||||
|
||||
uint8_t HardFork::get_ideal_version() const
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
return heights.back().version;
|
||||
}
|
||||
|
||||
uint8_t HardFork::get_ideal_version(uint64_t height) const
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
for (unsigned int n = heights.size() - 1; n > 0; --n) {
|
||||
if (height >= heights[n].height) {
|
||||
return heights[n].version;
|
||||
}
|
||||
}
|
||||
return original_version;
|
||||
}
|
||||
|
||||
uint64_t HardFork::get_earliest_ideal_height_for_version(uint8_t version) const
|
||||
{
|
||||
uint64_t height = std::numeric_limits<uint64_t>::max();
|
||||
for (auto i = heights.rbegin(); i != heights.rend(); ++i) {
|
||||
if (i->version >= version) {
|
||||
height = i->height;
|
||||
} else {
|
||||
std::pair<uint8_t, uint8_t>
|
||||
get_network_version_revision(network_type nettype, uint64_t height) {
|
||||
std::pair<uint8_t, uint8_t> result;
|
||||
for (auto [it, end] = get_hard_forks(nettype); it != end; it++) {
|
||||
if (it->height <= height)
|
||||
result = {it->version, it->snode_revision};
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
return height;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t HardFork::get_next_version() const
|
||||
bool is_hard_fork_at_least(network_type type, uint8_t version, uint64_t height) {
|
||||
return get_network_version(type, height) >= version;
|
||||
}
|
||||
|
||||
std::pair<uint8_t, uint8_t>
|
||||
get_ideal_block_version(network_type nettype, uint64_t height)
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
uint64_t height = db.height();
|
||||
for (auto i = heights.rbegin(); i != heights.rend(); ++i) {
|
||||
if (height >= i->height) {
|
||||
return (i == heights.rbegin() ? i : (i - 1))->version;
|
||||
}
|
||||
std::pair<uint8_t, uint8_t> result;
|
||||
for (auto [it, end] = get_hard_forks(nettype); it != end; it++) {
|
||||
if (it->height <= height)
|
||||
result.first = it->version;
|
||||
result.second = it->version;
|
||||
}
|
||||
return original_version;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool HardFork::get_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const
|
||||
{
|
||||
std::unique_lock l{lock};
|
||||
|
||||
const uint8_t current_version = heights[current_fork_index].version;
|
||||
const bool enabled = current_version >= version;
|
||||
window = versions.size();
|
||||
votes = 0;
|
||||
for (size_t n = version; n < 256; ++n)
|
||||
votes += last_versions[n];
|
||||
threshold = (window * heights[current_fork_index].threshold + 99) / 100;
|
||||
//assert((votes >= threshold) == enabled);
|
||||
earliest_height = get_earliest_ideal_height_for_version(version);
|
||||
voting = heights.back().version;
|
||||
return enabled;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2019, The Monero Project
|
||||
// Copyright (c) 2018-2021, The Oxen Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -29,263 +29,72 @@
|
|||
#pragma once
|
||||
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include <mutex>
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
class BlockchainDB;
|
||||
|
||||
class HardFork
|
||||
{
|
||||
public:
|
||||
struct Params
|
||||
{
|
||||
uint8_t version;
|
||||
uint64_t height;
|
||||
uint8_t threshold;
|
||||
time_t time;
|
||||
};
|
||||
|
||||
constexpr static uint8_t INVALID_HF_VERSION = 255;
|
||||
constexpr static uint64_t INVALID_HF_VERSION_HEIGHT = static_cast<uint64_t>(-1);
|
||||
typedef enum {
|
||||
LikelyForked,
|
||||
UpdateNeeded,
|
||||
Ready,
|
||||
} State;
|
||||
|
||||
static const uint64_t DEFAULT_ORIGINAL_VERSION_TILL_HEIGHT = 0; // <= actual height
|
||||
static const time_t DEFAULT_FORKED_TIME = 31557600; // a year in seconds
|
||||
static const time_t DEFAULT_UPDATE_TIME = 31557600 / 2;
|
||||
static const uint64_t DEFAULT_WINDOW_SIZE = 10080; // supermajority window check length - a week
|
||||
static const uint8_t DEFAULT_THRESHOLD_PERCENT = 80;
|
||||
|
||||
struct ParamsIterator
|
||||
{
|
||||
const Params *begin_, *end_;
|
||||
constexpr Params const *begin() { return begin_; };
|
||||
constexpr Params const *end() { return end_; };
|
||||
};
|
||||
|
||||
// NOTE: Returns INVALID_HF_VERSION_HEIGHT if version not specified for nettype
|
||||
static uint64_t get_hardcoded_hard_fork_height(network_type nettype, cryptonote::network_version version);
|
||||
static ParamsIterator get_hardcoded_hard_forks(network_type nettype);
|
||||
|
||||
/**
|
||||
* @brief creates a new HardFork object
|
||||
*
|
||||
* @param original_version the block version for blocks 0 through to the first fork
|
||||
* @param forked_time the time in seconds before thinking we're forked
|
||||
* @param update_time the time in seconds before thinking we need to update
|
||||
* @param window_size the size of the window in blocks to consider for version voting
|
||||
* @param default_threshold_percent the size of the majority in percents
|
||||
*/
|
||||
HardFork(cryptonote::BlockchainDB &db, uint8_t original_version = 1, time_t forked_time = DEFAULT_FORKED_TIME, time_t update_time = DEFAULT_UPDATE_TIME, uint64_t window_size = DEFAULT_WINDOW_SIZE, uint8_t default_threshold_percent = DEFAULT_THRESHOLD_PERCENT);
|
||||
|
||||
/**
|
||||
* @brief add a new hardfork height
|
||||
*
|
||||
* returns true if no error, false otherwise
|
||||
*
|
||||
* @param version the major block version for the fork, must be > 0 and > the last-added hf
|
||||
* @param height The height the hardfork takes effect; must be > the last-added hf
|
||||
* @param threshold The threshold of votes needed for this fork (0-100)
|
||||
* @param time Approximate time of the hardfork (seconds since epoch); must be >= the timestamp
|
||||
* of the last-added hf
|
||||
*
|
||||
* @throws std::invalid_argument if any parameters are invalid
|
||||
*/
|
||||
void add_fork(uint8_t version, uint64_t height, uint8_t threshold, time_t time);
|
||||
|
||||
/**
|
||||
* @brief add a new hardfork height
|
||||
*
|
||||
* returns true if no error, false otherwise
|
||||
*
|
||||
* @param version the major block version for the fork
|
||||
* @param height The height the hardfork takes effect
|
||||
* @param time Approximate time of the hardfork (seconds since epoch)
|
||||
*
|
||||
* @throws std::invalid_argument if any parameters are invalid
|
||||
*/
|
||||
void add_fork(uint8_t version, uint64_t height, time_t time);
|
||||
|
||||
/**
|
||||
* @brief initialize the object
|
||||
*
|
||||
* Must be done after adding all the required hardforks via add above
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* @brief check whether a new block would be accepted
|
||||
*
|
||||
* returns true if the block is accepted, false otherwise
|
||||
*
|
||||
* @param block the new block
|
||||
*
|
||||
* This check is made by add. It is exposed publicly to allow
|
||||
* the caller to inexpensively check whether a block would be
|
||||
* accepted or rejected by its version number. Indeed, if this
|
||||
* check could only be done as part of add, the caller would
|
||||
* either have to add the block to the blockchain first, then
|
||||
* call add, then have to pop the block from the blockchain if
|
||||
* its version did not satisfy the hard fork requirements, or
|
||||
* call add first, then, if the hard fork requirements are met,
|
||||
* add the block to the blockchain, upon which a failure (the
|
||||
* block being invalid, double spending, etc) would cause the
|
||||
* hardfork object to reorganize.
|
||||
*/
|
||||
bool check(const cryptonote::block &block) const;
|
||||
|
||||
/**
|
||||
* @brief same as check, but for a particular height, rather than the top
|
||||
*
|
||||
* NOTE: this does not play well with voting, and relies on voting to be
|
||||
* disabled (that is, forks happen on the scheduled date, whether or not
|
||||
* enough blocks have voted for the fork).
|
||||
*
|
||||
* returns true if no error, false otherwise
|
||||
*
|
||||
* @param block the new block
|
||||
* @param height which height to check for
|
||||
*/
|
||||
bool check_for_height(const cryptonote::block &block, uint64_t height) const;
|
||||
|
||||
/**
|
||||
* @brief add a new block
|
||||
*
|
||||
* returns true if no error, false otherwise
|
||||
*
|
||||
* @param block the new block
|
||||
*/
|
||||
bool add(const cryptonote::block &block, uint64_t height);
|
||||
|
||||
/**
|
||||
* @brief called when the blockchain is reorganized
|
||||
*
|
||||
* This will rescan the blockchain to determine which hard forks
|
||||
* have been triggered
|
||||
*
|
||||
* returns true if no error, false otherwise
|
||||
*
|
||||
* @param blockchain the blockchain
|
||||
* @param height of the last block kept from the previous blockchain
|
||||
*/
|
||||
bool reorganize_from_block_height(uint64_t height);
|
||||
bool reorganize_from_chain_height(uint64_t height);
|
||||
|
||||
/**
|
||||
* @brief called when one or more blocks are popped from the blockchain
|
||||
*
|
||||
* The current fork will be updated by looking up the db,
|
||||
* which is much cheaper than recomputing everything
|
||||
*
|
||||
* @param new_chain_height the height of the chain after popping
|
||||
*/
|
||||
void on_block_popped(uint64_t new_chain_height);
|
||||
|
||||
/**
|
||||
* @brief returns current state at the given time
|
||||
*
|
||||
* Based on the approximate time of the last known hard fork,
|
||||
* estimate whether we need to update, or if we're way behind
|
||||
*
|
||||
* @param t the time to consider
|
||||
*/
|
||||
State get_state(time_t t) const;
|
||||
State get_state() const;
|
||||
|
||||
/**
|
||||
* @brief returns the hard fork version for the given block height
|
||||
*
|
||||
* @param height height of the block to check
|
||||
*/
|
||||
uint8_t get(uint64_t height) const;
|
||||
|
||||
/**
|
||||
* @brief returns the latest "ideal" version
|
||||
*
|
||||
* This is the latest version that's been scheduled
|
||||
*/
|
||||
uint8_t get_ideal_version() const;
|
||||
|
||||
/**
|
||||
* @brief returns the "ideal" version for a given height
|
||||
*
|
||||
* @param height height of the block to check
|
||||
*/
|
||||
uint8_t get_ideal_version(uint64_t height) const;
|
||||
|
||||
/**
|
||||
* @brief returns the next version
|
||||
*
|
||||
* This is the version which will we fork to next
|
||||
*/
|
||||
uint8_t get_next_version() const;
|
||||
|
||||
/**
|
||||
* @brief returns the current version
|
||||
*
|
||||
* This is the latest version that's past its trigger date and had enough votes
|
||||
* at one point in the past.
|
||||
*/
|
||||
uint8_t get_current_version() const;
|
||||
|
||||
/**
|
||||
* @brief returns the earliest block a given version may activate
|
||||
*/
|
||||
uint64_t get_earliest_ideal_height_for_version(uint8_t version) const;
|
||||
|
||||
/**
|
||||
* @brief returns information about current voting state
|
||||
*
|
||||
* returns true if the given version is enabled (ie, the current version
|
||||
* is at least the passed version), false otherwise
|
||||
*
|
||||
* @param version the version to check voting for
|
||||
* @param window the number of blocks considered in voting
|
||||
* @param votes number of votes for next version
|
||||
* @param threshold number of votes needed to switch to next version
|
||||
* @param earliest_height earliest height at which the version can take effect
|
||||
*/
|
||||
bool get_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const;
|
||||
|
||||
/**
|
||||
* @brief returns the size of the voting window in blocks
|
||||
*/
|
||||
uint64_t get_window_size() const { return window_size; }
|
||||
|
||||
private:
|
||||
|
||||
uint8_t get_block_version(uint64_t height) const;
|
||||
bool do_check(uint8_t block_version, uint8_t voting_version) const;
|
||||
bool do_check_for_height(uint8_t block_version, uint8_t voting_version, uint64_t height) const;
|
||||
int get_voted_fork_index(uint64_t height) const;
|
||||
uint8_t get_effective_version(uint8_t voting_version) const;
|
||||
bool add(uint8_t block_version, uint8_t voting_version, uint64_t height);
|
||||
|
||||
bool rescan_from_block_height(uint64_t height);
|
||||
bool rescan_from_chain_height(uint64_t height);
|
||||
|
||||
private:
|
||||
|
||||
BlockchainDB &db;
|
||||
|
||||
time_t forked_time;
|
||||
time_t update_time;
|
||||
uint64_t window_size;
|
||||
uint8_t default_threshold_percent;
|
||||
|
||||
uint8_t original_version;
|
||||
std::vector<Params> heights;
|
||||
|
||||
std::deque<uint8_t> versions; /* rolling window of the last N blocks' versions */
|
||||
unsigned int last_versions[256]; /* count of the block versions in the last N blocks */
|
||||
uint32_t current_fork_index;
|
||||
|
||||
mutable std::recursive_mutex lock;
|
||||
// Defines where hard fork (i.e. new minimum network versions) begin
|
||||
struct hard_fork {
|
||||
uint8_t version; // Blockchain major version
|
||||
uint8_t snode_revision; // Snode revision for enforcing non-blockchain-breaking mandatory service node updates
|
||||
uint64_t height;
|
||||
time_t time;
|
||||
};
|
||||
|
||||
// Stick your fake hard forks in here if you're into that sort of thing.
|
||||
extern std::vector<hard_fork> fakechain_hardforks;
|
||||
|
||||
// Returns an iteratable range over hard fork values for the given network.
|
||||
std::pair<const hard_fork*, const hard_fork*> get_hard_forks(network_type type);
|
||||
|
||||
// Returns the height range for which the given block/network version is valid. Returns a pair of
|
||||
// heights {A, B} where A/B is the first/last height at which the version is acceptable. Returns
|
||||
// nullopt for A if the version indicates a hardfork we do not know about (i.e. we are likely
|
||||
// outdated), and returns nullopt for B if the version indicates that top network version we know
|
||||
// about (i.e. there is no subsequent hardfork scheduled).
|
||||
std::pair<std::optional<uint64_t>, std::optional<uint64_t>>
|
||||
get_hard_fork_heights(network_type type, uint8_t version);
|
||||
|
||||
// Returns the lowest network version >= the given version, that is, it rounds up missing hf table
|
||||
// entries to the next largest entry. Typically this returns the network version itself, but if
|
||||
// some versions are skipped (particularly on testnet/devnet/fakechain) then this will return the
|
||||
// next version that does exist in the hard fork list. If there is no >= value in the hard fork
|
||||
// table then this returns the given hard fork value itself.
|
||||
//
|
||||
// For example, if the HF list contains hf versions {7,8,14} then:
|
||||
// hard_fork_ceil(7) == 7
|
||||
// hard_fork_ceil(8) == 8
|
||||
// hard_fork_ceil(9) == 14
|
||||
// ...
|
||||
// hard_fork_ceil(14) == 14
|
||||
// hard_fork_ceil(15) == 15
|
||||
uint8_t hard_fork_ceil(network_type type, uint8_t version);
|
||||
|
||||
// Returns true if the given height is sufficiently high to be at or after the given hard fork
|
||||
// version.
|
||||
bool is_hard_fork_at_least(network_type type, uint8_t version, uint64_t height);
|
||||
|
||||
// Returns the active network version and snode revision for the given height.
|
||||
std::pair<uint8_t, uint8_t>
|
||||
get_network_version_revision(network_type nettype, uint64_t height);
|
||||
|
||||
// Returns the network (i.e. block) version for the given height.
|
||||
inline uint8_t get_network_version(network_type nettype, uint64_t height) {
|
||||
return get_network_version_revision(nettype, height).first;
|
||||
}
|
||||
|
||||
// Returns the first height at which the given network version rules become active. This is
|
||||
// a shortcut for `get_hard_fork_heights(type, hard_fork_ceil(type, version)).first`, i.e. it
|
||||
// returns the first height at which `version` rules become active (even if they became active at
|
||||
// a hard fork > the given value).
|
||||
inline std::optional<uint64_t> hard_fork_begins(network_type type, uint8_t version) {
|
||||
return get_hard_fork_heights(type, hard_fork_ceil(type, version)).first;
|
||||
}
|
||||
|
||||
// Returns the "ideal" network version that we want to use on blocks we create, which is to use
|
||||
// the required major version for major version and the maximum major version we know about as
|
||||
// minor version. If this seems a bit silly, it is, and will be changed in the future.
|
||||
std::pair<uint8_t, uint8_t> get_ideal_block_version(network_type nettype, uint64_t height);
|
||||
|
||||
} // namespace cryptonote
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
|
||||
|
@ -37,6 +38,7 @@
|
|||
#include "common/hex.h"
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "cryptonote_core/cryptonote_tx_utils.h"
|
||||
#include "ringct/rctTypes.h"
|
||||
#include "tx_pool.h"
|
||||
|
@ -109,7 +111,7 @@ Blockchain::block_extended_info::block_extended_info(const alt_block_data_t &src
|
|||
|
||||
//------------------------------------------------------------------
|
||||
Blockchain::Blockchain(tx_memory_pool& tx_pool, service_nodes::service_node_list& service_node_list):
|
||||
m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_current_block_cumul_weight_limit(0), m_current_block_cumul_weight_median(0),
|
||||
m_db(), m_tx_pool(tx_pool), m_current_block_cumul_weight_limit(0), m_current_block_cumul_weight_median(0),
|
||||
m_max_prepare_blocks_threads(4), m_db_sync_on_blocks(true), m_db_sync_threshold(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_bytes_to_sync(0), m_cancel(false),
|
||||
m_long_term_block_weights_window(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE),
|
||||
m_long_term_effective_median_block_weight(0),
|
||||
|
@ -298,8 +300,8 @@ uint64_t Blockchain::get_current_blockchain_height(bool lock) const
|
|||
//------------------------------------------------------------------
|
||||
bool Blockchain::load_missing_blocks_into_oxen_subsystems()
|
||||
{
|
||||
uint64_t const snl_height = std::max(m_hardfork->get_earliest_ideal_height_for_version(network_version_9_service_nodes), m_service_node_list.height() + 1);
|
||||
uint64_t const ons_height = std::max(m_hardfork->get_earliest_ideal_height_for_version(network_version_15_ons), m_ons_db.height() + 1);
|
||||
uint64_t const snl_height = std::max(hard_fork_begins(m_nettype, network_version_9_service_nodes).value_or(0), m_service_node_list.height() + 1);
|
||||
uint64_t const ons_height = std::max(hard_fork_begins(m_nettype, network_version_15_ons).value_or(0), m_ons_db.height() + 1);
|
||||
uint64_t const end_height = m_db->height();
|
||||
uint64_t const start_height = std::min(end_height, std::min(ons_height, snl_height));
|
||||
|
||||
|
@ -444,28 +446,9 @@ bool Blockchain::init(BlockchainDB* db, sqlite3 *ons_db, const network_type nett
|
|||
|
||||
m_offline = offline;
|
||||
m_fixed_difficulty = fixed_difficulty;
|
||||
if (m_hardfork == nullptr)
|
||||
m_hardfork = new HardFork(*db, 7);
|
||||
|
||||
if (test_options) // Fakechain mode or in integration testing mode we're overriding hardfork dates
|
||||
{
|
||||
for (auto n = 0u; n < test_options->hard_forks.size(); ++n)
|
||||
{
|
||||
const auto& hf = test_options->hard_forks.at(n);
|
||||
m_hardfork->add_fork(hf.first, hf.second, 0, n + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto &record : HardFork::get_hardcoded_hard_forks(m_nettype))
|
||||
{
|
||||
m_hardfork->add_fork(record.version, record.height, record.threshold, record.time);
|
||||
}
|
||||
}
|
||||
|
||||
m_hardfork->init();
|
||||
|
||||
m_db->set_hard_fork(m_hardfork);
|
||||
if (test_options) // Fakechain mode or in integration testing mode we're overriding hardfork heights
|
||||
fakechain_hardforks = test_options->hard_forks;
|
||||
|
||||
// if the blockchain is new, add the genesis block
|
||||
// this feels kinda kludgy to do it this way, but can be looked at later.
|
||||
|
@ -519,7 +502,7 @@ bool Blockchain::init(BlockchainDB* db, sqlite3 *ons_db, const network_type nett
|
|||
uint64_t top_height;
|
||||
const crypto::hash top_id = m_db->top_block_hash(&top_height);
|
||||
const block top_block = m_db->get_top_block();
|
||||
const uint8_t ideal_hf_version = get_ideal_hard_fork_version(top_height);
|
||||
const uint8_t ideal_hf_version = get_network_version(top_height);
|
||||
if (ideal_hf_version <= 1 || ideal_hf_version == top_block.major_version)
|
||||
{
|
||||
if (num_popped_blocks > 0)
|
||||
|
@ -556,7 +539,6 @@ bool Blockchain::init(BlockchainDB* db, sqlite3 *ons_db, const network_type nett
|
|||
if (num_popped_blocks > 0)
|
||||
{
|
||||
m_cache.m_timestamps_and_difficulties_height = 0;
|
||||
m_hardfork->reorganize_from_chain_height(get_current_blockchain_height());
|
||||
m_tx_pool.on_blockchain_dec();
|
||||
}
|
||||
|
||||
|
@ -592,16 +574,6 @@ bool Blockchain::init(BlockchainDB* db, sqlite3 *ons_db, const network_type nett
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::init(BlockchainDB* db, HardFork*& hf, sqlite3 *ons_db, const network_type nettype, bool offline)
|
||||
{
|
||||
if (hf != nullptr)
|
||||
m_hardfork = hf;
|
||||
bool res = init(db, ons_db, nettype, offline, NULL);
|
||||
if (hf == nullptr)
|
||||
hf = m_hardfork;
|
||||
return res;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::store_blockchain()
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
@ -663,10 +635,8 @@ bool Blockchain::deinit()
|
|||
LOG_ERROR("There was an issue closing/storing the blockchain, shutting down now to prevent issues!");
|
||||
}
|
||||
|
||||
delete m_hardfork;
|
||||
m_hardfork = NULL;
|
||||
delete m_db;
|
||||
m_db = NULL;
|
||||
m_db = nullptr;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
@ -749,8 +719,6 @@ block Blockchain::pop_block_from_blockchain()
|
|||
throw;
|
||||
}
|
||||
|
||||
// make sure the hard fork object updates its current version
|
||||
m_hardfork->on_block_popped(1);
|
||||
m_ons_db.block_detach(*this, m_db->height());
|
||||
|
||||
// return transactions from popped block to the tx_pool
|
||||
|
@ -766,10 +734,7 @@ block Blockchain::pop_block_from_blockchain()
|
|||
{
|
||||
cryptonote::tx_verification_context tvc{};
|
||||
|
||||
// FIXME: HardFork
|
||||
// Besides the below, popping a block should also remove the last entry
|
||||
// in hf_versions.
|
||||
uint8_t version = get_ideal_hard_fork_version(m_db->height());
|
||||
uint8_t version = get_network_version(m_db->height());
|
||||
|
||||
// We assume that if they were in a block, the transactions are already
|
||||
// known to the network as a whole. However, if we had mined that block,
|
||||
|
@ -804,7 +769,6 @@ bool Blockchain::reset_and_set_genesis_block(const block& b)
|
|||
invalidate_block_template_cache();
|
||||
m_db->reset();
|
||||
m_db->drop_alt_blocks();
|
||||
m_hardfork->init();
|
||||
|
||||
for (InitHook* hook : m_init_hooks)
|
||||
hook->init();
|
||||
|
@ -967,7 +931,7 @@ difficulty_type Blockchain::get_difficulty_for_next_block(bool pulse)
|
|||
if (pulse)
|
||||
return PULSE_FIXED_DIFFICULTY;
|
||||
|
||||
uint8_t const hf_version = get_current_hard_fork_version();
|
||||
uint8_t const hf_version = get_network_version();
|
||||
crypto::hash top_hash = get_tail_id();
|
||||
{
|
||||
std::unique_lock diff_lock{m_cache.m_difficulty_lock};
|
||||
|
@ -989,7 +953,7 @@ difficulty_type Blockchain::get_difficulty_for_next_block(bool pulse)
|
|||
uint64_t diff = next_difficulty_v2(m_cache.m_timestamps,
|
||||
m_cache.m_difficulties,
|
||||
tools::to_seconds(TARGET_BLOCK_TIME),
|
||||
difficulty_mode(m_nettype, hf_version, chain_height));
|
||||
difficulty_mode(m_nettype, chain_height));
|
||||
|
||||
m_cache.m_timestamps_and_difficulties_height = chain_height;
|
||||
|
||||
|
@ -1037,9 +1001,6 @@ bool Blockchain::rollback_blockchain_switching(const std::list<block_and_checkpo
|
|||
hook->blockchain_detached(rollback_height, false /*by_pop_blocks*/);
|
||||
load_missing_blocks_into_oxen_subsystems();
|
||||
|
||||
// make sure the hard fork object updates its current version
|
||||
m_hardfork->reorganize_from_chain_height(rollback_height);
|
||||
|
||||
//return back original chain
|
||||
for (auto& entry : original_chain)
|
||||
{
|
||||
|
@ -1048,7 +1009,6 @@ bool Blockchain::rollback_blockchain_switching(const std::list<block_and_checkpo
|
|||
CHECK_AND_ASSERT_MES(r && bvc.m_added_to_main_chain, false, "PANIC! failed to add (again) block while chain switching during the rollback!");
|
||||
}
|
||||
|
||||
m_hardfork->reorganize_from_chain_height(rollback_height);
|
||||
MINFO("Rollback to height " << rollback_height << " was successful.");
|
||||
if (!original_chain.empty())
|
||||
{
|
||||
|
@ -1159,7 +1119,6 @@ bool Blockchain::switch_to_alternative_blockchain(const std::list<block_extended
|
|||
m_db->remove_alt_block(cryptonote::get_block_hash(bei.bl));
|
||||
}
|
||||
|
||||
m_hardfork->reorganize_from_chain_height(split_height);
|
||||
get_block_longhash_reorg(split_height);
|
||||
|
||||
std::shared_ptr<tools::Notify> reorg_notify = m_reorg_notify;
|
||||
|
@ -1196,10 +1155,7 @@ difficulty_type Blockchain::get_difficulty_for_alternative_chain(const std::list
|
|||
if (alt_chain.size())
|
||||
before_hf16 = alt_chain.back().bl.major_version < network_version_16_pulse;
|
||||
else
|
||||
{
|
||||
static const uint64_t hf16_height = HardFork::get_hardcoded_hard_fork_height(m_nettype, cryptonote::network_version_16_pulse);
|
||||
before_hf16 = get_current_blockchain_height() < hf16_height;
|
||||
}
|
||||
before_hf16 = !is_hard_fork_at_least(m_nettype, cryptonote::network_version_16_pulse, get_current_blockchain_height());
|
||||
|
||||
block_count = DIFFICULTY_BLOCKS_COUNT(before_hf16);
|
||||
}
|
||||
|
@ -1262,7 +1218,7 @@ difficulty_type Blockchain::get_difficulty_for_alternative_chain(const std::list
|
|||
return next_difficulty_v2(timestamps,
|
||||
cumulative_difficulties,
|
||||
tools::to_seconds(TARGET_BLOCK_TIME),
|
||||
difficulty_mode(m_nettype, get_current_hard_fork_version(), height));
|
||||
difficulty_mode(m_nettype, height));
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
// This function does a sanity check on basic things that all miner
|
||||
|
@ -1551,8 +1507,9 @@ bool Blockchain::create_block_template_internal(block& b, const crypto::hash *fr
|
|||
{
|
||||
height = alt_chain.back().height + 1;
|
||||
}
|
||||
b.major_version = m_hardfork->get_ideal_version(height);
|
||||
b.minor_version = m_hardfork->get_ideal_version();
|
||||
auto [maj, min] = get_ideal_block_version(m_nettype, height);
|
||||
b.major_version = maj;
|
||||
b.minor_version = min;
|
||||
b.prev_id = *from_block;
|
||||
|
||||
// cheat and use the weight of the block we start from, virtually certain to be acceptable
|
||||
|
@ -1578,8 +1535,9 @@ bool Blockchain::create_block_template_internal(block& b, const crypto::hash *fr
|
|||
else
|
||||
{
|
||||
height = m_db->height();
|
||||
b.major_version = m_hardfork->get_current_version();
|
||||
b.minor_version = m_hardfork->get_ideal_version();
|
||||
auto [maj, min] = get_ideal_block_version(m_nettype, height);
|
||||
b.major_version = maj;
|
||||
b.minor_version = min;
|
||||
b.prev_id = get_tail_id();
|
||||
median_weight = m_current_block_cumul_weight_limit / 2;
|
||||
diffic = get_difficulty_for_next_block(!info.is_miner);
|
||||
|
@ -2862,6 +2820,12 @@ bool Blockchain::add_block_as_invalid(cryptonote::block const &block)
|
|||
MINFO("BLOCK ADDED AS INVALID: " << (*i_res.first) << std::endl << ", prev_id=" << block.prev_id << ", m_invalid_blocks count=" << m_invalid_blocks.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t Blockchain::get_network_version(std::optional<uint64_t> height) const {
|
||||
if (!height) height = get_current_blockchain_height();
|
||||
return cryptonote::get_network_version(m_nettype, *height);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
void Blockchain::flush_invalid_blocks()
|
||||
{
|
||||
|
@ -3067,7 +3031,8 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
|||
return true;
|
||||
|
||||
// from v10, allow bulletproofs
|
||||
const uint8_t hf_version = m_hardfork->get_current_version();
|
||||
auto height = get_current_blockchain_height();
|
||||
const uint8_t hf_version = get_network_version(height);
|
||||
if (hf_version < network_version_10_bulletproofs) {
|
||||
const bool bulletproof = rct::is_rct_bulletproof(tx.rct_signatures.type);
|
||||
if (bulletproof || !tx.rct_signatures.p.bulletproofs.empty())
|
||||
|
@ -3077,27 +3042,17 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
|||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (rct::is_rct_borromean(tx.rct_signatures.type))
|
||||
{
|
||||
const bool borromean = rct::is_rct_borromean(tx.rct_signatures.type);
|
||||
if (borromean)
|
||||
// The HF10 block height itself was allowed to (and did) have a Borromean tx as an exception
|
||||
// to the HF10 rules so that a borderline tx didn't end up unmineable, hence the strict `>`
|
||||
// here:
|
||||
if (auto hf10_height = hard_fork_begins(m_nettype, network_version_10_bulletproofs);
|
||||
hf10_height && height > *hf10_height)
|
||||
{
|
||||
uint64_t hf10_height = m_hardfork->get_earliest_ideal_height_for_version(network_version_10_bulletproofs);
|
||||
uint64_t curr_height = this->get_current_blockchain_height();
|
||||
if (curr_height == hf10_height)
|
||||
{
|
||||
// NOTE(oxen): Allow the hardforking block to contain a borromean proof
|
||||
// incase there were some transactions in the TX Pool that were
|
||||
// generated pre-HF10 rules. Note, this isn't bulletproof. If there were
|
||||
// more than 1 blocks worth of borromean proof TX's sitting in the pool
|
||||
// this isn't going to work.
|
||||
}
|
||||
else
|
||||
{
|
||||
MERROR_VER("Borromean range proofs are not allowed after v10");
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
MERROR_VER("Borromean range proofs are not allowed after v10");
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3136,10 +3091,11 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
|||
|
||||
// Require CLSAGs starting 10 blocks after the CLSAG-enabling hard fork (the 10 block buffer is to
|
||||
// allow staggling txes around fork time to still make it into a block).
|
||||
// NB: there *are* such txes on mainnet in this 10-block window so this code has to stay.
|
||||
if (hf_version >= HF_VERSION_CLSAG
|
||||
&& tx.rct_signatures.type < rct::RCTType::CLSAG
|
||||
&& tx.version >= txversion::v4_tx_types && tx.is_transfer()
|
||||
&& (hf_version > HF_VERSION_CLSAG || get_current_blockchain_height() >= 10 + m_hardfork->get_earliest_ideal_height_for_version(HF_VERSION_CLSAG)))
|
||||
&& (hf_version > HF_VERSION_CLSAG || height >= 10 + *hard_fork_begins(m_nettype, HF_VERSION_CLSAG)))
|
||||
{
|
||||
MERROR_VER("Ringct type " << (unsigned)tx.rct_signatures.type << " is not allowed from v" << HF_VERSION_CLSAG);
|
||||
tvc.m_invalid_output = true;
|
||||
|
@ -3256,7 +3212,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
|||
pmax_used_block_height = &max_used_block_height;
|
||||
*pmax_used_block_height = 0;
|
||||
|
||||
const auto hf_version = m_hardfork->get_current_version();
|
||||
const auto hf_version = get_network_version();
|
||||
|
||||
// Min/Max Type/Version Check
|
||||
{
|
||||
|
@ -3571,23 +3527,20 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
|||
return false;
|
||||
}
|
||||
|
||||
auto const quorum_type = service_nodes::quorum_type::obligations;
|
||||
auto const quorum = m_service_node_list.get_quorum(quorum_type, state_change.block_height);
|
||||
auto quorum = m_service_node_list.get_quorum(service_nodes::quorum_type::obligations, state_change.block_height);
|
||||
if (!quorum)
|
||||
{
|
||||
if (!quorum)
|
||||
{
|
||||
MERROR_VER("could not get obligations quorum for recent state change tx");
|
||||
return false;
|
||||
}
|
||||
MERROR_VER("could not get obligations quorum for recent state change tx");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!service_nodes::verify_tx_state_change(state_change, get_current_blockchain_height(), tvc, *quorum, hf_version))
|
||||
{
|
||||
// will be set by the above on serious failures (i.e. illegal value), but not for less
|
||||
// serious ones like state change heights slightly outside of allowed bounds:
|
||||
//tvc.m_verifivation_failed = true;
|
||||
MERROR_VER("tx " << get_transaction_hash(tx) << ": state change tx could not be completely verified reason: " << print_vote_verification_context(tvc.m_vote_ctx));
|
||||
return false;
|
||||
}
|
||||
if (!service_nodes::verify_tx_state_change(state_change, get_current_blockchain_height(), tvc, *quorum, hf_version))
|
||||
{
|
||||
// will be set by the above on serious failures (i.e. illegal value), but not for less
|
||||
// serious ones like state change heights slightly outside of allowed bounds:
|
||||
//tvc.m_verifivation_failed = true;
|
||||
MERROR_VER("tx " << get_transaction_hash(tx) << ": state change tx could not be completely verified reason: " << print_vote_verification_context(tvc.m_vote_ctx));
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::public_key const &state_change_service_node_pubkey = quorum->workers[state_change.service_node_index];
|
||||
|
@ -3743,7 +3696,7 @@ byte_and_output_fees Blockchain::get_dynamic_base_fee(uint64_t block_reward, siz
|
|||
//------------------------------------------------------------------
|
||||
bool Blockchain::check_fee(size_t tx_weight, size_t tx_outs, uint64_t fee, uint64_t burned, const tx_pool_options &opts) const
|
||||
{
|
||||
const uint8_t version = get_current_hard_fork_version();
|
||||
const uint8_t version = get_network_version();
|
||||
const uint64_t blockchain_height = get_current_blockchain_height();
|
||||
|
||||
uint64_t median = m_current_block_cumul_weight_limit / 2;
|
||||
|
@ -3802,7 +3755,7 @@ bool Blockchain::check_fee(size_t tx_weight, size_t tx_outs, uint64_t fee, uint6
|
|||
//------------------------------------------------------------------
|
||||
byte_and_output_fees Blockchain::get_dynamic_base_fee_estimate(uint64_t grace_blocks) const
|
||||
{
|
||||
const uint8_t version = get_current_hard_fork_version();
|
||||
const uint8_t version = get_network_version();
|
||||
const uint64_t db_height = m_db->height();
|
||||
|
||||
if (grace_blocks >= CRYPTONOTE_REWARD_BLOCKS_WINDOW)
|
||||
|
@ -3964,7 +3917,7 @@ bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) cons
|
|||
//------------------------------------------------------------------
|
||||
void Blockchain::return_tx_to_pool(std::vector<std::pair<transaction, blobdata>> &txs)
|
||||
{
|
||||
uint8_t version = get_current_hard_fork_version();
|
||||
uint8_t version = get_network_version();
|
||||
for (auto& tx : txs)
|
||||
{
|
||||
cryptonote::tx_verification_context tvc{};
|
||||
|
@ -4020,7 +3973,7 @@ Blockchain::block_pow_verified Blockchain::verify_block_pow(cryptonote::block co
|
|||
// Hence this hack: starting at that block until the next hard fork, we allow a slight grace
|
||||
// (0.2%) on the required difficulty (but we don't *change* the actual difficulty value used for
|
||||
// diff calculation).
|
||||
if (cryptonote::get_block_height(blk) >= 526483 && m_hardfork->get_current_version() < network_version_16_pulse)
|
||||
if (cryptonote::get_block_height(blk) >= 526483 && get_network_version() < network_version_16_pulse)
|
||||
difficulty = (difficulty * 998) / 1000;
|
||||
|
||||
CHECK_AND_ASSERT_MES(difficulty, result, "!!!!!!!!! difficulty overhead !!!!!!!!!");
|
||||
|
@ -4102,7 +4055,7 @@ bool Blockchain::basic_block_checks(cryptonote::block const &blk, bool alt_block
|
|||
const crypto::hash blk_hash = cryptonote::get_block_hash(blk);
|
||||
const uint64_t blk_height = cryptonote::get_block_height(blk);
|
||||
const uint64_t chain_height = get_current_blockchain_height();
|
||||
const uint8_t hf_version = get_current_hard_fork_version();
|
||||
const uint8_t hf_version = get_network_version();
|
||||
|
||||
if (alt_block)
|
||||
{
|
||||
|
@ -4119,9 +4072,11 @@ bool Blockchain::basic_block_checks(cryptonote::block const &blk, bool alt_block
|
|||
}
|
||||
|
||||
// this is a cheap test
|
||||
if (!m_hardfork->check_for_height(blk, blk_height))
|
||||
// HF19 TODO: remove the requirement that minor_version must be >= network version
|
||||
if (auto v = get_network_version(blk_height); blk.major_version != v || blk.minor_version < v)
|
||||
{
|
||||
LOG_PRINT_L1("Block with id: " << blk_hash << ", has old version: " << +blk.major_version << ", current: " << +hf_version << " for height " << blk_height);
|
||||
LOG_PRINT_L1("Block with id: " << blk_hash << ", has invalid version " << +blk.major_version << "." << +blk.minor_version <<
|
||||
"; current: " << +v << "." << +v << " for height " << blk_height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -4134,21 +4089,28 @@ bool Blockchain::basic_block_checks(cryptonote::block const &blk, bool alt_block
|
|||
return false;
|
||||
}
|
||||
|
||||
for (static bool seen_future_version = false;
|
||||
!seen_future_version && blk.major_version > m_hardfork->get_ideal_version();
|
||||
seen_future_version = true)
|
||||
auto required_major_version = get_network_version();
|
||||
if (blk.major_version > required_major_version)
|
||||
{
|
||||
const el::Level level = el::Level::Warning;
|
||||
MCLOG_RED(level, "global", "**********************************************************************");
|
||||
MCLOG_RED(level, "global", "A block was seen on the network with a version higher than the last");
|
||||
MCLOG_RED(level, "global", "known one. This may be an old version of the daemon, and a software");
|
||||
MCLOG_RED(level, "global", "update may be required to sync further. Try running: update check");
|
||||
MCLOG_RED(level, "global", "**********************************************************************");
|
||||
// Show a warning at most once every 5 minutes if we are receiving future hf blocks
|
||||
std::lock_guard lock{last_outdated_warning_mutex};
|
||||
if (auto now = std::chrono::steady_clock::now(); now > last_outdated_warning + 5min)
|
||||
{
|
||||
last_outdated_warning = now;
|
||||
const el::Level level = el::Level::Warning;
|
||||
MCLOG_RED(level, "global", "**********************************************************************");
|
||||
MCLOG_RED(level, "global", "A block was seen on the network with a version higher than the last");
|
||||
MCLOG_RED(level, "global", "known one. This may be an old version of the daemon, and a software");
|
||||
MCLOG_RED(level, "global", "update may be required to sync further. Try running: update check");
|
||||
MCLOG_RED(level, "global", "**********************************************************************");
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_hardfork->check(blk))
|
||||
// HF19 TODO: remove the requirement that minor_version must be >= network version
|
||||
if (blk.major_version != required_major_version || blk.minor_version < required_major_version)
|
||||
{
|
||||
MGINFO_RED("Block with id: " << blk_hash << ", has old version: " << +blk.major_version << ", current: " << (unsigned)m_hardfork->get_current_version());
|
||||
MGINFO_RED("Block with id: " << blk_hash << ", has invalid version " << +blk.major_version << "." << +blk.minor_version <<
|
||||
"; current: " << +required_major_version << "." << +required_major_version << " for height " << blk_height);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4365,7 +4327,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
|
|||
TIME_MEASURE_START(vmt);
|
||||
uint64_t base_reward = 0;
|
||||
uint64_t already_generated_coins = chain_height ? m_db->get_block_already_generated_coins(chain_height - 1) : 0;
|
||||
if(!validate_miner_transaction(bl, cumulative_block_weight, fee_summary, base_reward, already_generated_coins, m_hardfork->get_current_version()))
|
||||
if(!validate_miner_transaction(bl, cumulative_block_weight, fee_summary, base_reward, already_generated_coins, get_network_version()))
|
||||
{
|
||||
MGINFO_RED("Block " << (chain_height - 1) << " with id: " << id << " has incorrect miner transaction");
|
||||
bvc.m_verifivation_failed = true;
|
||||
|
@ -4552,8 +4514,7 @@ uint64_t Blockchain::get_next_long_term_block_weight(uint64_t block_weight) cons
|
|||
const uint64_t db_height = m_db->height();
|
||||
const uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights_window, db_height);
|
||||
|
||||
const uint8_t hf_version = get_current_hard_fork_version();
|
||||
if (hf_version < HF_VERSION_LONG_TERM_BLOCK_WEIGHT)
|
||||
if (!is_hard_fork_at_least(m_nettype, HF_VERSION_LONG_TERM_BLOCK_WEIGHT, get_current_blockchain_height()))
|
||||
return block_weight;
|
||||
|
||||
uint64_t long_term_median = get_long_term_block_weight_median(db_height - nblocks, nblocks);
|
||||
|
@ -4573,7 +4534,7 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
|
|||
|
||||
// when we reach this, the last hf version is not yet written to the db
|
||||
const uint64_t db_height = m_db->height();
|
||||
const uint8_t hf_version = get_current_hard_fork_version();
|
||||
const uint8_t hf_version = get_network_version();
|
||||
uint64_t full_reward_zone = get_min_block_weight(hf_version);
|
||||
|
||||
if (hf_version < HF_VERSION_LONG_TERM_BLOCK_WEIGHT)
|
||||
|
@ -4976,7 +4937,7 @@ uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector
|
|||
bool Blockchain::calc_batched_governance_reward(uint64_t height, uint64_t &reward) const
|
||||
{
|
||||
reward = 0;
|
||||
auto hard_fork_version = get_ideal_hard_fork_version(height);
|
||||
auto hard_fork_version = get_network_version(height);
|
||||
if (hard_fork_version <= network_version_9_service_nodes)
|
||||
{
|
||||
return true;
|
||||
|
@ -5453,16 +5414,6 @@ void Blockchain::safesyncmode(const bool onoff)
|
|||
}
|
||||
}
|
||||
|
||||
HardFork::State Blockchain::get_hard_fork_state() const
|
||||
{
|
||||
return m_hardfork->get_state();
|
||||
}
|
||||
|
||||
bool Blockchain::get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const
|
||||
{
|
||||
return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting);
|
||||
}
|
||||
|
||||
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> Blockchain:: get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff, uint64_t min_count) const
|
||||
{
|
||||
return m_db->get_output_histogram(amounts, unlocked, recent_cutoff, min_count);
|
||||
|
|
|
@ -61,7 +61,6 @@
|
|||
#include "cryptonote_basic/verification_context.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "checkpoints/checkpoints.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "cryptonote_core/oxen_name_system.h"
|
||||
#include "pulse.h"
|
||||
|
@ -149,19 +148,7 @@ namespace cryptonote
|
|||
*
|
||||
* @return true on success, false if any initialization steps fail
|
||||
*/
|
||||
bool init(BlockchainDB* db, sqlite3 *ons_db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL, difficulty_type fixed_difficulty = 0, const GetCheckpointsCallback& get_checkpoints = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Initialize the Blockchain state
|
||||
*
|
||||
* @param db a pointer to the backing store to use for the blockchain
|
||||
* @param hf a structure containing hardfork information
|
||||
* @param nettype network type
|
||||
* @param offline true if running offline, else false
|
||||
*
|
||||
* @return true on success, false if any initialization steps fail
|
||||
*/
|
||||
bool init(BlockchainDB* db, HardFork*& hf, sqlite3 *ons_db, const network_type nettype = MAINNET, bool offline = false);
|
||||
bool init(BlockchainDB* db, sqlite3 *ons_db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = nullptr, difficulty_type fixed_difficulty = 0, const GetCheckpointsCallback& get_checkpoints = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Uninitializes the blockchain state
|
||||
|
@ -822,72 +809,12 @@ namespace cryptonote
|
|||
void set_show_time_stats(bool stats) { m_show_time_stats = stats; }
|
||||
|
||||
/**
|
||||
* @brief gets the hardfork voting state object
|
||||
*
|
||||
* @return the HardFork object
|
||||
*/
|
||||
HardFork::State get_hard_fork_state() const;
|
||||
|
||||
/**
|
||||
* @brief gets the current hardfork version in use/voted for
|
||||
* @brief gets the network hard fork version of the blockchain at the given height.
|
||||
* If height is omitted, uses the current blockchain height.
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
uint8_t get_current_hard_fork_version() const { return m_hardfork->get_current_version(); }
|
||||
|
||||
/**
|
||||
* @brief returns the newest hardfork version known to the blockchain
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
uint8_t get_ideal_hard_fork_version() const { return m_hardfork->get_ideal_version(); }
|
||||
|
||||
/**
|
||||
* @brief returns the next hardfork version
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
uint8_t get_next_hard_fork_version() const { return m_hardfork->get_next_version(); }
|
||||
|
||||
/**
|
||||
* @brief returns the newest hardfork version voted to be enabled
|
||||
* as of a certain height
|
||||
*
|
||||
* @param height the height for which to check version info
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
uint8_t get_ideal_hard_fork_version(uint64_t height) const { return m_hardfork->get_ideal_version(height); }
|
||||
|
||||
/**
|
||||
* @brief returns the actual hardfork version for a given block height
|
||||
*
|
||||
* @param height the height for which to check version info
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
uint8_t get_hard_fork_version(uint64_t height) const { return m_hardfork->get(height); }
|
||||
|
||||
/**
|
||||
* @brief returns the earliest block a given version may activate
|
||||
*
|
||||
* @return the height
|
||||
*/
|
||||
uint64_t get_earliest_ideal_height_for_version(uint8_t version) const { return m_hardfork->get_earliest_ideal_height_for_version(version); }
|
||||
|
||||
/**
|
||||
* @brief get information about hardfork voting for a version
|
||||
*
|
||||
* @param version the version in question
|
||||
* @param window the size of the voting window
|
||||
* @param votes the number of votes to enable <version>
|
||||
* @param threshold the number of votes required to enable <version>
|
||||
* @param earliest_height the earliest height at which <version> is allowed
|
||||
* @param voting which version this node is voting for/using
|
||||
*
|
||||
* @return whether the version queried is enabled
|
||||
*/
|
||||
bool get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const;
|
||||
uint8_t get_network_version(std::optional<uint64_t> height = std::nullopt) const;
|
||||
|
||||
/**
|
||||
* @brief remove transactions from the transaction pool (if present)
|
||||
|
@ -1194,7 +1121,6 @@ namespace cryptonote
|
|||
std::vector<AltBlockAddedHook*> m_alt_block_added_hooks;
|
||||
|
||||
checkpoints m_checkpoints;
|
||||
HardFork *m_hardfork;
|
||||
|
||||
network_type m_nettype;
|
||||
bool m_offline;
|
||||
|
@ -1222,6 +1148,9 @@ namespace cryptonote
|
|||
uint64_t m_prepare_nblocks;
|
||||
std::vector<block> *m_prepare_blocks;
|
||||
|
||||
std::chrono::steady_clock::time_point last_outdated_warning = {};
|
||||
std::mutex last_outdated_warning_mutex;
|
||||
|
||||
/**
|
||||
* @brief collects the keys for all outputs being "spent" as an input
|
||||
*
|
||||
|
|
|
@ -60,6 +60,7 @@ extern "C" {
|
|||
#include "epee/warnings.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "epee/misc_language.h"
|
||||
#include <csignal>
|
||||
#include "checkpoints/checkpoints.h"
|
||||
|
@ -791,13 +792,14 @@ namespace cryptonote
|
|||
MERROR("Failed to parse block rate notify spec");
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint8_t, uint64_t>> regtest_hard_forks;
|
||||
for (uint8_t hf = cryptonote::network_version_7; hf < cryptonote::network_version_count; hf++)
|
||||
regtest_hard_forks.emplace_back(hf, regtest_hard_forks.size() + 1);
|
||||
const cryptonote::test_options regtest_test_options = {
|
||||
std::move(regtest_hard_forks),
|
||||
0
|
||||
};
|
||||
|
||||
cryptonote::test_options regtest_test_options{};
|
||||
for (auto [it, end] = get_hard_forks(network_type::MAINNET);
|
||||
it != end;
|
||||
it++) {
|
||||
regtest_test_options.hard_forks.push_back(hard_fork{
|
||||
it->version, it->snode_revision, regtest_test_options.hard_forks.size(), std::time(nullptr)});
|
||||
}
|
||||
|
||||
// Service Nodes
|
||||
{
|
||||
|
@ -832,7 +834,7 @@ namespace cryptonote
|
|||
|
||||
// now that we have a valid m_blockchain_storage, we can clean out any
|
||||
// transactions in the pool that do not conform to the current fork
|
||||
m_mempool.validate(m_blockchain_storage.get_current_hard_fork_version());
|
||||
m_mempool.validate(m_blockchain_storage.get_network_version());
|
||||
|
||||
bool show_time_stats = command_line::get_arg(vm, arg_show_time_stats) != 0;
|
||||
m_blockchain_storage.set_show_time_stats(show_time_stats);
|
||||
|
@ -1346,7 +1348,7 @@ namespace cryptonote
|
|||
{
|
||||
// Caller needs to do this around both this *and* parse_incoming_txs
|
||||
//auto lock = incoming_tx_lock();
|
||||
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
|
||||
uint8_t version = m_blockchain_storage.get_network_version();
|
||||
bool ok = true;
|
||||
bool tx_pool_changed = false;
|
||||
if (blink_rollback_height)
|
||||
|
@ -1415,7 +1417,7 @@ namespace cryptonote
|
|||
auto &new_blinks = results.first;
|
||||
auto &missing_txs = results.second;
|
||||
|
||||
if (m_blockchain_storage.get_current_hard_fork_version() < HF_VERSION_BLINK)
|
||||
if (m_blockchain_storage.get_network_version() < HF_VERSION_BLINK)
|
||||
return results;
|
||||
|
||||
std::vector<uint8_t> want(blinks.size(), false); // Really bools, but std::vector<bool> is broken.
|
||||
|
@ -1870,7 +1872,7 @@ namespace cryptonote
|
|||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_inputs_ring_members_diff(const transaction& tx) const
|
||||
{
|
||||
const uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
|
||||
const uint8_t version = m_blockchain_storage.get_network_version();
|
||||
if (version >= 6)
|
||||
{
|
||||
for(const auto& in: tx.vin)
|
||||
|
@ -1995,7 +1997,7 @@ namespace cryptonote
|
|||
bool core::relay_service_node_votes()
|
||||
{
|
||||
auto height = get_current_blockchain_height();
|
||||
auto hf_version = get_hard_fork_version(height);
|
||||
auto hf_version = get_network_version(m_nettype, height);
|
||||
|
||||
auto quorum_votes = m_quorum_cop.get_relayable_votes(height, hf_version, true);
|
||||
auto p2p_votes = m_quorum_cop.get_relayable_votes(height, hf_version, false);
|
||||
|
@ -2387,7 +2389,6 @@ namespace cryptonote
|
|||
m_starter_message_showed = true;
|
||||
}
|
||||
|
||||
m_fork_moaner.do_call([this] { return check_fork_time(); });
|
||||
m_txpool_auto_relayer.do_call([this] { return relay_txpool_transactions(); });
|
||||
m_service_node_vote_relayer.do_call([this] { return relay_service_node_votes(); });
|
||||
m_check_disk_space_interval.do_call([this] { return check_disk_space(); });
|
||||
|
@ -2415,48 +2416,6 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_fork_time()
|
||||
{
|
||||
if (m_nettype == FAKECHAIN)
|
||||
return true;
|
||||
|
||||
HardFork::State state = m_blockchain_storage.get_hard_fork_state();
|
||||
const el::Level level = el::Level::Warning;
|
||||
switch (state) {
|
||||
case HardFork::LikelyForked:
|
||||
MCLOG_RED(level, "global", "**********************************************************************");
|
||||
MCLOG_RED(level, "global", "Last scheduled hard fork is too far in the past.");
|
||||
MCLOG_RED(level, "global", "We are most likely forked from the network. Daemon update needed now.");
|
||||
MCLOG_RED(level, "global", "**********************************************************************");
|
||||
break;
|
||||
case HardFork::UpdateNeeded:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
uint8_t core::get_ideal_hard_fork_version() const
|
||||
{
|
||||
return get_blockchain_storage().get_ideal_hard_fork_version();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
uint8_t core::get_ideal_hard_fork_version(uint64_t height) const
|
||||
{
|
||||
return get_blockchain_storage().get_ideal_hard_fork_version(height);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
uint8_t core::get_hard_fork_version(uint64_t height) const
|
||||
{
|
||||
return get_blockchain_storage().get_hard_fork_version(height);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
uint64_t core::get_earliest_ideal_height_for_version(uint8_t version) const
|
||||
{
|
||||
return get_blockchain_storage().get_earliest_ideal_height_for_version(version);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_disk_space()
|
||||
{
|
||||
uint64_t free_space = get_free_space();
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <boost/program_options/variables_map.hpp>
|
||||
#include <oxenmq/oxenmq.h>
|
||||
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler_common.h"
|
||||
#include "epee/storages/portable_storage_template_helper.h"
|
||||
#include "common/command_line.h"
|
||||
|
@ -60,7 +61,7 @@ DISABLE_VS_WARNINGS(4355)
|
|||
namespace cryptonote
|
||||
{
|
||||
struct test_options {
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks;
|
||||
std::vector<hard_fork> hard_forks;
|
||||
size_t long_term_block_weight_window;
|
||||
};
|
||||
|
||||
|
@ -729,34 +730,6 @@ namespace cryptonote
|
|||
*/
|
||||
uint64_t get_target_blockchain_height() const;
|
||||
|
||||
/**
|
||||
* @brief returns the newest hardfork version known to the blockchain
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
uint8_t get_ideal_hard_fork_version() const;
|
||||
|
||||
/**
|
||||
* @brief return the ideal hard fork version for a given block height
|
||||
*
|
||||
* @return what it says above
|
||||
*/
|
||||
uint8_t get_ideal_hard_fork_version(uint64_t height) const;
|
||||
|
||||
/**
|
||||
* @brief return the hard fork version for a given block height
|
||||
*
|
||||
* @return what it says above
|
||||
*/
|
||||
uint8_t get_hard_fork_version(uint64_t height) const;
|
||||
|
||||
/**
|
||||
* @brief return the earliest block a given version may activate
|
||||
*
|
||||
* @return what it says above
|
||||
*/
|
||||
uint64_t get_earliest_ideal_height_for_version(uint8_t version) const;
|
||||
|
||||
/**
|
||||
* @brief gets start_time
|
||||
*
|
||||
|
@ -1107,18 +1080,6 @@ namespace cryptonote
|
|||
*/
|
||||
bool check_tx_inputs_keyimages_domain(const transaction& tx) const;
|
||||
|
||||
/**
|
||||
* @brief checks HardFork status and prints messages about it
|
||||
*
|
||||
* Checks the status of HardFork and logs/prints if an update to
|
||||
* the daemon is necessary.
|
||||
*
|
||||
* @note see Blockchain::get_hard_fork_state and HardFork::State
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
bool check_fork_time();
|
||||
|
||||
/**
|
||||
* @brief checks free disk space
|
||||
*
|
||||
|
@ -1215,8 +1176,6 @@ namespace cryptonote
|
|||
std::mutex m_sn_timestamp_mutex;
|
||||
service_nodes::participation_history<service_nodes::timesync_entry, 30> m_sn_times;
|
||||
|
||||
tools::periodic_task m_store_blockchain_interval{12h, false}; //!< interval for manual storing of Blockchain, if enabled
|
||||
tools::periodic_task m_fork_moaner{2h}; //!< interval for checking HardFork status
|
||||
tools::periodic_task m_txpool_auto_relayer{2min, false}; //!< interval for checking re-relaying txpool transactions
|
||||
tools::periodic_task m_check_disk_space_interval{10min}; //!< interval for checking for disk space
|
||||
tools::periodic_task m_check_uptime_proof_interval{30s}; //!< interval for checking our own uptime proof (will be set to get_net_config().UPTIME_PROOF_CHECK_INTERVAL after init)
|
||||
|
|
|
@ -936,7 +936,7 @@ bool mapping_value::validate(cryptonote::network_type nettype, mapping_type type
|
|||
iter = std::copy_n(addr_info.address.m_view_public_key.data, sizeof(addr_info.address.m_view_public_key.data), iter);
|
||||
|
||||
size_t counter = 65;
|
||||
assert(std::distance(blob->buffer.begin(), iter) == counter);
|
||||
assert(std::distance(blob->buffer.begin(), iter) == static_cast<int>(counter));
|
||||
if (addr_info.has_payment_id) {
|
||||
std::copy_n(addr_info.payment_id.data, sizeof(addr_info.payment_id.data), iter);
|
||||
counter+=sizeof(addr_info.payment_id);
|
||||
|
|
|
@ -734,15 +734,12 @@ bool pulse::convert_time_to_round(pulse::time_point const &time, pulse::time_poi
|
|||
bool pulse::get_round_timings(cryptonote::Blockchain const &blockchain, uint64_t block_height, uint64_t prev_timestamp, pulse::timings ×)
|
||||
{
|
||||
times = {};
|
||||
static uint64_t const hf16_height = blockchain.get_earliest_ideal_height_for_version(cryptonote::network_version_16_pulse);
|
||||
if (hf16_height == std::numeric_limits<uint64_t>::max())
|
||||
return false;
|
||||
|
||||
if (blockchain.get_current_blockchain_height() < hf16_height)
|
||||
auto hf16 = hard_fork_begins(blockchain.nettype(), cryptonote::network_version_16_pulse);
|
||||
if (!hf16 || blockchain.get_current_blockchain_height() < *hf16)
|
||||
return false;
|
||||
|
||||
cryptonote::block genesis_block;
|
||||
if (!blockchain.get_block_by_height(hf16_height - 1, genesis_block))
|
||||
if (!blockchain.get_block_by_height(*hf16 - 1, genesis_block))
|
||||
return false;
|
||||
|
||||
uint64_t const delta_height = block_height - cryptonote::get_block_height(genesis_block);
|
||||
|
@ -1165,7 +1162,7 @@ round_state prepare_for_round(round_context &context, service_nodes::service_nod
|
|||
|
||||
std::vector<crypto::hash> const entropy = service_nodes::get_pulse_entropy_for_next_block(blockchain.get_db(), context.wait_for_next_block.top_hash, context.prepare_for_round.round);
|
||||
auto const active_node_list = blockchain.get_service_node_list().active_service_nodes_infos();
|
||||
uint8_t const hf_version = blockchain.get_current_hard_fork_version();
|
||||
uint8_t const hf_version = blockchain.get_network_version();
|
||||
crypto::public_key const &block_leader = blockchain.get_service_node_list().get_block_leader().key;
|
||||
|
||||
context.prepare_for_round.quorum =
|
||||
|
@ -1685,18 +1682,18 @@ void pulse::main(void *quorumnet_state, cryptonote::core &core)
|
|||
//
|
||||
// NOTE: Early exit if too early
|
||||
//
|
||||
static uint64_t const hf16_height = cryptonote::HardFork::get_hardcoded_hard_fork_height(blockchain.nettype(), cryptonote::network_version_16_pulse);
|
||||
if (hf16_height == cryptonote::HardFork::INVALID_HF_VERSION_HEIGHT)
|
||||
auto hf16 = hard_fork_begins(core.get_nettype(), cryptonote::network_version_16_pulse);
|
||||
if (!hf16)
|
||||
{
|
||||
for (static bool once = true; once; once = !once)
|
||||
MERROR("Pulse: HF16 is not defined, pulse worker waiting");
|
||||
return;
|
||||
}
|
||||
|
||||
if (uint64_t height = blockchain.get_current_blockchain_height(true /*lock*/); height < hf16_height)
|
||||
if (uint64_t height = blockchain.get_current_blockchain_height(true /*lock*/); height < *hf16)
|
||||
{
|
||||
for (static bool once = true; once; once = !once)
|
||||
MDEBUG("Pulse: Network at block " << height << " is not ready for Pulse until block " << hf16_height << ", waiting");
|
||||
MDEBUG("Pulse: Network at block " << height << " is not ready for Pulse until block " << *hf16 << ", waiting");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1713,7 +1710,7 @@ void pulse::main(void *quorumnet_state, cryptonote::core &core)
|
|||
break;
|
||||
|
||||
case round_state::wait_for_next_block:
|
||||
context.state = wait_for_next_block(hf16_height, context, blockchain);
|
||||
context.state = wait_for_next_block(*hf16, context, blockchain);
|
||||
break;
|
||||
|
||||
case round_state::prepare_for_round:
|
||||
|
|
|
@ -93,7 +93,7 @@ namespace service_nodes
|
|||
void service_node_list::init()
|
||||
{
|
||||
std::lock_guard lock(m_sn_mutex);
|
||||
if (m_blockchain.get_current_hard_fork_version() < 9)
|
||||
if (m_blockchain.get_network_version() < cryptonote::network_version_9_service_nodes)
|
||||
{
|
||||
reset(true);
|
||||
return;
|
||||
|
@ -471,7 +471,7 @@ namespace service_nodes
|
|||
hw::device &hwdev = hw::get_device("default");
|
||||
contribution->transferred = 0;
|
||||
bool stake_decoded = true;
|
||||
if (hf_version >= cryptonote::network_version_11_infinite_staking || hf_version == cryptonote::HardFork::INVALID_HF_VERSION)
|
||||
if (hf_version >= cryptonote::network_version_11_infinite_staking)
|
||||
{
|
||||
// In Infinite Staking, we lock the key image that would be generated if
|
||||
// you tried to send your stake and prevent it from being transacted on
|
||||
|
@ -552,7 +552,7 @@ namespace service_nodes
|
|||
}
|
||||
}
|
||||
|
||||
if (hf_version < cryptonote::network_version_11_infinite_staking || (hf_version == cryptonote::HardFork::INVALID_HF_VERSION && !stake_decoded))
|
||||
if (hf_version < cryptonote::network_version_11_infinite_staking)
|
||||
{
|
||||
// Pre Infinite Staking, we only need to prove the amount sent is
|
||||
// sufficient to become a contributor to the Service Node and that there
|
||||
|
@ -889,7 +889,7 @@ namespace service_nodes
|
|||
|
||||
// check the initial contribution exists
|
||||
|
||||
uint64_t staking_requirement = get_staking_requirement(nettype, block_height, hf_version);
|
||||
uint64_t staking_requirement = get_staking_requirement(nettype, block_height);
|
||||
cryptonote::account_public_address address;
|
||||
|
||||
staking_components stake = {};
|
||||
|
@ -2666,7 +2666,7 @@ namespace service_nodes
|
|||
if (!m_blockchain.has_db())
|
||||
return false; // Haven't been initialized yet
|
||||
|
||||
uint8_t hf_version = m_blockchain.get_current_hard_fork_version();
|
||||
uint8_t hf_version = m_blockchain.get_network_version();
|
||||
if (hf_version < cryptonote::network_version_9_service_nodes)
|
||||
return true;
|
||||
|
||||
|
@ -2747,7 +2747,7 @@ namespace service_nodes
|
|||
return true;
|
||||
}
|
||||
|
||||
//TODO: remove after HF18
|
||||
//TODO: remove after HF18, snode revision 1
|
||||
crypto::hash service_node_list::hash_uptime_proof(const cryptonote::NOTIFY_UPTIME_PROOF::request &proof) const
|
||||
{
|
||||
size_t buf_size;
|
||||
|
@ -2850,7 +2850,7 @@ namespace service_nodes
|
|||
};
|
||||
|
||||
|
||||
//TODO remove after HF18
|
||||
//TODO remove after HF18, snode revision 1
|
||||
bool proof_info::update(uint64_t ts,
|
||||
uint32_t ip,
|
||||
uint16_t s_https_port,
|
||||
|
@ -2904,10 +2904,13 @@ namespace service_nodes
|
|||
|
||||
#define REJECT_PROOF(log) do { LOG_PRINT_L2("Rejecting uptime proof from " << proof.pubkey << ": " log); return false; } while (0)
|
||||
|
||||
//TODO remove after HF18
|
||||
//TODO remove after HF18, snode revision 1
|
||||
bool service_node_list::handle_uptime_proof(cryptonote::NOTIFY_UPTIME_PROOF::request const &proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key &x25519_pkey)
|
||||
{
|
||||
uint8_t const hf_version = m_blockchain.get_current_hard_fork_version();
|
||||
auto vers = get_network_version_revision(m_blockchain.nettype(), m_blockchain.get_current_blockchain_height());
|
||||
if (vers >= std::pair<uint8_t, uint8_t>{cryptonote::network_version_18, 1})
|
||||
REJECT_PROOF("Old format (non-bt) proofs are not acceptable from v18+1 onwards");
|
||||
|
||||
auto& netconf = get_config(m_blockchain.nettype());
|
||||
auto now = std::chrono::system_clock::now();
|
||||
|
||||
|
@ -2917,8 +2920,8 @@ namespace service_nodes
|
|||
REJECT_PROOF("timestamp is too far from now");
|
||||
|
||||
for (auto const &min : MIN_UPTIME_PROOF_VERSIONS)
|
||||
if (hf_version >= min.hardfork && proof.snode_version < min.version)
|
||||
REJECT_PROOF("v" << min.version[0] << "." << min.version[1] << "." << min.version[2] << "+ oxen version is required for v" << std::to_string(hf_version) << "+ network proofs");
|
||||
if (vers >= min.hardfork_revision && proof.snode_version < min.oxend)
|
||||
REJECT_PROOF("v" << tools::join(".", min.oxend) << "+ oxend version is required for v" << +vers.first << "." << +vers.second << "+ network proofs");
|
||||
|
||||
if (!debug_allow_local_ips && !epee::net_utils::is_ip_public(proof.public_ip))
|
||||
REJECT_PROOF("public_ip is not actually public");
|
||||
|
@ -3000,7 +3003,7 @@ namespace service_nodes
|
|||
|
||||
bool service_node_list::handle_btencoded_uptime_proof(std::unique_ptr<uptime_proof::Proof> proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key &x25519_pkey)
|
||||
{
|
||||
uint8_t const hf_version = m_blockchain.get_current_hard_fork_version();
|
||||
auto vers = get_network_version_revision(m_blockchain.nettype(), m_blockchain.get_current_blockchain_height());
|
||||
auto& netconf = get_config(m_blockchain.nettype());
|
||||
auto now = std::chrono::system_clock::now();
|
||||
|
||||
|
@ -3009,9 +3012,16 @@ namespace service_nodes
|
|||
if (time_deviation > netconf.UPTIME_PROOF_TOLERANCE || time_deviation < -netconf.UPTIME_PROOF_TOLERANCE)
|
||||
REJECT_PROOF("timestamp is too far from now");
|
||||
|
||||
for (auto const &min : MIN_UPTIME_PROOF_VERSIONS)
|
||||
if (hf_version >= min.hardfork && proof->version < min.version)
|
||||
REJECT_PROOF("v" << min.version[0] << "." << min.version[1] << "." << min.version[2] << "+ oxen version is required for v" << std::to_string(hf_version) << "+ network proofs");
|
||||
for (auto const &min : MIN_UPTIME_PROOF_VERSIONS) {
|
||||
if (vers >= min.hardfork_revision) {
|
||||
if (proof->version < min.oxend)
|
||||
REJECT_PROOF("v" << tools::join(".", min.oxend) << "+ oxend version is required for v" << +vers.first << "." << +vers.second << "+ network proofs");
|
||||
if (proof->lokinet_version < min.lokinet)
|
||||
REJECT_PROOF("v" << tools::join(".", min.lokinet) << "+ lokinet version is required for v" << +vers.first << "." << +vers.second << "+ network proofs");
|
||||
if (proof->storage_server_version < min.storage_server)
|
||||
REJECT_PROOF("v" << tools::join(".", min.storage_server) << "+ storage server version is required for v" << +vers.first << "." << +vers.second << "+ network proofs");
|
||||
}
|
||||
}
|
||||
|
||||
if (!debug_allow_local_ips && !epee::net_utils::is_ip_public(proof->public_ip))
|
||||
REJECT_PROOF("public_ip is not actually public");
|
||||
|
@ -3322,7 +3332,7 @@ namespace service_nodes
|
|||
if (info.version < version_t::v1_add_registration_hf_version)
|
||||
{
|
||||
info.version = version_t::v1_add_registration_hf_version;
|
||||
info.registration_hf_version = sn_list->m_blockchain.get_hard_fork_version(pubkey_info.info->registration_height);
|
||||
info.registration_hf_version = sn_list->m_blockchain.get_network_version(pubkey_info.info->registration_height);
|
||||
}
|
||||
if (info.version < version_t::v4_noproofs)
|
||||
{
|
||||
|
@ -3552,13 +3562,7 @@ namespace service_nodes
|
|||
m_blockchain.get_db().clear_service_node_data();
|
||||
}
|
||||
|
||||
uint64_t hardfork_9_from_height = 0;
|
||||
{
|
||||
uint32_t window, votes, threshold;
|
||||
uint8_t voting;
|
||||
m_blockchain.get_hard_fork_voting_info(9, window, votes, threshold, hardfork_9_from_height, voting);
|
||||
}
|
||||
m_state.height = hardfork_9_from_height - 1;
|
||||
m_state.height = hard_fork_begins(m_blockchain.nettype(), cryptonote::network_version_9_service_nodes).value_or(1) - 1;
|
||||
}
|
||||
|
||||
size_t service_node_info::total_num_locked_contributions() const
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "uptime_proof.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "cryptonote_core.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "version.h"
|
||||
#include "common/oxen.h"
|
||||
#include "common/util.h"
|
||||
|
@ -183,7 +184,7 @@ namespace service_nodes
|
|||
|
||||
void quorum_cop::blockchain_detached(uint64_t height, bool by_pop_blocks)
|
||||
{
|
||||
uint8_t hf_version = m_core.get_hard_fork_version(height);
|
||||
uint8_t hf_version = get_network_version(m_core.get_nettype(), height);
|
||||
uint64_t const REORG_SAFETY_BUFFER_BLOCKS = (hf_version >= cryptonote::network_version_12_checkpointing)
|
||||
? REORG_SAFETY_BUFFER_BLOCKS_POST_HF12
|
||||
: REORG_SAFETY_BUFFER_BLOCKS_PRE_HF12;
|
||||
|
@ -280,7 +281,7 @@ namespace service_nodes
|
|||
m_obligations_height = std::max(m_obligations_height, start_voting_from_height);
|
||||
for (; m_obligations_height < (height - REORG_SAFETY_BUFFER_BLOCKS); m_obligations_height++)
|
||||
{
|
||||
uint8_t const obligations_height_hf_version = m_core.get_hard_fork_version(m_obligations_height);
|
||||
uint8_t const obligations_height_hf_version = get_network_version(m_core.get_nettype(), m_obligations_height);
|
||||
if (obligations_height_hf_version < cryptonote::network_version_9_service_nodes) continue;
|
||||
|
||||
// NOTE: Count checkpoints for other nodes, irrespective of being
|
||||
|
@ -476,7 +477,7 @@ namespace service_nodes
|
|||
m_last_checkpointed_height <= height;
|
||||
m_last_checkpointed_height += CHECKPOINT_INTERVAL)
|
||||
{
|
||||
uint8_t checkpointed_height_hf_version = m_core.get_hard_fork_version(m_last_checkpointed_height);
|
||||
uint8_t checkpointed_height_hf_version = get_network_version(m_core.get_nettype(), m_last_checkpointed_height);
|
||||
if (checkpointed_height_hf_version <= cryptonote::network_version_11_infinite_staking)
|
||||
continue;
|
||||
|
||||
|
@ -536,21 +537,21 @@ namespace service_nodes
|
|||
return true;
|
||||
}
|
||||
|
||||
uint8_t const hf_version = core.get_blockchain_storage().get_current_hard_fork_version();
|
||||
auto net = core.get_blockchain_storage().get_network_version();
|
||||
|
||||
// NOTE: Verify state change is still valid or have we processed some other state change already that makes it invalid
|
||||
{
|
||||
crypto::public_key const &service_node_pubkey = quorum.workers[vote.state_change.worker_index];
|
||||
auto service_node_infos = core.get_service_node_list_state({service_node_pubkey});
|
||||
if (!service_node_infos.size() ||
|
||||
!service_node_infos[0].info->can_transition_to_state(hf_version, vote.block_height, vote.state_change.state))
|
||||
!service_node_infos[0].info->can_transition_to_state(net, vote.block_height, vote.state_change.state))
|
||||
// NOTE: Vote is valid but is invalidated because we cannot apply the change to a service node or it is not on the network anymore
|
||||
// So don't bother generating a state change tx.
|
||||
return true;
|
||||
}
|
||||
|
||||
using version_t = cryptonote::tx_extra_service_node_state_change::version_t;
|
||||
auto ver = hf_version >= HF_VERSION_PROOF_BTENC ? version_t::v4_reasons : version_t::v0;
|
||||
auto ver = net >= HF_VERSION_PROOF_BTENC ? version_t::v4_reasons : version_t::v0;
|
||||
cryptonote::tx_extra_service_node_state_change state_change{
|
||||
ver,
|
||||
vote.state_change.state,
|
||||
|
@ -569,9 +570,9 @@ namespace service_nodes
|
|||
}
|
||||
|
||||
cryptonote::transaction state_change_tx{};
|
||||
if (cryptonote::add_service_node_state_change_to_tx_extra(state_change_tx.extra, state_change, hf_version))
|
||||
if (cryptonote::add_service_node_state_change_to_tx_extra(state_change_tx.extra, state_change, net))
|
||||
{
|
||||
state_change_tx.version = cryptonote::transaction::get_max_version_for_hf(hf_version);
|
||||
state_change_tx.version = cryptonote::transaction::get_max_version_for_hf(net);
|
||||
state_change_tx.type = cryptonote::txtype::state_change;
|
||||
|
||||
cryptonote::tx_verification_context tvc{};
|
||||
|
@ -677,7 +678,7 @@ namespace service_nodes
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!verify_vote_signature(m_core.get_hard_fork_version(vote.block_height), vote, vvc, *quorum))
|
||||
if (!verify_vote_signature(get_network_version(m_core.get_nettype(), vote.block_height), vote, vvc, *quorum))
|
||||
return false;
|
||||
|
||||
std::vector<pool_vote_entry> votes = m_vote_pool.add_pool_vote_if_unique(vote, vvc);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "cryptonote_config.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "common/oxen.h"
|
||||
#include "epee/int-util.h"
|
||||
#include <boost/endian/conversion.hpp>
|
||||
|
@ -12,15 +13,15 @@
|
|||
namespace service_nodes {
|
||||
|
||||
// TODO(oxen): Move to oxen_economy, this will also need access to oxen::exp2
|
||||
uint64_t get_staking_requirement(cryptonote::network_type m_nettype, uint64_t height, uint8_t hf_version)
|
||||
uint64_t get_staking_requirement(cryptonote::network_type nettype, uint64_t height)
|
||||
{
|
||||
if (m_nettype == cryptonote::TESTNET || m_nettype == cryptonote::FAKECHAIN || m_nettype == cryptonote::DEVNET)
|
||||
if (nettype == cryptonote::TESTNET || nettype == cryptonote::FAKECHAIN || nettype == cryptonote::DEVNET)
|
||||
return COIN * 100;
|
||||
|
||||
if (hf_version >= cryptonote::network_version_16_pulse)
|
||||
if (is_hard_fork_at_least(nettype, cryptonote::network_version_16_pulse, height))
|
||||
return 15000'000000000;
|
||||
|
||||
if (hf_version >= cryptonote::network_version_13_enforce_checkpoints)
|
||||
if (is_hard_fork_at_least(nettype, cryptonote::network_version_13_enforce_checkpoints, height))
|
||||
{
|
||||
constexpr int64_t heights[] = {
|
||||
385824,
|
||||
|
@ -69,7 +70,7 @@ uint64_t get_staking_requirement(cryptonote::network_type m_nettype, uint64_t he
|
|||
uint64_t height_adjusted = height - hardfork_height;
|
||||
uint64_t base = 0, variable = 0;
|
||||
std::fesetround(FE_TONEAREST);
|
||||
if (hf_version >= cryptonote::network_version_11_infinite_staking)
|
||||
if (is_hard_fork_at_least(nettype, cryptonote::network_version_11_infinite_staking, height))
|
||||
{
|
||||
base = 15000 * COIN;
|
||||
variable = (25007.0 * COIN) / oxen::exp2(height_adjusted/129600.0);
|
||||
|
|
|
@ -211,23 +211,21 @@ namespace service_nodes {
|
|||
// blocks out of sync and sending something that it thinks is legit.
|
||||
constexpr uint64_t VOTE_OR_TX_VERIFY_HEIGHT_BUFFER = 5;
|
||||
|
||||
constexpr std::array<uint16_t, 3> MIN_STORAGE_SERVER_VERSION{{2, 1, 1}};
|
||||
constexpr std::array<uint16_t, 3> MIN_LOKINET_VERSION{{0, 9, 3}};
|
||||
constexpr std::array<uint16_t, 3> MIN_STORAGE_SERVER_VERSION{{2, 2, 0}};
|
||||
constexpr std::array<uint16_t, 3> MIN_LOKINET_VERSION{{0, 9, 5}};
|
||||
|
||||
// The minimum accepted version number, broadcasted by Service Nodes via uptime proofs for each hardfork
|
||||
struct proof_version
|
||||
{
|
||||
uint8_t hardfork;
|
||||
std::array<uint16_t, 3> version;
|
||||
std::pair<uint8_t, uint8_t> hardfork_revision;
|
||||
std::array<uint16_t, 3> oxend;
|
||||
std::array<uint16_t, 3> lokinet;
|
||||
std::array<uint16_t, 3> storage_server;
|
||||
};
|
||||
|
||||
constexpr proof_version MIN_UPTIME_PROOF_VERSIONS[] = {
|
||||
{cryptonote::network_version_18, {9,1,0}},
|
||||
{cryptonote::network_version_16_pulse, {8,1,0}},
|
||||
{cryptonote::network_version_15_ons, {7,1,2}},
|
||||
{cryptonote::network_version_14_blink, {6,1,0}},
|
||||
{cryptonote::network_version_13_enforce_checkpoints, {5,1,0}},
|
||||
{cryptonote::network_version_12_checkpointing, {4,0,3}},
|
||||
constexpr std::array MIN_UPTIME_PROOF_VERSIONS = {
|
||||
proof_version{{cryptonote::network_version_18, 1}, {9,2,0}, {0,9,5}, {2,2,0}},
|
||||
proof_version{{cryptonote::network_version_18, 0}, {9,1,0}, {0,9,0}, {2,1,0}},
|
||||
};
|
||||
|
||||
using swarm_id_t = uint64_t;
|
||||
|
@ -280,7 +278,7 @@ uint64_t get_min_node_contribution_in_portions(uint8_t version, uint64_t staking
|
|||
// available contribution room, which allows slight overstaking but disallows larger overstakes.
|
||||
uint64_t get_max_node_contribution(uint8_t version, uint64_t staking_requirement, uint64_t total_reserved);
|
||||
|
||||
uint64_t get_staking_requirement(cryptonote::network_type nettype, uint64_t height, uint8_t hf_version);
|
||||
uint64_t get_staking_requirement(cryptonote::network_type nettype, uint64_t height);
|
||||
|
||||
uint64_t portions_to_amount(uint64_t portions, uint64_t staking_requirement);
|
||||
|
||||
|
|
|
@ -497,7 +497,7 @@ namespace cryptonote
|
|||
}
|
||||
|
||||
bool approved = blink.approved();
|
||||
auto hf_version = m_blockchain.get_ideal_hard_fork_version(blink.height);
|
||||
auto hf_version = m_blockchain.get_network_version(blink.height);
|
||||
bool result = add_tx(tx, tvc, tx_pool_options::new_blink(approved, hf_version), hf_version);
|
||||
if (result && approved)
|
||||
{
|
||||
|
|
|
@ -30,10 +30,10 @@ Proof::Proof(
|
|||
qnet_port{quorumnet_port},
|
||||
storage_https_port{sn_storage_https_port},
|
||||
storage_omq_port{sn_storage_omq_port},
|
||||
storage_server_version{ss_version}
|
||||
storage_server_version{ss_version},
|
||||
lokinet_version{lokinet_version}
|
||||
{
|
||||
this->lokinet_version = lokinet_version;
|
||||
crypto::hash hash = this->hash_uptime_proof();
|
||||
crypto::hash hash = hash_uptime_proof();
|
||||
|
||||
crypto::generate_signature(hash, keys.pub, keys.key, sig);
|
||||
crypto_sign_detached(sig_ed25519.data, NULL, reinterpret_cast<unsigned char *>(hash.data), sizeof(hash.data), keys.key_ed25519.data);
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <chrono>
|
||||
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "cryptonote_basic/verification_context.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
|
@ -342,13 +343,14 @@ namespace cryptonote
|
|||
if(context.m_state == cryptonote_connection_context::state_synchronizing)
|
||||
return true;
|
||||
|
||||
// from v6, if the peer advertises a top block version, reject if it's not what it should be (will only work if no voting)
|
||||
// if the peer advertises a top block version, reject if it's not what it should be
|
||||
if (hshd.current_height > 0)
|
||||
{
|
||||
const uint8_t version = m_core.get_ideal_hard_fork_version(hshd.current_height - 1);
|
||||
if (version >= 6 && version != hshd.top_version)
|
||||
auto nettype = m_core.get_nettype();
|
||||
const uint8_t version = get_network_version(nettype, hshd.current_height - 1);
|
||||
if (version != hshd.top_version)
|
||||
{
|
||||
if (version < hshd.top_version && version == m_core.get_ideal_hard_fork_version())
|
||||
if (version < hshd.top_version && version == get_network_version(nettype, m_core.get_current_blockchain_height()))
|
||||
MCLOG_RED(el::Level::Warning, "global", context << " peer claims higher version than we think (" <<
|
||||
(unsigned)hshd.top_version << " for " << (hshd.current_height - 1) << " instead of " << (unsigned)version <<
|
||||
") - we may be forked from the network and a software upgrade may be needed");
|
||||
|
@ -385,7 +387,7 @@ namespace cryptonote
|
|||
|
||||
context.m_need_blink_sync = false;
|
||||
// Check for any blink txes being advertised that we don't know about
|
||||
if (m_core.get_blockchain_storage().get_current_hard_fork_version() >= HF_VERSION_BLINK)
|
||||
if (is_hard_fork_at_least(m_core.get_nettype(), HF_VERSION_BLINK, curr_height))
|
||||
{
|
||||
if (hshd.blink_blocks.size() != hshd.blink_hash.size())
|
||||
{
|
||||
|
@ -527,7 +529,7 @@ namespace cryptonote
|
|||
bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(CORE_SYNC_DATA& hshd)
|
||||
{
|
||||
m_core.get_blockchain_top(hshd.current_height, hshd.top_id);
|
||||
hshd.top_version = m_core.get_ideal_hard_fork_version(hshd.current_height);
|
||||
hshd.top_version = get_network_version(m_core.get_nettype(), hshd.current_height);
|
||||
hshd.cumulative_difficulty = m_core.get_block_cumulative_difficulty(hshd.current_height);
|
||||
hshd.current_height +=1;
|
||||
hshd.pruning_seed = m_core.get_blockchain_pruning_seed();
|
||||
|
@ -2593,7 +2595,7 @@ skip:
|
|||
// blink data that got sent to us (we may have additional blink info, or may have rejected some
|
||||
// of the incoming blink data).
|
||||
arg.blinks.clear();
|
||||
if (m_core.get_blockchain_storage().get_current_hard_fork_version() >= HF_VERSION_BLINK)
|
||||
if (is_hard_fork_at_least(m_core.get_nettype(), HF_VERSION_BLINK, m_core.get_current_blockchain_height()))
|
||||
{
|
||||
auto &pool = m_core.get_pool();
|
||||
auto lock = pool.blink_shared_lock();
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "quorumnet.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_core/service_node_voting.h"
|
||||
#include "cryptonote_core/service_node_rules.h"
|
||||
|
@ -853,7 +854,9 @@ void handle_blink(oxenmq::Message& m, QnetState& qnet) {
|
|||
|
||||
auto tag = get_or<uint64_t>(data, "!", 0);
|
||||
|
||||
auto hf_version = qnet.core.get_blockchain_storage().get_current_hard_fork_version();
|
||||
auto local_height = qnet.core.get_current_blockchain_height();
|
||||
|
||||
auto hf_version = get_network_version(qnet.core.get_nettype(), local_height);
|
||||
if (hf_version < HF_VERSION_BLINK) {
|
||||
MWARNING("Rejecting blink message: blink is not available for hardfork " << (int) hf_version);
|
||||
if (tag)
|
||||
|
@ -863,7 +866,6 @@ void handle_blink(oxenmq::Message& m, QnetState& qnet) {
|
|||
|
||||
// verify that height is within-2 of current height
|
||||
auto blink_height = get_int<uint64_t>(data.at("h"));
|
||||
auto local_height = qnet.core.get_current_blockchain_height();
|
||||
|
||||
if (blink_height < local_height - 2) {
|
||||
MINFO("Rejecting blink tx because blink auth height is too low (" << blink_height << " vs. " << local_height << ")");
|
||||
|
|
|
@ -686,28 +686,6 @@ bool command_parser_executor::in_peers(const std::vector<std::string>& args)
|
|||
return m_executor.in_peers(set, limit);
|
||||
}
|
||||
|
||||
bool command_parser_executor::hard_fork_info(const std::vector<std::string>& args)
|
||||
{
|
||||
int version;
|
||||
if (args.size() == 0) {
|
||||
version = 0;
|
||||
}
|
||||
else if (args.size() == 1) {
|
||||
try {
|
||||
version = std::stoi(args[0]);
|
||||
}
|
||||
catch(const std::exception& ex) {
|
||||
return false;
|
||||
}
|
||||
if (version <= 0 || version > 255)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return m_executor.hard_fork_info(version);
|
||||
}
|
||||
|
||||
bool command_parser_executor::show_bans(const std::vector<std::string>& args)
|
||||
{
|
||||
if (!args.empty()) return false;
|
||||
|
|
|
@ -118,8 +118,6 @@ public:
|
|||
|
||||
bool in_peers(const std::vector<std::string>& args);
|
||||
|
||||
bool hard_fork_info(const std::vector<std::string>& args);
|
||||
|
||||
bool show_bans(const std::vector<std::string>& args);
|
||||
|
||||
bool ban(const std::vector<std::string>& args);
|
||||
|
|
|
@ -262,11 +262,6 @@ void command_server::init_commands(cryptonote::rpc::core_rpc_server* rpc_server)
|
|||
, "in_peers <max_number>"
|
||||
, "Set the <max_number> of in peers."
|
||||
);
|
||||
m_command_lookup.set_handler(
|
||||
"hard_fork_info"
|
||||
, [this](const auto &x) { return m_parser.hard_fork_info(x); }
|
||||
, "Print the hard fork voting information."
|
||||
);
|
||||
m_command_lookup.set_handler(
|
||||
"bans"
|
||||
, [this](const auto &x) { return m_parser.show_bans(x); }
|
||||
|
|
|
@ -532,12 +532,8 @@ bool rpc_command_executor::show_status() {
|
|||
|
||||
str << ", v" << (ires.version.empty() ? "?.?.?" : ires.version);
|
||||
str << "(net v" << +hfres.version << ')';
|
||||
print_fork_extra_info(str, hfres.earliest_height, net_height, ires.target);
|
||||
|
||||
str << ", " << (
|
||||
hfres.state == cryptonote::HardFork::Ready ? "up to date" :
|
||||
hfres.state == cryptonote::HardFork::UpdateNeeded ? "update needed" :
|
||||
"out of date, likely forked");
|
||||
if (hfres.earliest_height)
|
||||
print_fork_extra_info(str, *hfres.earliest_height, net_height, ires.target);
|
||||
|
||||
std::time_t now = std::time(nullptr);
|
||||
|
||||
|
@ -1196,20 +1192,6 @@ bool rpc_command_executor::in_peers(bool set, uint32_t limit)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool rpc_command_executor::hard_fork_info(uint8_t version)
|
||||
{
|
||||
HARD_FORK_INFO::response res{};
|
||||
if (!invoke<HARD_FORK_INFO>({version}, res, "Failed to retrieve hard fork info"))
|
||||
return false;
|
||||
|
||||
version = version > 0 ? version : res.voting;
|
||||
tools::msg_writer() << "version " << (uint32_t)version << " " << (res.enabled ? "enabled" : "not enabled") <<
|
||||
", " << res.votes << "/" << res.window << " votes, threshold " << res.threshold;
|
||||
tools::msg_writer() << "current version " << (uint32_t)res.version << ", voting for version " << (uint32_t)res.voting;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rpc_command_executor::print_bans()
|
||||
{
|
||||
GETBANS::response res{};
|
||||
|
@ -2058,8 +2040,8 @@ bool rpc_command_executor::prepare_registration(bool force_registration)
|
|||
}
|
||||
|
||||
const uint64_t staking_requirement =
|
||||
std::max(service_nodes::get_staking_requirement(nettype, block_height, hf_version),
|
||||
service_nodes::get_staking_requirement(nettype, block_height + 30 * 24, hf_version)); // allow 1 day
|
||||
std::max(service_nodes::get_staking_requirement(nettype, block_height),
|
||||
service_nodes::get_staking_requirement(nettype, block_height + 30 * 24)); // allow 1 day
|
||||
|
||||
// anything less than DUST will be added to operator stake
|
||||
const uint64_t DUST = MAX_NUMBER_OF_CONTRIBUTORS;
|
||||
|
|
|
@ -155,8 +155,6 @@ public:
|
|||
|
||||
bool in_peers(bool set, uint32_t limit);
|
||||
|
||||
bool hard_fork_info(uint8_t version);
|
||||
|
||||
bool print_bans();
|
||||
|
||||
bool ban(const std::string &address, time_t seconds, bool clear_ban = false);
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <variant>
|
||||
#include <oxenmq/base64.h>
|
||||
#include "crypto/crypto.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "cryptonote_basic/tx_extra.h"
|
||||
#include "cryptonote_core/oxen_name_system.h"
|
||||
#include "cryptonote_core/pulse.h"
|
||||
|
@ -1024,7 +1025,7 @@ namespace cryptonote { namespace rpc {
|
|||
}
|
||||
|
||||
if (req.stake_info) {
|
||||
auto hf_version = m_core.get_hard_fork_version(e.in_pool ? m_core.get_current_blockchain_height() : e.block_height);
|
||||
auto hf_version = get_network_version(nettype(), e.in_pool ? m_core.get_current_blockchain_height() : e.block_height);
|
||||
service_nodes::staking_components sc;
|
||||
if (service_nodes::tx_get_staking_components_and_amounts(nettype(), hf_version, t, e.block_height, &sc)
|
||||
&& sc.transferred > 0)
|
||||
|
@ -1312,7 +1313,7 @@ namespace cryptonote { namespace rpc {
|
|||
const account_public_address& lMiningAdr = lMiner.get_mining_address();
|
||||
if (lMiner.is_mining())
|
||||
res.address = get_account_address_as_str(nettype(), false, lMiningAdr);
|
||||
const uint8_t major_version = m_core.get_blockchain_storage().get_current_hard_fork_version();
|
||||
const uint8_t major_version = m_core.get_blockchain_storage().get_network_version();
|
||||
|
||||
res.pow_algorithm =
|
||||
major_version >= network_version_12_checkpointing ? "RandomX (OXEN variant)" :
|
||||
|
@ -1466,14 +1467,14 @@ namespace cryptonote { namespace rpc {
|
|||
|
||||
std::function<void(const transaction& tx, tx_info& txi)> load_extra;
|
||||
if (req.tx_extra || req.stake_info)
|
||||
load_extra = [this, &req](const transaction& tx, tx_info& txi) {
|
||||
load_extra = [this, &req, net=nettype()](const transaction& tx, tx_info& txi) {
|
||||
if (req.tx_extra)
|
||||
load_tx_extra_data(txi.extra.emplace(), tx, nettype());
|
||||
load_tx_extra_data(txi.extra.emplace(), tx, net);
|
||||
if (req.stake_info) {
|
||||
auto height = m_core.get_current_blockchain_height();
|
||||
auto hf_version = m_core.get_hard_fork_version(height);
|
||||
auto hf_version = get_network_version(net, height);
|
||||
service_nodes::staking_components sc;
|
||||
if (service_nodes::tx_get_staking_components_and_amounts(nettype(), hf_version, tx, height, &sc)
|
||||
if (service_nodes::tx_get_staking_components_and_amounts(net, hf_version, tx, height, &sc)
|
||||
&& sc.transferred > 0)
|
||||
txi.stake_amount = sc.transferred;
|
||||
}
|
||||
|
@ -2104,10 +2105,15 @@ namespace cryptonote { namespace rpc {
|
|||
return res;
|
||||
|
||||
const Blockchain &blockchain = m_core.get_blockchain_storage();
|
||||
uint8_t version = req.version > 0 ? req.version : blockchain.get_next_hard_fork_version();
|
||||
res.version = blockchain.get_current_hard_fork_version();
|
||||
res.enabled = blockchain.get_hard_fork_voting_info(version, res.window, res.votes, res.threshold, res.earliest_height, res.voting);
|
||||
res.state = blockchain.get_hard_fork_state();
|
||||
uint8_t version =
|
||||
req.version > 0 ? req.version :
|
||||
req.height > 0 ? blockchain.get_network_version(req.height) :
|
||||
blockchain.get_network_version();
|
||||
res.version = version;
|
||||
res.enabled = blockchain.get_network_version() >= version;
|
||||
auto heights = get_hard_fork_heights(m_core.get_nettype(), version);
|
||||
res.earliest_height = heights.first;
|
||||
res.last_height = heights.second;
|
||||
res.status = STATUS_OK;
|
||||
return res;
|
||||
}
|
||||
|
@ -2844,10 +2850,10 @@ namespace cryptonote { namespace rpc {
|
|||
|
||||
bool at_least_one_succeeded = false;
|
||||
res.quorums.reserve(std::min((uint64_t)16, count));
|
||||
auto net = nettype();
|
||||
for (size_t height = start; height != end;)
|
||||
{
|
||||
uint8_t hf_version = m_core.get_hard_fork_version(height);
|
||||
if (hf_version != HardFork::INVALID_HF_VERSION)
|
||||
uint8_t hf_version = get_network_version(net, height);
|
||||
{
|
||||
auto start_quorum_iterator = static_cast<service_nodes::quorum_type>(0);
|
||||
auto end_quorum_iterator = service_nodes::max_quorum_type_for_hf(hf_version);
|
||||
|
@ -2886,7 +2892,7 @@ namespace cryptonote { namespace rpc {
|
|||
}
|
||||
|
||||
if (uint8_t hf_version; add_curr_pulse
|
||||
&& (hf_version = m_core.get_hard_fork_version(curr_height)) >= network_version_16_pulse)
|
||||
&& (hf_version = get_network_version(nettype(), curr_height)) >= network_version_16_pulse)
|
||||
{
|
||||
cryptonote::Blockchain const &blockchain = m_core.get_blockchain_storage();
|
||||
cryptonote::block_header const &top_header = blockchain.get_db().get_block_header_from_height(curr_height - 1);
|
||||
|
@ -2940,7 +2946,7 @@ namespace cryptonote { namespace rpc {
|
|||
if (!m_core.service_node())
|
||||
throw rpc_error{ERROR_WRONG_PARAM, "Daemon has not been started in service node mode, please relaunch with --service-node flag."};
|
||||
|
||||
uint8_t hf_version = m_core.get_hard_fork_version(m_core.get_current_blockchain_height());
|
||||
uint8_t hf_version = get_network_version(nettype(), m_core.get_current_blockchain_height());
|
||||
if (!service_nodes::make_registration_cmd(m_core.get_nettype(), hf_version, req.staking_requirement, req.args, m_core.get_service_keys(), res.registration_cmd, req.make_friendly))
|
||||
throw rpc_error{ERROR_INTERNAL, "Failed to make registration command"};
|
||||
|
||||
|
@ -2957,7 +2963,7 @@ namespace cryptonote { namespace rpc {
|
|||
std::vector<std::string> args;
|
||||
|
||||
uint64_t const curr_height = m_core.get_current_blockchain_height();
|
||||
uint64_t staking_requirement = service_nodes::get_staking_requirement(m_core.get_nettype(), curr_height, m_core.get_hard_fork_version(curr_height));
|
||||
uint64_t staking_requirement = service_nodes::get_staking_requirement(nettype(), curr_height);
|
||||
|
||||
{
|
||||
uint64_t portions_cut;
|
||||
|
@ -3142,7 +3148,9 @@ namespace cryptonote { namespace rpc {
|
|||
res.height = m_core.get_current_blockchain_height() - 1;
|
||||
res.target_height = m_core.get_target_blockchain_height();
|
||||
res.block_hash = tools::type_to_hex(m_core.get_block_id_by_height(res.height));
|
||||
res.hardfork = m_core.get_hard_fork_version(res.height);
|
||||
auto [hf, snode_rev] = get_network_version_revision(nettype(), res.height);
|
||||
res.hardfork = hf;
|
||||
res.snode_revision = snode_rev;
|
||||
|
||||
if (!req.poll_block_hash.empty()) {
|
||||
res.polling_mode = true;
|
||||
|
@ -3284,7 +3292,7 @@ namespace cryptonote { namespace rpc {
|
|||
PERF_TIMER(on_get_staking_requirement);
|
||||
res.height = req.height > 0 ? req.height : m_core.get_current_blockchain_height();
|
||||
|
||||
res.staking_requirement = service_nodes::get_staking_requirement(m_core.get_nettype(), res.height, m_core.get_hard_fork_version(res.height));
|
||||
res.staking_requirement = service_nodes::get_staking_requirement(nettype(), res.height);
|
||||
res.status = STATUS_OK;
|
||||
return res;
|
||||
}
|
||||
|
@ -3483,7 +3491,7 @@ namespace cryptonote { namespace rpc {
|
|||
check_quantity_limit(req.entries.size(), ONS_NAMES_TO_OWNERS::MAX_REQUEST_ENTRIES);
|
||||
|
||||
std::optional<uint64_t> height = m_core.get_current_blockchain_height();
|
||||
uint8_t hf_version = m_core.get_hard_fork_version(*height);
|
||||
uint8_t hf_version = get_network_version(nettype(), *height);
|
||||
if (req.include_expired) height = std::nullopt;
|
||||
|
||||
std::vector<ons::mapping_type> types;
|
||||
|
@ -3605,7 +3613,7 @@ namespace cryptonote { namespace rpc {
|
|||
throw rpc_error{ERROR_WRONG_PARAM, "Unable to resolve ONS address: invalid 'name_hash' value '" + req.name_hash + "'"};
|
||||
|
||||
|
||||
uint8_t hf_version = m_core.get_hard_fork_version(m_core.get_current_blockchain_height());
|
||||
uint8_t hf_version = m_core.get_blockchain_storage().get_network_version();
|
||||
auto type = static_cast<ons::mapping_type>(req.type);
|
||||
if (!ons::mapping_type_allowed(hf_version, type))
|
||||
throw rpc_error{ERROR_WRONG_PARAM, "Invalid lokinet type '" + std::to_string(req.type) + "'"};
|
||||
|
|
|
@ -727,18 +727,15 @@ KV_SERIALIZE_MAP_CODE_END()
|
|||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(HARD_FORK_INFO::request)
|
||||
KV_SERIALIZE(version)
|
||||
KV_SERIALIZE(height)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(HARD_FORK_INFO::response)
|
||||
KV_SERIALIZE(version)
|
||||
KV_SERIALIZE(enabled)
|
||||
KV_SERIALIZE(window)
|
||||
KV_SERIALIZE(votes)
|
||||
KV_SERIALIZE(threshold)
|
||||
KV_SERIALIZE(voting)
|
||||
KV_SERIALIZE(state)
|
||||
KV_SERIALIZE(earliest_height)
|
||||
KV_SERIALIZE(last_height)
|
||||
KV_SERIALIZE(status)
|
||||
KV_SERIALIZE(untrusted)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
@ -1116,6 +1113,7 @@ KV_SERIALIZE_MAP_CODE_BEGIN(GET_SERVICE_NODES::requested_fields_t)
|
|||
KV_SERIALIZE(height)
|
||||
KV_SERIALIZE(target_height)
|
||||
KV_SERIALIZE(hardfork)
|
||||
KV_SERIALIZE(snode_revision)
|
||||
|
||||
KV_SERIALIZE(last_uptime_proof)
|
||||
KV_SERIALIZE(storage_server_reachable)
|
||||
|
@ -1200,6 +1198,7 @@ KV_SERIALIZE_MAP_CODE_BEGIN(GET_SERVICE_NODES::response)
|
|||
if (fields.target_height || fields.all) KV_SERIALIZE(target_height)
|
||||
if (fields.block_hash || fields.all || (polling_mode && !unchanged)) KV_SERIALIZE(block_hash)
|
||||
if (fields.hardfork || fields.all) KV_SERIALIZE(hardfork)
|
||||
if (fields.snode_revision || fields.all) KV_SERIALIZE(snode_revision)
|
||||
if (!as_json.empty()) KV_SERIALIZE(as_json)
|
||||
if (polling_mode) KV_SERIALIZE(unchanged);
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
|
|
@ -1429,7 +1429,8 @@ namespace rpc {
|
|||
|
||||
struct request
|
||||
{
|
||||
uint8_t version; // The major block version for the fork.
|
||||
uint8_t version; // The major block version for the fork (only one of `version` and `height` may be given).
|
||||
uint64_t height; // Request hard fork info about this height (only one of `version` and `height` may be given).
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
|
@ -1437,13 +1438,9 @@ namespace rpc {
|
|||
struct response
|
||||
{
|
||||
uint8_t version; // The major block version for the fork.
|
||||
bool enabled; // Tells if hard fork is enforced.
|
||||
uint32_t window; // Number of blocks over which current votes are cast. Default is 10080 blocks.
|
||||
uint32_t votes; // Number of votes towards hard fork.
|
||||
uint32_t threshold; // Minimum percent of votes to trigger hard fork. Default is 80.
|
||||
uint8_t voting; // Hard fork voting status.
|
||||
uint32_t state; // Current hard fork state: 0 (There is likely a hard fork), 1 (An update is needed to fork properly), or 2 (Everything looks good).
|
||||
uint64_t earliest_height; // Block height at which hard fork would be enabled if voted in.
|
||||
bool enabled; // Indicates whether hard fork is enforced (that is, at or above the requested hardfork)
|
||||
std::optional<uint64_t> earliest_height; // Block height at which hard fork will be enabled.
|
||||
std::optional<uint64_t> last_height; // The last block height at which this hard fork will be active; will be omitted if this oxend is not aware of any future hard fork.
|
||||
std::string status; // General RPC error code. "OK" means everything looks good.
|
||||
bool untrusted; // States if the result is obtained using the bootstrap mode, and is therefore not trusted (`true`), or when the daemon is fully synced (`false`).
|
||||
|
||||
|
@ -2068,6 +2065,7 @@ namespace rpc {
|
|||
bool height;
|
||||
bool target_height;
|
||||
bool hardfork;
|
||||
bool snode_revision;
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
|
||||
|
@ -2146,6 +2144,7 @@ namespace rpc {
|
|||
std::string block_hash; // Current block's hash.
|
||||
bool unchanged; // Will be true (and `service_node_states` omitted) if you gave the current block hash to poll_block_hash
|
||||
uint8_t hardfork; // Current hardfork version.
|
||||
uint8_t snode_revision; // snode revision for non-hardfork but mandatory snode updates
|
||||
std::string status; // Generic RPC error code. "OK" is the success value.
|
||||
std::string as_json; // If `include_json` is set in the request, this contains the json representation of the `entry` data structure
|
||||
|
||||
|
|
|
@ -161,7 +161,9 @@ bool NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_heigh
|
|||
req_t.version = version;
|
||||
try {
|
||||
auto resp_t = invoke_json_rpc<rpc::HARD_FORK_INFO>(req_t);
|
||||
m_earliest_height[version] = resp_t.earliest_height;
|
||||
if (!resp_t.earliest_height)
|
||||
return false;
|
||||
m_earliest_height[version] = *resp_t.earliest_height;
|
||||
} catch (...) { return false; }
|
||||
}
|
||||
|
||||
|
|
|
@ -8389,7 +8389,7 @@ wallet2::register_service_node_result wallet2::create_register_service_node_tx(c
|
|||
}
|
||||
}
|
||||
|
||||
staking_requirement = service_nodes::get_staking_requirement(nettype(), bc_height, *hf_version);
|
||||
staking_requirement = service_nodes::get_staking_requirement(nettype(), bc_height);
|
||||
std::vector<std::string> const args(local_args.begin(), local_args.begin() + local_args.size() - 3);
|
||||
contributor_args = service_nodes::convert_registration_args(nettype(), args, staking_requirement, *hf_version);
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "cryptonote_config.h"
|
||||
#define IN_UNIT_TESTS
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -101,8 +102,6 @@ public:
|
|||
return top;
|
||||
}
|
||||
virtual void pop_block(cryptonote::block &blk, std::vector<cryptonote::transaction> &txs) override { blocks.pop_back(); }
|
||||
virtual void set_hard_fork_version(uint64_t height, uint8_t version) override { if (height >= hf.size()) hf.resize(height + 1); hf[height] = version; }
|
||||
virtual uint8_t get_hard_fork_version(uint64_t height) const override { if (height >= hf.size()) return 255; return hf[height]; }
|
||||
|
||||
private:
|
||||
std::vector<block_t> blocks;
|
||||
|
@ -111,26 +110,6 @@ private:
|
|||
|
||||
}
|
||||
|
||||
#define PREFIX_WINDOW(hf_version,window) \
|
||||
blockchain_objects_t bc_objects = {}; \
|
||||
struct get_test_options { \
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks; \
|
||||
const cryptonote::test_options test_options = { \
|
||||
hard_forks, \
|
||||
window, \
|
||||
}; \
|
||||
get_test_options(): hard_forks{{std::make_pair(cryptonote::network_version_7, (uint64_t)0), std::make_pair((uint8_t)hf_version, (uint64_t)LONG_TERM_BLOCK_WEIGHT_WINDOW)}} {} \
|
||||
} opts; \
|
||||
cryptonote::Blockchain *bc = &bc_objects.m_blockchain; \
|
||||
bool r = bc->init(new TestDB(), nullptr /*ons_db*/, cryptonote::FAKECHAIN, true, &opts.test_options, 0); \
|
||||
if (!r) \
|
||||
{ \
|
||||
fprintf(stderr, "Failed to init blockchain\n"); \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
#define PREFIX(hf_version) PREFIX_WINDOW(hf_version, LONG_TERM_BLOCK_WEIGHT_WINDOW)
|
||||
|
||||
static uint32_t lcg_seed = 0;
|
||||
|
||||
static uint32_t lcg()
|
||||
|
@ -141,15 +120,27 @@ static uint32_t lcg()
|
|||
|
||||
static void test(test_t t, uint64_t blocks)
|
||||
{
|
||||
PREFIX(HF_VERSION_LONG_TERM_BLOCK_WEIGHT);
|
||||
blockchain_objects_t bc_objects = {};
|
||||
|
||||
const std::vector<cryptonote::hard_fork> hard_forks{
|
||||
{cryptonote::network_version_7, 0, 0, 0},
|
||||
{cryptonote::network_version_11_infinite_staking, 0, 5000, 0}};
|
||||
|
||||
const cryptonote::test_options test_options{hard_forks, 5000};
|
||||
|
||||
auto& bc = bc_objects.m_blockchain;
|
||||
if (!bc.init(new TestDB(), nullptr, cryptonote ::FAKECHAIN, true, &test_options, 0)) {
|
||||
fprintf(stderr, "Failed to init blockchain\n");
|
||||
exit(1);
|
||||
};
|
||||
|
||||
for (uint64_t h = 0; h < LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
|
||||
{
|
||||
cryptonote::block b;
|
||||
b.major_version = cryptonote::network_version_7;
|
||||
b.minor_version = cryptonote::network_version_7;
|
||||
bc->get_db().add_block(std::make_pair(b, ""), 300000, 300000, bc->get_db().height(), bc->get_db().height(), {});
|
||||
if (!bc->update_next_cumulative_weight_limit())
|
||||
bc.get_db().add_block(std::make_pair(b, ""), 300000, 300000, bc.get_db().height(), bc.get_db().height(), {});
|
||||
if (!bc.update_next_cumulative_weight_limit())
|
||||
{
|
||||
fprintf(stderr, "Failed to update cumulative weight limit 1\n");
|
||||
exit(1);
|
||||
|
@ -159,7 +150,7 @@ static void test(test_t t, uint64_t blocks)
|
|||
for (uint64_t h = 0; h < blocks; ++h)
|
||||
{
|
||||
uint64_t w;
|
||||
uint64_t effective_block_weight_median = bc->get_current_cumulative_block_weight_median();
|
||||
uint64_t effective_block_weight_median = bc.get_current_cumulative_block_weight_median();
|
||||
switch (t)
|
||||
{
|
||||
case test_lcg:
|
||||
|
@ -170,7 +161,7 @@ static void test(test_t t, uint64_t blocks)
|
|||
break;
|
||||
}
|
||||
case test_max:
|
||||
w = bc->get_current_cumulative_block_weight_limit();
|
||||
w = bc.get_current_cumulative_block_weight_limit();
|
||||
break;
|
||||
case test_min:
|
||||
w = 90;
|
||||
|
@ -178,13 +169,13 @@ static void test(test_t t, uint64_t blocks)
|
|||
default:
|
||||
exit(1);
|
||||
}
|
||||
uint64_t ltw = bc->get_next_long_term_block_weight(w);
|
||||
uint64_t ltw = bc.get_next_long_term_block_weight(w);
|
||||
cryptonote::block b;
|
||||
b.major_version = HF_VERSION_LONG_TERM_BLOCK_WEIGHT;
|
||||
b.minor_version = HF_VERSION_LONG_TERM_BLOCK_WEIGHT;
|
||||
bc->get_db().add_block(std::make_pair(std::move(b), ""), w, ltw, bc->get_db().height(), bc->get_db().height(), {});
|
||||
bc.get_db().add_block(std::make_pair(std::move(b), ""), w, ltw, bc.get_db().height(), bc.get_db().height(), {});
|
||||
|
||||
if (!bc->update_next_cumulative_weight_limit())
|
||||
if (!bc.update_next_cumulative_weight_limit())
|
||||
{
|
||||
fprintf(stderr, "Failed to update cumulative weight limit\n");
|
||||
exit(1);
|
||||
|
|
|
@ -65,4 +65,4 @@ set_property(TARGET core_tests
|
|||
|
||||
add_test(
|
||||
NAME core_tests
|
||||
COMMAND core_tests --generate_and_play_test_data)
|
||||
COMMAND core_tests)
|
||||
|
|
|
@ -571,10 +571,10 @@ bool gen_block_is_too_big::generate(std::vector<test_event_entry>& events) const
|
|||
bool gen_block_invalid_binary_format::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
#if 1
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_n_blocks(10);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
|
|
|
@ -61,11 +61,11 @@ bool gen_bp_tx_validation_base::generate_with(std::vector<test_event_entry>& eve
|
|||
++amounts_paid_len;
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = {
|
||||
{7,0}, {8,1}, {target_hf, NUM_UNLOCKED_BLOCKS + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW + 1},
|
||||
std::vector<cryptonote::hard_fork> hard_forks = {
|
||||
{7,0,0}, {8,0,1}, {target_hf, 0, NUM_UNLOCKED_BLOCKS + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW + 1},
|
||||
};
|
||||
event_replay_settings settings = {};
|
||||
settings.hard_forks = hard_forks;
|
||||
settings.hard_forks = hard_forks;
|
||||
events.push_back(settings);
|
||||
|
||||
// create 12 miner accounts, and have them mine the next 48 blocks
|
||||
|
@ -78,8 +78,8 @@ bool gen_bp_tx_validation_base::generate_with(std::vector<test_event_entry>& eve
|
|||
for (size_t i = 0; i < NUM_MINERS; ++i)
|
||||
miner_accounts[i].generate();
|
||||
|
||||
uint8_t const first_hf = hard_forks[1].first;
|
||||
uint8_t const last_hf = hard_forks.back().first;
|
||||
uint8_t const first_hf = hard_forks[1].version;
|
||||
uint8_t const last_hf = hard_forks.back().version;
|
||||
generator.m_hf_version = first_hf;
|
||||
for (size_t n = 0; n < NUM_UNLOCKED_BLOCKS; ++n) {
|
||||
CHECK_AND_ASSERT_MES(
|
||||
|
|
|
@ -71,21 +71,21 @@ void oxen_register_callback(std::vector<test_event_entry> &events,
|
|||
events.push_back(oxen_callback_entry{callback_name, callback});
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint8_t, uint64_t>>
|
||||
std::vector<cryptonote::hard_fork>
|
||||
oxen_generate_hard_fork_table(uint8_t hf_version, uint64_t pos_delay)
|
||||
{
|
||||
assert(hf_version < cryptonote::network_version_count);
|
||||
// We always need block 0 == v7 for the genesis block:
|
||||
std::vector<std::pair<uint8_t, uint64_t>> result{{cryptonote::network_version_7, 0}};
|
||||
std::vector<cryptonote::hard_fork> result{{cryptonote::network_version_7, 0, 0}};
|
||||
uint64_t version_height = 1;
|
||||
// HF15 reduces and HF16+ eliminates miner block rewards, so we need to ensure we have enough
|
||||
// HF14 blocks to generate enough LOKI for tests:
|
||||
if (hf_version > cryptonote::network_version_14_blink) {
|
||||
result.emplace_back(cryptonote::network_version_14_blink, version_height);
|
||||
result.push_back({cryptonote::network_version_14_blink, 0, version_height});
|
||||
version_height += pos_delay;
|
||||
}
|
||||
|
||||
result.emplace_back(hf_version, version_height);
|
||||
result.push_back({hf_version, 0, version_height});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ std::vector<cryptonote::block> oxen_chain_generator_db::get_blocks_range(const u
|
|||
return result;
|
||||
}
|
||||
|
||||
oxen_chain_generator::oxen_chain_generator(std::vector<test_event_entry> &events, const std::vector<std::pair<uint8_t, uint64_t>> &hard_forks)
|
||||
oxen_chain_generator::oxen_chain_generator(std::vector<test_event_entry> &events, const std::vector<cryptonote::hard_fork>& hard_forks)
|
||||
: events_(events)
|
||||
, hard_forks_(hard_forks)
|
||||
{
|
||||
|
@ -270,7 +270,7 @@ cryptonote::account_base oxen_chain_generator::add_account()
|
|||
void oxen_chain_generator::add_blocks_until_version(uint8_t hf_version)
|
||||
{
|
||||
assert(hard_forks_.size());
|
||||
assert(hf_version_ <= hard_forks_.back().first);
|
||||
assert(hf_version_ <= hard_forks_.back().version);
|
||||
assert(db_.blocks.size() >= 1); // NOTE: We must have genesis block
|
||||
for (;;)
|
||||
{
|
||||
|
@ -462,7 +462,7 @@ oxen_chain_generator::create_registration_tx(const cryptonote::account_base &src
|
|||
|
||||
uint64_t new_height = get_block_height(top().block) + 1;
|
||||
uint8_t new_hf_version = get_hf_version_at(new_height);
|
||||
const auto staking_requirement = service_nodes::get_staking_requirement(cryptonote::FAKECHAIN, new_height, new_hf_version);
|
||||
const auto staking_requirement = service_nodes::get_staking_requirement(cryptonote::FAKECHAIN, new_height);
|
||||
uint64_t amount = service_nodes::portions_to_amount(portions[0], staking_requirement);
|
||||
|
||||
uint64_t unlock_time = 0;
|
||||
|
@ -1115,8 +1115,8 @@ uint8_t oxen_chain_generator::get_hf_version_at(uint64_t height) const {
|
|||
uint8_t cur_hf_ver = 0;
|
||||
for (auto i = 0u; i < hard_forks_.size(); ++i)
|
||||
{
|
||||
if (height < hard_forks_[i].second) break;
|
||||
cur_hf_ver = hard_forks_[i].first;
|
||||
if (height < hard_forks_[i].height) break;
|
||||
cur_hf_ver = hard_forks_[i].version;
|
||||
}
|
||||
|
||||
assert(cur_hf_ver != 0);
|
||||
|
@ -1447,7 +1447,7 @@ cryptonote::transaction make_registration_tx(std::vector<test_event_entry>& even
|
|||
uint8_t hf_version)
|
||||
{
|
||||
const auto new_height = cryptonote::get_block_height(head) + 1;
|
||||
const auto staking_requirement = service_nodes::get_staking_requirement(cryptonote::FAKECHAIN, new_height, hf_version);
|
||||
const auto staking_requirement = service_nodes::get_staking_requirement(cryptonote::FAKECHAIN, new_height);
|
||||
uint64_t amount = service_nodes::portions_to_amount(portions[0], staking_requirement);
|
||||
|
||||
cryptonote::transaction tx;
|
||||
|
@ -2269,7 +2269,7 @@ uint64_t get_unlocked_balance(const cryptonote::account_base& addr, const std::v
|
|||
return res;
|
||||
}
|
||||
|
||||
bool extract_hard_forks(const std::vector<test_event_entry>& events, v_hardforks_t& hard_forks)
|
||||
bool extract_hard_forks(const std::vector<test_event_entry>& events, std::vector<cryptonote::hard_fork>& hard_forks)
|
||||
{
|
||||
for(auto & ev : events)
|
||||
{
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_basic/cryptonote_boost_serialization.h"
|
||||
|
@ -203,11 +204,10 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
typedef std::vector<std::pair<uint8_t, uint64_t>> v_hardforks_t;
|
||||
struct event_replay_settings
|
||||
{
|
||||
event_replay_settings() = default;
|
||||
std::optional<v_hardforks_t> hard_forks;
|
||||
std::optional<std::vector<cryptonote::hard_fork>> hard_forks;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
|
@ -588,7 +588,7 @@ uint64_t get_amount(const cryptonote::account_base& account, const cryptonote::t
|
|||
uint64_t get_balance(const cryptonote::account_base& addr, const std::vector<cryptonote::block>& blockchain, const map_hash2tx_t& mtx);
|
||||
uint64_t get_unlocked_balance(const cryptonote::account_base& addr, const std::vector<cryptonote::block>& blockchain, const map_hash2tx_t& mtx);
|
||||
|
||||
bool extract_hard_forks(const std::vector<test_event_entry>& events, v_hardforks_t& hard_forks);
|
||||
bool extract_hard_forks(const std::vector<test_event_entry>& events, std::vector<cryptonote::hard_fork>& hard_forks);
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
@ -908,7 +908,7 @@ inline bool replay_events_through_core_plain(cryptonote::core& cr, const std::ve
|
|||
//--------------------------------------------------------------------------
|
||||
template<typename t_test_class>
|
||||
struct get_test_options {
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks = {{7, 0}};
|
||||
const std::vector<cryptonote::hard_fork> hard_forks = {{7, 0, 0, 0}};
|
||||
const cryptonote::test_options test_options = {
|
||||
hard_forks, 0
|
||||
};
|
||||
|
@ -947,7 +947,7 @@ inline bool do_replay_events_get_core(std::vector<test_event_entry>& events, cry
|
|||
// events should be passed a testing context which should have this specific
|
||||
// testing situation
|
||||
// Hardforks can be specified in events.
|
||||
v_hardforks_t derived_hardforks;
|
||||
std::vector<cryptonote::hard_fork> derived_hardforks;
|
||||
bool use_derived_hardforks = extract_hard_forks(events, derived_hardforks);
|
||||
const cryptonote::test_options derived_test_options =
|
||||
{
|
||||
|
@ -1152,18 +1152,6 @@ inline bool do_replay_file(const std::string& filename)
|
|||
|
||||
#define SET_EVENT_VISITOR_SETT(VEC_EVENTS, SETT, VAL) VEC_EVENTS.push_back(event_visitor_settings(SETT, VAL));
|
||||
|
||||
#define GENERATE(filename, generator_class) \
|
||||
{ \
|
||||
std::vector<test_event_entry> events; \
|
||||
generator_class g; \
|
||||
g.generate(events); \
|
||||
if (!tools::serialize_obj_to_file(events, filename)) \
|
||||
{ \
|
||||
MERROR("Failed to serialize data to file: " << filename); \
|
||||
throw std::runtime_error("Failed to serialize data to file"); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define PLAY(filename, generator_class) \
|
||||
if(!do_replay_file<generator_class>(filename)) \
|
||||
|
@ -1242,19 +1230,6 @@ inline bool do_replay_file(const std::string& filename)
|
|||
CATCH_GENERATE_REPLAY_CORE(generator_class, generator_class_instance, CORE); \
|
||||
}
|
||||
|
||||
#define CALL_TEST(test_name, function) \
|
||||
{ \
|
||||
if(!function()) \
|
||||
{ \
|
||||
MERROR("#TEST# Failed " << test_name); \
|
||||
return 1; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
MGINFO_GREEN("#TEST# Succeeded " << test_name); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define QUOTEME(x) #x
|
||||
#define DEFINE_TESTS_ERROR_CONTEXT(text) const char* perr_context = text;
|
||||
#define CHECK_TEST_CONDITION(cond) CHECK_AND_ASSERT_MES(cond, false, "[" << perr_context << "] failed: \"" << QUOTEME(cond) << "\"")
|
||||
|
@ -1263,7 +1238,7 @@ inline bool do_replay_file(const std::string& filename)
|
|||
#define CHECK_NOT_EQ(v1, v2) CHECK_AND_ASSERT_MES(!(v1 == v2), false, "[" << perr_context << "] failed: \"" << QUOTEME(v1) << " != " << QUOTEME(v2) << "\", " << v1 << " == " << v2)
|
||||
#define MK_COINS(amount) (UINT64_C(amount) * COIN)
|
||||
|
||||
static std::string make_junk() {
|
||||
inline std::string make_junk() {
|
||||
std::string junk;
|
||||
junk.reserve(1024);
|
||||
for (size_t i = 0; i < 256; i++)
|
||||
|
@ -1393,7 +1368,7 @@ public:
|
|||
|
||||
void fill_nonce_with_oxen_generator(struct oxen_chain_generator const *generator, cryptonote::block& blk, const cryptonote::difficulty_type& diffic, uint64_t height);
|
||||
void oxen_register_callback(std::vector<test_event_entry> &events, std::string const &callback_name, oxen_callback callback);
|
||||
std::vector<std::pair<uint8_t, uint64_t>> oxen_generate_hard_fork_table(uint8_t hf_version = cryptonote::network_version_count - 1, uint64_t pos_delay = 60);
|
||||
std::vector<cryptonote::hard_fork> oxen_generate_hard_fork_table(uint8_t hf_version = cryptonote::network_version_count - 1, uint64_t pos_delay = 60);
|
||||
|
||||
struct oxen_blockchain_entry
|
||||
{
|
||||
|
@ -1460,10 +1435,10 @@ struct oxen_chain_generator
|
|||
oxen_chain_generator_db db_;
|
||||
uint8_t hf_version_ = cryptonote::network_version_7;
|
||||
std::vector<test_event_entry>& events_;
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks_;
|
||||
const std::vector<cryptonote::hard_fork> hard_forks_;
|
||||
cryptonote::account_base first_miner_;
|
||||
|
||||
oxen_chain_generator(std::vector<test_event_entry> &events, const std::vector<std::pair<uint8_t, uint64_t>> &hard_forks);
|
||||
oxen_chain_generator(std::vector<test_event_entry> &events, const std::vector<cryptonote::hard_fork>& hard_forks);
|
||||
|
||||
uint64_t height() const { return cryptonote::get_block_height(db_.blocks.back().block); }
|
||||
uint64_t chain_height() const { return height() + 1; }
|
||||
|
|
|
@ -39,11 +39,6 @@ namespace po = boost::program_options;
|
|||
|
||||
namespace
|
||||
{
|
||||
const command_line::arg_descriptor<std::string> arg_test_data_path = {"test_data_path", "", ""};
|
||||
const command_line::arg_descriptor<bool> arg_generate_test_data = {"generate_test_data", ""};
|
||||
const command_line::arg_descriptor<bool> arg_play_test_data = {"play_test_data", ""};
|
||||
const command_line::arg_descriptor<bool> arg_generate_and_play_test_data = {"generate_and_play_test_data", ""};
|
||||
const command_line::arg_descriptor<bool> arg_test_transactions = {"test_transactions", ""};
|
||||
const command_line::arg_descriptor<std::string> arg_filter = { "filter", "Regular expression filter for which tests to run" };
|
||||
const command_line::arg_descriptor<bool> arg_list_tests = {"list_tests", ""};
|
||||
const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", ""};
|
||||
|
@ -63,11 +58,6 @@ int main(int argc, char* argv[])
|
|||
|
||||
po::options_description desc_options("Allowed options");
|
||||
command_line::add_arg(desc_options, command_line::arg_help);
|
||||
command_line::add_arg(desc_options, arg_test_data_path);
|
||||
command_line::add_arg(desc_options, arg_generate_test_data);
|
||||
command_line::add_arg(desc_options, arg_play_test_data);
|
||||
command_line::add_arg(desc_options, arg_generate_and_play_test_data);
|
||||
command_line::add_arg(desc_options, arg_test_transactions);
|
||||
command_line::add_arg(desc_options, arg_filter);
|
||||
command_line::add_arg(desc_options, arg_list_tests);
|
||||
command_line::add_arg(desc_options, arg_log_level);
|
||||
|
@ -97,21 +87,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
size_t tests_count = 0;
|
||||
std::vector<std::string> failed_tests;
|
||||
std::string tests_folder = command_line::get_arg(vm, arg_test_data_path);
|
||||
bool list_tests = false;
|
||||
if (command_line::get_arg(vm, arg_generate_test_data))
|
||||
{
|
||||
GENERATE("chain001.dat", gen_simple_chain_001);
|
||||
}
|
||||
else if (command_line::get_arg(vm, arg_play_test_data))
|
||||
{
|
||||
PLAY("chain001.dat", gen_simple_chain_001);
|
||||
}
|
||||
else if (command_line::get_arg(vm, arg_test_transactions))
|
||||
{
|
||||
CALL_TEST("TRANSACTIONS TESTS", test_transactions);
|
||||
}
|
||||
else
|
||||
{
|
||||
list_tests = command_line::get_arg(vm, arg_list_tests);
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ using namespace cryptonote;
|
|||
|
||||
bool gen_double_spend_in_tx::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_n_blocks(20);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
|
@ -114,9 +114,9 @@ bool gen_double_spend_in_tx::generate(std::vector<test_event_entry>& events) con
|
|||
|
||||
bool gen_double_spend_in_the_same_block::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_n_blocks(10);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
|
@ -157,9 +157,9 @@ bool gen_double_spend_in_the_same_block::generate(std::vector<test_event_entry>&
|
|||
|
||||
bool gen_double_spend_in_different_blocks::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_n_blocks(10);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
|
@ -200,9 +200,9 @@ bool gen_double_spend_in_different_blocks::generate(std::vector<test_event_entry
|
|||
|
||||
bool gen_double_spend_in_alt_chain_in_the_same_block::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_n_blocks(10);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
|
@ -244,9 +244,9 @@ bool gen_double_spend_in_alt_chain_in_the_same_block::generate(std::vector<test_
|
|||
|
||||
bool gen_double_spend_in_alt_chain_in_different_blocks::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_n_blocks(10);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
|
@ -285,9 +285,9 @@ bool gen_double_spend_in_alt_chain_in_different_blocks::generate(std::vector<tes
|
|||
|
||||
bool gen_double_spend_in_different_chains::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_n_blocks(10);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
|
|
|
@ -98,10 +98,10 @@ bool gen_uint_overflow_base::mark_last_valid_block(cryptonote::core& c, size_t e
|
|||
|
||||
bool gen_uint_overflow_1::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_n_blocks(40);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ private:
|
|||
|
||||
template<>
|
||||
struct get_test_options<gen_multisig_tx_validation_base> {
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks = {std::make_pair(7, 0)};
|
||||
const std::vector<cryptonote::hard_fork> hard_forks = {{7,0,0,0}};
|
||||
const cryptonote::test_options test_options = {
|
||||
hard_forks, 0
|
||||
};
|
||||
|
|
|
@ -69,10 +69,10 @@ static void add_service_nodes(oxen_chain_generator &gen, size_t count)
|
|||
// code path" again
|
||||
bool oxen_checkpointing_alt_chain_handle_alt_blocks_at_tip::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
add_service_nodes(gen, service_nodes::CHECKPOINT_QUORUM_SIZE);
|
||||
|
||||
|
@ -128,10 +128,10 @@ bool oxen_checkpointing_alt_chain_handle_alt_blocks_at_tip::generate(std::vector
|
|||
// NOTE: - Checks that a chain with a checkpoint but less PoW is preferred over a chain that is longer with more PoW but no checkpoints
|
||||
bool oxen_checkpointing_alt_chain_more_service_node_checkpoints_less_pow_overtakes::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
int constexpr NUM_SERVICE_NODES = service_nodes::CHECKPOINT_QUORUM_SIZE;
|
||||
|
@ -165,10 +165,10 @@ bool oxen_checkpointing_alt_chain_more_service_node_checkpoints_less_pow_overtak
|
|||
// NOTE: - A chain that receives checkpointing votes sufficient to form a checkpoint should reorg back accordingly
|
||||
bool oxen_checkpointing_alt_chain_receive_checkpoint_votes_should_reorg_back::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
int constexpr NUM_SERVICE_NODES = service_nodes::CHECKPOINT_QUORUM_SIZE;
|
||||
|
@ -232,9 +232,9 @@ bool oxen_checkpointing_alt_chain_receive_checkpoint_votes_should_reorg_back::ge
|
|||
|
||||
bool oxen_checkpointing_alt_chain_too_old_should_be_dropped::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
int constexpr NUM_SERVICE_NODES = service_nodes::CHECKPOINT_QUORUM_SIZE;
|
||||
|
@ -267,10 +267,10 @@ bool oxen_checkpointing_alt_chain_too_old_should_be_dropped::generate(std::vecto
|
|||
// available checkpoint heights whilst maintaining equal heights with the main chain
|
||||
bool oxen_checkpointing_alt_chain_with_increasing_service_node_checkpoints::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
add_service_nodes(gen, service_nodes::CHECKPOINT_QUORUM_SIZE);
|
||||
|
||||
|
@ -327,10 +327,10 @@ bool oxen_checkpointing_alt_chain_with_increasing_service_node_checkpoints::gene
|
|||
// - Checks invalid vote (signature or key) is not accepted due to not being part of the quorum
|
||||
bool oxen_checkpointing_service_node_checkpoint_from_votes::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
add_service_nodes(gen, service_nodes::CHECKPOINT_QUORUM_SIZE);
|
||||
|
||||
|
@ -391,10 +391,10 @@ bool oxen_checkpointing_service_node_checkpoint_from_votes::generate(std::vector
|
|||
// - Checks you can add a block after the 1st checkpoint out of 2 checkpoints.
|
||||
bool oxen_checkpointing_service_node_checkpoints_check_reorg_windows::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
add_service_nodes(gen, service_nodes::CHECKPOINT_QUORUM_SIZE);
|
||||
|
||||
|
@ -438,11 +438,11 @@ bool oxen_checkpointing_service_node_checkpoints_check_reorg_windows::generate(s
|
|||
|
||||
bool oxen_core_block_reward_unpenalized_pre_pulse::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table(cryptonote::network_version_16_pulse - 1);
|
||||
auto hard_forks = oxen_generate_hard_fork_table(cryptonote::network_version_16_pulse - 1);
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
|
||||
uint8_t newest_hf = hard_forks.back().first;
|
||||
uint8_t newest_hf = hard_forks.back().version;
|
||||
assert(newest_hf >= cryptonote::network_version_13_enforce_checkpoints);
|
||||
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
@ -478,13 +478,13 @@ bool oxen_core_block_reward_unpenalized_pre_pulse::generate(std::vector<test_eve
|
|||
|
||||
bool oxen_core_block_reward_unpenalized_post_pulse::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table(cryptonote::network_version_count -1, 150 /*Proof Of Stake Delay*/);
|
||||
auto hard_forks = oxen_generate_hard_fork_table(cryptonote::network_version_count -1, 150 /*Proof Of Stake Delay*/);
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
uint8_t const newest_hf = hard_forks.back().first;
|
||||
uint8_t const newest_hf = hard_forks.back().version;
|
||||
assert(newest_hf >= cryptonote::network_version_13_enforce_checkpoints);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
// Make big chunky TX's to trigger the block size penalty
|
||||
|
@ -527,11 +527,11 @@ bool oxen_core_block_reward_unpenalized_post_pulse::generate(std::vector<test_ev
|
|||
|
||||
bool oxen_core_fee_burning::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
|
||||
uint8_t newest_hf = hard_forks.back().first;
|
||||
uint8_t newest_hf = hard_forks.back().version;
|
||||
assert(newest_hf >= cryptonote::network_version_14_blink);
|
||||
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
@ -609,14 +609,14 @@ bool oxen_core_fee_burning::generate(std::vector<test_event_entry>& events)
|
|||
|
||||
bool oxen_core_governance_batched_reward::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table(cryptonote::network_version_10_bulletproofs);
|
||||
auto hard_forks = oxen_generate_hard_fork_table(cryptonote::network_version_10_bulletproofs);
|
||||
|
||||
uint64_t hf10_height = 0;
|
||||
for (std::pair<uint8_t, uint64_t> hf_pair : hard_forks)
|
||||
for (const auto& [maj, sn_rev, height, ts] : hard_forks)
|
||||
{
|
||||
if (hf_pair.first == cryptonote::network_version_10_bulletproofs)
|
||||
if (maj == cryptonote::network_version_10_bulletproofs)
|
||||
{
|
||||
hf10_height = hf_pair.second;
|
||||
hf10_height = height;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -635,14 +635,14 @@ bool oxen_core_governance_batched_reward::generate(std::vector<test_event_entry>
|
|||
// NOTE(oxen): Since hard fork 8 we have an emissions curve change, so if
|
||||
// you don't atleast progress and generate blocks from hf8 you will run into
|
||||
// problems
|
||||
std::vector<std::pair<uint8_t, uint64_t>> other_hard_forks = {
|
||||
std::make_pair(cryptonote::network_version_7, 0),
|
||||
std::make_pair(cryptonote::network_version_8, 1),
|
||||
std::make_pair(cryptonote::network_version_9_service_nodes, hf10_height)};
|
||||
std::vector<cryptonote::hard_fork> other_hard_forks = {
|
||||
{7,0,0,0},
|
||||
{8,0,1,0},
|
||||
{9,0,hf10_height,0}};
|
||||
|
||||
std::vector<test_event_entry> unused_events;
|
||||
oxen_chain_generator no_batched_governance_generator(unused_events, other_hard_forks);
|
||||
no_batched_governance_generator.add_blocks_until_version(other_hard_forks.back().first);
|
||||
no_batched_governance_generator.add_blocks_until_version(other_hard_forks.back().version);
|
||||
|
||||
while(no_batched_governance_generator.height() < batched_governance_generator.height())
|
||||
no_batched_governance_generator.create_and_add_next_block();
|
||||
|
@ -685,9 +685,9 @@ bool oxen_core_governance_batched_reward::generate(std::vector<test_event_entry>
|
|||
bool oxen_core_block_rewards_lrc6::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
constexpr auto& network = cryptonote::get_config(cryptonote::FAKECHAIN);
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table(cryptonote::network_version_15_ons);
|
||||
hard_forks.emplace_back(cryptonote::network_version_16_pulse, hard_forks.back().second + network.GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS + 10);
|
||||
hard_forks.emplace_back(cryptonote::network_version_17, hard_forks.back().second + network.GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS);
|
||||
auto hard_forks = oxen_generate_hard_fork_table(cryptonote::network_version_15_ons);
|
||||
hard_forks.push_back({cryptonote::network_version_16_pulse, 0, hard_forks.back().height + network.GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS + 10, 0});
|
||||
hard_forks.push_back({cryptonote::network_version_17, 0, hard_forks.back().height + network.GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS});
|
||||
oxen_chain_generator batched_governance_generator(events, hard_forks);
|
||||
batched_governance_generator.add_blocks_until_version(cryptonote::network_version_17);
|
||||
batched_governance_generator.add_n_blocks(network.GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS);
|
||||
|
@ -695,12 +695,12 @@ bool oxen_core_block_rewards_lrc6::generate(std::vector<test_event_entry>& event
|
|||
uint64_t hf15_height = 0, hf16_height = 0, hf17_height = 0;
|
||||
for (const auto &hf : hard_forks)
|
||||
{
|
||||
if (hf.first == cryptonote::network_version_15_ons)
|
||||
hf15_height = hf.second;
|
||||
else if (hf.first == cryptonote::network_version_16_pulse)
|
||||
hf16_height = hf.second;
|
||||
if (hf.version == cryptonote::network_version_15_ons)
|
||||
hf15_height = hf.height;
|
||||
else if (hf.version == cryptonote::network_version_16_pulse)
|
||||
hf16_height = hf.height;
|
||||
else
|
||||
hf17_height = hf.second;
|
||||
hf17_height = hf.height;
|
||||
}
|
||||
|
||||
oxen_register_callback(events, "check_lrc6_7_block_rewards", [hf15_height, hf16_height, hf17_height, interval=network.GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS](cryptonote::core &c, size_t ev_index)
|
||||
|
@ -768,12 +768,12 @@ bool oxen_core_block_rewards_lrc6::generate(std::vector<test_event_entry>& event
|
|||
|
||||
bool oxen_core_test_deregister_preferred::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
const auto miner = gen.first_miner();
|
||||
const auto alice = gen.add_account();
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_n_blocks(10); /// give miner some outputs to spend and unlock them
|
||||
add_service_nodes(gen, 12);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
@ -831,11 +831,11 @@ bool oxen_core_test_deregister_preferred::generate(std::vector<test_event_entry>
|
|||
// to test), they don't get deregistered.
|
||||
bool oxen_core_test_deregister_safety_buffer::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
const auto miner = gen.first_miner();
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
add_service_nodes(gen, service_nodes::STATE_CHANGE_QUORUM_SIZE * 2 + 1);
|
||||
gen.add_n_blocks(1);
|
||||
|
@ -880,9 +880,9 @@ bool oxen_core_test_deregister_safety_buffer::generate(std::vector<test_event_en
|
|||
// Daemon A accepts the block without X. Now X is too old and should not be added in future blocks.
|
||||
bool oxen_core_test_deregister_too_old::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
|
||||
/// generate some outputs and unlock them
|
||||
gen.add_n_blocks(20);
|
||||
|
@ -906,10 +906,10 @@ bool oxen_core_test_deregister_too_old::generate(std::vector<test_event_entry>&
|
|||
|
||||
bool oxen_core_test_deregister_zero_fee::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
size_t const NUM_SERVICE_NODES = 11;
|
||||
|
@ -931,10 +931,10 @@ bool oxen_core_test_deregister_zero_fee::generate(std::vector<test_event_entry>
|
|||
// those sitting on Chain 1 should not have problems switching over.
|
||||
bool oxen_core_test_deregister_on_split::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
add_service_nodes(gen, service_nodes::CHECKPOINT_QUORUM_SIZE + 1);
|
||||
|
@ -991,10 +991,10 @@ bool oxen_core_test_deregister_on_split::generate(std::vector<test_event_entry>
|
|||
|
||||
bool oxen_core_test_state_change_ip_penalty_disallow_dupes::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
add_service_nodes(gen, service_nodes::STATE_CHANGE_QUORUM_SIZE + 1);
|
||||
|
@ -1053,11 +1053,11 @@ static bool verify_ons_mapping_record(char const *perr_context,
|
|||
|
||||
bool oxen_name_system_disallow_reserved_type::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
ons::mapping_value mapping_value = {};
|
||||
|
@ -1091,8 +1091,8 @@ static ons_keys_t make_ons_keys(cryptonote::account_base const &src)
|
|||
auto iter = result.wallet_value.buffer.begin();
|
||||
uint8_t identifier = 0;
|
||||
iter = std::copy_n(&identifier, 1, iter);
|
||||
iter = std::copy_n(src.get_keys().m_account_address.m_spend_public_key.data, sizeof(&src.get_keys().m_account_address.m_spend_public_key.data), iter);
|
||||
iter = std::copy_n(src.get_keys().m_account_address.m_view_public_key.data, sizeof(&src.get_keys().m_account_address.m_view_public_key.data), iter);
|
||||
iter = std::copy_n(src.get_keys().m_account_address.m_spend_public_key.data, sizeof(src.get_keys().m_account_address.m_spend_public_key.data), iter);
|
||||
iter = std::copy_n(src.get_keys().m_account_address.m_view_public_key.data, sizeof(src.get_keys().m_account_address.m_view_public_key.data), iter);
|
||||
|
||||
// NOTE: Just needs a 32 byte key. Reuse spend key
|
||||
memcpy(&result.lokinet_value.buffer[0], (char *)&result.owner.wallet.address.m_spend_public_key, result.lokinet_value.len);
|
||||
|
@ -1110,11 +1110,11 @@ uint64_t lokinet_expiry(ons::mapping_type type) {
|
|||
|
||||
bool oxen_name_system_expiration::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
ons_keys_t miner_key = make_ons_keys(miner);
|
||||
|
@ -1182,12 +1182,12 @@ bool oxen_name_system_expiration::generate(std::vector<test_event_entry> &events
|
|||
|
||||
bool oxen_name_system_get_mappings_by_owner::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
cryptonote::account_base bob = gen.add_account();
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
|
||||
// NOTE: Fund Bob's wallet
|
||||
{
|
||||
|
@ -1258,9 +1258,10 @@ bool oxen_name_system_get_mappings_by_owner::generate(std::vector<test_event_ent
|
|||
std::vector<ons::mapping_record> records = ons_db.get_mappings_by_owner(bob_key.owner);
|
||||
|
||||
size_t expected_size = 0;
|
||||
if (ons::mapping_type_allowed(c.get_blockchain_storage().get_current_hard_fork_version(), ons::mapping_type::session)) expected_size += 2;
|
||||
if (ons::mapping_type_allowed(c.get_blockchain_storage().get_current_hard_fork_version(), ons::mapping_type::wallet)) expected_size += 2;
|
||||
if (ons::mapping_type_allowed(c.get_blockchain_storage().get_current_hard_fork_version(), ons::mapping_type::lokinet)) expected_size += 2;
|
||||
auto netv = get_network_version(c.get_nettype(), c.get_current_blockchain_height());
|
||||
if (ons::mapping_type_allowed(netv, ons::mapping_type::session)) expected_size += 2;
|
||||
if (ons::mapping_type_allowed(netv, ons::mapping_type::wallet)) expected_size += 2;
|
||||
if (ons::mapping_type_allowed(netv, ons::mapping_type::lokinet)) expected_size += 2;
|
||||
CHECK_EQ(records.size(), expected_size);
|
||||
|
||||
std::sort(records.begin(), records.end(), [](const auto& a, const auto& b) {
|
||||
|
@ -1268,7 +1269,7 @@ bool oxen_name_system_get_mappings_by_owner::generate(std::vector<test_event_ent
|
|||
< std::make_tuple(b.update_height, b.name_hash);
|
||||
});
|
||||
|
||||
if (ons::mapping_type_allowed(c.get_blockchain_storage().get_current_hard_fork_version(), ons::mapping_type::session))
|
||||
if (ons::mapping_type_allowed(netv, ons::mapping_type::session))
|
||||
{
|
||||
CHECK_EQ(records[0].name_hash, session_name_hash1);
|
||||
CHECK_TEST_CONDITION(verify_ons_mapping_record(perr_context, records[0], ons::mapping_type::session, session_name1, bob_key.session_value, session_height, std::nullopt, session_name1_txid, bob_key.owner, {} /*backup_owner*/));
|
||||
|
@ -1276,7 +1277,7 @@ bool oxen_name_system_get_mappings_by_owner::generate(std::vector<test_event_ent
|
|||
CHECK_TEST_CONDITION(verify_ons_mapping_record(perr_context, records[1], ons::mapping_type::session, session_name2, bob_key.session_value, session_height, std::nullopt, session_name2_txid, bob_key.owner, {} /*backup_owner*/));
|
||||
}
|
||||
|
||||
if (ons::mapping_type_allowed(c.get_blockchain_storage().get_current_hard_fork_version(), ons::mapping_type::lokinet))
|
||||
if (ons::mapping_type_allowed(netv, ons::mapping_type::lokinet))
|
||||
{
|
||||
CHECK_EQ(records[2].name_hash, lokinet_name_hash1);
|
||||
CHECK_TEST_CONDITION(verify_ons_mapping_record(perr_context, records[2], ons::mapping_type::lokinet, lokinet_name1, bob_key.lokinet_value, lokinet_height, lokinet_height + lokinet_expiry(ons::mapping_type::lokinet), lokinet_name1_txid, bob_key.owner, {} /*backup_owner*/));
|
||||
|
@ -1284,7 +1285,7 @@ bool oxen_name_system_get_mappings_by_owner::generate(std::vector<test_event_ent
|
|||
CHECK_TEST_CONDITION(verify_ons_mapping_record(perr_context, records[3], ons::mapping_type::lokinet, lokinet_name2, bob_key.lokinet_value, lokinet_height, lokinet_height + lokinet_expiry(ons::mapping_type::lokinet_5years), lokinet_name2_txid, bob_key.owner, {} /*backup_owner*/));
|
||||
}
|
||||
|
||||
if (ons::mapping_type_allowed(c.get_blockchain_storage().get_current_hard_fork_version(), ons::mapping_type::wallet))
|
||||
if (ons::mapping_type_allowed(netv, ons::mapping_type::wallet))
|
||||
{
|
||||
CHECK_EQ(records[4].name_hash, wallet_name_hash1);
|
||||
CHECK_TEST_CONDITION(verify_ons_mapping_record(perr_context, records[4], ons::mapping_type::wallet, wallet_name1, bob_key.wallet_value, wallet_height, std::nullopt, wallet_name1_txid, bob_key.owner, {} /*backup_owner*/));
|
||||
|
@ -1299,12 +1300,12 @@ bool oxen_name_system_get_mappings_by_owner::generate(std::vector<test_event_ent
|
|||
|
||||
bool oxen_name_system_get_mappings_by_owners::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
cryptonote::account_base bob = gen.add_account();
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
|
||||
// NOTE: Fund Bob's wallet
|
||||
{
|
||||
|
@ -1369,12 +1370,12 @@ bool oxen_name_system_get_mappings_by_owners::generate(std::vector<test_event_en
|
|||
|
||||
bool oxen_name_system_get_mappings::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
cryptonote::account_base bob = gen.add_account();
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
|
||||
// NOTE: Fund Bob's wallet
|
||||
{
|
||||
|
@ -1411,13 +1412,13 @@ bool oxen_name_system_get_mappings::generate(std::vector<test_event_entry> &even
|
|||
|
||||
bool oxen_name_system_handles_duplicate_in_ons_db::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
cryptonote::account_base bob = gen.add_account();
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
cryptonote::transaction transfer = gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(400));
|
||||
|
@ -1471,7 +1472,8 @@ bool oxen_name_system_handles_duplicate_in_ons_db::generate(std::vector<test_eve
|
|||
CHECK_TEST_CONDITION(verify_ons_mapping_record(perr_context, record1, ons::mapping_type::session, session_name, bob_key.session_value, height_of_ons_entry, std::nullopt, session_tx_hash, miner_key.owner, {} /*backup_owner*/));
|
||||
CHECK_EQ(record1.owner_id, owner.id);
|
||||
|
||||
if (ons::mapping_type_allowed(c.get_blockchain_storage().get_current_hard_fork_version(), ons::mapping_type::lokinet))
|
||||
auto netv = get_network_version(c.get_nettype(), c.get_current_blockchain_height());
|
||||
if (ons::mapping_type_allowed(netv, ons::mapping_type::lokinet))
|
||||
{
|
||||
ons::mapping_record record2 = ons_db.get_mapping(ons::mapping_type::lokinet, session_name_hash);
|
||||
CHECK_TEST_CONDITION(verify_ons_mapping_record(perr_context, record2, ons::mapping_type::lokinet, lokinet_name, miner_key.lokinet_value, height_of_ons_entry, height_of_ons_entry + lokinet_expiry(ons::mapping_type::lokinet_2years), lokinet_tx_hash, miner_key.owner, {} /*backup_owner*/));
|
||||
|
@ -1488,13 +1490,13 @@ bool oxen_name_system_handles_duplicate_in_ons_db::generate(std::vector<test_eve
|
|||
|
||||
bool oxen_name_system_handles_duplicate_in_tx_pool::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
cryptonote::account_base bob = gen.add_account();
|
||||
{
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
cryptonote::transaction transfer = gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(400));
|
||||
|
@ -1522,11 +1524,11 @@ bool oxen_name_system_handles_duplicate_in_tx_pool::generate(std::vector<test_ev
|
|||
|
||||
bool oxen_name_system_invalid_tx_extra_params::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
ons_keys_t miner_key = make_ons_keys(miner);
|
||||
|
@ -1653,7 +1655,7 @@ bool oxen_name_system_invalid_tx_extra_params::generate(std::vector<test_event_e
|
|||
|
||||
bool oxen_name_system_large_reorg::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
cryptonote::account_base const miner = gen.first_miner_;
|
||||
|
@ -1661,7 +1663,7 @@ bool oxen_name_system_large_reorg::generate(std::vector<test_event_entry> &event
|
|||
ons_keys_t const miner_key = make_ons_keys(miner);
|
||||
ons_keys_t const bob_key = make_ons_keys(bob);
|
||||
{
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
cryptonote::transaction transfer = gen.create_and_add_tx(miner, bob.get_keys().m_account_address, MK_COINS(400));
|
||||
|
@ -1708,8 +1710,9 @@ bool oxen_name_system_large_reorg::generate(std::vector<test_event_entry> &event
|
|||
CHECK_EQ(ons_db.height(), first_ons_height);
|
||||
|
||||
size_t expected_size = 1;
|
||||
if (ons::mapping_type_allowed(c.get_blockchain_storage().get_current_hard_fork_version(), ons::mapping_type::wallet)) expected_size += 1;
|
||||
if (ons::mapping_type_allowed(c.get_blockchain_storage().get_current_hard_fork_version(), ons::mapping_type::lokinet)) expected_size += 1;
|
||||
auto netv = get_network_version(c.get_nettype(), c.get_current_blockchain_height());
|
||||
if (ons::mapping_type_allowed(netv, ons::mapping_type::wallet)) expected_size += 1;
|
||||
if (ons::mapping_type_allowed(netv, ons::mapping_type::lokinet)) expected_size += 1;
|
||||
CHECK_EQ(records.size(), expected_size);
|
||||
|
||||
for (ons::mapping_record const &record : records)
|
||||
|
@ -1814,8 +1817,9 @@ bool oxen_name_system_large_reorg::generate(std::vector<test_event_entry> &event
|
|||
{
|
||||
std::vector<ons::mapping_record> records = ons_db.get_mappings_by_owner(miner_key.owner);
|
||||
size_t expected_size = 1;
|
||||
if (ons::mapping_type_allowed(c.get_blockchain_storage().get_current_hard_fork_version(), ons::mapping_type::wallet)) expected_size += 1;
|
||||
if (ons::mapping_type_allowed(c.get_blockchain_storage().get_current_hard_fork_version(), ons::mapping_type::lokinet)) expected_size += 1;
|
||||
auto netv = get_network_version(c.get_nettype(), c.get_current_blockchain_height());
|
||||
if (ons::mapping_type_allowed(netv, ons::mapping_type::wallet)) expected_size += 1;
|
||||
if (ons::mapping_type_allowed(netv, ons::mapping_type::lokinet)) expected_size += 1;
|
||||
CHECK_EQ(records.size(), expected_size);
|
||||
|
||||
for (ons::mapping_record const &record : records)
|
||||
|
@ -1863,15 +1867,15 @@ bool oxen_name_system_large_reorg::generate(std::vector<test_event_entry> &event
|
|||
|
||||
bool oxen_name_system_name_renewal::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
|
||||
if (!ons::mapping_type_allowed(hard_forks.back().first, ons::mapping_type::lokinet))
|
||||
if (!ons::mapping_type_allowed(hard_forks.back().version, ons::mapping_type::lokinet))
|
||||
return true;
|
||||
|
||||
{
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
}
|
||||
|
||||
|
@ -1946,11 +1950,11 @@ bool oxen_name_system_name_renewal::generate(std::vector<test_event_entry> &even
|
|||
|
||||
bool oxen_name_system_name_value_max_lengths::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
auto make_ons_tx_with_custom_extra = [&](oxen_chain_generator &gen,
|
||||
|
@ -2016,11 +2020,11 @@ bool oxen_name_system_name_value_max_lengths::generate(std::vector<test_event_en
|
|||
|
||||
bool oxen_name_system_update_mapping_after_expiry_fails::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
ons_keys_t miner_key = make_ons_keys(miner);
|
||||
|
@ -2070,9 +2074,9 @@ uint8_t oxen_name_system_update_mapping::hf() { return cryptonote::network_versi
|
|||
uint8_t oxen_name_system_update_mapping_argon2::hf() { return cryptonote::network_version_15_ons; }
|
||||
bool oxen_name_system_update_mapping::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table(hf());
|
||||
auto hard_forks = oxen_generate_hard_fork_table(hf());
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
|
@ -2149,9 +2153,9 @@ ons::generic_signature ons_monero_signature(const crypto::hash& h, const crypto:
|
|||
|
||||
bool oxen_name_system_update_mapping_multiple_owners::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_n_blocks(10); /// generate some outputs and unlock them
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
|
@ -2413,9 +2417,9 @@ bool oxen_name_system_update_mapping_multiple_owners::generate(std::vector<test_
|
|||
|
||||
bool oxen_name_system_update_mapping_non_existent_name_fails::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
|
@ -2428,9 +2432,9 @@ bool oxen_name_system_update_mapping_non_existent_name_fails::generate(std::vect
|
|||
|
||||
bool oxen_name_system_update_mapping_invalid_signature::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
|
@ -2450,9 +2454,9 @@ bool oxen_name_system_update_mapping_invalid_signature::generate(std::vector<tes
|
|||
|
||||
bool oxen_name_system_update_mapping_replay::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
|
@ -2502,10 +2506,10 @@ bool oxen_name_system_update_mapping_replay::generate(std::vector<test_event_ent
|
|||
|
||||
bool oxen_name_system_wrong_burn::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
|
||||
// NOTE: Fund Miner's wallet
|
||||
{
|
||||
|
@ -2563,11 +2567,11 @@ bool oxen_name_system_wrong_burn::generate(std::vector<test_event_entry> &events
|
|||
|
||||
bool oxen_name_system_wrong_version::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
cryptonote::account_base miner = gen.first_miner_;
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
std::string name = "ons_name";
|
||||
|
@ -2601,10 +2605,10 @@ bool oxen_name_system_wrong_version::generate(std::vector<test_event_entry> &eve
|
|||
// NOTE: Generate forked block, check that alternative quorums are generated and accessible
|
||||
bool oxen_service_nodes_alt_quorums::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
add_service_nodes(gen, service_nodes::STATE_CHANGE_QUORUM_SIZE + 3);
|
||||
|
||||
|
@ -2649,10 +2653,10 @@ bool oxen_service_nodes_alt_quorums::generate(std::vector<test_event_entry>& eve
|
|||
|
||||
bool oxen_service_nodes_checkpoint_quorum_size::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
add_service_nodes(gen, service_nodes::CHECKPOINT_QUORUM_SIZE - 1);
|
||||
|
||||
|
@ -2689,13 +2693,13 @@ bool oxen_service_nodes_checkpoint_quorum_size::generate(std::vector<test_event_
|
|||
|
||||
bool oxen_service_nodes_gen_nodes::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table(cryptonote::network_version_9_service_nodes);
|
||||
const auto hard_forks = oxen_generate_hard_fork_table(cryptonote::network_version_9_service_nodes);
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
const auto miner = gen.first_miner();
|
||||
const auto alice = gen.add_account();
|
||||
size_t alice_account_base_event_index = gen.event_index();
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_n_blocks(10);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
|
@ -2768,9 +2772,9 @@ static bool contains(const std::vector<sn_info_t>& infos, const crypto::public_k
|
|||
|
||||
bool oxen_service_nodes_test_rollback::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
add_service_nodes(gen, 11);
|
||||
|
||||
gen.add_n_blocks(5); /// create a few blocks with active service nodes
|
||||
|
@ -2805,8 +2809,8 @@ bool oxen_service_nodes_test_rollback::generate(std::vector<test_event_entry>& e
|
|||
CHECK_TEST_CONDITION(dereg_tx.data.tx.type == cryptonote::txtype::state_change);
|
||||
|
||||
cryptonote::tx_extra_service_node_state_change deregistration;
|
||||
cryptonote::get_service_node_state_change_from_tx_extra(
|
||||
dereg_tx.data.tx.extra, deregistration, c.get_blockchain_storage().get_current_hard_fork_version());
|
||||
auto netv = get_network_version(c.get_nettype(), c.get_current_blockchain_height());
|
||||
cryptonote::get_service_node_state_change_from_tx_extra(dereg_tx.data.tx.extra, deregistration, netv);
|
||||
|
||||
const auto uptime_quorum = c.get_quorum(service_nodes::quorum_type::obligations, deregistration.block_height);
|
||||
CHECK_TEST_CONDITION(uptime_quorum);
|
||||
|
@ -2842,11 +2846,11 @@ bool oxen_service_nodes_test_rollback::generate(std::vector<test_event_entry>& e
|
|||
|
||||
bool oxen_service_nodes_test_swarms_basic::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks = {
|
||||
std::make_pair(7, 0), std::make_pair(8, 1), std::make_pair(9, 2), std::make_pair(10, 150)};
|
||||
const std::vector<cryptonote::hard_fork> hard_forks = {
|
||||
{7,0,0,0}, {8,0,1,0}, {9,0,2,0}, {10,0,150,0}};
|
||||
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
gen.add_blocks_until_version(hard_forks.rbegin()[1].first);
|
||||
gen.add_blocks_until_version(hard_forks.rbegin()[1].version);
|
||||
|
||||
/// Create some service nodes before hf version 10
|
||||
constexpr size_t INIT_SN_COUNT = 13;
|
||||
|
@ -2973,10 +2977,10 @@ bool oxen_service_nodes_test_swarms_basic::generate(std::vector<test_event_entry
|
|||
|
||||
bool oxen_service_nodes_insufficient_contribution::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
uint64_t operator_portions = STAKING_PORTIONS / 2;
|
||||
|
@ -3005,10 +3009,10 @@ bool oxen_service_nodes_insufficient_contribution::generate(std::vector<test_eve
|
|||
|
||||
static oxen_chain_generator setup_pulse_tests(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator result(events, hard_forks);
|
||||
|
||||
result.add_blocks_until_version(hard_forks.back().first);
|
||||
result.add_blocks_until_version(hard_forks.back().version);
|
||||
result.add_mined_money_unlock_blocks();
|
||||
|
||||
std::vector<cryptonote::transaction> registration_txs(service_nodes::pulse_min_service_nodes(cryptonote::FAKECHAIN));
|
||||
|
@ -3177,10 +3181,10 @@ bool oxen_pulse_reject_miner_block::generate(std::vector<test_event_entry> &even
|
|||
|
||||
bool oxen_pulse_generate_blocks::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
add_service_nodes(gen, service_nodes::pulse_min_service_nodes(cryptonote::FAKECHAIN));
|
||||
|
@ -3201,10 +3205,10 @@ bool oxen_pulse_generate_blocks::generate(std::vector<test_event_entry> &events)
|
|||
|
||||
bool oxen_pulse_fallback_to_pow_and_back::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
|
||||
add_service_nodes(gen, service_nodes::pulse_min_service_nodes(cryptonote::FAKECHAIN));
|
||||
|
@ -3249,10 +3253,10 @@ bool oxen_pulse_fallback_to_pow_and_back::generate(std::vector<test_event_entry>
|
|||
|
||||
bool oxen_pulse_chain_split::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
add_service_nodes(gen, std::max(service_nodes::pulse_min_service_nodes(cryptonote::FAKECHAIN), service_nodes::CHECKPOINT_QUORUM_SIZE));
|
||||
|
||||
|
@ -3294,10 +3298,10 @@ bool oxen_pulse_chain_split::generate(std::vector<test_event_entry> &events)
|
|||
// Pulse chain weight to switch over.
|
||||
bool oxen_pulse_chain_split_with_no_checkpoints::generate(std::vector<test_event_entry> &events)
|
||||
{
|
||||
std::vector<std::pair<uint8_t, uint64_t>> hard_forks = oxen_generate_hard_fork_table();
|
||||
auto hard_forks = oxen_generate_hard_fork_table();
|
||||
oxen_chain_generator gen(events, hard_forks);
|
||||
|
||||
gen.add_blocks_until_version(hard_forks.back().first);
|
||||
gen.add_blocks_until_version(hard_forks.back().version);
|
||||
gen.add_mined_money_unlock_blocks();
|
||||
add_service_nodes(gen, std::max(service_nodes::pulse_min_service_nodes(cryptonote::FAKECHAIN), service_nodes::CHECKPOINT_QUORUM_SIZE));
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ private:
|
|||
|
||||
template<>
|
||||
struct get_test_options<gen_rct_tx_validation_base> {
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks = {std::make_pair(1, 0), std::make_pair(2, 1), std::make_pair(4, 65)};
|
||||
const std::vector<cryptonote::hard_fork> hard_forks = {{1,0,0,0}, {2,0,1,0}, {4,0,65,0}};
|
||||
const cryptonote::test_options test_options = {
|
||||
hard_forks, 0
|
||||
};
|
||||
|
@ -271,7 +271,7 @@ struct gen_rct_tx_uses_output_too_early : public gen_rct_tx_validation_base
|
|||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
template<> struct get_test_options<gen_rct_tx_uses_output_too_early> {
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks = {std::make_pair(1, 0), std::make_pair(2, 1), std::make_pair(4, 65), std::make_pair(12, 69), std::make_pair(0, 0)};
|
||||
const std::vector<cryptonote::hard_fork> hard_forks = {{1,0,0,0}, {2,0,1,0}, {4,0,65,0}, {12,0,69,0}, {0,0,0,0}};
|
||||
const cryptonote::test_options test_options = {
|
||||
hard_forks, 0
|
||||
};
|
||||
|
|
|
@ -79,7 +79,7 @@ private:
|
|||
|
||||
template<>
|
||||
struct get_test_options<gen_v2_tx_validation_base> {
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks = {std::make_pair(1, 0), std::make_pair(2, 1)};
|
||||
const std::vector<cryptonote::hard_fork> hard_forks = {{1,0,0,0}, {2,0,0,0}};
|
||||
const cryptonote::test_options test_options = {
|
||||
hard_forks, 0
|
||||
};
|
||||
|
|
|
@ -1,157 +0,0 @@
|
|||
Changes for 1.7.0:
|
||||
|
||||
* New feature: death tests are supported on OpenBSD and in iOS
|
||||
simulator now.
|
||||
* New feature: Google Test now implements a protocol to allow
|
||||
a test runner to detect that a test program has exited
|
||||
prematurely and report it as a failure (before it would be
|
||||
falsely reported as a success if the exit code is 0).
|
||||
* New feature: Test::RecordProperty() can now be used outside of the
|
||||
lifespan of a test method, in which case it will be attributed to
|
||||
the current test case or the test program in the XML report.
|
||||
* New feature (potentially breaking): --gtest_list_tests now prints
|
||||
the type parameters and value parameters for each test.
|
||||
* Improvement: char pointers and char arrays are now escaped properly
|
||||
in failure messages.
|
||||
* Improvement: failure summary in XML reports now includes file and
|
||||
line information.
|
||||
* Improvement: the <testsuites> XML element now has a timestamp attribute.
|
||||
* Improvement: When --gtest_filter is specified, XML report now doesn't
|
||||
contain information about tests that are filtered out.
|
||||
* Fixed the bug where long --gtest_filter flag values are truncated in
|
||||
death tests.
|
||||
* Potentially breaking change: RUN_ALL_TESTS() is now implemented as a
|
||||
function instead of a macro in order to work better with Clang.
|
||||
* Compatibility fixes with C++ 11 and various platforms.
|
||||
* Bug/warning fixes.
|
||||
|
||||
Changes for 1.6.0:
|
||||
|
||||
* New feature: ADD_FAILURE_AT() for reporting a test failure at the
|
||||
given source location -- useful for writing testing utilities.
|
||||
* New feature: the universal value printer is moved from Google Mock
|
||||
to Google Test.
|
||||
* New feature: type parameters and value parameters are reported in
|
||||
the XML report now.
|
||||
* A gtest_disable_pthreads CMake option.
|
||||
* Colored output works in GNU Screen sessions now.
|
||||
* Parameters of value-parameterized tests are now printed in the
|
||||
textual output.
|
||||
* Failures from ad hoc test assertions run before RUN_ALL_TESTS() are
|
||||
now correctly reported.
|
||||
* Arguments of ASSERT_XY and EXPECT_XY no longer need to support << to
|
||||
ostream.
|
||||
* More complete handling of exceptions.
|
||||
* GTEST_ASSERT_XY can be used instead of ASSERT_XY in case the latter
|
||||
name is already used by another library.
|
||||
* --gtest_catch_exceptions is now true by default, allowing a test
|
||||
program to continue after an exception is thrown.
|
||||
* Value-parameterized test fixtures can now derive from Test and
|
||||
WithParamInterface<T> separately, easing conversion of legacy tests.
|
||||
* Death test messages are clearly marked to make them more
|
||||
distinguishable from other messages.
|
||||
* Compatibility fixes for Android, Google Native Client, MinGW, HP UX,
|
||||
PowerPC, Lucid autotools, libCStd, Sun C++, Borland C++ Builder (Code Gear),
|
||||
IBM XL C++ (Visual Age C++), and C++0x.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
* Potentially incompatible changes: disables the harmful 'make install'
|
||||
command in autotools.
|
||||
|
||||
Changes for 1.5.0:
|
||||
|
||||
* New feature: assertions can be safely called in multiple threads
|
||||
where the pthreads library is available.
|
||||
* New feature: predicates used inside EXPECT_TRUE() and friends
|
||||
can now generate custom failure messages.
|
||||
* New feature: Google Test can now be compiled as a DLL.
|
||||
* New feature: fused source files are included.
|
||||
* New feature: prints help when encountering unrecognized Google Test flags.
|
||||
* Experimental feature: CMake build script (requires CMake 2.6.4+).
|
||||
* Experimental feature: the Pump script for meta programming.
|
||||
* double values streamed to an assertion are printed with enough precision
|
||||
to differentiate any two different values.
|
||||
* Google Test now works on Solaris and AIX.
|
||||
* Build and test script improvements.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
|
||||
Potentially breaking changes:
|
||||
|
||||
* Stopped supporting VC++ 7.1 with exceptions disabled.
|
||||
* Dropped support for 'make install'.
|
||||
|
||||
Changes for 1.4.0:
|
||||
|
||||
* New feature: the event listener API
|
||||
* New feature: test shuffling
|
||||
* New feature: the XML report format is closer to junitreport and can
|
||||
be parsed by Hudson now.
|
||||
* New feature: when a test runs under Visual Studio, its failures are
|
||||
integrated in the IDE.
|
||||
* New feature: /MD(d) versions of VC++ projects.
|
||||
* New feature: elapsed time for the tests is printed by default.
|
||||
* New feature: comes with a TR1 tuple implementation such that Boost
|
||||
is no longer needed for Combine().
|
||||
* New feature: EXPECT_DEATH_IF_SUPPORTED macro and friends.
|
||||
* New feature: the Xcode project can now produce static gtest
|
||||
libraries in addition to a framework.
|
||||
* Compatibility fixes for Solaris, Cygwin, minGW, Windows Mobile,
|
||||
Symbian, gcc, and C++Builder.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
|
||||
Changes for 1.3.0:
|
||||
|
||||
* New feature: death tests on Windows, Cygwin, and Mac.
|
||||
* New feature: ability to use Google Test assertions in other testing
|
||||
frameworks.
|
||||
* New feature: ability to run disabled test via
|
||||
--gtest_also_run_disabled_tests.
|
||||
* New feature: the --help flag for printing the usage.
|
||||
* New feature: access to Google Test flag values in user code.
|
||||
* New feature: a script that packs Google Test into one .h and one
|
||||
.cc file for easy deployment.
|
||||
* New feature: support for distributing test functions to multiple
|
||||
machines (requires support from the test runner).
|
||||
* Bug fixes and implementation clean-ups.
|
||||
|
||||
Changes for 1.2.1:
|
||||
|
||||
* Compatibility fixes for Linux IA-64 and IBM z/OS.
|
||||
* Added support for using Boost and other TR1 implementations.
|
||||
* Changes to the build scripts to support upcoming release of Google C++
|
||||
Mocking Framework.
|
||||
* Added Makefile to the distribution package.
|
||||
* Improved build instructions in README.
|
||||
|
||||
Changes for 1.2.0:
|
||||
|
||||
* New feature: value-parameterized tests.
|
||||
* New feature: the ASSERT/EXPECT_(NON)FATAL_FAILURE(_ON_ALL_THREADS)
|
||||
macros.
|
||||
* Changed the XML report format to match JUnit/Ant's.
|
||||
* Added tests to the Xcode project.
|
||||
* Added scons/SConscript for building with SCons.
|
||||
* Added src/gtest-all.cc for building Google Test from a single file.
|
||||
* Fixed compatibility with Solaris and z/OS.
|
||||
* Enabled running Python tests on systems with python 2.3 installed,
|
||||
e.g. Mac OS X 10.4.
|
||||
* Bug fixes.
|
||||
|
||||
Changes for 1.1.0:
|
||||
|
||||
* New feature: type-parameterized tests.
|
||||
* New feature: exception assertions.
|
||||
* New feature: printing elapsed time of tests.
|
||||
* Improved the robustness of death tests.
|
||||
* Added an Xcode project and samples.
|
||||
* Adjusted the output format on Windows to be understandable by Visual Studio.
|
||||
* Minor bug fixes.
|
||||
|
||||
Changes for 1.0.1:
|
||||
|
||||
* Added project files for Visual Studio 7.1.
|
||||
* Fixed issues with compiling on Mac OS X.
|
||||
* Fixed issues with compiling on Cygwin.
|
||||
|
||||
Changes for 1.0.0:
|
||||
|
||||
* Initial Open Source release of Google Test
|
|
@ -1,286 +0,0 @@
|
|||
########################################################################
|
||||
# CMake build script for Google Test.
|
||||
#
|
||||
# To run the tests for Google Test itself on Linux, use 'make test' or
|
||||
# ctest. You can select which tests to run using 'ctest -R regex'.
|
||||
# For more options, run 'ctest --help'.
|
||||
|
||||
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to
|
||||
# make it prominent in the GUI.
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
|
||||
|
||||
# When other libraries are using a shared version of runtime libraries,
|
||||
# Google Test also has to use one.
|
||||
option(
|
||||
gtest_force_shared_crt
|
||||
"Use shared (DLL) run-time lib even when Google Test is built as static lib."
|
||||
OFF)
|
||||
|
||||
option(gtest_build_tests "Build all of gtest's own tests." OFF)
|
||||
|
||||
option(gtest_build_samples "Build gtest's sample programs." OFF)
|
||||
|
||||
option(gtest_disable_pthreads "Disable uses of pthreads in gtest." OFF)
|
||||
|
||||
option(
|
||||
gtest_hide_internal_symbols
|
||||
"Build gtest with internal symbols hidden in shared libraries."
|
||||
OFF)
|
||||
|
||||
# Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build().
|
||||
include(cmake/hermetic_build.cmake OPTIONAL)
|
||||
|
||||
if (COMMAND pre_project_set_up_hermetic_build)
|
||||
pre_project_set_up_hermetic_build()
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Project-wide settings
|
||||
|
||||
# Name of the project.
|
||||
#
|
||||
# CMake files in this project can refer to the root source directory
|
||||
# as ${gtest_SOURCE_DIR} and to the root binary directory as
|
||||
# ${gtest_BINARY_DIR}.
|
||||
# Language "C" is required for find_package(Threads).
|
||||
project(gtest CXX C)
|
||||
cmake_minimum_required(VERSION 2.6.2)
|
||||
|
||||
if (COMMAND set_up_hermetic_build)
|
||||
set_up_hermetic_build()
|
||||
endif()
|
||||
|
||||
if (gtest_hide_internal_symbols)
|
||||
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
|
||||
endif()
|
||||
|
||||
# Define helper functions and macros used by Google Test.
|
||||
include(cmake/internal_utils.cmake)
|
||||
|
||||
config_compiler_and_linker() # Defined in internal_utils.cmake.
|
||||
|
||||
# Where Google Test's .h files can be found.
|
||||
include_directories(
|
||||
${gtest_SOURCE_DIR}/include
|
||||
${gtest_SOURCE_DIR})
|
||||
|
||||
# Where Google Test's libraries can be found.
|
||||
link_directories(${gtest_BINARY_DIR}/src)
|
||||
|
||||
# Summary of tuple support for Microsoft Visual Studio:
|
||||
# Compiler version(MS) version(cmake) Support
|
||||
# ---------- ----------- -------------- -----------------------------
|
||||
# <= VS 2010 <= 10 <= 1600 Use Google Tests's own tuple.
|
||||
# VS 2012 11 1700 std::tr1::tuple + _VARIADIC_MAX=10
|
||||
# VS 2013 12 1800 std::tr1::tuple
|
||||
if (MSVC AND MSVC_VERSION EQUAL 1700)
|
||||
add_definitions(/D _VARIADIC_MAX=10)
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Defines the gtest & gtest_main libraries. User tests should link
|
||||
# with one of them.
|
||||
|
||||
# Google Test libraries. We build them using more strict warnings than what
|
||||
# are used for other targets, to ensure that gtest can be compiled by a user
|
||||
# aggressive about warnings.
|
||||
cxx_library(gtest "${cxx_strict}" src/gtest-all.cc)
|
||||
cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc)
|
||||
target_link_libraries(gtest_main gtest)
|
||||
|
||||
# If the CMake version supports it, attach header directory information
|
||||
# to the targets for when we are part of a parent build (ie being pulled
|
||||
# in via add_subdirectory() rather than being a standalone build).
|
||||
if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
|
||||
target_include_directories(gtest INTERFACE "${gtest_SOURCE_DIR}/include")
|
||||
target_include_directories(gtest_main INTERFACE "${gtest_SOURCE_DIR}/include")
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Install rules
|
||||
install(TARGETS gtest gtest_main
|
||||
DESTINATION lib)
|
||||
install(DIRECTORY ${gtest_SOURCE_DIR}/include/gtest
|
||||
DESTINATION include)
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Samples on how to link user tests with gtest or gtest_main.
|
||||
#
|
||||
# They are not built by default. To build them, set the
|
||||
# gtest_build_samples option to ON. You can do it by running ccmake
|
||||
# or specifying the -Dgtest_build_samples=ON flag when running cmake.
|
||||
|
||||
if (gtest_build_samples)
|
||||
cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc)
|
||||
cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc)
|
||||
cxx_executable(sample3_unittest samples gtest_main)
|
||||
cxx_executable(sample4_unittest samples gtest_main samples/sample4.cc)
|
||||
cxx_executable(sample5_unittest samples gtest_main samples/sample1.cc)
|
||||
cxx_executable(sample6_unittest samples gtest_main)
|
||||
cxx_executable(sample7_unittest samples gtest_main)
|
||||
cxx_executable(sample8_unittest samples gtest_main)
|
||||
cxx_executable(sample9_unittest samples gtest)
|
||||
cxx_executable(sample10_unittest samples gtest)
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Google Test's own tests.
|
||||
#
|
||||
# You can skip this section if you aren't interested in testing
|
||||
# Google Test itself.
|
||||
#
|
||||
# The tests are not built by default. To build them, set the
|
||||
# gtest_build_tests option to ON. You can do it by running ccmake
|
||||
# or specifying the -Dgtest_build_tests=ON flag when running cmake.
|
||||
|
||||
if (gtest_build_tests)
|
||||
# This must be set in the root directory for the tests to be run by
|
||||
# 'make test' or ctest.
|
||||
enable_testing()
|
||||
|
||||
############################################################
|
||||
# C++ tests built with standard compiler flags.
|
||||
|
||||
cxx_test(gtest-death-test_test gtest_main)
|
||||
cxx_test(gtest_environment_test gtest)
|
||||
cxx_test(gtest-filepath_test gtest_main)
|
||||
cxx_test(gtest-linked_ptr_test gtest_main)
|
||||
cxx_test(gtest-listener_test gtest_main)
|
||||
cxx_test(gtest_main_unittest gtest_main)
|
||||
cxx_test(gtest-message_test gtest_main)
|
||||
cxx_test(gtest_no_test_unittest gtest)
|
||||
cxx_test(gtest-options_test gtest_main)
|
||||
cxx_test(gtest-param-test_test gtest
|
||||
test/gtest-param-test2_test.cc)
|
||||
cxx_test(gtest-port_test gtest_main)
|
||||
cxx_test(gtest_pred_impl_unittest gtest_main)
|
||||
cxx_test(gtest_premature_exit_test gtest
|
||||
test/gtest_premature_exit_test.cc)
|
||||
cxx_test(gtest-printers_test gtest_main)
|
||||
cxx_test(gtest_prod_test gtest_main
|
||||
test/production.cc)
|
||||
cxx_test(gtest_repeat_test gtest)
|
||||
cxx_test(gtest_sole_header_test gtest_main)
|
||||
cxx_test(gtest_stress_test gtest)
|
||||
cxx_test(gtest-test-part_test gtest_main)
|
||||
cxx_test(gtest_throw_on_failure_ex_test gtest)
|
||||
cxx_test(gtest-typed-test_test gtest_main
|
||||
test/gtest-typed-test2_test.cc)
|
||||
cxx_test(gtest_unittest gtest_main)
|
||||
cxx_test(gtest-unittest-api_test gtest)
|
||||
|
||||
############################################################
|
||||
# C++ tests built with non-standard compiler flags.
|
||||
|
||||
# MSVC 7.1 does not support STL with exceptions disabled.
|
||||
if (NOT MSVC OR MSVC_VERSION GREATER 1310)
|
||||
cxx_library(gtest_no_exception "${cxx_no_exception}"
|
||||
src/gtest-all.cc)
|
||||
cxx_library(gtest_main_no_exception "${cxx_no_exception}"
|
||||
src/gtest-all.cc src/gtest_main.cc)
|
||||
endif()
|
||||
cxx_library(gtest_main_no_rtti "${cxx_no_rtti}"
|
||||
src/gtest-all.cc src/gtest_main.cc)
|
||||
|
||||
cxx_test_with_flags(gtest-death-test_ex_nocatch_test
|
||||
"${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0"
|
||||
gtest test/gtest-death-test_ex_test.cc)
|
||||
cxx_test_with_flags(gtest-death-test_ex_catch_test
|
||||
"${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1"
|
||||
gtest test/gtest-death-test_ex_test.cc)
|
||||
|
||||
cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}"
|
||||
gtest_main_no_rtti test/gtest_unittest.cc)
|
||||
|
||||
cxx_shared_library(gtest_dll "${cxx_default}"
|
||||
src/gtest-all.cc src/gtest_main.cc)
|
||||
|
||||
cxx_executable_with_flags(gtest_dll_test_ "${cxx_default}"
|
||||
gtest_dll test/gtest_all_test.cc)
|
||||
set_target_properties(gtest_dll_test_
|
||||
PROPERTIES
|
||||
COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
|
||||
|
||||
if (NOT MSVC OR MSVC_VERSION LESS 1600) # 1600 is Visual Studio 2010.
|
||||
# Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that
|
||||
# conflict with our own definitions. Therefore using our own tuple does not
|
||||
# work on those compilers.
|
||||
cxx_library(gtest_main_use_own_tuple "${cxx_use_own_tuple}"
|
||||
src/gtest-all.cc src/gtest_main.cc)
|
||||
|
||||
cxx_test_with_flags(gtest-tuple_test "${cxx_use_own_tuple}"
|
||||
gtest_main_use_own_tuple test/gtest-tuple_test.cc)
|
||||
|
||||
cxx_test_with_flags(gtest_use_own_tuple_test "${cxx_use_own_tuple}"
|
||||
gtest_main_use_own_tuple
|
||||
test/gtest-param-test_test.cc test/gtest-param-test2_test.cc)
|
||||
endif()
|
||||
|
||||
############################################################
|
||||
# Python tests.
|
||||
|
||||
cxx_executable(gtest_break_on_failure_unittest_ test gtest)
|
||||
py_test(gtest_break_on_failure_unittest)
|
||||
|
||||
# Visual Studio .NET 2003 does not support STL with exceptions disabled.
|
||||
if (NOT MSVC OR MSVC_VERSION GREATER 1310) # 1310 is Visual Studio .NET 2003
|
||||
cxx_executable_with_flags(
|
||||
gtest_catch_exceptions_no_ex_test_
|
||||
"${cxx_no_exception}"
|
||||
gtest_main_no_exception
|
||||
test/gtest_catch_exceptions_test_.cc)
|
||||
endif()
|
||||
|
||||
cxx_executable_with_flags(
|
||||
gtest_catch_exceptions_ex_test_
|
||||
"${cxx_exception}"
|
||||
gtest_main
|
||||
test/gtest_catch_exceptions_test_.cc)
|
||||
py_test(gtest_catch_exceptions_test)
|
||||
|
||||
cxx_executable(gtest_color_test_ test gtest)
|
||||
py_test(gtest_color_test)
|
||||
|
||||
cxx_executable(gtest_env_var_test_ test gtest)
|
||||
py_test(gtest_env_var_test)
|
||||
|
||||
cxx_executable(gtest_filter_unittest_ test gtest)
|
||||
py_test(gtest_filter_unittest)
|
||||
|
||||
cxx_executable(gtest_help_test_ test gtest_main)
|
||||
py_test(gtest_help_test)
|
||||
|
||||
cxx_executable(gtest_list_tests_unittest_ test gtest)
|
||||
py_test(gtest_list_tests_unittest)
|
||||
|
||||
cxx_executable(gtest_output_test_ test gtest)
|
||||
py_test(gtest_output_test)
|
||||
|
||||
cxx_executable(gtest_shuffle_test_ test gtest)
|
||||
py_test(gtest_shuffle_test)
|
||||
|
||||
# MSVC 7.1 does not support STL with exceptions disabled.
|
||||
if (NOT MSVC OR MSVC_VERSION GREATER 1310)
|
||||
cxx_executable(gtest_throw_on_failure_test_ test gtest_no_exception)
|
||||
set_target_properties(gtest_throw_on_failure_test_
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${cxx_no_exception}")
|
||||
py_test(gtest_throw_on_failure_test)
|
||||
endif()
|
||||
|
||||
cxx_executable(gtest_uninitialized_test_ test gtest)
|
||||
py_test(gtest_uninitialized_test)
|
||||
|
||||
cxx_executable(gtest_xml_outfile1_test_ test gtest_main)
|
||||
cxx_executable(gtest_xml_outfile2_test_ test gtest_main)
|
||||
py_test(gtest_xml_outfiles_test)
|
||||
|
||||
cxx_executable(gtest_xml_output_unittest_ test gtest)
|
||||
py_test(gtest_xml_output_unittest)
|
||||
endif()
|
|
@ -1,37 +0,0 @@
|
|||
# This file contains a list of people who've made non-trivial
|
||||
# contribution to the Google C++ Testing Framework project. People
|
||||
# who commit code to the project are encouraged to add their names
|
||||
# here. Please keep the list sorted by first names.
|
||||
|
||||
Ajay Joshi <jaj@google.com>
|
||||
Balázs Dán <balazs.dan@gmail.com>
|
||||
Bharat Mediratta <bharat@menalto.com>
|
||||
Chandler Carruth <chandlerc@google.com>
|
||||
Chris Prince <cprince@google.com>
|
||||
Chris Taylor <taylorc@google.com>
|
||||
Dan Egnor <egnor@google.com>
|
||||
Eric Roman <eroman@chromium.org>
|
||||
Hady Zalek <hady.zalek@gmail.com>
|
||||
Jeffrey Yasskin <jyasskin@google.com>
|
||||
Jói Sigurðsson <joi@google.com>
|
||||
Keir Mierle <mierle@gmail.com>
|
||||
Keith Ray <keith.ray@gmail.com>
|
||||
Kenton Varda <kenton@google.com>
|
||||
Manuel Klimek <klimek@google.com>
|
||||
Markus Heule <markus.heule@gmail.com>
|
||||
Mika Raento <mikie@iki.fi>
|
||||
Miklós Fazekas <mfazekas@szemafor.com>
|
||||
Pasi Valminen <pasi.valminen@gmail.com>
|
||||
Patrick Hanna <phanna@google.com>
|
||||
Patrick Riley <pfr@google.com>
|
||||
Peter Kaminski <piotrk@google.com>
|
||||
Preston Jackson <preston.a.jackson@gmail.com>
|
||||
Rainer Klaffenboeck <rainer.klaffenboeck@dynatrace.com>
|
||||
Russ Cox <rsc@google.com>
|
||||
Russ Rufer <russ@pentad.com>
|
||||
Sean Mcafee <eefacm@gmail.com>
|
||||
Sigurður Ásgeirsson <siggi@google.com>
|
||||
Tracy Bialik <tracy@pentad.com>
|
||||
Vadim Berman <vadimb@google.com>
|
||||
Vlad Losev <vladl@google.com>
|
||||
Zhanyong Wan <wan@google.com>
|
|
@ -1,28 +0,0 @@
|
|||
Copyright 2008, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,320 +0,0 @@
|
|||
|
||||
### Generic Build Instructions ###
|
||||
|
||||
#### Setup ####
|
||||
|
||||
To build Google Test and your tests that use it, you need to tell your
|
||||
build system where to find its headers and source files. The exact
|
||||
way to do it depends on which build system you use, and is usually
|
||||
straightforward.
|
||||
|
||||
#### Build ####
|
||||
|
||||
Suppose you put Google Test in directory `${GTEST_DIR}`. To build it,
|
||||
create a library build target (or a project as called by Visual Studio
|
||||
and Xcode) to compile
|
||||
|
||||
```bash
|
||||
${GTEST_DIR}/src/gtest-all.cc
|
||||
```
|
||||
|
||||
with `${GTEST_DIR}/include` in the system header search path and `${GTEST_DIR}`
|
||||
in the normal header search path. Assuming a Linux-like system and gcc,
|
||||
something like the following will do:
|
||||
|
||||
```bash
|
||||
g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
|
||||
-pthread -c ${GTEST_DIR}/src/gtest-all.cc
|
||||
ar -rv libgtest.a gtest-all.o
|
||||
```
|
||||
|
||||
(We need `-pthread` as Google Test uses threads.)
|
||||
|
||||
Next, you should compile your test source file with
|
||||
`${GTEST_DIR}/include` in the system header search path, and link it
|
||||
with gtest and any other necessary libraries:
|
||||
|
||||
```bash
|
||||
g++ -isystem ${GTEST_DIR}/include -pthread path/to/your_test.cc libgtest.a \
|
||||
-o your_test
|
||||
```
|
||||
|
||||
As an example, the make/ directory contains a Makefile that you can
|
||||
use to build Google Test on systems where GNU make is available
|
||||
(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
|
||||
Test's own tests. Instead, it just builds the Google Test library and
|
||||
a sample test. You can use it as a starting point for your own build
|
||||
script.
|
||||
|
||||
If the default settings are correct for your environment, the
|
||||
following commands should succeed:
|
||||
|
||||
```bash
|
||||
cd ${GTEST_DIR}/make
|
||||
make
|
||||
./sample1_unittest
|
||||
```
|
||||
|
||||
If you see errors, try to tweak the contents of `make/Makefile` to make
|
||||
them go away. There are instructions in `make/Makefile` on how to do
|
||||
it.
|
||||
|
||||
### Using CMake ###
|
||||
|
||||
Google Test comes with a CMake build script (
|
||||
[CMakeLists.txt](CMakeLists.txt)) that can be used on a wide range of platforms ("C" stands for
|
||||
cross-platform.). If you don't have CMake installed already, you can
|
||||
download it for free from <http://www.cmake.org/>.
|
||||
|
||||
CMake works by generating native makefiles or build projects that can
|
||||
be used in the compiler environment of your choice. The typical
|
||||
workflow starts with:
|
||||
|
||||
```bash
|
||||
mkdir mybuild # Create a directory to hold the build output.
|
||||
cd mybuild
|
||||
cmake ${GTEST_DIR} # Generate native build scripts.
|
||||
```
|
||||
|
||||
If you want to build Google Test's samples, you should replace the
|
||||
last command with
|
||||
|
||||
```bash
|
||||
cmake -Dgtest_build_samples=ON ${GTEST_DIR}
|
||||
```
|
||||
|
||||
If you are on a \*nix system, you should now see a Makefile in the
|
||||
current directory. Just type 'make' to build gtest.
|
||||
|
||||
If you use Windows and have Visual Studio installed, a `gtest.sln` file
|
||||
and several `.vcproj` files will be created. You can then build them
|
||||
using Visual Studio.
|
||||
|
||||
On Mac OS X with Xcode installed, a `.xcodeproj` file will be generated.
|
||||
|
||||
### Legacy Build Scripts ###
|
||||
|
||||
Before settling on CMake, we have been providing hand-maintained build
|
||||
projects/scripts for Visual Studio, Xcode, and Autotools. While we
|
||||
continue to provide them for convenience, they are not actively
|
||||
maintained any more. We highly recommend that you follow the
|
||||
instructions in the previous two sections to integrate Google Test
|
||||
with your existing build system.
|
||||
|
||||
If you still need to use the legacy build scripts, here's how:
|
||||
|
||||
The msvc\ folder contains two solutions with Visual C++ projects.
|
||||
Open the `gtest.sln` or `gtest-md.sln` file using Visual Studio, and you
|
||||
are ready to build Google Test the same way you build any Visual
|
||||
Studio project. Files that have names ending with -md use DLL
|
||||
versions of Microsoft runtime libraries (the /MD or the /MDd compiler
|
||||
option). Files without that suffix use static versions of the runtime
|
||||
libraries (the /MT or the /MTd option). Please note that one must use
|
||||
the same option to compile both gtest and the test code. If you use
|
||||
Visual Studio 2005 or above, we recommend the -md version as /MD is
|
||||
the default for new projects in these versions of Visual Studio.
|
||||
|
||||
On Mac OS X, open the `gtest.xcodeproj` in the `xcode/` folder using
|
||||
Xcode. Build the "gtest" target. The universal binary framework will
|
||||
end up in your selected build directory (selected in the Xcode
|
||||
"Preferences..." -> "Building" pane and defaults to xcode/build).
|
||||
Alternatively, at the command line, enter:
|
||||
|
||||
```bash
|
||||
xcodebuild
|
||||
```
|
||||
|
||||
This will build the "Release" configuration of gtest.framework in your
|
||||
default build location. See the "xcodebuild" man page for more
|
||||
information about building different configurations and building in
|
||||
different locations.
|
||||
|
||||
If you wish to use the Google Test Xcode project with Xcode 4.x and
|
||||
above, you need to either:
|
||||
|
||||
* update the SDK configuration options in xcode/Config/General.xconfig.
|
||||
Comment options `SDKROOT`, `MACOS_DEPLOYMENT_TARGET`, and `GCC_VERSION`. If
|
||||
you choose this route you lose the ability to target earlier versions
|
||||
of MacOS X.
|
||||
* Install an SDK for an earlier version. This doesn't appear to be
|
||||
supported by Apple, but has been reported to work
|
||||
(http://stackoverflow.com/questions/5378518).
|
||||
|
||||
### Tweaking Google Test ###
|
||||
|
||||
Google Test can be used in diverse environments. The default
|
||||
configuration may not work (or may not work well) out of the box in
|
||||
some environments. However, you can easily tweak Google Test by
|
||||
defining control macros on the compiler command line. Generally,
|
||||
these macros are named like `GTEST_XYZ` and you define them to either 1
|
||||
or 0 to enable or disable a certain feature.
|
||||
|
||||
We list the most frequently used macros below. For a complete list,
|
||||
see file [include/gtest/internal/gtest-port.h](include/gtest/internal/gtest-port.h).
|
||||
|
||||
### Choosing a TR1 Tuple Library ###
|
||||
|
||||
Some Google Test features require the C++ Technical Report 1 (TR1)
|
||||
tuple library, which is not yet available with all compilers. The
|
||||
good news is that Google Test implements a subset of TR1 tuple that's
|
||||
enough for its own need, and will automatically use this when the
|
||||
compiler doesn't provide TR1 tuple.
|
||||
|
||||
Usually you don't need to care about which tuple library Google Test
|
||||
uses. However, if your project already uses TR1 tuple, you need to
|
||||
tell Google Test to use the same TR1 tuple library the rest of your
|
||||
project uses, or the two tuple implementations will clash. To do
|
||||
that, add
|
||||
|
||||
```bash
|
||||
-DGTEST_USE_OWN_TR1_TUPLE=0
|
||||
```
|
||||
|
||||
to the compiler flags while compiling Google Test and your tests. If
|
||||
you want to force Google Test to use its own tuple library, just add
|
||||
|
||||
```bash
|
||||
-DGTEST_USE_OWN_TR1_TUPLE=1
|
||||
```
|
||||
|
||||
to the compiler flags instead.
|
||||
|
||||
If you don't want Google Test to use tuple at all, add
|
||||
|
||||
```bash
|
||||
-DGTEST_HAS_TR1_TUPLE=0
|
||||
```
|
||||
|
||||
and all features using tuple will be disabled.
|
||||
|
||||
### Multi-threaded Tests ###
|
||||
|
||||
Google Test is thread-safe where the pthread library is available.
|
||||
After `#include "gtest/gtest.h"`, you can check the `GTEST_IS_THREADSAFE`
|
||||
macro to see whether this is the case (yes if the macro is `#defined` to
|
||||
1, no if it's undefined.).
|
||||
|
||||
If Google Test doesn't correctly detect whether pthread is available
|
||||
in your environment, you can force it with
|
||||
|
||||
```bash
|
||||
-DGTEST_HAS_PTHREAD=1
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
-DGTEST_HAS_PTHREAD=0
|
||||
```
|
||||
|
||||
When Google Test uses pthread, you may need to add flags to your
|
||||
compiler and/or linker to select the pthread library, or you'll get
|
||||
link errors. If you use the CMake script or the deprecated Autotools
|
||||
script, this is taken care of for you. If you use your own build
|
||||
script, you'll need to read your compiler and linker's manual to
|
||||
figure out what flags to add.
|
||||
|
||||
### As a Shared Library (DLL) ###
|
||||
|
||||
Google Test is compact, so most users can build and link it as a
|
||||
static library for the simplicity. You can choose to use Google Test
|
||||
as a shared library (known as a DLL on Windows) if you prefer.
|
||||
|
||||
To compile *gtest* as a shared library, add
|
||||
|
||||
```bash
|
||||
-DGTEST_CREATE_SHARED_LIBRARY=1
|
||||
```
|
||||
|
||||
to the compiler flags. You'll also need to tell the linker to produce
|
||||
a shared library instead - consult your linker's manual for how to do
|
||||
it.
|
||||
|
||||
To compile your *tests* that use the gtest shared library, add
|
||||
|
||||
```bash
|
||||
-DGTEST_LINKED_AS_SHARED_LIBRARY=1
|
||||
```
|
||||
|
||||
to the compiler flags.
|
||||
|
||||
Note: while the above steps aren't technically necessary today when
|
||||
using some compilers (e.g. GCC), they may become necessary in the
|
||||
future, if we decide to improve the speed of loading the library (see
|
||||
<http://gcc.gnu.org/wiki/Visibility> for details). Therefore you are
|
||||
recommended to always add the above flags when using Google Test as a
|
||||
shared library. Otherwise a future release of Google Test may break
|
||||
your build script.
|
||||
|
||||
### Avoiding Macro Name Clashes ###
|
||||
|
||||
In C++, macros don't obey namespaces. Therefore two libraries that
|
||||
both define a macro of the same name will clash if you #include both
|
||||
definitions. In case a Google Test macro clashes with another
|
||||
library, you can force Google Test to rename its macro to avoid the
|
||||
conflict.
|
||||
|
||||
Specifically, if both Google Test and some other code define macro
|
||||
FOO, you can add
|
||||
|
||||
```bash
|
||||
-DGTEST_DONT_DEFINE_FOO=1
|
||||
```
|
||||
|
||||
to the compiler flags to tell Google Test to change the macro's name
|
||||
from `FOO` to `GTEST_FOO`. Currently `FOO` can be `FAIL`, `SUCCEED`,
|
||||
or `TEST`. For example, with `-DGTEST_DONT_DEFINE_TEST=1`, you'll
|
||||
need to write
|
||||
|
||||
```c++
|
||||
GTEST_TEST(SomeTest, DoesThis) { ... }
|
||||
```
|
||||
|
||||
instead of
|
||||
|
||||
```c++
|
||||
TEST(SomeTest, DoesThis) { ... }
|
||||
```
|
||||
|
||||
in order to define a test.
|
||||
|
||||
## Developing Google Test ##
|
||||
|
||||
This section discusses how to make your own changes to Google Test.
|
||||
|
||||
### Testing Google Test Itself ###
|
||||
|
||||
To make sure your changes work as intended and don't break existing
|
||||
functionality, you'll want to compile and run Google Test's own tests.
|
||||
For that you can use CMake:
|
||||
|
||||
```bash
|
||||
mkdir mybuild
|
||||
cd mybuild
|
||||
cmake -Dgtest_build_tests=ON ${GTEST_DIR}
|
||||
```
|
||||
|
||||
Make sure you have Python installed, as some of Google Test's tests
|
||||
are written in Python. If the cmake command complains about not being
|
||||
able to find Python (`Could NOT find PythonInterp (missing:
|
||||
PYTHON_EXECUTABLE)`), try telling it explicitly where your Python
|
||||
executable can be found:
|
||||
|
||||
```bash
|
||||
cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR}
|
||||
```
|
||||
|
||||
Next, you can build Google Test and all of its own tests. On \*nix,
|
||||
this is usually done by 'make'. To run the tests, do
|
||||
|
||||
```bash
|
||||
make test
|
||||
```
|
||||
|
||||
All tests should pass.
|
||||
|
||||
Normally you don't need to worry about regenerating the source files,
|
||||
unless you need to modify them. In that case, you should modify the
|
||||
corresponding .pump files instead and run the pump.py Python script to
|
||||
regenerate them. You can find pump.py in the [scripts/](scripts/) directory.
|
||||
Read the [Pump manual](docs/PumpManual.md) for how to use it.
|
|
@ -1,246 +0,0 @@
|
|||
# Defines functions and macros useful for building Google Test and
|
||||
# Google Mock.
|
||||
#
|
||||
# Note:
|
||||
#
|
||||
# - This file will be run twice when building Google Mock (once via
|
||||
# Google Test's CMakeLists.txt, and once via Google Mock's).
|
||||
# Therefore it shouldn't have any side effects other than defining
|
||||
# the functions and macros.
|
||||
#
|
||||
# - The functions/macros defined in this file may depend on Google
|
||||
# Test and Google Mock's option() definitions, and thus must be
|
||||
# called *after* the options have been defined.
|
||||
|
||||
# Tweaks CMake's default compiler/linker settings to suit Google Test's needs.
|
||||
#
|
||||
# This must be a macro(), as inside a function string() can only
|
||||
# update variables in the function scope.
|
||||
macro(fix_default_compiler_settings_)
|
||||
if (MSVC)
|
||||
# For MSVC, CMake sets certain flags to defaults we want to override.
|
||||
# This replacement code is taken from sample in the CMake Wiki at
|
||||
# http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace.
|
||||
foreach (flag_var
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt)
|
||||
# When Google Test is built as a shared library, it should also use
|
||||
# shared runtime libraries. Otherwise, it may end up with multiple
|
||||
# copies of runtime library data in different modules, resulting in
|
||||
# hard-to-find crashes. When it is built as a static library, it is
|
||||
# preferable to use CRT as static libraries, as we don't have to rely
|
||||
# on CRT DLLs being available. CMake always defaults to using shared
|
||||
# CRT libraries, so we override that default here.
|
||||
string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}")
|
||||
endif()
|
||||
|
||||
# We prefer more strict warning checking for building Google Test.
|
||||
# Replaces /W3 with /W4 in defaults.
|
||||
string(REPLACE "/W3" "/W4" ${flag_var} "${${flag_var}}")
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Defines the compiler/linker flags used to build Google Test and
|
||||
# Google Mock. You can tweak these definitions to suit your need. A
|
||||
# variable's value is empty before it's explicitly assigned to.
|
||||
macro(config_compiler_and_linker)
|
||||
if (NOT gtest_disable_pthreads AND NOT MINGW)
|
||||
# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT.
|
||||
find_package(Threads)
|
||||
endif()
|
||||
|
||||
fix_default_compiler_settings_()
|
||||
if (MSVC)
|
||||
# Newlines inside flags variables break CMake's NMake generator.
|
||||
# TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds.
|
||||
set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J -Zi")
|
||||
if (MSVC_VERSION LESS 1400) # 1400 is Visual Studio 2005
|
||||
# Suppress spurious warnings MSVC 7.1 sometimes issues.
|
||||
# Forcing value to bool.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4800")
|
||||
# Copy constructor and assignment operator could not be generated.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4511 -wd4512")
|
||||
# Compatibility warnings not applicable to Google Test.
|
||||
# Resolved overload was found by argument-dependent lookup.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4675")
|
||||
endif()
|
||||
if (MSVC_VERSION LESS 1500) # 1500 is Visual Studio 2008
|
||||
# Conditional expression is constant.
|
||||
# When compiling with /W4, we get several instances of C4127
|
||||
# (Conditional expression is constant). In our code, we disable that
|
||||
# warning on a case-by-case basis. However, on Visual Studio 2005,
|
||||
# the warning fires on std::list. Therefore on that compiler and earlier,
|
||||
# we disable the warning project-wide.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4127")
|
||||
endif()
|
||||
if (NOT (MSVC_VERSION LESS 1700)) # 1700 is Visual Studio 2012.
|
||||
# Suppress "unreachable code" warning on VS 2012 and later.
|
||||
# http://stackoverflow.com/questions/3232669 explains the issue.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4702")
|
||||
endif()
|
||||
|
||||
set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32")
|
||||
set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN")
|
||||
set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1")
|
||||
set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0")
|
||||
set(cxx_no_rtti_flags "-GR-")
|
||||
elseif (CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(cxx_base_flags "-Wall -Wshadow -fPIC")
|
||||
set(cxx_exception_flags "-fexceptions")
|
||||
set(cxx_no_exception_flags "-fno-exceptions")
|
||||
# Until version 4.3.2, GCC doesn't define a macro to indicate
|
||||
# whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
|
||||
# explicitly.
|
||||
set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0")
|
||||
set(cxx_strict_flags
|
||||
"-Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(cxx_base_flags "-Wall -Wshadow -fPIC")
|
||||
set(cxx_exception_flags "-fexceptions")
|
||||
set(cxx_no_exception_flags "-fno-exceptions")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
|
||||
set(cxx_exception_flags "-features=except")
|
||||
# Sun Pro doesn't provide macros to indicate whether exceptions and
|
||||
# RTTI are enabled, so we define GTEST_HAS_* explicitly.
|
||||
set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0")
|
||||
set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR
|
||||
CMAKE_CXX_COMPILER_ID STREQUAL "XL")
|
||||
# CMake 2.8 changes Visual Age's compiler ID to "XL".
|
||||
set(cxx_exception_flags "-qeh")
|
||||
set(cxx_no_exception_flags "-qnoeh")
|
||||
# Until version 9.0, Visual Age doesn't define a macro to indicate
|
||||
# whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
|
||||
# explicitly.
|
||||
set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "HP")
|
||||
set(cxx_base_flags "-AA -mt")
|
||||
set(cxx_exception_flags "-DGTEST_HAS_EXCEPTIONS=1")
|
||||
set(cxx_no_exception_flags "+noeh -DGTEST_HAS_EXCEPTIONS=0")
|
||||
# RTTI can not be disabled in HP aCC compiler.
|
||||
set(cxx_no_rtti_flags "")
|
||||
endif()
|
||||
|
||||
if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available and allowed.
|
||||
set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1")
|
||||
else()
|
||||
set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0")
|
||||
endif()
|
||||
|
||||
# For building gtest's own tests and samples.
|
||||
set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}")
|
||||
set(cxx_no_exception
|
||||
"${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}")
|
||||
set(cxx_default "${cxx_exception}")
|
||||
set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}")
|
||||
set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1")
|
||||
|
||||
# For building the gtest libraries.
|
||||
set(cxx_strict "${cxx_default} ${cxx_strict_flags}")
|
||||
endmacro()
|
||||
|
||||
# Defines the gtest & gtest_main libraries. User tests should link
|
||||
# with one of them.
|
||||
function(cxx_library_with_type name type cxx_flags)
|
||||
# type can be either STATIC or SHARED to denote a static or shared library.
|
||||
# ARGN refers to additional arguments after 'cxx_flags'.
|
||||
add_library(${name} ${type} ${ARGN})
|
||||
set_target_properties(${name}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${cxx_flags}")
|
||||
if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED")
|
||||
set_target_properties(${name}
|
||||
PROPERTIES
|
||||
COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1")
|
||||
endif()
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Helper functions for creating build targets.
|
||||
|
||||
function(cxx_shared_library name cxx_flags)
|
||||
cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN})
|
||||
endfunction()
|
||||
|
||||
function(cxx_library name cxx_flags)
|
||||
cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN})
|
||||
endfunction()
|
||||
|
||||
# cxx_executable_with_flags(name cxx_flags libs srcs...)
|
||||
#
|
||||
# creates a named C++ executable that depends on the given libraries and
|
||||
# is built from the given source files with the given compiler flags.
|
||||
function(cxx_executable_with_flags name cxx_flags libs)
|
||||
add_executable(${name} ${ARGN})
|
||||
if (cxx_flags)
|
||||
set_target_properties(${name}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${cxx_flags}")
|
||||
endif()
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set_target_properties(${name}
|
||||
PROPERTIES
|
||||
COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
|
||||
endif()
|
||||
# To support mixing linking in static and dynamic libraries, link each
|
||||
# library in with an extra call to target_link_libraries.
|
||||
foreach (lib "${libs}")
|
||||
target_link_libraries(${name} ${lib})
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# cxx_executable(name dir lib srcs...)
|
||||
#
|
||||
# creates a named target that depends on the given libs and is built
|
||||
# from the given source files. dir/name.cc is implicitly included in
|
||||
# the source file list.
|
||||
function(cxx_executable name dir libs)
|
||||
cxx_executable_with_flags(
|
||||
${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN})
|
||||
endfunction()
|
||||
|
||||
# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE.
|
||||
find_package(PythonInterp)
|
||||
|
||||
# cxx_test_with_flags(name cxx_flags libs srcs...)
|
||||
#
|
||||
# creates a named C++ test that depends on the given libs and is built
|
||||
# from the given source files with the given compiler flags.
|
||||
function(cxx_test_with_flags name cxx_flags libs)
|
||||
cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN})
|
||||
add_test(${name} ${name})
|
||||
endfunction()
|
||||
|
||||
# cxx_test(name libs srcs...)
|
||||
#
|
||||
# creates a named test target that depends on the given libs and is
|
||||
# built from the given source files. Unlike cxx_test_with_flags,
|
||||
# test/name.cc is already implicitly included in the source file list.
|
||||
function(cxx_test name libs)
|
||||
cxx_test_with_flags("${name}" "${cxx_default}" "${libs}"
|
||||
"test/${name}.cc" ${ARGN})
|
||||
endfunction()
|
||||
|
||||
# py_test(name)
|
||||
#
|
||||
# creates a Python test with the given name whose main module is in
|
||||
# test/name.py. It does nothing if Python is not installed.
|
||||
function(py_test name)
|
||||
# We are not supporting Python tests on Linux yet as they consider
|
||||
# all Linux environments to be google3 and try to use google3 features.
|
||||
if (PYTHONINTERP_FOUND)
|
||||
# ${CMAKE_BINARY_DIR} is known at configuration time, so we can
|
||||
# directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known
|
||||
# only at ctest runtime (by calling ctest -c <Configuration>), so
|
||||
# we have to escape $ to delay variable substitution here.
|
||||
add_test(${name}
|
||||
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
|
||||
--build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE})
|
||||
endif()
|
||||
endfunction()
|
|
@ -1,294 +0,0 @@
|
|||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file defines the public API for death tests. It is
|
||||
// #included by gtest.h so a user doesn't need to include this
|
||||
// directly.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
||||
|
||||
#include "gtest/internal/gtest-death-test-internal.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// This flag controls the style of death tests. Valid values are "threadsafe",
|
||||
// meaning that the death test child process will re-execute the test binary
|
||||
// from the start, running only a single death test, or "fast",
|
||||
// meaning that the child process will execute the test logic immediately
|
||||
// after forking.
|
||||
GTEST_DECLARE_string_(death_test_style);
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Returns a Boolean value indicating whether the caller is currently
|
||||
// executing in the context of the death test child process. Tools such as
|
||||
// Valgrind heap checkers may need this to modify their behavior in death
|
||||
// tests. IMPORTANT: This is an internal utility. Using it may break the
|
||||
// implementation of death tests. User code MUST NOT use it.
|
||||
GTEST_API_ bool InDeathTestChild();
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// The following macros are useful for writing death tests.
|
||||
|
||||
// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
|
||||
// executed:
|
||||
//
|
||||
// 1. It generates a warning if there is more than one active
|
||||
// thread. This is because it's safe to fork() or clone() only
|
||||
// when there is a single thread.
|
||||
//
|
||||
// 2. The parent process clone()s a sub-process and runs the death
|
||||
// test in it; the sub-process exits with code 0 at the end of the
|
||||
// death test, if it hasn't exited already.
|
||||
//
|
||||
// 3. The parent process waits for the sub-process to terminate.
|
||||
//
|
||||
// 4. The parent process checks the exit code and error message of
|
||||
// the sub-process.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
|
||||
// for (int i = 0; i < 5; i++) {
|
||||
// EXPECT_DEATH(server.ProcessRequest(i),
|
||||
// "Invalid request .* in ProcessRequest()")
|
||||
// << "Failed to die on request " << i;
|
||||
// }
|
||||
//
|
||||
// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
|
||||
//
|
||||
// bool KilledBySIGHUP(int exit_code) {
|
||||
// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
|
||||
// }
|
||||
//
|
||||
// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
|
||||
//
|
||||
// On the regular expressions used in death tests:
|
||||
//
|
||||
// On POSIX-compliant systems (*nix), we use the <regex.h> library,
|
||||
// which uses the POSIX extended regex syntax.
|
||||
//
|
||||
// On other platforms (e.g. Windows), we only support a simple regex
|
||||
// syntax implemented as part of Google Test. This limited
|
||||
// implementation should be enough most of the time when writing
|
||||
// death tests; though it lacks many features you can find in PCRE
|
||||
// or POSIX extended regex syntax. For example, we don't support
|
||||
// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
|
||||
// repetition count ("x{5,7}"), among others.
|
||||
//
|
||||
// Below is the syntax that we do support. We chose it to be a
|
||||
// subset of both PCRE and POSIX extended regex, so it's easy to
|
||||
// learn wherever you come from. In the following: 'A' denotes a
|
||||
// literal character, period (.), or a single \\ escape sequence;
|
||||
// 'x' and 'y' denote regular expressions; 'm' and 'n' are for
|
||||
// natural numbers.
|
||||
//
|
||||
// c matches any literal character c
|
||||
// \\d matches any decimal digit
|
||||
// \\D matches any character that's not a decimal digit
|
||||
// \\f matches \f
|
||||
// \\n matches \n
|
||||
// \\r matches \r
|
||||
// \\s matches any ASCII whitespace, including \n
|
||||
// \\S matches any character that's not a whitespace
|
||||
// \\t matches \t
|
||||
// \\v matches \v
|
||||
// \\w matches any letter, _, or decimal digit
|
||||
// \\W matches any character that \\w doesn't match
|
||||
// \\c matches any literal character c, which must be a punctuation
|
||||
// . matches any single character except \n
|
||||
// A? matches 0 or 1 occurrences of A
|
||||
// A* matches 0 or many occurrences of A
|
||||
// A+ matches 1 or many occurrences of A
|
||||
// ^ matches the beginning of a string (not that of each line)
|
||||
// $ matches the end of a string (not that of each line)
|
||||
// xy matches x followed by y
|
||||
//
|
||||
// If you accidentally use PCRE or POSIX extended regex features
|
||||
// not implemented by us, you will get a run-time failure. In that
|
||||
// case, please try to rewrite your regular expression within the
|
||||
// above syntax.
|
||||
//
|
||||
// This implementation is *not* meant to be as highly tuned or robust
|
||||
// as a compiled regex library, but should perform well enough for a
|
||||
// death test, which already incurs significant overhead by launching
|
||||
// a child process.
|
||||
//
|
||||
// Known caveats:
|
||||
//
|
||||
// A "threadsafe" style death test obtains the path to the test
|
||||
// program from argv[0] and re-executes it in the sub-process. For
|
||||
// simplicity, the current implementation doesn't search the PATH
|
||||
// when launching the sub-process. This means that the user must
|
||||
// invoke the test program via a path that contains at least one
|
||||
// path separator (e.g. path/to/foo_test and
|
||||
// /absolute/path/to/bar_test are fine, but foo_test is not). This
|
||||
// is rarely a problem as people usually don't put the test binary
|
||||
// directory in PATH.
|
||||
//
|
||||
// TODO(wan@google.com): make thread-safe death tests search the PATH.
|
||||
|
||||
// Asserts that a given statement causes the program to exit, with an
|
||||
// integer exit status that satisfies predicate, and emitting error output
|
||||
// that matches regex.
|
||||
# define ASSERT_EXIT(statement, predicate, regex) \
|
||||
GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
|
||||
|
||||
// Like ASSERT_EXIT, but continues on to successive tests in the
|
||||
// test case, if any:
|
||||
# define EXPECT_EXIT(statement, predicate, regex) \
|
||||
GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
|
||||
|
||||
// Asserts that a given statement causes the program to exit, either by
|
||||
// explicitly exiting with a nonzero exit code or being killed by a
|
||||
// signal, and emitting error output that matches regex.
|
||||
# define ASSERT_DEATH(statement, regex) \
|
||||
ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
|
||||
|
||||
// Like ASSERT_DEATH, but continues on to successive tests in the
|
||||
// test case, if any:
|
||||
# define EXPECT_DEATH(statement, regex) \
|
||||
EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
|
||||
|
||||
// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
|
||||
|
||||
// Tests that an exit code describes a normal exit with a given exit code.
|
||||
class GTEST_API_ ExitedWithCode {
|
||||
public:
|
||||
explicit ExitedWithCode(int exit_code);
|
||||
bool operator()(int exit_status) const;
|
||||
private:
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const ExitedWithCode& other);
|
||||
|
||||
const int exit_code_;
|
||||
};
|
||||
|
||||
# if !GTEST_OS_WINDOWS
|
||||
// Tests that an exit code describes an exit due to termination by a
|
||||
// given signal.
|
||||
class GTEST_API_ KilledBySignal {
|
||||
public:
|
||||
explicit KilledBySignal(int signum);
|
||||
bool operator()(int exit_status) const;
|
||||
private:
|
||||
const int signum_;
|
||||
};
|
||||
# endif // !GTEST_OS_WINDOWS
|
||||
|
||||
// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
|
||||
// The death testing framework causes this to have interesting semantics,
|
||||
// since the sideeffects of the call are only visible in opt mode, and not
|
||||
// in debug mode.
|
||||
//
|
||||
// In practice, this can be used to test functions that utilize the
|
||||
// LOG(DFATAL) macro using the following style:
|
||||
//
|
||||
// int DieInDebugOr12(int* sideeffect) {
|
||||
// if (sideeffect) {
|
||||
// *sideeffect = 12;
|
||||
// }
|
||||
// LOG(DFATAL) << "death";
|
||||
// return 12;
|
||||
// }
|
||||
//
|
||||
// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
|
||||
// int sideeffect = 0;
|
||||
// // Only asserts in dbg.
|
||||
// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
|
||||
//
|
||||
// #ifdef NDEBUG
|
||||
// // opt-mode has sideeffect visible.
|
||||
// EXPECT_EQ(12, sideeffect);
|
||||
// #else
|
||||
// // dbg-mode no visible sideeffect.
|
||||
// EXPECT_EQ(0, sideeffect);
|
||||
// #endif
|
||||
// }
|
||||
//
|
||||
// This will assert that DieInDebugReturn12InOpt() crashes in debug
|
||||
// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
|
||||
// appropriate fallback value (12 in this case) in opt mode. If you
|
||||
// need to test that a function has appropriate side-effects in opt
|
||||
// mode, include assertions against the side-effects. A general
|
||||
// pattern for this is:
|
||||
//
|
||||
// EXPECT_DEBUG_DEATH({
|
||||
// // Side-effects here will have an effect after this statement in
|
||||
// // opt mode, but none in debug mode.
|
||||
// EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
|
||||
// }, "death");
|
||||
//
|
||||
# ifdef NDEBUG
|
||||
|
||||
# define EXPECT_DEBUG_DEATH(statement, regex) \
|
||||
GTEST_EXECUTE_STATEMENT_(statement, regex)
|
||||
|
||||
# define ASSERT_DEBUG_DEATH(statement, regex) \
|
||||
GTEST_EXECUTE_STATEMENT_(statement, regex)
|
||||
|
||||
# else
|
||||
|
||||
# define EXPECT_DEBUG_DEATH(statement, regex) \
|
||||
EXPECT_DEATH(statement, regex)
|
||||
|
||||
# define ASSERT_DEBUG_DEATH(statement, regex) \
|
||||
ASSERT_DEATH(statement, regex)
|
||||
|
||||
# endif // NDEBUG for EXPECT_DEBUG_DEATH
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
|
||||
// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
|
||||
// death tests are supported; otherwise they just issue a warning. This is
|
||||
// useful when you are combining death test assertions with normal test
|
||||
// assertions in one test.
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
EXPECT_DEATH(statement, regex)
|
||||
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
ASSERT_DEATH(statement, regex)
|
||||
#else
|
||||
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
|
||||
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
|
||||
#endif
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
|
@ -1,250 +0,0 @@
|
|||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file defines the Message class.
|
||||
//
|
||||
// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
|
||||
// leave some internal implementation details in this header file.
|
||||
// They are clearly marked by comments like this:
|
||||
//
|
||||
// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
//
|
||||
// Such code is NOT meant to be used by a user directly, and is subject
|
||||
// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
|
||||
// program!
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
// Ensures that there is at least one operator<< in the global namespace.
|
||||
// See Message& operator<<(...) below for why.
|
||||
void operator<<(const testing::internal::Secret&, int);
|
||||
|
||||
namespace testing {
|
||||
|
||||
// The Message class works like an ostream repeater.
|
||||
//
|
||||
// Typical usage:
|
||||
//
|
||||
// 1. You stream a bunch of values to a Message object.
|
||||
// It will remember the text in a stringstream.
|
||||
// 2. Then you stream the Message object to an ostream.
|
||||
// This causes the text in the Message to be streamed
|
||||
// to the ostream.
|
||||
//
|
||||
// For example;
|
||||
//
|
||||
// testing::Message foo;
|
||||
// foo << 1 << " != " << 2;
|
||||
// std::cout << foo;
|
||||
//
|
||||
// will print "1 != 2".
|
||||
//
|
||||
// Message is not intended to be inherited from. In particular, its
|
||||
// destructor is not virtual.
|
||||
//
|
||||
// Note that stringstream behaves differently in gcc and in MSVC. You
|
||||
// can stream a NULL char pointer to it in the former, but not in the
|
||||
// latter (it causes an access violation if you do). The Message
|
||||
// class hides this difference by treating a NULL char pointer as
|
||||
// "(null)".
|
||||
class GTEST_API_ Message {
|
||||
private:
|
||||
// The type of basic IO manipulators (endl, ends, and flush) for
|
||||
// narrow streams.
|
||||
typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
|
||||
|
||||
public:
|
||||
// Constructs an empty Message.
|
||||
Message();
|
||||
|
||||
// Copy constructor.
|
||||
Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT
|
||||
*ss_ << msg.GetString();
|
||||
}
|
||||
|
||||
// Constructs a Message from a C-string.
|
||||
explicit Message(const char* str) : ss_(new ::std::stringstream) {
|
||||
*ss_ << str;
|
||||
}
|
||||
|
||||
#if GTEST_OS_SYMBIAN
|
||||
// Streams a value (either a pointer or not) to this object.
|
||||
template <typename T>
|
||||
inline Message& operator <<(const T& value) {
|
||||
StreamHelper(typename internal::is_pointer<T>::type(), value);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
// Streams a non-pointer value to this object.
|
||||
template <typename T>
|
||||
inline Message& operator <<(const T& val) {
|
||||
// Some libraries overload << for STL containers. These
|
||||
// overloads are defined in the global namespace instead of ::std.
|
||||
//
|
||||
// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
|
||||
// overloads are visible in either the std namespace or the global
|
||||
// namespace, but not other namespaces, including the testing
|
||||
// namespace which Google Test's Message class is in.
|
||||
//
|
||||
// To allow STL containers (and other types that has a << operator
|
||||
// defined in the global namespace) to be used in Google Test
|
||||
// assertions, testing::Message must access the custom << operator
|
||||
// from the global namespace. With this using declaration,
|
||||
// overloads of << defined in the global namespace and those
|
||||
// visible via Koenig lookup are both exposed in this function.
|
||||
using ::operator <<;
|
||||
*ss_ << val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Streams a pointer value to this object.
|
||||
//
|
||||
// This function is an overload of the previous one. When you
|
||||
// stream a pointer to a Message, this definition will be used as it
|
||||
// is more specialized. (The C++ Standard, section
|
||||
// [temp.func.order].) If you stream a non-pointer, then the
|
||||
// previous definition will be used.
|
||||
//
|
||||
// The reason for this overload is that streaming a NULL pointer to
|
||||
// ostream is undefined behavior. Depending on the compiler, you
|
||||
// may get "0", "(nil)", "(null)", or an access violation. To
|
||||
// ensure consistent result across compilers, we always treat NULL
|
||||
// as "(null)".
|
||||
template <typename T>
|
||||
inline Message& operator <<(T* const& pointer) { // NOLINT
|
||||
if (pointer == NULL) {
|
||||
*ss_ << "(null)";
|
||||
} else {
|
||||
*ss_ << pointer;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif // GTEST_OS_SYMBIAN
|
||||
|
||||
// Since the basic IO manipulators are overloaded for both narrow
|
||||
// and wide streams, we have to provide this specialized definition
|
||||
// of operator <<, even though its body is the same as the
|
||||
// templatized version above. Without this definition, streaming
|
||||
// endl or other basic IO manipulators to Message will confuse the
|
||||
// compiler.
|
||||
Message& operator <<(BasicNarrowIoManip val) {
|
||||
*ss_ << val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Instead of 1/0, we want to see true/false for bool values.
|
||||
Message& operator <<(bool b) {
|
||||
return *this << (b ? "true" : "false");
|
||||
}
|
||||
|
||||
// These two overloads allow streaming a wide C string to a Message
|
||||
// using the UTF-8 encoding.
|
||||
Message& operator <<(const wchar_t* wide_c_str);
|
||||
Message& operator <<(wchar_t* wide_c_str);
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
// Converts the given wide string to a narrow string using the UTF-8
|
||||
// encoding, and streams the result to this Message object.
|
||||
Message& operator <<(const ::std::wstring& wstr);
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
||||
#if GTEST_HAS_GLOBAL_WSTRING
|
||||
// Converts the given wide string to a narrow string using the UTF-8
|
||||
// encoding, and streams the result to this Message object.
|
||||
Message& operator <<(const ::wstring& wstr);
|
||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||
|
||||
// Gets the text streamed to this object so far as an std::string.
|
||||
// Each '\0' character in the buffer is replaced with "\\0".
|
||||
//
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
std::string GetString() const;
|
||||
|
||||
private:
|
||||
|
||||
#if GTEST_OS_SYMBIAN
|
||||
// These are needed as the Nokia Symbian Compiler cannot decide between
|
||||
// const T& and const T* in a function template. The Nokia compiler _can_
|
||||
// decide between class template specializations for T and T*, so a
|
||||
// tr1::type_traits-like is_pointer works, and we can overload on that.
|
||||
template <typename T>
|
||||
inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) {
|
||||
if (pointer == NULL) {
|
||||
*ss_ << "(null)";
|
||||
} else {
|
||||
*ss_ << pointer;
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
inline void StreamHelper(internal::false_type /*is_pointer*/,
|
||||
const T& value) {
|
||||
// See the comments in Message& operator <<(const T&) above for why
|
||||
// we need this using statement.
|
||||
using ::operator <<;
|
||||
*ss_ << value;
|
||||
}
|
||||
#endif // GTEST_OS_SYMBIAN
|
||||
|
||||
// We'll hold the text streamed to this object here.
|
||||
const internal::scoped_ptr< ::std::stringstream> ss_;
|
||||
|
||||
// We declare (but don't implement) this to prevent the compiler
|
||||
// from implementing the assignment operator.
|
||||
void operator=(const Message&);
|
||||
};
|
||||
|
||||
// Streams a Message to an ostream.
|
||||
inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
|
||||
return os << sb.GetString();
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Converts a streamable value to an std::string. A NULL pointer is
|
||||
// converted to "(null)". When the input value is a ::string,
|
||||
// ::std::string, ::wstring, or ::std::wstring object, each NUL
|
||||
// character in it is replaced with "\\0".
|
||||
template <typename T>
|
||||
std::string StreamableToString(const T& streamable) {
|
||||
return (Message() << streamable).GetString();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -1,510 +0,0 @@
|
|||
$$ -*- mode: c++; -*-
|
||||
$var n = 50 $$ Maximum length of Values arguments we want to support.
|
||||
$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support.
|
||||
// Copyright 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: vladl@google.com (Vlad Losev)
|
||||
//
|
||||
// Macros and functions for implementing parameterized tests
|
||||
// in Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
|
||||
//
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
|
||||
|
||||
|
||||
// Value-parameterized tests allow you to test your code with different
|
||||
// parameters without writing multiple copies of the same test.
|
||||
//
|
||||
// Here is how you use value-parameterized tests:
|
||||
|
||||
#if 0
|
||||
|
||||
// To write value-parameterized tests, first you should define a fixture
|
||||
// class. It is usually derived from testing::TestWithParam<T> (see below for
|
||||
// another inheritance scheme that's sometimes useful in more complicated
|
||||
// class hierarchies), where the type of your parameter values.
|
||||
// TestWithParam<T> is itself derived from testing::Test. T can be any
|
||||
// copyable type. If it's a raw pointer, you are responsible for managing the
|
||||
// lifespan of the pointed values.
|
||||
|
||||
class FooTest : public ::testing::TestWithParam<const char*> {
|
||||
// You can implement all the usual class fixture members here.
|
||||
};
|
||||
|
||||
// Then, use the TEST_P macro to define as many parameterized tests
|
||||
// for this fixture as you want. The _P suffix is for "parameterized"
|
||||
// or "pattern", whichever you prefer to think.
|
||||
|
||||
TEST_P(FooTest, DoesBlah) {
|
||||
// Inside a test, access the test parameter with the GetParam() method
|
||||
// of the TestWithParam<T> class:
|
||||
EXPECT_TRUE(foo.Blah(GetParam()));
|
||||
...
|
||||
}
|
||||
|
||||
TEST_P(FooTest, HasBlahBlah) {
|
||||
...
|
||||
}
|
||||
|
||||
// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
|
||||
// case with any set of parameters you want. Google Test defines a number
|
||||
// of functions for generating test parameters. They return what we call
|
||||
// (surprise!) parameter generators. Here is a summary of them, which
|
||||
// are all in the testing namespace:
|
||||
//
|
||||
//
|
||||
// Range(begin, end [, step]) - Yields values {begin, begin+step,
|
||||
// begin+step+step, ...}. The values do not
|
||||
// include end. step defaults to 1.
|
||||
// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}.
|
||||
// ValuesIn(container) - Yields values from a C-style array, an STL
|
||||
// ValuesIn(begin,end) container, or an iterator range [begin, end).
|
||||
// Bool() - Yields sequence {false, true}.
|
||||
// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product
|
||||
// for the math savvy) of the values generated
|
||||
// by the N generators.
|
||||
//
|
||||
// For more details, see comments at the definitions of these functions below
|
||||
// in this file.
|
||||
//
|
||||
// The following statement will instantiate tests from the FooTest test case
|
||||
// each with parameter values "meeny", "miny", and "moe".
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(InstantiationName,
|
||||
FooTest,
|
||||
Values("meeny", "miny", "moe"));
|
||||
|
||||
// To distinguish different instances of the pattern, (yes, you
|
||||
// can instantiate it more then once) the first argument to the
|
||||
// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
|
||||
// actual test case name. Remember to pick unique prefixes for different
|
||||
// instantiations. The tests from the instantiation above will have
|
||||
// these names:
|
||||
//
|
||||
// * InstantiationName/FooTest.DoesBlah/0 for "meeny"
|
||||
// * InstantiationName/FooTest.DoesBlah/1 for "miny"
|
||||
// * InstantiationName/FooTest.DoesBlah/2 for "moe"
|
||||
// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
|
||||
// * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
|
||||
// * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
|
||||
//
|
||||
// You can use these names in --gtest_filter.
|
||||
//
|
||||
// This statement will instantiate all tests from FooTest again, each
|
||||
// with parameter values "cat" and "dog":
|
||||
|
||||
const char* pets[] = {"cat", "dog"};
|
||||
INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
|
||||
|
||||
// The tests from the instantiation above will have these names:
|
||||
//
|
||||
// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
|
||||
// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
|
||||
// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
|
||||
// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
|
||||
//
|
||||
// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
|
||||
// in the given test case, whether their definitions come before or
|
||||
// AFTER the INSTANTIATE_TEST_CASE_P statement.
|
||||
//
|
||||
// Please also note that generator expressions (including parameters to the
|
||||
// generators) are evaluated in InitGoogleTest(), after main() has started.
|
||||
// This allows the user on one hand, to adjust generator parameters in order
|
||||
// to dynamically determine a set of tests to run and on the other hand,
|
||||
// give the user a chance to inspect the generated tests with Google Test
|
||||
// reflection API before RUN_ALL_TESTS() is executed.
|
||||
//
|
||||
// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
|
||||
// for more examples.
|
||||
//
|
||||
// In the future, we plan to publish the API for defining new parameter
|
||||
// generators. But for now this interface remains part of the internal
|
||||
// implementation and is subject to change.
|
||||
//
|
||||
//
|
||||
// A parameterized test fixture must be derived from testing::Test and from
|
||||
// testing::WithParamInterface<T>, where T is the type of the parameter
|
||||
// values. Inheriting from TestWithParam<T> satisfies that requirement because
|
||||
// TestWithParam<T> inherits from both Test and WithParamInterface. In more
|
||||
// complicated hierarchies, however, it is occasionally useful to inherit
|
||||
// separately from Test and WithParamInterface. For example:
|
||||
|
||||
class BaseTest : public ::testing::Test {
|
||||
// You can inherit all the usual members for a non-parameterized test
|
||||
// fixture here.
|
||||
};
|
||||
|
||||
class DerivedTest : public BaseTest, public ::testing::WithParamInterface<int> {
|
||||
// The usual test fixture members go here too.
|
||||
};
|
||||
|
||||
TEST_F(BaseTest, HasFoo) {
|
||||
// This is an ordinary non-parameterized test.
|
||||
}
|
||||
|
||||
TEST_P(DerivedTest, DoesBlah) {
|
||||
// GetParam works just the same here as if you inherit from TestWithParam.
|
||||
EXPECT_TRUE(foo.Blah(GetParam()));
|
||||
}
|
||||
|
||||
#endif // 0
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
#if !GTEST_OS_SYMBIAN
|
||||
# include <utility>
|
||||
#endif
|
||||
|
||||
// scripts/fuse_gtest.py depends on gtest's own header being #included
|
||||
// *unconditionally*. Therefore these #includes cannot be moved
|
||||
// inside #if GTEST_HAS_PARAM_TEST.
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-param-util.h"
|
||||
#include "gtest/internal/gtest-param-util-generated.h"
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Functions producing parameter generators.
|
||||
//
|
||||
// Google Test uses these generators to produce parameters for value-
|
||||
// parameterized tests. When a parameterized test case is instantiated
|
||||
// with a particular generator, Google Test creates and runs tests
|
||||
// for each element in the sequence produced by the generator.
|
||||
//
|
||||
// In the following sample, tests from test case FooTest are instantiated
|
||||
// each three times with parameter values 3, 5, and 8:
|
||||
//
|
||||
// class FooTest : public TestWithParam<int> { ... };
|
||||
//
|
||||
// TEST_P(FooTest, TestThis) {
|
||||
// }
|
||||
// TEST_P(FooTest, TestThat) {
|
||||
// }
|
||||
// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
|
||||
//
|
||||
|
||||
// Range() returns generators providing sequences of values in a range.
|
||||
//
|
||||
// Synopsis:
|
||||
// Range(start, end)
|
||||
// - returns a generator producing a sequence of values {start, start+1,
|
||||
// start+2, ..., }.
|
||||
// Range(start, end, step)
|
||||
// - returns a generator producing a sequence of values {start, start+step,
|
||||
// start+step+step, ..., }.
|
||||
// Notes:
|
||||
// * The generated sequences never include end. For example, Range(1, 5)
|
||||
// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
|
||||
// returns a generator producing {1, 3, 5, 7}.
|
||||
// * start and end must have the same type. That type may be any integral or
|
||||
// floating-point type or a user defined type satisfying these conditions:
|
||||
// * It must be assignable (have operator=() defined).
|
||||
// * It must have operator+() (operator+(int-compatible type) for
|
||||
// two-operand version).
|
||||
// * It must have operator<() defined.
|
||||
// Elements in the resulting sequences will also have that type.
|
||||
// * Condition start < end must be satisfied in order for resulting sequences
|
||||
// to contain any elements.
|
||||
//
|
||||
template <typename T, typename IncrementT>
|
||||
internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
|
||||
return internal::ParamGenerator<T>(
|
||||
new internal::RangeGenerator<T, IncrementT>(start, end, step));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
internal::ParamGenerator<T> Range(T start, T end) {
|
||||
return Range(start, end, 1);
|
||||
}
|
||||
|
||||
// ValuesIn() function allows generation of tests with parameters coming from
|
||||
// a container.
|
||||
//
|
||||
// Synopsis:
|
||||
// ValuesIn(const T (&array)[N])
|
||||
// - returns a generator producing sequences with elements from
|
||||
// a C-style array.
|
||||
// ValuesIn(const Container& container)
|
||||
// - returns a generator producing sequences with elements from
|
||||
// an STL-style container.
|
||||
// ValuesIn(Iterator begin, Iterator end)
|
||||
// - returns a generator producing sequences with elements from
|
||||
// a range [begin, end) defined by a pair of STL-style iterators. These
|
||||
// iterators can also be plain C pointers.
|
||||
//
|
||||
// Please note that ValuesIn copies the values from the containers
|
||||
// passed in and keeps them to generate tests in RUN_ALL_TESTS().
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// This instantiates tests from test case StringTest
|
||||
// each with C-string values of "foo", "bar", and "baz":
|
||||
//
|
||||
// const char* strings[] = {"foo", "bar", "baz"};
|
||||
// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
|
||||
//
|
||||
// This instantiates tests from test case StlStringTest
|
||||
// each with STL strings with values "a" and "b":
|
||||
//
|
||||
// ::std::vector< ::std::string> GetParameterStrings() {
|
||||
// ::std::vector< ::std::string> v;
|
||||
// v.push_back("a");
|
||||
// v.push_back("b");
|
||||
// return v;
|
||||
// }
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(CharSequence,
|
||||
// StlStringTest,
|
||||
// ValuesIn(GetParameterStrings()));
|
||||
//
|
||||
//
|
||||
// This will also instantiate tests from CharTest
|
||||
// each with parameter values 'a' and 'b':
|
||||
//
|
||||
// ::std::list<char> GetParameterChars() {
|
||||
// ::std::list<char> list;
|
||||
// list.push_back('a');
|
||||
// list.push_back('b');
|
||||
// return list;
|
||||
// }
|
||||
// ::std::list<char> l = GetParameterChars();
|
||||
// INSTANTIATE_TEST_CASE_P(CharSequence2,
|
||||
// CharTest,
|
||||
// ValuesIn(l.begin(), l.end()));
|
||||
//
|
||||
template <typename ForwardIterator>
|
||||
internal::ParamGenerator<
|
||||
typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
|
||||
ValuesIn(ForwardIterator begin, ForwardIterator end) {
|
||||
typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
|
||||
::value_type ParamType;
|
||||
return internal::ParamGenerator<ParamType>(
|
||||
new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
|
||||
return ValuesIn(array, array + N);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
internal::ParamGenerator<typename Container::value_type> ValuesIn(
|
||||
const Container& container) {
|
||||
return ValuesIn(container.begin(), container.end());
|
||||
}
|
||||
|
||||
// Values() allows generating tests from explicitly specified list of
|
||||
// parameters.
|
||||
//
|
||||
// Synopsis:
|
||||
// Values(T v1, T v2, ..., T vN)
|
||||
// - returns a generator producing sequences with elements v1, v2, ..., vN.
|
||||
//
|
||||
// For example, this instantiates tests from test case BarTest each
|
||||
// with values "one", "two", and "three":
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
|
||||
//
|
||||
// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
|
||||
// The exact type of values will depend on the type of parameter in BazTest.
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
|
||||
//
|
||||
// Currently, Values() supports from 1 to $n parameters.
|
||||
//
|
||||
$range i 1..n
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[typename T$j]]>
|
||||
internal::ValueArray$i<$for j, [[T$j]]> Values($for j, [[T$j v$j]]) {
|
||||
return internal::ValueArray$i<$for j, [[T$j]]>($for j, [[v$j]]);
|
||||
}
|
||||
|
||||
]]
|
||||
|
||||
// Bool() allows generating tests with parameters in a set of (false, true).
|
||||
//
|
||||
// Synopsis:
|
||||
// Bool()
|
||||
// - returns a generator producing sequences with elements {false, true}.
|
||||
//
|
||||
// It is useful when testing code that depends on Boolean flags. Combinations
|
||||
// of multiple flags can be tested when several Bool()'s are combined using
|
||||
// Combine() function.
|
||||
//
|
||||
// In the following example all tests in the test case FlagDependentTest
|
||||
// will be instantiated twice with parameters false and true.
|
||||
//
|
||||
// class FlagDependentTest : public testing::TestWithParam<bool> {
|
||||
// virtual void SetUp() {
|
||||
// external_flag = GetParam();
|
||||
// }
|
||||
// }
|
||||
// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
|
||||
//
|
||||
inline internal::ParamGenerator<bool> Bool() {
|
||||
return Values(false, true);
|
||||
}
|
||||
|
||||
# if GTEST_HAS_COMBINE
|
||||
// Combine() allows the user to combine two or more sequences to produce
|
||||
// values of a Cartesian product of those sequences' elements.
|
||||
//
|
||||
// Synopsis:
|
||||
// Combine(gen1, gen2, ..., genN)
|
||||
// - returns a generator producing sequences with elements coming from
|
||||
// the Cartesian product of elements from the sequences generated by
|
||||
// gen1, gen2, ..., genN. The sequence elements will have a type of
|
||||
// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
|
||||
// of elements from sequences produces by gen1, gen2, ..., genN.
|
||||
//
|
||||
// Combine can have up to $maxtuple arguments. This number is currently limited
|
||||
// by the maximum number of elements in the tuple implementation used by Google
|
||||
// Test.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// This will instantiate tests in test case AnimalTest each one with
|
||||
// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
|
||||
// tuple("dog", BLACK), and tuple("dog", WHITE):
|
||||
//
|
||||
// enum Color { BLACK, GRAY, WHITE };
|
||||
// class AnimalTest
|
||||
// : public testing::TestWithParam<tuple<const char*, Color> > {...};
|
||||
//
|
||||
// TEST_P(AnimalTest, AnimalLooksNice) {...}
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
|
||||
// Combine(Values("cat", "dog"),
|
||||
// Values(BLACK, WHITE)));
|
||||
//
|
||||
// This will instantiate tests in FlagDependentTest with all variations of two
|
||||
// Boolean flags:
|
||||
//
|
||||
// class FlagDependentTest
|
||||
// : public testing::TestWithParam<tuple<bool, bool> > {
|
||||
// virtual void SetUp() {
|
||||
// // Assigns external_flag_1 and external_flag_2 values from the tuple.
|
||||
// tie(external_flag_1, external_flag_2) = GetParam();
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// TEST_P(FlagDependentTest, TestFeature1) {
|
||||
// // Test your code using external_flag_1 and external_flag_2 here.
|
||||
// }
|
||||
// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
|
||||
// Combine(Bool(), Bool()));
|
||||
//
|
||||
$range i 2..maxtuple
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[typename Generator$j]]>
|
||||
internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine(
|
||||
$for j, [[const Generator$j& g$j]]) {
|
||||
return internal::CartesianProductHolder$i<$for j, [[Generator$j]]>(
|
||||
$for j, [[g$j]]);
|
||||
}
|
||||
|
||||
]]
|
||||
# endif // GTEST_HAS_COMBINE
|
||||
|
||||
|
||||
|
||||
# define TEST_P(test_case_name, test_name) \
|
||||
class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
|
||||
: public test_case_name { \
|
||||
public: \
|
||||
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
|
||||
virtual void TestBody(); \
|
||||
private: \
|
||||
static int AddToRegistry() { \
|
||||
::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
|
||||
GetTestCasePatternHolder<test_case_name>(\
|
||||
#test_case_name, \
|
||||
::testing::internal::CodeLocation(\
|
||||
__FILE__, __LINE__))->AddTestPattern(\
|
||||
#test_case_name, \
|
||||
#test_name, \
|
||||
new ::testing::internal::TestMetaFactory< \
|
||||
GTEST_TEST_CLASS_NAME_(\
|
||||
test_case_name, test_name)>()); \
|
||||
return 0; \
|
||||
} \
|
||||
static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(\
|
||||
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
|
||||
}; \
|
||||
int GTEST_TEST_CLASS_NAME_(test_case_name, \
|
||||
test_name)::gtest_registering_dummy_ = \
|
||||
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
|
||||
void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
|
||||
|
||||
// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user
|
||||
// to specify a function or functor that generates custom test name suffixes
|
||||
// based on the test parameters. The function should accept one argument of
|
||||
// type testing::TestParamInfo<class ParamType>, and return std::string.
|
||||
//
|
||||
// testing::PrintToStringParamName is a builtin test suffix generator that
|
||||
// returns the value of testing::PrintToString(GetParam()).
|
||||
//
|
||||
// Note: test names must be non-empty, unique, and may only contain ASCII
|
||||
// alphanumeric characters or underscore. Because PrintToString adds quotes
|
||||
// to std::string and C strings, it won't work for these types.
|
||||
|
||||
# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \
|
||||
::testing::internal::ParamGenerator<test_case_name::ParamType> \
|
||||
gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
|
||||
::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \
|
||||
const ::testing::TestParamInfo<test_case_name::ParamType>& info) { \
|
||||
return ::testing::internal::GetParamNameGen<test_case_name::ParamType> \
|
||||
(__VA_ARGS__)(info); \
|
||||
} \
|
||||
int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \
|
||||
::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
|
||||
GetTestCasePatternHolder<test_case_name>(\
|
||||
#test_case_name, \
|
||||
::testing::internal::CodeLocation(\
|
||||
__FILE__, __LINE__))->AddTestCaseInstantiation(\
|
||||
#prefix, \
|
||||
>est_##prefix##test_case_name##_EvalGenerator_, \
|
||||
>est_##prefix##test_case_name##_EvalGenerateName_, \
|
||||
__FILE__, __LINE__)
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
|
|
@ -1,993 +0,0 @@
|
|||
// Copyright 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
// Google Test - The Google C++ Testing Framework
|
||||
//
|
||||
// This file implements a universal value printer that can print a
|
||||
// value of any type T:
|
||||
//
|
||||
// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
|
||||
//
|
||||
// A user can teach this function how to print a class type T by
|
||||
// defining either operator<<() or PrintTo() in the namespace that
|
||||
// defines T. More specifically, the FIRST defined function in the
|
||||
// following list will be used (assuming T is defined in namespace
|
||||
// foo):
|
||||
//
|
||||
// 1. foo::PrintTo(const T&, ostream*)
|
||||
// 2. operator<<(ostream&, const T&) defined in either foo or the
|
||||
// global namespace.
|
||||
//
|
||||
// If none of the above is defined, it will print the debug string of
|
||||
// the value if it is a protocol buffer, or print the raw bytes in the
|
||||
// value otherwise.
|
||||
//
|
||||
// To aid debugging: when T is a reference type, the address of the
|
||||
// value is also printed; when T is a (const) char pointer, both the
|
||||
// pointer value and the NUL-terminated string it points to are
|
||||
// printed.
|
||||
//
|
||||
// We also provide some convenient wrappers:
|
||||
//
|
||||
// // Prints a value to a string. For a (const or not) char
|
||||
// // pointer, the NUL-terminated string (but not the pointer) is
|
||||
// // printed.
|
||||
// std::string ::testing::PrintToString(const T& value);
|
||||
//
|
||||
// // Prints a value tersely: for a reference type, the referenced
|
||||
// // value (but not the address) is printed; for a (const or not) char
|
||||
// // pointer, the NUL-terminated string (but not the pointer) is
|
||||
// // printed.
|
||||
// void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
|
||||
//
|
||||
// // Prints value using the type inferred by the compiler. The difference
|
||||
// // from UniversalTersePrint() is that this function prints both the
|
||||
// // pointer and the NUL-terminated string for a (const or not) char pointer.
|
||||
// void ::testing::internal::UniversalPrint(const T& value, ostream*);
|
||||
//
|
||||
// // Prints the fields of a tuple tersely to a string vector, one
|
||||
// // element for each field. Tuple support must be enabled in
|
||||
// // gtest-port.h.
|
||||
// std::vector<string> UniversalTersePrintTupleFieldsToStrings(
|
||||
// const Tuple& value);
|
||||
//
|
||||
// Known limitation:
|
||||
//
|
||||
// The print primitives print the elements of an STL-style container
|
||||
// using the compiler-inferred type of *iter where iter is a
|
||||
// const_iterator of the container. When const_iterator is an input
|
||||
// iterator but not a forward iterator, this inferred type may not
|
||||
// match value_type, and the print output may be incorrect. In
|
||||
// practice, this is rarely a problem as for most containers
|
||||
// const_iterator is a forward iterator. We'll fix this if there's an
|
||||
// actual need for it. Note that this fix cannot rely on value_type
|
||||
// being defined as many user-defined container types don't have
|
||||
// value_type.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
||||
|
||||
#include <ostream> // NOLINT
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
||||
#if GTEST_HAS_STD_TUPLE_
|
||||
# include <tuple>
|
||||
#endif
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Definitions in the 'internal' and 'internal2' name spaces are
|
||||
// subject to change without notice. DO NOT USE THEM IN USER CODE!
|
||||
namespace internal2 {
|
||||
|
||||
// Prints the given number of bytes in the given object to the given
|
||||
// ostream.
|
||||
GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
|
||||
size_t count,
|
||||
::std::ostream* os);
|
||||
|
||||
// For selecting which printer to use when a given type has neither <<
|
||||
// nor PrintTo().
|
||||
enum TypeKind {
|
||||
kProtobuf, // a protobuf type
|
||||
kConvertibleToInteger, // a type implicitly convertible to BiggestInt
|
||||
// (e.g. a named or unnamed enum type)
|
||||
kOtherType // anything else
|
||||
};
|
||||
|
||||
// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
|
||||
// by the universal printer to print a value of type T when neither
|
||||
// operator<< nor PrintTo() is defined for T, where kTypeKind is the
|
||||
// "kind" of T as defined by enum TypeKind.
|
||||
template <typename T, TypeKind kTypeKind>
|
||||
class TypeWithoutFormatter {
|
||||
public:
|
||||
// This default version is called when kTypeKind is kOtherType.
|
||||
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||
PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
|
||||
sizeof(value), os);
|
||||
}
|
||||
};
|
||||
|
||||
// We print a protobuf using its ShortDebugString() when the string
|
||||
// doesn't exceed this many characters; otherwise we print it using
|
||||
// DebugString() for better readability.
|
||||
const size_t kProtobufOneLinerMaxLength = 50;
|
||||
|
||||
template <typename T>
|
||||
class TypeWithoutFormatter<T, kProtobuf> {
|
||||
public:
|
||||
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||
const ::testing::internal::string short_str = value.ShortDebugString();
|
||||
const ::testing::internal::string pretty_str =
|
||||
short_str.length() <= kProtobufOneLinerMaxLength ?
|
||||
short_str : ("\n" + value.DebugString());
|
||||
*os << ("<" + pretty_str + ">");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypeWithoutFormatter<T, kConvertibleToInteger> {
|
||||
public:
|
||||
// Since T has no << operator or PrintTo() but can be implicitly
|
||||
// converted to BiggestInt, we print it as a BiggestInt.
|
||||
//
|
||||
// Most likely T is an enum type (either named or unnamed), in which
|
||||
// case printing it as an integer is the desired behavior. In case
|
||||
// T is not an enum, printing it as an integer is the best we can do
|
||||
// given that it has no user-defined printer.
|
||||
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||
const internal::BiggestInt kBigInt = value;
|
||||
*os << kBigInt;
|
||||
}
|
||||
};
|
||||
|
||||
// Prints the given value to the given ostream. If the value is a
|
||||
// protocol message, its debug string is printed; if it's an enum or
|
||||
// of a type implicitly convertible to BiggestInt, it's printed as an
|
||||
// integer; otherwise the bytes in the value are printed. This is
|
||||
// what UniversalPrinter<T>::Print() does when it knows nothing about
|
||||
// type T and T has neither << operator nor PrintTo().
|
||||
//
|
||||
// A user can override this behavior for a class type Foo by defining
|
||||
// a << operator in the namespace where Foo is defined.
|
||||
//
|
||||
// We put this operator in namespace 'internal2' instead of 'internal'
|
||||
// to simplify the implementation, as much code in 'internal' needs to
|
||||
// use << in STL, which would conflict with our own << were it defined
|
||||
// in 'internal'.
|
||||
//
|
||||
// Note that this operator<< takes a generic std::basic_ostream<Char,
|
||||
// CharTraits> type instead of the more restricted std::ostream. If
|
||||
// we define it to take an std::ostream instead, we'll get an
|
||||
// "ambiguous overloads" compiler error when trying to print a type
|
||||
// Foo that supports streaming to std::basic_ostream<Char,
|
||||
// CharTraits>, as the compiler cannot tell whether
|
||||
// operator<<(std::ostream&, const T&) or
|
||||
// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more
|
||||
// specific.
|
||||
template <typename Char, typename CharTraits, typename T>
|
||||
::std::basic_ostream<Char, CharTraits>& operator<<(
|
||||
::std::basic_ostream<Char, CharTraits>& os, const T& x) {
|
||||
TypeWithoutFormatter<T,
|
||||
(internal::IsAProtocolMessage<T>::value ? kProtobuf :
|
||||
internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ?
|
||||
kConvertibleToInteger : kOtherType)>::PrintValue(x, &os);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace internal2
|
||||
} // namespace testing
|
||||
|
||||
// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up
|
||||
// magic needed for implementing UniversalPrinter won't work.
|
||||
namespace testing_internal {
|
||||
|
||||
// Used to print a value that is not an STL-style container when the
|
||||
// user doesn't define PrintTo() for it.
|
||||
template <typename T>
|
||||
void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
|
||||
// With the following statement, during unqualified name lookup,
|
||||
// testing::internal2::operator<< appears as if it was declared in
|
||||
// the nearest enclosing namespace that contains both
|
||||
// ::testing_internal and ::testing::internal2, i.e. the global
|
||||
// namespace. For more details, refer to the C++ Standard section
|
||||
// 7.3.4-1 [namespace.udir]. This allows us to fall back onto
|
||||
// testing::internal2::operator<< in case T doesn't come with a <<
|
||||
// operator.
|
||||
//
|
||||
// We cannot write 'using ::testing::internal2::operator<<;', which
|
||||
// gcc 3.3 fails to compile due to a compiler bug.
|
||||
using namespace ::testing::internal2; // NOLINT
|
||||
|
||||
// Assuming T is defined in namespace foo, in the next statement,
|
||||
// the compiler will consider all of:
|
||||
//
|
||||
// 1. foo::operator<< (thanks to Koenig look-up),
|
||||
// 2. ::operator<< (as the current namespace is enclosed in ::),
|
||||
// 3. testing::internal2::operator<< (thanks to the using statement above).
|
||||
//
|
||||
// The operator<< whose type matches T best will be picked.
|
||||
//
|
||||
// We deliberately allow #2 to be a candidate, as sometimes it's
|
||||
// impossible to define #1 (e.g. when foo is ::std, defining
|
||||
// anything in it is undefined behavior unless you are a compiler
|
||||
// vendor.).
|
||||
*os << value;
|
||||
}
|
||||
|
||||
} // namespace testing_internal
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
|
||||
// value of type ToPrint that is an operand of a comparison assertion
|
||||
// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in
|
||||
// the comparison, and is used to help determine the best way to
|
||||
// format the value. In particular, when the value is a C string
|
||||
// (char pointer) and the other operand is an STL string object, we
|
||||
// want to format the C string as a string, since we know it is
|
||||
// compared by value with the string object. If the value is a char
|
||||
// pointer but the other operand is not an STL string object, we don't
|
||||
// know whether the pointer is supposed to point to a NUL-terminated
|
||||
// string, and thus want to print it as a pointer to be safe.
|
||||
//
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
|
||||
// The default case.
|
||||
template <typename ToPrint, typename OtherOperand>
|
||||
class FormatForComparison {
|
||||
public:
|
||||
static ::std::string Format(const ToPrint& value) {
|
||||
return ::testing::PrintToString(value);
|
||||
}
|
||||
};
|
||||
|
||||
// Array.
|
||||
template <typename ToPrint, size_t N, typename OtherOperand>
|
||||
class FormatForComparison<ToPrint[N], OtherOperand> {
|
||||
public:
|
||||
static ::std::string Format(const ToPrint* value) {
|
||||
return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
|
||||
}
|
||||
};
|
||||
|
||||
// By default, print C string as pointers to be safe, as we don't know
|
||||
// whether they actually point to a NUL-terminated string.
|
||||
|
||||
#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \
|
||||
template <typename OtherOperand> \
|
||||
class FormatForComparison<CharType*, OtherOperand> { \
|
||||
public: \
|
||||
static ::std::string Format(CharType* value) { \
|
||||
return ::testing::PrintToString(static_cast<const void*>(value)); \
|
||||
} \
|
||||
}
|
||||
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
|
||||
|
||||
#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
|
||||
|
||||
// If a C string is compared with an STL string object, we know it's meant
|
||||
// to point to a NUL-terminated string, and thus can print it as a string.
|
||||
|
||||
#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
|
||||
template <> \
|
||||
class FormatForComparison<CharType*, OtherStringType> { \
|
||||
public: \
|
||||
static ::std::string Format(CharType* value) { \
|
||||
return ::testing::PrintToString(value); \
|
||||
} \
|
||||
}
|
||||
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
|
||||
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
|
||||
#endif
|
||||
|
||||
#if GTEST_HAS_GLOBAL_WSTRING
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
|
||||
#endif
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
|
||||
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
|
||||
#endif
|
||||
|
||||
#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
|
||||
|
||||
// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
|
||||
// operand to be used in a failure message. The type (but not value)
|
||||
// of the other operand may affect the format. This allows us to
|
||||
// print a char* as a raw pointer when it is compared against another
|
||||
// char* or void*, and print it as a C string when it is compared
|
||||
// against an std::string object, for example.
|
||||
//
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
template <typename T1, typename T2>
|
||||
std::string FormatForComparisonFailureMessage(
|
||||
const T1& value, const T2& /* other_operand */) {
|
||||
return FormatForComparison<T1, T2>::Format(value);
|
||||
}
|
||||
|
||||
// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
|
||||
// value to the given ostream. The caller must ensure that
|
||||
// 'ostream_ptr' is not NULL, or the behavior is undefined.
|
||||
//
|
||||
// We define UniversalPrinter as a class template (as opposed to a
|
||||
// function template), as we need to partially specialize it for
|
||||
// reference types, which cannot be done with function templates.
|
||||
template <typename T>
|
||||
class UniversalPrinter;
|
||||
|
||||
template <typename T>
|
||||
void UniversalPrint(const T& value, ::std::ostream* os);
|
||||
|
||||
// Used to print an STL-style container when the user doesn't define
|
||||
// a PrintTo() for it.
|
||||
template <typename C>
|
||||
void DefaultPrintTo(IsContainer /* dummy */,
|
||||
false_type /* is not a pointer */,
|
||||
const C& container, ::std::ostream* os) {
|
||||
const size_t kMaxCount = 32; // The maximum number of elements to print.
|
||||
*os << '{';
|
||||
size_t count = 0;
|
||||
for (typename C::const_iterator it = container.begin();
|
||||
it != container.end(); ++it, ++count) {
|
||||
if (count > 0) {
|
||||
*os << ',';
|
||||
if (count == kMaxCount) { // Enough has been printed.
|
||||
*os << " ...";
|
||||
break;
|
||||
}
|
||||
}
|
||||
*os << ' ';
|
||||
// We cannot call PrintTo(*it, os) here as PrintTo() doesn't
|
||||
// handle *it being a native array.
|
||||
internal::UniversalPrint(*it, os);
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
*os << ' ';
|
||||
}
|
||||
*os << '}';
|
||||
}
|
||||
|
||||
// Used to print a pointer that is neither a char pointer nor a member
|
||||
// pointer, when the user doesn't define PrintTo() for it. (A member
|
||||
// variable pointer or member function pointer doesn't really point to
|
||||
// a location in the address space. Their representation is
|
||||
// implementation-defined. Therefore they will be printed as raw
|
||||
// bytes.)
|
||||
template <typename T>
|
||||
void DefaultPrintTo(IsNotContainer /* dummy */,
|
||||
true_type /* is a pointer */,
|
||||
T* p, ::std::ostream* os) {
|
||||
if (p == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
// C++ doesn't allow casting from a function pointer to any object
|
||||
// pointer.
|
||||
//
|
||||
// IsTrue() silences warnings: "Condition is always true",
|
||||
// "unreachable code".
|
||||
if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) {
|
||||
// T is not a function type. We just call << to print p,
|
||||
// relying on ADL to pick up user-defined << for their pointer
|
||||
// types, if any.
|
||||
*os << p;
|
||||
} else {
|
||||
// T is a function type, so '*os << p' doesn't do what we want
|
||||
// (it just prints p as bool). We want to print p as a const
|
||||
// void*. However, we cannot cast it to const void* directly,
|
||||
// even using reinterpret_cast, as earlier versions of gcc
|
||||
// (e.g. 3.4.5) cannot compile the cast when p is a function
|
||||
// pointer. Casting to UInt64 first solves the problem.
|
||||
*os << reinterpret_cast<const void*>(
|
||||
reinterpret_cast<internal::UInt64>(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used to print a non-container, non-pointer value when the user
|
||||
// doesn't define PrintTo() for it.
|
||||
template <typename T>
|
||||
void DefaultPrintTo(IsNotContainer /* dummy */,
|
||||
false_type /* is not a pointer */,
|
||||
const T& value, ::std::ostream* os) {
|
||||
::testing_internal::DefaultPrintNonContainerTo(value, os);
|
||||
}
|
||||
|
||||
// Prints the given value using the << operator if it has one;
|
||||
// otherwise prints the bytes in it. This is what
|
||||
// UniversalPrinter<T>::Print() does when PrintTo() is not specialized
|
||||
// or overloaded for type T.
|
||||
//
|
||||
// A user can override this behavior for a class type Foo by defining
|
||||
// an overload of PrintTo() in the namespace where Foo is defined. We
|
||||
// give the user this option as sometimes defining a << operator for
|
||||
// Foo is not desirable (e.g. the coding style may prevent doing it,
|
||||
// or there is already a << operator but it doesn't do what the user
|
||||
// wants).
|
||||
template <typename T>
|
||||
void PrintTo(const T& value, ::std::ostream* os) {
|
||||
// DefaultPrintTo() is overloaded. The type of its first two
|
||||
// arguments determine which version will be picked. If T is an
|
||||
// STL-style container, the version for container will be called; if
|
||||
// T is a pointer, the pointer version will be called; otherwise the
|
||||
// generic version will be called.
|
||||
//
|
||||
// Note that we check for container types here, prior to we check
|
||||
// for protocol message types in our operator<<. The rationale is:
|
||||
//
|
||||
// For protocol messages, we want to give people a chance to
|
||||
// override Google Mock's format by defining a PrintTo() or
|
||||
// operator<<. For STL containers, other formats can be
|
||||
// incompatible with Google Mock's format for the container
|
||||
// elements; therefore we check for container types here to ensure
|
||||
// that our format is used.
|
||||
//
|
||||
// The second argument of DefaultPrintTo() is needed to bypass a bug
|
||||
// in Symbian's C++ compiler that prevents it from picking the right
|
||||
// overload between:
|
||||
//
|
||||
// PrintTo(const T& x, ...);
|
||||
// PrintTo(T* x, ...);
|
||||
DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
|
||||
}
|
||||
|
||||
// The following list of PrintTo() overloads tells
|
||||
// UniversalPrinter<T>::Print() how to print standard types (built-in
|
||||
// types, strings, plain arrays, and pointers).
|
||||
|
||||
// Overloads for various char types.
|
||||
GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os);
|
||||
GTEST_API_ void PrintTo(signed char c, ::std::ostream* os);
|
||||
inline void PrintTo(char c, ::std::ostream* os) {
|
||||
// When printing a plain char, we always treat it as unsigned. This
|
||||
// way, the output won't be affected by whether the compiler thinks
|
||||
// char is signed or not.
|
||||
PrintTo(static_cast<unsigned char>(c), os);
|
||||
}
|
||||
|
||||
// Overloads for other simple built-in types.
|
||||
inline void PrintTo(bool x, ::std::ostream* os) {
|
||||
*os << (x ? "true" : "false");
|
||||
}
|
||||
|
||||
// Overload for wchar_t type.
|
||||
// Prints a wchar_t as a symbol if it is printable or as its internal
|
||||
// code otherwise and also as its decimal code (except for L'\0').
|
||||
// The L'\0' char is printed as "L'\\0'". The decimal code is printed
|
||||
// as signed integer when wchar_t is implemented by the compiler
|
||||
// as a signed type and is printed as an unsigned integer when wchar_t
|
||||
// is implemented as an unsigned type.
|
||||
GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);
|
||||
|
||||
// Overloads for C strings.
|
||||
GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
|
||||
inline void PrintTo(char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const char*>(s), os);
|
||||
}
|
||||
|
||||
// signed/unsigned char is often used for representing binary data, so
|
||||
// we print pointers to it as void* to be safe.
|
||||
inline void PrintTo(const signed char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
inline void PrintTo(signed char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
inline void PrintTo(const unsigned char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
inline void PrintTo(unsigned char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
|
||||
// MSVC can be configured to define wchar_t as a typedef of unsigned
|
||||
// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
|
||||
// type. When wchar_t is a typedef, defining an overload for const
|
||||
// wchar_t* would cause unsigned short* be printed as a wide string,
|
||||
// possibly causing invalid memory accesses.
|
||||
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
// Overloads for wide C strings
|
||||
GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os);
|
||||
inline void PrintTo(wchar_t* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const wchar_t*>(s), os);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Overload for C arrays. Multi-dimensional arrays are printed
|
||||
// properly.
|
||||
|
||||
// Prints the given number of elements in an array, without printing
|
||||
// the curly braces.
|
||||
template <typename T>
|
||||
void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
|
||||
UniversalPrint(a[0], os);
|
||||
for (size_t i = 1; i != count; i++) {
|
||||
*os << ", ";
|
||||
UniversalPrint(a[i], os);
|
||||
}
|
||||
}
|
||||
|
||||
// Overloads for ::string and ::std::string.
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::string& s, ::std::ostream* os) {
|
||||
PrintStringTo(s, os);
|
||||
}
|
||||
#endif // GTEST_HAS_GLOBAL_STRING
|
||||
|
||||
GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
|
||||
PrintStringTo(s, os);
|
||||
}
|
||||
|
||||
// Overloads for ::wstring and ::std::wstring.
|
||||
#if GTEST_HAS_GLOBAL_WSTRING
|
||||
GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::wstring& s, ::std::ostream* os) {
|
||||
PrintWideStringTo(s, os);
|
||||
}
|
||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
|
||||
PrintWideStringTo(s, os);
|
||||
}
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
||||
#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
|
||||
// Helper function for printing a tuple. T must be instantiated with
|
||||
// a tuple type.
|
||||
template <typename T>
|
||||
void PrintTupleTo(const T& t, ::std::ostream* os);
|
||||
#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
|
||||
|
||||
#if GTEST_HAS_TR1_TUPLE
|
||||
// Overload for ::std::tr1::tuple. Needed for printing function arguments,
|
||||
// which are packed as tuples.
|
||||
|
||||
// Overloaded PrintTo() for tuples of various arities. We support
|
||||
// tuples of up-to 10 fields. The following implementation works
|
||||
// regardless of whether tr1::tuple is implemented using the
|
||||
// non-standard variadic template feature or not.
|
||||
|
||||
inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1>
|
||||
void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8, typename T9>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8, typename T9, typename T10>
|
||||
void PrintTo(
|
||||
const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
#endif // GTEST_HAS_TR1_TUPLE
|
||||
|
||||
#if GTEST_HAS_STD_TUPLE_
|
||||
template <typename... Types>
|
||||
void PrintTo(const ::std::tuple<Types...>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
#endif // GTEST_HAS_STD_TUPLE_
|
||||
|
||||
// Overload for std::pair.
|
||||
template <typename T1, typename T2>
|
||||
void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
|
||||
*os << '(';
|
||||
// We cannot use UniversalPrint(value.first, os) here, as T1 may be
|
||||
// a reference type. The same for printing value.second.
|
||||
UniversalPrinter<T1>::Print(value.first, os);
|
||||
*os << ", ";
|
||||
UniversalPrinter<T2>::Print(value.second, os);
|
||||
*os << ')';
|
||||
}
|
||||
|
||||
// Implements printing a non-reference type T by letting the compiler
|
||||
// pick the right overload of PrintTo() for T.
|
||||
template <typename T>
|
||||
class UniversalPrinter {
|
||||
public:
|
||||
// MSVC warns about adding const to a function type, so we want to
|
||||
// disable the warning.
|
||||
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
|
||||
|
||||
// Note: we deliberately don't call this PrintTo(), as that name
|
||||
// conflicts with ::testing::internal::PrintTo in the body of the
|
||||
// function.
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
// By default, ::testing::internal::PrintTo() is used for printing
|
||||
// the value.
|
||||
//
|
||||
// Thanks to Koenig look-up, if T is a class and has its own
|
||||
// PrintTo() function defined in its namespace, that function will
|
||||
// be visible here. Since it is more specific than the generic ones
|
||||
// in ::testing::internal, it will be picked by the compiler in the
|
||||
// following statement - exactly what we want.
|
||||
PrintTo(value, os);
|
||||
}
|
||||
|
||||
GTEST_DISABLE_MSC_WARNINGS_POP_()
|
||||
};
|
||||
|
||||
// UniversalPrintArray(begin, len, os) prints an array of 'len'
|
||||
// elements, starting at address 'begin'.
|
||||
template <typename T>
|
||||
void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
|
||||
if (len == 0) {
|
||||
*os << "{}";
|
||||
} else {
|
||||
*os << "{ ";
|
||||
const size_t kThreshold = 18;
|
||||
const size_t kChunkSize = 8;
|
||||
// If the array has more than kThreshold elements, we'll have to
|
||||
// omit some details by printing only the first and the last
|
||||
// kChunkSize elements.
|
||||
// TODO(wan@google.com): let the user control the threshold using a flag.
|
||||
if (len <= kThreshold) {
|
||||
PrintRawArrayTo(begin, len, os);
|
||||
} else {
|
||||
PrintRawArrayTo(begin, kChunkSize, os);
|
||||
*os << ", ..., ";
|
||||
PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
|
||||
}
|
||||
*os << " }";
|
||||
}
|
||||
}
|
||||
// This overload prints a (const) char array compactly.
|
||||
GTEST_API_ void UniversalPrintArray(
|
||||
const char* begin, size_t len, ::std::ostream* os);
|
||||
|
||||
// This overload prints a (const) wchar_t array compactly.
|
||||
GTEST_API_ void UniversalPrintArray(
|
||||
const wchar_t* begin, size_t len, ::std::ostream* os);
|
||||
|
||||
// Implements printing an array type T[N].
|
||||
template <typename T, size_t N>
|
||||
class UniversalPrinter<T[N]> {
|
||||
public:
|
||||
// Prints the given array, omitting some elements when there are too
|
||||
// many.
|
||||
static void Print(const T (&a)[N], ::std::ostream* os) {
|
||||
UniversalPrintArray(a, N, os);
|
||||
}
|
||||
};
|
||||
|
||||
// Implements printing a reference type T&.
|
||||
template <typename T>
|
||||
class UniversalPrinter<T&> {
|
||||
public:
|
||||
// MSVC warns about adding const to a function type, so we want to
|
||||
// disable the warning.
|
||||
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
|
||||
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
// Prints the address of the value. We use reinterpret_cast here
|
||||
// as static_cast doesn't compile when T is a function type.
|
||||
*os << "@" << reinterpret_cast<const void*>(&value) << " ";
|
||||
|
||||
// Then prints the value itself.
|
||||
UniversalPrint(value, os);
|
||||
}
|
||||
|
||||
GTEST_DISABLE_MSC_WARNINGS_POP_()
|
||||
};
|
||||
|
||||
// Prints a value tersely: for a reference type, the referenced value
|
||||
// (but not the address) is printed; for a (const) char pointer, the
|
||||
// NUL-terminated string (but not the pointer) is printed.
|
||||
|
||||
template <typename T>
|
||||
class UniversalTersePrinter {
|
||||
public:
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
UniversalPrint(value, os);
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
class UniversalTersePrinter<T&> {
|
||||
public:
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
UniversalPrint(value, os);
|
||||
}
|
||||
};
|
||||
template <typename T, size_t N>
|
||||
class UniversalTersePrinter<T[N]> {
|
||||
public:
|
||||
static void Print(const T (&value)[N], ::std::ostream* os) {
|
||||
UniversalPrinter<T[N]>::Print(value, os);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class UniversalTersePrinter<const char*> {
|
||||
public:
|
||||
static void Print(const char* str, ::std::ostream* os) {
|
||||
if (str == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
UniversalPrint(string(str), os);
|
||||
}
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class UniversalTersePrinter<char*> {
|
||||
public:
|
||||
static void Print(char* str, ::std::ostream* os) {
|
||||
UniversalTersePrinter<const char*>::Print(str, os);
|
||||
}
|
||||
};
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
template <>
|
||||
class UniversalTersePrinter<const wchar_t*> {
|
||||
public:
|
||||
static void Print(const wchar_t* str, ::std::ostream* os) {
|
||||
if (str == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
UniversalPrint(::std::wstring(str), os);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <>
|
||||
class UniversalTersePrinter<wchar_t*> {
|
||||
public:
|
||||
static void Print(wchar_t* str, ::std::ostream* os) {
|
||||
UniversalTersePrinter<const wchar_t*>::Print(str, os);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void UniversalTersePrint(const T& value, ::std::ostream* os) {
|
||||
UniversalTersePrinter<T>::Print(value, os);
|
||||
}
|
||||
|
||||
// Prints a value using the type inferred by the compiler. The
|
||||
// difference between this and UniversalTersePrint() is that for a
|
||||
// (const) char pointer, this prints both the pointer and the
|
||||
// NUL-terminated string.
|
||||
template <typename T>
|
||||
void UniversalPrint(const T& value, ::std::ostream* os) {
|
||||
// A workarond for the bug in VC++ 7.1 that prevents us from instantiating
|
||||
// UniversalPrinter with T directly.
|
||||
typedef T T1;
|
||||
UniversalPrinter<T1>::Print(value, os);
|
||||
}
|
||||
|
||||
typedef ::std::vector<string> Strings;
|
||||
|
||||
// TuplePolicy<TupleT> must provide:
|
||||
// - tuple_size
|
||||
// size of tuple TupleT.
|
||||
// - get<size_t I>(const TupleT& t)
|
||||
// static function extracting element I of tuple TupleT.
|
||||
// - tuple_element<size_t I>::type
|
||||
// type of element I of tuple TupleT.
|
||||
template <typename TupleT>
|
||||
struct TuplePolicy;
|
||||
|
||||
#if GTEST_HAS_TR1_TUPLE
|
||||
template <typename TupleT>
|
||||
struct TuplePolicy {
|
||||
typedef TupleT Tuple;
|
||||
static const size_t tuple_size = ::std::tr1::tuple_size<Tuple>::value;
|
||||
|
||||
template <size_t I>
|
||||
struct tuple_element : ::std::tr1::tuple_element<I, Tuple> {};
|
||||
|
||||
template <size_t I>
|
||||
static typename AddReference<
|
||||
const typename ::std::tr1::tuple_element<I, Tuple>::type>::type get(
|
||||
const Tuple& tuple) {
|
||||
return ::std::tr1::get<I>(tuple);
|
||||
}
|
||||
};
|
||||
template <typename TupleT>
|
||||
const size_t TuplePolicy<TupleT>::tuple_size;
|
||||
#endif // GTEST_HAS_TR1_TUPLE
|
||||
|
||||
#if GTEST_HAS_STD_TUPLE_
|
||||
template <typename... Types>
|
||||
struct TuplePolicy< ::std::tuple<Types...> > {
|
||||
typedef ::std::tuple<Types...> Tuple;
|
||||
static const size_t tuple_size = ::std::tuple_size<Tuple>::value;
|
||||
|
||||
template <size_t I>
|
||||
struct tuple_element : ::std::tuple_element<I, Tuple> {};
|
||||
|
||||
template <size_t I>
|
||||
static const typename ::std::tuple_element<I, Tuple>::type& get(
|
||||
const Tuple& tuple) {
|
||||
return ::std::get<I>(tuple);
|
||||
}
|
||||
};
|
||||
template <typename... Types>
|
||||
const size_t TuplePolicy< ::std::tuple<Types...> >::tuple_size;
|
||||
#endif // GTEST_HAS_STD_TUPLE_
|
||||
|
||||
#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
|
||||
// This helper template allows PrintTo() for tuples and
|
||||
// UniversalTersePrintTupleFieldsToStrings() to be defined by
|
||||
// induction on the number of tuple fields. The idea is that
|
||||
// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
|
||||
// fields in tuple t, and can be defined in terms of
|
||||
// TuplePrefixPrinter<N - 1>.
|
||||
//
|
||||
// The inductive case.
|
||||
template <size_t N>
|
||||
struct TuplePrefixPrinter {
|
||||
// Prints the first N fields of a tuple.
|
||||
template <typename Tuple>
|
||||
static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
|
||||
TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
|
||||
GTEST_INTENTIONAL_CONST_COND_PUSH_()
|
||||
if (N > 1) {
|
||||
GTEST_INTENTIONAL_CONST_COND_POP_()
|
||||
*os << ", ";
|
||||
}
|
||||
UniversalPrinter<
|
||||
typename TuplePolicy<Tuple>::template tuple_element<N - 1>::type>
|
||||
::Print(TuplePolicy<Tuple>::template get<N - 1>(t), os);
|
||||
}
|
||||
|
||||
// Tersely prints the first N fields of a tuple to a string vector,
|
||||
// one element for each field.
|
||||
template <typename Tuple>
|
||||
static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
|
||||
TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
|
||||
::std::stringstream ss;
|
||||
UniversalTersePrint(TuplePolicy<Tuple>::template get<N - 1>(t), &ss);
|
||||
strings->push_back(ss.str());
|
||||
}
|
||||
};
|
||||
|
||||
// Base case.
|
||||
template <>
|
||||
struct TuplePrefixPrinter<0> {
|
||||
template <typename Tuple>
|
||||
static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}
|
||||
|
||||
template <typename Tuple>
|
||||
static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
|
||||
};
|
||||
|
||||
// Helper function for printing a tuple.
|
||||
// Tuple must be either std::tr1::tuple or std::tuple type.
|
||||
template <typename Tuple>
|
||||
void PrintTupleTo(const Tuple& t, ::std::ostream* os) {
|
||||
*os << "(";
|
||||
TuplePrefixPrinter<TuplePolicy<Tuple>::tuple_size>::PrintPrefixTo(t, os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
// Prints the fields of a tuple tersely to a string vector, one
|
||||
// element for each field. See the comment before
|
||||
// UniversalTersePrint() for how we define "tersely".
|
||||
template <typename Tuple>
|
||||
Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
|
||||
Strings result;
|
||||
TuplePrefixPrinter<TuplePolicy<Tuple>::tuple_size>::
|
||||
TersePrintPrefixToStrings(value, &result);
|
||||
return result;
|
||||
}
|
||||
#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
::std::string PrintToString(const T& value) {
|
||||
::std::stringstream ss;
|
||||
internal::UniversalTersePrinter<T>::Print(value, &ss);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
// Include any custom printer added by the local installation.
|
||||
// We must include this header at the end to make sure it can use the
|
||||
// declarations from this file.
|
||||
#include "gtest/internal/custom/gtest-printers.h"
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
|
@ -1,232 +0,0 @@
|
|||
// Copyright 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// Utilities for testing Google Test itself and code that uses Google Test
|
||||
// (e.g. frameworks built on top of Google Test).
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// This helper class can be used to mock out Google Test failure reporting
|
||||
// so that we can test Google Test or code that builds on Google Test.
|
||||
//
|
||||
// An object of this class appends a TestPartResult object to the
|
||||
// TestPartResultArray object given in the constructor whenever a Google Test
|
||||
// failure is reported. It can either intercept only failures that are
|
||||
// generated in the same thread that created this object or it can intercept
|
||||
// all generated failures. The scope of this mock object can be controlled with
|
||||
// the second argument to the two arguments constructor.
|
||||
class GTEST_API_ ScopedFakeTestPartResultReporter
|
||||
: public TestPartResultReporterInterface {
|
||||
public:
|
||||
// The two possible mocking modes of this object.
|
||||
enum InterceptMode {
|
||||
INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures.
|
||||
INTERCEPT_ALL_THREADS // Intercepts all failures.
|
||||
};
|
||||
|
||||
// The c'tor sets this object as the test part result reporter used
|
||||
// by Google Test. The 'result' parameter specifies where to report the
|
||||
// results. This reporter will only catch failures generated in the current
|
||||
// thread. DEPRECATED
|
||||
explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
|
||||
|
||||
// Same as above, but you can choose the interception scope of this object.
|
||||
ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
|
||||
TestPartResultArray* result);
|
||||
|
||||
// The d'tor restores the previous test part result reporter.
|
||||
virtual ~ScopedFakeTestPartResultReporter();
|
||||
|
||||
// Appends the TestPartResult object to the TestPartResultArray
|
||||
// received in the constructor.
|
||||
//
|
||||
// This method is from the TestPartResultReporterInterface
|
||||
// interface.
|
||||
virtual void ReportTestPartResult(const TestPartResult& result);
|
||||
private:
|
||||
void Init();
|
||||
|
||||
const InterceptMode intercept_mode_;
|
||||
TestPartResultReporterInterface* old_reporter_;
|
||||
TestPartResultArray* const result_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// A helper class for implementing EXPECT_FATAL_FAILURE() and
|
||||
// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
|
||||
// TestPartResultArray contains exactly one failure that has the given
|
||||
// type and contains the given substring. If that's not the case, a
|
||||
// non-fatal failure will be generated.
|
||||
class GTEST_API_ SingleFailureChecker {
|
||||
public:
|
||||
// The constructor remembers the arguments.
|
||||
SingleFailureChecker(const TestPartResultArray* results,
|
||||
TestPartResult::Type type,
|
||||
const string& substr);
|
||||
~SingleFailureChecker();
|
||||
private:
|
||||
const TestPartResultArray* const results_;
|
||||
const TestPartResult::Type type_;
|
||||
const string substr_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace testing
|
||||
|
||||
// A set of macros for testing Google Test assertions or code that's expected
|
||||
// to generate Google Test fatal failures. It verifies that the given
|
||||
// statement will cause exactly one fatal Google Test failure with 'substr'
|
||||
// being part of the failure message.
|
||||
//
|
||||
// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
|
||||
// affects and considers failures generated in the current thread and
|
||||
// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
|
||||
//
|
||||
// The verification of the assertion is done correctly even when the statement
|
||||
// throws an exception or aborts the current function.
|
||||
//
|
||||
// Known restrictions:
|
||||
// - 'statement' cannot reference local non-static variables or
|
||||
// non-static members of the current object.
|
||||
// - 'statement' cannot return a value.
|
||||
// - You cannot stream a failure message to this macro.
|
||||
//
|
||||
// Note that even though the implementations of the following two
|
||||
// macros are much alike, we cannot refactor them to use a common
|
||||
// helper macro, due to some peculiarity in how the preprocessor
|
||||
// works. The AcceptsMacroThatExpandsToUnprotectedComma test in
|
||||
// gtest_unittest.cc will fail to compile if we do that.
|
||||
#define EXPECT_FATAL_FAILURE(statement, substr) \
|
||||
do { \
|
||||
class GTestExpectFatalFailureHelper {\
|
||||
public:\
|
||||
static void Execute() { statement; }\
|
||||
};\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter:: \
|
||||
INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
|
||||
GTestExpectFatalFailureHelper::Execute();\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
|
||||
do { \
|
||||
class GTestExpectFatalFailureHelper {\
|
||||
public:\
|
||||
static void Execute() { statement; }\
|
||||
};\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter:: \
|
||||
INTERCEPT_ALL_THREADS, >est_failures);\
|
||||
GTestExpectFatalFailureHelper::Execute();\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
// A macro for testing Google Test assertions or code that's expected to
|
||||
// generate Google Test non-fatal failures. It asserts that the given
|
||||
// statement will cause exactly one non-fatal Google Test failure with 'substr'
|
||||
// being part of the failure message.
|
||||
//
|
||||
// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
|
||||
// affects and considers failures generated in the current thread and
|
||||
// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
|
||||
//
|
||||
// 'statement' is allowed to reference local variables and members of
|
||||
// the current object.
|
||||
//
|
||||
// The verification of the assertion is done correctly even when the statement
|
||||
// throws an exception or aborts the current function.
|
||||
//
|
||||
// Known restrictions:
|
||||
// - You cannot stream a failure message to this macro.
|
||||
//
|
||||
// Note that even though the implementations of the following two
|
||||
// macros are much alike, we cannot refactor them to use a common
|
||||
// helper macro, due to some peculiarity in how the preprocessor
|
||||
// works. If we do that, the code won't compile when the user gives
|
||||
// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
|
||||
// expands to code containing an unprotected comma. The
|
||||
// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
|
||||
// catches that.
|
||||
//
|
||||
// For the same reason, we have to write
|
||||
// if (::testing::internal::AlwaysTrue()) { statement; }
|
||||
// instead of
|
||||
// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
|
||||
// to avoid an MSVC warning on unreachable code.
|
||||
#define EXPECT_NONFATAL_FAILURE(statement, substr) \
|
||||
do {\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kNonFatalFailure, \
|
||||
(substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter:: \
|
||||
INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
|
||||
if (::testing::internal::AlwaysTrue()) { statement; }\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
|
||||
do {\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kNonFatalFailure, \
|
||||
(substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
|
||||
>est_failures);\
|
||||
if (::testing::internal::AlwaysTrue()) { statement; }\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
|
@ -1,179 +0,0 @@
|
|||
// Copyright 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: mheule@google.com (Markus Heule)
|
||||
//
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// A copyable object representing the result of a test part (i.e. an
|
||||
// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
|
||||
//
|
||||
// Don't inherit from TestPartResult as its destructor is not virtual.
|
||||
class GTEST_API_ TestPartResult {
|
||||
public:
|
||||
// The possible outcomes of a test part (i.e. an assertion or an
|
||||
// explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
|
||||
enum Type {
|
||||
kSuccess, // Succeeded.
|
||||
kNonFatalFailure, // Failed but the test can continue.
|
||||
kFatalFailure // Failed and the test should be terminated.
|
||||
};
|
||||
|
||||
// C'tor. TestPartResult does NOT have a default constructor.
|
||||
// Always use this constructor (with parameters) to create a
|
||||
// TestPartResult object.
|
||||
TestPartResult(Type a_type,
|
||||
const char* a_file_name,
|
||||
int a_line_number,
|
||||
const char* a_message)
|
||||
: type_(a_type),
|
||||
file_name_(a_file_name == NULL ? "" : a_file_name),
|
||||
line_number_(a_line_number),
|
||||
summary_(ExtractSummary(a_message)),
|
||||
message_(a_message) {
|
||||
}
|
||||
|
||||
// Gets the outcome of the test part.
|
||||
Type type() const { return type_; }
|
||||
|
||||
// Gets the name of the source file where the test part took place, or
|
||||
// NULL if it's unknown.
|
||||
const char* file_name() const {
|
||||
return file_name_.empty() ? NULL : file_name_.c_str();
|
||||
}
|
||||
|
||||
// Gets the line in the source file where the test part took place,
|
||||
// or -1 if it's unknown.
|
||||
int line_number() const { return line_number_; }
|
||||
|
||||
// Gets the summary of the failure message.
|
||||
const char* summary() const { return summary_.c_str(); }
|
||||
|
||||
// Gets the message associated with the test part.
|
||||
const char* message() const { return message_.c_str(); }
|
||||
|
||||
// Returns true iff the test part passed.
|
||||
bool passed() const { return type_ == kSuccess; }
|
||||
|
||||
// Returns true iff the test part failed.
|
||||
bool failed() const { return type_ != kSuccess; }
|
||||
|
||||
// Returns true iff the test part non-fatally failed.
|
||||
bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
|
||||
|
||||
// Returns true iff the test part fatally failed.
|
||||
bool fatally_failed() const { return type_ == kFatalFailure; }
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
|
||||
// Gets the summary of the failure message by omitting the stack
|
||||
// trace in it.
|
||||
static std::string ExtractSummary(const char* message);
|
||||
|
||||
// The name of the source file where the test part took place, or
|
||||
// "" if the source file is unknown.
|
||||
std::string file_name_;
|
||||
// The line in the source file where the test part took place, or -1
|
||||
// if the line number is unknown.
|
||||
int line_number_;
|
||||
std::string summary_; // The test failure summary.
|
||||
std::string message_; // The test failure message.
|
||||
};
|
||||
|
||||
// Prints a TestPartResult object.
|
||||
std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
|
||||
|
||||
// An array of TestPartResult objects.
|
||||
//
|
||||
// Don't inherit from TestPartResultArray as its destructor is not
|
||||
// virtual.
|
||||
class GTEST_API_ TestPartResultArray {
|
||||
public:
|
||||
TestPartResultArray() {}
|
||||
|
||||
// Appends the given TestPartResult to the array.
|
||||
void Append(const TestPartResult& result);
|
||||
|
||||
// Returns the TestPartResult at the given index (0-based).
|
||||
const TestPartResult& GetTestPartResult(int index) const;
|
||||
|
||||
// Returns the number of TestPartResult objects in the array.
|
||||
int size() const;
|
||||
|
||||
private:
|
||||
std::vector<TestPartResult> array_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
|
||||
};
|
||||
|
||||
// This interface knows how to report a test part result.
|
||||
class TestPartResultReporterInterface {
|
||||
public:
|
||||
virtual ~TestPartResultReporterInterface() {}
|
||||
|
||||
virtual void ReportTestPartResult(const TestPartResult& result) = 0;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
|
||||
// statement generates new fatal failures. To do so it registers itself as the
|
||||
// current test part result reporter. Besides checking if fatal failures were
|
||||
// reported, it only delegates the reporting to the former result reporter.
|
||||
// The original result reporter is restored in the destructor.
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
class GTEST_API_ HasNewFatalFailureHelper
|
||||
: public TestPartResultReporterInterface {
|
||||
public:
|
||||
HasNewFatalFailureHelper();
|
||||
virtual ~HasNewFatalFailureHelper();
|
||||
virtual void ReportTestPartResult(const TestPartResult& result);
|
||||
bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
|
||||
private:
|
||||
bool has_new_fatal_failure_;
|
||||
TestPartResultReporterInterface* original_reporter_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
|
@ -1,263 +0,0 @@
|
|||
// Copyright 2008 Google Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
||||
|
||||
// This header implements typed tests and type-parameterized tests.
|
||||
|
||||
// Typed (aka type-driven) tests repeat the same test for types in a
|
||||
// list. You must know which types you want to test with when writing
|
||||
// typed tests. Here's how you do it:
|
||||
|
||||
#if 0
|
||||
|
||||
// First, define a fixture class template. It should be parameterized
|
||||
// by a type. Remember to derive it from testing::Test.
|
||||
template <typename T>
|
||||
class FooTest : public testing::Test {
|
||||
public:
|
||||
...
|
||||
typedef std::list<T> List;
|
||||
static T shared_;
|
||||
T value_;
|
||||
};
|
||||
|
||||
// Next, associate a list of types with the test case, which will be
|
||||
// repeated for each type in the list. The typedef is necessary for
|
||||
// the macro to parse correctly.
|
||||
typedef testing::Types<char, int, unsigned int> MyTypes;
|
||||
TYPED_TEST_CASE(FooTest, MyTypes);
|
||||
|
||||
// If the type list contains only one type, you can write that type
|
||||
// directly without Types<...>:
|
||||
// TYPED_TEST_CASE(FooTest, int);
|
||||
|
||||
// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
|
||||
// tests for this test case as you want.
|
||||
TYPED_TEST(FooTest, DoesBlah) {
|
||||
// Inside a test, refer to TypeParam to get the type parameter.
|
||||
// Since we are inside a derived class template, C++ requires use to
|
||||
// visit the members of FooTest via 'this'.
|
||||
TypeParam n = this->value_;
|
||||
|
||||
// To visit static members of the fixture, add the TestFixture::
|
||||
// prefix.
|
||||
n += TestFixture::shared_;
|
||||
|
||||
// To refer to typedefs in the fixture, add the "typename
|
||||
// TestFixture::" prefix.
|
||||
typename TestFixture::List values;
|
||||
values.push_back(n);
|
||||
...
|
||||
}
|
||||
|
||||
TYPED_TEST(FooTest, HasPropertyA) { ... }
|
||||
|
||||
#endif // 0
|
||||
|
||||
// Type-parameterized tests are abstract test patterns parameterized
|
||||
// by a type. Compared with typed tests, type-parameterized tests
|
||||
// allow you to define the test pattern without knowing what the type
|
||||
// parameters are. The defined pattern can be instantiated with
|
||||
// different types any number of times, in any number of translation
|
||||
// units.
|
||||
//
|
||||
// If you are designing an interface or concept, you can define a
|
||||
// suite of type-parameterized tests to verify properties that any
|
||||
// valid implementation of the interface/concept should have. Then,
|
||||
// each implementation can easily instantiate the test suite to verify
|
||||
// that it conforms to the requirements, without having to write
|
||||
// similar tests repeatedly. Here's an example:
|
||||
|
||||
#if 0
|
||||
|
||||
// First, define a fixture class template. It should be parameterized
|
||||
// by a type. Remember to derive it from testing::Test.
|
||||
template <typename T>
|
||||
class FooTest : public testing::Test {
|
||||
...
|
||||
};
|
||||
|
||||
// Next, declare that you will define a type-parameterized test case
|
||||
// (the _P suffix is for "parameterized" or "pattern", whichever you
|
||||
// prefer):
|
||||
TYPED_TEST_CASE_P(FooTest);
|
||||
|
||||
// Then, use TYPED_TEST_P() to define as many type-parameterized tests
|
||||
// for this type-parameterized test case as you want.
|
||||
TYPED_TEST_P(FooTest, DoesBlah) {
|
||||
// Inside a test, refer to TypeParam to get the type parameter.
|
||||
TypeParam n = 0;
|
||||
...
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FooTest, HasPropertyA) { ... }
|
||||
|
||||
// Now the tricky part: you need to register all test patterns before
|
||||
// you can instantiate them. The first argument of the macro is the
|
||||
// test case name; the rest are the names of the tests in this test
|
||||
// case.
|
||||
REGISTER_TYPED_TEST_CASE_P(FooTest,
|
||||
DoesBlah, HasPropertyA);
|
||||
|
||||
// Finally, you are free to instantiate the pattern with the types you
|
||||
// want. If you put the above code in a header file, you can #include
|
||||
// it in multiple C++ source files and instantiate it multiple times.
|
||||
//
|
||||
// To distinguish different instances of the pattern, the first
|
||||
// argument to the INSTANTIATE_* macro is a prefix that will be added
|
||||
// to the actual test case name. Remember to pick unique prefixes for
|
||||
// different instances.
|
||||
typedef testing::Types<char, int, unsigned int> MyTypes;
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
|
||||
|
||||
// If the type list contains only one type, you can write that type
|
||||
// directly without Types<...>:
|
||||
// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
|
||||
|
||||
#endif // 0
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/internal/gtest-type-util.h"
|
||||
|
||||
// Implements typed tests.
|
||||
|
||||
#if GTEST_HAS_TYPED_TEST
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Expands to the name of the typedef for the type parameters of the
|
||||
// given test case.
|
||||
# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
|
||||
|
||||
// The 'Types' template argument below must have spaces around it
|
||||
// since some compilers may choke on '>>' when passing a template
|
||||
// instance (e.g. Types<int>)
|
||||
# define TYPED_TEST_CASE(CaseName, Types) \
|
||||
typedef ::testing::internal::TypeList< Types >::type \
|
||||
GTEST_TYPE_PARAMS_(CaseName)
|
||||
|
||||
# define TYPED_TEST(CaseName, TestName) \
|
||||
template <typename gtest_TypeParam_> \
|
||||
class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
|
||||
: public CaseName<gtest_TypeParam_> { \
|
||||
private: \
|
||||
typedef CaseName<gtest_TypeParam_> TestFixture; \
|
||||
typedef gtest_TypeParam_ TypeParam; \
|
||||
virtual void TestBody(); \
|
||||
}; \
|
||||
bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \
|
||||
::testing::internal::TypeParameterizedTest< \
|
||||
CaseName, \
|
||||
::testing::internal::TemplateSel< \
|
||||
GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
|
||||
GTEST_TYPE_PARAMS_(CaseName)>::Register(\
|
||||
"", ::testing::internal::CodeLocation(__FILE__, __LINE__), \
|
||||
#CaseName, #TestName, 0); \
|
||||
template <typename gtest_TypeParam_> \
|
||||
void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
|
||||
|
||||
#endif // GTEST_HAS_TYPED_TEST
|
||||
|
||||
// Implements type-parameterized tests.
|
||||
|
||||
#if GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Expands to the namespace name that the type-parameterized tests for
|
||||
// the given type-parameterized test case are defined in. The exact
|
||||
// name of the namespace is subject to change without notice.
|
||||
# define GTEST_CASE_NAMESPACE_(TestCaseName) \
|
||||
gtest_case_##TestCaseName##_
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Expands to the name of the variable used to remember the names of
|
||||
// the defined tests in the given test case.
|
||||
# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
|
||||
gtest_typed_test_case_p_state_##TestCaseName##_
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
|
||||
//
|
||||
// Expands to the name of the variable used to remember the names of
|
||||
// the registered tests in the given test case.
|
||||
# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
|
||||
gtest_registered_test_names_##TestCaseName##_
|
||||
|
||||
// The variables defined in the type-parameterized test macros are
|
||||
// static as typically these macros are used in a .h file that can be
|
||||
// #included in multiple translation units linked together.
|
||||
# define TYPED_TEST_CASE_P(CaseName) \
|
||||
static ::testing::internal::TypedTestCasePState \
|
||||
GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
|
||||
|
||||
# define TYPED_TEST_P(CaseName, TestName) \
|
||||
namespace GTEST_CASE_NAMESPACE_(CaseName) { \
|
||||
template <typename gtest_TypeParam_> \
|
||||
class TestName : public CaseName<gtest_TypeParam_> { \
|
||||
private: \
|
||||
typedef CaseName<gtest_TypeParam_> TestFixture; \
|
||||
typedef gtest_TypeParam_ TypeParam; \
|
||||
virtual void TestBody(); \
|
||||
}; \
|
||||
static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
|
||||
GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
|
||||
__FILE__, __LINE__, #CaseName, #TestName); \
|
||||
} \
|
||||
template <typename gtest_TypeParam_> \
|
||||
void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
|
||||
|
||||
# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
|
||||
namespace GTEST_CASE_NAMESPACE_(CaseName) { \
|
||||
typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
|
||||
} \
|
||||
static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
|
||||
GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
|
||||
__FILE__, __LINE__, #__VA_ARGS__)
|
||||
|
||||
// The 'Types' template argument below must have spaces around it
|
||||
// since some compilers may choke on '>>' when passing a template
|
||||
// instance (e.g. Types<int>)
|
||||
# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
|
||||
bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
|
||||
::testing::internal::TypeParameterizedTestCase<CaseName, \
|
||||
GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
|
||||
::testing::internal::TypeList< Types >::type>::Register(\
|
||||
#Prefix, \
|
||||
::testing::internal::CodeLocation(__FILE__, __LINE__), \
|
||||
>EST_TYPED_TEST_CASE_P_STATE_(CaseName), \
|
||||
#CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
|
||||
|
||||
#endif // GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -1,358 +0,0 @@
|
|||
// Copyright 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command
|
||||
// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
|
||||
//
|
||||
// Implements a family of generic predicate assertion macros.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
||||
|
||||
// Makes sure this header is not included before gtest.h.
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
|
||||
# error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_H_
|
||||
|
||||
// This header implements a family of generic predicate assertion
|
||||
// macros:
|
||||
//
|
||||
// ASSERT_PRED_FORMAT1(pred_format, v1)
|
||||
// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
|
||||
// ...
|
||||
//
|
||||
// where pred_format is a function or functor that takes n (in the
|
||||
// case of ASSERT_PRED_FORMATn) values and their source expression
|
||||
// text, and returns a testing::AssertionResult. See the definition
|
||||
// of ASSERT_EQ in gtest.h for an example.
|
||||
//
|
||||
// If you don't care about formatting, you can use the more
|
||||
// restrictive version:
|
||||
//
|
||||
// ASSERT_PRED1(pred, v1)
|
||||
// ASSERT_PRED2(pred, v1, v2)
|
||||
// ...
|
||||
//
|
||||
// where pred is an n-ary function or functor that returns bool,
|
||||
// and the values v1, v2, ..., must support the << operator for
|
||||
// streaming to std::ostream.
|
||||
//
|
||||
// We also define the EXPECT_* variations.
|
||||
//
|
||||
// For now we only support predicates whose arity is at most 5.
|
||||
// Please email googletestframework@googlegroups.com if you need
|
||||
// support for higher arities.
|
||||
|
||||
// GTEST_ASSERT_ is the basic statement to which all of the assertions
|
||||
// in this file reduce. Don't use this in your code.
|
||||
|
||||
#define GTEST_ASSERT_(expression, on_failure) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (const ::testing::AssertionResult gtest_ar = (expression)) \
|
||||
; \
|
||||
else \
|
||||
on_failure(gtest_ar.failure_message())
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1>
|
||||
AssertionResult AssertPred1Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
Pred pred,
|
||||
const T1& v1) {
|
||||
if (pred(v1)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, v1), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED1_(pred, v1, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
|
||||
#v1, \
|
||||
pred, \
|
||||
v1), on_failure)
|
||||
|
||||
// Unary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT1(pred_format, v1) \
|
||||
GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED1(pred, v1) \
|
||||
GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT1(pred_format, v1) \
|
||||
GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED1(pred, v1) \
|
||||
GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2>
|
||||
AssertionResult AssertPred2Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2) {
|
||||
if (pred(v1, v2)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED2_(pred, v1, v2, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2), on_failure)
|
||||
|
||||
// Binary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
|
||||
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED2(pred, v1, v2) \
|
||||
GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
|
||||
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED2(pred, v1, v2) \
|
||||
GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2,
|
||||
typename T3>
|
||||
AssertionResult AssertPred3Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
const char* e3,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2,
|
||||
const T3& v3) {
|
||||
if (pred(v1, v2, v3)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ", "
|
||||
<< e3 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2
|
||||
<< "\n" << e3 << " evaluates to " << v3;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
#v3, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2, \
|
||||
v3), on_failure)
|
||||
|
||||
// Ternary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
|
||||
GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED3(pred, v1, v2, v3) \
|
||||
GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
|
||||
GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED3(pred, v1, v2, v3) \
|
||||
GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2,
|
||||
typename T3,
|
||||
typename T4>
|
||||
AssertionResult AssertPred4Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
const char* e3,
|
||||
const char* e4,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2,
|
||||
const T3& v3,
|
||||
const T4& v4) {
|
||||
if (pred(v1, v2, v3, v4)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ", "
|
||||
<< e3 << ", "
|
||||
<< e4 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2
|
||||
<< "\n" << e3 << " evaluates to " << v3
|
||||
<< "\n" << e4 << " evaluates to " << v4;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
#v3, \
|
||||
#v4, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2, \
|
||||
v3, \
|
||||
v4), on_failure)
|
||||
|
||||
// 4-ary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
|
||||
GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
|
||||
GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
|
||||
GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
|
||||
GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2,
|
||||
typename T3,
|
||||
typename T4,
|
||||
typename T5>
|
||||
AssertionResult AssertPred5Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
const char* e3,
|
||||
const char* e4,
|
||||
const char* e5,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2,
|
||||
const T3& v3,
|
||||
const T4& v4,
|
||||
const T5& v5) {
|
||||
if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ", "
|
||||
<< e3 << ", "
|
||||
<< e4 << ", "
|
||||
<< e5 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2
|
||||
<< "\n" << e3 << " evaluates to " << v3
|
||||
<< "\n" << e4 << " evaluates to " << v4
|
||||
<< "\n" << e5 << " evaluates to " << v5;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
#v3, \
|
||||
#v4, \
|
||||
#v5, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2, \
|
||||
v3, \
|
||||
v4, \
|
||||
v5), on_failure)
|
||||
|
||||
// 5-ary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// Google C++ Testing Framework definitions useful in production code.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
||||
|
||||
// When you need to test the private or protected members of a class,
|
||||
// use the FRIEND_TEST macro to declare your tests as friends of the
|
||||
// class. For example:
|
||||
//
|
||||
// class MyClass {
|
||||
// private:
|
||||
// void MyMethod();
|
||||
// FRIEND_TEST(MyClassTest, MyMethod);
|
||||
// };
|
||||
//
|
||||
// class MyClassTest : public testing::Test {
|
||||
// // ...
|
||||
// };
|
||||
//
|
||||
// TEST_F(MyClassTest, MyMethod) {
|
||||
// // Can call MyClass::MyMethod() here.
|
||||
// }
|
||||
|
||||
#define FRIEND_TEST(test_case_name, test_name)\
|
||||
friend class test_case_name##_##test_name##_Test
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
|
@ -1,69 +0,0 @@
|
|||
// Copyright 2015, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Injection point for custom user configurations.
|
||||
// The following macros can be defined:
|
||||
//
|
||||
// Flag related macros:
|
||||
// GTEST_FLAG(flag_name)
|
||||
// GTEST_USE_OWN_FLAGFILE_FLAG_ - Define to 0 when the system provides its
|
||||
// own flagfile flag parsing.
|
||||
// GTEST_DECLARE_bool_(name)
|
||||
// GTEST_DECLARE_int32_(name)
|
||||
// GTEST_DECLARE_string_(name)
|
||||
// GTEST_DEFINE_bool_(name, default_val, doc)
|
||||
// GTEST_DEFINE_int32_(name, default_val, doc)
|
||||
// GTEST_DEFINE_string_(name, default_val, doc)
|
||||
//
|
||||
// Test filtering:
|
||||
// GTEST_TEST_FILTER_ENV_VAR_ - The name of an environment variable that
|
||||
// will be used if --GTEST_FLAG(test_filter)
|
||||
// is not provided.
|
||||
//
|
||||
// Logging:
|
||||
// GTEST_LOG_(severity)
|
||||
// GTEST_CHECK_(condition)
|
||||
// Functions LogToStderr() and FlushInfoLog() have to be provided too.
|
||||
//
|
||||
// Threading:
|
||||
// GTEST_HAS_NOTIFICATION_ - Enabled if Notification is already provided.
|
||||
// GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ - Enabled if Mutex and ThreadLocal are
|
||||
// already provided.
|
||||
// Must also provide GTEST_DECLARE_STATIC_MUTEX_(mutex) and
|
||||
// GTEST_DEFINE_STATIC_MUTEX_(mutex)
|
||||
//
|
||||
// GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
|
||||
// GTEST_LOCK_EXCLUDED_(locks)
|
||||
//
|
||||
// ** Custom implementation starts here **
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright 2015, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This file provides an injection point for custom printers in a local
|
||||
// installation of gTest.
|
||||
// It will be included from gtest-printers.h and the overrides in this file
|
||||
// will be visible to everyone.
|
||||
// See documentation at gtest/gtest-printers.h for details on how to define a
|
||||
// custom printer.
|
||||
//
|
||||
// ** Custom implementation starts here **
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
|
|
@ -1,41 +0,0 @@
|
|||
// Copyright 2015, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Injection point for custom user configurations.
|
||||
// The following macros can be defined:
|
||||
//
|
||||
// GTEST_OS_STACK_TRACE_GETTER_ - The name of an implementation of
|
||||
// OsStackTraceGetterInterface.
|
||||
//
|
||||
// ** Custom implementation starts here **
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
|
|
@ -1,319 +0,0 @@
|
|||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file defines internal utilities needed for implementing
|
||||
// death tests. They are subject to change without notice.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
||||
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
GTEST_DECLARE_string_(internal_run_death_test);
|
||||
|
||||
// Names of the flags (needed for parsing Google Test flags).
|
||||
const char kDeathTestStyleFlag[] = "death_test_style";
|
||||
const char kDeathTestUseFork[] = "death_test_use_fork";
|
||||
const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
// DeathTest is a class that hides much of the complexity of the
|
||||
// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
|
||||
// returns a concrete class that depends on the prevailing death test
|
||||
// style, as defined by the --gtest_death_test_style and/or
|
||||
// --gtest_internal_run_death_test flags.
|
||||
|
||||
// In describing the results of death tests, these terms are used with
|
||||
// the corresponding definitions:
|
||||
//
|
||||
// exit status: The integer exit information in the format specified
|
||||
// by wait(2)
|
||||
// exit code: The integer code passed to exit(3), _exit(2), or
|
||||
// returned from main()
|
||||
class GTEST_API_ DeathTest {
|
||||
public:
|
||||
// Create returns false if there was an error determining the
|
||||
// appropriate action to take for the current death test; for example,
|
||||
// if the gtest_death_test_style flag is set to an invalid value.
|
||||
// The LastMessage method will return a more detailed message in that
|
||||
// case. Otherwise, the DeathTest pointer pointed to by the "test"
|
||||
// argument is set. If the death test should be skipped, the pointer
|
||||
// is set to NULL; otherwise, it is set to the address of a new concrete
|
||||
// DeathTest object that controls the execution of the current test.
|
||||
static bool Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test);
|
||||
DeathTest();
|
||||
virtual ~DeathTest() { }
|
||||
|
||||
// A helper class that aborts a death test when it's deleted.
|
||||
class ReturnSentinel {
|
||||
public:
|
||||
explicit ReturnSentinel(DeathTest* test) : test_(test) { }
|
||||
~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
|
||||
private:
|
||||
DeathTest* const test_;
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
|
||||
} GTEST_ATTRIBUTE_UNUSED_;
|
||||
|
||||
// An enumeration of possible roles that may be taken when a death
|
||||
// test is encountered. EXECUTE means that the death test logic should
|
||||
// be executed immediately. OVERSEE means that the program should prepare
|
||||
// the appropriate environment for a child process to execute the death
|
||||
// test, then wait for it to complete.
|
||||
enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
|
||||
|
||||
// An enumeration of the three reasons that a test might be aborted.
|
||||
enum AbortReason {
|
||||
TEST_ENCOUNTERED_RETURN_STATEMENT,
|
||||
TEST_THREW_EXCEPTION,
|
||||
TEST_DID_NOT_DIE
|
||||
};
|
||||
|
||||
// Assumes one of the above roles.
|
||||
virtual TestRole AssumeRole() = 0;
|
||||
|
||||
// Waits for the death test to finish and returns its status.
|
||||
virtual int Wait() = 0;
|
||||
|
||||
// Returns true if the death test passed; that is, the test process
|
||||
// exited during the test, its exit status matches a user-supplied
|
||||
// predicate, and its stderr output matches a user-supplied regular
|
||||
// expression.
|
||||
// The user-supplied predicate may be a macro expression rather
|
||||
// than a function pointer or functor, or else Wait and Passed could
|
||||
// be combined.
|
||||
virtual bool Passed(bool exit_status_ok) = 0;
|
||||
|
||||
// Signals that the death test did not die as expected.
|
||||
virtual void Abort(AbortReason reason) = 0;
|
||||
|
||||
// Returns a human-readable outcome message regarding the outcome of
|
||||
// the last death test.
|
||||
static const char* LastMessage();
|
||||
|
||||
static void set_last_death_test_message(const std::string& message);
|
||||
|
||||
private:
|
||||
// A string containing a description of the outcome of the last death test.
|
||||
static std::string last_death_test_message_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
|
||||
};
|
||||
|
||||
// Factory interface for death tests. May be mocked out for testing.
|
||||
class DeathTestFactory {
|
||||
public:
|
||||
virtual ~DeathTestFactory() { }
|
||||
virtual bool Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test) = 0;
|
||||
};
|
||||
|
||||
// A concrete DeathTestFactory implementation for normal use.
|
||||
class DefaultDeathTestFactory : public DeathTestFactory {
|
||||
public:
|
||||
virtual bool Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test);
|
||||
};
|
||||
|
||||
// Returns true if exit_status describes a process that was terminated
|
||||
// by a signal, or exited normally with a nonzero exit code.
|
||||
GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
||||
|
||||
// Traps C++ exceptions escaping statement and reports them as test
|
||||
// failures. Note that trapping SEH exceptions is not implemented here.
|
||||
# if GTEST_HAS_EXCEPTIONS
|
||||
# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
|
||||
try { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} catch (const ::std::exception& gtest_exception) { \
|
||||
fprintf(\
|
||||
stderr, \
|
||||
"\n%s: Caught std::exception-derived exception escaping the " \
|
||||
"death test statement. Exception message: %s\n", \
|
||||
::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \
|
||||
gtest_exception.what()); \
|
||||
fflush(stderr); \
|
||||
death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
|
||||
} catch (...) { \
|
||||
death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
|
||||
}
|
||||
|
||||
# else
|
||||
# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
|
||||
|
||||
# endif
|
||||
|
||||
// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
|
||||
// ASSERT_EXIT*, and EXPECT_EXIT*.
|
||||
# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
const ::testing::internal::RE& gtest_regex = (regex); \
|
||||
::testing::internal::DeathTest* gtest_dt; \
|
||||
if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \
|
||||
__FILE__, __LINE__, >est_dt)) { \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||
} \
|
||||
if (gtest_dt != NULL) { \
|
||||
::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
|
||||
gtest_dt_ptr(gtest_dt); \
|
||||
switch (gtest_dt->AssumeRole()) { \
|
||||
case ::testing::internal::DeathTest::OVERSEE_TEST: \
|
||||
if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||
} \
|
||||
break; \
|
||||
case ::testing::internal::DeathTest::EXECUTE_TEST: { \
|
||||
::testing::internal::DeathTest::ReturnSentinel \
|
||||
gtest_sentinel(gtest_dt); \
|
||||
GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
|
||||
gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else \
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
|
||||
fail(::testing::internal::DeathTest::LastMessage())
|
||||
// The symbol "fail" here expands to something into which a message
|
||||
// can be streamed.
|
||||
|
||||
// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
|
||||
// NDEBUG mode. In this case we need the statements to be executed, the regex is
|
||||
// ignored, and the macro must accept a streamed message even though the message
|
||||
// is never printed.
|
||||
# define GTEST_EXECUTE_STATEMENT_(statement, regex) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} else \
|
||||
::testing::Message()
|
||||
|
||||
// A class representing the parsed contents of the
|
||||
// --gtest_internal_run_death_test flag, as it existed when
|
||||
// RUN_ALL_TESTS was called.
|
||||
class InternalRunDeathTestFlag {
|
||||
public:
|
||||
InternalRunDeathTestFlag(const std::string& a_file,
|
||||
int a_line,
|
||||
int an_index,
|
||||
int a_write_fd)
|
||||
: file_(a_file), line_(a_line), index_(an_index),
|
||||
write_fd_(a_write_fd) {}
|
||||
|
||||
~InternalRunDeathTestFlag() {
|
||||
if (write_fd_ >= 0)
|
||||
posix::Close(write_fd_);
|
||||
}
|
||||
|
||||
const std::string& file() const { return file_; }
|
||||
int line() const { return line_; }
|
||||
int index() const { return index_; }
|
||||
int write_fd() const { return write_fd_; }
|
||||
|
||||
private:
|
||||
std::string file_;
|
||||
int line_;
|
||||
int index_;
|
||||
int write_fd_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
|
||||
};
|
||||
|
||||
// Returns a newly created InternalRunDeathTestFlag object with fields
|
||||
// initialized from the GTEST_FLAG(internal_run_death_test) flag if
|
||||
// the flag is specified; otherwise returns NULL.
|
||||
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
|
||||
|
||||
#else // GTEST_HAS_DEATH_TEST
|
||||
|
||||
// This macro is used for implementing macros such as
|
||||
// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
|
||||
// death tests are not supported. Those macros must compile on such systems
|
||||
// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
|
||||
// systems that support death tests. This allows one to write such a macro
|
||||
// on a system that does not support death tests and be sure that it will
|
||||
// compile on a death-test supporting system.
|
||||
//
|
||||
// Parameters:
|
||||
// statement - A statement that a macro such as EXPECT_DEATH would test
|
||||
// for program termination. This macro has to make sure this
|
||||
// statement is compiled but not executed, to ensure that
|
||||
// EXPECT_DEATH_IF_SUPPORTED compiles with a certain
|
||||
// parameter iff EXPECT_DEATH compiles with it.
|
||||
// regex - A regex that a macro such as EXPECT_DEATH would use to test
|
||||
// the output of statement. This parameter has to be
|
||||
// compiled but not evaluated by this macro, to ensure that
|
||||
// this macro only accepts expressions that a macro such as
|
||||
// EXPECT_DEATH would accept.
|
||||
// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
|
||||
// and a return statement for ASSERT_DEATH_IF_SUPPORTED.
|
||||
// This ensures that ASSERT_DEATH_IF_SUPPORTED will not
|
||||
// compile inside functions where ASSERT_DEATH doesn't
|
||||
// compile.
|
||||
//
|
||||
// The branch that has an always false condition is used to ensure that
|
||||
// statement and regex are compiled (and thus syntactically correct) but
|
||||
// never executed. The unreachable code macro protects the terminator
|
||||
// statement from generating an 'unreachable code' warning in case
|
||||
// statement unconditionally returns or throws. The Message constructor at
|
||||
// the end allows the syntax of streaming additional messages into the
|
||||
// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
|
||||
# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
GTEST_LOG_(WARNING) \
|
||||
<< "Death tests are not supported on this platform.\n" \
|
||||
<< "Statement '" #statement "' cannot be verified."; \
|
||||
} else if (::testing::internal::AlwaysFalse()) { \
|
||||
::testing::internal::RE::PartialMatch(".*", (regex)); \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
terminator; \
|
||||
} else \
|
||||
::testing::Message()
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
|
@ -1,206 +0,0 @@
|
|||
// Copyright 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: keith.ray@gmail.com (Keith Ray)
|
||||
//
|
||||
// Google Test filepath utilities
|
||||
//
|
||||
// This header file declares classes and functions used internally by
|
||||
// Google Test. They are subject to change without notice.
|
||||
//
|
||||
// This file is #included in <gtest/internal/gtest-internal.h>.
|
||||
// Do not include this header file separately!
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
||||
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// FilePath - a class for file and directory pathname manipulation which
|
||||
// handles platform-specific conventions (like the pathname separator).
|
||||
// Used for helper functions for naming files in a directory for xml output.
|
||||
// Except for Set methods, all methods are const or static, which provides an
|
||||
// "immutable value object" -- useful for peace of mind.
|
||||
// A FilePath with a value ending in a path separator ("like/this/") represents
|
||||
// a directory, otherwise it is assumed to represent a file. In either case,
|
||||
// it may or may not represent an actual file or directory in the file system.
|
||||
// Names are NOT checked for syntax correctness -- no checking for illegal
|
||||
// characters, malformed paths, etc.
|
||||
|
||||
class GTEST_API_ FilePath {
|
||||
public:
|
||||
FilePath() : pathname_("") { }
|
||||
FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
|
||||
|
||||
explicit FilePath(const std::string& pathname) : pathname_(pathname) {
|
||||
Normalize();
|
||||
}
|
||||
|
||||
FilePath& operator=(const FilePath& rhs) {
|
||||
Set(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Set(const FilePath& rhs) {
|
||||
pathname_ = rhs.pathname_;
|
||||
}
|
||||
|
||||
const std::string& string() const { return pathname_; }
|
||||
const char* c_str() const { return pathname_.c_str(); }
|
||||
|
||||
// Returns the current working directory, or "" if unsuccessful.
|
||||
static FilePath GetCurrentDir();
|
||||
|
||||
// Given directory = "dir", base_name = "test", number = 0,
|
||||
// extension = "xml", returns "dir/test.xml". If number is greater
|
||||
// than zero (e.g., 12), returns "dir/test_12.xml".
|
||||
// On Windows platform, uses \ as the separator rather than /.
|
||||
static FilePath MakeFileName(const FilePath& directory,
|
||||
const FilePath& base_name,
|
||||
int number,
|
||||
const char* extension);
|
||||
|
||||
// Given directory = "dir", relative_path = "test.xml",
|
||||
// returns "dir/test.xml".
|
||||
// On Windows, uses \ as the separator rather than /.
|
||||
static FilePath ConcatPaths(const FilePath& directory,
|
||||
const FilePath& relative_path);
|
||||
|
||||
// Returns a pathname for a file that does not currently exist. The pathname
|
||||
// will be directory/base_name.extension or
|
||||
// directory/base_name_<number>.extension if directory/base_name.extension
|
||||
// already exists. The number will be incremented until a pathname is found
|
||||
// that does not already exist.
|
||||
// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
|
||||
// There could be a race condition if two or more processes are calling this
|
||||
// function at the same time -- they could both pick the same filename.
|
||||
static FilePath GenerateUniqueFileName(const FilePath& directory,
|
||||
const FilePath& base_name,
|
||||
const char* extension);
|
||||
|
||||
// Returns true iff the path is "".
|
||||
bool IsEmpty() const { return pathname_.empty(); }
|
||||
|
||||
// If input name has a trailing separator character, removes it and returns
|
||||
// the name, otherwise return the name string unmodified.
|
||||
// On Windows platform, uses \ as the separator, other platforms use /.
|
||||
FilePath RemoveTrailingPathSeparator() const;
|
||||
|
||||
// Returns a copy of the FilePath with the directory part removed.
|
||||
// Example: FilePath("path/to/file").RemoveDirectoryName() returns
|
||||
// FilePath("file"). If there is no directory part ("just_a_file"), it returns
|
||||
// the FilePath unmodified. If there is no file part ("just_a_dir/") it
|
||||
// returns an empty FilePath ("").
|
||||
// On Windows platform, '\' is the path separator, otherwise it is '/'.
|
||||
FilePath RemoveDirectoryName() const;
|
||||
|
||||
// RemoveFileName returns the directory path with the filename removed.
|
||||
// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
|
||||
// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
|
||||
// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
|
||||
// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
|
||||
// On Windows platform, '\' is the path separator, otherwise it is '/'.
|
||||
FilePath RemoveFileName() const;
|
||||
|
||||
// Returns a copy of the FilePath with the case-insensitive extension removed.
|
||||
// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
|
||||
// FilePath("dir/file"). If a case-insensitive extension is not
|
||||
// found, returns a copy of the original FilePath.
|
||||
FilePath RemoveExtension(const char* extension) const;
|
||||
|
||||
// Creates directories so that path exists. Returns true if successful or if
|
||||
// the directories already exist; returns false if unable to create
|
||||
// directories for any reason. Will also return false if the FilePath does
|
||||
// not represent a directory (that is, it doesn't end with a path separator).
|
||||
bool CreateDirectoriesRecursively() const;
|
||||
|
||||
// Create the directory so that path exists. Returns true if successful or
|
||||
// if the directory already exists; returns false if unable to create the
|
||||
// directory for any reason, including if the parent directory does not
|
||||
// exist. Not named "CreateDirectory" because that's a macro on Windows.
|
||||
bool CreateFolder() const;
|
||||
|
||||
// Returns true if FilePath describes something in the file-system,
|
||||
// either a file, directory, or whatever, and that something exists.
|
||||
bool FileOrDirectoryExists() const;
|
||||
|
||||
// Returns true if pathname describes a directory in the file-system
|
||||
// that exists.
|
||||
bool DirectoryExists() const;
|
||||
|
||||
// Returns true if FilePath ends with a path separator, which indicates that
|
||||
// it is intended to represent a directory. Returns false otherwise.
|
||||
// This does NOT check that a directory (or file) actually exists.
|
||||
bool IsDirectory() const;
|
||||
|
||||
// Returns true if pathname describes a root directory. (Windows has one
|
||||
// root directory per disk drive.)
|
||||
bool IsRootDirectory() const;
|
||||
|
||||
// Returns true if pathname describes an absolute path.
|
||||
bool IsAbsolutePath() const;
|
||||
|
||||
private:
|
||||
// Replaces multiple consecutive separators with a single separator.
|
||||
// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
|
||||
// redundancies that might be in a pathname involving "." or "..".
|
||||
//
|
||||
// A pathname with multiple consecutive separators may occur either through
|
||||
// user error or as a result of some scripts or APIs that generate a pathname
|
||||
// with a trailing separator. On other platforms the same API or script
|
||||
// may NOT generate a pathname with a trailing "/". Then elsewhere that
|
||||
// pathname may have another "/" and pathname components added to it,
|
||||
// without checking for the separator already being there.
|
||||
// The script language and operating system may allow paths like "foo//bar"
|
||||
// but some of the functions in FilePath will not handle that correctly. In
|
||||
// particular, RemoveTrailingPathSeparator() only removes one separator, and
|
||||
// it is called in CreateDirectoriesRecursively() assuming that it will change
|
||||
// a pathname from directory syntax (trailing separator) to filename syntax.
|
||||
//
|
||||
// On Windows this method also replaces the alternate path separator '/' with
|
||||
// the primary path separator '\\', so that for example "bar\\/\\foo" becomes
|
||||
// "bar\\foo".
|
||||
|
||||
void Normalize();
|
||||
|
||||
// Returns a pointer to the last occurrence of a valid path separator in
|
||||
// the FilePath. On Windows, for example, both '/' and '\' are valid path
|
||||
// separators. Returns NULL if no path separator was found.
|
||||
const char* FindLastPathSeparator() const;
|
||||
|
||||
std::string pathname_;
|
||||
}; // class FilePath
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -1,243 +0,0 @@
|
|||
// Copyright 2003 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: Dan Egnor (egnor@google.com)
|
||||
//
|
||||
// A "smart" pointer type with reference tracking. Every pointer to a
|
||||
// particular object is kept on a circular linked list. When the last pointer
|
||||
// to an object is destroyed or reassigned, the object is deleted.
|
||||
//
|
||||
// Used properly, this deletes the object when the last reference goes away.
|
||||
// There are several caveats:
|
||||
// - Like all reference counting schemes, cycles lead to leaks.
|
||||
// - Each smart pointer is actually two pointers (8 bytes instead of 4).
|
||||
// - Every time a pointer is assigned, the entire list of pointers to that
|
||||
// object is traversed. This class is therefore NOT SUITABLE when there
|
||||
// will often be more than two or three pointers to a particular object.
|
||||
// - References are only tracked as long as linked_ptr<> objects are copied.
|
||||
// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
|
||||
// will happen (double deletion).
|
||||
//
|
||||
// A good use of this class is storing object references in STL containers.
|
||||
// You can safely put linked_ptr<> in a vector<>.
|
||||
// Other uses may not be as good.
|
||||
//
|
||||
// Note: If you use an incomplete type with linked_ptr<>, the class
|
||||
// *containing* linked_ptr<> must have a constructor and destructor (even
|
||||
// if they do nothing!).
|
||||
//
|
||||
// Bill Gibbons suggested we use something like this.
|
||||
//
|
||||
// Thread Safety:
|
||||
// Unlike other linked_ptr implementations, in this implementation
|
||||
// a linked_ptr object is thread-safe in the sense that:
|
||||
// - it's safe to copy linked_ptr objects concurrently,
|
||||
// - it's safe to copy *from* a linked_ptr and read its underlying
|
||||
// raw pointer (e.g. via get()) concurrently, and
|
||||
// - it's safe to write to two linked_ptrs that point to the same
|
||||
// shared object concurrently.
|
||||
// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
|
||||
// confusion with normal linked_ptr.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// Protects copying of all linked_ptr objects.
|
||||
GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);
|
||||
|
||||
// This is used internally by all instances of linked_ptr<>. It needs to be
|
||||
// a non-template class because different types of linked_ptr<> can refer to
|
||||
// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
|
||||
// So, it needs to be possible for different types of linked_ptr to participate
|
||||
// in the same circular linked list, so we need a single class type here.
|
||||
//
|
||||
// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
|
||||
class linked_ptr_internal {
|
||||
public:
|
||||
// Create a new circle that includes only this instance.
|
||||
void join_new() {
|
||||
next_ = this;
|
||||
}
|
||||
|
||||
// Many linked_ptr operations may change p.link_ for some linked_ptr
|
||||
// variable p in the same circle as this object. Therefore we need
|
||||
// to prevent two such operations from occurring concurrently.
|
||||
//
|
||||
// Note that different types of linked_ptr objects can coexist in a
|
||||
// circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
|
||||
// linked_ptr<Derived2>). Therefore we must use a single mutex to
|
||||
// protect all linked_ptr objects. This can create serious
|
||||
// contention in production code, but is acceptable in a testing
|
||||
// framework.
|
||||
|
||||
// Join an existing circle.
|
||||
void join(linked_ptr_internal const* ptr)
|
||||
GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
|
||||
MutexLock lock(&g_linked_ptr_mutex);
|
||||
|
||||
linked_ptr_internal const* p = ptr;
|
||||
while (p->next_ != ptr) {
|
||||
assert(p->next_ != this &&
|
||||
"Trying to join() a linked ring we are already in. "
|
||||
"Is GMock thread safety enabled?");
|
||||
p = p->next_;
|
||||
}
|
||||
p->next_ = this;
|
||||
next_ = ptr;
|
||||
}
|
||||
|
||||
// Leave whatever circle we're part of. Returns true if we were the
|
||||
// last member of the circle. Once this is done, you can join() another.
|
||||
bool depart()
|
||||
GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
|
||||
MutexLock lock(&g_linked_ptr_mutex);
|
||||
|
||||
if (next_ == this) return true;
|
||||
linked_ptr_internal const* p = next_;
|
||||
while (p->next_ != this) {
|
||||
assert(p->next_ != next_ &&
|
||||
"Trying to depart() a linked ring we are not in. "
|
||||
"Is GMock thread safety enabled?");
|
||||
p = p->next_;
|
||||
}
|
||||
p->next_ = next_;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable linked_ptr_internal const* next_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class linked_ptr {
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
// Take over ownership of a raw pointer. This should happen as soon as
|
||||
// possible after the object is created.
|
||||
explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
|
||||
~linked_ptr() { depart(); }
|
||||
|
||||
// Copy an existing linked_ptr<>, adding ourselves to the list of references.
|
||||
template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
|
||||
linked_ptr(linked_ptr const& ptr) { // NOLINT
|
||||
assert(&ptr != this);
|
||||
copy(&ptr);
|
||||
}
|
||||
|
||||
// Assignment releases the old value and acquires the new.
|
||||
template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
|
||||
depart();
|
||||
copy(&ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
linked_ptr& operator=(linked_ptr const& ptr) {
|
||||
if (&ptr != this) {
|
||||
depart();
|
||||
copy(&ptr);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Smart pointer members.
|
||||
void reset(T* ptr = NULL) {
|
||||
depart();
|
||||
capture(ptr);
|
||||
}
|
||||
T* get() const { return value_; }
|
||||
T* operator->() const { return value_; }
|
||||
T& operator*() const { return *value_; }
|
||||
|
||||
bool operator==(T* p) const { return value_ == p; }
|
||||
bool operator!=(T* p) const { return value_ != p; }
|
||||
template <typename U>
|
||||
bool operator==(linked_ptr<U> const& ptr) const {
|
||||
return value_ == ptr.get();
|
||||
}
|
||||
template <typename U>
|
||||
bool operator!=(linked_ptr<U> const& ptr) const {
|
||||
return value_ != ptr.get();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename U>
|
||||
friend class linked_ptr;
|
||||
|
||||
T* value_;
|
||||
linked_ptr_internal link_;
|
||||
|
||||
void depart() {
|
||||
if (link_.depart()) delete value_;
|
||||
}
|
||||
|
||||
void capture(T* ptr) {
|
||||
value_ = ptr;
|
||||
link_.join_new();
|
||||
}
|
||||
|
||||
template <typename U> void copy(linked_ptr<U> const* ptr) {
|
||||
value_ = ptr->get();
|
||||
if (value_)
|
||||
link_.join(&ptr->link_);
|
||||
else
|
||||
link_.join_new();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> inline
|
||||
bool operator==(T* ptr, const linked_ptr<T>& x) {
|
||||
return ptr == x.get();
|
||||
}
|
||||
|
||||
template<typename T> inline
|
||||
bool operator!=(T* ptr, const linked_ptr<T>& x) {
|
||||
return ptr != x.get();
|
||||
}
|
||||
|
||||
// A function to convert T* into linked_ptr<T>
|
||||
// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
|
||||
// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
|
||||
template <typename T>
|
||||
linked_ptr<T> make_linked_ptr(T* ptr) {
|
||||
return linked_ptr<T>(ptr);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -1,286 +0,0 @@
|
|||
$$ -*- mode: c++; -*-
|
||||
$var n = 50 $$ Maximum length of Values arguments we want to support.
|
||||
$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support.
|
||||
// Copyright 2008 Google Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: vladl@google.com (Vlad Losev)
|
||||
|
||||
// Type and function utilities for implementing parameterized tests.
|
||||
// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
|
||||
//
|
||||
// Currently Google Test supports at most $n arguments in Values,
|
||||
// and at most $maxtuple arguments in Combine. Please contact
|
||||
// googletestframework@googlegroups.com if you need more.
|
||||
// Please note that the number of arguments to Combine is limited
|
||||
// by the maximum arity of the implementation of tuple which is
|
||||
// currently set at $maxtuple.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
|
||||
|
||||
// scripts/fuse_gtest.py depends on gtest's own header being #included
|
||||
// *unconditionally*. Therefore these #includes cannot be moved
|
||||
// inside #if GTEST_HAS_PARAM_TEST.
|
||||
#include "gtest/internal/gtest-param-util.h"
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Forward declarations of ValuesIn(), which is implemented in
|
||||
// include/gtest/gtest-param-test.h.
|
||||
template <typename ForwardIterator>
|
||||
internal::ParamGenerator<
|
||||
typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
|
||||
ValuesIn(ForwardIterator begin, ForwardIterator end);
|
||||
|
||||
template <typename T, size_t N>
|
||||
internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
|
||||
|
||||
template <class Container>
|
||||
internal::ParamGenerator<typename Container::value_type> ValuesIn(
|
||||
const Container& container);
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Used in the Values() function to provide polymorphic capabilities.
|
||||
$range i 1..n
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[typename T$j]]>
|
||||
class ValueArray$i {
|
||||
public:
|
||||
$if i==1 [[explicit ]]ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {}
|
||||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {$for j, [[static_cast<T>(v$(j)_)]]};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
private:
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const ValueArray$i& other);
|
||||
|
||||
$for j [[
|
||||
|
||||
const T$j v$(j)_;
|
||||
]]
|
||||
|
||||
};
|
||||
|
||||
]]
|
||||
|
||||
# if GTEST_HAS_COMBINE
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Generates values from the Cartesian product of values produced
|
||||
// by the argument generators.
|
||||
//
|
||||
$range i 2..maxtuple
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
$range k 2..i
|
||||
|
||||
template <$for j, [[typename T$j]]>
|
||||
class CartesianProductGenerator$i
|
||||
: public ParamGeneratorInterface< ::testing::tuple<$for j, [[T$j]]> > {
|
||||
public:
|
||||
typedef ::testing::tuple<$for j, [[T$j]]> ParamType;
|
||||
|
||||
CartesianProductGenerator$i($for j, [[const ParamGenerator<T$j>& g$j]])
|
||||
: $for j, [[g$(j)_(g$j)]] {}
|
||||
virtual ~CartesianProductGenerator$i() {}
|
||||
|
||||
virtual ParamIteratorInterface<ParamType>* Begin() const {
|
||||
return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]);
|
||||
}
|
||||
virtual ParamIteratorInterface<ParamType>* End() const {
|
||||
return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]);
|
||||
}
|
||||
|
||||
private:
|
||||
class Iterator : public ParamIteratorInterface<ParamType> {
|
||||
public:
|
||||
Iterator(const ParamGeneratorInterface<ParamType>* base, $for j, [[
|
||||
|
||||
const ParamGenerator<T$j>& g$j,
|
||||
const typename ParamGenerator<T$j>::iterator& current$(j)]])
|
||||
: base_(base),
|
||||
$for j, [[
|
||||
|
||||
begin$(j)_(g$j.begin()), end$(j)_(g$j.end()), current$(j)_(current$j)
|
||||
]] {
|
||||
ComputeCurrentValue();
|
||||
}
|
||||
virtual ~Iterator() {}
|
||||
|
||||
virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
|
||||
return base_;
|
||||
}
|
||||
// Advance should not be called on beyond-of-range iterators
|
||||
// so no component iterators must be beyond end of range, either.
|
||||
virtual void Advance() {
|
||||
assert(!AtEnd());
|
||||
++current$(i)_;
|
||||
|
||||
$for k [[
|
||||
if (current$(i+2-k)_ == end$(i+2-k)_) {
|
||||
current$(i+2-k)_ = begin$(i+2-k)_;
|
||||
++current$(i+2-k-1)_;
|
||||
}
|
||||
|
||||
]]
|
||||
ComputeCurrentValue();
|
||||
}
|
||||
virtual ParamIteratorInterface<ParamType>* Clone() const {
|
||||
return new Iterator(*this);
|
||||
}
|
||||
virtual const ParamType* Current() const { return ¤t_value_; }
|
||||
virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
|
||||
// Having the same base generator guarantees that the other
|
||||
// iterator is of the same type and we can downcast.
|
||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||
<< "The program attempted to compare iterators "
|
||||
<< "from different generators." << std::endl;
|
||||
const Iterator* typed_other =
|
||||
CheckedDowncastToActualType<const Iterator>(&other);
|
||||
// We must report iterators equal if they both point beyond their
|
||||
// respective ranges. That can happen in a variety of fashions,
|
||||
// so we have to consult AtEnd().
|
||||
return (AtEnd() && typed_other->AtEnd()) ||
|
||||
($for j && [[
|
||||
|
||||
current$(j)_ == typed_other->current$(j)_
|
||||
]]);
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator(const Iterator& other)
|
||||
: base_(other.base_), $for j, [[
|
||||
|
||||
begin$(j)_(other.begin$(j)_),
|
||||
end$(j)_(other.end$(j)_),
|
||||
current$(j)_(other.current$(j)_)
|
||||
]] {
|
||||
ComputeCurrentValue();
|
||||
}
|
||||
|
||||
void ComputeCurrentValue() {
|
||||
if (!AtEnd())
|
||||
current_value_ = ParamType($for j, [[*current$(j)_]]);
|
||||
}
|
||||
bool AtEnd() const {
|
||||
// We must report iterator past the end of the range when either of the
|
||||
// component iterators has reached the end of its range.
|
||||
return
|
||||
$for j || [[
|
||||
|
||||
current$(j)_ == end$(j)_
|
||||
]];
|
||||
}
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const Iterator& other);
|
||||
|
||||
const ParamGeneratorInterface<ParamType>* const base_;
|
||||
// begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
|
||||
// current[i]_ is the actual traversing iterator.
|
||||
$for j [[
|
||||
|
||||
const typename ParamGenerator<T$j>::iterator begin$(j)_;
|
||||
const typename ParamGenerator<T$j>::iterator end$(j)_;
|
||||
typename ParamGenerator<T$j>::iterator current$(j)_;
|
||||
]]
|
||||
|
||||
ParamType current_value_;
|
||||
}; // class CartesianProductGenerator$i::Iterator
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const CartesianProductGenerator$i& other);
|
||||
|
||||
|
||||
$for j [[
|
||||
const ParamGenerator<T$j> g$(j)_;
|
||||
|
||||
]]
|
||||
}; // class CartesianProductGenerator$i
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Helper classes providing Combine() with polymorphic features. They allow
|
||||
// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
|
||||
// convertible to U.
|
||||
//
|
||||
$range i 2..maxtuple
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[class Generator$j]]>
|
||||
class CartesianProductHolder$i {
|
||||
public:
|
||||
CartesianProductHolder$i($for j, [[const Generator$j& g$j]])
|
||||
: $for j, [[g$(j)_(g$j)]] {}
|
||||
template <$for j, [[typename T$j]]>
|
||||
operator ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >() const {
|
||||
return ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >(
|
||||
new CartesianProductGenerator$i<$for j, [[T$j]]>(
|
||||
$for j,[[
|
||||
|
||||
static_cast<ParamGenerator<T$j> >(g$(j)_)
|
||||
]]));
|
||||
}
|
||||
|
||||
private:
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const CartesianProductHolder$i& other);
|
||||
|
||||
|
||||
$for j [[
|
||||
const Generator$j g$(j)_;
|
||||
|
||||
]]
|
||||
}; // class CartesianProductHolder$i
|
||||
|
||||
]]
|
||||
|
||||
# endif // GTEST_HAS_COMBINE
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
|
|
@ -1,731 +0,0 @@
|
|||
// Copyright 2008 Google Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: vladl@google.com (Vlad Losev)
|
||||
|
||||
// Type and function utilities for implementing parameterized tests.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// scripts/fuse_gtest.py depends on gtest's own header being #included
|
||||
// *unconditionally*. Therefore these #includes cannot be moved
|
||||
// inside #if GTEST_HAS_PARAM_TEST.
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-linked_ptr.h"
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/gtest-printers.h"
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Input to a parameterized test name generator, describing a test parameter.
|
||||
// Consists of the parameter value and the integer parameter index.
|
||||
template <class ParamType>
|
||||
struct TestParamInfo {
|
||||
TestParamInfo(const ParamType& a_param, size_t an_index) :
|
||||
param(a_param),
|
||||
index(an_index) {}
|
||||
ParamType param;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
// A builtin parameterized test name generator which returns the result of
|
||||
// testing::PrintToString.
|
||||
struct PrintToStringParamName {
|
||||
template <class ParamType>
|
||||
std::string operator()(const TestParamInfo<ParamType>& info) const {
|
||||
return PrintToString(info.param);
|
||||
}
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Outputs a message explaining invalid registration of different
|
||||
// fixture class for the same test case. This may happen when
|
||||
// TEST_P macro is used to define two tests with the same name
|
||||
// but in different namespaces.
|
||||
GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
|
||||
CodeLocation code_location);
|
||||
|
||||
template <typename> class ParamGeneratorInterface;
|
||||
template <typename> class ParamGenerator;
|
||||
|
||||
// Interface for iterating over elements provided by an implementation
|
||||
// of ParamGeneratorInterface<T>.
|
||||
template <typename T>
|
||||
class ParamIteratorInterface {
|
||||
public:
|
||||
virtual ~ParamIteratorInterface() {}
|
||||
// A pointer to the base generator instance.
|
||||
// Used only for the purposes of iterator comparison
|
||||
// to make sure that two iterators belong to the same generator.
|
||||
virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
|
||||
// Advances iterator to point to the next element
|
||||
// provided by the generator. The caller is responsible
|
||||
// for not calling Advance() on an iterator equal to
|
||||
// BaseGenerator()->End().
|
||||
virtual void Advance() = 0;
|
||||
// Clones the iterator object. Used for implementing copy semantics
|
||||
// of ParamIterator<T>.
|
||||
virtual ParamIteratorInterface* Clone() const = 0;
|
||||
// Dereferences the current iterator and provides (read-only) access
|
||||
// to the pointed value. It is the caller's responsibility not to call
|
||||
// Current() on an iterator equal to BaseGenerator()->End().
|
||||
// Used for implementing ParamGenerator<T>::operator*().
|
||||
virtual const T* Current() const = 0;
|
||||
// Determines whether the given iterator and other point to the same
|
||||
// element in the sequence generated by the generator.
|
||||
// Used for implementing ParamGenerator<T>::operator==().
|
||||
virtual bool Equals(const ParamIteratorInterface& other) const = 0;
|
||||
};
|
||||
|
||||
// Class iterating over elements provided by an implementation of
|
||||
// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
|
||||
// and implements the const forward iterator concept.
|
||||
template <typename T>
|
||||
class ParamIterator {
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef const T& reference;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
// ParamIterator assumes ownership of the impl_ pointer.
|
||||
ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
|
||||
ParamIterator& operator=(const ParamIterator& other) {
|
||||
if (this != &other)
|
||||
impl_.reset(other.impl_->Clone());
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T& operator*() const { return *impl_->Current(); }
|
||||
const T* operator->() const { return impl_->Current(); }
|
||||
// Prefix version of operator++.
|
||||
ParamIterator& operator++() {
|
||||
impl_->Advance();
|
||||
return *this;
|
||||
}
|
||||
// Postfix version of operator++.
|
||||
ParamIterator operator++(int /*unused*/) {
|
||||
ParamIteratorInterface<T>* clone = impl_->Clone();
|
||||
impl_->Advance();
|
||||
return ParamIterator(clone);
|
||||
}
|
||||
bool operator==(const ParamIterator& other) const {
|
||||
return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
|
||||
}
|
||||
bool operator!=(const ParamIterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ParamGenerator<T>;
|
||||
explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
|
||||
scoped_ptr<ParamIteratorInterface<T> > impl_;
|
||||
};
|
||||
|
||||
// ParamGeneratorInterface<T> is the binary interface to access generators
|
||||
// defined in other translation units.
|
||||
template <typename T>
|
||||
class ParamGeneratorInterface {
|
||||
public:
|
||||
typedef T ParamType;
|
||||
|
||||
virtual ~ParamGeneratorInterface() {}
|
||||
|
||||
// Generator interface definition
|
||||
virtual ParamIteratorInterface<T>* Begin() const = 0;
|
||||
virtual ParamIteratorInterface<T>* End() const = 0;
|
||||
};
|
||||
|
||||
// Wraps ParamGeneratorInterface<T> and provides general generator syntax
|
||||
// compatible with the STL Container concept.
|
||||
// This class implements copy initialization semantics and the contained
|
||||
// ParamGeneratorInterface<T> instance is shared among all copies
|
||||
// of the original object. This is possible because that instance is immutable.
|
||||
template<typename T>
|
||||
class ParamGenerator {
|
||||
public:
|
||||
typedef ParamIterator<T> iterator;
|
||||
|
||||
explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
|
||||
ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
|
||||
|
||||
ParamGenerator& operator=(const ParamGenerator& other) {
|
||||
impl_ = other.impl_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin() const { return iterator(impl_->Begin()); }
|
||||
iterator end() const { return iterator(impl_->End()); }
|
||||
|
||||
private:
|
||||
linked_ptr<const ParamGeneratorInterface<T> > impl_;
|
||||
};
|
||||
|
||||
// Generates values from a range of two comparable values. Can be used to
|
||||
// generate sequences of user-defined types that implement operator+() and
|
||||
// operator<().
|
||||
// This class is used in the Range() function.
|
||||
template <typename T, typename IncrementT>
|
||||
class RangeGenerator : public ParamGeneratorInterface<T> {
|
||||
public:
|
||||
RangeGenerator(T begin, T end, IncrementT step)
|
||||
: begin_(begin), end_(end),
|
||||
step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
|
||||
virtual ~RangeGenerator() {}
|
||||
|
||||
virtual ParamIteratorInterface<T>* Begin() const {
|
||||
return new Iterator(this, begin_, 0, step_);
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* End() const {
|
||||
return new Iterator(this, end_, end_index_, step_);
|
||||
}
|
||||
|
||||
private:
|
||||
class Iterator : public ParamIteratorInterface<T> {
|
||||
public:
|
||||
Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
|
||||
IncrementT step)
|
||||
: base_(base), value_(value), index_(index), step_(step) {}
|
||||
virtual ~Iterator() {}
|
||||
|
||||
virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
|
||||
return base_;
|
||||
}
|
||||
virtual void Advance() {
|
||||
value_ = static_cast<T>(value_ + step_);
|
||||
index_++;
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* Clone() const {
|
||||
return new Iterator(*this);
|
||||
}
|
||||
virtual const T* Current() const { return &value_; }
|
||||
virtual bool Equals(const ParamIteratorInterface<T>& other) const {
|
||||
// Having the same base generator guarantees that the other
|
||||
// iterator is of the same type and we can downcast.
|
||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||
<< "The program attempted to compare iterators "
|
||||
<< "from different generators." << std::endl;
|
||||
const int other_index =
|
||||
CheckedDowncastToActualType<const Iterator>(&other)->index_;
|
||||
return index_ == other_index;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator(const Iterator& other)
|
||||
: ParamIteratorInterface<T>(),
|
||||
base_(other.base_), value_(other.value_), index_(other.index_),
|
||||
step_(other.step_) {}
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const Iterator& other);
|
||||
|
||||
const ParamGeneratorInterface<T>* const base_;
|
||||
T value_;
|
||||
int index_;
|
||||
const IncrementT step_;
|
||||
}; // class RangeGenerator::Iterator
|
||||
|
||||
static int CalculateEndIndex(const T& begin,
|
||||
const T& end,
|
||||
const IncrementT& step) {
|
||||
int end_index = 0;
|
||||
for (T i = begin; i < end; i = static_cast<T>(i + step))
|
||||
end_index++;
|
||||
return end_index;
|
||||
}
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const RangeGenerator& other);
|
||||
|
||||
const T begin_;
|
||||
const T end_;
|
||||
const IncrementT step_;
|
||||
// The index for the end() iterator. All the elements in the generated
|
||||
// sequence are indexed (0-based) to aid iterator comparison.
|
||||
const int end_index_;
|
||||
}; // class RangeGenerator
|
||||
|
||||
|
||||
// Generates values from a pair of STL-style iterators. Used in the
|
||||
// ValuesIn() function. The elements are copied from the source range
|
||||
// since the source can be located on the stack, and the generator
|
||||
// is likely to persist beyond that stack frame.
|
||||
template <typename T>
|
||||
class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
|
||||
public:
|
||||
template <typename ForwardIterator>
|
||||
ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
|
||||
: container_(begin, end) {}
|
||||
virtual ~ValuesInIteratorRangeGenerator() {}
|
||||
|
||||
virtual ParamIteratorInterface<T>* Begin() const {
|
||||
return new Iterator(this, container_.begin());
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* End() const {
|
||||
return new Iterator(this, container_.end());
|
||||
}
|
||||
|
||||
private:
|
||||
typedef typename ::std::vector<T> ContainerType;
|
||||
|
||||
class Iterator : public ParamIteratorInterface<T> {
|
||||
public:
|
||||
Iterator(const ParamGeneratorInterface<T>* base,
|
||||
typename ContainerType::const_iterator iterator)
|
||||
: base_(base), iterator_(iterator) {}
|
||||
virtual ~Iterator() {}
|
||||
|
||||
virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
|
||||
return base_;
|
||||
}
|
||||
virtual void Advance() {
|
||||
++iterator_;
|
||||
value_.reset();
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* Clone() const {
|
||||
return new Iterator(*this);
|
||||
}
|
||||
// We need to use cached value referenced by iterator_ because *iterator_
|
||||
// can return a temporary object (and of type other then T), so just
|
||||
// having "return &*iterator_;" doesn't work.
|
||||
// value_ is updated here and not in Advance() because Advance()
|
||||
// can advance iterator_ beyond the end of the range, and we cannot
|
||||
// detect that fact. The client code, on the other hand, is
|
||||
// responsible for not calling Current() on an out-of-range iterator.
|
||||
virtual const T* Current() const {
|
||||
if (value_.get() == NULL)
|
||||
value_.reset(new T(*iterator_));
|
||||
return value_.get();
|
||||
}
|
||||
virtual bool Equals(const ParamIteratorInterface<T>& other) const {
|
||||
// Having the same base generator guarantees that the other
|
||||
// iterator is of the same type and we can downcast.
|
||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||
<< "The program attempted to compare iterators "
|
||||
<< "from different generators." << std::endl;
|
||||
return iterator_ ==
|
||||
CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator(const Iterator& other)
|
||||
// The explicit constructor call suppresses a false warning
|
||||
// emitted by gcc when supplied with the -Wextra option.
|
||||
: ParamIteratorInterface<T>(),
|
||||
base_(other.base_),
|
||||
iterator_(other.iterator_) {}
|
||||
|
||||
const ParamGeneratorInterface<T>* const base_;
|
||||
typename ContainerType::const_iterator iterator_;
|
||||
// A cached value of *iterator_. We keep it here to allow access by
|
||||
// pointer in the wrapping iterator's operator->().
|
||||
// value_ needs to be mutable to be accessed in Current().
|
||||
// Use of scoped_ptr helps manage cached value's lifetime,
|
||||
// which is bound by the lifespan of the iterator itself.
|
||||
mutable scoped_ptr<const T> value_;
|
||||
}; // class ValuesInIteratorRangeGenerator::Iterator
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const ValuesInIteratorRangeGenerator& other);
|
||||
|
||||
const ContainerType container_;
|
||||
}; // class ValuesInIteratorRangeGenerator
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Default parameterized test name generator, returns a string containing the
|
||||
// integer test parameter index.
|
||||
template <class ParamType>
|
||||
std::string DefaultParamName(const TestParamInfo<ParamType>& info) {
|
||||
Message name_stream;
|
||||
name_stream << info.index;
|
||||
return name_stream.GetString();
|
||||
}
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Parameterized test name overload helpers, which help the
|
||||
// INSTANTIATE_TEST_CASE_P macro choose between the default parameterized
|
||||
// test name generator and user param name generator.
|
||||
template <class ParamType, class ParamNameGenFunctor>
|
||||
ParamNameGenFunctor GetParamNameGen(ParamNameGenFunctor func) {
|
||||
return func;
|
||||
}
|
||||
|
||||
template <class ParamType>
|
||||
struct ParamNameGenFunc {
|
||||
typedef std::string Type(const TestParamInfo<ParamType>&);
|
||||
};
|
||||
|
||||
template <class ParamType>
|
||||
typename ParamNameGenFunc<ParamType>::Type *GetParamNameGen() {
|
||||
return DefaultParamName;
|
||||
}
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Stores a parameter value and later creates tests parameterized with that
|
||||
// value.
|
||||
template <class TestClass>
|
||||
class ParameterizedTestFactory : public TestFactoryBase {
|
||||
public:
|
||||
typedef typename TestClass::ParamType ParamType;
|
||||
explicit ParameterizedTestFactory(ParamType parameter) :
|
||||
parameter_(parameter) {}
|
||||
virtual Test* CreateTest() {
|
||||
TestClass::SetParam(¶meter_);
|
||||
return new TestClass();
|
||||
}
|
||||
|
||||
private:
|
||||
const ParamType parameter_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// TestMetaFactoryBase is a base class for meta-factories that create
|
||||
// test factories for passing into MakeAndRegisterTestInfo function.
|
||||
template <class ParamType>
|
||||
class TestMetaFactoryBase {
|
||||
public:
|
||||
virtual ~TestMetaFactoryBase() {}
|
||||
|
||||
virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// TestMetaFactory creates test factories for passing into
|
||||
// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
|
||||
// ownership of test factory pointer, same factory object cannot be passed
|
||||
// into that method twice. But ParameterizedTestCaseInfo is going to call
|
||||
// it for each Test/Parameter value combination. Thus it needs meta factory
|
||||
// creator class.
|
||||
template <class TestCase>
|
||||
class TestMetaFactory
|
||||
: public TestMetaFactoryBase<typename TestCase::ParamType> {
|
||||
public:
|
||||
typedef typename TestCase::ParamType ParamType;
|
||||
|
||||
TestMetaFactory() {}
|
||||
|
||||
virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
|
||||
return new ParameterizedTestFactory<TestCase>(parameter);
|
||||
}
|
||||
|
||||
private:
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// ParameterizedTestCaseInfoBase is a generic interface
|
||||
// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
|
||||
// accumulates test information provided by TEST_P macro invocations
|
||||
// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
|
||||
// and uses that information to register all resulting test instances
|
||||
// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
|
||||
// a collection of pointers to the ParameterizedTestCaseInfo objects
|
||||
// and calls RegisterTests() on each of them when asked.
|
||||
class ParameterizedTestCaseInfoBase {
|
||||
public:
|
||||
virtual ~ParameterizedTestCaseInfoBase() {}
|
||||
|
||||
// Base part of test case name for display purposes.
|
||||
virtual const string& GetTestCaseName() const = 0;
|
||||
// Test case id to verify identity.
|
||||
virtual TypeId GetTestCaseTypeId() const = 0;
|
||||
// UnitTest class invokes this method to register tests in this
|
||||
// test case right before running them in RUN_ALL_TESTS macro.
|
||||
// This method should not be called more then once on any single
|
||||
// instance of a ParameterizedTestCaseInfoBase derived class.
|
||||
virtual void RegisterTests() = 0;
|
||||
|
||||
protected:
|
||||
ParameterizedTestCaseInfoBase() {}
|
||||
|
||||
private:
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
|
||||
// macro invocations for a particular test case and generators
|
||||
// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
|
||||
// test case. It registers tests with all values generated by all
|
||||
// generators when asked.
|
||||
template <class TestCase>
|
||||
class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
|
||||
public:
|
||||
// ParamType and GeneratorCreationFunc are private types but are required
|
||||
// for declarations of public methods AddTestPattern() and
|
||||
// AddTestCaseInstantiation().
|
||||
typedef typename TestCase::ParamType ParamType;
|
||||
// A function that returns an instance of appropriate generator type.
|
||||
typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
|
||||
typedef typename ParamNameGenFunc<ParamType>::Type ParamNameGeneratorFunc;
|
||||
|
||||
explicit ParameterizedTestCaseInfo(
|
||||
const char* name, CodeLocation code_location)
|
||||
: test_case_name_(name), code_location_(code_location) {}
|
||||
|
||||
// Test case base name for display purposes.
|
||||
virtual const string& GetTestCaseName() const { return test_case_name_; }
|
||||
// Test case id to verify identity.
|
||||
virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
|
||||
// TEST_P macro uses AddTestPattern() to record information
|
||||
// about a single test in a LocalTestInfo structure.
|
||||
// test_case_name is the base name of the test case (without invocation
|
||||
// prefix). test_base_name is the name of an individual test without
|
||||
// parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
|
||||
// test case base name and DoBar is test base name.
|
||||
void AddTestPattern(const char* test_case_name,
|
||||
const char* test_base_name,
|
||||
TestMetaFactoryBase<ParamType>* meta_factory) {
|
||||
tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
|
||||
test_base_name,
|
||||
meta_factory)));
|
||||
}
|
||||
// INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
|
||||
// about a generator.
|
||||
int AddTestCaseInstantiation(const string& instantiation_name,
|
||||
GeneratorCreationFunc* func,
|
||||
ParamNameGeneratorFunc* name_func,
|
||||
const char* file,
|
||||
int line) {
|
||||
instantiations_.push_back(
|
||||
InstantiationInfo(instantiation_name, func, name_func, file, line));
|
||||
return 0; // Return value used only to run this method in namespace scope.
|
||||
}
|
||||
// UnitTest class invokes this method to register tests in this test case
|
||||
// test cases right before running tests in RUN_ALL_TESTS macro.
|
||||
// This method should not be called more then once on any single
|
||||
// instance of a ParameterizedTestCaseInfoBase derived class.
|
||||
// UnitTest has a guard to prevent from calling this method more then once.
|
||||
virtual void RegisterTests() {
|
||||
for (typename TestInfoContainer::iterator test_it = tests_.begin();
|
||||
test_it != tests_.end(); ++test_it) {
|
||||
linked_ptr<TestInfo> test_info = *test_it;
|
||||
for (typename InstantiationContainer::iterator gen_it =
|
||||
instantiations_.begin(); gen_it != instantiations_.end();
|
||||
++gen_it) {
|
||||
const string& instantiation_name = gen_it->name;
|
||||
ParamGenerator<ParamType> generator((*gen_it->generator)());
|
||||
ParamNameGeneratorFunc* name_func = gen_it->name_func;
|
||||
const char* file = gen_it->file;
|
||||
int line = gen_it->line;
|
||||
|
||||
string test_case_name;
|
||||
if ( !instantiation_name.empty() )
|
||||
test_case_name = instantiation_name + "/";
|
||||
test_case_name += test_info->test_case_base_name;
|
||||
|
||||
size_t i = 0;
|
||||
std::set<std::string> test_param_names;
|
||||
for (typename ParamGenerator<ParamType>::iterator param_it =
|
||||
generator.begin();
|
||||
param_it != generator.end(); ++param_it, ++i) {
|
||||
Message test_name_stream;
|
||||
|
||||
std::string param_name = name_func(
|
||||
TestParamInfo<ParamType>(*param_it, i));
|
||||
|
||||
GTEST_CHECK_(IsValidParamName(param_name))
|
||||
<< "Parameterized test name '" << param_name
|
||||
<< "' is invalid, in " << file
|
||||
<< " line " << line << std::endl;
|
||||
|
||||
GTEST_CHECK_(test_param_names.count(param_name) == 0)
|
||||
<< "Duplicate parameterized test name '" << param_name
|
||||
<< "', in " << file << " line " << line << std::endl;
|
||||
|
||||
test_param_names.insert(param_name);
|
||||
|
||||
test_name_stream << test_info->test_base_name << "/" << param_name;
|
||||
MakeAndRegisterTestInfo(
|
||||
test_case_name.c_str(),
|
||||
test_name_stream.GetString().c_str(),
|
||||
NULL, // No type parameter.
|
||||
PrintToString(*param_it).c_str(),
|
||||
code_location_,
|
||||
GetTestCaseTypeId(),
|
||||
TestCase::SetUpTestCase,
|
||||
TestCase::TearDownTestCase,
|
||||
test_info->test_meta_factory->CreateTestFactory(*param_it));
|
||||
} // for param_it
|
||||
} // for gen_it
|
||||
} // for test_it
|
||||
} // RegisterTests
|
||||
|
||||
private:
|
||||
// LocalTestInfo structure keeps information about a single test registered
|
||||
// with TEST_P macro.
|
||||
struct TestInfo {
|
||||
TestInfo(const char* a_test_case_base_name,
|
||||
const char* a_test_base_name,
|
||||
TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
|
||||
test_case_base_name(a_test_case_base_name),
|
||||
test_base_name(a_test_base_name),
|
||||
test_meta_factory(a_test_meta_factory) {}
|
||||
|
||||
const string test_case_base_name;
|
||||
const string test_base_name;
|
||||
const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
|
||||
};
|
||||
typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
|
||||
// Records data received from INSTANTIATE_TEST_CASE_P macros:
|
||||
// <Instantiation name, Sequence generator creation function,
|
||||
// Name generator function, Source file, Source line>
|
||||
struct InstantiationInfo {
|
||||
InstantiationInfo(const std::string &name_in,
|
||||
GeneratorCreationFunc* generator_in,
|
||||
ParamNameGeneratorFunc* name_func_in,
|
||||
const char* file_in,
|
||||
int line_in)
|
||||
: name(name_in),
|
||||
generator(generator_in),
|
||||
name_func(name_func_in),
|
||||
file(file_in),
|
||||
line(line_in) {}
|
||||
|
||||
std::string name;
|
||||
GeneratorCreationFunc* generator;
|
||||
ParamNameGeneratorFunc* name_func;
|
||||
const char* file;
|
||||
int line;
|
||||
};
|
||||
typedef ::std::vector<InstantiationInfo> InstantiationContainer;
|
||||
|
||||
static bool IsValidParamName(const std::string& name) {
|
||||
// Check for empty string
|
||||
if (name.empty())
|
||||
return false;
|
||||
|
||||
// Check for invalid characters
|
||||
for (std::string::size_type index = 0; index < name.size(); ++index) {
|
||||
if (!isalnum(name[index]) && name[index] != '_')
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const string test_case_name_;
|
||||
CodeLocation code_location_;
|
||||
TestInfoContainer tests_;
|
||||
InstantiationContainer instantiations_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
|
||||
}; // class ParameterizedTestCaseInfo
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
|
||||
// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
|
||||
// macros use it to locate their corresponding ParameterizedTestCaseInfo
|
||||
// descriptors.
|
||||
class ParameterizedTestCaseRegistry {
|
||||
public:
|
||||
ParameterizedTestCaseRegistry() {}
|
||||
~ParameterizedTestCaseRegistry() {
|
||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
||||
it != test_case_infos_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
// Looks up or creates and returns a structure containing information about
|
||||
// tests and instantiations of a particular test case.
|
||||
template <class TestCase>
|
||||
ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
|
||||
const char* test_case_name,
|
||||
CodeLocation code_location) {
|
||||
ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
|
||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
||||
it != test_case_infos_.end(); ++it) {
|
||||
if ((*it)->GetTestCaseName() == test_case_name) {
|
||||
if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
|
||||
// Complain about incorrect usage of Google Test facilities
|
||||
// and terminate the program since we cannot guaranty correct
|
||||
// test case setup and tear-down in this case.
|
||||
ReportInvalidTestCaseType(test_case_name, code_location);
|
||||
posix::Abort();
|
||||
} else {
|
||||
// At this point we are sure that the object we found is of the same
|
||||
// type we are looking for, so we downcast it to that type
|
||||
// without further checks.
|
||||
typed_test_info = CheckedDowncastToActualType<
|
||||
ParameterizedTestCaseInfo<TestCase> >(*it);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (typed_test_info == NULL) {
|
||||
typed_test_info = new ParameterizedTestCaseInfo<TestCase>(
|
||||
test_case_name, code_location);
|
||||
test_case_infos_.push_back(typed_test_info);
|
||||
}
|
||||
return typed_test_info;
|
||||
}
|
||||
void RegisterTests() {
|
||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
||||
it != test_case_infos_.end(); ++it) {
|
||||
(*it)->RegisterTests();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
|
||||
|
||||
TestCaseInfoContainer test_case_infos_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
|
@ -1,93 +0,0 @@
|
|||
// Copyright 2015, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file defines the GTEST_OS_* macro.
|
||||
// It is separate from gtest-port.h so that custom/gtest-port.h can include it.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
|
||||
|
||||
// Determines the platform on which Google Test is compiled.
|
||||
#ifdef __CYGWIN__
|
||||
# define GTEST_OS_CYGWIN 1
|
||||
#elif defined __SYMBIAN32__
|
||||
# define GTEST_OS_SYMBIAN 1
|
||||
#elif defined _WIN32
|
||||
# define GTEST_OS_WINDOWS 1
|
||||
# ifdef _WIN32_WCE
|
||||
# define GTEST_OS_WINDOWS_MOBILE 1
|
||||
# elif defined(__MINGW__) || defined(__MINGW32__)
|
||||
# define GTEST_OS_WINDOWS_MINGW 1
|
||||
# elif defined(WINAPI_FAMILY)
|
||||
# include <winapifamily.h>
|
||||
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
# define GTEST_OS_WINDOWS_DESKTOP 1
|
||||
# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
|
||||
# define GTEST_OS_WINDOWS_PHONE 1
|
||||
# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
# define GTEST_OS_WINDOWS_RT 1
|
||||
# else
|
||||
// WINAPI_FAMILY defined but no known partition matched.
|
||||
// Default to desktop.
|
||||
# define GTEST_OS_WINDOWS_DESKTOP 1
|
||||
# endif
|
||||
# else
|
||||
# define GTEST_OS_WINDOWS_DESKTOP 1
|
||||
# endif // _WIN32_WCE
|
||||
#elif defined __APPLE__
|
||||
# define GTEST_OS_MAC 1
|
||||
# if TARGET_OS_IPHONE
|
||||
# define GTEST_OS_IOS 1
|
||||
# endif
|
||||
#elif defined __FreeBSD__
|
||||
# define GTEST_OS_FREEBSD 1
|
||||
#elif defined __linux__
|
||||
# define GTEST_OS_LINUX 1
|
||||
# if defined __ANDROID__
|
||||
# define GTEST_OS_LINUX_ANDROID 1
|
||||
# endif
|
||||
#elif defined __MVS__
|
||||
# define GTEST_OS_ZOS 1
|
||||
#elif defined(__sun) && defined(__SVR4)
|
||||
# define GTEST_OS_SOLARIS 1
|
||||
#elif defined(_AIX)
|
||||
# define GTEST_OS_AIX 1
|
||||
#elif defined(__hpux)
|
||||
# define GTEST_OS_HPUX 1
|
||||
#elif defined __native_client__
|
||||
# define GTEST_OS_NACL 1
|
||||
#elif defined __OpenBSD__
|
||||
# define GTEST_OS_OPENBSD 1
|
||||
#elif defined __QNX__
|
||||
# define GTEST_OS_QNX 1
|
||||
#endif // __CYGWIN__
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -1,167 +0,0 @@
|
|||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file declares the String class and functions used internally by
|
||||
// Google Test. They are subject to change without notice. They should not used
|
||||
// by code external to Google Test.
|
||||
//
|
||||
// This header file is #included by <gtest/internal/gtest-internal.h>.
|
||||
// It should not be #included by other files.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
// string.h is not guaranteed to provide strcpy on C++ Builder.
|
||||
# include <mem.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// String - an abstract class holding static string utilities.
|
||||
class GTEST_API_ String {
|
||||
public:
|
||||
// Static utility methods
|
||||
|
||||
// Clones a 0-terminated C string, allocating memory using new. The
|
||||
// caller is responsible for deleting the return value using
|
||||
// delete[]. Returns the cloned string, or NULL if the input is
|
||||
// NULL.
|
||||
//
|
||||
// This is different from strdup() in string.h, which allocates
|
||||
// memory using malloc().
|
||||
static const char* CloneCString(const char* c_str);
|
||||
|
||||
#if GTEST_OS_WINDOWS_MOBILE
|
||||
// Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
|
||||
// able to pass strings to Win32 APIs on CE we need to convert them
|
||||
// to 'Unicode', UTF-16.
|
||||
|
||||
// Creates a UTF-16 wide string from the given ANSI string, allocating
|
||||
// memory using new. The caller is responsible for deleting the return
|
||||
// value using delete[]. Returns the wide string, or NULL if the
|
||||
// input is NULL.
|
||||
//
|
||||
// The wide string is created using the ANSI codepage (CP_ACP) to
|
||||
// match the behaviour of the ANSI versions of Win32 calls and the
|
||||
// C runtime.
|
||||
static LPCWSTR AnsiToUtf16(const char* c_str);
|
||||
|
||||
// Creates an ANSI string from the given wide string, allocating
|
||||
// memory using new. The caller is responsible for deleting the return
|
||||
// value using delete[]. Returns the ANSI string, or NULL if the
|
||||
// input is NULL.
|
||||
//
|
||||
// The returned string is created using the ANSI codepage (CP_ACP) to
|
||||
// match the behaviour of the ANSI versions of Win32 calls and the
|
||||
// C runtime.
|
||||
static const char* Utf16ToAnsi(LPCWSTR utf16_str);
|
||||
#endif
|
||||
|
||||
// Compares two C strings. Returns true iff they have the same content.
|
||||
//
|
||||
// Unlike strcmp(), this function can handle NULL argument(s). A
|
||||
// NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool CStringEquals(const char* lhs, const char* rhs);
|
||||
|
||||
// Converts a wide C string to a String using the UTF-8 encoding.
|
||||
// NULL will be converted to "(null)". If an error occurred during
|
||||
// the conversion, "(failed to convert from wide string)" is
|
||||
// returned.
|
||||
static std::string ShowWideCString(const wchar_t* wide_c_str);
|
||||
|
||||
// Compares two wide C strings. Returns true iff they have the same
|
||||
// content.
|
||||
//
|
||||
// Unlike wcscmp(), this function can handle NULL argument(s). A
|
||||
// NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
|
||||
|
||||
// Compares two C strings, ignoring case. Returns true iff they
|
||||
// have the same content.
|
||||
//
|
||||
// Unlike strcasecmp(), this function can handle NULL argument(s).
|
||||
// A NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool CaseInsensitiveCStringEquals(const char* lhs,
|
||||
const char* rhs);
|
||||
|
||||
// Compares two wide C strings, ignoring case. Returns true iff they
|
||||
// have the same content.
|
||||
//
|
||||
// Unlike wcscasecmp(), this function can handle NULL argument(s).
|
||||
// A NULL C string is considered different to any non-NULL wide C string,
|
||||
// including the empty string.
|
||||
// NB: The implementations on different platforms slightly differ.
|
||||
// On windows, this method uses _wcsicmp which compares according to LC_CTYPE
|
||||
// environment variable. On GNU platform this method uses wcscasecmp
|
||||
// which compares according to LC_CTYPE category of the current locale.
|
||||
// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
|
||||
// current locale.
|
||||
static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
|
||||
const wchar_t* rhs);
|
||||
|
||||
// Returns true iff the given string ends with the given suffix, ignoring
|
||||
// case. Any string is considered to end with an empty suffix.
|
||||
static bool EndsWithCaseInsensitive(
|
||||
const std::string& str, const std::string& suffix);
|
||||
|
||||
// Formats an int value as "%02d".
|
||||
static std::string FormatIntWidth2(int value); // "%02d" for width == 2
|
||||
|
||||
// Formats an int value as "%X".
|
||||
static std::string FormatHexInt(int value);
|
||||
|
||||
// Formats a byte as "%02X".
|
||||
static std::string FormatByte(unsigned char value);
|
||||
|
||||
private:
|
||||
String(); // Not meant to be instantiated.
|
||||
}; // class String
|
||||
|
||||
// Gets the content of the stringstream's buffer as an std::string. Each '\0'
|
||||
// character in the buffer is replaced with "\\0".
|
||||
GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -1,347 +0,0 @@
|
|||
$$ -*- mode: c++; -*-
|
||||
$var n = 10 $$ Maximum number of tuple fields we want to support.
|
||||
$$ This meta comment fixes auto-indentation in Emacs. }}
|
||||
// Copyright 2009 Google Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
|
||||
|
||||
#include <utility> // For ::std::pair.
|
||||
|
||||
// The compiler used in Symbian has a bug that prevents us from declaring the
|
||||
// tuple template as a friend (it complains that tuple is redefined). This
|
||||
// hack bypasses the bug by declaring the members that should otherwise be
|
||||
// private as public.
|
||||
// Sun Studio versions < 12 also have the above bug.
|
||||
#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
|
||||
# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
|
||||
#else
|
||||
# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
|
||||
template <GTEST_$(n)_TYPENAMES_(U)> friend class tuple; \
|
||||
private:
|
||||
#endif
|
||||
|
||||
// Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict
|
||||
// with our own definitions. Therefore using our own tuple does not work on
|
||||
// those compilers.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 /* 1600 is Visual Studio 2010 */
|
||||
# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \
|
||||
GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers."
|
||||
#endif
|
||||
|
||||
|
||||
$range i 0..n-1
|
||||
$range j 0..n
|
||||
$range k 1..n
|
||||
// GTEST_n_TUPLE_(T) is the type of an n-tuple.
|
||||
#define GTEST_0_TUPLE_(T) tuple<>
|
||||
|
||||
$for k [[
|
||||
$range m 0..k-1
|
||||
$range m2 k..n-1
|
||||
#define GTEST_$(k)_TUPLE_(T) tuple<$for m, [[T##$m]]$for m2 [[, void]]>
|
||||
|
||||
]]
|
||||
|
||||
// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
|
||||
|
||||
$for j [[
|
||||
$range m 0..j-1
|
||||
#define GTEST_$(j)_TYPENAMES_(T) $for m, [[typename T##$m]]
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// In theory, defining stuff in the ::std namespace is undefined
|
||||
// behavior. We can do this as we are playing the role of a standard
|
||||
// library vendor.
|
||||
namespace std {
|
||||
namespace tr1 {
|
||||
|
||||
template <$for i, [[typename T$i = void]]>
|
||||
class tuple;
|
||||
|
||||
// Anything in namespace gtest_internal is Google Test's INTERNAL
|
||||
// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
|
||||
namespace gtest_internal {
|
||||
|
||||
// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
|
||||
template <typename T>
|
||||
struct ByRef { typedef const T& type; }; // NOLINT
|
||||
template <typename T>
|
||||
struct ByRef<T&> { typedef T& type; }; // NOLINT
|
||||
|
||||
// A handy wrapper for ByRef.
|
||||
#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
|
||||
|
||||
// AddRef<T>::type is T if T is a reference; otherwise it's T&. This
|
||||
// is the same as tr1::add_reference<T>::type.
|
||||
template <typename T>
|
||||
struct AddRef { typedef T& type; }; // NOLINT
|
||||
template <typename T>
|
||||
struct AddRef<T&> { typedef T& type; }; // NOLINT
|
||||
|
||||
// A handy wrapper for AddRef.
|
||||
#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
|
||||
|
||||
// A helper for implementing get<k>().
|
||||
template <int k> class Get;
|
||||
|
||||
// A helper for implementing tuple_element<k, T>. kIndexValid is true
|
||||
// iff k < the number of fields in tuple type T.
|
||||
template <bool kIndexValid, int kIndex, class Tuple>
|
||||
struct TupleElement;
|
||||
|
||||
|
||||
$for i [[
|
||||
template <GTEST_$(n)_TYPENAMES_(T)>
|
||||
struct TupleElement<true, $i, GTEST_$(n)_TUPLE_(T) > {
|
||||
typedef T$i type;
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
} // namespace gtest_internal
|
||||
|
||||
template <>
|
||||
class tuple<> {
|
||||
public:
|
||||
tuple() {}
|
||||
tuple(const tuple& /* t */) {}
|
||||
tuple& operator=(const tuple& /* t */) { return *this; }
|
||||
};
|
||||
|
||||
|
||||
$for k [[
|
||||
$range m 0..k-1
|
||||
template <GTEST_$(k)_TYPENAMES_(T)>
|
||||
class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] {
|
||||
public:
|
||||
template <int k> friend class gtest_internal::Get;
|
||||
|
||||
tuple() : $for m, [[f$(m)_()]] {}
|
||||
|
||||
explicit tuple($for m, [[GTEST_BY_REF_(T$m) f$m]]) : [[]]
|
||||
$for m, [[f$(m)_(f$m)]] {}
|
||||
|
||||
tuple(const tuple& t) : $for m, [[f$(m)_(t.f$(m)_)]] {}
|
||||
|
||||
template <GTEST_$(k)_TYPENAMES_(U)>
|
||||
tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {}
|
||||
|
||||
$if k == 2 [[
|
||||
template <typename U0, typename U1>
|
||||
tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
|
||||
|
||||
]]
|
||||
|
||||
tuple& operator=(const tuple& t) { return CopyFrom(t); }
|
||||
|
||||
template <GTEST_$(k)_TYPENAMES_(U)>
|
||||
tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) {
|
||||
return CopyFrom(t);
|
||||
}
|
||||
|
||||
$if k == 2 [[
|
||||
template <typename U0, typename U1>
|
||||
tuple& operator=(const ::std::pair<U0, U1>& p) {
|
||||
f0_ = p.first;
|
||||
f1_ = p.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
]]
|
||||
|
||||
GTEST_DECLARE_TUPLE_AS_FRIEND_
|
||||
|
||||
template <GTEST_$(k)_TYPENAMES_(U)>
|
||||
tuple& CopyFrom(const GTEST_$(k)_TUPLE_(U)& t) {
|
||||
|
||||
$for m [[
|
||||
f$(m)_ = t.f$(m)_;
|
||||
|
||||
]]
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
$for m [[
|
||||
T$m f$(m)_;
|
||||
|
||||
]]
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
// 6.1.3.2 Tuple creation functions.
|
||||
|
||||
// Known limitations: we don't support passing an
|
||||
// std::tr1::reference_wrapper<T> to make_tuple(). And we don't
|
||||
// implement tie().
|
||||
|
||||
inline tuple<> make_tuple() { return tuple<>(); }
|
||||
|
||||
$for k [[
|
||||
$range m 0..k-1
|
||||
|
||||
template <GTEST_$(k)_TYPENAMES_(T)>
|
||||
inline GTEST_$(k)_TUPLE_(T) make_tuple($for m, [[const T$m& f$m]]) {
|
||||
return GTEST_$(k)_TUPLE_(T)($for m, [[f$m]]);
|
||||
}
|
||||
|
||||
]]
|
||||
|
||||
// 6.1.3.3 Tuple helper classes.
|
||||
|
||||
template <typename Tuple> struct tuple_size;
|
||||
|
||||
|
||||
$for j [[
|
||||
template <GTEST_$(j)_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_$(j)_TUPLE_(T) > {
|
||||
static const int value = $j;
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
template <int k, class Tuple>
|
||||
struct tuple_element {
|
||||
typedef typename gtest_internal::TupleElement<
|
||||
k < (tuple_size<Tuple>::value), k, Tuple>::type type;
|
||||
};
|
||||
|
||||
#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
|
||||
|
||||
// 6.1.3.4 Element access.
|
||||
|
||||
namespace gtest_internal {
|
||||
|
||||
|
||||
$for i [[
|
||||
template <>
|
||||
class Get<$i> {
|
||||
public:
|
||||
template <class Tuple>
|
||||
static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple))
|
||||
Field(Tuple& t) { return t.f$(i)_; } // NOLINT
|
||||
|
||||
template <class Tuple>
|
||||
static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple))
|
||||
ConstField(const Tuple& t) { return t.f$(i)_; }
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
} // namespace gtest_internal
|
||||
|
||||
template <int k, GTEST_$(n)_TYPENAMES_(T)>
|
||||
GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T)))
|
||||
get(GTEST_$(n)_TUPLE_(T)& t) {
|
||||
return gtest_internal::Get<k>::Field(t);
|
||||
}
|
||||
|
||||
template <int k, GTEST_$(n)_TYPENAMES_(T)>
|
||||
GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T)))
|
||||
get(const GTEST_$(n)_TUPLE_(T)& t) {
|
||||
return gtest_internal::Get<k>::ConstField(t);
|
||||
}
|
||||
|
||||
// 6.1.3.5 Relational operators
|
||||
|
||||
// We only implement == and !=, as we don't have a need for the rest yet.
|
||||
|
||||
namespace gtest_internal {
|
||||
|
||||
// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
|
||||
// first k fields of t1 equals the first k fields of t2.
|
||||
// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
|
||||
// k1 != k2.
|
||||
template <int kSize1, int kSize2>
|
||||
struct SameSizeTuplePrefixComparator;
|
||||
|
||||
template <>
|
||||
struct SameSizeTuplePrefixComparator<0, 0> {
|
||||
template <class Tuple1, class Tuple2>
|
||||
static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <int k>
|
||||
struct SameSizeTuplePrefixComparator<k, k> {
|
||||
template <class Tuple1, class Tuple2>
|
||||
static bool Eq(const Tuple1& t1, const Tuple2& t2) {
|
||||
return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
|
||||
::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gtest_internal
|
||||
|
||||
template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
|
||||
inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t,
|
||||
const GTEST_$(n)_TUPLE_(U)& u) {
|
||||
return gtest_internal::SameSizeTuplePrefixComparator<
|
||||
tuple_size<GTEST_$(n)_TUPLE_(T) >::value,
|
||||
tuple_size<GTEST_$(n)_TUPLE_(U) >::value>::Eq(t, u);
|
||||
}
|
||||
|
||||
template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
|
||||
inline bool operator!=(const GTEST_$(n)_TUPLE_(T)& t,
|
||||
const GTEST_$(n)_TUPLE_(U)& u) { return !(t == u); }
|
||||
|
||||
// 6.1.4 Pairs.
|
||||
// Unimplemented.
|
||||
|
||||
} // namespace tr1
|
||||
} // namespace std
|
||||
|
||||
|
||||
$for j [[
|
||||
#undef GTEST_$(j)_TUPLE_
|
||||
|
||||
]]
|
||||
|
||||
|
||||
$for j [[
|
||||
#undef GTEST_$(j)_TYPENAMES_
|
||||
|
||||
]]
|
||||
|
||||
#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
|
||||
#undef GTEST_BY_REF_
|
||||
#undef GTEST_ADD_REF_
|
||||
#undef GTEST_TUPLE_ELEMENT_
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -1,297 +0,0 @@
|
|||
$$ -*- mode: c++; -*-
|
||||
$var n = 50 $$ Maximum length of type lists we want to support.
|
||||
// Copyright 2008 Google Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
// Type utilities needed for implementing typed and type-parameterized
|
||||
// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
|
||||
//
|
||||
// Currently we support at most $n types in a list, and at most $n
|
||||
// type-parameterized tests in one type-parameterized test case.
|
||||
// Please contact googletestframework@googlegroups.com if you need
|
||||
// more.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
|
||||
// libstdc++ (which is where cxxabi.h comes from).
|
||||
# if GTEST_HAS_CXXABI_H_
|
||||
# include <cxxabi.h>
|
||||
# elif defined(__HP_aCC)
|
||||
# include <acxx_demangle.h>
|
||||
# endif // GTEST_HASH_CXXABI_H_
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// GetTypeName<T>() returns a human-readable name of type T.
|
||||
// NB: This function is also used in Google Mock, so don't move it inside of
|
||||
// the typed-test-only section below.
|
||||
template <typename T>
|
||||
std::string GetTypeName() {
|
||||
# if GTEST_HAS_RTTI
|
||||
|
||||
const char* const name = typeid(T).name();
|
||||
# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
|
||||
int status = 0;
|
||||
// gcc's implementation of typeid(T).name() mangles the type name,
|
||||
// so we have to demangle it.
|
||||
# if GTEST_HAS_CXXABI_H_
|
||||
using abi::__cxa_demangle;
|
||||
# endif // GTEST_HAS_CXXABI_H_
|
||||
char* const readable_name = __cxa_demangle(name, 0, 0, &status);
|
||||
const std::string name_str(status == 0 ? readable_name : name);
|
||||
free(readable_name);
|
||||
return name_str;
|
||||
# else
|
||||
return name;
|
||||
# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC
|
||||
|
||||
# else
|
||||
|
||||
return "<type>";
|
||||
|
||||
# endif // GTEST_HAS_RTTI
|
||||
}
|
||||
|
||||
#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
|
||||
// type. This can be used as a compile-time assertion to ensure that
|
||||
// two types are equal.
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct AssertTypeEq;
|
||||
|
||||
template <typename T>
|
||||
struct AssertTypeEq<T, T> {
|
||||
typedef bool type;
|
||||
};
|
||||
|
||||
// A unique type used as the default value for the arguments of class
|
||||
// template Types. This allows us to simulate variadic templates
|
||||
// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
|
||||
// support directly.
|
||||
struct None {};
|
||||
|
||||
// The following family of struct and struct templates are used to
|
||||
// represent type lists. In particular, TypesN<T1, T2, ..., TN>
|
||||
// represents a type list with N types (T1, T2, ..., and TN) in it.
|
||||
// Except for Types0, every struct in the family has two member types:
|
||||
// Head for the first type in the list, and Tail for the rest of the
|
||||
// list.
|
||||
|
||||
// The empty type list.
|
||||
struct Types0 {};
|
||||
|
||||
// Type lists of length 1, 2, 3, and so on.
|
||||
|
||||
template <typename T1>
|
||||
struct Types1 {
|
||||
typedef T1 Head;
|
||||
typedef Types0 Tail;
|
||||
};
|
||||
|
||||
$range i 2..n
|
||||
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
$range k 2..i
|
||||
template <$for j, [[typename T$j]]>
|
||||
struct Types$i {
|
||||
typedef T1 Head;
|
||||
typedef Types$(i-1)<$for k, [[T$k]]> Tail;
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// We don't want to require the users to write TypesN<...> directly,
|
||||
// as that would require them to count the length. Types<...> is much
|
||||
// easier to write, but generates horrible messages when there is a
|
||||
// compiler error, as gcc insists on printing out each template
|
||||
// argument, even if it has the default value (this means Types<int>
|
||||
// will appear as Types<int, None, None, ..., None> in the compiler
|
||||
// errors).
|
||||
//
|
||||
// Our solution is to combine the best part of the two approaches: a
|
||||
// user would write Types<T1, ..., TN>, and Google Test will translate
|
||||
// that to TypesN<T1, ..., TN> internally to make error messages
|
||||
// readable. The translation is done by the 'type' member of the
|
||||
// Types template.
|
||||
|
||||
$range i 1..n
|
||||
template <$for i, [[typename T$i = internal::None]]>
|
||||
struct Types {
|
||||
typedef internal::Types$n<$for i, [[T$i]]> type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Types<$for i, [[internal::None]]> {
|
||||
typedef internal::Types0 type;
|
||||
};
|
||||
|
||||
$range i 1..n-1
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
$range k i+1..n
|
||||
template <$for j, [[typename T$j]]>
|
||||
struct Types<$for j, [[T$j]]$for k[[, internal::None]]> {
|
||||
typedef internal::Types$i<$for j, [[T$j]]> type;
|
||||
};
|
||||
|
||||
]]
|
||||
|
||||
namespace internal {
|
||||
|
||||
# define GTEST_TEMPLATE_ template <typename T> class
|
||||
|
||||
// The template "selector" struct TemplateSel<Tmpl> is used to
|
||||
// represent Tmpl, which must be a class template with one type
|
||||
// parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined
|
||||
// as the type Tmpl<T>. This allows us to actually instantiate the
|
||||
// template "selected" by TemplateSel<Tmpl>.
|
||||
//
|
||||
// This trick is necessary for simulating typedef for class templates,
|
||||
// which C++ doesn't support directly.
|
||||
template <GTEST_TEMPLATE_ Tmpl>
|
||||
struct TemplateSel {
|
||||
template <typename T>
|
||||
struct Bind {
|
||||
typedef Tmpl<T> type;
|
||||
};
|
||||
};
|
||||
|
||||
# define GTEST_BIND_(TmplSel, T) \
|
||||
TmplSel::template Bind<T>::type
|
||||
|
||||
// A unique struct template used as the default value for the
|
||||
// arguments of class template Templates. This allows us to simulate
|
||||
// variadic templates (e.g. Templates<int>, Templates<int, double>,
|
||||
// and etc), which C++ doesn't support directly.
|
||||
template <typename T>
|
||||
struct NoneT {};
|
||||
|
||||
// The following family of struct and struct templates are used to
|
||||
// represent template lists. In particular, TemplatesN<T1, T2, ...,
|
||||
// TN> represents a list of N templates (T1, T2, ..., and TN). Except
|
||||
// for Templates0, every struct in the family has two member types:
|
||||
// Head for the selector of the first template in the list, and Tail
|
||||
// for the rest of the list.
|
||||
|
||||
// The empty template list.
|
||||
struct Templates0 {};
|
||||
|
||||
// Template lists of length 1, 2, 3, and so on.
|
||||
|
||||
template <GTEST_TEMPLATE_ T1>
|
||||
struct Templates1 {
|
||||
typedef TemplateSel<T1> Head;
|
||||
typedef Templates0 Tail;
|
||||
};
|
||||
|
||||
$range i 2..n
|
||||
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
$range k 2..i
|
||||
template <$for j, [[GTEST_TEMPLATE_ T$j]]>
|
||||
struct Templates$i {
|
||||
typedef TemplateSel<T1> Head;
|
||||
typedef Templates$(i-1)<$for k, [[T$k]]> Tail;
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// We don't want to require the users to write TemplatesN<...> directly,
|
||||
// as that would require them to count the length. Templates<...> is much
|
||||
// easier to write, but generates horrible messages when there is a
|
||||
// compiler error, as gcc insists on printing out each template
|
||||
// argument, even if it has the default value (this means Templates<list>
|
||||
// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
|
||||
// errors).
|
||||
//
|
||||
// Our solution is to combine the best part of the two approaches: a
|
||||
// user would write Templates<T1, ..., TN>, and Google Test will translate
|
||||
// that to TemplatesN<T1, ..., TN> internally to make error messages
|
||||
// readable. The translation is done by the 'type' member of the
|
||||
// Templates template.
|
||||
|
||||
$range i 1..n
|
||||
template <$for i, [[GTEST_TEMPLATE_ T$i = NoneT]]>
|
||||
struct Templates {
|
||||
typedef Templates$n<$for i, [[T$i]]> type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Templates<$for i, [[NoneT]]> {
|
||||
typedef Templates0 type;
|
||||
};
|
||||
|
||||
$range i 1..n-1
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
$range k i+1..n
|
||||
template <$for j, [[GTEST_TEMPLATE_ T$j]]>
|
||||
struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> {
|
||||
typedef Templates$i<$for j, [[T$j]]> type;
|
||||
};
|
||||
|
||||
]]
|
||||
|
||||
// The TypeList template makes it possible to use either a single type
|
||||
// or a Types<...> list in TYPED_TEST_CASE() and
|
||||
// INSTANTIATE_TYPED_TEST_CASE_P().
|
||||
|
||||
template <typename T>
|
||||
struct TypeList {
|
||||
typedef Types1<T> type;
|
||||
};
|
||||
|
||||
|
||||
$range i 1..n
|
||||
template <$for i, [[typename T$i]]>
|
||||
struct TypeList<Types<$for i, [[T$i]]> > {
|
||||
typedef typename Types<$for i, [[T$i]]>::type type;
|
||||
};
|
||||
|
||||
#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
|
|
@ -1,48 +0,0 @@
|
|||
// Copyright 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: mheule@google.com (Markus Heule)
|
||||
//
|
||||
// Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// Sometimes it's desirable to build Google Test by compiling a single file.
|
||||
// This file serves this purpose.
|
||||
|
||||
// This line ensures that gtest.h can be compiled on its own, even
|
||||
// when it's fused.
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
// The following lines pull in the real gtest *.cc files.
|
||||
#include "src/gtest.cc"
|
||||
#include "src/gtest-death-test.cc"
|
||||
#include "src/gtest-filepath.cc"
|
||||
#include "src/gtest-port.cc"
|
||||
#include "src/gtest-printers.cc"
|
||||
#include "src/gtest-test-part.cc"
|
||||
#include "src/gtest-typed-test.cc"
|
File diff suppressed because it is too large
Load Diff
|
@ -1,387 +0,0 @@
|
|||
// Copyright 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: keith.ray@gmail.com (Keith Ray)
|
||||
|
||||
#include "gtest/gtest-message.h"
|
||||
#include "gtest/internal/gtest-filepath.h"
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if GTEST_OS_WINDOWS_MOBILE
|
||||
# include <windows.h>
|
||||
#elif GTEST_OS_WINDOWS
|
||||
# include <direct.h>
|
||||
# include <io.h>
|
||||
#elif GTEST_OS_SYMBIAN
|
||||
// Symbian OpenC has PATH_MAX in sys/syslimits.h
|
||||
# include <sys/syslimits.h>
|
||||
#else
|
||||
# include <limits.h>
|
||||
# include <climits> // Some Linux distributions define PATH_MAX here.
|
||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
# define GTEST_PATH_MAX_ _MAX_PATH
|
||||
#elif defined(PATH_MAX)
|
||||
# define GTEST_PATH_MAX_ PATH_MAX
|
||||
#elif defined(_XOPEN_PATH_MAX)
|
||||
# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
|
||||
#else
|
||||
# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
// On Windows, '\\' is the standard path separator, but many tools and the
|
||||
// Windows API also accept '/' as an alternate path separator. Unless otherwise
|
||||
// noted, a file path can contain either kind of path separators, or a mixture
|
||||
// of them.
|
||||
const char kPathSeparator = '\\';
|
||||
const char kAlternatePathSeparator = '/';
|
||||
const char kAlternatePathSeparatorString[] = "/";
|
||||
# if GTEST_OS_WINDOWS_MOBILE
|
||||
// Windows CE doesn't have a current directory. You should not use
|
||||
// the current directory in tests on Windows CE, but this at least
|
||||
// provides a reasonable fallback.
|
||||
const char kCurrentDirectoryString[] = "\\";
|
||||
// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
|
||||
const DWORD kInvalidFileAttributes = 0xffffffff;
|
||||
# else
|
||||
const char kCurrentDirectoryString[] = ".\\";
|
||||
# endif // GTEST_OS_WINDOWS_MOBILE
|
||||
#else
|
||||
const char kPathSeparator = '/';
|
||||
const char kCurrentDirectoryString[] = "./";
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
|
||||
// Returns whether the given character is a valid path separator.
|
||||
static bool IsPathSeparator(char c) {
|
||||
#if GTEST_HAS_ALT_PATH_SEP_
|
||||
return (c == kPathSeparator) || (c == kAlternatePathSeparator);
|
||||
#else
|
||||
return c == kPathSeparator;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns the current working directory, or "" if unsuccessful.
|
||||
FilePath FilePath::GetCurrentDir() {
|
||||
#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
|
||||
// Windows CE doesn't have a current directory, so we just return
|
||||
// something reasonable.
|
||||
return FilePath(kCurrentDirectoryString);
|
||||
#elif GTEST_OS_WINDOWS
|
||||
char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
|
||||
return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
|
||||
#else
|
||||
char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
|
||||
char* result = getcwd(cwd, sizeof(cwd));
|
||||
# if GTEST_OS_NACL
|
||||
// getcwd will likely fail in NaCl due to the sandbox, so return something
|
||||
// reasonable. The user may have provided a shim implementation for getcwd,
|
||||
// however, so fallback only when failure is detected.
|
||||
return FilePath(result == NULL ? kCurrentDirectoryString : cwd);
|
||||
# endif // GTEST_OS_NACL
|
||||
return FilePath(result == NULL ? "" : cwd);
|
||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||
}
|
||||
|
||||
// Returns a copy of the FilePath with the case-insensitive extension removed.
|
||||
// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
|
||||
// FilePath("dir/file"). If a case-insensitive extension is not
|
||||
// found, returns a copy of the original FilePath.
|
||||
FilePath FilePath::RemoveExtension(const char* extension) const {
|
||||
const std::string dot_extension = std::string(".") + extension;
|
||||
if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
|
||||
return FilePath(pathname_.substr(
|
||||
0, pathname_.length() - dot_extension.length()));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Returns a pointer to the last occurrence of a valid path separator in
|
||||
// the FilePath. On Windows, for example, both '/' and '\' are valid path
|
||||
// separators. Returns NULL if no path separator was found.
|
||||
const char* FilePath::FindLastPathSeparator() const {
|
||||
const char* const last_sep = strrchr(c_str(), kPathSeparator);
|
||||
#if GTEST_HAS_ALT_PATH_SEP_
|
||||
const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
|
||||
// Comparing two pointers of which only one is NULL is undefined.
|
||||
if (last_alt_sep != NULL &&
|
||||
(last_sep == NULL || last_alt_sep > last_sep)) {
|
||||
return last_alt_sep;
|
||||
}
|
||||
#endif
|
||||
return last_sep;
|
||||
}
|
||||
|
||||
// Returns a copy of the FilePath with the directory part removed.
|
||||
// Example: FilePath("path/to/file").RemoveDirectoryName() returns
|
||||
// FilePath("file"). If there is no directory part ("just_a_file"), it returns
|
||||
// the FilePath unmodified. If there is no file part ("just_a_dir/") it
|
||||
// returns an empty FilePath ("").
|
||||
// On Windows platform, '\' is the path separator, otherwise it is '/'.
|
||||
FilePath FilePath::RemoveDirectoryName() const {
|
||||
const char* const last_sep = FindLastPathSeparator();
|
||||
return last_sep ? FilePath(last_sep + 1) : *this;
|
||||
}
|
||||
|
||||
// RemoveFileName returns the directory path with the filename removed.
|
||||
// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
|
||||
// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
|
||||
// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
|
||||
// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
|
||||
// On Windows platform, '\' is the path separator, otherwise it is '/'.
|
||||
FilePath FilePath::RemoveFileName() const {
|
||||
const char* const last_sep = FindLastPathSeparator();
|
||||
std::string dir;
|
||||
if (last_sep) {
|
||||
dir = std::string(c_str(), last_sep + 1 - c_str());
|
||||
} else {
|
||||
dir = kCurrentDirectoryString;
|
||||
}
|
||||
return FilePath(dir);
|
||||
}
|
||||
|
||||
// Helper functions for naming files in a directory for xml output.
|
||||
|
||||
// Given directory = "dir", base_name = "test", number = 0,
|
||||
// extension = "xml", returns "dir/test.xml". If number is greater
|
||||
// than zero (e.g., 12), returns "dir/test_12.xml".
|
||||
// On Windows platform, uses \ as the separator rather than /.
|
||||
FilePath FilePath::MakeFileName(const FilePath& directory,
|
||||
const FilePath& base_name,
|
||||
int number,
|
||||
const char* extension) {
|
||||
std::string file;
|
||||
if (number == 0) {
|
||||
file = base_name.string() + "." + extension;
|
||||
} else {
|
||||
file = base_name.string() + "_" + StreamableToString(number)
|
||||
+ "." + extension;
|
||||
}
|
||||
return ConcatPaths(directory, FilePath(file));
|
||||
}
|
||||
|
||||
// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
|
||||
// On Windows, uses \ as the separator rather than /.
|
||||
FilePath FilePath::ConcatPaths(const FilePath& directory,
|
||||
const FilePath& relative_path) {
|
||||
if (directory.IsEmpty())
|
||||
return relative_path;
|
||||
const FilePath dir(directory.RemoveTrailingPathSeparator());
|
||||
return FilePath(dir.string() + kPathSeparator + relative_path.string());
|
||||
}
|
||||
|
||||
// Returns true if pathname describes something findable in the file-system,
|
||||
// either a file, directory, or whatever.
|
||||
bool FilePath::FileOrDirectoryExists() const {
|
||||
#if GTEST_OS_WINDOWS_MOBILE
|
||||
LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
|
||||
const DWORD attributes = GetFileAttributes(unicode);
|
||||
delete [] unicode;
|
||||
return attributes != kInvalidFileAttributes;
|
||||
#else
|
||||
posix::StatStruct file_stat;
|
||||
return posix::Stat(pathname_.c_str(), &file_stat) == 0;
|
||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||
}
|
||||
|
||||
// Returns true if pathname describes a directory in the file-system
|
||||
// that exists.
|
||||
bool FilePath::DirectoryExists() const {
|
||||
bool result = false;
|
||||
#if GTEST_OS_WINDOWS
|
||||
// Don't strip off trailing separator if path is a root directory on
|
||||
// Windows (like "C:\\").
|
||||
const FilePath& path(IsRootDirectory() ? *this :
|
||||
RemoveTrailingPathSeparator());
|
||||
#else
|
||||
const FilePath& path(*this);
|
||||
#endif
|
||||
|
||||
#if GTEST_OS_WINDOWS_MOBILE
|
||||
LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
|
||||
const DWORD attributes = GetFileAttributes(unicode);
|
||||
delete [] unicode;
|
||||
if ((attributes != kInvalidFileAttributes) &&
|
||||
(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
result = true;
|
||||
}
|
||||
#else
|
||||
posix::StatStruct file_stat;
|
||||
result = posix::Stat(path.c_str(), &file_stat) == 0 &&
|
||||
posix::IsDir(file_stat);
|
||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns true if pathname describes a root directory. (Windows has one
|
||||
// root directory per disk drive.)
|
||||
bool FilePath::IsRootDirectory() const {
|
||||
#if GTEST_OS_WINDOWS
|
||||
// TODO(wan@google.com): on Windows a network share like
|
||||
// \\server\share can be a root directory, although it cannot be the
|
||||
// current directory. Handle this properly.
|
||||
return pathname_.length() == 3 && IsAbsolutePath();
|
||||
#else
|
||||
return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns true if pathname describes an absolute path.
|
||||
bool FilePath::IsAbsolutePath() const {
|
||||
const char* const name = pathname_.c_str();
|
||||
#if GTEST_OS_WINDOWS
|
||||
return pathname_.length() >= 3 &&
|
||||
((name[0] >= 'a' && name[0] <= 'z') ||
|
||||
(name[0] >= 'A' && name[0] <= 'Z')) &&
|
||||
name[1] == ':' &&
|
||||
IsPathSeparator(name[2]);
|
||||
#else
|
||||
return IsPathSeparator(name[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns a pathname for a file that does not currently exist. The pathname
|
||||
// will be directory/base_name.extension or
|
||||
// directory/base_name_<number>.extension if directory/base_name.extension
|
||||
// already exists. The number will be incremented until a pathname is found
|
||||
// that does not already exist.
|
||||
// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
|
||||
// There could be a race condition if two or more processes are calling this
|
||||
// function at the same time -- they could both pick the same filename.
|
||||
FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
|
||||
const FilePath& base_name,
|
||||
const char* extension) {
|
||||
FilePath full_pathname;
|
||||
int number = 0;
|
||||
do {
|
||||
full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
|
||||
} while (full_pathname.FileOrDirectoryExists());
|
||||
return full_pathname;
|
||||
}
|
||||
|
||||
// Returns true if FilePath ends with a path separator, which indicates that
|
||||
// it is intended to represent a directory. Returns false otherwise.
|
||||
// This does NOT check that a directory (or file) actually exists.
|
||||
bool FilePath::IsDirectory() const {
|
||||
return !pathname_.empty() &&
|
||||
IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
|
||||
}
|
||||
|
||||
// Create directories so that path exists. Returns true if successful or if
|
||||
// the directories already exist; returns false if unable to create directories
|
||||
// for any reason.
|
||||
bool FilePath::CreateDirectoriesRecursively() const {
|
||||
if (!this->IsDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pathname_.length() == 0 || this->DirectoryExists()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
|
||||
return parent.CreateDirectoriesRecursively() && this->CreateFolder();
|
||||
}
|
||||
|
||||
// Create the directory so that path exists. Returns true if successful or
|
||||
// if the directory already exists; returns false if unable to create the
|
||||
// directory for any reason, including if the parent directory does not
|
||||
// exist. Not named "CreateDirectory" because that's a macro on Windows.
|
||||
bool FilePath::CreateFolder() const {
|
||||
#if GTEST_OS_WINDOWS_MOBILE
|
||||
FilePath removed_sep(this->RemoveTrailingPathSeparator());
|
||||
LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
|
||||
int result = CreateDirectory(unicode, NULL) ? 0 : -1;
|
||||
delete [] unicode;
|
||||
#elif GTEST_OS_WINDOWS
|
||||
int result = _mkdir(pathname_.c_str());
|
||||
#else
|
||||
int result = mkdir(pathname_.c_str(), 0777);
|
||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||
|
||||
if (result == -1) {
|
||||
return this->DirectoryExists(); // An error is OK if the directory exists.
|
||||
}
|
||||
return true; // No error.
|
||||
}
|
||||
|
||||
// If input name has a trailing separator character, remove it and return the
|
||||
// name, otherwise return the name string unmodified.
|
||||
// On Windows platform, uses \ as the separator, other platforms use /.
|
||||
FilePath FilePath::RemoveTrailingPathSeparator() const {
|
||||
return IsDirectory()
|
||||
? FilePath(pathname_.substr(0, pathname_.length() - 1))
|
||||
: *this;
|
||||
}
|
||||
|
||||
// Removes any redundant separators that might be in the pathname.
|
||||
// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
|
||||
// redundancies that might be in a pathname involving "." or "..".
|
||||
// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share).
|
||||
void FilePath::Normalize() {
|
||||
if (pathname_.c_str() == NULL) {
|
||||
pathname_ = "";
|
||||
return;
|
||||
}
|
||||
const char* src = pathname_.c_str();
|
||||
char* const dest = new char[pathname_.length() + 1];
|
||||
char* dest_ptr = dest;
|
||||
memset(dest_ptr, 0, pathname_.length() + 1);
|
||||
|
||||
while (*src != '\0') {
|
||||
*dest_ptr = *src;
|
||||
if (!IsPathSeparator(*src)) {
|
||||
src++;
|
||||
} else {
|
||||
#if GTEST_HAS_ALT_PATH_SEP_
|
||||
if (*dest_ptr == kAlternatePathSeparator) {
|
||||
*dest_ptr = kPathSeparator;
|
||||
}
|
||||
#endif
|
||||
while (IsPathSeparator(*src))
|
||||
src++;
|
||||
}
|
||||
dest_ptr++;
|
||||
}
|
||||
*dest_ptr = '\0';
|
||||
pathname_ = dest;
|
||||
delete[] dest;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,373 +0,0 @@
|
|||
// Copyright 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
// Google Test - The Google C++ Testing Framework
|
||||
//
|
||||
// This file implements a universal value printer that can print a
|
||||
// value of any type T:
|
||||
//
|
||||
// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
|
||||
//
|
||||
// It uses the << operator when possible, and prints the bytes in the
|
||||
// object otherwise. A user can override its behavior for a class
|
||||
// type Foo by defining either operator<<(::std::ostream&, const Foo&)
|
||||
// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that
|
||||
// defines Foo.
|
||||
|
||||
#include "gtest/gtest-printers.h"
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <cwchar>
|
||||
#include <ostream> // NOLINT
|
||||
#include <string>
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
namespace {
|
||||
|
||||
using ::std::ostream;
|
||||
|
||||
// Prints a segment of bytes in the given object.
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
|
||||
void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
|
||||
size_t count, ostream* os) {
|
||||
char text[5] = "";
|
||||
for (size_t i = 0; i != count; i++) {
|
||||
const size_t j = start + i;
|
||||
if (i != 0) {
|
||||
// Organizes the bytes into groups of 2 for easy parsing by
|
||||
// human.
|
||||
if ((j % 2) == 0)
|
||||
*os << ' ';
|
||||
else
|
||||
*os << '-';
|
||||
}
|
||||
GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]);
|
||||
*os << text;
|
||||
}
|
||||
}
|
||||
|
||||
// Prints the bytes in the given value to the given ostream.
|
||||
void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
|
||||
ostream* os) {
|
||||
// Tells the user how big the object is.
|
||||
*os << count << "-byte object <";
|
||||
|
||||
const size_t kThreshold = 132;
|
||||
const size_t kChunkSize = 64;
|
||||
// If the object size is bigger than kThreshold, we'll have to omit
|
||||
// some details by printing only the first and the last kChunkSize
|
||||
// bytes.
|
||||
// TODO(wan): let the user control the threshold using a flag.
|
||||
if (count < kThreshold) {
|
||||
PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
|
||||
} else {
|
||||
PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os);
|
||||
*os << " ... ";
|
||||
// Rounds up to 2-byte boundary.
|
||||
const size_t resume_pos = (count - kChunkSize + 1)/2*2;
|
||||
PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os);
|
||||
}
|
||||
*os << ">";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace internal2 {
|
||||
|
||||
// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
|
||||
// given object. The delegation simplifies the implementation, which
|
||||
// uses the << operator and thus is easier done outside of the
|
||||
// ::testing::internal namespace, which contains a << operator that
|
||||
// sometimes conflicts with the one in STL.
|
||||
void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count,
|
||||
ostream* os) {
|
||||
PrintBytesInObjectToImpl(obj_bytes, count, os);
|
||||
}
|
||||
|
||||
} // namespace internal2
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Depending on the value of a char (or wchar_t), we print it in one
|
||||
// of three formats:
|
||||
// - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
|
||||
// - as a hexidecimal escape sequence (e.g. '\x7F'), or
|
||||
// - as a special escape sequence (e.g. '\r', '\n').
|
||||
enum CharFormat {
|
||||
kAsIs,
|
||||
kHexEscape,
|
||||
kSpecialEscape
|
||||
};
|
||||
|
||||
// Returns true if c is a printable ASCII character. We test the
|
||||
// value of c directly instead of calling isprint(), which is buggy on
|
||||
// Windows Mobile.
|
||||
inline bool IsPrintableAscii(wchar_t c) {
|
||||
return 0x20 <= c && c <= 0x7E;
|
||||
}
|
||||
|
||||
// Prints a wide or narrow char c as a character literal without the
|
||||
// quotes, escaping it when necessary; returns how c was formatted.
|
||||
// The template argument UnsignedChar is the unsigned version of Char,
|
||||
// which is the type of c.
|
||||
template <typename UnsignedChar, typename Char>
|
||||
static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
|
||||
switch (static_cast<wchar_t>(c)) {
|
||||
case L'\0':
|
||||
*os << "\\0";
|
||||
break;
|
||||
case L'\'':
|
||||
*os << "\\'";
|
||||
break;
|
||||
case L'\\':
|
||||
*os << "\\\\";
|
||||
break;
|
||||
case L'\a':
|
||||
*os << "\\a";
|
||||
break;
|
||||
case L'\b':
|
||||
*os << "\\b";
|
||||
break;
|
||||
case L'\f':
|
||||
*os << "\\f";
|
||||
break;
|
||||
case L'\n':
|
||||
*os << "\\n";
|
||||
break;
|
||||
case L'\r':
|
||||
*os << "\\r";
|
||||
break;
|
||||
case L'\t':
|
||||
*os << "\\t";
|
||||
break;
|
||||
case L'\v':
|
||||
*os << "\\v";
|
||||
break;
|
||||
default:
|
||||
if (IsPrintableAscii(c)) {
|
||||
*os << static_cast<char>(c);
|
||||
return kAsIs;
|
||||
} else {
|
||||
*os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c));
|
||||
return kHexEscape;
|
||||
}
|
||||
}
|
||||
return kSpecialEscape;
|
||||
}
|
||||
|
||||
// Prints a wchar_t c as if it's part of a string literal, escaping it when
|
||||
// necessary; returns how c was formatted.
|
||||
static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
|
||||
switch (c) {
|
||||
case L'\'':
|
||||
*os << "'";
|
||||
return kAsIs;
|
||||
case L'"':
|
||||
*os << "\\\"";
|
||||
return kSpecialEscape;
|
||||
default:
|
||||
return PrintAsCharLiteralTo<wchar_t>(c, os);
|
||||
}
|
||||
}
|
||||
|
||||
// Prints a char c as if it's part of a string literal, escaping it when
|
||||
// necessary; returns how c was formatted.
|
||||
static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
|
||||
return PrintAsStringLiteralTo(
|
||||
static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
|
||||
}
|
||||
|
||||
// Prints a wide or narrow character c and its code. '\0' is printed
|
||||
// as "'\\0'", other unprintable characters are also properly escaped
|
||||
// using the standard C++ escape sequence. The template argument
|
||||
// UnsignedChar is the unsigned version of Char, which is the type of c.
|
||||
template <typename UnsignedChar, typename Char>
|
||||
void PrintCharAndCodeTo(Char c, ostream* os) {
|
||||
// First, print c as a literal in the most readable form we can find.
|
||||
*os << ((sizeof(c) > 1) ? "L'" : "'");
|
||||
const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os);
|
||||
*os << "'";
|
||||
|
||||
// To aid user debugging, we also print c's code in decimal, unless
|
||||
// it's 0 (in which case c was printed as '\\0', making the code
|
||||
// obvious).
|
||||
if (c == 0)
|
||||
return;
|
||||
*os << " (" << static_cast<int>(c);
|
||||
|
||||
// For more convenience, we print c's code again in hexidecimal,
|
||||
// unless c was already printed in the form '\x##' or the code is in
|
||||
// [1, 9].
|
||||
if (format == kHexEscape || (1 <= c && c <= 9)) {
|
||||
// Do nothing.
|
||||
} else {
|
||||
*os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
|
||||
}
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
void PrintTo(unsigned char c, ::std::ostream* os) {
|
||||
PrintCharAndCodeTo<unsigned char>(c, os);
|
||||
}
|
||||
void PrintTo(signed char c, ::std::ostream* os) {
|
||||
PrintCharAndCodeTo<unsigned char>(c, os);
|
||||
}
|
||||
|
||||
// Prints a wchar_t as a symbol if it is printable or as its internal
|
||||
// code otherwise and also as its code. L'\0' is printed as "L'\\0'".
|
||||
void PrintTo(wchar_t wc, ostream* os) {
|
||||
PrintCharAndCodeTo<wchar_t>(wc, os);
|
||||
}
|
||||
|
||||
// Prints the given array of characters to the ostream. CharType must be either
|
||||
// char or wchar_t.
|
||||
// The array starts at begin, the length is len, it may include '\0' characters
|
||||
// and may not be NUL-terminated.
|
||||
template <typename CharType>
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
|
||||
static void PrintCharsAsStringTo(
|
||||
const CharType* begin, size_t len, ostream* os) {
|
||||
const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
|
||||
*os << kQuoteBegin;
|
||||
bool is_previous_hex = false;
|
||||
for (size_t index = 0; index < len; ++index) {
|
||||
const CharType cur = begin[index];
|
||||
if (is_previous_hex && IsXDigit(cur)) {
|
||||
// Previous character is of '\x..' form and this character can be
|
||||
// interpreted as another hexadecimal digit in its number. Break string to
|
||||
// disambiguate.
|
||||
*os << "\" " << kQuoteBegin;
|
||||
}
|
||||
is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
|
||||
}
|
||||
*os << "\"";
|
||||
}
|
||||
|
||||
// Prints a (const) char/wchar_t array of 'len' elements, starting at address
|
||||
// 'begin'. CharType must be either char or wchar_t.
|
||||
template <typename CharType>
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
|
||||
static void UniversalPrintCharArray(
|
||||
const CharType* begin, size_t len, ostream* os) {
|
||||
// The code
|
||||
// const char kFoo[] = "foo";
|
||||
// generates an array of 4, not 3, elements, with the last one being '\0'.
|
||||
//
|
||||
// Therefore when printing a char array, we don't print the last element if
|
||||
// it's '\0', such that the output matches the string literal as it's
|
||||
// written in the source code.
|
||||
if (len > 0 && begin[len - 1] == '\0') {
|
||||
PrintCharsAsStringTo(begin, len - 1, os);
|
||||
return;
|
||||
}
|
||||
|
||||
// If, however, the last element in the array is not '\0', e.g.
|
||||
// const char kFoo[] = { 'f', 'o', 'o' };
|
||||
// we must print the entire array. We also print a message to indicate
|
||||
// that the array is not NUL-terminated.
|
||||
PrintCharsAsStringTo(begin, len, os);
|
||||
*os << " (no terminating NUL)";
|
||||
}
|
||||
|
||||
// Prints a (const) char array of 'len' elements, starting at address 'begin'.
|
||||
void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
|
||||
UniversalPrintCharArray(begin, len, os);
|
||||
}
|
||||
|
||||
// Prints a (const) wchar_t array of 'len' elements, starting at address
|
||||
// 'begin'.
|
||||
void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
|
||||
UniversalPrintCharArray(begin, len, os);
|
||||
}
|
||||
|
||||
// Prints the given C string to the ostream.
|
||||
void PrintTo(const char* s, ostream* os) {
|
||||
if (s == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
*os << ImplicitCast_<const void*>(s) << " pointing to ";
|
||||
PrintCharsAsStringTo(s, strlen(s), os);
|
||||
}
|
||||
}
|
||||
|
||||
// MSVC compiler can be configured to define whar_t as a typedef
|
||||
// of unsigned short. Defining an overload for const wchar_t* in that case
|
||||
// would cause pointers to unsigned shorts be printed as wide strings,
|
||||
// possibly accessing more memory than intended and causing invalid
|
||||
// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
|
||||
// wchar_t is implemented as a native type.
|
||||
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
// Prints the given wide C string to the ostream.
|
||||
void PrintTo(const wchar_t* s, ostream* os) {
|
||||
if (s == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
*os << ImplicitCast_<const void*>(s) << " pointing to ";
|
||||
PrintCharsAsStringTo(s, std::wcslen(s), os);
|
||||
}
|
||||
}
|
||||
#endif // wchar_t is native
|
||||
|
||||
// Prints a ::string object.
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
void PrintStringTo(const ::string& s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
#endif // GTEST_HAS_GLOBAL_STRING
|
||||
|
||||
void PrintStringTo(const ::std::string& s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
|
||||
// Prints a ::wstring object.
|
||||
#if GTEST_HAS_GLOBAL_WSTRING
|
||||
void PrintWideStringTo(const ::wstring& s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace testing
|
|
@ -1,110 +0,0 @@
|
|||
// Copyright 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: mheule@google.com (Markus Heule)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
|
||||
#include "gtest/gtest-test-part.h"
|
||||
|
||||
// Indicates that this translation unit is part of Google Test's
|
||||
// implementation. It must come before gtest-internal-inl.h is
|
||||
// included, or there will be a compiler error. This trick exists to
|
||||
// prevent the accidental inclusion of gtest-internal-inl.h in the
|
||||
// user's code.
|
||||
#define GTEST_IMPLEMENTATION_ 1
|
||||
#include "src/gtest-internal-inl.h"
|
||||
#undef GTEST_IMPLEMENTATION_
|
||||
|
||||
namespace testing {
|
||||
|
||||
using internal::GetUnitTestImpl;
|
||||
|
||||
// Gets the summary of the failure message by omitting the stack trace
|
||||
// in it.
|
||||
std::string TestPartResult::ExtractSummary(const char* message) {
|
||||
const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
|
||||
return stack_trace == NULL ? message :
|
||||
std::string(message, stack_trace);
|
||||
}
|
||||
|
||||
// Prints a TestPartResult object.
|
||||
std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
|
||||
return os
|
||||
<< result.file_name() << ":" << result.line_number() << ": "
|
||||
<< (result.type() == TestPartResult::kSuccess ? "Success" :
|
||||
result.type() == TestPartResult::kFatalFailure ? "Fatal failure" :
|
||||
"Non-fatal failure") << ":\n"
|
||||
<< result.message() << std::endl;
|
||||
}
|
||||
|
||||
// Appends a TestPartResult to the array.
|
||||
void TestPartResultArray::Append(const TestPartResult& result) {
|
||||
array_.push_back(result);
|
||||
}
|
||||
|
||||
// Returns the TestPartResult at the given index (0-based).
|
||||
const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
|
||||
if (index < 0 || index >= size()) {
|
||||
printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
|
||||
internal::posix::Abort();
|
||||
}
|
||||
|
||||
return array_[index];
|
||||
}
|
||||
|
||||
// Returns the number of TestPartResult objects in the array.
|
||||
int TestPartResultArray::size() const {
|
||||
return static_cast<int>(array_.size());
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
HasNewFatalFailureHelper::HasNewFatalFailureHelper()
|
||||
: has_new_fatal_failure_(false),
|
||||
original_reporter_(GetUnitTestImpl()->
|
||||
GetTestPartResultReporterForCurrentThread()) {
|
||||
GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this);
|
||||
}
|
||||
|
||||
HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {
|
||||
GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(
|
||||
original_reporter_);
|
||||
}
|
||||
|
||||
void HasNewFatalFailureHelper::ReportTestPartResult(
|
||||
const TestPartResult& result) {
|
||||
if (result.fatally_failed())
|
||||
has_new_fatal_failure_ = true;
|
||||
original_reporter_->ReportTestPartResult(result);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace testing
|
|
@ -1,118 +0,0 @@
|
|||
// Copyright 2008 Google Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
#include "gtest/gtest-typed-test.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
#if GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
// Skips to the first non-space char in str. Returns an empty string if str
|
||||
// contains only whitespace characters.
|
||||
static const char* SkipSpaces(const char* str) {
|
||||
while (IsSpace(*str))
|
||||
str++;
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::vector<std::string> SplitIntoTestNames(const char* src) {
|
||||
std::vector<std::string> name_vec;
|
||||
src = SkipSpaces(src);
|
||||
for (; src != NULL; src = SkipComma(src)) {
|
||||
name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src)));
|
||||
}
|
||||
return name_vec;
|
||||
}
|
||||
|
||||
// Verifies that registered_tests match the test names in
|
||||
// registered_tests_; returns registered_tests if successful, or
|
||||
// aborts the program otherwise.
|
||||
const char* TypedTestCasePState::VerifyRegisteredTestNames(
|
||||
const char* file, int line, const char* registered_tests) {
|
||||
typedef RegisteredTestsMap::const_iterator RegisteredTestIter;
|
||||
registered_ = true;
|
||||
|
||||
std::vector<std::string> name_vec = SplitIntoTestNames(registered_tests);
|
||||
|
||||
Message errors;
|
||||
|
||||
std::set<std::string> tests;
|
||||
for (std::vector<std::string>::const_iterator name_it = name_vec.begin();
|
||||
name_it != name_vec.end(); ++name_it) {
|
||||
const std::string& name = *name_it;
|
||||
if (tests.count(name) != 0) {
|
||||
errors << "Test " << name << " is listed more than once.\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (RegisteredTestIter it = registered_tests_.begin();
|
||||
it != registered_tests_.end();
|
||||
++it) {
|
||||
if (name == it->first) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
tests.insert(name);
|
||||
} else {
|
||||
errors << "No test named " << name
|
||||
<< " can be found in this test case.\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (RegisteredTestIter it = registered_tests_.begin();
|
||||
it != registered_tests_.end();
|
||||
++it) {
|
||||
if (tests.count(it->first) == 0) {
|
||||
errors << "You forgot to list test " << it->first << ".\n";
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& errors_str = errors.GetString();
|
||||
if (errors_str != "") {
|
||||
fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
|
||||
errors_str.c_str());
|
||||
fflush(stderr);
|
||||
posix::Abort();
|
||||
}
|
||||
|
||||
return registered_tests;
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
File diff suppressed because it is too large
Load Diff
|
@ -1,38 +0,0 @@
|
|||
// Copyright 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
GTEST_API_ int main(int argc, char **argv) {
|
||||
printf("Running main() from gtest_main.cc\n");
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
|
@ -80,7 +80,6 @@ add_executable(unit_tests
|
|||
test_peerlist.cpp
|
||||
test_protocol_pack.cpp
|
||||
threadpool.cpp
|
||||
hardfork.cpp
|
||||
unbound.cpp
|
||||
uri.cpp
|
||||
varint.cpp
|
||||
|
|
|
@ -156,7 +156,7 @@ template <typename T>
|
|||
class BlockchainDBTest : public testing::Test
|
||||
{
|
||||
protected:
|
||||
BlockchainDBTest() : m_db(new T()), m_hardfork(*m_db, 1, 0)
|
||||
BlockchainDBTest() : m_db(new T())
|
||||
{
|
||||
for (auto& i : t_blocks)
|
||||
{
|
||||
|
@ -185,18 +185,11 @@ protected:
|
|||
}
|
||||
|
||||
BlockchainDB* m_db;
|
||||
HardFork m_hardfork;
|
||||
fs::path m_prefix;
|
||||
std::vector<std::pair<block, blobdata>> m_blocks;
|
||||
std::vector<std::vector<std::pair<transaction, blobdata>>> m_txs;
|
||||
std::vector<fs::path> m_filenames;
|
||||
|
||||
void init_hard_fork()
|
||||
{
|
||||
m_hardfork.init();
|
||||
m_db->set_hard_fork(&m_hardfork);
|
||||
}
|
||||
|
||||
void get_filenames()
|
||||
{
|
||||
m_filenames = m_db->get_filenames();
|
||||
|
@ -265,7 +258,6 @@ TYPED_TEST(BlockchainDBTest, AddBlock)
|
|||
// make sure open does not throw
|
||||
ASSERT_NO_THROW(this->m_db->open(dirPath, cryptonote::FAKECHAIN));
|
||||
this->get_filenames();
|
||||
this->init_hard_fork();
|
||||
|
||||
db_wtxn_guard guard(this->m_db);
|
||||
|
||||
|
@ -313,7 +305,6 @@ TYPED_TEST(BlockchainDBTest, RetrieveBlockData)
|
|||
// make sure open does not throw
|
||||
ASSERT_NO_THROW(this->m_db->open(dirPath, cryptonote::FAKECHAIN));
|
||||
this->get_filenames();
|
||||
this->init_hard_fork();
|
||||
|
||||
db_wtxn_guard guard(this->m_db);
|
||||
|
||||
|
|
|
@ -1,609 +0,0 @@
|
|||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include <algorithm>
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "blockchain_db/testdb.h"
|
||||
#include "checkpoints/checkpoints.h"
|
||||
|
||||
using namespace cryptonote;
|
||||
|
||||
#define BLOCKS_PER_YEAR 525960
|
||||
#define SECONDS_PER_YEAR 31557600
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class TestDB: public cryptonote::BaseTestDB {
|
||||
public:
|
||||
virtual uint64_t height() const override { return blocks.size(); }
|
||||
virtual void add_block( const block& blk
|
||||
, size_t block_weight
|
||||
, uint64_t long_term_block_weight
|
||||
, const difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, uint64_t num_rct_outs
|
||||
, const crypto::hash& blk_hash
|
||||
) override {
|
||||
blocks.push_back(blk);
|
||||
}
|
||||
virtual void remove_block() override { blocks.pop_back(); }
|
||||
virtual block get_block_from_height(uint64_t height) const override {
|
||||
return blocks.at(height);
|
||||
}
|
||||
virtual void set_hard_fork_version(uint64_t height, uint8_t version) override {
|
||||
if (versions.size() <= height)
|
||||
versions.resize(height+1);
|
||||
versions[height] = version;
|
||||
}
|
||||
virtual uint8_t get_hard_fork_version(uint64_t height) const override {
|
||||
return versions.at(height);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<block> blocks;
|
||||
std::deque<uint8_t> versions;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static cryptonote::block mkblock(uint8_t version, uint8_t vote)
|
||||
{
|
||||
cryptonote::block b;
|
||||
b.major_version = version;
|
||||
b.minor_version = vote;
|
||||
return b;
|
||||
}
|
||||
|
||||
static cryptonote::block mkblock(const HardFork &hf, uint64_t height, uint8_t vote)
|
||||
{
|
||||
cryptonote::block b;
|
||||
b.major_version = hf.get(height);
|
||||
b.minor_version = vote;
|
||||
return b;
|
||||
}
|
||||
|
||||
TEST(hardfork, major_only)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 0, 0, 1, 0); // no voting
|
||||
|
||||
// v h t
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 2, 1));
|
||||
hf.init();
|
||||
|
||||
// block height 0, only version 1 is accepted
|
||||
ASSERT_FALSE(hf.add(mkblock(0, 2), 0));
|
||||
ASSERT_FALSE(hf.add(mkblock(2, 2), 0));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 2), 0));
|
||||
db.add_block(mkblock(1, 1), 0, 0, 0, 0, 0, crypto::hash());
|
||||
|
||||
// block height 1, only version 1 is accepted
|
||||
ASSERT_FALSE(hf.add(mkblock(0, 2), 1));
|
||||
ASSERT_FALSE(hf.add(mkblock(2, 2), 1));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 2), 1));
|
||||
db.add_block(mkblock(1, 1), 0, 0, 0, 0, 0, crypto::hash());
|
||||
|
||||
// block height 2, only version 2 is accepted
|
||||
ASSERT_FALSE(hf.add(mkblock(0, 2), 2));
|
||||
ASSERT_FALSE(hf.add(mkblock(1, 2), 2));
|
||||
ASSERT_FALSE(hf.add(mkblock(3, 2), 2));
|
||||
ASSERT_TRUE(hf.add(mkblock(2, 2), 2));
|
||||
db.add_block(mkblock(2, 1), 0, 0, 0, 0, 0, crypto::hash());
|
||||
}
|
||||
|
||||
TEST(hardfork, empty_hardforks_success)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db);
|
||||
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
hf.init();
|
||||
ASSERT_TRUE(hf.get_state(time(NULL)) == HardFork::Ready);
|
||||
ASSERT_TRUE(hf.get_state(time(NULL) + 3600*24*400) == HardFork::Ready);
|
||||
|
||||
for (uint64_t h = 0; h <= 10; ++h) {
|
||||
db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, 0, crypto::hash());
|
||||
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
|
||||
}
|
||||
ASSERT_EQ(hf.get(0), 1);
|
||||
ASSERT_EQ(hf.get(1), 1);
|
||||
ASSERT_EQ(hf.get(10), 1);
|
||||
}
|
||||
|
||||
TEST(hardfork, ordering_success)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db);
|
||||
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 2, 1));
|
||||
ASSERT_ANY_THROW(hf.add_fork(3, 3, 0));
|
||||
ASSERT_ANY_THROW(hf.add_fork(3, 2, 2));
|
||||
ASSERT_ANY_THROW(hf.add_fork(2, 3, 2));
|
||||
ASSERT_NO_THROW(hf.add_fork(3, 10, 2));
|
||||
ASSERT_NO_THROW(hf.add_fork(4, 20, 3));
|
||||
ASSERT_ANY_THROW(hf.add_fork(5, 5, 4));
|
||||
}
|
||||
|
||||
TEST(hardfork, check_for_height_success)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 0, 0, 1, 0); // no voting
|
||||
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 5, 1));
|
||||
hf.init();
|
||||
|
||||
for (uint64_t h = 0; h <= 4; ++h) {
|
||||
ASSERT_TRUE(hf.check_for_height(mkblock(1, 1), h));
|
||||
ASSERT_FALSE(hf.check_for_height(mkblock(2, 2), h)); // block version is too high
|
||||
db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, 0, crypto::hash());
|
||||
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
|
||||
}
|
||||
|
||||
for (uint64_t h = 5; h <= 10; ++h) {
|
||||
ASSERT_FALSE(hf.check_for_height(mkblock(1, 1), h)); // block version is too low
|
||||
ASSERT_TRUE(hf.check_for_height(mkblock(2, 2), h));
|
||||
db.add_block(mkblock(hf, h, 2), 0, 0, 0, 0, 0, crypto::hash());
|
||||
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(hardfork, get_next_version)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db);
|
||||
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 5, 1));
|
||||
ASSERT_NO_THROW(hf.add_fork(4, 10, 2));
|
||||
hf.init();
|
||||
|
||||
for (uint64_t h = 0; h <= 4; ++h) {
|
||||
ASSERT_EQ(2, hf.get_next_version());
|
||||
db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, 0, crypto::hash());
|
||||
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
|
||||
}
|
||||
|
||||
for (uint64_t h = 5; h <= 9; ++h) {
|
||||
ASSERT_EQ(4, hf.get_next_version());
|
||||
db.add_block(mkblock(hf, h, 2), 0, 0, 0, 0, 0, crypto::hash());
|
||||
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
|
||||
}
|
||||
|
||||
for (uint64_t h = 10; h <= 15; ++h) {
|
||||
ASSERT_EQ(4, hf.get_next_version());
|
||||
db.add_block(mkblock(hf, h, 4), 0, 0, 0, 0, 0, crypto::hash());
|
||||
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(hardfork, states_success)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db);
|
||||
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(2, BLOCKS_PER_YEAR, SECONDS_PER_YEAR));
|
||||
|
||||
ASSERT_TRUE(hf.get_state(0) == HardFork::Ready);
|
||||
ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR / 2) == HardFork::Ready);
|
||||
ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR + HardFork::DEFAULT_UPDATE_TIME / 2) == HardFork::Ready);
|
||||
ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR + (HardFork::DEFAULT_UPDATE_TIME + HardFork::DEFAULT_FORKED_TIME) / 2) == HardFork::UpdateNeeded);
|
||||
ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR + HardFork::DEFAULT_FORKED_TIME * 2) == HardFork::LikelyForked);
|
||||
|
||||
ASSERT_NO_THROW(hf.add_fork(3, BLOCKS_PER_YEAR * 5, SECONDS_PER_YEAR * 5));
|
||||
|
||||
ASSERT_TRUE(hf.get_state(0) == HardFork::Ready);
|
||||
ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR / 2) == HardFork::Ready);
|
||||
ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR + HardFork::DEFAULT_UPDATE_TIME / 2) == HardFork::Ready);
|
||||
ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR + (HardFork::DEFAULT_UPDATE_TIME + HardFork::DEFAULT_FORKED_TIME) / 2) == HardFork::Ready);
|
||||
ASSERT_TRUE(hf.get_state(SECONDS_PER_YEAR + HardFork::DEFAULT_FORKED_TIME * 2) == HardFork::Ready);
|
||||
}
|
||||
|
||||
TEST(hardfork, steps_asap_success)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db, 1,1,1,1);
|
||||
|
||||
// v h t
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(4, 2, 1));
|
||||
ASSERT_NO_THROW(hf.add_fork(7, 4, 2));
|
||||
ASSERT_NO_THROW(hf.add_fork(9, 6, 3));
|
||||
hf.init();
|
||||
|
||||
for (uint64_t h = 0; h < 10; ++h) {
|
||||
db.add_block(mkblock(hf, h, 9), 0, 0, 0, 0, 0, crypto::hash());
|
||||
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
|
||||
}
|
||||
|
||||
ASSERT_EQ(hf.get(0), 1);
|
||||
ASSERT_EQ(hf.get(1), 1);
|
||||
ASSERT_EQ(hf.get(2), 4);
|
||||
ASSERT_EQ(hf.get(3), 4);
|
||||
ASSERT_EQ(hf.get(4), 7);
|
||||
ASSERT_EQ(hf.get(5), 7);
|
||||
ASSERT_EQ(hf.get(6), 9);
|
||||
ASSERT_EQ(hf.get(7), 9);
|
||||
ASSERT_EQ(hf.get(8), 9);
|
||||
ASSERT_EQ(hf.get(9), 9);
|
||||
}
|
||||
|
||||
TEST(hardfork, steps_1_success)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db, 1,1,1,1);
|
||||
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
for (int n = 1 ; n < 10; ++n)
|
||||
ASSERT_NO_THROW(hf.add_fork(n+1, n, n));
|
||||
hf.init();
|
||||
|
||||
for (uint64_t h = 0 ; h < 10; ++h) {
|
||||
db.add_block(mkblock(hf, h, h+1), 0, 0, 0, 0, 0, crypto::hash());
|
||||
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
|
||||
}
|
||||
|
||||
for (uint64_t h = 0; h < 10; ++h) {
|
||||
ASSERT_EQ(hf.get(h), std::max(1,(int)h));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(hardfork, reorganize_same)
|
||||
{
|
||||
for (int history = 1; history <= 12; ++history) {
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 1, 1, history, 100);
|
||||
|
||||
// v h t
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(4, 2, 1));
|
||||
ASSERT_NO_THROW(hf.add_fork(7, 4, 1)); // <- same timestamp should be allowed
|
||||
ASSERT_NO_THROW(hf.add_fork(9, 6, 1)); //
|
||||
hf.init();
|
||||
|
||||
// index 0 1 2 3 4 5 6 7 8 9
|
||||
static const uint8_t block_versions[] = { 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
|
||||
for (uint64_t h = 0; h < 20; ++h) {
|
||||
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, crypto::hash());
|
||||
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
|
||||
}
|
||||
|
||||
for (uint64_t rh = 0; rh < 20; ++rh) {
|
||||
hf.reorganize_from_block_height(rh);
|
||||
for (int hh = 0; hh < 20; ++hh) {
|
||||
uint8_t version = hh >= history ? block_versions[hh - history] : 1;
|
||||
ASSERT_EQ(hf.get(hh), version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(hardfork, reorganize_changed_1)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 1, 1, 4, 100);
|
||||
|
||||
// v h t
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(4, 2, 1));
|
||||
ASSERT_NO_THROW(hf.add_fork(7, 4, 2));
|
||||
ASSERT_NO_THROW(hf.add_fork(9, 6, 3));
|
||||
hf.init();
|
||||
|
||||
// fork 4 7 9
|
||||
// index 0 1 2 3 4 5 6 7 8 9
|
||||
static const uint8_t block_versions[] = { 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
|
||||
static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9 };
|
||||
for (uint64_t h = 0; h < 16; ++h) {
|
||||
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, crypto::hash());
|
||||
ASSERT_TRUE (hf.add(db.get_block_from_height(h), h));
|
||||
}
|
||||
|
||||
for (uint64_t rh = 0; rh < 16; ++rh) {
|
||||
hf.reorganize_from_block_height(rh);
|
||||
for (int hh = 0; hh < 16; ++hh) {
|
||||
ASSERT_EQ(hf.get(hh), expected_versions[hh]);
|
||||
}
|
||||
}
|
||||
|
||||
// delay a bit for 9, and go back to 1 to check it stays at 9
|
||||
static const uint8_t block_versions_new[] = { 1, 1, 4, 4, 7, 7, 4, 7, 7, 7, 9, 9, 9, 9, 9, 1 };
|
||||
static const uint8_t expected_versions_new[] = { 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 7, 7, 7, 9, 9 };
|
||||
for (uint64_t h = 3; h < 16; ++h) {
|
||||
db.remove_block();
|
||||
}
|
||||
ASSERT_EQ(db.height(), 3);
|
||||
hf.reorganize_from_block_height(2);
|
||||
for (uint64_t h = 3; h < 16; ++h) {
|
||||
db.add_block(mkblock(hf, h, block_versions_new[h]), 0, 0, 0, 0, 0, crypto::hash());
|
||||
bool ret = hf.add(db.get_block_from_height(h), h);
|
||||
ASSERT_EQ (ret, h < 15);
|
||||
}
|
||||
db.remove_block(); // last block added to the blockchain, but not hf
|
||||
ASSERT_EQ(db.height(), 15);
|
||||
for (int hh = 0; hh < 15; ++hh) {
|
||||
ASSERT_EQ(hf.get(hh), expected_versions_new[hh]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(hardfork, voting_threshold)
|
||||
{
|
||||
for (int threshold = 87; threshold <= 88; ++threshold) {
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 1, 1, 8, threshold);
|
||||
|
||||
// v h t
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 2, 1));
|
||||
hf.init();
|
||||
|
||||
for (uint64_t h = 0; h <= 8; ++h) {
|
||||
uint8_t v = 1 + !!(h % 8);
|
||||
db.add_block(mkblock(hf, h, v), 0, 0, 0, 0, 0, crypto::hash());
|
||||
bool ret = hf.add(db.get_block_from_height(h), h);
|
||||
if (h >= 8 && threshold == 87) {
|
||||
// for threshold 87, we reach the treshold at height 7, so from height 8, hard fork to version 2, but 8 tries to add 1
|
||||
ASSERT_FALSE(ret);
|
||||
}
|
||||
else {
|
||||
// for threshold 88, we never reach the threshold
|
||||
ASSERT_TRUE(ret);
|
||||
uint8_t expected = threshold == 88 ? 1 : h < 8 ? 1 : 2;
|
||||
ASSERT_EQ(hf.get(h), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(hardfork, voting_different_thresholds)
|
||||
{
|
||||
for (int threshold = 87; threshold <= 88; ++threshold) {
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 1, 1, 4, 50); // window size 4
|
||||
|
||||
// v h t
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 5, 0, 1)); // asap
|
||||
ASSERT_NO_THROW(hf.add_fork(3, 10, 100, 2)); // all votes
|
||||
ASSERT_NO_THROW(hf.add_fork(4, 15, 3)); // default 50% votes
|
||||
hf.init();
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
|
||||
static const uint8_t block_versions[] = { 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4 };
|
||||
static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 };
|
||||
|
||||
for (uint64_t h = 0; h < sizeof(block_versions) / sizeof(block_versions[0]); ++h) {
|
||||
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, crypto::hash());
|
||||
bool ret = hf.add(db.get_block_from_height(h), h);
|
||||
ASSERT_EQ(ret, true);
|
||||
}
|
||||
for (uint64_t h = 0; h < sizeof(expected_versions) / sizeof(expected_versions[0]); ++h) {
|
||||
ASSERT_EQ(hf.get(h), expected_versions[h]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(hardfork, voting_info)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 1, 1, 4, 50); // window size 4, default threshold 50%
|
||||
|
||||
// v h ts
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
// v h thr ts
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 5, 0, 1)); // asap
|
||||
ASSERT_NO_THROW(hf.add_fork(3, 10, 100, 2)); // all votes
|
||||
// v h ts
|
||||
ASSERT_NO_THROW(hf.add_fork(4, 15, 3)); // default 50% votes
|
||||
hf.init();
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
|
||||
static const uint8_t block_versions[] = { 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4 };
|
||||
static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 };
|
||||
static const uint8_t expected_thresholds[] = { 0, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 2, 2, 2, 2 };
|
||||
|
||||
for (uint64_t h = 0; h < sizeof(block_versions) / sizeof(block_versions[0]); ++h) {
|
||||
uint32_t window, votes, threshold;
|
||||
uint64_t earliest_height;
|
||||
uint8_t voting;
|
||||
|
||||
ASSERT_TRUE(hf.get_voting_info(1, window, votes, threshold, earliest_height, voting));
|
||||
ASSERT_EQ(std::min<uint64_t>(h, 4), votes);
|
||||
ASSERT_EQ(0, earliest_height);
|
||||
|
||||
ASSERT_EQ(hf.get_current_version() >= 2, hf.get_voting_info(2, window, votes, threshold, earliest_height, voting));
|
||||
ASSERT_EQ(std::min<uint64_t>(h <= 3 ? 0 : h - 3, 4), votes);
|
||||
ASSERT_EQ(5, earliest_height);
|
||||
|
||||
ASSERT_EQ(hf.get_current_version() >= 3, hf.get_voting_info(3, window, votes, threshold, earliest_height, voting));
|
||||
ASSERT_EQ(std::min<uint64_t>(h <= 8 ? 0 : h - 8, 4), votes);
|
||||
ASSERT_EQ(10, earliest_height);
|
||||
|
||||
ASSERT_EQ(hf.get_current_version() == 4, hf.get_voting_info(4, window, votes, threshold, earliest_height, voting));
|
||||
ASSERT_EQ(std::min<uint64_t>(h <= 14 ? 0 : h - 14, 4), votes);
|
||||
ASSERT_EQ(15, earliest_height);
|
||||
|
||||
ASSERT_EQ(std::min<uint64_t>(h, 4), window);
|
||||
ASSERT_EQ(expected_thresholds[h], threshold);
|
||||
ASSERT_EQ(4, voting);
|
||||
|
||||
db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, 0, crypto::hash());
|
||||
ASSERT_TRUE(hf.add(db.get_block_from_height(h), h));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(hardfork, new_blocks_denied)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 1, 1, 4, 50);
|
||||
|
||||
// v h t
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 2, 1));
|
||||
hf.init();
|
||||
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 1), 0));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 1), 1));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 1), 2));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 2), 3));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 1), 4));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 1), 5));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 1), 6));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 2), 7));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 2), 8)); // we reach 50% of the last 4
|
||||
ASSERT_FALSE(hf.add(mkblock(2, 1), 9)); // so this one can't get added
|
||||
ASSERT_TRUE(hf.add(mkblock(2, 2), 9));
|
||||
}
|
||||
|
||||
TEST(hardfork, new_version_early)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 1, 1, 4, 50);
|
||||
|
||||
// v h t
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 4, 1));
|
||||
hf.init();
|
||||
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 2), 0));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 2), 1)); // we have enough votes already
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 2), 2));
|
||||
ASSERT_TRUE(hf.add(mkblock(1, 1), 3)); // we accept a previous version because we did not switch, even with all the votes
|
||||
ASSERT_TRUE(hf.add(mkblock(2, 2), 4)); // but have to wait for the declared height anyway
|
||||
ASSERT_TRUE(hf.add(mkblock(2, 2), 5));
|
||||
ASSERT_FALSE(hf.add(mkblock(2, 1), 6)); // we don't accept 1 anymore
|
||||
ASSERT_TRUE(hf.add(mkblock(2, 2), 7)); // but we do accept 2
|
||||
}
|
||||
|
||||
TEST(hardfork, reorganize_changed_2)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 1, 1, 4, 50);
|
||||
|
||||
// v h t
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 2, 1));
|
||||
ASSERT_NO_THROW(hf.add_fork(3, 5, 2));
|
||||
ASSERT_NO_THROW(hf.add_fork(4, 555, 222));
|
||||
hf.init();
|
||||
|
||||
#define ADD(v, h, a) \
|
||||
do { \
|
||||
cryptonote::block b = mkblock(hf, h, v); \
|
||||
db.add_block(b, 0, 0, 0, 0, 0, crypto::hash()); \
|
||||
ASSERT_##a(hf.add(b, h)); \
|
||||
} while(0)
|
||||
#define ADD_TRUE(v, h) ADD(v, h, TRUE)
|
||||
#define ADD_FALSE(v, h) ADD(v, h, FALSE)
|
||||
|
||||
ADD_TRUE(1, 0);
|
||||
ADD_TRUE(1, 1);
|
||||
ADD_TRUE(2, 2);
|
||||
ADD_TRUE(2, 3); // switch to 2 here
|
||||
ADD_TRUE(2, 4);
|
||||
ADD_TRUE(2, 5);
|
||||
ADD_TRUE(2, 6);
|
||||
ASSERT_EQ(hf.get_current_version(), 2);
|
||||
ADD_TRUE(3, 7);
|
||||
ADD_TRUE(4, 8);
|
||||
ADD_TRUE(4, 9);
|
||||
ASSERT_EQ(hf.get_current_version(), 3);
|
||||
|
||||
// pop a few blocks and check current version goes back down
|
||||
db.remove_block();
|
||||
hf.reorganize_from_block_height(8);
|
||||
ASSERT_EQ(hf.get_current_version(), 3);
|
||||
db.remove_block();
|
||||
hf.reorganize_from_block_height(7);
|
||||
ASSERT_EQ(hf.get_current_version(), 2);
|
||||
db.remove_block();
|
||||
ASSERT_EQ(hf.get_current_version(), 2);
|
||||
|
||||
// add blocks again, but remaining at 2
|
||||
ADD_TRUE(2, 7);
|
||||
ADD_TRUE(2, 8);
|
||||
ADD_TRUE(2, 9);
|
||||
ASSERT_EQ(hf.get_current_version(), 2); // we did not bump to 3 this time
|
||||
}
|
||||
|
||||
TEST(hardfork, get_higher)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 1, 1, 4, 50);
|
||||
|
||||
// v h t
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 2, 1));
|
||||
ASSERT_NO_THROW(hf.add_fork(3, 5, 2));
|
||||
hf.init();
|
||||
|
||||
ASSERT_EQ(hf.get_ideal_version(0), 1);
|
||||
ASSERT_EQ(hf.get_ideal_version(1), 1);
|
||||
ASSERT_EQ(hf.get_ideal_version(2), 2);
|
||||
ASSERT_EQ(hf.get_ideal_version(3), 2);
|
||||
ASSERT_EQ(hf.get_ideal_version(4), 2);
|
||||
ASSERT_EQ(hf.get_ideal_version(5), 3);
|
||||
ASSERT_EQ(hf.get_ideal_version(6), 3);
|
||||
ASSERT_EQ(hf.get_ideal_version(7), 3);
|
||||
}
|
||||
|
||||
TEST(hardfork, get_earliest_ideal_height)
|
||||
{
|
||||
TestDB db;
|
||||
HardFork hf(db, 1, 1, 1, 4, 50);
|
||||
|
||||
// v h t
|
||||
ASSERT_NO_THROW(hf.add_fork(1, 0, 0));
|
||||
ASSERT_NO_THROW(hf.add_fork(2, 2, 1));
|
||||
ASSERT_NO_THROW(hf.add_fork(5, 5, 2));
|
||||
ASSERT_NO_THROW(hf.add_fork(6, 10, 3));
|
||||
ASSERT_NO_THROW(hf.add_fork(9, 15, 4));
|
||||
hf.init();
|
||||
|
||||
ASSERT_EQ(hf.get_earliest_ideal_height_for_version(1), 0);
|
||||
ASSERT_EQ(hf.get_earliest_ideal_height_for_version(2), 2);
|
||||
ASSERT_EQ(hf.get_earliest_ideal_height_for_version(3), 5);
|
||||
ASSERT_EQ(hf.get_earliest_ideal_height_for_version(4), 5);
|
||||
ASSERT_EQ(hf.get_earliest_ideal_height_for_version(5), 5);
|
||||
ASSERT_EQ(hf.get_earliest_ideal_height_for_version(6), 10);
|
||||
ASSERT_EQ(hf.get_earliest_ideal_height_for_version(7), 15);
|
||||
ASSERT_EQ(hf.get_earliest_ideal_height_for_version(8), 15);
|
||||
ASSERT_EQ(hf.get_earliest_ideal_height_for_version(9), 15);
|
||||
ASSERT_EQ(hf.get_earliest_ideal_height_for_version(10), std::numeric_limits<uint64_t>::max());
|
||||
}
|
||||
|
|
@ -110,16 +110,14 @@ static uint32_t lcg()
|
|||
|
||||
#define PREFIX_WINDOW(hf_version,window) \
|
||||
blockchain_objects_t bc_objects = {}; \
|
||||
struct get_test_options { \
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks; \
|
||||
const cryptonote::test_options test_options = { \
|
||||
hard_forks, \
|
||||
window, \
|
||||
}; \
|
||||
get_test_options(): hard_forks{{std::make_pair(cryptonote::network_version_7, (uint64_t)0), std::make_pair((uint8_t)hf_version, (uint64_t)1)}} {} \
|
||||
} opts; \
|
||||
const std::vector<cryptonote::hard_fork> hard_forks{ \
|
||||
{7,0,0,0}, {hf_version,0,1,0}}; \
|
||||
const cryptonote::test_options test_options = { \
|
||||
hard_forks, \
|
||||
window, \
|
||||
}; \
|
||||
cryptonote::Blockchain *bc = &bc_objects.m_blockchain; \
|
||||
bool r = bc->init(new ::TestDB(), nullptr /*ons_db*/, cryptonote::FAKECHAIN, true, &opts.test_options, 0); \
|
||||
bool r = bc->init(new ::TestDB(), nullptr /*ons_db*/, cryptonote::FAKECHAIN, true, &test_options, 0); \
|
||||
ASSERT_TRUE(r)
|
||||
|
||||
#define PREFIX(hf_version) PREFIX_WINDOW(hf_version, TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW)
|
||||
|
|
|
@ -83,11 +83,10 @@ bool get_output_distribution(uint64_t amount, uint64_t from, uint64_t to, uint64
|
|||
{
|
||||
blockchain_objects_t bc = {};
|
||||
struct get_test_options {
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks;
|
||||
const std::vector<cryptonote::hard_fork> hard_forks{{1,0,0,0}};
|
||||
const cryptonote::test_options test_options = {
|
||||
hard_forks
|
||||
};
|
||||
get_test_options():hard_forks{{std::make_pair((uint8_t)1, (uint64_t)0)}}{}
|
||||
} opts;
|
||||
cryptonote::Blockchain *blockchain = &bc.m_blockchain;
|
||||
bool r = blockchain->init(new TestDB(test_distribution_size), nullptr /*ons_db*/, cryptonote::FAKECHAIN, true, &opts.test_options, 0, NULL);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue