Skip to content

Commit

Permalink
Fix incorrect parsing of MonetaryAmount built with single string when…
Browse files Browse the repository at this point in the history
… currency starts with a digit
  • Loading branch information
sjanel committed Oct 31, 2022
1 parent f4e3e1a commit be304ff
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 10 deletions.
16 changes: 8 additions & 8 deletions src/objects/src/monetaryamount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ namespace {
/// Theorem 15
constexpr int kNbMaxDoubleDecimals = std::numeric_limits<double>::max_digits10;

inline void RemovePrefixSpaces(std::string_view &str) {
constexpr void RemovePrefixSpaces(std::string_view &str) {
str.remove_prefix(std::find_if(str.begin(), str.end(), [](char c) { return c != ' '; }) - str.begin());
}
inline void RemoveTrailing(std::string_view &str, char r) {
constexpr void RemoveTrailing(std::string_view &str, char r) {
str.remove_suffix(std::find_if(str.rbegin(), str.rend(), [r](char c) { return c != r; }) - str.rbegin());
}

Expand All @@ -35,9 +35,7 @@ inline bool ParseNegativeChar(std::string_view &amountStr) {
isNeg = true;
[[fallthrough]];
case '+': // Let's accept inputs like: "+3" -> "3"
// Remove at least one char + possible spaces after it
amountStr.remove_prefix(std::find_if(amountStr.begin() + 1, amountStr.end(), [](char c) { return c != ' '; }) -
amountStr.begin());
amountStr.remove_prefix(1UL);
break;
case '.': // Let's accept inputs like: ".5" -> "0.5"
break;
Expand Down Expand Up @@ -132,14 +130,16 @@ MonetaryAmount::MonetaryAmount(std::string_view amountCurrencyStr) {

auto last = amountCurrencyStr.begin();
auto endIt = amountCurrencyStr.end();
while (last != endIt && *last <= '9') { // Trick: all '.', '+', '-' are before digits in the ASCII code
static_assert(' ' < '+' && '+' < '-' && '+' < '.'); // Trick: all '.', '+', '-' are before digits in the ASCII code
while (last != endIt && *last >= '+' && *last <= '9') {
++last;
}
std::string_view amountStr(amountCurrencyStr.begin(), last);
RemoveTrailing(amountStr, ' ');
int8_t nbDecimals;
std::tie(_amount, nbDecimals) = AmountIntegralFromStr(amountStr);
_curWithDecimals = CurrencyCode(std::string_view(last, endIt));
std::string_view currencyStr(last, endIt);
RemovePrefixSpaces(currencyStr);
_curWithDecimals = CurrencyCode(currencyStr);
sanitizeDecimals(nbDecimals, maxNbDecimals());
}

Expand Down
31 changes: 29 additions & 2 deletions src/objects/test/monetaryamount_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,17 +552,44 @@ TEST(MonetaryAmountTest, PositiveAmountStr) {
EXPECT_EQ(MonetaryAmount("9204.1260").amountStr(), "9204.126");
EXPECT_EQ(MonetaryAmount("0.709").amountStr(), "0.709");
EXPECT_EQ(MonetaryAmount("0.0").amountStr(), "0");
EXPECT_EQ(MonetaryAmount("3.4950EUR").amountStr(), "3.495");
EXPECT_EQ(MonetaryAmount("94.5").amountStr(), "94.5");
EXPECT_EQ(MonetaryAmount("15003.74").amountStr(), "15003.74");
EXPECT_EQ(MonetaryAmount("15003.740 1INCH").amountStr(), "15003.74");
EXPECT_EQ(MonetaryAmount("0 KRW").amountStr(), "0");
EXPECT_EQ(MonetaryAmount("22337203685477.5808 MAGIC4LIFE").amountStr(), "22337203685477.5808");
EXPECT_EQ(MonetaryAmount("0.000001573004009 MAGIC4LIFE").amountStr(), "0.000001573004009");
EXPECT_EQ(MonetaryAmount("764.00000000000001 MAGIC4LIFE").amountStr(), "764.00000000000001");
}

TEST(MonetaryAmountTest, NegativeAmountStr) {
EXPECT_EQ(MonetaryAmount("-3.4950EUR").amountStr(), "-3.495");
EXPECT_EQ(MonetaryAmount("-0.0034090").amountStr(), "-0.003409");
EXPECT_EQ(MonetaryAmount("-0.0").amountStr(), "0");
EXPECT_EQ(MonetaryAmount("-3.4950EUR").amountStr(), "-3.495");
EXPECT_EQ(MonetaryAmount("-94.5").amountStr(), "-94.5");
EXPECT_EQ(MonetaryAmount("-15003.740").amountStr(), "-15003.74");
EXPECT_EQ(MonetaryAmount("-15003.740 1INCH").amountStr(), "-15003.74");
EXPECT_EQ(MonetaryAmount("-0 KRW").amountStr(), "0");
EXPECT_EQ(MonetaryAmount("-22337203685477.5808 MAGIC4LIFE").amountStr(), "-22337203685477.5808");
EXPECT_EQ(MonetaryAmount("-0.000001573004009 MAGIC4LIFE").amountStr(), "-0.000001573004009");
EXPECT_EQ(MonetaryAmount("-764.00000000000001 MAGIC4LIFE").amountStr(), "-764.00000000000001");
}

TEST(MonetaryAmountTest, PositiveStringRepresentation) {
EXPECT_EQ(MonetaryAmount("3.4950EUR").str(), "3.495 EUR");
EXPECT_EQ(MonetaryAmount("94.5").str(), "94.5");
EXPECT_EQ(MonetaryAmount("15003.740 1INCH").str(), "15003.74 1INCH");
EXPECT_EQ(MonetaryAmount("0 KRW").str(), "0 KRW");
EXPECT_EQ(MonetaryAmount("22337203685477.5808 MAGIC4LIFE").str(), "22337203685477.5808 MAGIC4LIFE");
EXPECT_EQ(MonetaryAmount("0.000001573004009 MAGIC4LIFE").str(), "0.000001573004009 MAGIC4LIFE");
EXPECT_EQ(MonetaryAmount("764.00000000000001 MAGIC4LIFE").str(), "764.00000000000001 MAGIC4LIFE");
}

TEST(MonetaryAmountTest, ExoticInput) {
EXPECT_EQ(MonetaryAmount(" + 4.6 EUr "), MonetaryAmount("4.6EUR"));
EXPECT_EQ(MonetaryAmount(" - .9 f&g "), MonetaryAmount("-0.9F&G"));
EXPECT_EQ(MonetaryAmount(" +4.6 EUr "), MonetaryAmount("4.6EUR"));
EXPECT_EQ(MonetaryAmount(" -.9 f&g "), MonetaryAmount("-0.9F&G"));
EXPECT_THROW(MonetaryAmount(" - .9 f&g "), exception);
EXPECT_THROW(MonetaryAmount("--.9"), exception);
}

Expand Down

0 comments on commit be304ff

Please sign in to comment.