added decimal point support to currency::parse_amount() + minor refactoring

This commit is contained in:
sowle 2024-07-02 20:49:51 +02:00
parent 9150c31666
commit b6e84b460e
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
6 changed files with 121 additions and 60 deletions

View file

@ -793,8 +793,7 @@ namespace currency
}
}
//---------------------------------------------------------------
// TODO: reverse order of arguments
bool parse_amount(uint64_t& amount, const std::string& str_amount_)
bool parse_amount(const std::string& str_amount_, uint64_t& amount, const size_t decimal_point /* = CURRENCY_DISPLAY_DECIMAL_POINT */)
{
std::string str_amount = str_amount_;
boost::algorithm::trim(str_amount);
@ -804,12 +803,12 @@ namespace currency
if (std::string::npos != point_index)
{
fraction_size = str_amount.size() - point_index - 1;
while (CURRENCY_DISPLAY_DECIMAL_POINT < fraction_size && '0' == str_amount.back())
while (decimal_point < fraction_size && '0' == str_amount.back())
{
str_amount.erase(str_amount.size() - 1, 1);
--fraction_size;
}
if (CURRENCY_DISPLAY_DECIMAL_POINT < fraction_size)
if (decimal_point < fraction_size)
return false;
str_amount.erase(point_index, 1);
}
@ -821,9 +820,9 @@ namespace currency
if (str_amount.empty())
return false;
if (fraction_size < CURRENCY_DISPLAY_DECIMAL_POINT)
if (fraction_size < decimal_point)
{
str_amount.append(CURRENCY_DISPLAY_DECIMAL_POINT - fraction_size, '0');
str_amount.append(decimal_point - fraction_size, '0');
}
return string_tools::get_xtype_from_string(amount, str_amount);

View file

@ -402,7 +402,7 @@ namespace currency
uint64_t get_outs_money_amount(const transaction& tx, const currency::account_keys& acc_keys_for_hidden_amounts = currency::null_acc_keys);
bool check_inputs_types_supported(const transaction& tx);
bool check_outs_valid(const transaction& tx);
bool parse_amount(uint64_t& amount, const std::string& str_amount);
bool parse_amount(const std::string& str_amount, uint64_t& amount, const size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT);
bool parse_tracking_seed(const std::string& tracking_seed, account_public_address& address, crypto::secret_key& view_sec_key, uint64_t& creation_timestamp);

View file

@ -2592,7 +2592,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args)
}
uint64_t amount = 0;
r = currency::parse_amount(amount, args[2]);
r = currency::parse_amount(args[2], amount);
if (!r || amount == 0)
{
fail_msg_writer() << "incorrect amount: " << args[2];
@ -3127,7 +3127,7 @@ int main(int argc, char* argv[])
uint64_t max_amount = 0;
CHECK_AND_ASSERT_MES(epee::string_tools::string_to_num_fast(params[0], outs_min) && outs_min > 0 && outs_min < 256, EXIT_FAILURE, "incorrect param: " << params[0]);
CHECK_AND_ASSERT_MES(epee::string_tools::string_to_num_fast(params[1], outs_max) && outs_max > 0 && outs_max < 256, EXIT_FAILURE, "incorrect param: " << params[1]);
CHECK_AND_ASSERT_MES(currency::parse_amount(max_amount, params[2]), EXIT_FAILURE, "incorrect param: " << params[2]);
CHECK_AND_ASSERT_MES(currency::parse_amount(params[2], max_amount), EXIT_FAILURE, "incorrect param: " << params[2]);
wal.set_defragmentation_tx_settings(true, outs_min, outs_max, max_amount);
}
}

View file

@ -1539,7 +1539,7 @@ std::string wallets_manager::transfer(uint64_t wallet_id, const view::transfer_p
}
if(!currency::parse_amount(dsts.back().amount, d.amount))
if(!currency::parse_amount(d.amount, dsts.back().amount))
{
return API_RETURN_CODE_BAD_ARG_WRONG_AMOUNT;
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2022 Zano Project
// Copyright (c) 2022-2024 Zano Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -10,23 +10,23 @@ using namespace currency;
namespace
{
void do_pos_test(uint64_t expected, const std::string& str)
void do_pos_test(uint64_t expected, const std::string& str, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT)
{
uint64_t val;
std::string number_str = str;
std::replace(number_str.begin(), number_str.end(), '_', '.');
number_str.erase(std::remove(number_str.begin(), number_str.end(), '~'), number_str.end());
ASSERT_TRUE(parse_amount(val, number_str));
ASSERT_TRUE(parse_amount(number_str, val, decimal_point));
ASSERT_EQ(expected, val);
}
void do_neg_test(const std::string& str)
void do_neg_test(const std::string& str, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT)
{
uint64_t val;
std::string number_str = str;
std::replace(number_str.begin(), number_str.end(), '_', '.');
number_str.erase(std::remove(number_str.begin(), number_str.end(), '~'), number_str.end());
ASSERT_FALSE(parse_amount(val, number_str));
ASSERT_FALSE(parse_amount(number_str, val, decimal_point));
}
}
@ -48,6 +48,23 @@ namespace
do_neg_test(#str); \
}
#define TEST_pos_dp(expected, str, decimal_point) \
TEST(parse_amount, handles_pos_ ## str ## _dp ## decimal_point) \
{ \
do_pos_test(UINT64_C(expected), #str, decimal_point); \
}
#define TEST_neg_dp(str, decimal_point) \
TEST(parse_amount, handles_neg_ ## str ## _dp ## decimal_point) \
{ \
do_neg_test(#str, decimal_point); \
}
#define TEST_neg_n_dp(str, name, decimal_point) \
TEST(parse_amount, handles_neg_ ## name ## _dp ## decimal_point) \
{ \
do_neg_test(#str, decimal_point); \
}
TEST_pos(0, 0);
TEST_pos(0, 00);
@ -96,6 +113,44 @@ TEST_pos(18446744073700000000, 18446744_0737000000000);
TEST_pos(18446744073700000000, 18446744_07370000000000000000000);
TEST_pos(18446744073709551615, 18446744_073709551615);
// non-standard decimal point
TEST_pos_dp(0, 0_0, 3);
TEST_pos_dp(0, 00_0, 3);
TEST_pos_dp(0, 00_00, 3);
TEST_pos_dp(0, 00000000_00, 3);
TEST_pos_dp(0, 00_000000000, 3);
TEST_pos_dp(0, 00_00000000000000000000000000000000, 3);
TEST_pos_dp( 65535, 65535, 0);
TEST_pos_dp( 6553500, 65535, 2);
TEST_pos_dp( 65535000000, 65535, 6);
TEST_pos_dp( 18000000000000000000, 18, 18);
TEST_pos_dp( 1, 0_1, 1);
TEST_pos_dp( 10, 0_1, 2);
TEST_pos_dp( 100, 0_1, 3);
TEST_pos_dp( 10000000000000000000, 0_1, 20);
TEST_pos_dp( 1, 0_001, 3);
TEST_pos_dp( 123, 0_123, 3);
TEST_pos_dp( 1230, 0_123, 4);
TEST_pos_dp( 12300, 0_123, 5);
TEST_pos_dp( 123000, 0_123, 6);
TEST_pos_dp(18446744073709551615, 18446744073709551615, 0);
TEST_pos_dp(18446744073709551615, 18446744073709551615_0, 0);
TEST_pos_dp(18446744073709551615, 1844674407370955161_5, 1);
TEST_pos_dp(18446744073709551615, 1844674407370955161_50, 1);
TEST_pos_dp(18446744073709551615, 18446744073709551_615, 3);
TEST_pos_dp(18446744073709551615, 18446744073709551_615000, 3);
TEST_pos_dp(18446744073709551615, 1_8446744073709551615, 19);
TEST_pos_dp(18446744073709551615, 1_844674407370955161500, 19);
TEST_pos_dp(18446744073709551615, 0_18446744073709551615, 20);
TEST_pos_dp(18446744073709551615, 0_1844674407370955161500, 20);
// Invalid numbers
TEST_neg_n(~, empty_string);
TEST_neg_n(-0, minus_0);
@ -109,10 +164,17 @@ TEST_neg(0_0000000000001);
TEST_neg(0_0000000000009);
TEST_neg(18446744_0737000000001);
TEST_neg_dp(00_184467440737095516150001, 20);
TEST_neg_dp(00_184467440737095516151, 20);
TEST_neg_dp(1_2, 0);
// Overflow
TEST_neg(184467440737_09551616);
TEST_neg(184467440738);
TEST_neg(18446744073709551616);
TEST_neg_dp(18446744073709551616, 0);
TEST_neg_dp(1844674407370955161_60, 1);
TEST_neg_dp(0_18446744073709551616, 20);
// Two or more points
TEST_neg(__);
@ -123,6 +185,51 @@ TEST_neg(0_0_);
TEST_neg(_0_0);
TEST_neg(0_0_0);
// moved from test_format_utils.cpp
TEST(validate_parse_amount_case, validate_parse_amount)
{
uint64_t res = 0;
bool r = currency::parse_amount("0.0001", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000000);
r = currency::parse_amount("100.0001", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000100000000);
r = currency::parse_amount("000.0000", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 0);
r = currency::parse_amount("0", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 0);
r = currency::parse_amount(" 100.0001 ", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000100000000);
r = currency::parse_amount(" 100.0000 ", res);
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000000000000);
r = currency::parse_amount(" 100. 0000 ", res);
ASSERT_FALSE(r);
r = currency::parse_amount("100. 0000", res);
ASSERT_FALSE(r);
r = currency::parse_amount("100 . 0000", res);
ASSERT_FALSE(r);
r = currency::parse_amount("100.00 00", res);
ASSERT_FALSE(r);
r = currency::parse_amount("1 00.00 00", res);
ASSERT_FALSE(r);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

View file

@ -125,48 +125,3 @@ void force_random(forced_to_pod_t& o)
// }
//
// }
TEST(validate_parse_amount_case, validate_parse_amount)
{
uint64_t res = 0;
bool r = currency::parse_amount(res, "0.0001");
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000000);
r = currency::parse_amount(res, "100.0001");
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000100000000);
r = currency::parse_amount(res, "000.0000");
ASSERT_TRUE(r);
ASSERT_EQ(res, 0);
r = currency::parse_amount(res, "0");
ASSERT_TRUE(r);
ASSERT_EQ(res, 0);
r = currency::parse_amount(res, " 100.0001 ");
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000100000000);
r = currency::parse_amount(res, " 100.0000 ");
ASSERT_TRUE(r);
ASSERT_EQ(res, 100000000000000);
r = currency::parse_amount(res, " 100. 0000 ");
ASSERT_FALSE(r);
r = currency::parse_amount(res, "100. 0000");
ASSERT_FALSE(r);
r = currency::parse_amount(res, "100 . 0000");
ASSERT_FALSE(r);
r = currency::parse_amount(res, "100.00 00");
ASSERT_FALSE(r);
r = currency::parse_amount(res, "1 00.00 00");
ASSERT_FALSE(r);
}