diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..f4f704fca --- /dev/null +++ b/Rakefile @@ -0,0 +1,9 @@ +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.libs = ["lib"] + t.warning = false + t.test_files = FileList['specs/*_spec.rb'] +end + +task default: :test diff --git a/design-activity.md b/design-activity.md new file mode 100644 index 000000000..d91d8cdb3 --- /dev/null +++ b/design-activity.md @@ -0,0 +1,74 @@ +__Hotel Design Changes Made__ +I refactored my Hotel program so that all logic and responsibility for reserving a room in a block was in the Block Class instead of the Room class. This is an improvement because Blocks are a special class that have specific rooms, from which a guest can select to create a Block reservation. Room instances do not need to know if they are in a Block, but a Block must know what Rooms it includes, and which are available for booking. Rooms in a Block have special conditions under which they can be reserved, so it makes more sense to have the responsibility and logic to reserve rooms in a block reside in the more specific Block class rather than the general Room class. + + + +1. What classes does each implementation include? Are the lists the same? + +Each of the implementations has three classes: CartEntry, ShoppingCart, and Order. The lists are the same. + + +2. Write down a sentence to describe each class. + +CartEntry seems to be any item/purchase you want to put in your cart, and must have a unit price and quantity. A ShoppingCart holds zero or more CartEntries in an array. Orders have a Shopping Cart, and calculate the total price (including Sales Tax) of all of the Cart Entries in the Cart. + +3. How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper. +Orders have a ShoppingCart which can hold zero or more CartEntries. + +4. What data does each class store? How (if at all) does this differ between the two implementations? + +__A__ +Cart Entry: @unit_price & @quantity instance variables +ShoppingCart: @entries array +Order: SALES_TAX constant, @cart variable that is an instance of ShoppingCart. + +__B__ +Cart Entry: @unit_price and @quantity instance variables +ShoppingCart: @entries array +Order: Constant SALES_TAX, @cart variable that is an instance of ShoppingCart + + +5. What methods does each class have? How (if at all) does this differ between the two implementations? + +__A__ +CartEntry: Initialize method, accessors for @unit_price and @quantity +ShoppingCart: Initialize method, accessor for @entries +Order: Initialize method, total_price method that calculates the sum of the prices of each entry in the @cart, and returns the total_price including SALEX_TAX. + +__B__ +CartEntry: Initialize method, price method that returns the price of each CartEntry +ShoppingCart: Initialize method, price method that returns the sum of the prices of each entry in the @cart. +Order: Initialize method, total_price method that returns the total price, including sales tax, of all of the items in the cart. + + +6. Consider the Order#total_price method. In each implementation: + + Is logic to compute the price delegated to "lower level" classes like ShoppingCart and CartEntry, or is it retained in Order? + + __A__ + The logic to compute the price is retained in Order. + + __B__ + The logic to compute the price is delegated to "lower level" classes like ShoppingCart and CartEntry. + + Does total_price directly manipulate the instance variables of other classes? + + __A__ + If I'm reading the question correctly, total_price directly manipulates instance variables of other classes in implementation A. It must access the entries array of the @cart instance, then iterate over each CartEntry instance to access the unit_price and quantity of each to calculate the price, sum up the prices of each CartEntry instance, then add the SALES_TAX to get the total_price. + + __B__ + No; Implementation B calls the .price method on the @cart, then adds the SALES_TAX to calculate the total_price. + +7. If we decide items are cheaper if bought in bulk, how would this change the code? + +We would have to add logic for the discounted bulk price (e.g. a lower unit_price or some kind of discount that is applied) if someone places a bulk order. We would also have to determine how a bulk order is placed, whether it's a subclass, or if we just add conditionals to our existing + +8. Which implementation is easier to modify? + +Implementation B- classes better follow single responsibility principle and logic is delegated to "low level" classes, and we can better target only the relevant classes and methods for modification without fear of messing up some other code. + +9. Which implementation better adheres to the single responsibility principle? + +Implementation B + +10. Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? diff --git a/lib/Block.rb b/lib/Block.rb new file mode 100644 index 000000000..efb7bfbfd --- /dev/null +++ b/lib/Block.rb @@ -0,0 +1,25 @@ + +module HotelBooking + class Block + attr_accessor :id, :guest, :check_in, :check_out, :room_ids, :available_rooms + attr_reader :discounted_rate + + def initialize(check_in,check_out,room_ids,discounted_rate,block_id) + @check_in = check_in #ruby Date object + @check_out = check_out #ruby Date object + @room_ids = room_ids + @available_rooms = room_ids.dup + @discounted_rate = discounted_rate + @id = block_id + end + + def reserve_block_room(room_id) + raise ArgumentError.new("This Block room is not available for this block reservation") if !(@available_rooms.include?(room_id)) + + @available_rooms.delete(room_id) + end + + + end + +end diff --git a/lib/BlockReservation.rb b/lib/BlockReservation.rb new file mode 100644 index 000000000..ae45d87f8 --- /dev/null +++ b/lib/BlockReservation.rb @@ -0,0 +1,19 @@ +require_relative 'Reservation' + +module HotelBooking + class BlockReservation < HotelBooking::Reservation + attr_accessor :id, :guest, :check_in, :check_out, :room, :block_id + attr_reader :all_reservations, :type + + def initialize(check_in,check_out,room_id, b_res_id, block_discount, guest = nil) + super(check_in,check_out,room_id, b_res_id,block_discount, guest = nil) + @rate = block_discount + @block_id = nil + @type= :block + end #end initialize + + def cost + num_nights_charged * @rate + end + end +end diff --git a/lib/Booking.rb b/lib/Booking.rb new file mode 100644 index 000000000..172d299f8 --- /dev/null +++ b/lib/Booking.rb @@ -0,0 +1,150 @@ + +require 'date' +require_relative 'Reservation' +require_relative 'Room' +require_relative 'Block' +module HotelBooking + + class Hotel + + #The Hotel class holds the data of all rooms, all reservations, and all blocks in the Hotel. It checks for valid dates before creating new reservations, block reservations, and blocks. + attr_reader :all_rooms, :all_reservations, :all_blocks + NUM_STANDARD_ROOMS = 20 + + def initialize + @all_rooms = HotelBooking::Hotel.setup_rooms + @all_reservations = [] + @all_blocks = [] + end + + def available_rooms(check_in,check_out, block_id = nil) + check_valid_dates(check_in,check_out) + @all_rooms.select {|room| room.available_all_days?(check_in, check_out)} + end + + def make_block(check_in,check_out,room_ids,discounted_rate) + check_in_date = Date.parse(check_in) + check_out_date = Date.parse(check_out) + + + #checks valid dates + check_valid_dates(check_in_date,check_out_date) + + #makes sure all rooms intended for the block are available for the date range provided + check_valid_block(check_in_date,check_out_date,room_ids) + + block_id = "B" + "#{@all_blocks.count + 1}" + + block = HotelBooking::Block.new(check_in_date,check_out_date,room_ids,discounted_rate,block_id) + + room_ids.each do |room_id| + room= find_room_by_id(room_id) + room.block_room(check_in_date,check_out_date,block_id) + end + + @all_blocks << block + + end + + def make_reservation(check_in,check_out,room_id, guest_id=nil) + + reservation_id = (@all_reservations.count + 1) + room= find_room_by_id(room_id) + check_in_date = Date.parse(check_in) + check_out_date = Date.parse(check_out) + + check_valid_dates(check_in_date,check_out_date) + + if available_rooms(check_in_date,check_out_date).include?(room) + + reservation = HotelBooking::Reservation.new(check_in_date,check_out_date,room_id, reservation_id) + + room.reserve_room(check_in_date,check_out_date,reservation_id, guest_id) + + @all_reservations << reservation + else + raise ArgumentError.new("This room is already reserved for these dates") + end + + end + + def make_block_reservation(block_id,room_id,guest_id = nil) + block= find_block_by_id(block_id) + reservation_id = "B" + (@all_reservations.count + 1).to_s + + raise ArgumentError.new("This room is not in the block") if !(block.room_ids.include?(room_id)) + raise ArgumentError.new("This Block room has already been reserved") if !(block.available_rooms.include?(room_id)) + + block_reservation = HotelBooking::BlockReservation.new(block.check_in,block.check_out,room_id, reservation_id, block.discounted_rate) + block_reservation.block_id = block_id + + block.reserve_block_room(room_id) + + @all_reservations << block_reservation + + end + + def find_room_by_id(room_id) + @all_rooms.each {|room| return room if room.id == room_id} + + raise ArgumentError.new "Sorry, we don't have a room matching that ID number." + end + + def find_res_by_date(date_str) + date_object= Date.parse(date_str) + @all_reservations.select {|reservation| ((reservation.check_in)..(reservation.check_out)).include?(date_object)} + end + + def find_block_by_id(block_id) + + @all_blocks.each {|block| return block if block.id == block_id} + raise ArgumentError.new "Sorry, we don't have a block matching that ID number." + end + + def find_available_rooms_by_block(block_id) + block= find_block_by_id(block_id) + block.available_rooms + end + + def check_valid_block(check_in,check_out,room_ids) + raise ArgumentError.new("Number of rooms in a block must be 5 or under") if room_ids.count > 5 + + available_rooms_ids = available_rooms(check_in,check_out).map {|room| room.id} + + room_ids.each do |room_id| + raise ArgumentError.new("This room is already reserved for the dates provided") if !(available_rooms_ids.include?(room_id)) + end + + return true + + end + + def check_valid_dates(check_in, check_out) + if check_in < Date.today || check_out < Date.today + raise ArgumentError.new("Can't make reservations for days earlier than today") + end + + if check_in.class != Date ||check_out.class != Date + raise ArgumentError.new("Please provide a valid date") + end + + if check_out < check_in + raise ArgumentError.new("Invalid Date Range: Check out date is earlier than check-in date.") + end + + end + + def self.setup_rooms + standard_rooms = [] + + (1..NUM_STANDARD_ROOMS).each do |num| + room = HotelBooking::Room.new(num) + standard_rooms << room + end + + return standard_rooms + end + + end + +end diff --git a/lib/Guest.rb b/lib/Guest.rb new file mode 100644 index 000000000..713db0698 --- /dev/null +++ b/lib/Guest.rb @@ -0,0 +1,7 @@ +### OPTIONAL CLASS + +module Hotel + class Guest + + end +end diff --git a/lib/Reservation.rb b/lib/Reservation.rb new file mode 100644 index 000000000..263dd2144 --- /dev/null +++ b/lib/Reservation.rb @@ -0,0 +1,28 @@ +require 'date' +module HotelBooking + + class Reservation + attr_accessor :id, :guest, :check_in, :check_out, :room_id + attr_reader :all_reservations, :type, :rate + + def initialize(check_in,check_out,room_id, res_id, rate = 200, guest = nil) + @id = res_id + @check_in = check_in #ruby Date object + @check_out = check_out #ruby Date object + @room_id= room_id + @guest = guest + @rate = rate + @type= :standard + end #end initialize + + def cost + num_nights_charged * @rate + end + + def num_nights_charged + (check_out.mjd - check_in.mjd) + end + + end + +end diff --git a/lib/Room.rb b/lib/Room.rb new file mode 100644 index 000000000..f45542590 --- /dev/null +++ b/lib/Room.rb @@ -0,0 +1,49 @@ +require 'date' + +module HotelBooking + + class Room + attr_reader :id, :nightly_rate, :type, :reserv_ids, :all_dates, :block_ids, :blocks_available + + def initialize(id_number, nightly_rate = 200) + @id = id_number + @nightly_rate = nightly_rate + @type = :standard + @reserv_ids = [] + @block_ids = [] + @all_dates = [] + @blocks_available = [] + end + + def reserve_room(check_in,check_out,reservation_id, guest_id=nil) + + (check_in...check_out).each do |date| + @all_dates << date + end + + @reserv_ids << reservation_id + end + + + def block_room(check_in,check_out,block_id) + if available_all_days?(check_in, check_out) + @blocks_available << block_id + + (check_in...check_out).each do |date| + @all_dates << date + end + end + + end + + def available_all_days?(check_in, check_out) + (check_in..check_out).each do |date| + return false if @all_dates.include?(date) + end + + return true + end + + end + +end diff --git a/specs/BlockReservation_spec.rb b/specs/BlockReservation_spec.rb new file mode 100644 index 000000000..cb50089b5 --- /dev/null +++ b/specs/BlockReservation_spec.rb @@ -0,0 +1,44 @@ +require 'date' + +require_relative 'spec_helper' + +describe "HotelBooking::BlockReservation class" do + describe "initialize" do + it "initalizes with the appropriate reservation type" do + check_in = Date.parse("2018-10-03") + check_out = Date.parse("2018-10-06") + room_id = 1 + b_res_id = 14 + discounted_rate = 5 + block_id = 42 + + new_block_res = HotelBooking::BlockReservation.new(check_in, check_out,room_id,b_res_id,discounted_rate, block_id) + + new_block_res.must_be_instance_of HotelBooking::BlockReservation + new_block_res.type.must_equal :block + + end + end + + describe "num_nights_charged" do + + it "correctly inherits the num_nights_charged method from the HotelBooking::Reservation class" do + blockres1 = HotelBooking::BlockReservation.new(Date.parse("2018-02-14"), Date.parse("2018-02-16"),3,14,5) + + blockres1.num_nights_charged.must_equal 2 + end + end + + describe "cost" do + it "calculates cost with a discounted rate" do + discounted_rate = 5 + blockres1 = HotelBooking::BlockReservation.new(Date.parse("2018-02-14"), Date.parse("2018-02-16"),14,42,discounted_rate) + blockres1.cost.must_equal 10 + + blockres2 = HotelBooking::BlockReservation.new(Date.parse("2018-12-01"), Date.parse("2018-12-02"),1,5,discounted_rate) + + blockres2.cost.must_equal 5 + end + end + +end diff --git a/specs/Block_spec.rb b/specs/Block_spec.rb new file mode 100644 index 000000000..78c9dc8dc --- /dev/null +++ b/specs/Block_spec.rb @@ -0,0 +1,66 @@ +require_relative 'spec_helper' + +describe "HotelBooking::Block class " do + describe "initialize" do + before do + @check_in_str = "2018-10-03" + @check_out_str = "2018-10-06" + @new_hotel = HotelBooking::Hotel.new + @room_ids= [1,2,3] + @block_id = "Amy's Party" + @discounted_rate = 5 + @new_block = HotelBooking::Block.new(Date.parse(@check_in_str), Date.parse(@check_out_str),@room_ids,@discounted_rate,@block_id) + end + + it "initalizes with attributes that we can access in our booking system" do + @new_block.must_be_instance_of HotelBooking::Block + + @new_block.id.must_equal @block_id + @new_block.check_in.to_s.must_equal @check_in_str + @new_block.check_out.to_s.must_equal @check_out_str + + end + + it "stores an array of room ids " do + @new_block.room_ids.must_be_instance_of Array + @new_block.room_ids.must_equal @room_ids + @new_block.room_ids.each do |id| + id.must_be_instance_of Integer + end + end + + end + + describe "reserve_block_room" do + it "can reserve a room in a given block if given the check-in/out date, reservation id, and block id" do + hotel = HotelBooking::Hotel.new + + rooms_in_block = [1,3] + + block_room_wanted = 3 + + check_in = "2018-08-09" + check_out = "2018-08-12" + discounted_rate = 10 + + hotel.make_block(check_in, check_out, rooms_in_block,discounted_rate) + + block1 = hotel.all_blocks[-1] + + hotel.all_blocks.count.must_equal 1 + block1.must_be_instance_of HotelBooking::Block + block1.id.must_equal "B1" + + + block1.reserve_block_room(block_room_wanted) + + block1.available_rooms.must_equal [1] + + # (block1.check_in...block1.check_out).each do |date| + # room.all_dates.must_include date + # end + + end + + end #end reserve_block_room +end diff --git a/specs/Booking_spec.rb b/specs/Booking_spec.rb new file mode 100644 index 000000000..8ae87b23a --- /dev/null +++ b/specs/Booking_spec.rb @@ -0,0 +1,303 @@ +require_relative 'spec_helper' + +describe "Hotel" do + describe "Initialize" do + it "initializes with 20 rooms, numbered 1 through 20 and I can can access the list of all rooms " do + new_hotel = HotelBooking::Hotel.new + + new_hotel.all_rooms.must_be_instance_of Array + new_hotel.all_rooms.each do |room| + room.must_be_instance_of HotelBooking::Room + end + + end + + end + + describe "find_res_by_date" do + it "Returns an array of Reservation objects" do + new_hotel = HotelBooking::Hotel.new + + new_hotel.make_reservation("2018-03-14", "2018-04-16", 3) + + new_hotel.make_reservation("2018-03-14", "2018-04-16", 5) + + new_hotel.make_reservation("2018-02-02", "2018-02-08", 18) + + new_hotel.make_reservation("2018-12-08", "2018-12-10", 7) + + new_hotel.make_reservation("2018-03-21", "2018-03-22", 15) + + + new_hotel.find_res_by_date("2018-03-21").must_be_instance_of Array + + new_hotel.find_res_by_date("2018-03-21").count.must_equal 3 + + end + end #end find_res_by_date + + describe "make_reservation" do + it "reserves a Room and makes a Reservation object " do + new_hotel = HotelBooking::Hotel.new + check_in ="2018-03-14" + check_out="2018-03-16" + + new_hotel.make_reservation(check_in, check_out, 3) + + new_reservation = new_hotel.all_reservations[0] + + + new_reservation.must_be_instance_of HotelBooking::Reservation + new_reservation.id.must_equal 1 + + new_res_room = new_hotel.find_room_by_id(new_reservation.room_id) + (Date.parse(check_in)...Date.parse(check_out)).each do |date| + new_res_room.all_dates.must_include date + end + + end + + end + + describe "make_block_reservation" do + it "makes a BlockReservation object if given a block id and room id" do + new_hotel = HotelBooking::Hotel.new + room_id = 3 + non_exist_block_id = "B2" + + rooms_in_block = [1,3,5] + + check_in = "2018-11-10" + check_out = "2018-11-12" + + proc {new_hotel.make_block_reservation(non_exist_block_id, room_id)}.must_raise ArgumentError + + new_hotel.make_block(check_in,check_out,rooms_in_block,10) + + new_hotel.all_blocks.count.must_equal 1 + + new_block = new_hotel.all_blocks[0] + block_id = new_block.id + + new_hotel.make_block_reservation(block_id,room_id) + + proc {new_hotel.make_block_reservation(block_id,room_id)}.must_raise ArgumentError + + new_block_reservation = new_hotel.all_reservations[-1] + new_block_reservation.block_id.must_equal "B1" + new_block_reservation.type.must_equal :block + end + + end + + describe "make_block" do + it "creates a Block and reserves a room" do + #note, need to fix: it shouldn't reserve room officially, but should be "Blocked off" test for this when the functionality is made + + new_hotel = HotelBooking::Hotel.new + + new_hotel.make_block("2018-03-14", "2018-03-16",[18,19,20], 2) + + new_block = new_hotel.all_blocks[0] + + + new_block.must_be_instance_of HotelBooking::Block + new_block.id.must_equal "B1" + + new_block.room_ids.each do |room_id| + room = new_hotel.find_room_by_id(room_id) + (Date.parse("2018-03-14")...Date.parse("2018-03-16")).each do |date| + room.all_dates.must_include date #fix this logic later + end + end + end + + it "does not allow you to create a Block if the room is reserved for any of the dates within the range you've proposed" do + new_hotel = HotelBooking::Hotel.new + + check_in= "2018-04-03" + check_out = "2018-04-17" + room_id = 5 + new_hotel.make_reservation(check_in,check_out,room_id) + + room = new_hotel.find_room_by_id(room_id) + + (Date.parse(check_in)...Date.parse(check_out)).to_a.each do |date| + room.all_dates.must_include date + end + + block_start= "2018-04-01" + + proc{new_hotel.make_block(block_start,check_in,[1,5],10)}.must_raise ArgumentError + + block_start2 = "2018-04-05" + block_end = "2018-04-08" + + proc{new_hotel.make_block(block_start2,block_end,[1,5],10)}.must_raise ArgumentError + + block_end2 = "2018-05-01" + new_hotel.make_block(check_out,block_end2,[1,5],10) + + end + end + + + describe "available_rooms" do + before do + @new_hotel = HotelBooking::Hotel.new + @check_in = Date.parse("June 1, 2018") + @check_out = Date.parse("June 30, 2018") + @june_rooms = @new_hotel.available_rooms(@check_in, @check_out) + end + + it "returns an array of available rooms" do + + @june_rooms.must_be_instance_of Array + @june_rooms.count.must_equal 20 + @june_rooms.each do |room| + room.must_be_instance_of HotelBooking::Room + end + end + + it "updates correctly when all rooms are reserved" do + @new_hotel.all_rooms.each do |room| + guest_idx = 1 + res_idx = 10 + room.reserve_room(@check_in, @check_out, res_idx, guest_idx) + + guest_idx +=1 + res_idx +=1 + end + + updated_june_rooms= @new_hotel.available_rooms(@check_in, @check_out) + + updated_june_rooms.count.must_equal 0 + updated_june_rooms.must_be_instance_of Array + + end + + it "shows the correct number when all but one room are reserved" do + @new_hotel.all_rooms[1..-1].each do |room| + guest_idx = 1 + res_idx = 10 + room.reserve_room(@check_in, @check_out, res_idx, guest_idx) + + guest_idx +=1 + res_idx +=1 + end + + updated_june_rooms= @new_hotel.available_rooms(@check_in, @check_out) + + updated_june_rooms.count.must_equal 1 + updated_june_rooms.must_be_instance_of Array + end + + end #end available_rooms + + + + describe "find_block_by_id" do + it "can find the first and last block" do + new_hotel = HotelBooking::Hotel.new + proc {new_hotel.find_block_by_id(1)}.must_raise ArgumentError + + room_ids = [3,4,5] + + new_hotel.make_block("2018-06-13", "2018-06-15", room_ids, 15) + + first_block = new_hotel.all_blocks[0] + first_block.must_be_instance_of HotelBooking::Block + first_block.id.must_equal "B1" + + found_block = new_hotel.find_block_by_id("B1") + + found_block.must_equal first_block + + end + + end + + describe "find_room_by_id" do + it "can find the first and last room" do + new_hotel = HotelBooking::Hotel.new + + first_room_id =1 + last_room_id = 20 + + + first_room = new_hotel.find_room_by_id(first_room_id) + last_room = new_hotel.find_room_by_id(last_room_id) + + first_room.must_be_instance_of HotelBooking::Room + first_room.id.must_equal 1 + first_room.must_equal new_hotel.all_rooms[0] + + last_room.must_be_instance_of HotelBooking::Room + last_room.id.must_equal 20 + last_room.must_equal new_hotel.all_rooms[-1] + end + end + + describe "find_available_rooms_by_block" do + it "Gives you an array of available rooms in a particular block and updates properly" do + new_hotel = HotelBooking::Hotel.new + rooms_in_block = [1,3,5] + room_id = 3 + non_exist_block_id = "B2" + check_in = "2018-11-10" + check_out = "2018-11-12" + discounted_rate = 10 + + new_hotel.make_block(check_in,check_out,rooms_in_block,discounted_rate) + new_hotel.all_blocks.count.must_equal 1 + + new_block = new_hotel.all_blocks[-1] + block_id = new_block.id + + proc {new_hotel.find_available_rooms_by_block(non_exist_block_id)}.must_raise ArgumentError + + avail_rooms_in_block = new_hotel.find_available_rooms_by_block(block_id) + + avail_rooms_in_block.must_be_instance_of Array + + avail_rooms_in_block.count.must_equal 3 + avail_rooms_in_block.must_equal rooms_in_block + + new_hotel.make_block_reservation(block_id, room_id) + + updated_available_rooms_in_block = new_hotel.find_available_rooms_by_block(block_id) + + updated_available_rooms_in_block.count.must_equal 2 + updated_available_rooms_in_block.must_equal [1,5] + + end + end + + describe "check valid dates " do + before do + @new_hotel = HotelBooking::Hotel.new + end + it "raises an error if the check-out dates is earlier than the check-in date" do + check_in= Date.parse("March 3, 2018") + check_out = Date.parse("February 20, 2018") + + proc { @new_hotel.check_valid_dates(check_in, check_out)}.must_raise ArgumentError + end + + it "Raises an error when given a check-in or check-out date earlier than today" do + + check_in = Date.parse("2016-08-09") + check_out = Date.parse("2016-08-12") + + proc { @new_hotel.check_valid_dates(check_in, check_out)}.must_raise ArgumentError + end + + it "raises an error if given input is not a Date object" do + check_in= 1 + check_out= 100 + + proc { @new_hotel.check_valid_dates(check_in, check_out)}.must_raise ArgumentError + + end + end +end diff --git a/specs/Guest_spec.rb b/specs/Guest_spec.rb new file mode 100644 index 000000000..234bbeaa5 --- /dev/null +++ b/specs/Guest_spec.rb @@ -0,0 +1,3 @@ +### OPTIONAL CLASS + +require_relative 'spec_helper' diff --git a/specs/Reservation_spec.rb b/specs/Reservation_spec.rb new file mode 100644 index 000000000..84445f51f --- /dev/null +++ b/specs/Reservation_spec.rb @@ -0,0 +1,43 @@ +require_relative 'spec_helper' + +describe "HotelBooking::Reservation class" do + describe "initialize" do + it "requires five arguments, an id, a guest, a check-in date, a check-out date, and a room" do + proc {HotelBooking::Reservation.new}.must_raise ArgumentError + proc {HotelBooking::Reservation.new("Jim Bob", Date.parse("2018-07-01"),5)}.must_raise ArgumentError + + new_res = HotelBooking::Reservation.new(Date.parse("July 1"), Date.parse("2018-07-03"), 5, 14) + + new_res.must_be_instance_of HotelBooking::Reservation + end + + it "creates a Reservation instance that allows us to read the id, guest, check-in date, check-out date, type, and room " do + read_res = HotelBooking::Reservation.new(Date.parse("2018-07-01"), Date.parse("2018-07-03"), 5,100) + + read_res.must_be_instance_of HotelBooking::Reservation + [read_res.check_in, read_res.check_out].each do |date| + date.month.must_equal 7 + end + + read_res.check_in.day.must_equal 1 + read_res.check_out.day.must_equal 3 + read_res.id.must_equal 100 + read_res.room_id.must_equal 5 + read_res.type.must_equal :standard + end + + end #end initialize tests + + describe "Cost" do + it "Returns an integer value that is the total cost of the reservation" do + reservation = HotelBooking::Reservation.new(Date.parse("2018-02-14"), Date.parse("2018-02-16"),5,1) + + reservation.cost.must_equal 400 + + res2 = HotelBooking::Reservation.new(Date.parse("2018-12-01"), Date.parse("2018-12-02"), 17,3) + + res2.cost.must_equal 200 + end + + end +end diff --git a/specs/Room_spec.rb b/specs/Room_spec.rb new file mode 100644 index 000000000..339132e2a --- /dev/null +++ b/specs/Room_spec.rb @@ -0,0 +1,121 @@ +require 'date' +require_relative 'spec_helper' + +describe "HotelBooking::Room class" do + describe "initialize" do + it "requires one argument, number" do + proc {HotelBooking::Room.new}.must_raise ArgumentError + + new_room = HotelBooking::Room.new(1) + new_room.must_be_instance_of HotelBooking::Room + end + + it "creates a new Room object with the correct id, and initialized with the correct default values for status and nightly_rate" do + new_room = HotelBooking::Room.new(1) + + new_room.id.must_equal 1 + new_room.nightly_rate.must_equal 200 + end + + it "can take an optional argument nightly_rate if we want to give it a different nightly_rate" do + vip_room = HotelBooking::Room.new(100, 350) + + vip_room.id.must_equal 100 + vip_room.nightly_rate.must_equal 350 + end + + end #end initialize + + describe "reserve_room" do + it "can reserve a room if given the check-in/out date, reservation id, and guest id" do + room = HotelBooking::Room.new(666) + check_in= Date.parse("2018-08-09") + check_out = Date.parse("2018-08-12") + + room.reserve_room(check_in, check_out, 1, 13) + + (check_in...check_out).each do |date| + room.all_dates.must_include date + end + + check_in2 = Date.parse("2018-09-28") + check_out2= Date.parse("2018-10-1") + + room.reserve_room(check_in2, check_out2, 8, 23) + (check_in2...check_out2).each do |date| + room.all_dates.must_include date + end + end + + end #end reserve_room + + + describe "available_all_days?" do + it "returns the correct Boolean value" do + new_hotel = HotelBooking::Hotel.new + room1 = new_hotel.all_rooms[0] + + check_in = Date.parse("2018-03-14") + check_out = Date.parse("2018-03-18") + + room1.available_all_days?(check_in, check_out).must_equal true + room1.available_all_days?(check_in, check_out).must_be_instance_of TrueClass + + room1.reserve_room(check_in, check_out, 1, 2) + + check_in2 = Date.parse("2018-03-16") + check_out2= Date.parse("2018-03-17") + + room1.available_all_days?(check_in2, check_out2).must_equal false + room1.available_all_days?(check_in2, check_out2).must_be_instance_of FalseClass + + #### can make reservations that check-in on the same day that somebody checks out + check_in3 = Date.parse("2018-03-18") + check_out3 = Date.parse("2018-03-21") + + room1.available_all_days?(check_in3, check_out3).must_equal true + room1.available_all_days?(check_in3, check_out3).must_be_instance_of TrueClass + end + + end #end available_all_days + + describe "block room" do + it "can block a room if given the check-in/out date and block id so that it is unavailable to reserve via regular reservations" do + room = HotelBooking::Room.new(666) + check_in = Date.parse("2018-08-09") + check_out = Date.parse("2018-08-12") + block_id = 3 + + room.block_room(check_in, check_out, block_id) + + (check_in...check_out).each do |date| + room.all_dates.must_include date + end + + check_in2 = Date.parse("2018-09-28") + check_out2 = Date.parse("2018-10-1") + + room.reserve_room(check_in2, check_out2, 8, 23) + (check_in2...check_out2).each do |date| + room.all_dates.must_include date + end + end + end + + + describe "self.setup_rooms" do + it "returns an array of all room objects, with the accurate number of rooms" do + test_all_rooms = HotelBooking::Hotel.setup_rooms + + test_all_rooms.must_be_instance_of Array + + test_all_rooms.each do |room| + room.must_be_instance_of HotelBooking::Room + room.nightly_rate.must_equal 200 + end + + test_all_rooms.count.must_equal 20 + end + end #end self.setup_rooms + +end #end HotelBooking::Room class tests diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 000000000..481a2a381 --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,13 @@ +require 'simplecov' +SimpleCov.start +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/skip_dsl' +require_relative '../lib/Booking' +require_relative '../lib/Reservation' +require_relative '../lib/Room' +require_relative '../lib/Guest' +require_relative '../lib/Block' +require_relative '../lib/BlockReservation' + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new