diff --git a/lib/account.rb b/lib/account.rb index e69de29b..7466ffdd 100644 --- a/lib/account.rb +++ b/lib/account.rb @@ -0,0 +1,100 @@ +require 'csv' +require 'date' + +module Bank + class Account + # Allows access to the current balance of an account at any time. + attr_accessor :balance, :owner + # Only allow reader on unique account id, and opendate + attr_reader :id, :open_date + + # Constructs a new Account object + # Give a default value, in case the Owner class object is not passed + # Assumes passed parameters are formated in their correct data type. + def initialize id, balance, open_date, owner = nil + # error handling for initial negative balance + if balance >= 0 + @balance = balance + else + raise ArgumentError.new "Inital balance cannot be a negetive value" + end + + @id = id + @open_date = DateTime.parse(open_date) + + # Assumes that required csv file is accesible + CSV.read("support/account_owners.csv").each do |line| + if line[0].to_i == @id + @owner = Bank::Owner.find(line[1].to_i) + end + end + + if owner.class == Bank::Owner + @owner = owner + else + # Default instance of the Owner class initialized with empty hash + @owner = Bank::Owner.new({}) + end + end + + # Method that returns a collection of Account instances, from data read in CSV + def self.all + all_accounts_array= [] + + CSV.read("support/accounts.csv").each do |line| + all_accounts_array << Bank::Account.new( line[0].to_i, line[1].to_i, line[2] ) + end + return all_accounts_array + end + + # Method that returns an instance of an Account class, where the value of the id field in the CSV matches the passed parameter + def self.find(id) + raise ArgumentError.new ("Account id must be a positive integer value") if ( id.class != Integer || id < 1 ) + + CSV.read("support/accounts.csv").each do |line| + if line[0].to_i == id + account = Bank::Account.new( line[0].to_i, line[1].to_i, line[2]) + return account + end + end + raise ArgumentError.new "Account id does not exist in the database" + end + + + # Method that overwrites existing empty @owner instance variable + def update_owner_data(owner_hash) + # Only overwrite if initially not added to account at the time of initializing account object + if @owner.id == 0 + @owner = Bank::Owner.new(owner_hash) + end + end + + # Method that handles withdraw + def withdraw(withdraw_amount) + # Error handling for insufficient funds for a withdraw + raise ArgumentError.new ("Withdraw amount must be a positive numericla value") if ( !(withdraw_amount.class == Integer || withdraw_amount.class == Float) || withdraw_amount < 0 ) + # Insufficient funds + if @balance < withdraw_amount + puts "You do not have sufficient funds to withdraw the entered amount" + # Negative withdraw amount, invalid + elsif withdraw_amount < 0 + raise ArgumentError.new "Withdraw amount cannot be a negetive value" + # Allow withdraw and update the balance + else + @balance -= withdraw_amount + end + return @balance + end + + # Method that handles deposits + def deposit(money_amount) + # Negative deposit amount, invalid + if money_amount < 0 + raise ArgumentError.new "Deposit amount cannot be a negetive value" + else + @balance += money_amount + return @balance + end + end + end +end diff --git a/lib/checking_account.rb b/lib/checking_account.rb new file mode 100644 index 00000000..4365c13d --- /dev/null +++ b/lib/checking_account.rb @@ -0,0 +1,66 @@ +require 'csv' +require_relative 'account' + +module Bank + class CheckingAccount < Bank::Account + attr_accessor :new_month + attr_reader :num_checks_used + + def initialize(id, balance, open_date) + super(id, balance, open_date) + @num_checks_used = 0 + @new_month = false + end + + # Method that handles withdraw + def withdraw(withdraw_amount) + # raise error for erroneous withdraw value + raise ArgumentError.new ("Withdraw amount must be a positive numericla value") if ( !(withdraw_amount.class == Integer || withdraw_amount.class == Float) || withdraw_amount < 0 ) + + # Error handling for insufficient funds for a withdraw + transaction_fee = 100 + + # Balance is insufficient + if @balance <= (withdraw_amount + transaction_fee) + puts "The amount you enetered for the withdraw will cause the balance to go below the $0.00" + # Ok to withdraw, updates the balance + else + @balance -= (withdraw_amount + transaction_fee) + end + return @balance + end + + # Method that handles withdraw_using_check + def withdraw_using_check(withdraw_amount) + # raise error for non integer withdraw value + raise ArgumentError.new ("Withdraw amount must be a positive numerical value") if ( !(withdraw_amount.class == Integer || withdraw_amount.class == Float) || withdraw_amount < 0 ) + + # Error handling for insufficient funds for a withdraw + transaction_fee = 100 + allotted_negative_balance = -1000 + check_fee = 0 + + if @num_checks_used >= 3 + check_fee = 200 + end + # Balance is insufficient + if @balance < (withdraw_amount + transaction_fee + check_fee + allotted_negative_balance) + puts "The amount you enetered for the withdraw will cause the balance to go over the allotted_negative_balance of -$10.00" + # Ok to withdraw, update @balance + else + @balance -= (withdraw_amount + transaction_fee + check_fee) + @num_checks_used += 1 + end + return @balance + end + + # Resets the number of checks used to zero + def reset_checks() + if @new_month + @num_checks_used = 0 + @new_month = false + end + end + + end +end diff --git a/lib/money_market_account.rb b/lib/money_market_account.rb new file mode 100644 index 00000000..1c62b348 --- /dev/null +++ b/lib/money_market_account.rb @@ -0,0 +1,64 @@ +require 'csv' +require_relative 'savings_account' + +module Bank + class MoneyMarketAccount < Bank::SavingsAccount + attr_accessor :new_month, :num_transaction + + def initialize(id, balance, open_date) + raise ArgumentError.new("Your initial balance must be at least $10,000.00") if balance < 1000000 + super(id, balance, open_date) + @num_transaction = 0 + @new_month = false + end + + def withdraw(withdraw_amount) + # Raise error for non integer withdraw value + raise ArgumentError.new ("Withdraw amount must be a positive numerical value") if ( !(withdraw_amount.class == Integer || withdraw_amount.class == Float) || withdraw_amount < 0 ) + minimum_balance = 1000000 + penalty_fee = 0 + + # Withdraw allowed only if num_transaction is less than 6 AND balance is above minimum_balance + if @num_transaction < 6 && @balance >= minimum_balance + # Withdraw_amount will cause balance to go below minimum_balance + if @balance < withdraw_amount + minimum_balance + penalty_fee = 10000 + end + @balance -= (withdraw_amount + penalty_fee) + @num_transaction += 1 + end + return @balance + end + + # Method that handles interest + def add_interest(rate) + super(rate) + end + + # Method that handles deposits + def deposit(money_amount) + # Negative deposit amount, invalid + if money_amount < 0 + raise ArgumentError.new "Deposit amount cannot be a negetive value" + elsif @num_transaction < 6 + if @balance >= 1000000 + @num_transaction += 1 + end + @balance += money_amount + end + return @balance + end + + # Resets the number of checks used to zero + def reset_transactions() + if @new_month + if @num_transaction == 0 + puts "You haven't made any transactions yet." + else + @num_transaction = 0 + end + @new_month = false + end + end + end +end diff --git a/lib/owner.rb b/lib/owner.rb new file mode 100644 index 00000000..a38eca44 --- /dev/null +++ b/lib/owner.rb @@ -0,0 +1,67 @@ +module Bank + class Owner + attr_reader :id + attr_accessor :last_name, :first_name, :street_address, :city, :state + + def initialize owner_hash = {} + # Assumes that the parameter value is either properly formatted hash or an empty hash + if owner_hash != {} + [:id, :last_name, :first_name, :street_address, :city, :state].each do |expected_key| + if !owner_hash.has_key?(expected_key) + raise ArgumentError.new "Hey you are missing #{expected_key} information for the owner!" + end + end + @id = owner_hash[:id] + @first_name = owner_hash[:first_name] + @last_name = owner_hash[:last_name] + @street_address = owner_hash[:street_address] + @city = owner_hash[:city] + @state = owner_hash[:state] + else + @id = 0 + end + end + + # Method that returns a collection of Owner instances, from data read in CSV + def self.all + all_owners_array= [] + + CSV.read("support/owners.csv").each do |line| + all_owners_array << Bank::Owner.new( + { + id: line[0].to_i, + last_name: line[1], + first_name: line[2], + street_address: line[3], + city: line[4], + state: line[5] + } + ) + end + + return all_owners_array + end + + # Method that returns an instance of an Owner where the value of the id field in the CSV matches the passed parameter + def self.find(id) + raise ArgumentError.new ("Account id must be an positive integer value") if ( id.class != Integer || id < 1 ) + + CSV.read("support/owners.csv").each do |line| + if line[0].to_i == id + owner = Bank::Owner.new( + { + id: line[0].to_i, + last_name: line[1], + first_name: line[2], + street_address: line[3], + city: line[4], + state: line[5] + } + ) + return owner + end + end + raise ArgumentError.new "Owner id does not exist in the database" + end + end +end diff --git a/lib/savings_account.rb b/lib/savings_account.rb new file mode 100644 index 00000000..fbf75385 --- /dev/null +++ b/lib/savings_account.rb @@ -0,0 +1,41 @@ +require 'csv' +require_relative 'account' + +module Bank + class SavingsAccount < Bank::Account + + def initialize(id, balance, open_date) + raise ArgumentError.new("Your initial balance must be at least $10.00") if balance < 1000 + super(id, balance, open_date) + end + + # Method that handles withdraw + def withdraw(withdraw_amount) + # Raise error for non integer withdraw value + raise ArgumentError.new ("Withdraw amount must be a positive numerical value") if ( !(withdraw_amount.class == Integer || withdraw_amount.class == Float) || withdraw_amount < 0 ) + # Raises error for negativd withdraw value + raise ArgumentError.new("Withdraw amount cannot be a negetive value") if withdraw_amount < 0 + + # Error handling for insufficient funds for a withdraw + transaction_fee = 200 + minimum_balance = 1000 + + # Balance is insufficient + if @balance <= (withdraw_amount + minimum_balance + transaction_fee) + puts "The amount you enetered for the withdraw will cause your balance to go below the $10.00 minimum balance required" + # Allows withdraw, update @balance + else + @balance -= (withdraw_amount + transaction_fee) + end + return @balance + end + + # Method that handles interest + def add_interest(rate) + raise ArgumentError.new("The interest rate must be a positive numerical value") if rate <= 0 + interest = @balance * rate + @balance += interest + return interest + end + end +end diff --git a/specs/account_spec.rb b/specs/account_spec.rb index 6c399139..570699d0 100644 --- a/specs/account_spec.rb +++ b/specs/account_spec.rb @@ -2,42 +2,46 @@ require 'minitest/reporters' require 'minitest/skip_dsl' require_relative '../lib/account' +require_relative '../lib/owner' describe "Wave 1" do describe "Account#initialize" do + # Checks for instance variables it "Takes an ID and an initial balance" do id = 1337 balance = 100.0 - account = Bank::Account.new(id, balance) + open_date = "1999-03-27 11:30:09 -0800" + account = Bank::Account.new(id, balance, open_date) account.must_respond_to :id account.id.must_equal id account.must_respond_to :balance account.balance.must_equal balance + + account.must_respond_to :open_date + account.open_date.must_equal DateTime.parse(open_date) end + # Checks for erroneous values used for instance variables 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 - # 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 describe "Account#withdraw" do + # Updates the balance, given there are no conflicts 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) @@ -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) @@ -56,44 +60,40 @@ updated_balance.must_equal expected_balance end + # Outputs a warning message 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 - # 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 + # Both the value returned and the balance in the account must be un-modified. 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) - - # 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 + # User can withdraw all of the money in the account 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 end + # Checks for erroneous amount inout 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) @@ -102,70 +102,286 @@ end describe "Account#deposit" do + # Updates the balance, given there are no conflicts 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") + prev_balance = account.balance account.deposit(deposit_amount) - - expected_balance = start_balance + deposit_amount - account.balance.must_equal expected_balance + (prev_balance <= account.balance).must_equal true end + # Method returns te balance 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) - expected_balance = start_balance + deposit_amount updated_balance.must_equal expected_balance end + # Checks for erroneous amount inout 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) }.must_raise ArgumentError end end + + describe "Owner#added property to Account" do + # Handles missing owner parameter at initialization. + it "Initializes account without owner property" do + id = 1337 + balance = 100.0 + account = Bank::Account.new(id, balance, "1999-03-27 11:30:09 -0800") + + account.must_respond_to :owner + account.owner.class.must_equal Bank::Owner + account.owner.id.must_equal 0 + end + + # Handles incomplete or erroneous owner_hash + it "Raise an error if the owner_hash is missing a key" do + owner_hash = { + id: 1024, + last_name: "smith", + street_address: "123 main street", + city: "seattle", + state: "WA" + } + proc { + Bank::Owner.new(owner_hash) + }.must_raise ArgumentError + end + + # Initializes using the passed instance of the Owner class + it "Initializes account with owner property" do + id = 1337 + balance = 100.0 + open_date = "1999-03-27 11:30:09 -0800" + owner_hash = { + id: 1024, + first_name: "ginny", + last_name: "smith", + street_address: "123 main street", + city: "seattle", + state: "WA" + } + owner = Bank::Owner.new(owner_hash) + account = Bank::Account.new(id, balance, open_date, owner) + + account.must_respond_to :owner + account.owner.class.must_equal Bank::Owner + end + + # Adds owner property to accounts without existing owner info + it "Only accounts without initial owner property can be updated" do + owner_hash = { + id: 10, + first_name: "ginny", + last_name: "smith", + street_address: "123 main street", + city: "seattle", + state: "WA" + } + + test_hash = { + id: 9, + first_name: "fran", + last_name: "swan", + street_address: "456 grand street", + city: "columbus", + state: "OH" + } + + account_nil = Bank::Account.new(12345, 12, "1999-03-27 11:30:09 -0800") + account = Bank::Account.new(12346, 0, "1999-03-27 11:30:09 -0800", Bank::Owner.new(test_hash)) + + account_nil.update_owner_data(owner_hash) + account.update_owner_data(owner_hash) + + account_nil.owner.id.must_equal 10 + account_nil.owner.first_name.must_equal "ginny" + account_nil.owner.last_name.must_equal "smith" + account_nil.owner.street_address.must_equal "123 main street" + account_nil.owner.city.must_equal "seattle" + account_nil.owner.state.must_equal "WA" + + account.owner.id.must_equal 9 + account.owner.first_name.must_equal "fran" + account.owner.last_name.must_equal "swan" + account.owner.street_address.must_equal "456 grand street" + account.owner.city.must_equal "columbus" + account.owner.state.must_equal "OH" + end + end end -# 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! - # 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 + # Everything in the array is an Account + all_array = Bank::Account.all + + all_array.each do |account| + account.class.must_equal Bank::Account + end + + # The number of accounts is correct + all_array.length.must_equal CSV.read("support/accounts.csv").length + + # the ID and balance of the first and last accounts match what's in the CSV file + all_array[0].id.must_equal 1212 + all_array[0].balance.must_equal 1235667 + all_array[0].open_date.must_equal DateTime.parse("1999-03-27 11:30:09 -0800") + all_array[-1].id.must_equal 15156 + all_array[-1].balance.must_equal 4356772 + all_array[-1].open_date.must_equal DateTime.parse("1994-11-17 14:04:56 -0800") end - end - describe "Account.find" do - it "Returns an account that exists" do - # TODO: Your test code here! + + describe "Account.find" do + it "Returns an account that exists" do + account = Bank::Account.find(1213) + account.id.must_equal 1213 + account.balance.must_equal 66367 + account.open_date.must_equal DateTime.parse("2010-12-21 12:21:12 -0800") + end + + it "Can find the first account from the CSV" do + account = Bank::Account.find(1212) + account.id.must_equal 1212 + account.balance.must_equal 1235667 + account.open_date.must_equal DateTime.parse("1999-03-27 11:30:09 -0800") + end + + it "Can find the last account from the CSV" do + account = Bank::Account.find(15156) + account.id.must_equal 15156 + account.balance.must_equal 4356772 + account.open_date.must_equal DateTime.parse("1994-11-17 14:04:56 -0800") + end + + it "Raises an error for an account that doesn't exist" do + proc { + Bank::Account.find(100233332223003) + }.must_raise ArgumentError + end + + it "Raises an error for an invalid input data type" do + proc { + Bank::Account.find(0) + }.must_raise ArgumentError + proc { + Bank::Account.find(-1233) + }.must_raise ArgumentError + proc { + Bank::Account.find("happy dog") + }.must_raise ArgumentError + end end - it "Can find the first account from the CSV" do - # TODO: Your test code here! + describe "Owner.all" do + it "Returns an array of all owners" do + # Everything in the array is an Owner + all_array = Bank::Owner.all + all_array.class.must_equal Array + + all_array.each do |owner| + owner.class.must_equal Bank::Owner + end + + # The number of accounts is correct + all_array.length.must_equal CSV.read("support/owners.csv").length + + # The ID, last_name, first_name, street_address, city, state of the first and last accounts match what's in the CSV file + all_array[0].id.must_equal 14 + all_array[0].last_name.must_equal "Morales" + all_array[0].first_name.must_equal "Wanda" + all_array[0].street_address.must_equal "9003 Gerald Hill" + all_array[0].city.must_equal "Honolulu" + all_array[0].state.must_equal "Hawaii" + + all_array[-1].id.must_equal 25 + all_array[-1].last_name.must_equal "Clark" + all_array[-1].first_name.must_equal "Kathleen" + all_array[-1].street_address.must_equal "72984 Chive Hill" + all_array[-1].city.must_equal "New York City" + all_array[-1].state.must_equal "New York" + end end - it "Can find the last account from the CSV" do - # TODO: Your test code here! + describe "Owner.find" do + it "Returns an owner that exists" do + owner = Bank::Owner.find(18) + owner.id.must_equal 18 + owner.last_name.must_equal "Gonzalez" + owner.first_name.must_equal "Laura" + owner.street_address.must_equal "310 Hauk Street" + owner.city.must_equal "Springfield" + owner.state.must_equal "Illinois" + end + + it "Can find the first owner from the CSV" do + owner = Bank::Owner.find(14) + owner.id.must_equal 14 + owner.last_name.must_equal "Morales" + owner.first_name.must_equal "Wanda" + owner.street_address.must_equal "9003 Gerald Hill" + owner.city.must_equal "Honolulu" + owner.state.must_equal "Hawaii" + end + + it "Can find the last account from the CSV" do + owner = Bank::Owner.find(25) + owner.id.must_equal 25 + owner.last_name.must_equal "Clark" + owner.first_name.must_equal "Kathleen" + owner.street_address.must_equal "72984 Chive Hill" + owner.city.must_equal "New York City" + owner.state.must_equal "New York" + end + + it "Raises an error for an owner that doesn't exist" do + proc { + Bank::Owner.find(100233332223003) + }.must_raise ArgumentError + end + + it "Raises an error for an invalid input data type" do + proc { + Bank::Owner.find(0) + }.must_raise ArgumentError + proc { + Bank::Owner.find(-1233) + }.must_raise ArgumentError + proc { + Bank::Owner.find("happy dog") + }.must_raise ArgumentError + end end - it "Raises an error for an account that doesn't exist" do - # TODO: Your test code here! + describe "Use account_owners.csv to create owner property for existing " do + it "Makes account instance when account.id and owner.id pair doesn not exist within csv file" do + account = Bank::Account.new(1223222337, 0, "1999-03-27 11:30:09 -0800") + account.owner.id.must_equal 0 + owner_hash = { + id: 1000000, + first_name: "ginny", + last_name: "smith", + street_address: "123 main street", + city: "seattle", + state: "WA" + } + account = Bank::Account.new(1223222337, 0, "1999-03-27 11:30:09 -0800", Bank::Owner.new(owner_hash)) + account.owner.id.must_equal 1000000 + end end end end diff --git a/specs/checking_account_spec.rb b/specs/checking_account_spec.rb index 7f95339e..85eddbff 100644 --- a/specs/checking_account_spec.rb +++ b/specs/checking_account_spec.rb @@ -1,80 +1,144 @@ require 'minitest/autorun' require 'minitest/reporters' require 'minitest/skip_dsl' +require_relative '../lib/checking_account' -# TODO: uncomment the next line once you start wave 3 and add lib/checking_account.rb -# 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 - account = Bank::CheckingAccount.new(12345, 100.0) + account = Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800") account.must_be_kind_of Bank::Account + account.must_respond_to :num_checks_used + account.num_checks_used.must_equal 0 + account.must_respond_to :new_month + account.new_month.must_equal false + end + + # Checks for instance variables + it "Initial value for instance variable are set" do + account = Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800") + account.must_respond_to :num_checks_used + account.num_checks_used.must_equal 0 + account.must_respond_to :new_month + account.new_month.must_equal false end end + # Decreases balance in decreased by the withdrawal amount, including $1 fee describe "#withdraw" do it "Applies a $1 fee each time" do - # TODO: Your test code here! + Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").withdraw(100).must_equal 9800 end + # Balance does not change, returns amount it "Doesn't modify the balance if the fee would put it negative" do - # TODO: Your test code here! + proc { + Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").withdraw(10100) + }.must_output (/.+/) + end + + # Balance does not change, returns amount + it "Doesn't modify the balance if the fee would put it below $0.00" do + Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").withdraw(100000).must_equal 10000 end end describe "#withdraw_using_check" do + # Withdraw the amount entered, if theres no conflict it "Reduces the balance" do - # TODO: Your test code here! + account =Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800") + account.withdraw_using_check(1000) + account.balance.must_equal 8900 end + # Checks that the method returns the updated balance it "Returns the modified balance" do - # TODO: Your test code here! + Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").withdraw_using_check(100).must_equal 9800 end + # Checks that user can overdraft upto -$10.00, when using withdraw_using_check it "Allows the balance to go down to -$10" do - # TODO: Your test code here! + Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").withdraw_using_check(10900).must_equal (-1000) end + # Outputs an error message when the account will be overdraft by more than $10.00 it "Outputs a warning if the account would go below -$10" do - # TODO: Your test code here! + proc { + Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").withdraw_using_check(11000) + }.must_output (/.+/) end + # Checks that the method returns an unchanged balance. it "Doesn't modify the balance if the account would go below -$10" do - # TODO: Your test code here! + account = Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800") + account.withdraw_using_check(11000) + account.balance.must_equal (10000) end + # Checks that a negative check amount will raise an error. it "Requires a positive withdrawal amount" do - # TODO: Your test code here! + account = Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800") + proc { + account.withdraw_using_check(-1000) + }.must_raise ArgumentError end + # Account owner gets 3 free checks per month it "Allows 3 free uses" do # TODO: Your test code here! + account = Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800") + 3.times do + account.withdraw_using_check(1000) + end + account.balance.must_equal (6700) end - it "Applies a $2 fee after the third use" do + # Account owner is charged $2.00 fee for + it "Applies a $2 fee after the third check" do # TODO: Your test code here! + account = Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800") + 4.times do + account.withdraw_using_check(1000) + end + account.balance.must_equal (5400) end end describe "#reset_checks" do + # Calls the method without error it "Can be called without error" do # TODO: Your test code here! + account = Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800") + 3.times do + account.withdraw_using_check(1000) + end + account.new_month = true + account.reset_checks + account.withdraw_using_check(1000) + account.balance.must_equal (5600) end + # Resets used check count to 0 it "Makes the next three checks free if less than 3 checks had been used" do - # TODO: Your test code here! + account = Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800") + account.withdraw_using_check(1000) + account.new_month = true + account.reset_checks + account.withdraw_using_check(1000) + account.balance.must_equal (7800) end + # Resets used check count to 0 it "Makes the next three checks free if more than 3 checks had been used" do # TODO: Your test code here! + account = Bank::CheckingAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800") + 5.times do + account.withdraw_using_check(1000) + end + account.new_month = true + account.reset_checks + account.num_checks_used.must_equal 0 end end end diff --git a/specs/money_market_account_spec.rb b/specs/money_market_account_spec.rb new file mode 100644 index 00000000..e68e638f --- /dev/null +++ b/specs/money_market_account_spec.rb @@ -0,0 +1,169 @@ +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/skip_dsl' +require_relative '../lib/money_market_account' + +describe "MoneyMarketAccount" do + describe "#initialize" do + # Check that a MoneyMarketAccount is in fact a kind of account + it "Is a kind of SavingsAccount" do + account = Bank::MoneyMarketAccount.new(12345, 1000000, "1999-03-27 11:30:09 -0800") + account.must_be_kind_of Bank::SavingsAccount + end + + # Checks for instance variables + it "Initial value for instance variable are set" do + account = Bank::MoneyMarketAccount.new(12345, 1000000, "1999-03-27 11:30:09 -0800") + account.must_respond_to :num_transaction + account.num_transaction.must_equal 0 + account.must_respond_to :new_month + account.new_month.must_equal false + end + + # Raises an error when attemted to initialize MoneyMarketAccount with initial balance less than $10,000 + it "Invalid initial balance" do + proc { + Bank::MoneyMarketAccount.new(12345, 900000, "1999-03-27 11:30:09 -0800") + }.must_raise ArgumentError + end + end + + describe "#withdraw" do + # Raises error when an erroneous withdrawal amount is entered + it "Requires a positive withdrawal amount" do + account = Bank::MoneyMarketAccount.new(12345, 1000000, "1999-03-27 11:30:09 -0800") + proc { + account.withdraw(-1000) + }.must_raise ArgumentError + end + + # Withdraw method will reduce accout balance, if there are no conflicts + it "Reduces the balance" do + account =Bank::MoneyMarketAccount.new(12345, 1000000, "1999-03-27 11:30:09 -0800") + account.withdraw(100000) + account.balance.must_equal 890000 + end + + # If a withdrawal causes the balance to go below $10,000, a fee of $100 is imposed + it "Applies a $100 fee when withdrawal causes the balance to go below $10,000" do + account = Bank::MoneyMarketAccount.new(12345, 2000000, "1999-03-27 11:30:09 -0800") + account.withdraw(1500000) + account.balance.must_equal 490000 + end + + # If the balance is below $10,000, balance does not change + it "Doesn't modify balance if the withdrawal causes the balance to be less than $10,000.00" do + account = Bank::MoneyMarketAccount.new(12345, 2000000, "1999-03-27 11:30:09 -0800") + account.withdraw(1100000) + account.withdraw(10000).must_equal 890000 + end + + # With each withdrawal, the num_transaction count goes up by 1 + it "Each withdraw transaction will be counted against the maximum number of transactions" do + account = Bank::MoneyMarketAccount.new(12345, 2000000, "1999-03-27 11:30:09 -0800") + account.withdraw(1100) + account.withdraw(1100) + account.num_transaction.must_equal 2 + end + + # Transaction is not allowed when the num_transaction is greater than equal to 6 + it "Doesn't modify the balance if the num_transaction is greater than equal to 6" do + account = Bank::MoneyMarketAccount.new(12345, 2000000, "1999-03-27 11:30:09 -0800") + 6.times do + account.withdraw(0) + end + account.withdraw(11000).must_equal 2000000 + end + end + + describe "#deposit" do + # Raises error when an erroneous deposit amount is entered + it "Requires a positive deposit amount" do + account = Bank::MoneyMarketAccount.new(12345, 1000000, "1999-03-27 11:30:09 -0800") + proc { + account.deposit(-1000) + }.must_raise ArgumentError + end + + # Deposit method will increase accout balance, if there are no conflicts + it "Increase the balance" do + account =Bank::MoneyMarketAccount.new(12345, 1000000, "1999-03-27 11:30:09 -0800") + account.deposit(1000) + account.balance.must_equal 1001000 + end + + # If a deposit causes the balance to be greater than equal to $10,000, a fee of $100 is removed + it "Removes $100 fee when deposit causes the balance to be greater than equal to $10,000" do + account = Bank::MoneyMarketAccount.new(12345, 2000000, "1999-03-27 11:30:09 -0800") + account.withdraw(1500000) + account.deposit(1510000) + account.withdraw(1000000).must_equal 1000000 + end + + # If a deposit causes the balance to be greater than equal to $10,000, that deposit does not add to num_transaction + it "Does not increase num_transaction, when deposit causes the balance to be greater than equal to $10,000" do + account = Bank::MoneyMarketAccount.new(12345, 2000000, "1999-03-27 11:30:09 -0800") + account.withdraw(1100000) + account.deposit(1100000) + account.num_transaction.must_equal 1 + end + + # With each deposit, the num_transaction count goes up by 1 + it "Each deposit transaction will be counted against the maximum number of transactions" do + account = Bank::MoneyMarketAccount.new(12345, 2000000, "1999-03-27 11:30:09 -0800") + 2.times do + account.deposit(1100) + end + account.num_transaction.must_equal 2 + end + + # Transaction is not allowed when the num_transaction is greater than equal to 6 + it "Doesn't modify the balance if the num_transaction is greater than equal to 6" do + account = Bank::MoneyMarketAccount.new(12345, 2000000, "1999-03-27 11:30:09 -0800") + account.num_transaction = 10 + account.deposit(1100000).must_equal 2000000 + end + end + + describe "#add_interest" do + # Only the actual interest amount added is returned + it "Returns the interest calculated" do + account = Bank::MoneyMarketAccount.new(12345, 1000000, "1999-03-27 11:30:09 -0800") + account.add_interest(0.25).must_equal 250000 + end + # Balance is updated + it "Updates the balance with calculated interest" do + account = Bank::MoneyMarketAccount.new(12345, 1000000, "1999-03-27 11:30:09 -0800") + account.add_interest(0.25) + account.balance.must_equal 1250000 + end + # Checks against erroneous rate value inputs + it "Requires a positive rate" do + proc { + Bank::MoneyMarketAccount.new(12345, 1000000, "1999-03-27 11:30:09 -0800").add_interest(-0.32) + }.must_raise ArgumentError + end + end + + describe "#reset_transactions" do + # Resets the number of transactions to zero + it "Resets the num_transaction to 0" do + account = Bank::MoneyMarketAccount.new(12345, 1000000, "1999-03-27 11:30:09 -0800") + 5.times do + account.withdraw(1000) + end + account.new_month = true + account.reset_transactions + account.num_transaction.must_equal 0 + end + + # When the num_transaction is zero, calling this method outputs a message + it "Outputs a message when the num_transaction is already 0" do + account = Bank::MoneyMarketAccount.new(12345, 1000000, "1999-03-27 11:30:09 -0800") + account.new_month = true + proc { + account.reset_transactions + }.must_output (/.+/) + end + end +end diff --git a/specs/savings_account_spec.rb b/specs/savings_account_spec.rb index 3f4d1e4a..a76e0ca2 100644 --- a/specs/savings_account_spec.rb +++ b/specs/savings_account_spec.rb @@ -1,58 +1,65 @@ 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 + # Check that a SavingsAccount is in fact a kind of account it "Is a kind of Account" do - # Check that a SavingsAccount is in fact a kind of account - account = Bank::SavingsAccount.new(12345, 100.0) - account.must_be_kind_of Bank::Account + Bank::SavingsAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").must_be_kind_of Bank::Account end - it "Requires an initial balance of at least $10" do - # TODO: Your test code here! + # Check that the initial balance is at least $10.00 + it "Requires an initial balance of at least $10, raises error otherwise" do + proc { + Bank::SavingsAccount.new(12345, 100, "1999-03-27 11:30:09 -0800") + }.must_raise ArgumentError end end describe "#withdraw" do + # Decreases balance in decreased by the withdrawal amount, including $2 fee it "Applies a $2 fee each time" do - # TODO: Your test code here! + Bank::SavingsAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").withdraw(100).must_equal 9700 end + # Outputs a message warning the user it "Outputs a warning if the balance would go below $10" do - # TODO: Your test code here! + proc { + Bank::SavingsAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").withdraw(9500) + }.must_output (/.+/) end + # Withdrawal amonut causes balance to go below $10 it "Doesn't modify the balance if it would go below $10" do - # TODO: Your test code here! + Bank::SavingsAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").withdraw(9100).must_equal 10000 end + # Withdrawal amonut and the fee causes balance to go below $10 it "Doesn't modify the balance if the fee would put it below $10" do - # TODO: Your test code here! + Bank::SavingsAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").withdraw(9000).must_equal 10000 end end describe "#add_interest" do + # Returns the actual interest amount it "Returns the interest calculated" do - # TODO: Your test code here! + Bank::SavingsAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").add_interest(0.25).must_equal 2500 end + # Checks that the balance is updated it "Updates the balance with calculated interest" do - # TODO: Your test code here! + account = Bank::SavingsAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800") + account.add_interest(0.25) + account.balance.must_equal 12500 end + # Checks that the rate passed is valid data type it "Requires a positive rate" do - # TODO: Your test code here! + proc { + Bank::SavingsAccount.new(12345, 10000, "1999-03-27 11:30:09 -0800").add_interest(-0.32) + }.must_raise ArgumentError end end end