Skip to content

Instantly share code, notes, and snippets.

@joaoh82
Created June 5, 2019 17:51
Show Gist options
  • Save joaoh82/1da781964a5b97aaa9f0d3c23742af5d to your computer and use it in GitHub Desktop.
Save joaoh82/1da781964a5b97aaa9f0d3c23742af5d to your computer and use it in GitHub Desktop.
package main
import (
"errors"
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
// BankAccount represents a bank account
type BankAccount interface {
// Balance returns the current balance of the account
Balance() (float64, error)
// Deposit deposits money onto the account
Deposit(value float64) error
// Withdraw widthdraws money from the account
Withdraw(value float64) error
}
// SavingsAccount represents a savings bank account
type SavingsAccount interface {
// Embedded public interface
BankAccount
// SetWithdrawalLimit sets a new withdrawal limit
SetWithdrawalLimit(newLimit float64) error
}
/*************************************************\
BASIC BANK ACCOUNT
\*************************************************/
// NewBankAccount creates a new bank account instance
func NewBankAccount(id string) (BankAccount, error) {
return newBankAccount(id)
}
func newBankAccount(id string) (*bankAccount, error) {
if len(id) < 1 {
return nil, errors.New("invalid bank account id")
}
return &bankAccount{
id: id,
blocked: false,
balance: 0,
}, nil
}
type bankAccount struct {
// Private fields
id string
blocked bool
balance float64
}
func (ba *bankAccount) checkBlocked() error {
if ba.blocked {
return fmt.Errorf("account %s is blocked", ba.id)
}
return nil
}
func (ba *bankAccount) Balance() (float64, error) {
if err := ba.checkBlocked(); err != nil {
return 0, err
}
return ba.balance, nil
}
func (ba *bankAccount) Deposit(value float64) error {
if err := ba.checkBlocked(); err != nil {
return err
}
if value > 0 {
ba.balance += value
return nil
}
return fmt.Errorf("invalid deposit value: %f", value)
}
func (ba *bankAccount) Withdraw(value float64) error {
if err := ba.checkBlocked(); err != nil {
return err
}
if ba.balance-value < 0 {
return errors.New("insufficient funds")
}
ba.balance -= value
return nil
}
// TestBankAccount tests BankAccount
func TestBankAccount(t *testing.T) {
account, err := NewBankAccount("ABC")
require.NoError(t, err)
require.NotNil(t, account)
b1, err := account.Balance()
require.NoError(t, err)
require.Equal(t, 0.0, b1)
require.NoError(t, account.Deposit(4.5))
b2, err := account.Balance()
require.NoError(t, err)
require.Equal(t, 4.5, b2)
require.NoError(t, account.Withdraw(2.5))
b3, err := account.Balance()
require.NoError(t, err)
require.Equal(t, 2.0, b3)
}
/*************************************************\
SAVINGS BANK ACCOUNT
- composes a basic account
- overwrites method Withdraw
\*************************************************/
// NewSavingsAccount creates a new savings bank account instance
func NewSavingsAccount(id string) (SavingsAccount, error) {
return newSavingsAccount(id)
}
func newSavingsAccount(id string) (*savingsAccount, error) {
newBankAccount, err := newBankAccount(id)
if err != nil {
return nil, err
}
return &savingsAccount{
bankAccount: newBankAccount,
withdrawalLimit: 0.0,
}, nil
}
type savingsAccount struct {
// Embedded private struct
*bankAccount
// Private fields
withdrawalLimit float64
}
func (ba *savingsAccount) Withdraw(value float64) error {
if value > ba.withdrawalLimit {
return fmt.Errorf("withdrawal limit (%f) exceeded", ba.withdrawalLimit)
}
return ba.bankAccount.Withdraw(value)
}
func (ba *savingsAccount) SetWithdrawalLimit(newLimit float64) error {
if newLimit < 0 {
return fmt.Errorf("invalid withdrawal limit: %f", newLimit)
}
ba.withdrawalLimit = newLimit
return nil
}
// TestSavingsAccount tests SavingsAccount
func TestSavingsAccount(t *testing.T) {
account, err := NewSavingsAccount("mysavings")
require.NoError(t, err)
require.NotNil(t, account)
b1, err := account.Balance()
require.NoError(t, err)
require.Equal(t, 0.0, b1)
require.NoError(t, account.Deposit(12.0))
b2, err := account.Balance()
require.NoError(t, err)
require.Equal(t, 12.0, b2)
account.SetWithdrawalLimit(4.0)
require.Error(t, account.Withdraw(5.0))
require.NoError(t, account.Withdraw(4.0))
b3, err := account.Balance()
require.NoError(t, err)
require.Equal(t, 8.0, b3)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment