diff --git a/exchange_rates.go b/exchange_rates.go index c84a5b7..e3d34cc 100644 --- a/exchange_rates.go +++ b/exchange_rates.go @@ -2,6 +2,7 @@ package finance import ( "encoding/xml" + "errors" "io/ioutil" "net/http" "strings" @@ -56,3 +57,27 @@ func ExchangeRates() (map[string]float64, error) { return ratesMap, nil } + +// ConvertRate converts a value from once exchange rate to another +func ConvertRate(value float64, from string, to string) (float64, error) { + + rates, err := ExchangeRates() + if err != nil { + return 0, err + } + + fromRate, ok := rates[from] + if !ok { + return 0, errors.New("Invalid from currency: " + from) + } + + toRate, ok := rates[to] + if !ok { + return 0, errors.New("Invalid to currency: " + to) + } + + result := value / fromRate * toRate + + return result, nil + +} diff --git a/exchange_rates_test.go b/exchange_rates_test.go index ffd8475..ece6860 100644 --- a/exchange_rates_test.go +++ b/exchange_rates_test.go @@ -95,6 +95,58 @@ func Test_ExchangeRates_InvalidXML(t *testing.T) { } +func Test_ConvertRate(t *testing.T) { + + type test struct { + name string + value float64 + from string + to string + expectsError bool + } + + var tests = []test{ + {"invalid", 1, "", "", true}, + {"invalid-from", 1, "EUR", "", true}, + {"invalid-to", 1, "", "EUR", true}, + {"valid-eur-eur", 2, "EUR", "EUR", false}, + {"valid-eur-usd", 2, "EUR", "USD", false}, + {"valid-aud-usd", 2, "AUD", "USD", false}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + + actual, err := finance.ConvertRate(tc.value, tc.from, tc.to) + + if tc.expectsError { + assert.Zero(t, actual, "actual") + assert.Error(t, err, "error") + } else { + assert.NotZero(t, actual, "actual") + assert.NoError(t, err, "error") + if tc.from != tc.to { + assert.NotEqual(t, tc.value, actual, "should-not-be-equal") + } + } + + }) + } + +} + +func Test_ConvertRate_InvalidURL(t *testing.T) { + + finance.RatesURL = "ht&@-tp://:aa" + defer resetRatesURL() + + actual, err := finance.ConvertRate(1, "EUR", "USD") + + assert.Zero(t, actual, "actual") + assert.Error(t, err, "error") + +} + func resetRatesURL() { finance.RatesURL = finance.DefaultRatesURL }