diff --git a/README.md b/README.md index 6251da8d..7ad86e24 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Make sure to write tests for any optionals you implement! - Add an `owner` property to each Account to track information about who owns the account. - The `Account` can be created with an `owner`, OR you can create a method that will add the `owner` after the `Account` has already been created. - - diff --git a/lib/account.rb b/lib/account.rb index e69de29b..668bdd94 100644 --- a/lib/account.rb +++ b/lib/account.rb @@ -0,0 +1,51 @@ +require "csv" # one require files. Use file name without .rb + +module Bank + class Account + attr_reader :id, :balance, :open_date + def initialize(id, balance, open_date = nil) + raise ArgumentError.new("The balance must be >= 0") if balance < 0 + @id = id + @balance = balance + @open_date = open_date + end + + def self.all + all_accounts = [] + CSV.open("./support/accounts.csv").each do |acc| + all_accounts << self.new(acc[0].to_i, acc[1].to_f, acc[2]) # acc[2] should be transformed to date-time + end + return all_accounts + end + + def self.find(id) + found_account = nil + self.all.each do |acc| + if acc.id == id + found_account = acc + break + end + end + raise ArgumentError.new "Account does not exist" if found_account == nil + return found_account + end + + def withdraw(amount) + # TODO: implement withdraw + raise ArgumentError.new("Withdrawal amount must be > 0") if amount < 0 + if amount > @balance + print "Withdrawal denied. The amount is bigger than your account balance" + elsif amount <= @balance + @balance -= amount + end + return @balance + end + + def deposit(amount) + # TODO: implement deposit + raise ArgumentError.new("Deposit amount must be >= 0") if amount < 0 + return @balance += amount + end + + end # End of class Account +end # End of module Bank diff --git a/lib/checking_account.rb b/lib/checking_account.rb new file mode 100644 index 00000000..fb806e88 --- /dev/null +++ b/lib/checking_account.rb @@ -0,0 +1,39 @@ +require_relative "account" + +module Bank + class CheckingAccount < Account + attr_accessor :check_count + attr_reader :withdraw_fee, :check_withdraw_fee + def initialize(id, balance, open_date = nil) + super(id, balance, open_date) + @withdraw_fee = 1 + @check_withdraw_fee = 2 + @check_count = 0 + end + + def withdraw(amount) + amount += @withdraw_fee + super(amount) + end + + def withdraw_using_check(check_amount) + raise ArgumentError.new("Note: The check amount must be positive") if check_amount < 0 + raise ArgumentError.new("Withdrawal denied. The balance will go pass the limit of -$10 ") if @balance - check_amount < -10 + @check_count += 1 + + if @check_count <= 3 + @balance -= check_amount + else + raise ArgumentError.new("Withdrawal denied. The balance will go pass the limit of -$10 ") if @balance - (check_amount + @check_withdraw_fee) < -10 + @balance -= (check_amount + @check_withdraw_fee) + end + + return @balance + end + + def reset_checks + @check_count = 0 + end + + end # End of the class CheckingAccount +end # End of the module Bank diff --git a/lib/owner.rb b/lib/owner.rb new file mode 100644 index 00000000..bfa7361c --- /dev/null +++ b/lib/owner.rb @@ -0,0 +1,25 @@ +## This class is unfinished + +module Bank + class Owner + attr_reader :id, :last_name, :first_name, :street_address, :city, :state + def initialize(id, last_name, first_name, street_address, city, state) + @id = id + @last_name = last_name + @first_name = first_name + @street_address = street_address + @city = city + @state = state + end + + def self.all + + end + + def self.find + + end + + + end #End of class Owner +end # End of module Bank diff --git a/lib/savings_account.rb b/lib/savings_account.rb new file mode 100644 index 00000000..4de74124 --- /dev/null +++ b/lib/savings_account.rb @@ -0,0 +1,30 @@ +require_relative "account" + +module Bank + class SavingsAccount < Account + attr_accessor :fee + def initialize(id, balance, open_date = nil) + raise ArgumentError.new("The balance must be >= $10") if balance < 10.0 + super(id, balance, open_date) + @withdraw_fee = 2 + end + + def withdraw(amount) + raise ArgumentError.new("Withdrawal amount must be > 0") if amount < 0 + if amount + @withdraw_fee > @balance - 10 + print "Withdrawal denied. Your balance would go below $10" + else + @balance -= amount + @withdraw_fee + end + return @balance + end + + def add_interest(rate) + raise ArgumentError.new("Note: The rate must be positive") if rate < 0 + interest = @balance * rate/100 + @balance += interest + return interest + end + + end # End of class SavingsAccount +end # End of module Bank diff --git a/specs/account_spec.rb b/specs/account_spec.rb index 6c399139..cc331dfc 100644 --- a/specs/account_spec.rb +++ b/specs/account_spec.rb @@ -3,6 +3,9 @@ require 'minitest/skip_dsl' require_relative '../lib/account' +########### +# WAVE 1 +########### describe "Wave 1" do describe "Account#initialize" do it "Takes an ID and an initial balance" do @@ -15,6 +18,7 @@ account.must_respond_to :balance account.balance.must_equal balance + end it "Raises an ArgumentError when created with a negative balance" do @@ -31,16 +35,14 @@ # If this raises, the test will fail. No 'must's needed! Bank::Account.new(1337, 0) end - end + end # End of describe "Account#initialize" describe "Account#withdraw" do it "Reduces the balance" do start_balance = 100.0 withdrawal_amount = 25.0 account = Bank::Account.new(1337, start_balance) - account.withdraw(withdrawal_amount) - expected_balance = start_balance - withdrawal_amount account.balance.must_equal expected_balance end @@ -49,9 +51,7 @@ start_balance = 100.0 withdrawal_amount = 25.0 account = Bank::Account.new(1337, start_balance) - updated_balance = account.withdraw(withdrawal_amount) - expected_balance = start_balance - withdrawal_amount updated_balance.must_equal expected_balance end @@ -60,23 +60,20 @@ start_balance = 100.0 withdrawal_amount = 200.0 account = Bank::Account.new(1337, start_balance) - # Another proc! This test expects something to be printed # to the terminal, using 'must_output'. /.+/ is a regular # expression matching one or more characters - as long as # anything at all is printed out the test will pass. proc { account.withdraw(withdrawal_amount) - }.must_output /.+/ + }.must_output (/.+/) 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) - 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 @@ -94,21 +91,18 @@ start_balance = 100.0 withdrawal_amount = -25.0 account = Bank::Account.new(1337, start_balance) - proc { account.withdraw(withdrawal_amount) }.must_raise ArgumentError end - end + end # End of describe "Account#withdraw" describe "Account#deposit" do it "Increases the balance" do start_balance = 100.0 deposit_amount = 25.0 account = Bank::Account.new(1337, start_balance) - account.deposit(deposit_amount) - expected_balance = start_balance + deposit_amount account.balance.must_equal expected_balance end @@ -117,9 +111,7 @@ start_balance = 100.0 deposit_amount = 25.0 account = Bank::Account.new(1337, start_balance) - updated_balance = account.deposit(deposit_amount) - expected_balance = start_balance + deposit_amount updated_balance.must_equal expected_balance end @@ -128,16 +120,16 @@ start_balance = 100.0 deposit_amount = -25.0 account = Bank::Account.new(1337, start_balance) - proc { account.deposit(deposit_amount) }.must_raise ArgumentError end - end -end + end # End of describe "Account#deposit" +end # End of describe "Wave 1" + # TODO: change 'xdescribe' to 'describe' to run these tests -xdescribe "Wave 2" do +describe "Wave 2" do describe "Account.all" do it "Returns an array of all accounts" do # TODO: Your test code here! @@ -148,24 +140,47 @@ # - 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 - end - end + all_accounts = Bank::Account.all + all_accounts.must_be_kind_of Array, "Ops, an array is not returned" + all_accounts.each do |acc| + acc.must_be_kind_of Bank::Account, "Ops, everything in the array is NOT an Account" + end + # Check number of accounts + all_accounts.length.must_equal 12, "Ops, the array does not return all accounts" + # Check id + all_accounts.first.id.must_equal 1212, "First id does not match up" + all_accounts.last.id.must_equal 15156, "Last id does not match up" + # Check balance + all_accounts.first.balance.must_equal 1235667, "First balance does not match up" + all_accounts.last.balance.must_equal 4356772, "Last balance does not match up" + end + end # End of describe "Account.all" describe "Account.find" do it "Returns an account that exists" do - # TODO: Your test code here! + # TODO: Your test code here + Bank::Account.find(15151).must_be_kind_of Bank::Account, "Does not return a Account object" end it "Can find the first account from the CSV" do # TODO: Your test code here! + first_account = Bank::Account.find(1212) + first_account.id.must_equal 1212, "Can't find the first account" end it "Can find the last account from the CSV" do # TODO: Your test code here! + last_account = Bank::Account.find(15156) + last_account.id.must_equal 15156, "Can't find the last account" + end it "Raises an error for an account that doesn't exist" do # TODO: Your test code here! + proc { + Bank::Account.find(1) + }.must_raise ArgumentError end - end -end + + end # End of describe "Account.find" +end # End of describe "Wave 2" diff --git a/specs/checking_account_spec.rb b/specs/checking_account_spec.rb index 7f95339e..609f682a 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,70 +11,173 @@ # 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 account = Bank::CheckingAccount.new(12345, 100.0) account.must_be_kind_of Bank::Account end - end + end # End describe "#initialize" describe "#withdraw" do it "Applies a $1 fee each time" do # TODO: Your test code here! + checking_account = Bank::CheckingAccount.new(1337, 200) + withdrawal_amount = 99 + new_balance = checking_account.withdraw(withdrawal_amount) + new_balance.must_equal withdrawal_amount + 1, "$1 fee is not withdrawn from the savings account" + checking_account.balance.must_equal withdrawal_amount + 1, "$1 fee is not withdrawn from the savings account" end it "Doesn't modify the balance if the fee would put it negative" do # TODO: Your test code here! + start_balance = 200 + withdrawal_amount = 200 + checking_account = Bank::CheckingAccount.new(1337, start_balance) + updated_balance = checking_account.withdraw(withdrawal_amount) + # Both the value returned and the balance in the account + # must be un-modified. + updated_balance.must_equal start_balance + checking_account.balance.must_equal start_balance end - end + end # End describe "#withdraw" describe "#withdraw_using_check" do it "Reduces the balance" do # TODO: Your test code here! + start_balance = 200 + check_amount = 25 + checking_account = Bank::CheckingAccount.new(1337, start_balance) + reduced_balance = checking_account.withdraw_using_check(check_amount) + reduced_balance.must_be :< ,start_balance , "The balance is not reduced" end it "Returns the modified balance" do # TODO: Your test code here! + start_balance = 200 + check_amount = 25 + checking_account = Bank::CheckingAccount.new(1337, start_balance) + new_balance = checking_account.withdraw_using_check(check_amount) + new_balance.must_equal start_balance - check_amount, "A modified balance is not returned" + checking_account.balance.must_equal new_balance, "The balance in the account is not the same as the return value of #withdraw_using_check" end it "Allows the balance to go down to -$10" do # TODO: Your test code here! + start_balance = 200 + check_amount = 210 + checking_account = Bank::CheckingAccount.new(1337, start_balance) + negative_balance = checking_account.withdraw_using_check(check_amount) + negative_balance.must_be :>=, -10 , "The balance cannot go down to -$10" end it "Outputs a warning if the account would go below -$10" do # TODO: Your test code here! + checking_account = Bank::CheckingAccount.new(1337, 200) + proc { + checking_account.withdraw_using_check(210.1) + }.must_raise ArgumentError end it "Doesn't modify the balance if the account would go below -$10" do # TODO: Your test code here! + start_balance = 200 + withdrawal_amount = 210.1 + checking_account = Bank::CheckingAccount.new(1337, start_balance) + proc { + checking_account.withdraw_using_check(withdrawal_amount) + }.must_raise ArgumentError + checking_account.balance.must_equal start_balance, "The balance is not the same as start_balance" end it "Requires a positive withdrawal amount" do # TODO: Your test code here! + start_balance = 200 + withdrawal_amount = -1 + checking_account = Bank::CheckingAccount.new(1337, start_balance) + proc { + checking_account.withdraw_using_check(withdrawal_amount) + }.must_raise ArgumentError end it "Allows 3 free uses" do # TODO: Your test code here! + start_balance = 200 + withdrawal_amount = 10 + checking_account = Bank::CheckingAccount.new(1337, start_balance) + 3.times do + checking_account.withdraw_using_check(withdrawal_amount) + end + checking_account.balance.must_equal (start_balance - 3 * withdrawal_amount) , "The resulting balance showsthat there is NOT 3 free uses" end it "Applies a $2 fee after the third use" do # TODO: Your test code here! + start_balance = 200 + withdrawal_amount = 10 + fee = 2 + checking_account = Bank::CheckingAccount.new(1337, start_balance) + 4.times do + checking_account.withdraw_using_check(withdrawal_amount) + end + checking_account.balance.must_equal (start_balance - 4 * withdrawal_amount - fee) , "The resulting balance shows that the fee is not included" end - end + + it "Doesn't modify the balance if the account would go below -$10 due to the fee" do + # TODO: Your test code here! + start_balance = 30 + withdrawal_amount = 10 + checking_account = Bank::CheckingAccount.new(1337, start_balance) + + 3.times do + checking_account.withdraw_using_check(withdrawal_amount) + end + + proc { + checking_account.withdraw_using_check(9) + }.must_raise ArgumentError + end + end # End describe "#withdraw_using_check" describe "#reset_checks" do it "Can be called without error" do # TODO: Your test code here! + checking_account = Bank::CheckingAccount.new(1337, 200) + checking_account.reset_checks.must_equal 0, "Calling this method throws an error" end it "Makes the next three checks free if less than 3 checks had been used" do # TODO: Your test code here! + start_balance = 200 + withdrawal_amount = 10 + checking_account = Bank::CheckingAccount.new(1337, start_balance) + 2.times do + checking_account.withdraw_using_check(withdrawal_amount) + end + checking_account.reset_checks + 3.times do + checking_account.withdraw_using_check(withdrawal_amount) + end + checking_account.balance.must_equal (start_balance - 5 * withdrawal_amount) , "Does NOT make the next three checks free if less than 3 checks had been used" end it "Makes the next three checks free if more than 3 checks had been used" do # TODO: Your test code here! + start_balance = 200 + withdrawal_amount = 10 + fee = 2 + checking_account = Bank::CheckingAccount.new(1337, start_balance) + 4.times do + checking_account.withdraw_using_check(withdrawal_amount) + end + checking_account.reset_checks + 3.times do + checking_account.withdraw_using_check(withdrawal_amount) + end + checking_account.balance.must_equal (start_balance - (4 * withdrawal_amount + fee) - 3 * withdrawal_amount) , "Does NOT + make the next three checks free if more than 3 checks had been used" end - end -end + + end # End describe "#reset_checks" +end # END describe "CheckingAccount" diff --git a/specs/owner_spec.rb b/specs/owner_spec.rb new file mode 100644 index 00000000..c6301314 --- /dev/null +++ b/specs/owner_spec.rb @@ -0,0 +1,44 @@ + + +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/skip_dsl' +require_relative '../lib/owner' + + +########### +# OPTIONAL +########### + +describe "Owner class" do + describe "Owner#initialize" do + it "Takes an ID, last name, first name, street address, city and state" do + id = 18 + last_name = "Gonzalez" + first_name = "Laura" + street_address = "310 Hauk Street" + city = "Springfield" + state = "Illinois" + + owner = Bank::Owner.new(id, last_name, first_name, street_address, city, state) + + owner.must_respond_to :id + owner.id.must_equal id + + owner.must_respond_to :last_name + owner.last_name.must_equal last_name + + owner.must_respond_to :first_name + owner.first_name.must_equal first_name + + owner.must_respond_to :street_address + owner.street_address.must_equal street_address + + owner.must_respond_to :city + owner.city.must_equal city + + owner.must_respond_to :state + owner.state.must_equal state + end + end +end diff --git a/specs/savings_account_spec.rb b/specs/savings_account_spec.rb index 3f4d1e4a..1c4a40e8 100644 --- a/specs/savings_account_spec.rb +++ b/specs/savings_account_spec.rb @@ -3,7 +3,7 @@ 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 +11,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 @@ -21,38 +21,72 @@ it "Requires an initial balance of at least $10" do # TODO: Your test code here! + proc { + Bank::SavingsAccount.new(1337, 9.99) + }.must_raise ArgumentError end - end + end # End of describe "#initialize" describe "#withdraw" do it "Applies a $2 fee each time" do # TODO: Your test code here! + savings_account = Bank::SavingsAccount.new(1337, 200) + new_balance = savings_account.withdraw(98) + new_balance.must_equal 98 + 2, "$2 fee is not withdrawn from the savings account" + savings_account.balance.must_equal 98 + 2, "$2 fee is not withdrawn from the savings account" end it "Outputs a warning if the balance would go below $10" do # TODO: Your test code here! + start_balance = 100.0 + withdrawal_amount = 90.1 + savings_account = Bank::SavingsAccount.new(1337, start_balance) + proc { + savings_account.withdraw(withdrawal_amount) + }.must_output (/.+/) end it "Doesn't modify the balance if it would go below $10" do # TODO: Your test code here! + start_balance = 100.0 + withdrawal_amount = 91.0 + savings_account = Bank::SavingsAccount.new(1337, start_balance) + updated_balance = savings_account.withdraw(withdrawal_amount) + updated_balance.must_equal start_balance + savings_account.balance.must_equal start_balance 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 = 88.1 + savings_account = Bank::SavingsAccount.new(1337, start_balance) + updated_balance = savings_account.withdraw(withdrawal_amount) + updated_balance.must_equal start_balance + savings_account.balance.must_equal start_balance end - end + end # End of describe "#withdraw" describe "#add_interest" do it "Returns the interest calculated" do # TODO: Your test code here! + savings_account = Bank::SavingsAccount.new(1337, 10000) + savings_account.add_interest(0.25).must_equal 10000 * 0.25/100, "The method does not return the calculated interest" end it "Updates the balance with calculated interest" do # TODO: Your test code here! + savings_account = Bank::SavingsAccount.new(1337, 10000) + savings_account.add_interest(0.25) + savings_account.balance.must_equal 10025, "The balance does not get updated" end it "Requires a positive rate" do # TODO: Your test code here! + savings_account = Bank::SavingsAccount.new(1337, 10000) + proc { + savings_account.add_interest(-0.25) + }.must_raise ArgumentError end - end -end + end # End of describe "#add_interest" +end # End of describe "SavingsAccount"