21#include <boost/test/unit_test.hpp>
58 void SetupArgs(
const std::vector<std::pair<std::string, unsigned int>>&
args)
60 for (
const auto& arg :
args) {
99 const char* argv[] = {
"ignored", arg};
105 if (
expect.setting.isNull() ||
expect.setting.isFalse()) {
114 BOOST_CHECK_NE(error.find(
expect.error), std::string::npos);
120 if (
expect.default_string) {
122 }
else if (
expect.string_value) {
130 }
else if (
expect.int_value) {
136 if (
expect.default_bool) {
139 }
else if (
expect.bool_value) {
147 auto l = test.
GetArgs(
"-value");
148 BOOST_CHECK_EQUAL_COLLECTIONS(l.begin(), l.end(),
expect.list_value->begin(),
expect.list_value->end());
159 CheckValue(M::ALLOW_ANY,
nullptr, Expect{{}}.DefaultString().DefaultInt().DefaultBool().List({}));
160 CheckValue(M::ALLOW_ANY,
"-novalue", Expect{
false}.String(
"0").Int(0).Bool(
false).List({}));
161 CheckValue(M::ALLOW_ANY,
"-novalue=", Expect{
false}.String(
"0").Int(0).Bool(
false).List({}));
162 CheckValue(M::ALLOW_ANY,
"-novalue=0", Expect{
true}.String(
"1").Int(1).Bool(
true).List({
"1"}));
163 CheckValue(M::ALLOW_ANY,
"-novalue=1", Expect{
false}.String(
"0").Int(0).Bool(
false).List({}));
164 CheckValue(M::ALLOW_ANY,
"-novalue=2", Expect{
false}.String(
"0").Int(0).Bool(
false).List({}));
165 CheckValue(M::ALLOW_ANY,
"-novalue=abc", Expect{
true}.String(
"1").Int(1).Bool(
true).List({
"1"}));
166 CheckValue(M::ALLOW_ANY,
"-value", Expect{
""}.String(
"").Int(0).Bool(
true).List({
""}));
167 CheckValue(M::ALLOW_ANY,
"-value=", Expect{
""}.String(
"").Int(0).Bool(
true).List({
""}));
168 CheckValue(M::ALLOW_ANY,
"-value=0", Expect{
"0"}.String(
"0").Int(0).Bool(
false).List({
"0"}));
169 CheckValue(M::ALLOW_ANY,
"-value=1", Expect{
"1"}.String(
"1").Int(1).Bool(
true).List({
"1"}));
170 CheckValue(M::ALLOW_ANY,
"-value=2", Expect{
"2"}.String(
"2").Int(2).Bool(
true).List({
"2"}));
171 CheckValue(M::ALLOW_ANY,
"-value=abc", Expect{
"abc"}.String(
"abc").Int(0).Bool(
false).List({
"abc"}));
179 std::array argv{
"ignored", arg};
189 BOOST_CHECK_EQUAL(
Parse(
"-includeconf"),
"-includeconf cannot be used from commandline; -includeconf=\"\"");
190 BOOST_CHECK_EQUAL(
Parse(
"-includeconf=file"),
"-includeconf cannot be used from commandline; -includeconf=\"file\"");
201 const char *argv_test[] = {
"-ignored",
"-a",
"-b",
"-ccc=argument",
"-ccc=multiple",
"f",
"-d=e"};
235 BOOST_CHECK(
s.command_line_options.at(
"a").size() == 1);
236 BOOST_CHECK(
s.command_line_options.at(
"a").front().get_str() ==
"");
237 BOOST_CHECK(
s.command_line_options.at(
"ccc").size() == 2);
238 BOOST_CHECK(
s.command_line_options.at(
"ccc").front().get_str() ==
"argument");
239 BOOST_CHECK(
s.command_line_options.at(
"ccc").back().get_str() ==
"multiple");
249 const char* argv[] = {
"ignored",
"-registered"};
254 argv[1] =
"-unregistered";
260 argv[1] =
"-test.registered";
265static void TestParse(
const std::string& str,
bool expected_bool, int64_t expected_int)
269 std::string arg =
"-value=" + str;
270 const char* argv[] = {
"ignored", arg.c_str()};
329 const char *argv_test[] = {
330 "ignored",
"-a",
"-nob",
"-c=0",
"-d=1",
"-e=false",
"-f=true"};
336 for (
const char opt :
"abcdef")
369 const char *argv_test[] = {
"ignored",
"-nofoo",
"-foo",
"-nobar=0"};
383 const char *conf_test =
"nofoo=1\nfoo=1\nnobar=0\n";
397 const char *combo_test_args[] = {
"ignored",
"-nofoo",
"-bar"};
398 const char *combo_test_conf =
"foo=1\nnobar=1\n";
410 BOOST_REQUIRE(testArgs.
GetArgs(
"-bar").size() == 1);
416 const char *str_config =
449 test_args.
SetupArgs({a, b, ccc, d, e, fff, ggg, h, i, iii});
498 for (
const bool def : {
false,
true}) {
511 BOOST_REQUIRE(test_args.
GetArgs(
"-a").size() == 1);
513 BOOST_REQUIRE(test_args.
GetArgs(
"-b").size() == 1);
515 BOOST_REQUIRE(test_args.
GetArgs(
"-ccc").size() == 2);
520 BOOST_REQUIRE(test_args.
GetArgs(
"-ggg").size() == 1);
525 BOOST_REQUIRE(test_args.
GetArgs(
"-i").size() == 1);
557 const std::vector<std::string> sec1_ccc_expected = {
"extend1",
"extend2",
"argument",
"multiple"};
558 const auto& sec1_ccc_res = test_args.
GetArgs(
"-ccc");
559 BOOST_CHECK_EQUAL_COLLECTIONS(sec1_ccc_res.begin(), sec1_ccc_res.end(), sec1_ccc_expected.begin(), sec1_ccc_expected.end());
576 const std::vector<std::string> sec2_ccc_expected = {
"extend3",
"argument",
"multiple"};
577 const auto& sec2_ccc_res = test_args.
GetArgs(
"-ccc");
578 BOOST_CHECK_EQUAL_COLLECTIONS(sec2_ccc_res.begin(), sec2_ccc_res.end(), sec2_ccc_expected.begin(), sec2_ccc_expected.end());
586 test_args.
SetupArgs({a, b, ccc2, d2, e, fff, ggg, h2, i, iii});
611 s.command_line_options.clear();
612 s.command_line_options[
"strtest1"] = {
"string..."};
614 s.command_line_options[
"inttest1"] = {
"12345"};
615 s.command_line_options[
"inttest2"] = {
"81985529216486895"};
617 s.command_line_options[
"booltest1"] = {
""};
619 s.command_line_options[
"booltest3"] = {
"0"};
620 s.command_line_options[
"booltest4"] = {
"1"};
623 s.command_line_options[
"pritest1"] = {
"a",
"b"};
624 s.ro_config[
""][
"pritest2"] = {
"a",
"b"};
625 s.command_line_options[
"pritest3"] = {
"a"};
626 s.ro_config[
""][
"pritest3"] = {
"b"};
627 s.command_line_options[
"pritest4"] = {
"a",
"b"};
628 s.ro_config[
""][
"pritest4"] = {
"c",
"d"};
649 enum TestFail { SUCCESS,
653 COMMAND_OPTS_BAD_DETAILS,
656 auto testfn = [&](
const auto& argv) -> TestFail {
662 test_args.
AddCommand(
"cmd1",
"No specific options");
663 test_args.
AddCommand(
"cmd2",
"Opt 1", {
"-opt1"});
664 test_args.
AddCommand(
"cmd3",
"Opt 1 or 2", {
"-opt1",
"-opt2"});
667 if (!test_args.
ParseParameters(argv.size(), argv.data(), error))
return PARSE_FAIL;
668 if (!error.empty())
return PARSE_ERROR;
670 if (!
command)
return NO_COMMAND;
671 std::vector<std::string> details;
673 if (details.empty())
return COMMAND_OPTS_BAD_DETAILS;
675 }
else if (!details.empty()) {
676 return COMMAND_OPTS_BAD_DETAILS;
693 BOOST_CHECK_EQUAL(COMMAND_OPTS, testfn(std::array{
"x",
"-opt1=foo",
"-opt3=bar",
"-opt2=baz",
"cmd1"}));
694 BOOST_CHECK_EQUAL(COMMAND_OPTS, testfn(std::array{
"x",
"-opt1=foo",
"-opt3=bar",
"-opt2=baz",
"cmd2"}));
695 BOOST_CHECK_EQUAL(SUCCESS, testfn(std::array{
"x",
"-opt1=foo",
"-opt3=bar",
"-opt2=baz",
"cmd3"}));
704 const auto add_command{[&](
TestArgsManager& test_args,
const std::string& option) {
710 add_command(test_args,
"-opt1");
712 add_command(test_args,
"-opt2");
718 std::vector<std::string> details;
729 test_args.
SetupArgs({testnet, testnet4, regtest});
731 const char* argv_testnet4[] = {
"cmd",
"-testnet4"};
732 const char* argv_regtest[] = {
"cmd",
"-regtest"};
733 const char* argv_test_no_reg[] = {
"cmd",
"-testnet4",
"-noregtest"};
734 const char* argv_both[] = {
"cmd",
"-testnet4",
"-regtest"};
737 const char* testnetconf =
"testnet4=1\nregtest=0\n[testnet4]\nregtest=1";
834 template <
typename Fn>
842 for (
bool soft_set : {
false,
true}) {
843 for (
bool force_set : {
false,
true}) {
846 for (
bool net_specific : {
false,
true}) {
847 fn(arg_actions, conf_actions, soft_set, force_set, section, network, net_specific);
859 const std::string& section,
860 const std::string&
name,
861 const std::string& value_prefix)
863 std::vector<std::string>
values;
865 for (
Action action : actions) {
866 if (action ==
NONE)
break;
870 for (
int i = 0; i < 2; ++i) {
889 FILE* out_file =
nullptr;
890 if (
const char* out_path = getenv(
"ARGS_MERGE_TEST_OUT")) {
892 if (!out_file)
throw std::system_error(errno, std::generic_category(),
"fopen failed");
895 ForEachMergeSetup([&](
const ActionList& arg_actions,
const ActionList& conf_actions,
bool soft_set,
bool force_set,
896 const std::string& section,
const std::string& network,
bool net_specific) {
899 std::string desc =
"net=";
903 const std::string&
name = net_specific ?
"wallet" :
"server";
904 const std::string key =
"-" +
name;
909 auto args = GetValues(arg_actions, section,
name,
"a");
910 std::vector<const char*> argv = {
"ignored"};
911 for (
auto& arg :
args) {
915 argv.push_back(arg.c_str());
922 for (
auto& conf_val : GetValues(conf_actions, section,
name,
"c")) {
928 std::istringstream conf_stream(conf);
956 desc += parser.
GetArg(key,
"default");
958 for (
const auto& arg : parser.
GetArgs(key)) {
965 if (!ignored.empty()) {
966 desc +=
" | ignored";
967 for (
const auto& arg : ignored) {
977 BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
982 if (fclose(out_file))
throw std::system_error(errno, std::generic_category(),
"fclose failed");
988 std::string out_sha_hex =
HexStr(out_sha_bytes);
999 BOOST_CHECK_EQUAL(out_sha_hex,
"f1ee5ab094cc43d16a6086fa7f2c10389e0f99902616b31bbf29189972ad1473");
1010 template <
typename Fn>
1024 FILE* out_file =
nullptr;
1025 if (
const char* out_path = getenv(
"CHAIN_MERGE_TEST_OUT")) {
1027 if (!out_file)
throw std::system_error(errno, std::generic_category(),
"fopen failed");
1030 ForEachMergeSetup([&](
const ActionList& arg_actions,
const ActionList& conf_actions) {
1035 auto arg = [](Action action) {
return action == ENABLE_TEST ?
"-testnet4=1" :
1036 action == DISABLE_TEST ?
"-testnet4=0" :
1037 action == NEGATE_TEST ?
"-notestnet4=1" :
1038 action == ENABLE_REG ?
"-regtest=1" :
1039 action == DISABLE_REG ?
"-regtest=0" :
1040 action == NEGATE_REG ?
"-noregtest=1" :
nullptr; };
1043 std::vector<const char*> argv = {
"ignored"};
1044 for (Action action : arg_actions) {
1045 const char* argstr = arg(action);
1047 argv.push_back(argstr);
1049 desc += argv.back();
1056 for (Action action : conf_actions) {
1057 const char* argstr = arg(action);
1064 std::istringstream conf_stream(conf);
1071 }
catch (
const std::runtime_error& e) {
1079 BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
1084 if (fclose(out_file))
throw std::system_error(errno, std::generic_category(),
"fclose failed");
1090 std::string out_sha_hex =
HexStr(out_sha_bytes);
1101 BOOST_CHECK_EQUAL(out_sha_hex,
"c0e33aab0c74e040ddcee9edad59e8148d8e1cacb3cccd9ea1a1f485cb6bad21");
BOOST_FIXTURE_TEST_CASE(util_CheckValue, CheckValueTest)
static void TestParse(const std::string &str, bool expected_bool, int64_t expected_int)
BOOST_AUTO_TEST_CASE(util_datadir)
std::string ChainTypeToString(ChainType chain)
bool ParseParameters(int argc, const char *const argv[], std::string &error) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
std::vector< common::SettingsValue > GetSettingsList(const std::string &arg) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Get list of setting values.
std::vector< std::string > GetArgs(const std::string &strArg) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return a vector of strings of the given argument.
@ ALLOW_ANY
disable validation
@ DISALLOW_NEGATION
disallow -nofoo syntax
common::SettingsValue GetSetting(const std::string &arg) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Get setting value.
bool ReadConfigString(const std::string &str_config) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
bool CheckCommandOptions(const std::string &command, std::vector< std::string > *errors=nullptr) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Check that any command-specific options the user specified are valid for the given command.
fs::path GetDataDirBase() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Get data directory path.
void AddCommand(const std::string &cmd, const std::string &help, std::set< std::string > options={}) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Add command.
bool SoftSetArg(const std::string &strArg, const std::string &strValue) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Set an argument if it doesn't already have a value.
std::set< std::string > GetUnsuitableSectionOnlyArgs() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Log warnings for options in m_section_only_args when they are specified in the default section but no...
void AddArg(const std::string &name, const std::string &help, unsigned int flags, const OptionsCategory &cat) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Add argument.
bool WriteSettingsFile(std::vector< std::string > *errors=nullptr, bool backup=false) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Write settings file or backup settings file.
void LockSettings(Fn &&fn) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Access settings with lock held.
void ClearPathCache() EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Clear cached directory paths.
void ForceSetArg(const std::string &strArg, const std::string &strValue) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
std::string GetArg(const std::string &strArg, const std::string &strDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return string argument or default value.
std::string GetChainTypeString() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Returns the appropriate chain type string from the program arguments.
bool ReadSettingsFile(std::vector< std::string > *errors=nullptr) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Read settings file.
void ClearArgs() EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Clear available arguments.
bool IsArgSet(const std::string &strArg) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return true if the given argument has been manually set.
std::optional< const Command > GetCommand() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Get the command and command args (returns std::nullopt if no command provided)
bool IsArgNegated(const std::string &strArg) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return true if the argument was originally passed as a negated option, i.e.
bool ReadConfigStream(std::istream &stream, const std::string &filepath, std::string &error, bool ignore_invalid_keys=false) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
bool GetBoolArg(const std::string &strArg, bool fDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return boolean argument or default value.
void SelectConfigNetwork(const std::string &network) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Select the network in use.
std::string GetHelpMessage() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Get the help string.
A hasher class for Bitcoin's 256-bit hash (double SHA-256).
void Finalize(std::span< unsigned char > output)
CHash256 & Write(std::span< const unsigned char > input)
static constexpr size_t OUTPUT_SIZE
Test GetSetting and GetArg type coercion, negation, and default value handling.
void CheckValue(unsigned int flags, const char *arg, const Expect &expect)
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
static UniValue Parse(std::string_view raw, ParamFormat format=ParamFormat::JSON)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
static std::string PathToString(const path &path)
Convert path object to a byte string.
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
BOOST_CHECK_EQUAL(headers.FindFirst("key"), "value")
FILE * fopen(const fs::path &p, const char *mode)
std::string ToString(const T &t)
Locale-independent version of std::to_string.
#define BOOST_CHECK_THROW(stmt, excMatch)
#define BOOST_CHECK(expr)
static const int64_t values[]
A selection of numbers that do not trigger int64_t overflow when added/subtracted.
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span{v}))
Like the std::span constructor, but for (const) unsigned char member types only.
void ForEachNoDup(CharType(&string)[StringLength], CharType min_char, CharType max_char, Fn &&fn)
Iterate over string values and call function for each string without successive duplicate characters.
void ForEachMergeSetup(Fn &&fn)
Enumerate all possible test configurations.
static constexpr int MAX_ACTIONS
Max number of actions to sequence together.
std::vector< std::string > GetValues(const ActionList &actions, const std::string §ion, const std::string &name, const std::string &value_prefix)
Translate actions into a list of <key>=setting strings.
Action[MAX_ACTIONS] ActionList
void ForEachMergeSetup(Fn &&fn)
Enumerate all possible test configurations.
Action[MAX_ACTIONS] ActionList
static constexpr int MAX_ACTIONS
Expect(common::SettingsValue s)
Expect & List(std::vector< std::string > m)
Expect & String(const char *s)
std::optional< int64_t > int_value
std::optional< std::vector< std::string > > list_value
Expect & Error(const char *e)
common::SettingsValue setting
std::optional< bool > bool_value
const char * string_value
std::string Parse(const char *arg)
void ReadConfigString(const std::string &str_config)
void SetupArgs(const std::vector< std::pair< std::string, unsigned int > > &args)
bool ReadConfigStream(std::istream &stream, const std::string &filepath, std::string &error, bool ignore_invalid_keys=false) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
#define ASSERT_DEBUG_LOG(message)