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:
Jason Rhinelander 2021-07-06 20:46:43 -03:00 committed by GitHub
commit 2e7e47a005
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 663 additions and 36451 deletions

View File

@ -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")

View File

@ -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}

2
external/googletest vendored

@ -1 +1 @@
Subproject commit 703bd9caab50b139428cea1aaff9974ebee5742e
Subproject commit e2239ee6043f73722e7aa812a459f54a28552929

View File

@ -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);

View File

@ -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

View File

@ -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));
}
}

View File

@ -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);

View File

@ -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; }

View File

@ -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());

View File

@ -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);

View File

@ -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;
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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
*

View File

@ -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();

View File

@ -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)

View File

@ -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);

View File

@ -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)
{
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:

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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();

View File

@ -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 << ")");

View File

@ -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;

View File

@ -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);

View File

@ -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); }

View File

@ -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;

View File

@ -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);

View File

@ -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) + "'"};

View File

@ -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()

View File

@ -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

View File

@ -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; }
}

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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();

View File

@ -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(

View File

@ -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)
{

View File

@ -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; }

View File

@ -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);

View File

@ -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();

View File

@ -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();

View File

@ -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
};

View File

@ -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));

View File

@ -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
};

View File

@ -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
};

View File

@ -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

View File

@ -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()

View File

@ -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>

View File

@ -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.

View File

@ -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.

View File

@ -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()

View File

@ -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_

View File

@ -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

View File

@ -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, \
&gtest_##prefix##test_case_name##_EvalGenerator_, \
&gtest_##prefix##test_case_name##_EvalGenerateName_, \
__FILE__, __LINE__)
} // namespace testing
#endif // GTEST_HAS_PARAM_TEST
#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_

View File

@ -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_

View File

@ -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(\
&gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
{\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter:: \
INTERCEPT_ONLY_CURRENT_THREAD, &gtest_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(\
&gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
{\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter:: \
INTERCEPT_ALL_THREADS, &gtest_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(\
&gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
(substr));\
{\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter:: \
INTERCEPT_ONLY_CURRENT_THREAD, &gtest_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(\
&gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
(substr));\
{\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
&gtest_failures);\
if (::testing::internal::AlwaysTrue()) { statement; }\
}\
} while (::testing::internal::AlwaysFalse())
#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_

View File

@ -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_

View File

@ -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__), \
&GTEST_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

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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, &gtest_regex, \
__FILE__, __LINE__, &gtest_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_

View File

@ -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

View File

@ -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

View File

@ -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 &current_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_

View File

@ -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(&parameter_);
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_

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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);

View File

@ -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());
}

View File

@ -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)

View File

@ -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