Having problem comparing Money struct string output

Despite copy and pasting the output, the comparison still return false

iex(2)> Money.to_string! Money.new(:AED, 1234)
"AED 1,234.00"
iex(3)> (Money.to_string! Money.new(:AED, 1234)) == "AED 1,234.00"
false

With more inspection, i can see they are different

ex(5)> (Money.to_string! Money.new(:AED, 1234)) |> IO.inspect(base: :hex)          
<<0x41, 0x45, 0x44, 0xC2, 0xA0, 0x31, 0x2C, 0x32, 0x33, 0x34, 0x2E, 0x30, 0x30>>
"AED 1,234.00"
iex(6)> "AED 1,234.00" |> IO.inspect(base: :hex)                          
<<0x41, 0x45, 0x44, 0x20, 0x31, 0x2C, 0x32, 0x33, 0x34, 0x2E, 0x30, 0x30>>
"AED 1,234.00"

Problem is how can i get Money.to_string output to output “regular” space characters so that comparison passes?
I looked into Cldr.Number — Cldr Numbers v2.31.0 but don’t see anything useful.

Most, if not all, currency formats in CLDR use a non-breaking space between the currency and the amount. This is, I think, correct because it would be potentially confusing if a word or line wrap were to occur between the two parts of the string.

If you really want to force a space than you can define your own format like:

# Note this is forcing a breaking space, 0x20
iex> Money.to_string!(Money.new(:AED, 1234), format: "¤ #,###.00")
"AED 1,234.00"
iex> Money.to_string!(Money.new(:AED, 1234), format: "¤ #,###.00") == "AED 1,234.00"
true

However I don’t recommend it for a few reasons:

  1. Not all currencies follow that format. They have variable number of decimal places. Some formats don’t have a space between the currency symbol and the amount.
  2. You’re not going to be local aware (different locales have different formats for the same currency).

In general I don’t think the comparison you’re doing adds a lot of value - although of course I don’t know your use case and I may be missing something. If so, please let me know what you’re trying to achieve and I’ll help.

ex_cldr_number (that does the actually formatting for ex_money) has thousands of tests. If some formatting is incorrect then it’s a bug and I will fix it.

7 Likes

Just mainly using this comparison in tests. For example

assert msg = "Final Price: AED 1,234.00"

Ok, I thought that was probably it. I think the best way to do that is to capture the output in iex and then, if you consider it to be correct, to copy/paste the emitted value into your tests. That’s exactly how I build most of the tests ex_cldr_numbers and ex_money.

I actually did what you suggested before this. It seems like copy and pasting still pasted the output as regular space character. But no worries i can type it out now

That’s interesting! Maybe some editors convert non-breaking to breaking space when pasting? I’ll do some searching on that so I can document it for the next person. Please update the thread if you find the cause?

If the goal of the test isn’t the formatting of the msg string, but rather that the msg string contains the correct currency and amount, I’d consider using String.contains?/2 in the test instead.

assert String.contains?(msg, "AED")
assert String.contains?(msg, "1,234.00")
2 Likes

It must be an iex console limitation! In a regular editor you would’ve seen a visual warning (VSCode here):

Code_aru9ALj2DT

But that would need to be a test output to capture such a nuance.