diff --git a/lib/account.rb b/lib/account.rb index e69de29b..aecf27fd 100644 --- a/lib/account.rb +++ b/lib/account.rb @@ -0,0 +1,71 @@ +# Create a class inside of a module +# Create methods inside the class to perform actions +# Learn how Ruby does error handling +# Verify code correctness by testing +require 'csv' + +module Bank + class Account + attr_reader :id, :balance, :timedate + + def initialize(id, balance, timedate = nil) + @min_opening_bal = 0 + @min_bal = 0 + @balance = balance + check_opening_bal + @id = id + @timedate = timedate + @fee = 0 + end + + def self.all + account_array = [] + CSV.read("support/accounts.csv").each do |account| + account_array << (Account.new(account[0], account[1].to_i/100.0, account[2])) + end + account_array + end + + # self.find(id) - returns an instance of Account + # where the value of the id field in the CSV matches + # the passed parameter. + def self.find(id) + account_array = Bank::Account.all + account_array.each do |account| + if id == account.id + return account + end + end + raise ArgumentError.new "Account #{id} does not exist" + end + + def check_opening_bal + raise ArgumentError.new "Opening balance must be greater than #{@min_opening_bal}" if @balance < @min_opening_bal + end + + def withdraw(withdrawal_amount) + check_for_negative(withdrawal_amount) + adjust_if_no_low_balance(withdrawal_amount) + @balance + end + + def deposit(deposit_amount) + raise ArgumentError.new "You must deposit an amount" if deposit_amount < 0 + @balance += deposit_amount + end + + def adjust_if_no_low_balance(withdrawal_amount) + if withdrawal_amount > (@balance - @min_bal) + puts "Warning low balance!" + else + @balance -= (withdrawal_amount + @fee) + end + @balance + end + + def check_for_negative(withdrawal_amount) + raise ArgumentError.new "You cannot withdraw a negative amount" if withdrawal_amount < 0 + end + + end #class account +end # module Bank diff --git a/lib/checking_account.rb b/lib/checking_account.rb new file mode 100644 index 00000000..680be31e --- /dev/null +++ b/lib/checking_account.rb @@ -0,0 +1,39 @@ +require_relative 'account' + +module Bank + class CheckingAccount < Account + + def initialize(id, balance, timedate = nil) + super + @number_of_checks = 0 + @fee = 1 + @check_fee = 0 + @min_bal = -10 + check_opening_bal + end + + def withdraw_using_check(withdrawal_amount) + @fee = 0 + check_for_negative(withdrawal_amount) + adjust_if_no_low_balance(withdrawal_amount) + count_check + charge_fee_if_appropriate(3, withdrawal_amount) + end + + def charge_fee_if_appropriate(check_limit, withdrawal_amount) + if @number_of_checks > check_limit && withdrawal_amount < (@balance - @min_bal) + @check_fee = 2 + @balance -= @check_fee + end + return @balance + end + + def count_check + @number_of_checks += 1 + end + + def reset_checks + @number_of_checks = 0 + end + end#class CheckingAccount +end#module Bank diff --git a/lib/savings_account.rb b/lib/savings_account.rb new file mode 100644 index 00000000..ad7ba8a3 --- /dev/null +++ b/lib/savings_account.rb @@ -0,0 +1,26 @@ +require_relative 'account' + +module Bank + class SavingsAccount < Account + + def initialize(id, balance, timedate = nil) + super + @min_opening_bal = 10 + @min_bal = 10 + check_opening_bal + end + + def withdraw(withdrawal_amount) + @min_bal = 10 + @fee = 2 + super + end + + def add_interest(rate, time_in_months) + raise ArgumentError.new "Please provide a positive rate" if rate <= 0 + interest = @balance * rate/100 * time_in_months + @balance += interest + interest + end + end#class SavingsAccount +end#module Bank diff --git a/specs/account_spec.rb b/specs/account_spec.rb index 6c399139..5d37e0b3 100644 --- a/specs/account_spec.rb +++ b/specs/account_spec.rb @@ -8,13 +8,19 @@ it "Takes an ID and an initial balance" do id = 1337 balance = 100.0 - account = Bank::Account.new(id, balance) + timedate = "1999-03-27 11:30:09 -0800" + account = Bank::Account.new(id, balance, timedate) account.must_respond_to :id account.id.must_equal id account.must_respond_to :balance account.balance.must_equal balance + + account.must_respond_to :timedate + account.timedate.must_equal timedate + + end it "Raises an ArgumentError when created with a negative balance" do @@ -23,13 +29,13 @@ # This code checks that, when the proc is executed, it # raises an ArgumentError. proc { - Bank::Account.new(1337, -100.0) + Bank::Account.new(1337, -100.0, "1999-03-27 11:30:09 -0800") }.must_raise ArgumentError 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) + Bank::Account.new(1337, 0, "1999-03-27 11:30:09 -0800") end end @@ -37,10 +43,8 @@ it "Reduces the balance" do start_balance = 100.0 withdrawal_amount = 25.0 - account = Bank::Account.new(1337, start_balance) - + account = Bank::Account.new(1337, start_balance, "1999-03-27 11:30:09 -0800") account.withdraw(withdrawal_amount) - expected_balance = start_balance - withdrawal_amount account.balance.must_equal expected_balance end @@ -48,7 +52,7 @@ it "Returns the modified balance" do start_balance = 100.0 withdrawal_amount = 25.0 - account = Bank::Account.new(1337, start_balance) + account = Bank::Account.new(1337, start_balance, "1999-03-27 11:30:09 -0800") updated_balance = account.withdraw(withdrawal_amount) @@ -59,7 +63,7 @@ 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) + account = Bank::Account.new(1337, start_balance, "1999-03-27 11:30:09 -0800") # Another proc! This test expects something to be printed # to the terminal, using 'must_output'. /.+/ is a regular @@ -73,7 +77,7 @@ 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) + account = Bank::Account.new(1337, start_balance, "1999-03-27 11:30:09 -0800") updated_balance = account.withdraw(withdrawal_amount) @@ -84,7 +88,7 @@ end it "Allows the balance to go to 0" do - account = Bank::Account.new(1337, 100.0) + account = Bank::Account.new(1337, 100.0, "1999-03-27 11:30:09 -0800") updated_balance = account.withdraw(account.balance) updated_balance.must_equal 0 account.balance.must_equal 0 @@ -93,7 +97,7 @@ it "Requires a positive withdrawal amount" do start_balance = 100.0 withdrawal_amount = -25.0 - account = Bank::Account.new(1337, start_balance) + account = Bank::Account.new(1337, start_balance, "1999-03-27 11:30:09 -0800") proc { account.withdraw(withdrawal_amount) @@ -105,7 +109,7 @@ it "Increases the balance" do start_balance = 100.0 deposit_amount = 25.0 - account = Bank::Account.new(1337, start_balance) + account = Bank::Account.new(1337, start_balance, "1999-03-27 11:30:09 -0800") account.deposit(deposit_amount) @@ -116,7 +120,7 @@ it "Returns the modified balance" do start_balance = 100.0 deposit_amount = 25.0 - account = Bank::Account.new(1337, start_balance) + account = Bank::Account.new(1337, start_balance, "1999-03-27 11:30:09 -0800") updated_balance = account.deposit(deposit_amount) @@ -127,7 +131,7 @@ it "Requires a positive deposit amount" do start_balance = 100.0 deposit_amount = -25.0 - account = Bank::Account.new(1337, start_balance) + account = Bank::Account.new(1337, start_balance, "1999-03-27 11:30:09 -0800") proc { account.deposit(deposit_amount) @@ -136,36 +140,88 @@ end end -# TODO: change 'xdescribe' to 'describe' to run these tests -xdescribe "Wave 2" do + + + +describe "Wave 2" do describe "Account.all" do + + before do + @account_array = Bank::Account.all + end + + 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 - # - 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 + @account_array.must_be_instance_of Array + + end + # Useful checks might include: + + # - The number of accounts is correct + it "The number of accounts is correct" do + @account_array.length.must_equal CSV.read("support/accounts.csv").length + end + # - account is an Array + it "account is an Array" do + @account_array.class.must_equal Array + end + + # - Everything in the array is an Account + it "Everything in the array is an Account" do + @account_array.each {|account| account.class.must_equal Bank::Account} + end + + # - The ID and balance of the first and last + # accounts match what's in the CSV file + it " accounts match what's in the CSV file" do + index = 0 + CSV.read("support/accounts.csv") do |line| + accounts[index].id.must_equal line[0].to_i + accounts[index].id.must_equal line[1].to_i + accounts[index].id.must_equal line[2].to_i + index += 1 + end + end + + it "The ID and balance of the first and last match csv" do + @account_array.first.id.must_equal "1212" + @account_array.first.balance.must_equal 12356.67 + @account_array.last.id.must_equal "15156" + @account_array.last.balance.must_equal 43567.72 end end + describe "Account.find" do + before do + @test_array = Bank::Account.all + end + # self.find(id) - returns an instance of Account + # where the value of the id field in the CSV matches + # the passed parameter. it "Returns an account that exists" do - # TODO: Your test code here! + test_variable = Bank::Account.find("1212") + test_variable.must_be_instance_of Bank::Account + test_variable.id.must_equal "1212" end it "Can find the first account from the CSV" do - # TODO: Your test code here! + Bank::Account.find(@test_array[0].id).id.must_equal "1212" end it "Can find the last account from the CSV" do - # TODO: Your test code here! + Bank::Account.find(@test_array[-1].id).id.must_equal "15156" end it "Raises an error for an account that doesn't exist" do - # TODO: Your test code here! + proc { + Bank::Account.find("0000") + }.must_raise ArgumentError end end + describe "Account.find" do + before do @test_array = Bank::Account.all + end + end + end diff --git a/specs/checking_account_spec.rb b/specs/checking_account_spec.rb index 7f95339e..fa58dbf7 100644 --- a/specs/checking_account_spec.rb +++ b/specs/checking_account_spec.rb @@ -3,15 +3,14 @@ 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 # 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 "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 @@ -22,59 +21,141 @@ describe "#withdraw" do it "Applies a $1 fee each time" do - # TODO: Your test code here! + start_balance = 100.0 + withdrawal_amount = 25.0 + account = Bank::CheckingAccount.new(1337, start_balance) + account.withdraw(withdrawal_amount) + expected_balance = start_balance - (withdrawal_amount + 1) + account.balance.must_equal expected_balance + end it "Doesn't modify the balance if the fee would put it negative" do - # TODO: Your test code here! + start_balance = 100.0 + withdrawal_amount = 200.0 + account = Bank::CheckingAccount.new(1337, start_balance) + + updated_balance = account.withdraw(withdrawal_amount) + + # Both the value returned and the balance in the account + # must be un-modified. + 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 + withdrawal_amount = 50.0 + account = Bank::CheckingAccount.new(1337, start_balance) + updated_balance = account.withdraw_using_check(withdrawal_amount) + boolean = updated_balance < start_balance + boolean.must_equal true end it "Returns the modified balance" do - # TODO: Your test code here! + start_balance = 100.0 + withdrawal_amount = 50.0 + account = Bank::CheckingAccount.new(1337, start_balance) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance.wont_equal 100 end it "Allows the balance to go down to -$10" do - # TODO: Your test code here! + start_balance = 100.0 + withdrawal_amount = 110.0 + account = Bank::CheckingAccount.new(1337, start_balance) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_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 + withdrawal_amount = 111.0 + account = Bank::CheckingAccount.new(1337, start_balance) + proc { + account.withdraw_using_check(withdrawal_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 + withdrawal_amount = 111.0 + account = Bank::CheckingAccount.new(1337, start_balance) + account.withdraw_using_check(withdrawal_amount).must_equal 100 end it "Requires a positive withdrawal amount" do - # TODO: Your test code here! + start_balance = 100.0 + deposit_amount = -25.0 + account = Bank::CheckingAccount.new(1337, start_balance) + proc { + account.deposit(deposit_amount) + }.must_raise ArgumentError end - + # it "Allows 3 free uses" do - # TODO: Your test code here! + start_balance = 100.0 + withdrawal_amount = 10.0 + account = Bank::CheckingAccount.new(1337, start_balance) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance.must_equal 70.0 end it "Applies a $2 fee after the third use" do - # TODO: Your test code here! + start_balance = 100.0 + withdrawal_amount = 10.0 + updated_balance = 0 + account = Bank::CheckingAccount.new(1337, start_balance) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance.must_equal 58 end end - + # describe "#reset_checks" do it "Can be called without error" do - # TODO: Your test code here! + start_balance = 100.0 + withdrawal_amount = 10 + account = Bank::CheckingAccount.new(1337, start_balance) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + account.reset_checks + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance.must_equal 36 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 + withdrawal_amount = 10 + account = Bank::CheckingAccount.new(1337, start_balance) + account.reset_checks + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance.must_equal 70 end it "Makes the next three checks free if more than 3 checks had been used" do - # TODO: Your test code here! + start_balance = 100.0 + withdrawal_amount = 10 + account = Bank::CheckingAccount.new(1337, start_balance) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + account.reset_checks + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance = account.withdraw_using_check(withdrawal_amount) + updated_balance.must_equal 40 end end end diff --git a/specs/savings_account_spec.rb b/specs/savings_account_spec.rb index 3f4d1e4a..0a781f04 100644 --- a/specs/savings_account_spec.rb +++ b/specs/savings_account_spec.rb @@ -2,8 +2,7 @@ require 'minitest/reporters' require 'minitest/skip_dsl' -# TODO: uncomment the next line once you start wave 3 and add lib/savings_account.rb -# require_relative '../lib/savings_account' +require_relative '../lib/savings_account' # Because a SavingsAccount is a kind # of Account, and we've already tested a bunch of functionality @@ -11,7 +10,7 @@ # 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,39 +19,60 @@ end it "Requires an initial balance of at least $10" do - # TODO: Your test code here! + proc { + Bank::SavingsAccount.new(1337, 9.0) + }.must_raise ArgumentError end end describe "#withdraw" do it "Applies a $2 fee each time" do - # TODO: Your test code here! + account = Bank::SavingsAccount.new(12345, 100.0) + updated_balance = account.withdraw(10) + updated_balance.must_equal 88 + end it "Outputs a warning if the balance would go below $10" do - # TODO: Your test code here! + account = Bank::SavingsAccount.new(12345, 100.0) + proc { + account.withdraw(91) + }.must_output /.+/ end it "Doesn't modify the balance if it would go below $10" do - # TODO: Your test code here! + account = Bank::SavingsAccount.new(12345, 100.0) + updated_balance = account.withdraw(91) + updated_balance.must_equal 100 end it "Doesn't modify the balance if the fee would put it below $10" do - # TODO: Your test code here! + start_balance = 100.0 + withdrawal_amount = 91 + account = Bank::SavingsAccount.new(1337, start_balance) + account.withdraw(withdrawal_amount).must_equal 100 end end describe "#add_interest" do it "Returns the interest calculated" do - # TODO: Your test code here! + start_balance = 100.0 + account = Bank::SavingsAccount.new(1337, start_balance) + account.add_interest(2.5, 1).must_equal 2.5 end it "Updates the balance with calculated interest" do - # TODO: Your test code here! + start_balance = 100.0 + account = Bank::SavingsAccount.new(1337, start_balance) + account.add_interest(2.5, 1) + account.balance.must_equal 102.5 end it "Requires a positive rate" do - # TODO: Your test code here! + account = Bank::SavingsAccount.new(1337, 100.0) + proc { + account.add_interest(0, 1) + }.must_raise ArgumentError end end end