diff --git a/lib/account.rb b/lib/account.rb index e69de29b..18718c59 100644 --- a/lib/account.rb +++ b/lib/account.rb @@ -0,0 +1,94 @@ +require 'csv' + +module Bank + + class Account + + attr_reader :id, :balance, :open_date + + def initialize(id, balance, open_date = nil) + @id = id + raise ArgumentError.new "The initial balance must not be a negative number" if balance < 0 + + @balance = balance + + + + # raise ArgumentError.new("The initial balance must not be a negative number") if balance < 0 + # + # @id = id + # @balance = balance + + # owner1 = Bank::Owner.new(owner) + + # @owner = owner + # @account = Accounts.all + # @owner = Bank::Owner.new(owner_info_hash) + # @owner_name = owner1.name + + + end + + def self.all + accounts = [] + CSV.open("../support/accounts.csv").each do |line| + id = line[0] + balance = line[1].to_i + open_date = line[2] + + new_account = Account.new(id, balance, open_date) + accounts << new_account + # accounts[ line[0] ] = line[1..-1] + # puts line + # accounts[line[0]] = line[1..-1] + + end + return accounts + end + + + def self.find(search_id) + # new_search = Account.all + match = nil + + Bank::Account.all.each do |account| + if account.id == search_id + match = search_id + break + else + match = nil + end + end + + raise ArgumentError.new("There are no accounts with that ID") if match == nil + + return match + + + end + + def withdraw(money_to_withdraw) + raise ArgumentError.new "The amount to withdraw must be greater than zero" if money_to_withdraw < 0 #requires positive withdrawal amount + if money_to_withdraw > @balance #requires withdrawal amount less than balance + puts "Amount to withdraw must be greater than balance" + else + @balance -= money_to_withdraw + end + return @balance + end + + def deposit(money_to_deposit) + raise ArgumentError.new "The deposit amount must be greater than zero" if money_to_deposit < 0 + # start_balance = @balance + # updated_balance = start_balance + money_to_deposit + @balance += money_to_deposit + + end + + # def add_owner + # + # end + + end + +end diff --git a/lib/checking_account.rb b/lib/checking_account.rb new file mode 100644 index 00000000..ff2b59ac --- /dev/null +++ b/lib/checking_account.rb @@ -0,0 +1,64 @@ +require_relative 'account' +require 'csv' + +module Bank + class CheckingAccount < Account + attr_reader :check_count + def initialize(id, balance, open_date = nil) + super + @check_count = 0 + end + + + def withdraw(withdrawal_amount) + if @balance - (withdrawal_amount + 1) < 0 + puts "Warning! This withdrawal will cause you to overdraft!" + # return @balance + else + super(withdrawal_amount) + @balance -= 1.0 + end + return @balance + + end + + def withdraw_using_check(check) + raise ArgumentError.new("Check cannot be a negative amount") if check < 0 + if @check_count < 3 + if (@balance - check) < -10 + puts "Warning! This withdrawal will cause you to be under more than ten dollars!" + # return @balance + + return @balance + else + @check_count += 1 + @balance -= check + end + + else + if (@balance - (check + 2.0)) < -10 + puts "Warning! This withdrawal will cause you to be under more than ten dollars!" + return @balance + else + @check_count += 1 + @balance = @balance - check - 2.0 + end + end + end + + def reset_checks + @check_count = 0 + end + + end +end + +# Create a CheckingAccount class which should inherit behavior from the Account class. It should include the following updated functionality: +# +# Updated withdrawal functionality: +# Each withdrawal 'transaction' incurs a fee of $1 that is taken out of the balance. Returns the updated account balance. +# Does not allow the account to go negative. Will output a warning message and return the original un-modified balance. +# #withdraw_using_check(amount): The input amount gets taken out of the account as a result of a check withdrawal. Returns the updated account balance. +# Allows the account to go into overdraft up to -$10 but not any lower +# The user is allowed three free check uses in one month, but any subsequent use adds a $2 transaction fee +# #reset_checks: Resets the number of checks used to zero diff --git a/lib/owner.rb b/lib/owner.rb new file mode 100644 index 00000000..dee5b610 --- /dev/null +++ b/lib/owner.rb @@ -0,0 +1,18 @@ +module Bank + + class Owner + + attr_reader :name, :address, :account_type + + def initialize(owner_info_hash) + @name = owner_info_hash[:name] + @address = owner_info_hash[:address] + @account_type = owner_info_hash[:account_type] + end + end + +end + + +# Create an Owner class which will store information about those who own the Accounts. +# This should have info like name and address and any other identifying information that an account owner would have. diff --git a/lib/savings_account.rb b/lib/savings_account.rb new file mode 100644 index 00000000..ebb37052 --- /dev/null +++ b/lib/savings_account.rb @@ -0,0 +1,46 @@ +require_relative 'account' +require 'csv' + +module Bank + + class SavingsAccount < Account + attr_accessor :calculated_interest + + def initialize(id, balance, open_date = nil) + super(id, balance, open_date = nil) + raise ArgumentError.new "The initial balance must not be less than 10" if balance < 10 + @calculated_interest = nil + end + + def withdraw(money_to_withdraw) + if @balance - (money_to_withdraw + 2) < 10 + puts "Warning! This withdrawal will put you under the $10 account minimum!" + return @balance + else + super(money_to_withdraw) + return @balance -= 2.0 + end + end + + def add_interest(rate) + raise ArgumentError.new("interest rate must be greater than 0") if rate < 0 + @calculated_interest = balance * rate / 100 + @balance += @calculated_interest + return @calculated_interest + + end + + # def calculate_interest(rate) + # @calculated_interest = balance * rate / 100 + # end + + end +end + + +# Create a SavingsAccount class which should inherit behavior from the Account class. It should include the following updated functionality: +# +# The initial balance cannot be less than $10. If it is, this will raise an ArgumentError +# Updated withdrawal functionality: +# Each withdrawal 'transaction' incurs a fee of $2 that is taken out of the balance. +# Does not allow the account to go below the $10 minimum balance - Will output a warning message and return the original un-modified balance diff --git a/specs/account_spec.rb b/specs/account_spec.rb index 6c399139..82faffb5 100644 --- a/specs/account_spec.rb +++ b/specs/account_spec.rb @@ -2,12 +2,30 @@ require 'minitest/reporters' require 'minitest/skip_dsl' require_relative '../lib/account' +require_relative '../lib/owner' describe "Wave 1" do + + # before do + # owner1_test = { :name => "Sally Mae", :address => "1234 Some Street, Seattle, WA 98144", :account_type => :checking } + # + # new_owner = Bank::Owner.new(owner1_test) + # end + describe "Account#initialize" do + + # before do + # owner1_test = { :name => "Sally Mae", :address => "1234 Some Street, Seattle, WA 98144", :account_type => :checking } + # + # new_owner = Bank::Owner.new(owner1_test) + # end + it "Takes an ID and an initial balance" do id = 1337 balance = 100.0 + # owner1_test = { :name => "Sally Mae", :address => "1234 Some Street, Seattle, WA 98144", :account_type => :checking } + # + # new_owner = Bank::Owner.new(owner1_test) account = Bank::Account.new(id, balance) account.must_respond_to :id @@ -15,9 +33,15 @@ account.must_respond_to :balance account.balance.must_equal balance + + # account.must_respond_to :owner + # account.owner.must_equal new_owner end it "Raises an ArgumentError when created with a negative balance" do + + + # Note: we haven't talked about procs yet. You can think # of them like blocks that sit by themselves. # This code checks that, when the proc is executed, it @@ -28,13 +52,25 @@ end it "Can be created with a balance of 0" do + + # If this raises, the test will fail. No 'must's needed! Bank::Account.new(1337, 0) end end + describe "Account#withdraw" do + + # before do + # owner1_test = { :name => "Sally Mae", :address => "1234 Some Street, Seattle, WA 98144", :account_type => :checking } + # + # new_owner = Bank::Owner.new(owner1_test) + # end + it "Reduces the balance" do + + start_balance = 100.0 withdrawal_amount = 25.0 account = Bank::Account.new(1337, start_balance) @@ -46,6 +82,8 @@ end it "Returns the modified balance" do + + start_balance = 100.0 withdrawal_amount = 25.0 account = Bank::Account.new(1337, start_balance) @@ -57,6 +95,8 @@ end it "Outputs a warning if the account would go negative" do + + start_balance = 100.0 withdrawal_amount = 200.0 account = Bank::Account.new(1337, start_balance) @@ -71,6 +111,8 @@ end it "Doesn't modify the balance if the account would go negative" do + + start_balance = 100.0 withdrawal_amount = 200.0 account = Bank::Account.new(1337, start_balance) @@ -84,6 +126,7 @@ end it "Allows the balance to go to 0" do + account = Bank::Account.new(1337, 100.0) updated_balance = account.withdraw(account.balance) updated_balance.must_equal 0 @@ -91,6 +134,7 @@ end it "Requires a positive withdrawal amount" do + start_balance = 100.0 withdrawal_amount = -25.0 account = Bank::Account.new(1337, start_balance) @@ -102,7 +146,16 @@ end describe "Account#deposit" do + + # before do + # owner1_test = { :name => "Sally Mae", :address => "1234 Some Street, Seattle, WA 98144", :account_type => :checking } + # + # new_owner = Bank::Owner.new(owner1_test) + # end + + it "Increases the balance" do + start_balance = 100.0 deposit_amount = 25.0 account = Bank::Account.new(1337, start_balance) @@ -114,6 +167,7 @@ end it "Returns the modified balance" do + start_balance = 100.0 deposit_amount = 25.0 account = Bank::Account.new(1337, start_balance) @@ -125,6 +179,7 @@ end it "Requires a positive deposit amount" do + start_balance = 100.0 deposit_amount = -25.0 account = Bank::Account.new(1337, start_balance) @@ -136,35 +191,145 @@ end end +# +# describe "Wave 1 - optional" do +# +# describe "Owner#initialize" do +# it "takes owner info as hash" do +# owner1_test = { :name => "Sally Mae", :address => "1234 Some Street, Seattle, WA 98144", :account_type => :checking } +# new_owner = Bank::Owner.new(owner1_test) +# +# new_owner.must_respond_to :name +# new_owner.name.must_equal owner1_test[:name] +# +# new_owner.must_respond_to :address +# new_owner.address.must_equal owner1_test[:address] +# +# new_owner.must_respond_to :account_type +# new_owner.account_type.must_equal owner1_test[:account_type] +# end +# end +# +# describe "Account#initialize" do +# it "Takes an ID, initial balance, and owner_info" do +# id = 1337 +# balance = 100.0 +# owner2_test = { :name => "Jim Bob", :address => "5678 Some Street, Seattle, WA 98109", :account_type => :savings } +# account = Bank::Account.new(id, balance) +# +# account.must_respond_to :id +# account.id.must_equal id +# +# account.must_respond_to :balance +# account.balance.must_equal balance +# +# account.owner_name.must_respond_to :name +# acount.owner_name.must_equal Bank::Owner.name +# end +# end +# +# +# end + + + # TODO: change 'xdescribe' to 'describe' to run these tests -xdescribe "Wave 2" do +describe "Wave 2" do + before do + + @account_array = Bank::Account.all + end + describe "Account.all" do it "Returns an array of all accounts" do + + # TODO: Your test code here! # Useful checks might include: # - Account.all returns an array - # - Everything in the array is an Account - # - The number of accounts is correct + + + @account_array.class.must_equal Array + end + # - Everything in the array is an Account + + # account_array.each do |element| + # element.class + # end + + it "Everything in array is an Account" do + @account_array.each do |element| + element.must_be_instance_of Bank::Account + end + end + + it "The number of accounts matches number of lines in csv file" do # - The number of accounts is correct + @account_array.length.must_equal 12 + + # @accounts.length.must_equal CSV.read("support/accounts.csv").length + end + + + it "ID/balance of first and last accounts match csv file" do # - The ID and balance of the first and last # accounts match what's in the CSV file - # Feel free to split this into multiple tests if needed + + first_account_id = @account_array[0].id + first_account_balance = @account_array[0].balance + + first_account_id.must_equal "1212" + first_account_balance.must_equal 1235667 + + last_account_id = @account_array[-1].id + last_account_balance = @account_array[-1].balance + + last_account_id.must_equal "15156" + last_account_balance.must_equal 4356772 end + + # Feel free to split this into multiple tests if needed + end + describe "Account.find" do + + before do + + @account_array = Bank::Account.all + end + it "Returns an account that exists" do + + # account_id = @account_array[3].id + # + Bank::Account.find("1215").must_equal "1215" + + # TODO: Your test code here! end it "Can find the first account from the CSV" do + + Bank::Account.find(@account_array[0].id).must_equal "1212" + + # TODO: Your test code here! end it "Can find the last account from the CSV" do + + Bank::Account.find(@account_array[-1].id).must_equal "15156" + # TODO: Your test code here! end it "Raises an error for an account that doesn't exist" do + + proc { + Bank::Account.find("00000") + }.must_raise ArgumentError + # TODO: Your test code here! end end diff --git a/specs/checking_account_spec.rb b/specs/checking_account_spec.rb index 7f95339e..13a4f254 100644 --- a/specs/checking_account_spec.rb +++ b/specs/checking_account_spec.rb @@ -3,7 +3,7 @@ require 'minitest/skip_dsl' # TODO: uncomment the next line once you start wave 3 and add lib/checking_account.rb -# require_relative '../lib/checking_account' +require_relative '../lib/checking_account' # Because a CheckingAccount is a kind # of Account, and we've already tested a bunch of functionality @@ -11,7 +11,7 @@ # Here we'll only test things that are different. # TODO: change 'xdescribe' to 'describe' to run these tests -xdescribe "CheckingAccount" do +describe "CheckingAccount" do describe "#initialize" do # Check that a CheckingAccount is in fact a kind of account it "Is a kind of Account" do @@ -23,57 +23,218 @@ describe "#withdraw" do it "Applies a $1 fee each time" do # TODO: Your test code here! + start_balance = 100.0 + account = Bank::CheckingAccount.new(12345, start_balance) + withdraw_amount = 25 + updated_balance = account.withdraw(withdraw_amount) + + updated_balance.must_equal (start_balance - (withdraw_amount + 1)) + end it "Doesn't modify the balance if the fee would put it negative" do # TODO: Your test code here! + + start_balance = 100.0 + account = Bank::CheckingAccount.new(12345, start_balance) + withdraw_amount = 100 + updated_balance = account.withdraw(withdraw_amount) + + updated_balance.must_equal start_balance + account.balance.must_equal start_balance + end end describe "#withdraw_using_check" do it "Reduces the balance" do # TODO: Your test code here! + start_balance = 100.0 + account = Bank::CheckingAccount.new(1235, start_balance) + check_amount = 80 + updated_balance = account.withdraw_using_check(check_amount) + + updated_balance.must_equal (start_balance - check_amount) + updated_balance.must_equal 20 + end it "Returns the modified balance" do # TODO: Your test code here! + + start_balance = 100.0 + account = Bank::CheckingAccount.new(1235, start_balance) + check_amount = 80 + updated_balance = account.withdraw_using_check(check_amount) + + account.balance.must_equal updated_balance + account.balance.must_equal (start_balance - check_amount) end it "Allows the balance to go down to -$10" do # TODO: Your test code here! + start_balance = 100.0 + account = Bank::CheckingAccount.new(1235, start_balance) + check_amount = 110.00 + updated_balance = account.withdraw_using_check(check_amount) + + account.balance.must_equal updated_balance + account.balance.must_equal (start_balance - check_amount) + account.balance.must_equal -10 + end it "Outputs a warning if the account would go below -$10" do # TODO: Your test code here! + + start_balance = 100.0 + account = Bank::CheckingAccount.new(1235, start_balance) + check_amount = 110.01 + # updated_balance = account.withdraw_using_check(check_amount) + + proc { account.withdraw_using_check(check_amount)}.must_output /.+/ + end it "Doesn't modify the balance if the account would go below -$10" do # TODO: Your test code here! + start_balance = 100.0 + account = Bank::CheckingAccount.new(1235, start_balance) + check_amount = 110.01 + updated_balance = account.withdraw_using_check(check_amount) + + updated_balance.must_equal start_balance + end it "Requires a positive withdrawal amount" do # TODO: Your test code here! + + start_balance = 100.0 + account = Bank::CheckingAccount.new(1235, start_balance) + check_amount = -10 + # updated_balance = account.withdraw_using_check(check_amount) + + # updated_balance.must_equal start_balance + proc { account.withdraw_using_check(check_amount)}.must_raise ArgumentError + end it "Allows 3 free uses" do # TODO: Your test code here! + + start_balance = 100.0 + account = Bank::CheckingAccount.new(1235, start_balance) + check1 = 10 + check2 = 20 + check3 = 40 + # check4 = 5 + + account.withdraw_using_check(check1).must_equal 90 + account.withdraw_using_check(check2).must_equal 70 + account.withdraw_using_check(check3).must_equal 30 + end it "Applies a $2 fee after the third use" do # TODO: Your test code here! + start_balance = 100.0 + account = Bank::CheckingAccount.new(1235, start_balance) + check1 = 10 + check2 = 20 + check3 = 40 + check4 = 5 + + account.withdraw_using_check(check1).must_equal 90 + account.withdraw_using_check(check2).must_equal 70 + account.withdraw_using_check(check3).must_equal 30 + account.withdraw_using_check(check4).must_equal 23 + + end end describe "#reset_checks" do it "Can be called without error" do # TODO: Your test code here! + + start_balance = 100.0 + account = Bank::CheckingAccount.new(1235, start_balance) + check1 = 10 + check2 = 20 + check3 = 40 + check4 = 5 + + account.withdraw_using_check(check1) + + account.check_count.must_equal 1 + account.withdraw_using_check(check2) + account.check_count.must_equal 2 + + account.reset_checks + account.check_count.must_equal 0 + end it "Makes the next three checks free if less than 3 checks had been used" do # TODO: Your test code here! + + start_balance = 100.0 + account = Bank::CheckingAccount.new(1235, start_balance) + check1 = 5 + check2 = 10 + check3 = 10 + check4 = 5 + check5 = 3 + check6 = 2 + + account.withdraw_using_check(check1) + account.withdraw_using_check(check2) + account.reset_checks + account.withdraw_using_check(check3) + account.withdraw_using_check(check4) + account.withdraw_using_check(check5).must_equal 67 + account.withdraw_using_check(check6).must_equal 63 + + account.check_count.must_equal 4 end it "Makes the next three checks free if more than 3 checks had been used" do + + start_balance = 100.0 + account = Bank::CheckingAccount.new(1235, start_balance) + check1 = 5 + check2 = 10 + check3 = 10 + check4 = 5 + check5 = 3 + check6 = 2 + check7 = 4 + check8 = 11 + + + account.withdraw_using_check(check1) + account.withdraw_using_check(check2) + account.withdraw_using_check(check3) + account.withdraw_using_check(check4) + + account.balance.must_equal 68 + account.check_count.must_equal 4 + + account.reset_checks + + account.check_count.must_equal 0 + + account.withdraw_using_check(check5) + account.withdraw_using_check(check6) + account.withdraw_using_check(check7) + + account.balance.must_equal 59 + account.check_count.must_equal 3 + + account.withdraw_using_check(check8) + account.balance.must_equal 46 + # TODO: Your test code here! end end diff --git a/specs/savings_account_spec.rb b/specs/savings_account_spec.rb index 3f4d1e4a..43bc9847 100644 --- a/specs/savings_account_spec.rb +++ b/specs/savings_account_spec.rb @@ -1,17 +1,19 @@ require 'minitest/autorun' require 'minitest/reporters' require 'minitest/skip_dsl' +require_relative '../lib/savings_account' # TODO: uncomment the next line once you start wave 3 and add lib/savings_account.rb # require_relative '../lib/savings_account' + # Because a SavingsAccount is a kind # of Account, and we've already tested a bunch of functionality # on Account, we effectively get all that testing for free! # Here we'll only test things that are different. # TODO: change 'xdescribe' to 'describe' to run these tests -xdescribe "SavingsAccount" do +describe "SavingsAccount" do describe "#initialize" do it "Is a kind of Account" do # Check that a SavingsAccount is in fact a kind of account @@ -20,38 +22,116 @@ end it "Requires an initial balance of at least $10" do + # account = Bank::SavingsAccount.new(3453, 8) + # TODO: Your test code here! + proc { + Bank::SavingsAccount.new(1337, 4.0) + }.must_raise ArgumentError + end end describe "#withdraw" do it "Applies a $2 fee each time" do + start_balance = 300.0 + withdrawal_amount = 120.0 + account = Bank::SavingsAccount.new(12345, start_balance) + + account.withdraw(withdrawal_amount) + + + expected_balance = start_balance - withdrawal_amount - 2.0 + account.balance.must_equal expected_balance # TODO: Your test code here! end it "Outputs a warning if the balance would go below $10" do + start_balance = 300.0 + withdrawal_amount = 291.0 + account = Bank::SavingsAccount.new(1234, start_balance) + + # account.withdraw(withdrawal_amount) + + proc { + account.withdraw(withdrawal_amount) + }.must_output /.+/ + + # TODO: Your test code here! end it "Doesn't modify the balance if it would go below $10" do - # TODO: Your test code here! + # TODO: Your test code here! + start_balance = 300.0 + withdrawal_amount = 291.0 + account = Bank::SavingsAccount.new(1234, start_balance) + updated_balance = account.withdraw(withdrawal_amount) + + updated_balance.must_equal start_balance + account.balance.must_equal start_balance + end it "Doesn't modify the balance if the fee would put it below $10" do + + start_balance = 300.0 + withdrawal_amount = 289.0 + account = Bank::SavingsAccount.new(1234, start_balance) + updated_balance = account.withdraw(withdrawal_amount) + + updated_balance.must_equal start_balance + account.balance.must_equal start_balance + # TODO: Your test code here! end end describe "#add_interest" do it "Returns the interest calculated" do + start_balance = 120 + account = Bank::SavingsAccount.new(1234, start_balance) + + rate = 25.0 + interest = start_balance * rate / 100 + + # balance_with_interest = account.add_interest(25.0) + + + account.add_interest(25.0).must_equal interest + # TODO: Your test code here! end it "Updates the balance with calculated interest" do + + start_balance = 120 + + account = Bank::SavingsAccount.new(1234, start_balance) + + rate = 25.0 + interest = account.add_interest(rate) + + interest.must_equal 30 + account.calculated_interest.must_equal interest + account.balance.must_equal start_balance + interest + account.balance.must_equal 150 + + # TODO: Your test code here! end it "Requires a positive rate" do + + start_balance = 120 + + account = Bank::SavingsAccount.new(1234, start_balance) + + proc { + account.add_interest(-0.35) + }.must_raise ArgumentError + + # TODO: Your test code here! end end