Skip to content

Commit b78b105

Browse files
author
Alexander Zutikov
committed
Add unit tests, refactor and add new feature to --rate flag
1 parent 0ec2e1c commit b78b105

File tree

6 files changed

+144
-29
lines changed

6 files changed

+144
-29
lines changed

lib/nbg_exrp/cli.ex

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
defmodule NbgExrp.CLI do
2-
32
alias NbgExrp.CurrencyParser
43

54
@default_currency "GEL"
65

76
def main(argv) do
7+
argv
8+
|> fetch_and_process
9+
|> format_output
10+
end
11+
12+
def fetch_and_process(argv) do
813
argv
914
|> parse_args
1015
|> process
@@ -13,20 +18,21 @@ defmodule NbgExrp.CLI do
1318
def parse_args(argv) do
1419
OptionParser.parse(argv,
1520
strict: [help: :boolean, rate: :string, convert: :string],
16-
aliases: [h: :help, r: :rate, c: :convert])
21+
aliases: [h: :help, r: :rate, c: :convert]
22+
)
1723
|> parse_flag()
1824
end
1925

20-
def parse_flag({ [ {flag, value} ], other, _}) do
21-
{ flag, value, other }
26+
def parse_flag({[{flag, value}], other, _}) do
27+
{flag, value, other}
2228
end
2329

2430
def parse_flag({[], _, _}) do
25-
{ :help, true, true }
31+
{:help, true, true}
2632
end
2733

28-
def process({ :help, _, _}) do
29-
IO.puts """
34+
def process({:help, _, _}) do
35+
IO.puts("""
3036
DESCRIPION
3137
3238
-h, --help
@@ -39,20 +45,34 @@ defmodule NbgExrp.CLI do
3945
-c, --convert
4046
Desc: Convert amount in currenty to GEL
4147
Usage: nbg_exrp -c 10 usd, nbg_exrp --conver 10 usd
42-
"""
48+
""")
4349

4450
System.halt(0)
4551
end
4652

47-
def process({:rate, currency, _}) do
48-
rec = currency |> CurrencyParser.parse
53+
def process({:rate, currency, other}) do
54+
records = [currency | other] |> CurrencyParser.parse()
4955

50-
IO.puts "1 #{@default_currency} = #{rec["rate"]} #{rec["code"]} (#{rec["name"]})"
56+
{:rate, records}
5157
end
5258

53-
def process({:convert, amount, [currency|_]}) do
59+
def process({:convert, amount, currency}) do
5460
total = currency |> CurrencyParser.parse_and_calculate(amount)
5561

56-
IO.puts "#{amount} #{currency} = #{total} #{@default_currency}"
62+
{:convert, [%{total: total, amount: amount, currency: currency}]}
63+
end
64+
65+
def format_output({:rate, records}) do
66+
records
67+
|> Enum.each(fn rec ->
68+
IO.puts("1 #{@default_currency} = #{rec["rate"]} #{rec["code"]} (#{rec["name"]})")
69+
end)
70+
end
71+
72+
def format_output({:convert, records}) do
73+
records
74+
|> Enum.each(fn rec ->
75+
IO.puts("#{rec[:amount]} #{rec[:currency]} = #{rec[:total]} #{@default_currency}")
76+
end)
5777
end
5878
end

lib/nbg_exrp/currency_parser.ex

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,49 @@
11
defmodule NbgExrp.CurrencyParser do
22
@nbg_resource "https://nbg.gov.ge/gw/api/ct/monetarypolicy/currencies/ka/json"
33

4-
def parse(currency) do
4+
def parse(currencies) do
55
fetch_currencies()
6-
|> filter_by(currency)
6+
|> filter_by(currencies)
77
end
88

99
def parse_and_calculate(currency, amount) do
1010
currency |> parse |> calculate(amount)
1111
end
1212

13-
def calculate(rec, amount) do
13+
def calculate([rec | _], amount) do
1414
Decimal.mult(Decimal.new(to_string(rec["rate"])), Decimal.new(amount))
1515
end
1616

1717
def fetch_currencies do
1818
case HTTPoison.get(@nbg_resource) do
1919
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
20-
Jason.decode! body
20+
Jason.decode!(body)
21+
2122
{:ok, %HTTPoison.Response{status_code: 404}} ->
22-
IO.puts "Not found :("
23+
IO.puts("Not found :(")
2324
System.halt(0)
25+
2426
{:error, %HTTPoison.Error{reason: reason}} ->
25-
IO.inspect reason
27+
IO.inspect(reason)
2628
System.halt(0)
2729
end
2830
end
2931

30-
def filter_by([currencies|_], currency) do
31-
Map.fetch(currencies, "currencies")
32+
def filter_by([crecords | _], currencies) do
33+
normalized_currencies = Enum.map(currencies, &String.upcase/1)
34+
35+
Map.fetch(crecords, "currencies")
3236
|> elem(1)
33-
|> Enum.filter(fn rec -> rec["code"] == String.upcase(currency) end)
34-
|> first
37+
|> Enum.filter(fn rec -> Enum.member?(normalized_currencies, rec["code"]) end)
38+
|> validate
3539
end
3640

37-
def first([rec|_]) do
38-
rec
41+
def validate([a | b]) do
42+
[a | b]
3943
end
4044

41-
def first([]) do
42-
IO.puts "No info"
45+
def validate([]) do
46+
IO.puts("No info")
4347
System.halt(0)
4448
end
45-
4649
end

mix.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ defmodule NbgExrp.MixProject do
2424
[
2525
{:jason, "~> 1.2"},
2626
{:httpoison, "~> 1.8"},
27-
{:decimal, "~> 2.0"}
27+
{:decimal, "~> 2.0"},
28+
{:mock, "~> 0.3.0", only: :test}
2829
]
2930
end
3031

mix.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
"httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"},
77
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
88
"jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
9+
"meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
910
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
1011
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
1112
"mint": {:hex, :mint, "1.3.0", "396b3301102f7b775e103da5a20494b25753aed818d6d6f0ad222a3a018c3600", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "a9aac960562e43ca69a77e5176576abfa78b8398cec5543dd4fb4ab0131d5c1e"},
13+
"mock": {:hex, :mock, "0.3.7", "75b3bbf1466d7e486ea2052a73c6e062c6256fb429d6797999ab02fa32f29e03", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "4da49a4609e41fd99b7836945c26f373623ea968cfb6282742bcb94440cf7e5c"},
1214
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
1315
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
1416
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},

nbg_exrp

329 Bytes
Binary file not shown.

test/cli_test.exs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
defmodule CLITest do
2+
use ExUnit.Case, async: false
3+
4+
alias NbgExrp.CLI
5+
6+
doctest CLI
7+
8+
import Mock
9+
10+
describe "with passed flag" do
11+
test "--rate usd returns currency" do
12+
with_mock HTTPoison, get: fn _url -> response() end do
13+
{:rate, [rec | _]} = CLI.fetch_and_process(["--rate", "usd"])
14+
15+
assert rec["code"] == "USD"
16+
end
17+
end
18+
19+
test "-r usd returns currency" do
20+
with_mock HTTPoison, get: fn _url -> response() end do
21+
{:rate, [rec | _]} = CLI.fetch_and_process(["-r", "usd"])
22+
23+
assert rec["code"] == "USD"
24+
end
25+
end
26+
27+
test "-r usd eur returns currencies" do
28+
with_mock HTTPoison, get: fn _url -> response() end do
29+
{:rate, crecords} = CLI.fetch_and_process(["-r", "usd", "eur"])
30+
31+
assert length(crecords) == 2
32+
end
33+
end
34+
35+
test "--convert 10 usd returnes converted currency" do
36+
with_mock HTTPoison, get: fn _url -> response() end do
37+
{:convert, [rec | _]} = CLI.fetch_and_process(["--convert", 10, "usd"])
38+
39+
assert Map.has_key?(rec, :total) == true
40+
assert rec[:amount] == 10
41+
end
42+
end
43+
44+
test "-c 10 usd returnes converted currency" do
45+
with_mock HTTPoison, get: fn _url -> response() end do
46+
{:convert, [rec | _]} = CLI.fetch_and_process(["-c", 10, "usd"])
47+
48+
assert Map.has_key?(rec, :total) == true
49+
assert rec[:amount] == 10
50+
end
51+
end
52+
end
53+
54+
defp response do
55+
result = [
56+
%{
57+
"date" => "2021-08-26T00:00:00.000Z",
58+
"currencies" => [
59+
%{
60+
"code" => "EUR",
61+
"date" => "2021-08-26T17:45:03.649Z",
62+
"diff" => 0.0077,
63+
"diffFormated" => "0.0077",
64+
"name" => "ევრო",
65+
"quantity" => 1,
66+
"rate" => 3.6842,
67+
"rateFormated" => "3.6842",
68+
"validFromDate" => "2021-08-27T00:00:00.000Z"
69+
},
70+
%{
71+
"code" => "USD",
72+
"date" => "2021-08-26T17:45:03.649Z",
73+
"diff" => -0.0017,
74+
"diffFormated" => "0.0017",
75+
"name" => "აშშ დოლარი",
76+
"quantity" => 1,
77+
"rate" => 3.1288,
78+
"rateFormated" => "3.1288",
79+
"validFromDate" => "2021-08-27T00:00:00.000Z"
80+
}
81+
]
82+
}
83+
]
84+
85+
{:ok, body} = Jason.encode(result)
86+
87+
{:ok, %HTTPoison.Response{status_code: 200, body: body}}
88+
end
89+
end

0 commit comments

Comments
 (0)