From 9a62bed58090d3a293427309c9a92bfabaa8901e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pinochet?= Date: Thu, 21 Jul 2022 19:03:47 -0400 Subject: [PATCH] add NewFromFloat and NewFromString (#108) --- money.go | 30 ++++++++++++++++++++++++++++++ money_test.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/money.go b/money.go index cb3d76f..0a026e6 100644 --- a/money.go +++ b/money.go @@ -5,6 +5,9 @@ import ( "encoding/json" "errors" "fmt" + "math" + "strconv" + "strings" ) // Injection points for backward compatibility. @@ -85,6 +88,33 @@ func New(amount int64, code string) *Money { } } +// NewFromFloat creates and returns new instance of Money from a float64. +func NewFromFloat(amount float64, currency string) *Money { + currencyDecimals := math.Pow(10, float64(GetCurrency(currency).Fraction)) + return New(int64(amount*currencyDecimals), currency) +} + +// NewFromFloat creates and returns new instance of Money from a float64. +func NewFromString(amount string, currency string) (*Money, error) { + amount = strings.Trim(amount, "0") + + var exponent int + if pointIndex := strings.Index(amount, "."); pointIndex != -1 { + exponent = len(amount[pointIndex+1:]) + } + + intString := strings.ReplaceAll(amount, ".", "") + parsed, err := strconv.ParseInt(intString, 10, 64) + if err != nil { + return nil, fmt.Errorf("can't parse '%s' to money", amount) + } + + currencyFraction := GetCurrency(currency).Fraction + parsed /= int64(math.Pow(10, float64(exponent-currencyFraction))) + + return New(parsed, currency), nil +} + // Currency returns the currency used by Money. func (m *Money) Currency() *Currency { return m.currency diff --git a/money_test.go b/money_test.go index 4be283b..40543f2 100644 --- a/money_test.go +++ b/money_test.go @@ -629,6 +629,56 @@ func TestMoney_Amount(t *testing.T) { } } +func TestNewFromFloat(t *testing.T) { + m := NewFromFloat(12.34, EUR) + + if m.amount.val != 1234 { + t.Errorf("Expected %d got %d", 1234, m.amount.val) + } + + if m.currency.Code != EUR { + t.Errorf("Expected currency %s got %s", EUR, m.currency.Code) + } + + m = NewFromFloat(-0.123, EUR) + + if m.amount.val != -12 { + t.Errorf("Expected %d got %d", -12, m.amount.val) + } +} + +func TestNewFromString(t *testing.T) { + m, err := NewFromString("12.34", EUR) + + if err != nil { + t.Error(err) + } + + if m.amount.val != 1234 { + t.Errorf("Expected %d got %d", 1234, m.amount.val) + } + + if m.currency.Code != EUR { + t.Errorf("Expected currency %s got %s", EUR, m.currency.Code) + } + + m, err = NewFromString("-1.12345", EUR) + + if err != nil { + t.Error(err) + } + + if m.amount.val != -112 { + t.Errorf("Expected %d got %d", -112, m.amount.val) + } + + _, err = NewFromString("invalid_input", EUR) + + if err.Error() != "can't parse 'invalid_input' to money" { + t.Error(err) + } +} + func TestDefaultMarshal(t *testing.T) { given := New(12345, IQD) expected := `{"amount":12345,"currency":"IQD"}`