21 #include <boost/test/unit_test.hpp>
55 std::istringstream streamConfig(str_config);
58 m_settings.ro_config.clear();
59 m_config_sections.clear();
67 m_network_only_args.insert(arg);
69 void SetupArgs(
const std::vector<std::pair<std::string, unsigned int>>&
args)
71 for (
const auto& arg :
args) {
79 using ArgsManager::m_network;
80 using ArgsManager::m_settings;
113 const char* argv[] = {
"ignored", arg};
119 if (
expect.setting.isNull() ||
expect.setting.isFalse()) {
128 BOOST_CHECK_NE(
error.find(
expect.error), std::string::npos);
134 if (
expect.default_string) {
136 }
else if (
expect.string_value) {
144 }
else if (
expect.int_value) {
150 if (
expect.default_bool) {
153 }
else if (
expect.bool_value) {
161 auto l = test.
GetArgs(
"-value");
162 BOOST_CHECK_EQUAL_COLLECTIONS(l.begin(), l.end(),
expect.list_value->begin(),
expect.list_value->end());
173 CheckValue(M::ALLOW_ANY,
nullptr, Expect{{}}.DefaultString().DefaultInt().DefaultBool().List({}));
174 CheckValue(M::ALLOW_ANY,
"-novalue", Expect{
false}.String(
"0").Int(0).Bool(
false).List({}));
175 CheckValue(M::ALLOW_ANY,
"-novalue=", Expect{
false}.String(
"0").Int(0).Bool(
false).List({}));
176 CheckValue(M::ALLOW_ANY,
"-novalue=0", Expect{
true}.String(
"1").Int(1).Bool(
true).List({
"1"}));
177 CheckValue(M::ALLOW_ANY,
"-novalue=1", Expect{
false}.String(
"0").Int(0).Bool(
false).List({}));
178 CheckValue(M::ALLOW_ANY,
"-novalue=2", Expect{
false}.String(
"0").Int(0).Bool(
false).List({}));
179 CheckValue(M::ALLOW_ANY,
"-novalue=abc", Expect{
true}.String(
"1").Int(1).Bool(
true).List({
"1"}));
180 CheckValue(M::ALLOW_ANY,
"-value", Expect{
""}.String(
"").Int(0).Bool(
true).List({
""}));
181 CheckValue(M::ALLOW_ANY,
"-value=", Expect{
""}.String(
"").Int(0).Bool(
true).List({
""}));
182 CheckValue(M::ALLOW_ANY,
"-value=0", Expect{
"0"}.String(
"0").Int(0).Bool(
false).List({
"0"}));
183 CheckValue(M::ALLOW_ANY,
"-value=1", Expect{
"1"}.String(
"1").Int(1).Bool(
true).List({
"1"}));
184 CheckValue(M::ALLOW_ANY,
"-value=2", Expect{
"2"}.String(
"2").Int(2).Bool(
true).List({
"2"}));
185 CheckValue(M::ALLOW_ANY,
"-value=abc", Expect{
"abc"}.String(
"abc").Int(0).Bool(
false).List({
"abc"}));
193 std::array argv{
"ignored", arg};
203 BOOST_CHECK_EQUAL(
Parse(
"-includeconf"),
"-includeconf cannot be used from commandline; -includeconf=\"\"");
204 BOOST_CHECK_EQUAL(
Parse(
"-includeconf=file"),
"-includeconf cannot be used from commandline; -includeconf=\"file\"");
215 const char *argv_test[] = {
"-ignored",
"-a",
"-b",
"-ccc=argument",
"-ccc=multiple",
"f",
"-d=e"};
221 BOOST_CHECK(testArgs.m_settings.command_line_options.empty() && testArgs.m_settings.ro_config.empty());
224 BOOST_CHECK(testArgs.m_settings.command_line_options.empty() && testArgs.m_settings.ro_config.empty());
230 BOOST_CHECK(testArgs.m_settings.command_line_options.size() == 3 && testArgs.m_settings.ro_config.empty());
233 BOOST_CHECK(testArgs.m_settings.command_line_options.count(
"a") && testArgs.m_settings.command_line_options.count(
"b") && testArgs.m_settings.command_line_options.count(
"ccc")
234 && !testArgs.m_settings.command_line_options.count(
"f") && !testArgs.m_settings.command_line_options.count(
"d"));
236 BOOST_CHECK(testArgs.m_settings.command_line_options[
"a"].size() == 1);
237 BOOST_CHECK(testArgs.m_settings.command_line_options[
"a"].front().get_str() ==
"");
238 BOOST_CHECK(testArgs.m_settings.command_line_options[
"ccc"].size() == 2);
239 BOOST_CHECK(testArgs.m_settings.command_line_options[
"ccc"].front().get_str() ==
"argument");
240 BOOST_CHECK(testArgs.m_settings.command_line_options[
"ccc"].back().get_str() ==
"multiple");
249 const char* argv[] = {
"ignored",
"-registered"};
254 argv[1] =
"-unregistered";
260 argv[1] =
"-test.registered";
265 static 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"};
337 for (
const char opt :
"abcdef")
341 BOOST_CHECK(testArgs.m_settings.command_line_options.size() == 6 &&
342 testArgs.m_settings.ro_config.empty());
368 const char *argv_test[] = {
"ignored",
"-nofoo",
"-foo",
"-nobar=0"};
382 const char *conf_test =
"nofoo=1\nfoo=1\nnobar=0\n";
396 const char *combo_test_args[] = {
"ignored",
"-nofoo",
"-bar"};
397 const char *combo_test_conf =
"foo=1\nnobar=1\n";
410 && testArgs.
GetArgs(
"-bar").front() ==
"");
415 const char *str_config =
449 test_args.
SetupArgs({a, b, ccc, d, e, fff, ggg, h, i, iii});
455 BOOST_CHECK(test_args.m_settings.command_line_options.empty());
456 BOOST_CHECK(test_args.m_settings.ro_config.size() == 3);
457 BOOST_CHECK(test_args.m_settings.ro_config[
""].size() == 8);
458 BOOST_CHECK(test_args.m_settings.ro_config[
"sec1"].size() == 3);
459 BOOST_CHECK(test_args.m_settings.ro_config[
"sec2"].size() == 2);
461 BOOST_CHECK(test_args.m_settings.ro_config[
""].count(
"a"));
462 BOOST_CHECK(test_args.m_settings.ro_config[
""].count(
"b"));
463 BOOST_CHECK(test_args.m_settings.ro_config[
""].count(
"ccc"));
464 BOOST_CHECK(test_args.m_settings.ro_config[
""].count(
"d"));
465 BOOST_CHECK(test_args.m_settings.ro_config[
""].count(
"fff"));
466 BOOST_CHECK(test_args.m_settings.ro_config[
""].count(
"ggg"));
467 BOOST_CHECK(test_args.m_settings.ro_config[
""].count(
"h"));
468 BOOST_CHECK(test_args.m_settings.ro_config[
""].count(
"i"));
469 BOOST_CHECK(test_args.m_settings.ro_config[
"sec1"].count(
"ccc"));
470 BOOST_CHECK(test_args.m_settings.ro_config[
"sec1"].count(
"h"));
471 BOOST_CHECK(test_args.m_settings.ro_config[
"sec2"].count(
"ccc"));
472 BOOST_CHECK(test_args.m_settings.ro_config[
"sec2"].count(
"iii"));
496 for (
const bool def : {
false,
true}) {
510 && test_args.
GetArgs(
"-a").front() ==
"");
512 && test_args.
GetArgs(
"-b").front() ==
"1");
514 && test_args.
GetArgs(
"-ccc").front() ==
"argument"
515 && test_args.
GetArgs(
"-ccc").back() ==
"multiple");
519 && test_args.
GetArgs(
"-ggg").front() ==
"1");
524 && test_args.
GetArgs(
"-i").front() ==
"1");
555 const std::vector<std::string> sec1_ccc_expected = {
"extend1",
"extend2",
"argument",
"multiple"};
556 const auto& sec1_ccc_res = test_args.
GetArgs(
"-ccc");
557 BOOST_CHECK_EQUAL_COLLECTIONS(sec1_ccc_res.begin(), sec1_ccc_res.end(), sec1_ccc_expected.begin(), sec1_ccc_expected.end());
574 const std::vector<std::string> sec2_ccc_expected = {
"extend3",
"argument",
"multiple"};
575 const auto& sec2_ccc_res = test_args.
GetArgs(
"-ccc");
576 BOOST_CHECK_EQUAL_COLLECTIONS(sec2_ccc_res.begin(), sec2_ccc_res.end(), sec2_ccc_expected.begin(), sec2_ccc_expected.end());
606 testArgs.m_settings.command_line_options.clear();
607 testArgs.m_settings.command_line_options[
"strtest1"] = {
"string..."};
609 testArgs.m_settings.command_line_options[
"inttest1"] = {
"12345"};
610 testArgs.m_settings.command_line_options[
"inttest2"] = {
"81985529216486895"};
612 testArgs.m_settings.command_line_options[
"booltest1"] = {
""};
614 testArgs.m_settings.command_line_options[
"booltest3"] = {
"0"};
615 testArgs.m_settings.command_line_options[
"booltest4"] = {
"1"};
618 testArgs.m_settings.command_line_options[
"pritest1"] = {
"a",
"b"};
619 testArgs.m_settings.ro_config[
""][
"pritest2"] = {
"a",
"b"};
620 testArgs.m_settings.command_line_options[
"pritest3"] = {
"a"};
621 testArgs.m_settings.ro_config[
""][
"pritest3"] = {
"b"};
622 testArgs.m_settings.command_line_options[
"pritest4"] = {
"a",
"b"};
623 testArgs.m_settings.ro_config[
""][
"pritest4"] = {
"c",
"d"};
648 const char* argv_testnet[] = {
"cmd",
"-testnet"};
649 const char* argv_regtest[] = {
"cmd",
"-regtest"};
650 const char* argv_test_no_reg[] = {
"cmd",
"-testnet",
"-noregtest"};
651 const char* argv_both[] = {
"cmd",
"-testnet",
"-regtest"};
655 const char* testnetconf =
"testnet=1\nregtest=0\n[test]\nregtest=1";
749 template <
typename Fn>
757 for (
bool soft_set : {
false,
true}) {
758 for (
bool force_set : {
false,
true}) {
761 for (
bool net_specific : {
false,
true}) {
762 fn(arg_actions, conf_actions, soft_set, force_set, section, network, net_specific);
774 const std::string& section,
775 const std::string&
name,
776 const std::string& value_prefix)
778 std::vector<std::string>
values;
780 for (
Action action : actions) {
781 if (action ==
NONE)
break;
785 for (
int i = 0; i < 2; ++i) {
804 FILE* out_file =
nullptr;
805 if (
const char* out_path = getenv(
"ARGS_MERGE_TEST_OUT")) {
807 if (!out_file)
throw std::system_error(errno, std::generic_category(),
"fopen failed");
810 ForEachMergeSetup([&](
const ActionList& arg_actions,
const ActionList& conf_actions,
bool soft_set,
bool force_set,
811 const std::string& section,
const std::string& network,
bool net_specific) {
815 std::string desc =
"net=";
817 parser.m_network = network;
819 const std::string&
name = net_specific ?
"wallet" :
"server";
820 const std::string key =
"-" +
name;
824 auto args = GetValues(arg_actions, section,
name,
"a");
825 std::vector<const char*> argv = {
"ignored"};
826 for (
auto& arg :
args) {
830 argv.push_back(arg.c_str());
837 for (
auto& conf_val : GetValues(conf_actions, section,
name,
"c")) {
843 std::istringstream conf_stream(conf);
871 desc += parser.
GetArg(key,
"default");
873 for (
const auto& arg : parser.
GetArgs(key)) {
880 if (!ignored.empty()) {
881 desc +=
" | ignored";
882 for (
const auto& arg : ignored) {
892 BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
897 if (fclose(out_file))
throw std::system_error(errno, std::generic_category(),
"fclose failed");
903 std::string out_sha_hex =
HexStr(out_sha_bytes);
914 BOOST_CHECK_EQUAL(out_sha_hex,
"d1e436c1cd510d0ec44d5205d4b4e3bee6387d316e0075c58206cb16603f3d82");
925 template <
typename Fn>
939 FILE* out_file =
nullptr;
940 if (
const char* out_path = getenv(
"CHAIN_MERGE_TEST_OUT")) {
942 if (!out_file)
throw std::system_error(errno, std::generic_category(),
"fopen failed");
945 ForEachMergeSetup([&](
const ActionList& arg_actions,
const ActionList& conf_actions) {
951 auto arg = [](Action action) {
return action == ENABLE_TEST ?
"-testnet=1" :
952 action == DISABLE_TEST ?
"-testnet=0" :
953 action == NEGATE_TEST ?
"-notestnet=1" :
954 action == ENABLE_REG ?
"-regtest=1" :
955 action == DISABLE_REG ?
"-regtest=0" :
956 action == NEGATE_REG ?
"-noregtest=1" :
nullptr; };
959 std::vector<const char*> argv = {
"ignored"};
960 for (Action action : arg_actions) {
961 const char* argstr = arg(action);
963 argv.push_back(argstr);
972 for (Action action : conf_actions) {
973 const char* argstr = arg(action);
980 std::istringstream conf_stream(conf);
987 }
catch (
const std::runtime_error& e) {
995 BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
1000 if (fclose(out_file))
throw std::system_error(errno, std::generic_category(),
"fclose failed");
1006 std::string out_sha_hex =
HexStr(out_sha_bytes);
1017 BOOST_CHECK_EQUAL(out_sha_hex,
"f263493e300023b6509963887444c41386f44b63bc30047eb8402e8c1144854c");
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)
std::set< std::string > GetUnsuitableSectionOnlyArgs() const
Log warnings for options in m_section_only_args when they are specified in the default section but no...
bool IsArgNegated(const std::string &strArg) const
Return true if the argument was originally passed as a negated option, i.e.
@ ALLOW_ANY
disable validation
common::SettingsValue GetSetting(const std::string &arg) const
Get setting value.
bool ReadSettingsFile(std::vector< std::string > *errors=nullptr)
Read settings file.
void ForceSetArg(const std::string &strArg, const std::string &strValue)
std::string GetChainTypeString() const
Returns the appropriate chain type string from the program arguments.
bool ParseParameters(int argc, const char *const argv[], std::string &error)
std::vector< std::string > GetArgs(const std::string &strArg) const
Return a vector of strings of the given argument.
const fs::path & GetDataDirBase() const
Get data directory path.
void LockSettings(Fn &&fn)
Access settings with lock held.
bool SoftSetArg(const std::string &strArg, const std::string &strValue)
Set an argument if it doesn't already have a value.
void SelectConfigNetwork(const std::string &network)
Select the network in use.
void ClearPathCache()
Clear cached directory paths.
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
bool WriteSettingsFile(std::vector< std::string > *errors=nullptr, bool backup=false) const
Write settings file or backup settings file.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
std::vector< common::SettingsValue > GetSettingsList(const std::string &arg) const
Get list of setting values.
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
bool ReadConfigStream(std::istream &stream, const std::string &filepath, std::string &error, bool ignore_invalid_keys=false)
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
void AddArg(const std::string &name, const std::string &help, unsigned int flags, const OptionsCategory &cat)
Add argument.
A hasher class for Bitcoin's 256-bit hash (double SHA-256).
CHash256 & Write(Span< const unsigned char > input)
void Finalize(Span< unsigned char > output)
static const 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
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
static UniValue Parse(std::string_view raw)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
BOOST_AUTO_TEST_SUITE_END()
bool error(const char *fmt, const Args &... args)
static std::string PathToString(const path &path)
Convert path object to a byte string.
FILE * fopen(const fs::path &p, const char *mode)
#define BOOST_CHECK_THROW(stmt, excMatch)
#define BOOST_CHECK_EQUAL(v1, v2)
#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(V &&v) -> decltype(UCharSpanCast(Span{std::forward< V >(v)}))
Like the 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.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
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.
void ForEachMergeSetup(Fn &&fn)
Enumerate all possible test configurations.
static constexpr int MAX_ACTIONS
Max number of actions to sequence together.
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 & Error(const char *e)
std::optional< int64_t > int_value
Expect & List(std::vector< std::string > m)
std::optional< std::vector< std::string > > list_value
common::SettingsValue setting
std::optional< bool > bool_value
const char * string_value
Expect & String(const char *s)
std::string Parse(const char *arg)
common::SettingsValue GetSetting(const std::string &arg) const
Get setting value.
void SetupArgs(const std::vector< std::pair< std::string, unsigned int >> &args)
void SetNetworkOnlyArg(const std::string arg)
std::vector< common::SettingsValue > GetSettingsList(const std::string &arg) const
Get list of setting values.
void ReadConfigString(const std::string str_config)
bool ReadConfigStream(std::istream &stream, const std::string &filepath, std::string &error, bool ignore_invalid_keys=false)
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
std::map< std::string, SettingsValue > rw_settings
Map of setting name to read-write file setting value.
#define ASSERT_DEBUG_LOG(message)
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.