Skip to content

Commit eff21ff

Browse files
committed
New Simple Bank exercise
1 parent d75c681 commit eff21ff

File tree

10 files changed

+212
-0
lines changed

10 files changed

+212
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ Each exercise is created as a standalone Mix project requiring a varying degree
2626

2727
> Provided with a string of characters ("aabbc"), print all possible palindrome premutations ("abcba", "bacab") to IO.
2828
29+
- [Simple Bank](/tree/master/simple_bank) _added 2018-04-30_
30+
31+
> Implement a GenServer based bank with support for account registration, deposits, withdrawls, and account balance inquiries.
32+
2933
## Contributions
3034

3135
We'd love to hear your feedback on how these exercises are working for you.

simple_bank/.formatter.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"]
4+
]

simple_bank/.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# The directory Mix will write compiled artifacts to.
2+
/_build/
3+
4+
# If you run "mix test --cover", coverage assets end up here.
5+
/cover/
6+
7+
# The directory Mix downloads your dependencies sources to.
8+
/deps/
9+
10+
# Where 3rd-party dependencies like ExDoc output generated docs.
11+
/doc/
12+
13+
# Ignore .fetch files in case you like to edit your project deps locally.
14+
/.fetch
15+
16+
# If the VM crashes, it generates a dump, let's ignore it too.
17+
erl_crash.dump
18+
19+
# Also ignore archive artifacts (built via "mix archive.build").
20+
*.ez
21+
22+
# Ignore package tarball (built via "mix hex.build").
23+
simple_bank-*.tar
24+

simple_bank/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# SimpleBank
2+
3+
**TODO: Add description**
4+
5+
## Installation
6+
7+
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
8+
by adding `simple_bank` to your list of dependencies in `mix.exs`:
9+
10+
```elixir
11+
def deps do
12+
[
13+
{:simple_bank, "~> 0.1.0"}
14+
]
15+
end
16+
```
17+
18+
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
19+
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
20+
be found at [https://hexdocs.pm/simple_bank](https://hexdocs.pm/simple_bank).
21+

simple_bank/config/config.exs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# This file is responsible for configuring your application
2+
# and its dependencies with the aid of the Mix.Config module.
3+
use Mix.Config
4+
5+
# This configuration is loaded before any dependency and is restricted
6+
# to this project. If another project depends on this project, this
7+
# file won't be loaded nor affect the parent project. For this reason,
8+
# if you want to provide default values for your application for
9+
# 3rd-party users, it should be done in your "mix.exs" file.
10+
11+
# You can configure your application as:
12+
#
13+
# config :simple_bank, key: :value
14+
#
15+
# and access this configuration in your application as:
16+
#
17+
# Application.get_env(:simple_bank, :key)
18+
#
19+
# You can also configure a 3rd-party app:
20+
#
21+
# config :logger, level: :info
22+
#
23+
24+
# It is also possible to import configuration files, relative to this
25+
# directory. For example, you can emulate configuration per environment
26+
# by uncommenting the line below and defining dev.exs, test.exs and such.
27+
# Configuration from the imported file will override the ones defined
28+
# here (which is why it is important to import them last).
29+
#
30+
# import_config "#{Mix.env}.exs"

simple_bank/lib/simple_bank.ex

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
defmodule SimpleBank do
2+
@moduledoc """
3+
SimpleBank is a GenServer charading as a bank.
4+
"""
5+
use GenServer
6+
7+
def start_link(initial_state \\ %{}) do
8+
GenServer.start_link(__MODULE__, initial_state)
9+
end
10+
11+
def init(initial_state) do
12+
{:ok, initial_state}
13+
end
14+
15+
@spec register(pid(), String.t()) :: {:ok, String.t()} | {:error, reason}
16+
def register(bank_pid, name) do
17+
end
18+
19+
@spec deposit(pid(), String.t(), pos_integer} :: {:ok, pos_integer} | {:error, reason}
20+
def deposit(bank_pid, account_id, amount) do
21+
end
22+
23+
@spec deposit(pid(), String.t()} :: {:ok, pos_integer} | {:error, reason}
24+
def balance(bank_pid, account_id) do
25+
end
26+
27+
@spec withdrawl(pid(), String.t(), pos_integer} :: {:ok, {pos_integer, pos_integer}} | {:error, reason}
28+
def withdrawl(bank_pid, account_id, amount) do
29+
end
30+
31+
def init(initial_state), do: initial_state
32+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
defmodule SimpleBank.Account do
2+
@type t :: %__MODULE__{balance: integer(), id: String.t(), name: String.t()}
3+
4+
defstruct [:balance, :id, :name]
5+
end

simple_bank/mix.exs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
defmodule SimpleBank.MixProject do
2+
use Mix.Project
3+
4+
def project do
5+
[
6+
app: :simple_bank,
7+
version: "0.1.0",
8+
elixir: "~> 1.6",
9+
start_permanent: Mix.env() == :prod,
10+
deps: deps()
11+
]
12+
end
13+
14+
# Run "mix help compile.app" to learn about applications.
15+
def application do
16+
[
17+
extra_applications: [:logger]
18+
]
19+
end
20+
21+
# Run "mix help deps" to learn about dependencies.
22+
defp deps do
23+
[
24+
# {:dep_from_hexpm, "~> 0.3.0"},
25+
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
26+
]
27+
end
28+
end

simple_bank/test/simple_bank_test.exs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
defmodule SimpleBankTest do
2+
use ExUnit.Case, async: false
3+
4+
alias SimpleBank.Account
5+
6+
setup do
7+
{:ok, bank_pid} = SimpleBank.start_link([%Account{balance: 100, id: "test_id", name: "Test"}])
8+
{:ok, bank: bank_pid}
9+
end
10+
11+
describe "register/2" do
12+
test "creates a new account and generates an account id", %{bank: bank_pid} do
13+
{:ok, account_id} = SimpleBank.register(bank_pid, "Another Test Account")
14+
assert is_binary(account_id)
15+
end
16+
17+
test "raises an error for existing account names", %{bank: bank_pid} do
18+
{:error, :existing_account} = SimpleBank.register(bank_pid, "Test")
19+
end
20+
end
21+
22+
describe "deposit/3" do
23+
test "increases the account balance by the deposited amount", %{bank: bank_pid} do
24+
assert {:ok, 110} == SimpleBank.deposit(bank_pid, "test_id", 10)
25+
end
26+
27+
test "does not allow deposits of negative ammounts", %{bank: bank_pid} do
28+
assert {:error, :pos_integer_only} == SimpleBank.deposit(bank_pid, "test_id", -1)
29+
end
30+
31+
test "raises an error if the account does not exist", %{bank: bank_pid} do
32+
assert {:error, :missing_account} == SimpleBank.deposit(bank_pid, "doesnotexist", 10)
33+
end
34+
end
35+
36+
describe "balance/2" do
37+
test "returns the current account balance", %{bank: bank_pid} do
38+
assert {:ok, 110} == SimpleBank.deposit(bank_pid, "test_id", 10)
39+
end
40+
41+
test "raises an error if the account does not exist", %{bank: bank_pid} do
42+
assert {:error, :missing_account} == SimpleBank.balance(bank_pid, "doesnotexist")
43+
end
44+
end
45+
46+
describe "withdrawl/3" do
47+
test "decreases the account balance by the withdrawn amount", %{bank: bank_pid} do
48+
assert {:ok, 100} == SimpleBank.withdrawl(bank_pid, "test_id", 10)
49+
end
50+
51+
test "does not negative ammount balances", %{bank: bank_pid} do
52+
assert {:error, :insufficient_funds} == SimpleBank.withdrawl(bank_pid, "test_id", -1)
53+
end
54+
55+
test "does not allow withdrawls of negative ammounts", %{bank: bank_pid} do
56+
assert {:error, :pos_integer_only} == SimpleBank.withdrawl(bank_pid, "test_id", 1000)
57+
end
58+
59+
test "raises an error if the account does not exist", %{bank: bank_pid} do
60+
assert {:error, :missing_account} == SimpleBank.deposit(bank_pid, "doesnotexist", 10)
61+
end
62+
end
63+
end

simple_bank/test/test_helper.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ExUnit.start()

0 commit comments

Comments
 (0)