Line data Source code
1 : // Copyright (c) 2011-2020 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #include <util/system.h>
6 :
7 : #include <clientversion.h>
8 : #include <hash.h> // For Hash()
9 : #include <key.h> // For CKey
10 : #include <optional.h>
11 : #include <sync.h>
12 : #include <test/util/logging.h>
13 : #include <test/util/setup_common.h>
14 : #include <test/util/str.h>
15 : #include <uint256.h>
16 : #include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC
17 : #include <util/moneystr.h>
18 : #include <util/spanparsing.h>
19 : #include <util/strencodings.h>
20 : #include <util/string.h>
21 : #include <util/time.h>
22 : #include <util/vector.h>
23 :
24 : #include <array>
25 : #include <stdint.h>
26 : #include <thread>
27 : #include <univalue.h>
28 : #include <utility>
29 : #include <vector>
30 : #ifndef WIN32
31 : #include <signal.h>
32 : #include <sys/types.h>
33 : #include <sys/wait.h>
34 : #endif
35 :
36 : #include <boost/test/unit_test.hpp>
37 :
38 : /* defined in logging.cpp */
39 : namespace BCLog {
40 : std::string LogEscapeMessage(const std::string& str);
41 : }
42 :
43 89 : BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup)
44 :
45 101 : BOOST_AUTO_TEST_CASE(util_check)
46 : {
47 : // Check that Assert can forward
48 4 : const std::unique_ptr<int> p_two = Assert(MakeUnique<int>(2));
49 : // Check that Assert works on lvalues and rvalues
50 4 : const int two = *Assert(p_two);
51 4 : Assert(two == 2);
52 4 : Assert(true);
53 2 : }
54 :
55 101 : BOOST_AUTO_TEST_CASE(util_criticalsection)
56 : {
57 2 : RecursiveMutex cs;
58 :
59 : do {
60 2 : LOCK(cs);
61 : break;
62 :
63 : BOOST_ERROR("break was swallowed!");
64 2 : } while(0);
65 :
66 : do {
67 2 : TRY_LOCK(cs, lockTest);
68 2 : if (lockTest) {
69 2 : BOOST_CHECK(true); // Needed to suppress "Test case [...] did not check any assertions"
70 2 : break;
71 : }
72 :
73 0 : BOOST_ERROR("break was swallowed!");
74 2 : } while(0);
75 2 : }
76 :
77 : static const unsigned char ParseHex_expected[65] = {
78 : 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7,
79 : 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde,
80 : 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12,
81 : 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d,
82 : 0x5f
83 : };
84 101 : BOOST_AUTO_TEST_CASE(util_ParseHex)
85 : {
86 2 : std::vector<unsigned char> result;
87 2 : std::vector<unsigned char> expected(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected));
88 : // Basic test vector
89 2 : result = ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
90 2 : BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
91 :
92 : // Spaces between bytes must be supported
93 2 : result = ParseHex("12 34 56 78");
94 2 : BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);
95 :
96 : // Leading space must be supported (used in BerkeleyEnvironment::Salvage)
97 2 : result = ParseHex(" 89 34 56 78");
98 2 : BOOST_CHECK(result.size() == 4 && result[0] == 0x89 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);
99 :
100 : // Stop parsing at invalid value
101 2 : result = ParseHex("1234 invalid 1234");
102 2 : BOOST_CHECK(result.size() == 2 && result[0] == 0x12 && result[1] == 0x34);
103 2 : }
104 :
105 101 : BOOST_AUTO_TEST_CASE(util_HexStr)
106 : {
107 2 : BOOST_CHECK_EQUAL(
108 : HexStr(ParseHex_expected),
109 : "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
110 :
111 2 : BOOST_CHECK_EQUAL(
112 : HexStr(Span<const unsigned char>(
113 : ParseHex_expected + sizeof(ParseHex_expected),
114 : ParseHex_expected + sizeof(ParseHex_expected))),
115 : "");
116 :
117 2 : BOOST_CHECK_EQUAL(
118 : HexStr(Span<const unsigned char>(ParseHex_expected, ParseHex_expected)),
119 : "");
120 :
121 2 : std::vector<unsigned char> ParseHex_vec(ParseHex_expected, ParseHex_expected + 5);
122 :
123 2 : BOOST_CHECK_EQUAL(
124 : HexStr(ParseHex_vec),
125 : "04678afdb0"
126 : );
127 2 : }
128 :
129 101 : BOOST_AUTO_TEST_CASE(util_Join)
130 : {
131 : // Normal version
132 2 : BOOST_CHECK_EQUAL(Join({}, ", "), "");
133 2 : BOOST_CHECK_EQUAL(Join({"foo"}, ", "), "foo");
134 4 : BOOST_CHECK_EQUAL(Join({"foo", "bar"}, ", "), "foo, bar");
135 :
136 : // Version with unary operator
137 6 : const auto op_upper = [](const std::string& s) { return ToUpper(s); };
138 2 : BOOST_CHECK_EQUAL(Join<std::string>({}, ", ", op_upper), "");
139 2 : BOOST_CHECK_EQUAL(Join<std::string>({"foo"}, ", ", op_upper), "FOO");
140 4 : BOOST_CHECK_EQUAL(Join<std::string>({"foo", "bar"}, ", ", op_upper), "FOO, BAR");
141 2 : }
142 :
143 101 : BOOST_AUTO_TEST_CASE(util_FormatParseISO8601DateTime)
144 : {
145 2 : BOOST_CHECK_EQUAL(FormatISO8601DateTime(1317425777), "2011-09-30T23:36:17Z");
146 2 : BOOST_CHECK_EQUAL(FormatISO8601DateTime(0), "1970-01-01T00:00:00Z");
147 :
148 2 : BOOST_CHECK_EQUAL(ParseISO8601DateTime("1970-01-01T00:00:00Z"), 0);
149 2 : BOOST_CHECK_EQUAL(ParseISO8601DateTime("1960-01-01T00:00:00Z"), 0);
150 2 : BOOST_CHECK_EQUAL(ParseISO8601DateTime("2011-09-30T23:36:17Z"), 1317425777);
151 :
152 2 : auto time = GetSystemTimeInSeconds();
153 2 : BOOST_CHECK_EQUAL(ParseISO8601DateTime(FormatISO8601DateTime(time)), time);
154 2 : }
155 :
156 101 : BOOST_AUTO_TEST_CASE(util_FormatISO8601Date)
157 : {
158 2 : BOOST_CHECK_EQUAL(FormatISO8601Date(1317425777), "2011-09-30");
159 2 : }
160 :
161 53176 : struct TestArgsManager : public ArgsManager
162 : {
163 53176 : TestArgsManager() { m_network_only_args.clear(); }
164 26 : void ReadConfigString(const std::string str_config)
165 : {
166 26 : std::istringstream streamConfig(str_config);
167 : {
168 26 : LOCK(cs_args);
169 26 : m_settings.ro_config.clear();
170 26 : m_config_sections.clear();
171 26 : }
172 26 : std::string error;
173 26 : BOOST_REQUIRE(ReadConfigStream(streamConfig, "", error));
174 26 : }
175 11878 : void SetNetworkOnlyArg(const std::string arg)
176 : {
177 11878 : LOCK(cs_args);
178 11878 : m_network_only_args.insert(arg);
179 11878 : }
180 100 : void SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args)
181 : {
182 238 : for (const auto& arg : args) {
183 138 : AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS);
184 : }
185 100 : }
186 : using ArgsManager::GetSetting;
187 : using ArgsManager::GetSettingsList;
188 : using ArgsManager::ReadConfigStream;
189 : using ArgsManager::cs_args;
190 : using ArgsManager::m_network;
191 : using ArgsManager::m_settings;
192 : };
193 :
194 : //! Test GetSetting and GetArg type coercion, negation, and default value handling.
195 4 : class CheckValueTest : public TestChain100Setup
196 : {
197 : public:
198 52 : struct Expect {
199 : util::SettingsValue setting;
200 26 : bool default_string = false;
201 26 : bool default_int = false;
202 26 : bool default_bool = false;
203 26 : const char* string_value = nullptr;
204 : Optional<int64_t> int_value;
205 : Optional<bool> bool_value;
206 : Optional<std::vector<std::string>> list_value;
207 26 : const char* error = nullptr;
208 :
209 52 : Expect(util::SettingsValue s) : setting(std::move(s)) {}
210 2 : Expect& DefaultString() { default_string = true; return *this; }
211 2 : Expect& DefaultInt() { default_int = true; return *this; }
212 2 : Expect& DefaultBool() { default_bool = true; return *this; }
213 24 : Expect& String(const char* s) { string_value = s; return *this; }
214 24 : Expect& Int(int64_t i) { int_value = i; return *this; }
215 24 : Expect& Bool(bool b) { bool_value = b; return *this; }
216 26 : Expect& List(std::vector<std::string> m) { list_value = std::move(m); return *this; }
217 : Expect& Error(const char* e) { error = e; return *this; }
218 : };
219 :
220 26 : void CheckValue(unsigned int flags, const char* arg, const Expect& expect)
221 : {
222 26 : TestArgsManager test;
223 26 : test.SetupArgs({{"-value", flags}});
224 26 : const char* argv[] = {"ignored", arg};
225 26 : std::string error;
226 26 : bool success = test.ParseParameters(arg ? 2 : 1, (char**)argv, error);
227 :
228 26 : BOOST_CHECK_EQUAL(test.GetSetting("-value").write(), expect.setting.write());
229 26 : auto settings_list = test.GetSettingsList("-value");
230 26 : if (expect.setting.isNull() || expect.setting.isFalse()) {
231 10 : BOOST_CHECK_EQUAL(settings_list.size(), 0U);
232 : } else {
233 16 : BOOST_CHECK_EQUAL(settings_list.size(), 1U);
234 16 : BOOST_CHECK_EQUAL(settings_list[0].write(), expect.setting.write());
235 : }
236 :
237 26 : if (expect.error) {
238 0 : BOOST_CHECK(!success);
239 0 : BOOST_CHECK_NE(error.find(expect.error), std::string::npos);
240 : } else {
241 26 : BOOST_CHECK(success);
242 26 : BOOST_CHECK_EQUAL(error, "");
243 : }
244 :
245 26 : if (expect.default_string) {
246 2 : BOOST_CHECK_EQUAL(test.GetArg("-value", "zzzzz"), "zzzzz");
247 24 : } else if (expect.string_value) {
248 24 : BOOST_CHECK_EQUAL(test.GetArg("-value", "zzzzz"), expect.string_value);
249 : } else {
250 0 : BOOST_CHECK(!success);
251 : }
252 :
253 26 : if (expect.default_int) {
254 2 : BOOST_CHECK_EQUAL(test.GetArg("-value", 99999), 99999);
255 24 : } else if (expect.int_value) {
256 24 : BOOST_CHECK_EQUAL(test.GetArg("-value", 99999), *expect.int_value);
257 : } else {
258 0 : BOOST_CHECK(!success);
259 : }
260 :
261 26 : if (expect.default_bool) {
262 2 : BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), false);
263 2 : BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), true);
264 24 : } else if (expect.bool_value) {
265 24 : BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), *expect.bool_value);
266 24 : BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), *expect.bool_value);
267 : } else {
268 0 : BOOST_CHECK(!success);
269 : }
270 :
271 26 : if (expect.list_value) {
272 26 : auto l = test.GetArgs("-value");
273 26 : BOOST_CHECK_EQUAL_COLLECTIONS(l.begin(), l.end(), expect.list_value->begin(), expect.list_value->end());
274 26 : } else {
275 0 : BOOST_CHECK(!success);
276 : }
277 26 : }
278 : };
279 :
280 101 : BOOST_FIXTURE_TEST_CASE(util_CheckValue, CheckValueTest)
281 : {
282 : using M = ArgsManager;
283 :
284 2 : CheckValue(M::ALLOW_ANY, nullptr, Expect{{}}.DefaultString().DefaultInt().DefaultBool().List({}));
285 2 : CheckValue(M::ALLOW_ANY, "-novalue", Expect{false}.String("0").Int(0).Bool(false).List({}));
286 2 : CheckValue(M::ALLOW_ANY, "-novalue=", Expect{false}.String("0").Int(0).Bool(false).List({}));
287 2 : CheckValue(M::ALLOW_ANY, "-novalue=0", Expect{true}.String("1").Int(1).Bool(true).List({"1"}));
288 2 : CheckValue(M::ALLOW_ANY, "-novalue=1", Expect{false}.String("0").Int(0).Bool(false).List({}));
289 2 : CheckValue(M::ALLOW_ANY, "-novalue=2", Expect{false}.String("0").Int(0).Bool(false).List({}));
290 2 : CheckValue(M::ALLOW_ANY, "-novalue=abc", Expect{true}.String("1").Int(1).Bool(true).List({"1"}));
291 2 : CheckValue(M::ALLOW_ANY, "-value", Expect{""}.String("").Int(0).Bool(true).List({""}));
292 2 : CheckValue(M::ALLOW_ANY, "-value=", Expect{""}.String("").Int(0).Bool(true).List({""}));
293 2 : CheckValue(M::ALLOW_ANY, "-value=0", Expect{"0"}.String("0").Int(0).Bool(false).List({"0"}));
294 2 : CheckValue(M::ALLOW_ANY, "-value=1", Expect{"1"}.String("1").Int(1).Bool(true).List({"1"}));
295 2 : CheckValue(M::ALLOW_ANY, "-value=2", Expect{"2"}.String("2").Int(2).Bool(true).List({"2"}));
296 2 : CheckValue(M::ALLOW_ANY, "-value=abc", Expect{"abc"}.String("abc").Int(0).Bool(false).List({"abc"}));
297 2 : }
298 :
299 101 : BOOST_AUTO_TEST_CASE(util_ParseParameters)
300 : {
301 2 : TestArgsManager testArgs;
302 2 : const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
303 2 : const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
304 2 : const auto ccc = std::make_pair("-ccc", ArgsManager::ALLOW_ANY);
305 2 : const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
306 :
307 2 : const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"};
308 :
309 2 : std::string error;
310 2 : LOCK(testArgs.cs_args);
311 8 : testArgs.SetupArgs({a, b, ccc, d});
312 2 : BOOST_CHECK(testArgs.ParseParameters(0, (char**)argv_test, error));
313 2 : BOOST_CHECK(testArgs.m_settings.command_line_options.empty() && testArgs.m_settings.ro_config.empty());
314 :
315 2 : BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error));
316 2 : BOOST_CHECK(testArgs.m_settings.command_line_options.empty() && testArgs.m_settings.ro_config.empty());
317 :
318 2 : BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error));
319 : // expectation: -ignored is ignored (program name argument),
320 : // -a, -b and -ccc end up in map, -d ignored because it is after
321 : // a non-option argument (non-GNU option parsing)
322 2 : BOOST_CHECK(testArgs.m_settings.command_line_options.size() == 3 && testArgs.m_settings.ro_config.empty());
323 2 : BOOST_CHECK(testArgs.IsArgSet("-a") && testArgs.IsArgSet("-b") && testArgs.IsArgSet("-ccc")
324 : && !testArgs.IsArgSet("f") && !testArgs.IsArgSet("-d"));
325 2 : 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")
326 : && !testArgs.m_settings.command_line_options.count("f") && !testArgs.m_settings.command_line_options.count("d"));
327 :
328 2 : BOOST_CHECK(testArgs.m_settings.command_line_options["a"].size() == 1);
329 2 : BOOST_CHECK(testArgs.m_settings.command_line_options["a"].front().get_str() == "");
330 2 : BOOST_CHECK(testArgs.m_settings.command_line_options["ccc"].size() == 2);
331 2 : BOOST_CHECK(testArgs.m_settings.command_line_options["ccc"].front().get_str() == "argument");
332 2 : BOOST_CHECK(testArgs.m_settings.command_line_options["ccc"].back().get_str() == "multiple");
333 2 : BOOST_CHECK(testArgs.GetArgs("-ccc").size() == 2);
334 2 : }
335 :
336 101 : BOOST_AUTO_TEST_CASE(util_ParseInvalidParameters)
337 : {
338 2 : TestArgsManager test;
339 2 : test.SetupArgs({{"-registered", ArgsManager::ALLOW_ANY}});
340 :
341 2 : const char* argv[] = {"ignored", "-registered"};
342 2 : std::string error;
343 2 : BOOST_CHECK(test.ParseParameters(2, (char**)argv, error));
344 2 : BOOST_CHECK_EQUAL(error, "");
345 :
346 2 : argv[1] = "-unregistered";
347 2 : BOOST_CHECK(!test.ParseParameters(2, (char**)argv, error));
348 2 : BOOST_CHECK_EQUAL(error, "Invalid parameter -unregistered");
349 :
350 : // Make sure registered parameters prefixed with a chain name trigger errors.
351 : // (Previously, they were accepted and ignored.)
352 2 : argv[1] = "-test.registered";
353 2 : BOOST_CHECK(!test.ParseParameters(2, (char**)argv, error));
354 2 : BOOST_CHECK_EQUAL(error, "Invalid parameter -test.registered");
355 2 : }
356 :
357 62 : static void TestParse(const std::string& str, bool expected_bool, int64_t expected_int)
358 : {
359 62 : TestArgsManager test;
360 62 : test.SetupArgs({{"-value", ArgsManager::ALLOW_ANY}});
361 62 : std::string arg = "-value=" + str;
362 62 : const char* argv[] = {"ignored", arg.c_str()};
363 62 : std::string error;
364 62 : BOOST_CHECK(test.ParseParameters(2, (char**)argv, error));
365 62 : BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), expected_bool);
366 62 : BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), expected_bool);
367 62 : BOOST_CHECK_EQUAL(test.GetArg("-value", 99998), expected_int);
368 62 : BOOST_CHECK_EQUAL(test.GetArg("-value", 99999), expected_int);
369 62 : }
370 :
371 : // Test bool and int parsing.
372 101 : BOOST_AUTO_TEST_CASE(util_ArgParsing)
373 : {
374 : // Some of these cases could be ambiguous or surprising to users, and might
375 : // be worth triggering errors or warnings in the future. But for now basic
376 : // test coverage is useful to avoid breaking backwards compatibility
377 : // unintentionally.
378 2 : TestParse("", true, 0);
379 2 : TestParse(" ", false, 0);
380 2 : TestParse("0", false, 0);
381 2 : TestParse("0 ", false, 0);
382 2 : TestParse(" 0", false, 0);
383 2 : TestParse("+0", false, 0);
384 2 : TestParse("-0", false, 0);
385 2 : TestParse("5", true, 5);
386 2 : TestParse("5 ", true, 5);
387 2 : TestParse(" 5", true, 5);
388 2 : TestParse("+5", true, 5);
389 2 : TestParse("-5", true, -5);
390 2 : TestParse("0 5", false, 0);
391 2 : TestParse("5 0", true, 5);
392 2 : TestParse("050", true, 50);
393 2 : TestParse("0.", false, 0);
394 2 : TestParse("5.", true, 5);
395 2 : TestParse("0.0", false, 0);
396 2 : TestParse("0.5", false, 0);
397 2 : TestParse("5.0", true, 5);
398 2 : TestParse("5.5", true, 5);
399 2 : TestParse("x", false, 0);
400 2 : TestParse("x0", false, 0);
401 2 : TestParse("x5", false, 0);
402 2 : TestParse("0x", false, 0);
403 2 : TestParse("5x", true, 5);
404 2 : TestParse("0x5", false, 0);
405 2 : TestParse("false", false, 0);
406 2 : TestParse("true", false, 0);
407 2 : TestParse("yes", false, 0);
408 2 : TestParse("no", false, 0);
409 2 : }
410 :
411 101 : BOOST_AUTO_TEST_CASE(util_GetBoolArg)
412 : {
413 2 : TestArgsManager testArgs;
414 2 : const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
415 2 : const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
416 2 : const auto c = std::make_pair("-c", ArgsManager::ALLOW_ANY);
417 2 : const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
418 2 : const auto e = std::make_pair("-e", ArgsManager::ALLOW_ANY);
419 2 : const auto f = std::make_pair("-f", ArgsManager::ALLOW_ANY);
420 :
421 2 : const char *argv_test[] = {
422 : "ignored", "-a", "-nob", "-c=0", "-d=1", "-e=false", "-f=true"};
423 2 : std::string error;
424 2 : LOCK(testArgs.cs_args);
425 12 : testArgs.SetupArgs({a, b, c, d, e, f});
426 2 : BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error));
427 :
428 : // Each letter should be set.
429 16 : for (const char opt : "abcdef")
430 14 : BOOST_CHECK(testArgs.IsArgSet({'-', opt}) || !opt);
431 :
432 : // Nothing else should be in the map
433 2 : BOOST_CHECK(testArgs.m_settings.command_line_options.size() == 6 &&
434 : testArgs.m_settings.ro_config.empty());
435 :
436 : // The -no prefix should get stripped on the way in.
437 2 : BOOST_CHECK(!testArgs.IsArgSet("-nob"));
438 :
439 : // The -b option is flagged as negated, and nothing else is
440 2 : BOOST_CHECK(testArgs.IsArgNegated("-b"));
441 2 : BOOST_CHECK(!testArgs.IsArgNegated("-a"));
442 :
443 : // Check expected values.
444 2 : BOOST_CHECK(testArgs.GetBoolArg("-a", false) == true);
445 2 : BOOST_CHECK(testArgs.GetBoolArg("-b", true) == false);
446 2 : BOOST_CHECK(testArgs.GetBoolArg("-c", true) == false);
447 2 : BOOST_CHECK(testArgs.GetBoolArg("-d", false) == true);
448 2 : BOOST_CHECK(testArgs.GetBoolArg("-e", true) == false);
449 2 : BOOST_CHECK(testArgs.GetBoolArg("-f", true) == false);
450 2 : }
451 :
452 101 : BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
453 : {
454 : // Test some awful edge cases that hopefully no user will ever exercise.
455 2 : TestArgsManager testArgs;
456 :
457 : // Params test
458 2 : const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY);
459 2 : const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY);
460 2 : const char *argv_test[] = {"ignored", "-nofoo", "-foo", "-nobar=0"};
461 4 : testArgs.SetupArgs({foo, bar});
462 2 : std::string error;
463 2 : BOOST_CHECK(testArgs.ParseParameters(4, (char**)argv_test, error));
464 :
465 : // This was passed twice, second one overrides the negative setting.
466 2 : BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
467 2 : BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "");
468 :
469 : // A double negative is a positive, and not marked as negated.
470 2 : BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
471 2 : BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
472 :
473 : // Config test
474 : const char *conf_test = "nofoo=1\nfoo=1\nnobar=0\n";
475 2 : BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error));
476 2 : testArgs.ReadConfigString(conf_test);
477 :
478 : // This was passed twice, second one overrides the negative setting,
479 : // and the value.
480 2 : BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
481 2 : BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "1");
482 :
483 : // A double negative is a positive, and does not count as negated.
484 2 : BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
485 2 : BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
486 :
487 : // Combined test
488 2 : const char *combo_test_args[] = {"ignored", "-nofoo", "-bar"};
489 : const char *combo_test_conf = "foo=1\nnobar=1\n";
490 2 : BOOST_CHECK(testArgs.ParseParameters(3, (char**)combo_test_args, error));
491 2 : testArgs.ReadConfigString(combo_test_conf);
492 :
493 : // Command line overrides, but doesn't erase old setting
494 2 : BOOST_CHECK(testArgs.IsArgNegated("-foo"));
495 2 : BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "0");
496 2 : BOOST_CHECK(testArgs.GetArgs("-foo").size() == 0);
497 :
498 : // Command line overrides, but doesn't erase old setting
499 2 : BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
500 2 : BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "");
501 2 : BOOST_CHECK(testArgs.GetArgs("-bar").size() == 1
502 : && testArgs.GetArgs("-bar").front() == "");
503 2 : }
504 :
505 101 : BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
506 : {
507 : const char *str_config =
508 : "a=\n"
509 : "b=1\n"
510 : "ccc=argument\n"
511 : "ccc=multiple\n"
512 : "d=e\n"
513 : "nofff=1\n"
514 : "noggg=0\n"
515 : "h=1\n"
516 : "noh=1\n"
517 : "noi=1\n"
518 : "i=1\n"
519 : "sec1.ccc=extend1\n"
520 : "\n"
521 : "[sec1]\n"
522 : "ccc=extend2\n"
523 : "d=eee\n"
524 : "h=1\n"
525 : "[sec2]\n"
526 : "ccc=extend3\n"
527 : "iii=2\n";
528 :
529 2 : TestArgsManager test_args;
530 2 : LOCK(test_args.cs_args);
531 2 : const auto a = std::make_pair("-a", ArgsManager::ALLOW_ANY);
532 2 : const auto b = std::make_pair("-b", ArgsManager::ALLOW_ANY);
533 2 : const auto ccc = std::make_pair("-ccc", ArgsManager::ALLOW_ANY);
534 2 : const auto d = std::make_pair("-d", ArgsManager::ALLOW_ANY);
535 2 : const auto e = std::make_pair("-e", ArgsManager::ALLOW_ANY);
536 2 : const auto fff = std::make_pair("-fff", ArgsManager::ALLOW_ANY);
537 2 : const auto ggg = std::make_pair("-ggg", ArgsManager::ALLOW_ANY);
538 2 : const auto h = std::make_pair("-h", ArgsManager::ALLOW_ANY);
539 2 : const auto i = std::make_pair("-i", ArgsManager::ALLOW_ANY);
540 2 : const auto iii = std::make_pair("-iii", ArgsManager::ALLOW_ANY);
541 20 : test_args.SetupArgs({a, b, ccc, d, e, fff, ggg, h, i, iii});
542 :
543 2 : test_args.ReadConfigString(str_config);
544 : // expectation: a, b, ccc, d, fff, ggg, h, i end up in map
545 : // so do sec1.ccc, sec1.d, sec1.h, sec2.ccc, sec2.iii
546 :
547 2 : BOOST_CHECK(test_args.m_settings.command_line_options.empty());
548 2 : BOOST_CHECK(test_args.m_settings.ro_config.size() == 3);
549 2 : BOOST_CHECK(test_args.m_settings.ro_config[""].size() == 8);
550 2 : BOOST_CHECK(test_args.m_settings.ro_config["sec1"].size() == 3);
551 2 : BOOST_CHECK(test_args.m_settings.ro_config["sec2"].size() == 2);
552 :
553 2 : BOOST_CHECK(test_args.m_settings.ro_config[""].count("a"));
554 2 : BOOST_CHECK(test_args.m_settings.ro_config[""].count("b"));
555 2 : BOOST_CHECK(test_args.m_settings.ro_config[""].count("ccc"));
556 2 : BOOST_CHECK(test_args.m_settings.ro_config[""].count("d"));
557 2 : BOOST_CHECK(test_args.m_settings.ro_config[""].count("fff"));
558 2 : BOOST_CHECK(test_args.m_settings.ro_config[""].count("ggg"));
559 2 : BOOST_CHECK(test_args.m_settings.ro_config[""].count("h"));
560 2 : BOOST_CHECK(test_args.m_settings.ro_config[""].count("i"));
561 2 : BOOST_CHECK(test_args.m_settings.ro_config["sec1"].count("ccc"));
562 2 : BOOST_CHECK(test_args.m_settings.ro_config["sec1"].count("h"));
563 2 : BOOST_CHECK(test_args.m_settings.ro_config["sec2"].count("ccc"));
564 2 : BOOST_CHECK(test_args.m_settings.ro_config["sec2"].count("iii"));
565 :
566 2 : BOOST_CHECK(test_args.IsArgSet("-a"));
567 2 : BOOST_CHECK(test_args.IsArgSet("-b"));
568 2 : BOOST_CHECK(test_args.IsArgSet("-ccc"));
569 2 : BOOST_CHECK(test_args.IsArgSet("-d"));
570 2 : BOOST_CHECK(test_args.IsArgSet("-fff"));
571 2 : BOOST_CHECK(test_args.IsArgSet("-ggg"));
572 2 : BOOST_CHECK(test_args.IsArgSet("-h"));
573 2 : BOOST_CHECK(test_args.IsArgSet("-i"));
574 2 : BOOST_CHECK(!test_args.IsArgSet("-zzz"));
575 2 : BOOST_CHECK(!test_args.IsArgSet("-iii"));
576 :
577 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-a", "xxx"), "");
578 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-b", "xxx"), "1");
579 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-ccc", "xxx"), "argument");
580 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-d", "xxx"), "e");
581 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-fff", "xxx"), "0");
582 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-ggg", "xxx"), "1");
583 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-h", "xxx"), "0");
584 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-i", "xxx"), "1");
585 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-zzz", "xxx"), "xxx");
586 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-iii", "xxx"), "xxx");
587 :
588 6 : for (const bool def : {false, true}) {
589 4 : BOOST_CHECK(test_args.GetBoolArg("-a", def));
590 4 : BOOST_CHECK(test_args.GetBoolArg("-b", def));
591 4 : BOOST_CHECK(!test_args.GetBoolArg("-ccc", def));
592 4 : BOOST_CHECK(!test_args.GetBoolArg("-d", def));
593 4 : BOOST_CHECK(!test_args.GetBoolArg("-fff", def));
594 4 : BOOST_CHECK(test_args.GetBoolArg("-ggg", def));
595 4 : BOOST_CHECK(!test_args.GetBoolArg("-h", def));
596 4 : BOOST_CHECK(test_args.GetBoolArg("-i", def));
597 4 : BOOST_CHECK(test_args.GetBoolArg("-zzz", def) == def);
598 4 : BOOST_CHECK(test_args.GetBoolArg("-iii", def) == def);
599 : }
600 :
601 2 : BOOST_CHECK(test_args.GetArgs("-a").size() == 1
602 : && test_args.GetArgs("-a").front() == "");
603 2 : BOOST_CHECK(test_args.GetArgs("-b").size() == 1
604 : && test_args.GetArgs("-b").front() == "1");
605 2 : BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2
606 : && test_args.GetArgs("-ccc").front() == "argument"
607 : && test_args.GetArgs("-ccc").back() == "multiple");
608 2 : BOOST_CHECK(test_args.GetArgs("-fff").size() == 0);
609 2 : BOOST_CHECK(test_args.GetArgs("-nofff").size() == 0);
610 2 : BOOST_CHECK(test_args.GetArgs("-ggg").size() == 1
611 : && test_args.GetArgs("-ggg").front() == "1");
612 2 : BOOST_CHECK(test_args.GetArgs("-noggg").size() == 0);
613 2 : BOOST_CHECK(test_args.GetArgs("-h").size() == 0);
614 2 : BOOST_CHECK(test_args.GetArgs("-noh").size() == 0);
615 2 : BOOST_CHECK(test_args.GetArgs("-i").size() == 1
616 : && test_args.GetArgs("-i").front() == "1");
617 2 : BOOST_CHECK(test_args.GetArgs("-noi").size() == 0);
618 2 : BOOST_CHECK(test_args.GetArgs("-zzz").size() == 0);
619 :
620 2 : BOOST_CHECK(!test_args.IsArgNegated("-a"));
621 2 : BOOST_CHECK(!test_args.IsArgNegated("-b"));
622 2 : BOOST_CHECK(!test_args.IsArgNegated("-ccc"));
623 2 : BOOST_CHECK(!test_args.IsArgNegated("-d"));
624 2 : BOOST_CHECK(test_args.IsArgNegated("-fff"));
625 2 : BOOST_CHECK(!test_args.IsArgNegated("-ggg"));
626 2 : BOOST_CHECK(test_args.IsArgNegated("-h")); // last setting takes precedence
627 2 : BOOST_CHECK(!test_args.IsArgNegated("-i")); // last setting takes precedence
628 2 : BOOST_CHECK(!test_args.IsArgNegated("-zzz"));
629 :
630 : // Test sections work
631 2 : test_args.SelectConfigNetwork("sec1");
632 :
633 : // same as original
634 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-a", "xxx"), "");
635 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-b", "xxx"), "1");
636 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-fff", "xxx"), "0");
637 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-ggg", "xxx"), "1");
638 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-zzz", "xxx"), "xxx");
639 2 : BOOST_CHECK_EQUAL(test_args.GetArg("-iii", "xxx"), "xxx");
640 : // d is overridden
641 2 : BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
642 : // section-specific setting
643 2 : BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
644 : // section takes priority for multiple values
645 2 : BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend1");
646 : // check multiple values works
647 8 : const std::vector<std::string> sec1_ccc_expected = {"extend1","extend2","argument","multiple"};
648 2 : const auto& sec1_ccc_res = test_args.GetArgs("-ccc");
649 2 : BOOST_CHECK_EQUAL_COLLECTIONS(sec1_ccc_res.begin(), sec1_ccc_res.end(), sec1_ccc_expected.begin(), sec1_ccc_expected.end());
650 :
651 2 : test_args.SelectConfigNetwork("sec2");
652 :
653 : // same as original
654 2 : BOOST_CHECK(test_args.GetArg("-a", "xxx") == "");
655 2 : BOOST_CHECK(test_args.GetArg("-b", "xxx") == "1");
656 2 : BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e");
657 2 : BOOST_CHECK(test_args.GetArg("-fff", "xxx") == "0");
658 2 : BOOST_CHECK(test_args.GetArg("-ggg", "xxx") == "1");
659 2 : BOOST_CHECK(test_args.GetArg("-zzz", "xxx") == "xxx");
660 2 : BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
661 : // section-specific setting
662 2 : BOOST_CHECK(test_args.GetArg("-iii", "xxx") == "2");
663 : // section takes priority for multiple values
664 2 : BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend3");
665 : // check multiple values works
666 6 : const std::vector<std::string> sec2_ccc_expected = {"extend3","argument","multiple"};
667 2 : const auto& sec2_ccc_res = test_args.GetArgs("-ccc");
668 2 : BOOST_CHECK_EQUAL_COLLECTIONS(sec2_ccc_res.begin(), sec2_ccc_res.end(), sec2_ccc_expected.begin(), sec2_ccc_expected.end());
669 :
670 : // Test section only options
671 :
672 2 : test_args.SetNetworkOnlyArg("-d");
673 2 : test_args.SetNetworkOnlyArg("-ccc");
674 2 : test_args.SetNetworkOnlyArg("-h");
675 :
676 2 : test_args.SelectConfigNetwork(CBaseChainParams::MAIN);
677 2 : BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e");
678 2 : BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
679 2 : BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
680 :
681 2 : test_args.SelectConfigNetwork("sec1");
682 2 : BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
683 2 : BOOST_CHECK(test_args.GetArgs("-d").size() == 1);
684 2 : BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
685 2 : BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
686 :
687 2 : test_args.SelectConfigNetwork("sec2");
688 2 : BOOST_CHECK(test_args.GetArg("-d", "xxx") == "xxx");
689 2 : BOOST_CHECK(test_args.GetArgs("-d").size() == 0);
690 2 : BOOST_CHECK(test_args.GetArgs("-ccc").size() == 1);
691 2 : BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
692 2 : }
693 :
694 101 : BOOST_AUTO_TEST_CASE(util_GetArg)
695 : {
696 2 : TestArgsManager testArgs;
697 2 : LOCK(testArgs.cs_args);
698 2 : testArgs.m_settings.command_line_options.clear();
699 2 : testArgs.m_settings.command_line_options["strtest1"] = {"string..."};
700 : // strtest2 undefined on purpose
701 2 : testArgs.m_settings.command_line_options["inttest1"] = {"12345"};
702 2 : testArgs.m_settings.command_line_options["inttest2"] = {"81985529216486895"};
703 : // inttest3 undefined on purpose
704 2 : testArgs.m_settings.command_line_options["booltest1"] = {""};
705 : // booltest2 undefined on purpose
706 2 : testArgs.m_settings.command_line_options["booltest3"] = {"0"};
707 2 : testArgs.m_settings.command_line_options["booltest4"] = {"1"};
708 :
709 : // priorities
710 4 : testArgs.m_settings.command_line_options["pritest1"] = {"a", "b"};
711 4 : testArgs.m_settings.ro_config[""]["pritest2"] = {"a", "b"};
712 2 : testArgs.m_settings.command_line_options["pritest3"] = {"a"};
713 2 : testArgs.m_settings.ro_config[""]["pritest3"] = {"b"};
714 4 : testArgs.m_settings.command_line_options["pritest4"] = {"a","b"};
715 4 : testArgs.m_settings.ro_config[""]["pritest4"] = {"c","d"};
716 :
717 2 : BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "string...");
718 2 : BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default");
719 2 : BOOST_CHECK_EQUAL(testArgs.GetArg("inttest1", -1), 12345);
720 2 : BOOST_CHECK_EQUAL(testArgs.GetArg("inttest2", -1), 81985529216486895LL);
721 2 : BOOST_CHECK_EQUAL(testArgs.GetArg("inttest3", -1), -1);
722 2 : BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", false), true);
723 2 : BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest2", false), false);
724 2 : BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest3", false), false);
725 2 : BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest4", false), true);
726 :
727 2 : BOOST_CHECK_EQUAL(testArgs.GetArg("pritest1", "default"), "b");
728 2 : BOOST_CHECK_EQUAL(testArgs.GetArg("pritest2", "default"), "a");
729 2 : BOOST_CHECK_EQUAL(testArgs.GetArg("pritest3", "default"), "a");
730 2 : BOOST_CHECK_EQUAL(testArgs.GetArg("pritest4", "default"), "b");
731 2 : }
732 :
733 101 : BOOST_AUTO_TEST_CASE(util_GetChainName)
734 : {
735 2 : TestArgsManager test_args;
736 2 : const auto testnet = std::make_pair("-testnet", ArgsManager::ALLOW_ANY);
737 2 : const auto regtest = std::make_pair("-regtest", ArgsManager::ALLOW_ANY);
738 4 : test_args.SetupArgs({testnet, regtest});
739 :
740 2 : const char* argv_testnet[] = {"cmd", "-testnet"};
741 2 : const char* argv_regtest[] = {"cmd", "-regtest"};
742 2 : const char* argv_test_no_reg[] = {"cmd", "-testnet", "-noregtest"};
743 2 : const char* argv_both[] = {"cmd", "-testnet", "-regtest"};
744 :
745 : // equivalent to "-testnet"
746 : // regtest in testnet section is ignored
747 : const char* testnetconf = "testnet=1\nregtest=0\n[test]\nregtest=1";
748 2 : std::string error;
749 :
750 2 : BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
751 2 : BOOST_CHECK_EQUAL(test_args.GetChainName(), "main");
752 :
753 2 : BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
754 2 : BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
755 :
756 2 : BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
757 2 : BOOST_CHECK_EQUAL(test_args.GetChainName(), "regtest");
758 :
759 2 : BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error));
760 2 : BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
761 :
762 2 : BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
763 4 : BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
764 :
765 2 : BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
766 2 : test_args.ReadConfigString(testnetconf);
767 2 : BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
768 :
769 2 : BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
770 2 : test_args.ReadConfigString(testnetconf);
771 2 : BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
772 :
773 2 : BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
774 2 : test_args.ReadConfigString(testnetconf);
775 4 : BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
776 :
777 2 : BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error));
778 2 : test_args.ReadConfigString(testnetconf);
779 2 : BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
780 :
781 2 : BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
782 2 : test_args.ReadConfigString(testnetconf);
783 4 : BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
784 :
785 : // check setting the network to test (and thus making
786 : // [test] regtest=1 potentially relevant) doesn't break things
787 2 : test_args.SelectConfigNetwork("test");
788 :
789 2 : BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
790 2 : test_args.ReadConfigString(testnetconf);
791 2 : BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
792 :
793 2 : BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
794 2 : test_args.ReadConfigString(testnetconf);
795 2 : BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
796 :
797 2 : BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
798 2 : test_args.ReadConfigString(testnetconf);
799 4 : BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
800 :
801 2 : BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_test_no_reg, error));
802 2 : test_args.ReadConfigString(testnetconf);
803 2 : BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
804 :
805 2 : BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
806 2 : test_args.ReadConfigString(testnetconf);
807 4 : BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
808 12 : }
809 :
810 : // Test different ways settings can be merged, and verify results. This test can
811 : // be used to confirm that updates to settings code don't change behavior
812 : // unintentionally.
813 : //
814 : // The test covers:
815 : //
816 : // - Combining different setting actions. Possible actions are: configuring a
817 : // setting, negating a setting (adding "-no" prefix), and configuring/negating
818 : // settings in a network section (adding "main." or "test." prefixes).
819 : //
820 : // - Combining settings from command line arguments and a config file.
821 : //
822 : // - Combining SoftSet and ForceSet calls.
823 : //
824 : // - Testing "main" and "test" network values to make sure settings from network
825 : // sections are applied and to check for mainnet-specific behaviors like
826 : // inheriting settings from the default section.
827 : //
828 : // - Testing network-specific settings like "-wallet", that may be ignored
829 : // outside a network section, and non-network specific settings like "-server"
830 : // that aren't sensitive to the network.
831 : //
832 4 : struct ArgsMergeTestingSetup : public BasicTestingSetup {
833 : //! Max number of actions to sequence together. Can decrease this when
834 : //! debugging to make test results easier to understand.
835 : static constexpr int MAX_ACTIONS = 3;
836 :
837 : enum Action { NONE, SET, NEGATE, SECTION_SET, SECTION_NEGATE };
838 : using ActionList = Action[MAX_ACTIONS];
839 :
840 : //! Enumerate all possible test configurations.
841 : template <typename Fn>
842 2 : void ForEachMergeSetup(Fn&& fn)
843 : {
844 2 : ActionList arg_actions = {};
845 : // command_line_options do not have sections. Only iterate over SET and NEGATE
846 16 : ForEachNoDup(arg_actions, SET, NEGATE, [&] {
847 14 : ActionList conf_actions = {};
848 756 : ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] {
849 2226 : for (bool soft_set : {false, true}) {
850 4452 : for (bool force_set : {false, true}) {
851 11872 : for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) {
852 23744 : for (const std::string& network : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) {
853 35616 : for (bool net_specific : {false, true}) {
854 23744 : fn(arg_actions, conf_actions, soft_set, force_set, section, network, net_specific);
855 : }
856 : }
857 : }
858 : }
859 : }
860 742 : });
861 14 : });
862 2 : }
863 :
864 : //! Translate actions into a list of <key>=<value> setting strings.
865 47488 : std::vector<std::string> GetValues(const ActionList& actions,
866 : const std::string& section,
867 : const std::string& name,
868 : const std::string& value_prefix)
869 : {
870 47488 : std::vector<std::string> values;
871 47488 : int suffix = 0;
872 149120 : for (Action action : actions) {
873 126208 : if (action == NONE) break;
874 101632 : std::string prefix;
875 101632 : if (action == SECTION_SET || action == SECTION_NEGATE) prefix = section + ".";
876 101632 : if (action == SET || action == SECTION_SET) {
877 152448 : for (int i = 0; i < 2; ++i) {
878 101632 : values.push_back(prefix + name + "=" + value_prefix + ToString(++suffix));
879 : }
880 50816 : }
881 101632 : if (action == NEGATE || action == SECTION_NEGATE) {
882 50816 : values.push_back(prefix + "no" + name + "=1");
883 50816 : }
884 101632 : }
885 : return values;
886 47488 : }
887 : };
888 :
889 : // Regression test covering different ways config settings can be merged. The
890 : // test parses and merges settings, representing the results as strings that get
891 : // compared against an expected hash. To debug, the result strings can be dumped
892 : // to a file (see comments below).
893 101 : BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
894 : {
895 2 : CHash256 out_sha;
896 2 : FILE* out_file = nullptr;
897 2 : if (const char* out_path = getenv("ARGS_MERGE_TEST_OUT")) {
898 0 : out_file = fsbridge::fopen(out_path, "w");
899 0 : if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed");
900 : }
901 :
902 23746 : ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions, bool soft_set, bool force_set,
903 : const std::string& section, const std::string& network, bool net_specific) {
904 23744 : TestArgsManager parser;
905 23744 : LOCK(parser.cs_args);
906 :
907 23744 : std::string desc = "net=";
908 23744 : desc += network;
909 23744 : parser.m_network = network;
910 :
911 23744 : const std::string& name = net_specific ? "wallet" : "server";
912 23744 : const std::string key = "-" + name;
913 23744 : parser.AddArg(key, name, ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
914 23744 : if (net_specific) parser.SetNetworkOnlyArg(key);
915 :
916 23744 : auto args = GetValues(arg_actions, section, name, "a");
917 23744 : std::vector<const char*> argv = {"ignored"};
918 84800 : for (auto& arg : args) {
919 61056 : arg.insert(0, "-");
920 61056 : desc += " ";
921 61056 : desc += arg;
922 61056 : argv.push_back(arg.c_str());
923 : }
924 23744 : std::string error;
925 23744 : BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error));
926 23744 : BOOST_CHECK_EQUAL(error, "");
927 :
928 23744 : std::string conf;
929 115136 : for (auto& conf_val : GetValues(conf_actions, section, name, "c")) {
930 91392 : desc += " ";
931 91392 : desc += conf_val;
932 91392 : conf += conf_val;
933 91392 : conf += "\n";
934 : }
935 23744 : std::istringstream conf_stream(conf);
936 23744 : BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error));
937 23744 : BOOST_CHECK_EQUAL(error, "");
938 :
939 23744 : if (soft_set) {
940 11872 : desc += " soft";
941 11872 : parser.SoftSetArg(key, "soft1");
942 11872 : parser.SoftSetArg(key, "soft2");
943 11872 : }
944 :
945 23744 : if (force_set) {
946 11872 : desc += " force";
947 11872 : parser.ForceSetArg(key, "force1");
948 11872 : parser.ForceSetArg(key, "force2");
949 11872 : }
950 :
951 23744 : desc += " || ";
952 :
953 23744 : if (!parser.IsArgSet(key)) {
954 116 : desc += "unset";
955 116 : BOOST_CHECK(!parser.IsArgNegated(key));
956 116 : BOOST_CHECK_EQUAL(parser.GetArg(key, "default"), "default");
957 116 : BOOST_CHECK(parser.GetArgs(key).empty());
958 23628 : } else if (parser.IsArgNegated(key)) {
959 5872 : desc += "negated";
960 5872 : BOOST_CHECK_EQUAL(parser.GetArg(key, "default"), "0");
961 5872 : BOOST_CHECK(parser.GetArgs(key).empty());
962 : } else {
963 17756 : desc += parser.GetArg(key, "default");
964 17756 : desc += " |";
965 61656 : for (const auto& arg : parser.GetArgs(key)) {
966 43900 : desc += " ";
967 43900 : desc += arg;
968 : }
969 : }
970 :
971 23744 : std::set<std::string> ignored = parser.GetUnsuitableSectionOnlyArgs();
972 23744 : if (!ignored.empty()) {
973 524 : desc += " | ignored";
974 1048 : for (const auto& arg : ignored) {
975 524 : desc += " ";
976 524 : desc += arg;
977 0 : }
978 524 : }
979 :
980 23744 : desc += "\n";
981 :
982 23744 : out_sha.Write(MakeUCharSpan(desc));
983 23744 : if (out_file) {
984 0 : BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
985 : }
986 23744 : });
987 :
988 2 : if (out_file) {
989 0 : if (fclose(out_file)) throw std::system_error(errno, std::generic_category(), "fclose failed");
990 0 : out_file = nullptr;
991 0 : }
992 :
993 2 : unsigned char out_sha_bytes[CSHA256::OUTPUT_SIZE];
994 2 : out_sha.Finalize(out_sha_bytes);
995 2 : std::string out_sha_hex = HexStr(out_sha_bytes);
996 :
997 : // If check below fails, should manually dump the results with:
998 : //
999 : // ARGS_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ArgsMerge
1000 : //
1001 : // And verify diff against previous results to make sure the changes are expected.
1002 : //
1003 : // Results file is formatted like:
1004 : //
1005 : // <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output>
1006 2 : BOOST_CHECK_EQUAL(out_sha_hex, "8fd4877bb8bf337badca950ede6c917441901962f160e52514e06a60dea46cde");
1007 2 : }
1008 :
1009 : // Similar test as above, but for ArgsManager::GetChainName function.
1010 4 : struct ChainMergeTestingSetup : public BasicTestingSetup {
1011 : static constexpr int MAX_ACTIONS = 2;
1012 :
1013 : enum Action { NONE, ENABLE_TEST, DISABLE_TEST, NEGATE_TEST, ENABLE_REG, DISABLE_REG, NEGATE_REG };
1014 : using ActionList = Action[MAX_ACTIONS];
1015 :
1016 : //! Enumerate all possible test configurations.
1017 : template <typename Fn>
1018 2 : void ForEachMergeSetup(Fn&& fn)
1019 : {
1020 2 : ActionList arg_actions = {};
1021 76 : ForEachNoDup(arg_actions, ENABLE_TEST, NEGATE_REG, [&] {
1022 74 : ActionList conf_actions = {};
1023 2812 : ForEachNoDup(conf_actions, ENABLE_TEST, NEGATE_REG, [&] { fn(arg_actions, conf_actions); });
1024 74 : });
1025 2 : }
1026 : };
1027 :
1028 101 : BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
1029 : {
1030 2 : CHash256 out_sha;
1031 2 : FILE* out_file = nullptr;
1032 2 : if (const char* out_path = getenv("CHAIN_MERGE_TEST_OUT")) {
1033 0 : out_file = fsbridge::fopen(out_path, "w");
1034 0 : if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed");
1035 : }
1036 :
1037 2740 : ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions) {
1038 2738 : TestArgsManager parser;
1039 2738 : LOCK(parser.cs_args);
1040 2738 : parser.AddArg("-regtest", "regtest", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
1041 2738 : parser.AddArg("-testnet", "testnet", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
1042 :
1043 22718 : auto arg = [](Action action) { return action == ENABLE_TEST ? "-testnet=1" :
1044 9176 : action == DISABLE_TEST ? "-testnet=0" :
1045 7548 : action == NEGATE_TEST ? "-notestnet=1" :
1046 5920 : action == ENABLE_REG ? "-regtest=1" :
1047 4292 : action == DISABLE_REG ? "-regtest=0" :
1048 2664 : action == NEGATE_REG ? "-noregtest=1" : nullptr; };
1049 :
1050 2738 : std::string desc;
1051 2738 : std::vector<const char*> argv = {"ignored"};
1052 7622 : for (Action action : arg_actions) {
1053 5402 : const char* argstr = arg(action);
1054 5402 : if (!argstr) break;
1055 4884 : argv.push_back(argstr);
1056 4884 : desc += " ";
1057 4884 : desc += argv.back();
1058 5402 : }
1059 2738 : std::string error;
1060 2738 : BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error));
1061 2738 : BOOST_CHECK_EQUAL(error, "");
1062 :
1063 2738 : std::string conf;
1064 7622 : for (Action action : conf_actions) {
1065 5402 : const char* argstr = arg(action);
1066 5402 : if (!argstr) break;
1067 4884 : desc += " ";
1068 4884 : desc += argstr + 1;
1069 4884 : conf += argstr + 1;
1070 4884 : conf += "\n";
1071 9768 : }
1072 2738 : std::istringstream conf_stream(conf);
1073 2738 : BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error));
1074 2738 : BOOST_CHECK_EQUAL(error, "");
1075 :
1076 2738 : desc += " || ";
1077 : try {
1078 3102 : desc += parser.GetChainName();
1079 2738 : } catch (const std::runtime_error& e) {
1080 364 : desc += "error: ";
1081 364 : desc += e.what();
1082 364 : }
1083 2738 : desc += "\n";
1084 :
1085 2738 : out_sha.Write(MakeUCharSpan(desc));
1086 2738 : if (out_file) {
1087 0 : BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
1088 : }
1089 3102 : });
1090 :
1091 2 : if (out_file) {
1092 0 : if (fclose(out_file)) throw std::system_error(errno, std::generic_category(), "fclose failed");
1093 0 : out_file = nullptr;
1094 0 : }
1095 :
1096 2 : unsigned char out_sha_bytes[CSHA256::OUTPUT_SIZE];
1097 2 : out_sha.Finalize(out_sha_bytes);
1098 2 : std::string out_sha_hex = HexStr(out_sha_bytes);
1099 :
1100 : // If check below fails, should manually dump the results with:
1101 : //
1102 : // CHAIN_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ChainMerge
1103 : //
1104 : // And verify diff against previous results to make sure the changes are expected.
1105 : //
1106 : // Results file is formatted like:
1107 : //
1108 : // <input> || <output>
1109 2 : BOOST_CHECK_EQUAL(out_sha_hex, "f0b3a3c29869edc765d579c928f7f1690a71fbb673b49ccf39cbc4de18156a0d");
1110 2 : }
1111 :
1112 101 : BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
1113 : {
1114 : // Test writing setting.
1115 2 : TestArgsManager args1;
1116 4 : args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; });
1117 2 : args1.WriteSettingsFile();
1118 :
1119 : // Test reading setting.
1120 2 : TestArgsManager args2;
1121 2 : args2.ReadSettingsFile();
1122 4 : args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); });
1123 :
1124 : // Test error logging, and remove previously written setting.
1125 : {
1126 2 : ASSERT_DEBUG_LOG("Failed renaming settings file");
1127 2 : fs::remove(GetDataDir() / "settings.json");
1128 2 : fs::create_directory(GetDataDir() / "settings.json");
1129 2 : args2.WriteSettingsFile();
1130 2 : fs::remove(GetDataDir() / "settings.json");
1131 2 : }
1132 2 : }
1133 :
1134 101 : BOOST_AUTO_TEST_CASE(util_FormatMoney)
1135 : {
1136 2 : BOOST_CHECK_EQUAL(FormatMoney(0), "0.00");
1137 2 : BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789), "12345.6789");
1138 2 : BOOST_CHECK_EQUAL(FormatMoney(-COIN), "-1.00");
1139 :
1140 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000), "100000000.00");
1141 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000), "10000000.00");
1142 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000), "1000000.00");
1143 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN*100000), "100000.00");
1144 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN*10000), "10000.00");
1145 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN*1000), "1000.00");
1146 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN*100), "100.00");
1147 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN*10), "10.00");
1148 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN), "1.00");
1149 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN/10), "0.10");
1150 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN/100), "0.01");
1151 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN/1000), "0.001");
1152 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN/10000), "0.0001");
1153 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN/100000), "0.00001");
1154 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000), "0.000001");
1155 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000), "0.0000001");
1156 2 : BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000), "0.00000001");
1157 2 : }
1158 :
1159 101 : BOOST_AUTO_TEST_CASE(util_ParseMoney)
1160 : {
1161 2 : CAmount ret = 0;
1162 2 : BOOST_CHECK(ParseMoney("0.0", ret));
1163 2 : BOOST_CHECK_EQUAL(ret, 0);
1164 :
1165 2 : BOOST_CHECK(ParseMoney("12345.6789", ret));
1166 2 : BOOST_CHECK_EQUAL(ret, (COIN/10000)*123456789);
1167 :
1168 2 : BOOST_CHECK(ParseMoney("100000000.00", ret));
1169 2 : BOOST_CHECK_EQUAL(ret, COIN*100000000);
1170 2 : BOOST_CHECK(ParseMoney("10000000.00", ret));
1171 2 : BOOST_CHECK_EQUAL(ret, COIN*10000000);
1172 2 : BOOST_CHECK(ParseMoney("1000000.00", ret));
1173 2 : BOOST_CHECK_EQUAL(ret, COIN*1000000);
1174 2 : BOOST_CHECK(ParseMoney("100000.00", ret));
1175 2 : BOOST_CHECK_EQUAL(ret, COIN*100000);
1176 2 : BOOST_CHECK(ParseMoney("10000.00", ret));
1177 2 : BOOST_CHECK_EQUAL(ret, COIN*10000);
1178 2 : BOOST_CHECK(ParseMoney("1000.00", ret));
1179 2 : BOOST_CHECK_EQUAL(ret, COIN*1000);
1180 2 : BOOST_CHECK(ParseMoney("100.00", ret));
1181 2 : BOOST_CHECK_EQUAL(ret, COIN*100);
1182 2 : BOOST_CHECK(ParseMoney("10.00", ret));
1183 2 : BOOST_CHECK_EQUAL(ret, COIN*10);
1184 2 : BOOST_CHECK(ParseMoney("1.00", ret));
1185 2 : BOOST_CHECK_EQUAL(ret, COIN);
1186 2 : BOOST_CHECK(ParseMoney("1", ret));
1187 2 : BOOST_CHECK_EQUAL(ret, COIN);
1188 2 : BOOST_CHECK(ParseMoney(" 1", ret));
1189 2 : BOOST_CHECK_EQUAL(ret, COIN);
1190 2 : BOOST_CHECK(ParseMoney("1 ", ret));
1191 2 : BOOST_CHECK_EQUAL(ret, COIN);
1192 2 : BOOST_CHECK(ParseMoney(" 1 ", ret));
1193 2 : BOOST_CHECK_EQUAL(ret, COIN);
1194 2 : BOOST_CHECK(ParseMoney("0.1", ret));
1195 2 : BOOST_CHECK_EQUAL(ret, COIN/10);
1196 2 : BOOST_CHECK(ParseMoney("0.01", ret));
1197 2 : BOOST_CHECK_EQUAL(ret, COIN/100);
1198 2 : BOOST_CHECK(ParseMoney("0.001", ret));
1199 2 : BOOST_CHECK_EQUAL(ret, COIN/1000);
1200 2 : BOOST_CHECK(ParseMoney("0.0001", ret));
1201 2 : BOOST_CHECK_EQUAL(ret, COIN/10000);
1202 2 : BOOST_CHECK(ParseMoney("0.00001", ret));
1203 2 : BOOST_CHECK_EQUAL(ret, COIN/100000);
1204 2 : BOOST_CHECK(ParseMoney("0.000001", ret));
1205 2 : BOOST_CHECK_EQUAL(ret, COIN/1000000);
1206 2 : BOOST_CHECK(ParseMoney("0.0000001", ret));
1207 2 : BOOST_CHECK_EQUAL(ret, COIN/10000000);
1208 2 : BOOST_CHECK(ParseMoney("0.00000001", ret));
1209 2 : BOOST_CHECK_EQUAL(ret, COIN/100000000);
1210 2 : BOOST_CHECK(ParseMoney(" 0.00000001 ", ret));
1211 2 : BOOST_CHECK_EQUAL(ret, COIN/100000000);
1212 2 : BOOST_CHECK(ParseMoney("0.00000001 ", ret));
1213 2 : BOOST_CHECK_EQUAL(ret, COIN/100000000);
1214 2 : BOOST_CHECK(ParseMoney(" 0.00000001", ret));
1215 2 : BOOST_CHECK_EQUAL(ret, COIN/100000000);
1216 :
1217 : // Parsing amount that can not be represented in ret should fail
1218 2 : BOOST_CHECK(!ParseMoney("0.000000001", ret));
1219 :
1220 : // Parsing empty string should fail
1221 2 : BOOST_CHECK(!ParseMoney("", ret));
1222 2 : BOOST_CHECK(!ParseMoney(" ", ret));
1223 2 : BOOST_CHECK(!ParseMoney(" ", ret));
1224 :
1225 : // Parsing two numbers should fail
1226 2 : BOOST_CHECK(!ParseMoney("1 2", ret));
1227 2 : BOOST_CHECK(!ParseMoney(" 1 2 ", ret));
1228 2 : BOOST_CHECK(!ParseMoney(" 1.2 3 ", ret));
1229 2 : BOOST_CHECK(!ParseMoney(" 1 2.3 ", ret));
1230 :
1231 : // Attempted 63 bit overflow should fail
1232 2 : BOOST_CHECK(!ParseMoney("92233720368.54775808", ret));
1233 :
1234 : // Parsing negative amounts must fail
1235 2 : BOOST_CHECK(!ParseMoney("-1", ret));
1236 :
1237 : // Parsing strings with embedded NUL characters should fail
1238 2 : BOOST_CHECK(!ParseMoney(std::string("\0-1", 3), ret));
1239 2 : BOOST_CHECK(!ParseMoney(std::string("\01", 2), ret));
1240 2 : BOOST_CHECK(!ParseMoney(std::string("1\0", 2), ret));
1241 2 : }
1242 :
1243 101 : BOOST_AUTO_TEST_CASE(util_IsHex)
1244 : {
1245 2 : BOOST_CHECK(IsHex("00"));
1246 2 : BOOST_CHECK(IsHex("00112233445566778899aabbccddeeffAABBCCDDEEFF"));
1247 2 : BOOST_CHECK(IsHex("ff"));
1248 2 : BOOST_CHECK(IsHex("FF"));
1249 :
1250 2 : BOOST_CHECK(!IsHex(""));
1251 2 : BOOST_CHECK(!IsHex("0"));
1252 2 : BOOST_CHECK(!IsHex("a"));
1253 2 : BOOST_CHECK(!IsHex("eleven"));
1254 2 : BOOST_CHECK(!IsHex("00xx00"));
1255 2 : BOOST_CHECK(!IsHex("0x0000"));
1256 2 : }
1257 :
1258 101 : BOOST_AUTO_TEST_CASE(util_IsHexNumber)
1259 : {
1260 2 : BOOST_CHECK(IsHexNumber("0x0"));
1261 2 : BOOST_CHECK(IsHexNumber("0"));
1262 2 : BOOST_CHECK(IsHexNumber("0x10"));
1263 2 : BOOST_CHECK(IsHexNumber("10"));
1264 2 : BOOST_CHECK(IsHexNumber("0xff"));
1265 2 : BOOST_CHECK(IsHexNumber("ff"));
1266 2 : BOOST_CHECK(IsHexNumber("0xFfa"));
1267 2 : BOOST_CHECK(IsHexNumber("Ffa"));
1268 2 : BOOST_CHECK(IsHexNumber("0x00112233445566778899aabbccddeeffAABBCCDDEEFF"));
1269 2 : BOOST_CHECK(IsHexNumber("00112233445566778899aabbccddeeffAABBCCDDEEFF"));
1270 :
1271 2 : BOOST_CHECK(!IsHexNumber("")); // empty string not allowed
1272 2 : BOOST_CHECK(!IsHexNumber("0x")); // empty string after prefix not allowed
1273 2 : BOOST_CHECK(!IsHexNumber("0x0 ")); // no spaces at end,
1274 2 : BOOST_CHECK(!IsHexNumber(" 0x0")); // or beginning,
1275 2 : BOOST_CHECK(!IsHexNumber("0x 0")); // or middle,
1276 2 : BOOST_CHECK(!IsHexNumber(" ")); // etc.
1277 2 : BOOST_CHECK(!IsHexNumber("0x0ga")); // invalid character
1278 2 : BOOST_CHECK(!IsHexNumber("x0")); // broken prefix
1279 2 : BOOST_CHECK(!IsHexNumber("0x0x00")); // two prefixes not allowed
1280 :
1281 2 : }
1282 :
1283 101 : BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
1284 : {
1285 2 : SeedInsecureRand(SeedRand::ZEROS);
1286 20 : for (int mod=2;mod<11;mod++)
1287 : {
1288 : int mask = 1;
1289 : // Really rough binomial confidence approximation.
1290 18 : int err = 30*10000./mod*sqrt((1./mod*(1-1./mod))/10000.);
1291 : //mask is 2^ceil(log2(mod))-1
1292 50 : while(mask<mod-1)mask=(mask<<1)+1;
1293 :
1294 : int count = 0;
1295 : //How often does it get a zero from the uniform range [0,mod)?
1296 180018 : for (int i = 0; i < 10000; i++) {
1297 : uint32_t rval;
1298 180000 : do{
1299 235652 : rval=InsecureRand32()&mask;
1300 235652 : }while(rval>=(uint32_t)mod);
1301 180000 : count += rval==0;
1302 : }
1303 18 : BOOST_CHECK(count<=10000/mod+err);
1304 18 : BOOST_CHECK(count>=10000/mod-err);
1305 : }
1306 2 : }
1307 :
1308 101 : BOOST_AUTO_TEST_CASE(util_TimingResistantEqual)
1309 : {
1310 2 : BOOST_CHECK(TimingResistantEqual(std::string(""), std::string("")));
1311 2 : BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string("")));
1312 2 : BOOST_CHECK(!TimingResistantEqual(std::string(""), std::string("abc")));
1313 2 : BOOST_CHECK(!TimingResistantEqual(std::string("a"), std::string("aa")));
1314 2 : BOOST_CHECK(!TimingResistantEqual(std::string("aa"), std::string("a")));
1315 2 : BOOST_CHECK(TimingResistantEqual(std::string("abc"), std::string("abc")));
1316 2 : BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string("aba")));
1317 2 : }
1318 :
1319 : /* Test strprintf formatting directives.
1320 : * Put a string before and after to ensure sanity of element sizes on stack. */
1321 : #define B "check_prefix"
1322 : #define E "check_postfix"
1323 101 : BOOST_AUTO_TEST_CASE(strprintf_numbers)
1324 : {
1325 2 : int64_t s64t = -9223372036854775807LL; /* signed 64 bit test value */
1326 2 : uint64_t u64t = 18446744073709551615ULL; /* unsigned 64 bit test value */
1327 2 : BOOST_CHECK(strprintf("%s %d %s", B, s64t, E) == B" -9223372036854775807 " E);
1328 2 : BOOST_CHECK(strprintf("%s %u %s", B, u64t, E) == B" 18446744073709551615 " E);
1329 2 : BOOST_CHECK(strprintf("%s %x %s", B, u64t, E) == B" ffffffffffffffff " E);
1330 :
1331 2 : size_t st = 12345678; /* unsigned size_t test value */
1332 2 : ssize_t sst = -12345678; /* signed size_t test value */
1333 2 : BOOST_CHECK(strprintf("%s %d %s", B, sst, E) == B" -12345678 " E);
1334 2 : BOOST_CHECK(strprintf("%s %u %s", B, st, E) == B" 12345678 " E);
1335 2 : BOOST_CHECK(strprintf("%s %x %s", B, st, E) == B" bc614e " E);
1336 :
1337 2 : ptrdiff_t pt = 87654321; /* positive ptrdiff_t test value */
1338 2 : ptrdiff_t spt = -87654321; /* negative ptrdiff_t test value */
1339 2 : BOOST_CHECK(strprintf("%s %d %s", B, spt, E) == B" -87654321 " E);
1340 2 : BOOST_CHECK(strprintf("%s %u %s", B, pt, E) == B" 87654321 " E);
1341 2 : BOOST_CHECK(strprintf("%s %x %s", B, pt, E) == B" 5397fb1 " E);
1342 2 : }
1343 : #undef B
1344 : #undef E
1345 :
1346 : /* Check for mingw/wine issue #3494
1347 : * Remove this test before time.ctime(0xffffffff) == 'Sun Feb 7 07:28:15 2106'
1348 : */
1349 101 : BOOST_AUTO_TEST_CASE(gettime)
1350 : {
1351 2 : BOOST_CHECK((GetTime() & ~0xFFFFFFFFLL) == 0);
1352 2 : }
1353 :
1354 101 : BOOST_AUTO_TEST_CASE(util_time_GetTime)
1355 : {
1356 2 : SetMockTime(111);
1357 : // Check that mock time does not change after a sleep
1358 6 : for (const auto& num_sleep : {0, 1}) {
1359 4 : UninterruptibleSleep(std::chrono::milliseconds{num_sleep});
1360 4 : BOOST_CHECK_EQUAL(111, GetTime()); // Deprecated time getter
1361 4 : BOOST_CHECK_EQUAL(111, GetTime<std::chrono::seconds>().count());
1362 4 : BOOST_CHECK_EQUAL(111000, GetTime<std::chrono::milliseconds>().count());
1363 4 : BOOST_CHECK_EQUAL(111000000, GetTime<std::chrono::microseconds>().count());
1364 : }
1365 :
1366 2 : SetMockTime(0);
1367 : // Check that system time changes after a sleep
1368 2 : const auto ms_0 = GetTime<std::chrono::milliseconds>();
1369 2 : const auto us_0 = GetTime<std::chrono::microseconds>();
1370 2 : UninterruptibleSleep(std::chrono::milliseconds{1});
1371 2 : BOOST_CHECK(ms_0 < GetTime<std::chrono::milliseconds>());
1372 2 : BOOST_CHECK(us_0 < GetTime<std::chrono::microseconds>());
1373 2 : }
1374 :
1375 101 : BOOST_AUTO_TEST_CASE(test_IsDigit)
1376 : {
1377 2 : BOOST_CHECK_EQUAL(IsDigit('0'), true);
1378 2 : BOOST_CHECK_EQUAL(IsDigit('1'), true);
1379 2 : BOOST_CHECK_EQUAL(IsDigit('8'), true);
1380 2 : BOOST_CHECK_EQUAL(IsDigit('9'), true);
1381 :
1382 2 : BOOST_CHECK_EQUAL(IsDigit('0' - 1), false);
1383 2 : BOOST_CHECK_EQUAL(IsDigit('9' + 1), false);
1384 2 : BOOST_CHECK_EQUAL(IsDigit(0), false);
1385 2 : BOOST_CHECK_EQUAL(IsDigit(1), false);
1386 2 : BOOST_CHECK_EQUAL(IsDigit(8), false);
1387 2 : BOOST_CHECK_EQUAL(IsDigit(9), false);
1388 2 : }
1389 :
1390 101 : BOOST_AUTO_TEST_CASE(test_ParseInt32)
1391 : {
1392 2 : int32_t n;
1393 : // Valid values
1394 2 : BOOST_CHECK(ParseInt32("1234", nullptr));
1395 2 : BOOST_CHECK(ParseInt32("0", &n) && n == 0);
1396 2 : BOOST_CHECK(ParseInt32("1234", &n) && n == 1234);
1397 2 : BOOST_CHECK(ParseInt32("01234", &n) && n == 1234); // no octal
1398 2 : BOOST_CHECK(ParseInt32("2147483647", &n) && n == 2147483647);
1399 2 : BOOST_CHECK(ParseInt32("-2147483648", &n) && n == (-2147483647 - 1)); // (-2147483647 - 1) equals INT_MIN
1400 2 : BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234);
1401 : // Invalid values
1402 2 : BOOST_CHECK(!ParseInt32("", &n));
1403 2 : BOOST_CHECK(!ParseInt32(" 1", &n)); // no padding inside
1404 2 : BOOST_CHECK(!ParseInt32("1 ", &n));
1405 2 : BOOST_CHECK(!ParseInt32("1a", &n));
1406 2 : BOOST_CHECK(!ParseInt32("aap", &n));
1407 2 : BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
1408 2 : BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
1409 2 : const char test_bytes[] = {'1', 0, '1'};
1410 2 : std::string teststr(test_bytes, sizeof(test_bytes));
1411 2 : BOOST_CHECK(!ParseInt32(teststr, &n)); // no embedded NULs
1412 : // Overflow and underflow
1413 2 : BOOST_CHECK(!ParseInt32("-2147483649", nullptr));
1414 2 : BOOST_CHECK(!ParseInt32("2147483648", nullptr));
1415 2 : BOOST_CHECK(!ParseInt32("-32482348723847471234", nullptr));
1416 2 : BOOST_CHECK(!ParseInt32("32482348723847471234", nullptr));
1417 2 : }
1418 :
1419 101 : BOOST_AUTO_TEST_CASE(test_ParseInt64)
1420 : {
1421 2 : int64_t n;
1422 : // Valid values
1423 2 : BOOST_CHECK(ParseInt64("1234", nullptr));
1424 2 : BOOST_CHECK(ParseInt64("0", &n) && n == 0LL);
1425 2 : BOOST_CHECK(ParseInt64("1234", &n) && n == 1234LL);
1426 2 : BOOST_CHECK(ParseInt64("01234", &n) && n == 1234LL); // no octal
1427 2 : BOOST_CHECK(ParseInt64("2147483647", &n) && n == 2147483647LL);
1428 2 : BOOST_CHECK(ParseInt64("-2147483648", &n) && n == -2147483648LL);
1429 2 : BOOST_CHECK(ParseInt64("9223372036854775807", &n) && n == (int64_t)9223372036854775807);
1430 2 : BOOST_CHECK(ParseInt64("-9223372036854775808", &n) && n == (int64_t)-9223372036854775807-1);
1431 2 : BOOST_CHECK(ParseInt64("-1234", &n) && n == -1234LL);
1432 : // Invalid values
1433 2 : BOOST_CHECK(!ParseInt64("", &n));
1434 2 : BOOST_CHECK(!ParseInt64(" 1", &n)); // no padding inside
1435 2 : BOOST_CHECK(!ParseInt64("1 ", &n));
1436 2 : BOOST_CHECK(!ParseInt64("1a", &n));
1437 2 : BOOST_CHECK(!ParseInt64("aap", &n));
1438 2 : BOOST_CHECK(!ParseInt64("0x1", &n)); // no hex
1439 2 : const char test_bytes[] = {'1', 0, '1'};
1440 2 : std::string teststr(test_bytes, sizeof(test_bytes));
1441 2 : BOOST_CHECK(!ParseInt64(teststr, &n)); // no embedded NULs
1442 : // Overflow and underflow
1443 2 : BOOST_CHECK(!ParseInt64("-9223372036854775809", nullptr));
1444 2 : BOOST_CHECK(!ParseInt64("9223372036854775808", nullptr));
1445 2 : BOOST_CHECK(!ParseInt64("-32482348723847471234", nullptr));
1446 2 : BOOST_CHECK(!ParseInt64("32482348723847471234", nullptr));
1447 2 : }
1448 :
1449 101 : BOOST_AUTO_TEST_CASE(test_ParseUInt32)
1450 : {
1451 2 : uint32_t n;
1452 : // Valid values
1453 2 : BOOST_CHECK(ParseUInt32("1234", nullptr));
1454 2 : BOOST_CHECK(ParseUInt32("0", &n) && n == 0);
1455 2 : BOOST_CHECK(ParseUInt32("1234", &n) && n == 1234);
1456 2 : BOOST_CHECK(ParseUInt32("01234", &n) && n == 1234); // no octal
1457 2 : BOOST_CHECK(ParseUInt32("2147483647", &n) && n == 2147483647);
1458 2 : BOOST_CHECK(ParseUInt32("2147483648", &n) && n == (uint32_t)2147483648);
1459 2 : BOOST_CHECK(ParseUInt32("4294967295", &n) && n == (uint32_t)4294967295);
1460 : // Invalid values
1461 2 : BOOST_CHECK(!ParseUInt32("", &n));
1462 2 : BOOST_CHECK(!ParseUInt32(" 1", &n)); // no padding inside
1463 2 : BOOST_CHECK(!ParseUInt32(" -1", &n));
1464 2 : BOOST_CHECK(!ParseUInt32("1 ", &n));
1465 2 : BOOST_CHECK(!ParseUInt32("1a", &n));
1466 2 : BOOST_CHECK(!ParseUInt32("aap", &n));
1467 2 : BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex
1468 2 : BOOST_CHECK(!ParseUInt32("0x1", &n)); // no hex
1469 2 : const char test_bytes[] = {'1', 0, '1'};
1470 2 : std::string teststr(test_bytes, sizeof(test_bytes));
1471 2 : BOOST_CHECK(!ParseUInt32(teststr, &n)); // no embedded NULs
1472 : // Overflow and underflow
1473 2 : BOOST_CHECK(!ParseUInt32("-2147483648", &n));
1474 2 : BOOST_CHECK(!ParseUInt32("4294967296", &n));
1475 2 : BOOST_CHECK(!ParseUInt32("-1234", &n));
1476 2 : BOOST_CHECK(!ParseUInt32("-32482348723847471234", nullptr));
1477 2 : BOOST_CHECK(!ParseUInt32("32482348723847471234", nullptr));
1478 2 : }
1479 :
1480 101 : BOOST_AUTO_TEST_CASE(test_ParseUInt64)
1481 : {
1482 2 : uint64_t n;
1483 : // Valid values
1484 2 : BOOST_CHECK(ParseUInt64("1234", nullptr));
1485 2 : BOOST_CHECK(ParseUInt64("0", &n) && n == 0LL);
1486 2 : BOOST_CHECK(ParseUInt64("1234", &n) && n == 1234LL);
1487 2 : BOOST_CHECK(ParseUInt64("01234", &n) && n == 1234LL); // no octal
1488 2 : BOOST_CHECK(ParseUInt64("2147483647", &n) && n == 2147483647LL);
1489 2 : BOOST_CHECK(ParseUInt64("9223372036854775807", &n) && n == 9223372036854775807ULL);
1490 2 : BOOST_CHECK(ParseUInt64("9223372036854775808", &n) && n == 9223372036854775808ULL);
1491 2 : BOOST_CHECK(ParseUInt64("18446744073709551615", &n) && n == 18446744073709551615ULL);
1492 : // Invalid values
1493 2 : BOOST_CHECK(!ParseUInt64("", &n));
1494 2 : BOOST_CHECK(!ParseUInt64(" 1", &n)); // no padding inside
1495 2 : BOOST_CHECK(!ParseUInt64(" -1", &n));
1496 2 : BOOST_CHECK(!ParseUInt64("1 ", &n));
1497 2 : BOOST_CHECK(!ParseUInt64("1a", &n));
1498 2 : BOOST_CHECK(!ParseUInt64("aap", &n));
1499 2 : BOOST_CHECK(!ParseUInt64("0x1", &n)); // no hex
1500 2 : const char test_bytes[] = {'1', 0, '1'};
1501 2 : std::string teststr(test_bytes, sizeof(test_bytes));
1502 2 : BOOST_CHECK(!ParseUInt64(teststr, &n)); // no embedded NULs
1503 : // Overflow and underflow
1504 2 : BOOST_CHECK(!ParseUInt64("-9223372036854775809", nullptr));
1505 2 : BOOST_CHECK(!ParseUInt64("18446744073709551616", nullptr));
1506 2 : BOOST_CHECK(!ParseUInt64("-32482348723847471234", nullptr));
1507 2 : BOOST_CHECK(!ParseUInt64("-2147483648", &n));
1508 2 : BOOST_CHECK(!ParseUInt64("-9223372036854775808", &n));
1509 2 : BOOST_CHECK(!ParseUInt64("-1234", &n));
1510 2 : }
1511 :
1512 101 : BOOST_AUTO_TEST_CASE(test_ParseDouble)
1513 : {
1514 2 : double n;
1515 : // Valid values
1516 2 : BOOST_CHECK(ParseDouble("1234", nullptr));
1517 2 : BOOST_CHECK(ParseDouble("0", &n) && n == 0.0);
1518 2 : BOOST_CHECK(ParseDouble("1234", &n) && n == 1234.0);
1519 2 : BOOST_CHECK(ParseDouble("01234", &n) && n == 1234.0); // no octal
1520 2 : BOOST_CHECK(ParseDouble("2147483647", &n) && n == 2147483647.0);
1521 2 : BOOST_CHECK(ParseDouble("-2147483648", &n) && n == -2147483648.0);
1522 2 : BOOST_CHECK(ParseDouble("-1234", &n) && n == -1234.0);
1523 2 : BOOST_CHECK(ParseDouble("1e6", &n) && n == 1e6);
1524 2 : BOOST_CHECK(ParseDouble("-1e6", &n) && n == -1e6);
1525 : // Invalid values
1526 2 : BOOST_CHECK(!ParseDouble("", &n));
1527 2 : BOOST_CHECK(!ParseDouble(" 1", &n)); // no padding inside
1528 2 : BOOST_CHECK(!ParseDouble("1 ", &n));
1529 2 : BOOST_CHECK(!ParseDouble("1a", &n));
1530 2 : BOOST_CHECK(!ParseDouble("aap", &n));
1531 2 : BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex
1532 2 : const char test_bytes[] = {'1', 0, '1'};
1533 2 : std::string teststr(test_bytes, sizeof(test_bytes));
1534 2 : BOOST_CHECK(!ParseDouble(teststr, &n)); // no embedded NULs
1535 : // Overflow and underflow
1536 2 : BOOST_CHECK(!ParseDouble("-1e10000", nullptr));
1537 2 : BOOST_CHECK(!ParseDouble("1e10000", nullptr));
1538 2 : }
1539 :
1540 101 : BOOST_AUTO_TEST_CASE(test_FormatParagraph)
1541 : {
1542 2 : BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), "");
1543 2 : BOOST_CHECK_EQUAL(FormatParagraph("test", 79, 0), "test");
1544 2 : BOOST_CHECK_EQUAL(FormatParagraph(" test", 79, 0), " test");
1545 2 : BOOST_CHECK_EQUAL(FormatParagraph("test test", 79, 0), "test test");
1546 2 : BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 0), "test\ntest");
1547 2 : BOOST_CHECK_EQUAL(FormatParagraph("testerde test", 4, 0), "testerde\ntest");
1548 2 : BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 4), "test\n test");
1549 :
1550 : // Make sure we don't indent a fully-new line following a too-long line ending
1551 2 : BOOST_CHECK_EQUAL(FormatParagraph("test test\nabc", 4, 4), "test\n test\nabc");
1552 :
1553 2 : BOOST_CHECK_EQUAL(FormatParagraph("This_is_a_very_long_test_string_without_any_spaces_so_it_should_just_get_returned_as_is_despite_the_length until it gets here", 79), "This_is_a_very_long_test_string_without_any_spaces_so_it_should_just_get_returned_as_is_despite_the_length\nuntil it gets here");
1554 :
1555 : // Test wrap length is exact
1556 2 : BOOST_CHECK_EQUAL(FormatParagraph("a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p", 79), "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\nf g h i j k l m n o p");
1557 2 : BOOST_CHECK_EQUAL(FormatParagraph("x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p", 79), "x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\nf g h i j k l m n o p");
1558 : // Indent should be included in length of lines
1559 2 : BOOST_CHECK_EQUAL(FormatParagraph("x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 a b c d e fg h i j k", 79, 4), "x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\n f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 a b c d e fg\n h i j k");
1560 :
1561 2 : BOOST_CHECK_EQUAL(FormatParagraph("This is a very long test string. This is a second sentence in the very long test string.", 79), "This is a very long test string. This is a second sentence in the very long\ntest string.");
1562 2 : BOOST_CHECK_EQUAL(FormatParagraph("This is a very long test string.\nThis is a second sentence in the very long test string. This is a third sentence in the very long test string.", 79), "This is a very long test string.\nThis is a second sentence in the very long test string. This is a third\nsentence in the very long test string.");
1563 2 : BOOST_CHECK_EQUAL(FormatParagraph("This is a very long test string.\n\nThis is a second sentence in the very long test string. This is a third sentence in the very long test string.", 79), "This is a very long test string.\n\nThis is a second sentence in the very long test string. This is a third\nsentence in the very long test string.");
1564 2 : BOOST_CHECK_EQUAL(FormatParagraph("Testing that normal newlines do not get indented.\nLike here.", 79), "Testing that normal newlines do not get indented.\nLike here.");
1565 2 : }
1566 :
1567 101 : BOOST_AUTO_TEST_CASE(test_FormatSubVersion)
1568 : {
1569 2 : std::vector<std::string> comments;
1570 2 : comments.push_back(std::string("comment1"));
1571 2 : std::vector<std::string> comments2;
1572 2 : comments2.push_back(std::string("comment1"));
1573 2 : comments2.push_back(SanitizeString(std::string("Comment2; .,_?@-; !\"#$%&'()*+/<=>[]\\^`{|}~"), SAFE_CHARS_UA_COMMENT)); // Semicolon is discouraged but not forbidden by BIP-0014
1574 2 : BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector<std::string>()),std::string("/Test:0.9.99/"));
1575 2 : BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),std::string("/Test:0.9.99(comment1)/"));
1576 2 : BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; Comment2; .,_?@-; )/"));
1577 2 : }
1578 :
1579 101 : BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)
1580 : {
1581 2 : int64_t amount = 0;
1582 2 : BOOST_CHECK(ParseFixedPoint("0", 8, &amount));
1583 2 : BOOST_CHECK_EQUAL(amount, 0LL);
1584 2 : BOOST_CHECK(ParseFixedPoint("1", 8, &amount));
1585 2 : BOOST_CHECK_EQUAL(amount, 100000000LL);
1586 2 : BOOST_CHECK(ParseFixedPoint("0.0", 8, &amount));
1587 2 : BOOST_CHECK_EQUAL(amount, 0LL);
1588 2 : BOOST_CHECK(ParseFixedPoint("-0.1", 8, &amount));
1589 2 : BOOST_CHECK_EQUAL(amount, -10000000LL);
1590 2 : BOOST_CHECK(ParseFixedPoint("1.1", 8, &amount));
1591 2 : BOOST_CHECK_EQUAL(amount, 110000000LL);
1592 2 : BOOST_CHECK(ParseFixedPoint("1.10000000000000000", 8, &amount));
1593 2 : BOOST_CHECK_EQUAL(amount, 110000000LL);
1594 2 : BOOST_CHECK(ParseFixedPoint("1.1e1", 8, &amount));
1595 2 : BOOST_CHECK_EQUAL(amount, 1100000000LL);
1596 2 : BOOST_CHECK(ParseFixedPoint("1.1e-1", 8, &amount));
1597 2 : BOOST_CHECK_EQUAL(amount, 11000000LL);
1598 2 : BOOST_CHECK(ParseFixedPoint("1000", 8, &amount));
1599 2 : BOOST_CHECK_EQUAL(amount, 100000000000LL);
1600 2 : BOOST_CHECK(ParseFixedPoint("-1000", 8, &amount));
1601 2 : BOOST_CHECK_EQUAL(amount, -100000000000LL);
1602 2 : BOOST_CHECK(ParseFixedPoint("0.00000001", 8, &amount));
1603 2 : BOOST_CHECK_EQUAL(amount, 1LL);
1604 2 : BOOST_CHECK(ParseFixedPoint("0.0000000100000000", 8, &amount));
1605 2 : BOOST_CHECK_EQUAL(amount, 1LL);
1606 2 : BOOST_CHECK(ParseFixedPoint("-0.00000001", 8, &amount));
1607 2 : BOOST_CHECK_EQUAL(amount, -1LL);
1608 2 : BOOST_CHECK(ParseFixedPoint("1000000000.00000001", 8, &amount));
1609 2 : BOOST_CHECK_EQUAL(amount, 100000000000000001LL);
1610 2 : BOOST_CHECK(ParseFixedPoint("9999999999.99999999", 8, &amount));
1611 2 : BOOST_CHECK_EQUAL(amount, 999999999999999999LL);
1612 2 : BOOST_CHECK(ParseFixedPoint("-9999999999.99999999", 8, &amount));
1613 2 : BOOST_CHECK_EQUAL(amount, -999999999999999999LL);
1614 :
1615 2 : BOOST_CHECK(!ParseFixedPoint("", 8, &amount));
1616 2 : BOOST_CHECK(!ParseFixedPoint("-", 8, &amount));
1617 2 : BOOST_CHECK(!ParseFixedPoint("a-1000", 8, &amount));
1618 2 : BOOST_CHECK(!ParseFixedPoint("-a1000", 8, &amount));
1619 2 : BOOST_CHECK(!ParseFixedPoint("-1000a", 8, &amount));
1620 2 : BOOST_CHECK(!ParseFixedPoint("-01000", 8, &amount));
1621 2 : BOOST_CHECK(!ParseFixedPoint("00.1", 8, &amount));
1622 2 : BOOST_CHECK(!ParseFixedPoint(".1", 8, &amount));
1623 2 : BOOST_CHECK(!ParseFixedPoint("--0.1", 8, &amount));
1624 2 : BOOST_CHECK(!ParseFixedPoint("0.000000001", 8, &amount));
1625 2 : BOOST_CHECK(!ParseFixedPoint("-0.000000001", 8, &amount));
1626 2 : BOOST_CHECK(!ParseFixedPoint("0.00000001000000001", 8, &amount));
1627 2 : BOOST_CHECK(!ParseFixedPoint("-10000000000.00000000", 8, &amount));
1628 2 : BOOST_CHECK(!ParseFixedPoint("10000000000.00000000", 8, &amount));
1629 2 : BOOST_CHECK(!ParseFixedPoint("-10000000000.00000001", 8, &amount));
1630 2 : BOOST_CHECK(!ParseFixedPoint("10000000000.00000001", 8, &amount));
1631 2 : BOOST_CHECK(!ParseFixedPoint("-10000000000.00000009", 8, &amount));
1632 2 : BOOST_CHECK(!ParseFixedPoint("10000000000.00000009", 8, &amount));
1633 2 : BOOST_CHECK(!ParseFixedPoint("-99999999999.99999999", 8, &amount));
1634 2 : BOOST_CHECK(!ParseFixedPoint("99999909999.09999999", 8, &amount));
1635 2 : BOOST_CHECK(!ParseFixedPoint("92233720368.54775807", 8, &amount));
1636 2 : BOOST_CHECK(!ParseFixedPoint("92233720368.54775808", 8, &amount));
1637 2 : BOOST_CHECK(!ParseFixedPoint("-92233720368.54775808", 8, &amount));
1638 2 : BOOST_CHECK(!ParseFixedPoint("-92233720368.54775809", 8, &amount));
1639 2 : BOOST_CHECK(!ParseFixedPoint("1.1e", 8, &amount));
1640 2 : BOOST_CHECK(!ParseFixedPoint("1.1e-", 8, &amount));
1641 2 : BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount));
1642 2 : }
1643 :
1644 1 : static void TestOtherThread(fs::path dirname, std::string lockname, bool *result)
1645 : {
1646 1 : *result = LockDirectory(dirname, lockname);
1647 1 : }
1648 :
1649 : #ifndef WIN32 // Cannot do this test on WIN32 due to lack of fork()
1650 : static constexpr char LockCommand = 'L';
1651 : static constexpr char UnlockCommand = 'U';
1652 : static constexpr char ExitCommand = 'X';
1653 :
1654 1 : static void TestOtherProcess(fs::path dirname, std::string lockname, int fd)
1655 : {
1656 1 : char ch;
1657 5 : while (true) {
1658 5 : int rv = read(fd, &ch, 1); // Wait for command
1659 5 : assert(rv == 1);
1660 5 : switch(ch) {
1661 : case LockCommand:
1662 3 : ch = LockDirectory(dirname, lockname);
1663 3 : rv = write(fd, &ch, 1);
1664 3 : assert(rv == 1);
1665 : break;
1666 : case UnlockCommand:
1667 1 : ReleaseDirectoryLocks();
1668 1 : ch = true; // Always succeeds
1669 1 : rv = write(fd, &ch, 1);
1670 1 : assert(rv == 1);
1671 : break;
1672 : case ExitCommand:
1673 1 : close(fd);
1674 1 : exit(0);
1675 : default:
1676 0 : assert(0);
1677 : }
1678 : }
1679 0 : }
1680 : #endif
1681 :
1682 99 : BOOST_AUTO_TEST_CASE(test_LockDirectory)
1683 : {
1684 2 : fs::path dirname = GetDataDir() / "lock_dir";
1685 2 : const std::string lockname = ".lock";
1686 : #ifndef WIN32
1687 : // Revert SIGCHLD to default, otherwise boost.test will catch and fail on
1688 : // it: there is BOOST_TEST_IGNORE_SIGCHLD but that only works when defined
1689 : // at build-time of the boost library
1690 2 : void (*old_handler)(int) = signal(SIGCHLD, SIG_DFL);
1691 :
1692 : // Fork another process for testing before creating the lock, so that we
1693 : // won't fork while holding the lock (which might be undefined, and is not
1694 : // relevant as test case as that is avoided with -daemonize).
1695 2 : int fd[2];
1696 2 : BOOST_CHECK_EQUAL(socketpair(AF_UNIX, SOCK_STREAM, 0, fd), 0);
1697 2 : pid_t pid = fork();
1698 2 : if (!pid) {
1699 1 : BOOST_CHECK_EQUAL(close(fd[1]), 0); // Child: close parent end
1700 1 : TestOtherProcess(dirname, lockname, fd[0]);
1701 0 : }
1702 1 : BOOST_CHECK_EQUAL(close(fd[0]), 0); // Parent: close child end
1703 : #endif
1704 : // Lock on non-existent directory should fail
1705 1 : BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), false);
1706 :
1707 1 : fs::create_directories(dirname);
1708 :
1709 : // Probing lock on new directory should succeed
1710 1 : BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
1711 :
1712 : // Persistent lock on new directory should succeed
1713 1 : BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), true);
1714 :
1715 : // Another lock on the directory from the same thread should succeed
1716 1 : BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), true);
1717 :
1718 : // Another lock on the directory from a different thread within the same process should succeed
1719 1 : bool threadresult;
1720 1 : std::thread thr(TestOtherThread, dirname, lockname, &threadresult);
1721 1 : thr.join();
1722 1 : BOOST_CHECK_EQUAL(threadresult, true);
1723 : #ifndef WIN32
1724 : // Try to acquire lock in child process while we're holding it, this should fail.
1725 1 : char ch;
1726 1 : BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1);
1727 1 : BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
1728 1 : BOOST_CHECK_EQUAL((bool)ch, false);
1729 :
1730 : // Give up our lock
1731 1 : ReleaseDirectoryLocks();
1732 : // Probing lock from our side now should succeed, but not hold on to the lock.
1733 1 : BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
1734 :
1735 : // Try to acquire the lock in the child process, this should be successful.
1736 1 : BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1);
1737 1 : BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
1738 1 : BOOST_CHECK_EQUAL((bool)ch, true);
1739 :
1740 : // When we try to probe the lock now, it should fail.
1741 1 : BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), false);
1742 :
1743 : // Unlock the lock in the child process
1744 1 : BOOST_CHECK_EQUAL(write(fd[1], &UnlockCommand, 1), 1);
1745 1 : BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
1746 1 : BOOST_CHECK_EQUAL((bool)ch, true);
1747 :
1748 : // When we try to probe the lock now, it should succeed.
1749 1 : BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
1750 :
1751 : // Re-lock the lock in the child process, then wait for it to exit, check
1752 : // successful return. After that, we check that exiting the process
1753 : // has released the lock as we would expect by probing it.
1754 1 : int processstatus;
1755 1 : BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1);
1756 1 : BOOST_CHECK_EQUAL(write(fd[1], &ExitCommand, 1), 1);
1757 1 : BOOST_CHECK_EQUAL(waitpid(pid, &processstatus, 0), pid);
1758 1 : BOOST_CHECK_EQUAL(processstatus, 0);
1759 1 : BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
1760 :
1761 : // Restore SIGCHLD
1762 1 : signal(SIGCHLD, old_handler);
1763 1 : BOOST_CHECK_EQUAL(close(fd[1]), 0); // Close our side of the socketpair
1764 : #endif
1765 : // Clean up
1766 1 : ReleaseDirectoryLocks();
1767 1 : fs::remove_all(dirname);
1768 1 : }
1769 :
1770 95 : BOOST_AUTO_TEST_CASE(test_DirIsWritable)
1771 : {
1772 : // Should be able to write to the data dir.
1773 1 : fs::path tmpdirname = GetDataDir();
1774 1 : BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true);
1775 :
1776 : // Should not be able to write to a non-existent dir.
1777 1 : tmpdirname = tmpdirname / fs::unique_path();
1778 1 : BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), false);
1779 :
1780 1 : fs::create_directory(tmpdirname);
1781 : // Should be able to write to it now.
1782 1 : BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true);
1783 1 : fs::remove(tmpdirname);
1784 1 : }
1785 :
1786 95 : BOOST_AUTO_TEST_CASE(test_ToLower)
1787 : {
1788 1 : BOOST_CHECK_EQUAL(ToLower('@'), '@');
1789 1 : BOOST_CHECK_EQUAL(ToLower('A'), 'a');
1790 1 : BOOST_CHECK_EQUAL(ToLower('Z'), 'z');
1791 1 : BOOST_CHECK_EQUAL(ToLower('['), '[');
1792 1 : BOOST_CHECK_EQUAL(ToLower(0), 0);
1793 1 : BOOST_CHECK_EQUAL(ToLower('\xff'), '\xff');
1794 :
1795 1 : BOOST_CHECK_EQUAL(ToLower(""), "");
1796 1 : BOOST_CHECK_EQUAL(ToLower("#HODL"), "#hodl");
1797 1 : BOOST_CHECK_EQUAL(ToLower("\x00\xfe\xff"), "\x00\xfe\xff");
1798 1 : }
1799 :
1800 95 : BOOST_AUTO_TEST_CASE(test_ToUpper)
1801 : {
1802 1 : BOOST_CHECK_EQUAL(ToUpper('`'), '`');
1803 1 : BOOST_CHECK_EQUAL(ToUpper('a'), 'A');
1804 1 : BOOST_CHECK_EQUAL(ToUpper('z'), 'Z');
1805 1 : BOOST_CHECK_EQUAL(ToUpper('{'), '{');
1806 1 : BOOST_CHECK_EQUAL(ToUpper(0), 0);
1807 1 : BOOST_CHECK_EQUAL(ToUpper('\xff'), '\xff');
1808 :
1809 1 : BOOST_CHECK_EQUAL(ToUpper(""), "");
1810 1 : BOOST_CHECK_EQUAL(ToUpper("#hodl"), "#HODL");
1811 1 : BOOST_CHECK_EQUAL(ToUpper("\x00\xfe\xff"), "\x00\xfe\xff");
1812 1 : }
1813 :
1814 95 : BOOST_AUTO_TEST_CASE(test_Capitalize)
1815 : {
1816 1 : BOOST_CHECK_EQUAL(Capitalize(""), "");
1817 1 : BOOST_CHECK_EQUAL(Capitalize("bitcoin"), "Bitcoin");
1818 1 : BOOST_CHECK_EQUAL(Capitalize("\x00\xfe\xff"), "\x00\xfe\xff");
1819 1 : }
1820 :
1821 28 : static std::string SpanToStr(Span<const char>& span)
1822 : {
1823 28 : return std::string(span.begin(), span.end());
1824 : }
1825 :
1826 95 : BOOST_AUTO_TEST_CASE(test_spanparsing)
1827 : {
1828 : using namespace spanparsing;
1829 1 : std::string input;
1830 1 : Span<const char> sp;
1831 : bool success;
1832 :
1833 : // Const(...): parse a constant, update span to skip it if successful
1834 1 : input = "MilkToastHoney";
1835 1 : sp = input;
1836 1 : success = Const("", sp); // empty
1837 1 : BOOST_CHECK(success);
1838 1 : BOOST_CHECK_EQUAL(SpanToStr(sp), "MilkToastHoney");
1839 :
1840 1 : success = Const("Milk", sp);
1841 1 : BOOST_CHECK(success);
1842 1 : BOOST_CHECK_EQUAL(SpanToStr(sp), "ToastHoney");
1843 :
1844 1 : success = Const("Bread", sp);
1845 1 : BOOST_CHECK(!success);
1846 :
1847 1 : success = Const("Toast", sp);
1848 1 : BOOST_CHECK(success);
1849 1 : BOOST_CHECK_EQUAL(SpanToStr(sp), "Honey");
1850 :
1851 1 : success = Const("Honeybadger", sp);
1852 1 : BOOST_CHECK(!success);
1853 :
1854 1 : success = Const("Honey", sp);
1855 1 : BOOST_CHECK(success);
1856 1 : BOOST_CHECK_EQUAL(SpanToStr(sp), "");
1857 :
1858 : // Func(...): parse a function call, update span to argument if successful
1859 1 : input = "Foo(Bar(xy,z()))";
1860 1 : sp = input;
1861 :
1862 1 : success = Func("FooBar", sp);
1863 1 : BOOST_CHECK(!success);
1864 :
1865 1 : success = Func("Foo(", sp);
1866 1 : BOOST_CHECK(!success);
1867 :
1868 1 : success = Func("Foo", sp);
1869 1 : BOOST_CHECK(success);
1870 1 : BOOST_CHECK_EQUAL(SpanToStr(sp), "Bar(xy,z())");
1871 :
1872 1 : success = Func("Bar", sp);
1873 1 : BOOST_CHECK(success);
1874 1 : BOOST_CHECK_EQUAL(SpanToStr(sp), "xy,z()");
1875 :
1876 1 : success = Func("xy", sp);
1877 1 : BOOST_CHECK(!success);
1878 :
1879 : // Expr(...): return expression that span begins with, update span to skip it
1880 1 : Span<const char> result;
1881 :
1882 1 : input = "(n*(n-1))/2";
1883 1 : sp = input;
1884 1 : result = Expr(sp);
1885 1 : BOOST_CHECK_EQUAL(SpanToStr(result), "(n*(n-1))/2");
1886 1 : BOOST_CHECK_EQUAL(SpanToStr(sp), "");
1887 :
1888 1 : input = "foo,bar";
1889 1 : sp = input;
1890 1 : result = Expr(sp);
1891 1 : BOOST_CHECK_EQUAL(SpanToStr(result), "foo");
1892 1 : BOOST_CHECK_EQUAL(SpanToStr(sp), ",bar");
1893 :
1894 1 : input = "(aaaaa,bbbbb()),c";
1895 1 : sp = input;
1896 1 : result = Expr(sp);
1897 1 : BOOST_CHECK_EQUAL(SpanToStr(result), "(aaaaa,bbbbb())");
1898 1 : BOOST_CHECK_EQUAL(SpanToStr(sp), ",c");
1899 :
1900 1 : input = "xyz)foo";
1901 1 : sp = input;
1902 1 : result = Expr(sp);
1903 1 : BOOST_CHECK_EQUAL(SpanToStr(result), "xyz");
1904 1 : BOOST_CHECK_EQUAL(SpanToStr(sp), ")foo");
1905 :
1906 1 : input = "((a),(b),(c)),xxx";
1907 1 : sp = input;
1908 1 : result = Expr(sp);
1909 1 : BOOST_CHECK_EQUAL(SpanToStr(result), "((a),(b),(c))");
1910 1 : BOOST_CHECK_EQUAL(SpanToStr(sp), ",xxx");
1911 :
1912 : // Split(...): split a string on every instance of sep, return vector
1913 1 : std::vector<Span<const char>> results;
1914 :
1915 1 : input = "xxx";
1916 1 : results = Split(input, 'x');
1917 1 : BOOST_CHECK_EQUAL(results.size(), 4U);
1918 1 : BOOST_CHECK_EQUAL(SpanToStr(results[0]), "");
1919 1 : BOOST_CHECK_EQUAL(SpanToStr(results[1]), "");
1920 1 : BOOST_CHECK_EQUAL(SpanToStr(results[2]), "");
1921 1 : BOOST_CHECK_EQUAL(SpanToStr(results[3]), "");
1922 :
1923 1 : input = "one#two#three";
1924 1 : results = Split(input, '-');
1925 1 : BOOST_CHECK_EQUAL(results.size(), 1U);
1926 1 : BOOST_CHECK_EQUAL(SpanToStr(results[0]), "one#two#three");
1927 :
1928 1 : input = "one#two#three";
1929 1 : results = Split(input, '#');
1930 1 : BOOST_CHECK_EQUAL(results.size(), 3U);
1931 1 : BOOST_CHECK_EQUAL(SpanToStr(results[0]), "one");
1932 1 : BOOST_CHECK_EQUAL(SpanToStr(results[1]), "two");
1933 1 : BOOST_CHECK_EQUAL(SpanToStr(results[2]), "three");
1934 :
1935 1 : input = "*foo*bar*";
1936 1 : results = Split(input, '*');
1937 1 : BOOST_CHECK_EQUAL(results.size(), 4U);
1938 1 : BOOST_CHECK_EQUAL(SpanToStr(results[0]), "");
1939 1 : BOOST_CHECK_EQUAL(SpanToStr(results[1]), "foo");
1940 1 : BOOST_CHECK_EQUAL(SpanToStr(results[2]), "bar");
1941 1 : BOOST_CHECK_EQUAL(SpanToStr(results[3]), "");
1942 1 : }
1943 :
1944 95 : BOOST_AUTO_TEST_CASE(test_LogEscapeMessage)
1945 : {
1946 : // ASCII and UTF-8 must pass through unaltered.
1947 1 : BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage("Valid log message貓"), "Valid log message貓");
1948 : // Newlines must pass through unaltered.
1949 1 : BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage("Message\n with newlines\n"), "Message\n with newlines\n");
1950 : // Other control characters are escaped in C syntax.
1951 1 : BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage("\x01\x7f Corrupted log message\x0d"), R"(\x01\x7f Corrupted log message\x0d)");
1952 : // Embedded NULL characters are escaped too.
1953 1 : const std::string NUL("O\x00O", 3);
1954 1 : BOOST_CHECK_EQUAL(BCLog::LogEscapeMessage(NUL), R"(O\x00O)");
1955 1 : }
1956 :
1957 : namespace {
1958 :
1959 : struct Tracker
1960 : {
1961 : //! Points to the original object (possibly itself) we moved/copied from
1962 : const Tracker* origin;
1963 : //! How many copies where involved between the original object and this one (moves are not counted)
1964 : int copies;
1965 :
1966 6 : Tracker() noexcept : origin(this), copies(0) {}
1967 20 : Tracker(const Tracker& t) noexcept : origin(t.origin), copies(t.copies + 1) {}
1968 26 : Tracker(Tracker&& t) noexcept : origin(t.origin), copies(t.copies) {}
1969 : Tracker& operator=(const Tracker& t) noexcept
1970 : {
1971 : origin = t.origin;
1972 : copies = t.copies + 1;
1973 : return *this;
1974 : }
1975 : Tracker& operator=(Tracker&& t) noexcept
1976 : {
1977 : origin = t.origin;
1978 : copies = t.copies;
1979 : return *this;
1980 : }
1981 : };
1982 :
1983 : }
1984 :
1985 95 : BOOST_AUTO_TEST_CASE(test_tracked_vector)
1986 : {
1987 1 : Tracker t1;
1988 1 : Tracker t2;
1989 1 : Tracker t3;
1990 :
1991 1 : BOOST_CHECK(t1.origin == &t1);
1992 1 : BOOST_CHECK(t2.origin == &t2);
1993 1 : BOOST_CHECK(t3.origin == &t3);
1994 :
1995 1 : auto v1 = Vector(t1);
1996 1 : BOOST_CHECK_EQUAL(v1.size(), 1U);
1997 1 : BOOST_CHECK(v1[0].origin == &t1);
1998 1 : BOOST_CHECK_EQUAL(v1[0].copies, 1);
1999 :
2000 1 : auto v2 = Vector(std::move(t2));
2001 1 : BOOST_CHECK_EQUAL(v2.size(), 1U);
2002 1 : BOOST_CHECK(v2[0].origin == &t2);
2003 1 : BOOST_CHECK_EQUAL(v2[0].copies, 0);
2004 :
2005 1 : auto v3 = Vector(t1, std::move(t2));
2006 1 : BOOST_CHECK_EQUAL(v3.size(), 2U);
2007 1 : BOOST_CHECK(v3[0].origin == &t1);
2008 1 : BOOST_CHECK(v3[1].origin == &t2);
2009 1 : BOOST_CHECK_EQUAL(v3[0].copies, 1);
2010 1 : BOOST_CHECK_EQUAL(v3[1].copies, 0);
2011 :
2012 1 : auto v4 = Vector(std::move(v3[0]), v3[1], std::move(t3));
2013 1 : BOOST_CHECK_EQUAL(v4.size(), 3U);
2014 1 : BOOST_CHECK(v4[0].origin == &t1);
2015 1 : BOOST_CHECK(v4[1].origin == &t2);
2016 1 : BOOST_CHECK(v4[2].origin == &t3);
2017 1 : BOOST_CHECK_EQUAL(v4[0].copies, 1);
2018 1 : BOOST_CHECK_EQUAL(v4[1].copies, 1);
2019 1 : BOOST_CHECK_EQUAL(v4[2].copies, 0);
2020 :
2021 1 : auto v5 = Cat(v1, v4);
2022 1 : BOOST_CHECK_EQUAL(v5.size(), 4U);
2023 1 : BOOST_CHECK(v5[0].origin == &t1);
2024 1 : BOOST_CHECK(v5[1].origin == &t1);
2025 1 : BOOST_CHECK(v5[2].origin == &t2);
2026 1 : BOOST_CHECK(v5[3].origin == &t3);
2027 1 : BOOST_CHECK_EQUAL(v5[0].copies, 2);
2028 1 : BOOST_CHECK_EQUAL(v5[1].copies, 2);
2029 1 : BOOST_CHECK_EQUAL(v5[2].copies, 2);
2030 1 : BOOST_CHECK_EQUAL(v5[3].copies, 1);
2031 :
2032 1 : auto v6 = Cat(std::move(v1), v3);
2033 1 : BOOST_CHECK_EQUAL(v6.size(), 3U);
2034 1 : BOOST_CHECK(v6[0].origin == &t1);
2035 1 : BOOST_CHECK(v6[1].origin == &t1);
2036 1 : BOOST_CHECK(v6[2].origin == &t2);
2037 1 : BOOST_CHECK_EQUAL(v6[0].copies, 1);
2038 1 : BOOST_CHECK_EQUAL(v6[1].copies, 2);
2039 1 : BOOST_CHECK_EQUAL(v6[2].copies, 1);
2040 :
2041 1 : auto v7 = Cat(v2, std::move(v4));
2042 1 : BOOST_CHECK_EQUAL(v7.size(), 4U);
2043 1 : BOOST_CHECK(v7[0].origin == &t2);
2044 1 : BOOST_CHECK(v7[1].origin == &t1);
2045 1 : BOOST_CHECK(v7[2].origin == &t2);
2046 1 : BOOST_CHECK(v7[3].origin == &t3);
2047 1 : BOOST_CHECK_EQUAL(v7[0].copies, 1);
2048 1 : BOOST_CHECK_EQUAL(v7[1].copies, 1);
2049 1 : BOOST_CHECK_EQUAL(v7[2].copies, 1);
2050 1 : BOOST_CHECK_EQUAL(v7[3].copies, 0);
2051 :
2052 1 : auto v8 = Cat(std::move(v2), std::move(v3));
2053 1 : BOOST_CHECK_EQUAL(v8.size(), 3U);
2054 1 : BOOST_CHECK(v8[0].origin == &t2);
2055 1 : BOOST_CHECK(v8[1].origin == &t1);
2056 1 : BOOST_CHECK(v8[2].origin == &t2);
2057 1 : BOOST_CHECK_EQUAL(v8[0].copies, 0);
2058 1 : BOOST_CHECK_EQUAL(v8[1].copies, 1);
2059 1 : BOOST_CHECK_EQUAL(v8[2].copies, 0);
2060 1 : }
2061 :
2062 95 : BOOST_AUTO_TEST_CASE(message_sign)
2063 : {
2064 1 : const std::array<unsigned char, 32> privkey_bytes = {
2065 : // just some random data
2066 : // derived address from this private key: 15CRxFdyRpGZLW9w8HnHvVduizdL5jKNbs
2067 : 0xD9, 0x7F, 0x51, 0x08, 0xF1, 0x1C, 0xDA, 0x6E,
2068 : 0xEE, 0xBA, 0xAA, 0x42, 0x0F, 0xEF, 0x07, 0x26,
2069 : 0xB1, 0xF8, 0x98, 0x06, 0x0B, 0x98, 0x48, 0x9F,
2070 : 0xA3, 0x09, 0x84, 0x63, 0xC0, 0x03, 0x28, 0x66
2071 : };
2072 :
2073 1 : const std::string message = "Trust no one";
2074 :
2075 1 : const std::string expected_signature =
2076 1 : "IPojfrX2dfPnH26UegfbGQQLrdK844DlHq5157/P6h57WyuS/Qsl+h/WSVGDF4MUi4rWSswW38oimDYfNNUBUOk=";
2077 :
2078 1 : CKey privkey;
2079 1 : std::string generated_signature;
2080 :
2081 1 : BOOST_REQUIRE_MESSAGE(!privkey.IsValid(),
2082 : "Confirm the private key is invalid");
2083 :
2084 1 : BOOST_CHECK_MESSAGE(!MessageSign(privkey, message, generated_signature),
2085 : "Sign with an invalid private key");
2086 :
2087 1 : privkey.Set(privkey_bytes.begin(), privkey_bytes.end(), true);
2088 :
2089 1 : BOOST_REQUIRE_MESSAGE(privkey.IsValid(),
2090 : "Confirm the private key is valid");
2091 :
2092 1 : BOOST_CHECK_MESSAGE(MessageSign(privkey, message, generated_signature),
2093 : "Sign with a valid private key");
2094 :
2095 1 : BOOST_CHECK_EQUAL(expected_signature, generated_signature);
2096 1 : }
2097 :
2098 95 : BOOST_AUTO_TEST_CASE(message_verify)
2099 : {
2100 1 : BOOST_CHECK_EQUAL(
2101 : MessageVerify(
2102 : "invalid address",
2103 : "signature should be irrelevant",
2104 : "message too"),
2105 : MessageVerificationResult::ERR_INVALID_ADDRESS);
2106 :
2107 1 : BOOST_CHECK_EQUAL(
2108 : MessageVerify(
2109 : "3B5fQsEXEaV8v6U3ejYc8XaKXAkyQj2MjV",
2110 : "signature should be irrelevant",
2111 : "message too"),
2112 : MessageVerificationResult::ERR_ADDRESS_NO_KEY);
2113 :
2114 1 : BOOST_CHECK_EQUAL(
2115 : MessageVerify(
2116 : "1KqbBpLy5FARmTPD4VZnDDpYjkUvkr82Pm",
2117 : "invalid signature, not in base64 encoding",
2118 : "message should be irrelevant"),
2119 : MessageVerificationResult::ERR_MALFORMED_SIGNATURE);
2120 :
2121 1 : BOOST_CHECK_EQUAL(
2122 : MessageVerify(
2123 : "1KqbBpLy5FARmTPD4VZnDDpYjkUvkr82Pm",
2124 : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
2125 : "message should be irrelevant"),
2126 : MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED);
2127 :
2128 1 : BOOST_CHECK_EQUAL(
2129 : MessageVerify(
2130 : "15CRxFdyRpGZLW9w8HnHvVduizdL5jKNbs",
2131 : "IPojfrX2dfPnH26UegfbGQQLrdK844DlHq5157/P6h57WyuS/Qsl+h/WSVGDF4MUi4rWSswW38oimDYfNNUBUOk=",
2132 : "I never signed this"),
2133 : MessageVerificationResult::ERR_NOT_SIGNED);
2134 :
2135 1 : BOOST_CHECK_EQUAL(
2136 : MessageVerify(
2137 : "15CRxFdyRpGZLW9w8HnHvVduizdL5jKNbs",
2138 : "IPojfrX2dfPnH26UegfbGQQLrdK844DlHq5157/P6h57WyuS/Qsl+h/WSVGDF4MUi4rWSswW38oimDYfNNUBUOk=",
2139 : "Trust no one"),
2140 : MessageVerificationResult::OK);
2141 :
2142 1 : BOOST_CHECK_EQUAL(
2143 : MessageVerify(
2144 : "11canuhp9X2NocwCq7xNrQYTmUgZAnLK3",
2145 : "IIcaIENoYW5jZWxsb3Igb24gYnJpbmsgb2Ygc2Vjb25kIGJhaWxvdXQgZm9yIGJhbmtzIAaHRtbCeDZINyavx14=",
2146 : "Trust me"),
2147 : MessageVerificationResult::OK);
2148 1 : }
2149 :
2150 95 : BOOST_AUTO_TEST_CASE(message_hash)
2151 : {
2152 1 : const std::string unsigned_tx = "...";
2153 1 : const std::string prefixed_message =
2154 2 : std::string(1, (char)MESSAGE_MAGIC.length()) +
2155 1 : MESSAGE_MAGIC +
2156 2 : std::string(1, (char)unsigned_tx.length()) +
2157 : unsigned_tx;
2158 :
2159 1 : const uint256 signature_hash = Hash(unsigned_tx);
2160 1 : const uint256 message_hash1 = Hash(prefixed_message);
2161 1 : const uint256 message_hash2 = MessageHash(unsigned_tx);
2162 :
2163 1 : BOOST_CHECK_EQUAL(message_hash1, message_hash2);
2164 1 : BOOST_CHECK_NE(message_hash1, signature_hash);
2165 1 : }
2166 :
2167 89 : BOOST_AUTO_TEST_SUITE_END()
|