diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..90c7b22c9 Binary files /dev/null and b/.DS_Store differ diff --git a/Rakefile.rb b/Rakefile.rb new file mode 100644 index 000000000..5032abcfb --- /dev/null +++ b/Rakefile.rb @@ -0,0 +1,9 @@ +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.libs = ["lib"] + t.warning = true + t.test_files = FileList['specs/*-specs.rb'] +end + +task default: :test diff --git a/design-activity.md b/design-activity.md new file mode 100644 index 000000000..c0bb6e8de --- /dev/null +++ b/design-activity.md @@ -0,0 +1,81 @@ +#What classes does each implementation include? Are the lists the same? + +Implementation A includes the following classes: +CartEntry, ShoppingCart, Order + +Implementation B includes the following classes: +CartEntry, ShoppingCart, Order + +The lists are the same. + +#Write down a sentence to describe each class. + +CartEntry adds an item to cart with the quantity and unit price. + +ShoppingCart holds a list of all items added to the cart. + +Order creates a new instance of ShoppingCart and can calculate the total price of the cart. + + +How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper. + +An Order holds a ShoppingCart and its price. A ShoppingCart holds all items entered for that cart. A CartEntry is used to create entries that will be added to the ShoppingCart. + +What data does each class store? How (if at all) does this differ between the two implementations? + +In A and B, CartEntry stores the unit price and quantity for an item. + +In A and B, ShoppingCart stores a list of entries. + +In A and B, Order stores SALES_TAX and a ShoppingCart. + +What methods does each class have? How (if at all) does this differ between the two implementations? + +A has the following methods for each class: +CartEntry: initialize +ShoppingCart: initialize +Order: initialize, total_price + +B had the following: +CartEntry: initialize, price +ShoppingCart: initialize, price +Order: initialize, total_price + +B has a method to calculate price for each class, rather than only one as in A. + + +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? +In B the logic to compute price is contained in lower level classes, but in A it is not - in A it is retained in Order. + +Does total_price directly manipulate the instance variables of other classes? + +In A it does. + +If we decide items are cheaper if bought in bulk, how would this change the code? + +In A it would be harder to change because we do not calculate price for each item separately in A. + +In B it would be easier to change, because we could add code to give an item discount when bought in bulk in the CartEntry class. Since price is calculated for each item in CartEntry, the other classes would not be affected or have knowledge of this change. + + Which implementation is easier to modify? + + B is easier to modify. + +Which implementation better adheres to the single responsibility principle? + +B adheres better. + +Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? + +B is more loosely coupled. + +# Identify one place in your Hotel project where a class takes on multiple roles, or directly modifies the attributes of another class. +The Reservations class directly modifies attributes of other classes and overreaches in responsibility. The other classes stick to single responsibility but Reservations does not and is much more complicated. Reservations is too tightly coupled with other classes in several methods. + +# Describe in design-activity.md what changes you would need to make to improve this design, and how why the resulting design would be an improvement. + +I would remove direct calls on other classes in the methods as much as possible, and instead create instance variables on initialize within Reservations. I would move as much as possible of the date checking, availability checking, date range creation, etc to the DateRange class. I would have DateRange initialize with an array of dates rather than needing to call that method on a date range each time I need it. + +This would be an improvement because it would make the program more resilient to breaking if changes are made to other classes. It would also make the code easier and less complicated to change in the future. diff --git a/lib/.DS_Store b/lib/.DS_Store new file mode 100644 index 000000000..5008ddfcf Binary files /dev/null and b/lib/.DS_Store differ diff --git a/lib/Block.rb b/lib/Block.rb new file mode 100644 index 000000000..d8a2f7921 --- /dev/null +++ b/lib/Block.rb @@ -0,0 +1,62 @@ + +module Hotel + class Block < DateRange + attr_accessor :check_in, :check_out, :date_range, :dates, :block_rooms_collection, :discounted_room_rate, :available_rooms, :booked, :block_name, :number_of_rooms + + def initialize(check_in, check_out, block_name, block_rooms_collection = [], discounted_room_rate = 180) + + @check_in = Date.parse(check_in) + @check_out = Date.parse(check_out) + @date_range = Hotel::DateRange.new(check_in, check_out) + @dates = @date_range.dates + # @dates = Hotel::DateRange.new(@check_in, @check_out).dates + @block_rooms_collection = block_rooms_collection + @discounted_room_rate = discounted_room_rate + @booked = [] + @block_name = block_name + # @number_of_rooms = number_of_rooms + # create_block_rooms_collection + # Hotel::Reservations.blocks_collection << Self + end + + # def create_block_rooms_collection + # unless @number_of_rooms <= 5 && @number_of_rooms >= 1 + # raise ArgumentError.new("Blocks can only have between 1 and 5 rooms.") + # end + # rooms_available = Hotel::Reservations.rooms_collection + # @dates.each do |date| + # Hotel::Reservations.list_reservations_by_date(date).each do |booking| + # rooms_available.each do |room| + # if room.room_number == booking.room_number + # rooms_available.delete(room) + # end + # end + # end + # end + # @block_rooms_collection = [] + # + # @number_of_rooms.times do |i| + # @block_rooms_collection << rooms_available[i] + # end + # return @block_rooms_collection + # end + + def validate_block_dates(check_in, check_out, block) + if check_in >= block.check_in && check_out <= block.check_out + return true + else + raise ArgumentError.new("Cannot reserve for those dates - dates must be the same as block dates.") + end + end + + def has_rooms_available? + if !(@booked.length < @block_rooms_collection.length) + return false + else + return true + end + end + + + end +end diff --git a/lib/Booking.rb b/lib/Booking.rb new file mode 100644 index 000000000..175f274b9 --- /dev/null +++ b/lib/Booking.rb @@ -0,0 +1,64 @@ +require 'date' +require 'DateRange' + +module Hotel + + + class Booking < DateRange + attr_reader :check_in, :check_out, :room_number, :date_range + def initialize(check_in, check_out, room_number = rand(1..20), room_rate = 200) + @room_number = room_number + @check_in = Date.parse(check_in) + @check_out = Date.parse(check_out) + @date_range = DateRange.new(check_in, check_out) + @dates = @date_range.dates + @room_rate = room_rate + #@dates = Hotel::DateRange.new(check_in, check_out) + # @num_days = (@check_out - @check_in).to_i + # @total_cost = (@room_rate * @num_days) + @discount = 0 + + # validate_dates + end + + # def validate_dates + # unless @check_in >= Date.today + # raise InvalidDateError.new("Check-in cannot be before today's date.") + # end + # unless @check_in < @check_out + # raise InvalidDateError.new("Check-in cannot be after check-out.") + # end + # end + + def total_cost + num_days = (@check_out - @check_in).to_i + total_cost = @room_rate * num_days + return total_cost + end + end + +end + +# def available +# # greater than or equal than check_in date +# # and less than or equal to check_out date +# # +# # if the reservation dates contains the check_in date of an existing reservation it's already aproblem? +# @dates[0...-1].each do |date| +# list = Hotel::Reservations.list_reservations_by_date(date) +# list.each do |booking| +# if booking.room_number == room_number +# raise ArgumentError.new("Room number #{room_number} is not available for those dates.") +# end +# end +# end +# end + + +# def valid_dates +# +# unless card_is_valid?(card_number) +# raise InvalidCardNumberError.new("Invalid credit card number #{card_number}") +# end +# # ... process the transaction ... +# end diff --git a/lib/Reservations.rb b/lib/Reservations.rb new file mode 100644 index 000000000..1693727fe --- /dev/null +++ b/lib/Reservations.rb @@ -0,0 +1,212 @@ +require 'Booking' +require 'DateRange' +require 'date' +require 'block' + +module Hotel + class Reservations + attr_reader :all_reservations, :rooms_collection + attr_accessor :blocks_collection + + def initialize + @all_reservations = [] + @rooms_collection = [] + all_rooms + @blocks_collection = [] + # @booking = Hotel::Booking.new(check_in, check_out, room_number, room_rate) + # @block = Hotel::Block.new(check_in, check_out, block_name, @block_rooms_collection, discounted_room_rate = 180) + # @dates = @date_range.dates + end + + def all_rooms + if @rooms_collection.empty? == false + return @rooms_collection + end + + n = 1 + + (1..20).each do + room = Hotel::Room.new(n) + @rooms_collection << room + n += 1 + end + return @rooms_collection + end + + + def new_reservation(check_in, check_out, room_number = rand(1..20), room_rate = 200) + booking = Hotel::Booking.new(check_in, check_out, room_number, room_rate) + dates = booking.dates + if check_availability?(dates, room_number) == false + raise ArgumentError.new("Room number #{room_number} unavailable for those dates.") + else + @all_reservations << booking + return booking + end + end + + def list_rooms_available_by_date(date) + rooms_available = @rooms_collection + + list_reservations_by_date(date).each do |booking| + rooms_available.each do |room| + if room.room_number == booking.room_number + rooms_available.delete(room) + end #if end + end #rooms avail end + end #list do end + + list_blocked_rooms_by_date(date).each do |block| + rooms_available.each do |room| + if room.room_number == block.room_number + rooms_availale.delete(room) + end #if end + end # room avail do end + end #list do end + + return rooms_available + end #def end + + def check_availability?(dates, room_number) + available = true + dates[0...-1].each do |date| + unless available == false + room_number_array = [] + list_rooms_available_by_date(date).each do |room| + room_number_array << room.room_number + end + if room_number_array.include?(room_number) + available = true + else + available = false + end + end + return available + end + end + + def new_block(check_in, check_out, block_name, number_of_rooms, block_rooms_collection = [], discounted_room_rate = 180) + @number_of_rooms = number_of_rooms + @dates = DateRange.new(check_in, check_out).dates + create_block_rooms_collection #Method already checks for room availability in order to create collection + block_rooms_collection = @block_rooms_collection + block = Hotel::Block.new(check_in, check_out, block_name, @block_rooms_collection, discounted_room_rate = 180) + # @dates = @date_range.dates + @blocks_collection << block + return block + end + + def create_block_rooms_collection + unless @number_of_rooms <= 5 && @number_of_rooms >= 1 + raise ArgumentError.new("Blocks can only have between 1 and 5 rooms.") + end + rooms_available = @rooms_collection + @dates.each do |date| + list_reservations_by_date(date).each do |booking| + rooms_available.each do |room| + if room.room_number == booking.room_number + rooms_available.delete(room) + end + end + end + end + + @block_rooms_collection = [] + + @number_of_rooms.times do |i| + @block_rooms_collection << rooms_available[i] + end + return @block_rooms_collection + end + + def check_in_block(block, room_number) + block.block_rooms_collection.each do |room| + if room.room_number == room_number + return true + end + end + raise ArgumentError.new("Room number #{room_number} not included in #{block.block_name} block.") + end + + def new_reservation_in_block(check_in, check_out, block_name, room_number = 0, room_rate = 180) + block_room_booking = Hotel::Booking.new(check_in, check_out, room_number, room_rate) + check_in = Date.parse(check_in) + check_out = Date.parse(check_out) + block = match_block(block_name) + block.validate_block_dates(check_in, check_out, block) + check_in_block(block, room_number) + check_block_room_available(block, room_number) + + + add_block_booking_to_block(block, block_room_booking) + + @all_reservations << block_room_booking + return block_room_booking + end + + def match_block(block_name) + this_block = nil + @blocks_collection.each do |block| + if block.block_name == block_name + this_block = block + end + end + + if this_block == nil + raise ArgumentError("Block #{block_name} does not exist.") + else + return this_block + end + + end + + + def add_block_booking_to_block(block, block_room_booking) + block.booked << block_room_booking + end + + def check_block_room_available(block, room_number) + block.booked.each do |booking| + if booking.room_number == room_number + raise ArgumentError.new("Unable to book. Room number #{room_number} has already been booked.") + end + end + return true + end + + def list_reservations_by_date(date) + if date.class != Date + date = Date.parse(date) + end + list = [] + @all_reservations.each do |reservation| + if date >= reservation.check_in && date < reservation.check_out + #reservation.overlaps?(date) #check_out date excluded + list << reservation + end + end + return list + end + + def list_blocked_rooms_by_date(date) + if date.class != Date + date = Date.parse(date) + end + + blocks_list = [] + @blocks_collection.each do |block| + if date >= block.dates[0] && date < block.dates[-1] + block.block_rooms_collection.each do |room| + blocks_list << room + end + end + end + return blocks_list + end + + def clear_reservations #Using this for testing purposes + @all_reservations = [] + end + + end +end diff --git a/lib/Room.rb b/lib/Room.rb new file mode 100644 index 000000000..aef1222e4 --- /dev/null +++ b/lib/Room.rb @@ -0,0 +1,12 @@ +module Hotel + class Room + attr_reader :room_number, :room_rate + + def initialize(room_number, room_rate = 200) + @room_number = room_number + @room_rate = room_rate + end + + end + +end diff --git a/lib/date_range.rb b/lib/date_range.rb new file mode 100644 index 000000000..e8408ee56 --- /dev/null +++ b/lib/date_range.rb @@ -0,0 +1,51 @@ +require 'date' + +module Hotel + class InvalidDateError < StandardError + end + + class DateRange + attr_reader :dates, :check_in, :check_out + def initialize(check_in, check_out) + @check_in = Date.parse(check_in) + @check_out = Date.parse(check_out) + @dates = Array(@check_in..@check_out) + validate_dates + end + + def validate_dates + unless @check_in >= Date.today + raise InvalidDateError.new("Check-in cannot be before today's date.") + end + unless @check_in < @check_out + raise InvalidDateError.new("Check-in cannot be after check-out.") + end + end + + def make_date(date) + if date.class != Date + date = Date.parse(date) + end + return date + end + + def validate_block_dates(check_in, check_out) + check_in = make_date(check_in) + check_out = make_date(check_out) + if @check_in >= check_in && @check_out <= check_out + return true + else + raise ArgumentError.new("Cannot reserve for those dates - dates must be the same as block dates.") + return false + end + end + + def overlaps?(date) + date = make_date(date) + unless date >= @check_in && date < @check_out + return false + end + end + + end +end diff --git a/specs/block_specs.rb b/specs/block_specs.rb new file mode 100644 index 000000000..517504793 --- /dev/null +++ b/specs/block_specs.rb @@ -0,0 +1,41 @@ +require_relative 'spec_helper' + +describe 'Block' do +before do + @hotel = Hotel::Reservations.new + @new_block = Hotel::Block.new("2018-01-01", "2018-01-10", []) +end + describe 'initialize' do + it "must be an instance of a Block" do + @new_block.must_be_instance_of Hotel::Block + end + end + + describe 'dates' do + it 'must have a list of dates' do + @new_block.must_respond_to :date_range + end + it 'must be an array' do + @new_block.dates.must_be_kind_of Array + end + it 'elements in the array must be of the date class' do + @new_block.dates[0].must_be_kind_of Date + end + end + + describe 'has_rooms_available' do + before do + @new_block1 = Hotel::Block.new("2018-01-01", "2018-01-10", "Heritage", [1, 2, 3, 4, 5]) + @new_block1.booked = [1, 2, 3, 4] + end + it 'must return true when at least one room is available' do + @new_block1.has_rooms_available?.must_equal true + end + it 'must return false when no rooms available' do + @new_block1.booked << 5 + @new_block1.has_rooms_available?.must_equal false + end + end + + +end diff --git a/specs/booking_specs.rb b/specs/booking_specs.rb new file mode 100644 index 000000000..437699c15 --- /dev/null +++ b/specs/booking_specs.rb @@ -0,0 +1,65 @@ +require_relative 'spec_helper' + +describe 'Booking' do + before do + @new_booking = Hotel::Booking.new("2018-09-21", "2018-09-23") + end + describe 'initialize' do + it "must be an instance of Booking" do + @new_booking.must_be_instance_of Hotel::Booking + end + it "must have a check in date" do + @new_booking.must_respond_to :check_in + end + it "must have a check out date" do + @new_booking.must_respond_to :check_out + end + it "must have a room number" do + @new_booking.must_respond_to :room_number + end + end + + describe "check in date" do + it "must be a date" do + @new_booking.check_in.must_be_kind_of Date + end + it "must output the correct date" do + @new_booking.check_in.must_equal Date.parse("2018-09-21") + end + end + + describe "check out date" do + it "must be a date do" do + @new_booking.check_out.must_be_kind_of Date + end + it "must output the correct date" do + @new_booking.check_out.must_equal Date.parse("2018-09-23") + end + end + + describe "room number" do + it "must be an integer" do + @new_booking.room_number.must_be_kind_of Integer + end + end +end + + +describe 'DateRange' do + before do + @new_date_range = Hotel::DateRange.new("2019-01-01", "2019-01-04") + end + describe 'initialize' do + it 'will initialize' do + @new_date_range.must_be_instance_of Hotel::DateRange + end + end + describe 'dates method' do + it 'is an array' do + @new_date_range.dates.must_be_kind_of Array + end + it 'must include the correct number of dates' do + @new_date_range.dates.length.must_equal 4 + end + end +end diff --git a/specs/date_range_specs.rb b/specs/date_range_specs.rb new file mode 100644 index 000000000..e1b9e6b07 --- /dev/null +++ b/specs/date_range_specs.rb @@ -0,0 +1,20 @@ +require_relative 'spec_helper' + +describe 'DateRange' do + before do + @new_date_range = Hotel::DateRange.new("2019-01-01", "2019-01-04") + end + describe 'initialize' do + it 'will initialize' do + @new_date_range.must_be_instance_of Hotel::DateRange + end + end + describe 'dates method' do + it 'is an array' do + @new_date_range.dates.must_be_kind_of Array + end + it 'must include the correct number of dates' do + @new_date_range.dates.length.must_equal 4 + end + end +end diff --git a/specs/reservations_specs.rb b/specs/reservations_specs.rb new file mode 100644 index 000000000..118ced34c --- /dev/null +++ b/specs/reservations_specs.rb @@ -0,0 +1,276 @@ +require_relative 'spec_helper' + +describe 'Reservations' do + before do + @new_hotel = Hotel::Reservations.new + end + describe 'initialize' do + it "must be an instance of Reservations" do + @new_hotel.must_be_instance_of Hotel::Reservations + end + end + + describe "collection of rooms" do + it "has a collection of rooms" do + @new_hotel.all_rooms.must_be_kind_of Array + end + ##TODO: write more tests here ## + end + + describe 'all reservations' do + it "has a collection of reservations" do + @new_hotel.all_reservations.must_be_kind_of Array + end + end + + describe 'new reservation' do + before do + @new_hotel.clear_reservations + @new_hotel1 = Hotel::Reservations.new + end + it 'must create a new booking' do + new_booking1 = @new_hotel1.new_reservation("2018-09-21", "2018-09-23", 1) + new_booking1.must_be_instance_of Hotel::Booking + end + it 'must raise an error if the check-in date is in the past' do + + proc{new_booking = @new_hotel1.new_reservation("2017-06-01", "2017-09-21", 2)}.must_raise Hotel::InvalidDateError + end + it 'must raise an error if the check-in date is the same as the check-out date' do + proc{new_booking = @new_hotel1.new_reservation("2018-09-20", "2018-09-20"), 3}.must_raise Hotel::InvalidDateError + end + it 'must raise an error if the check_in date is after the check-out date' do + proc{new_booking = @new_hotel1.new_reservation("2018-09-20", "2018-09-18"), 4}.must_raise Hotel::InvalidDateError + end + it 'must raise an error if the date is not valid on calendar' do + proc{new_booking = @new_hotel1.new_reservation("2018-02-30", "2018-02-31"), 5}.must_raise ArgumentError + end + it 'allows a new reservation to be made on a room on the same day as previous check-out' do + @new_hotel1.clear_reservations + @new_reservation1 = @new_hotel1.new_reservation("2018-01-01", "2018-01-05", 1) + @new_reservation2 = @new_hotel1.new_reservation("2018-01-05", "2018-01-07", 1) + @new_hotel1.all_reservations.length.must_equal 2 + end + end + + describe 'check availability' do + before do + @new_hotel_check = Hotel::Reservations.new + @new_hotel_check.new_reservation("2018-01-01", "2018-01-05", 1) + end + + it 'must must raise argument error if room is not available' do + proc{ new_reservation2 = @new_hotel_check.new_reservation("2018-01-01", "2018-01-04", 1) }.must_raise ArgumentError + end + + it 'must not allow a room to be booked for the same dates as another booking' do + proc{ new_reservation3 = @new_hotel_check.new_reservation("2018-01-01", "2018-01-05", 1)}.must_raise ArgumentError + end + + it 'must not allow dates to overlap with check-in date of another reservation' do + proc{ new_reservation4 = @new_hotel_check.new_reservation("2017-12-25", "2018-01-02", 1)}.must_raise ArgumentError + end + + it 'must not allow dates to overlap with end of another reservation (excluding check-out date)' do + proc{ new_reservation5 = @new_hotel_check.new_reservation("2018-01-04", "2018-01-06", 1)}.must_raise ArgumentError + end + + it 'must not allow a reservation to be booked when dates are completely contained within another reservation' do + proc{ new_reservation6 = @new_hotel_check.new_reservation("2018-01-02", "2018-01-03", 1)}.must_raise ArgumentError + end + + it 'must not allow a reservation to be booked which completely contains the dates of anothe reservation' do + proc{ new_reservation7 = @new_hotel_check.new_reservation("2017-12-25", "2018-01-10", 1)}.must_raise ArgumentError + end + + it 'must allow a reservation to be booked if dates are completely before another reservation' do + new_reservation8 = @new_hotel_check.new_reservation("2017-12-20", "2017-12-31", 1) + new_reservation8.must_be_instance_of Hotel::Booking + end + + it 'must allow a reservation to be booked if dates are completely after another reservation' do + new_reservation9 = @new_hotel_check.new_reservation("2018-01-15", "2018-01-28", 1) + new_reservation9.must_be_instance_of Hotel::Booking + end + + it 'must allow a reservation to be booked when reservation begins on previous reservation check out date' do + new_reservation10 = @new_hotel_check.new_reservation("2018-01-28", "2018-02-20", 1) + new_reservation10.must_be_instance_of Hotel::Booking + end + + it 'must allow a reservation to be booked when it ends on another reservations check-in date' do + new_reservation11 = @new_hotel_check.new_reservation("2018-03-20", "2018-03-22", 1) + + new_reservation12 = @new_hotel_check.new_reservation("2018-03-02", "2018-03-20", 1) + + new_reservation12.must_be_instance_of Hotel::Booking + end + + + + end + + describe 'list rooms available by date' do + before do + @new_hotel.clear_reservations + @new_reservation1 = @new_hotel.new_reservation("2018-01-01", "2018-01-05", 1) + @new_reservation2 = @new_hotel.new_reservation("2018-01-01", "2018-01-05", 2) + @new_reservation3 = @new_hotel.new_reservation("2018-01-01", "2018-01-05", 10) + end + after do + @new_hotel.clear_reservations + end + it 'must return an array' do + @new_hotel.list_rooms_available_by_date("2018-01-02").must_be_kind_of Array + end + it 'must return the correct number of rooms available' do + @new_hotel.list_rooms_available_by_date(Date.parse("2018-01-03")).length.must_equal 17 + end + it 'must return the correct rooms available' do + @new_hotel.list_rooms_available_by_date("2018-01-03")[0].room_number.must_equal 3 + end + end + # describe 'assign room number' do + # it 'will assign a room number if no room number is given' do + # new_booking = @new_hotel.new_reservation("2017-09-21", "2017-09-23") + # new_booking.room_number.wont_equal 0 + # end + # end + + # describe 'validate room number' do + # after do + # @new_hotel.clear_reservations + # end + # it 'must raise an error if a room number that does not exist is entered' do + # proc{new_booking = @new_hotel.new_reservation("2017-09-21", "2017-09-30", 45)}.must_raise ArgumentError + # end + # end + + describe 'all reservations' do + before do + @new_hotel.clear_reservations + @new_booking1 = @new_hotel.new_reservation("2018-09-21", "2018-09-23", 2) + @new_booking2 = @new_hotel.new_reservation("2020-01-01", "2020-01-15", 3) + @new_booking3 = @new_hotel.new_reservation("2019-01-01", "2019-01-15", 5) + end + it 'must be an array of all reservations' do + @new_hotel.all_reservations.must_be_kind_of Array + end + it 'must contain correct number of reservations made' do + @new_hotel.all_reservations.length.must_equal 3 + end + it 'must contain the first reservation made' do + @new_hotel.all_reservations[0].check_in.must_equal Date.parse("2018-09-21") + end + it 'must contain the correct total cost of the reservation' do + @new_hotel.all_reservations[0].total_cost.must_equal 400 + end + end + + describe 'list_reservations_by_date' do + before do + @new_hotel.clear_reservations + @new_booking1 = @new_hotel.new_reservation("2018-09-21", "2018-09-23", 1) + @new_booking2 = @new_hotel.new_reservation("2019-01-01", "2019-01-15", 10) + @new_booking3 = @new_hotel.new_reservation("2019-01-02", "2019-01-12", 12) + @new_booking4 = @new_hotel.new_reservation("2019-01-01", "2019-01-13", 15) + end + it "must be a method of Reservations" do + @new_hotel.must_respond_to :list_reservations_by_date + end + it "must be an array" do + @new_hotel.list_reservations_by_date("2019-01-01").must_be_kind_of Array + end + it "must have the correct number of reservations for the date given" do + @new_hotel.list_reservations_by_date("2019-01-04").length.must_equal 3 + end + it "must return the correct reservations" do + @new_hotel.list_reservations_by_date("2018-09-21")[0].room_number.must_equal @new_booking1.room_number + end + end + + describe 'make a new block' do + before do + @new_hotel.clear_reservations + @new_block = @new_hotel.new_block("2018-01-01", "2018-01-10", "Heritage", 5) + #@new_block2 = @new_hotel.new_block("2018-02-02", "2018-02-05", 3) + end + after do + @new_hotel.clear_reservations + end + it 'must be an instance of a block' do + @new_block.must_be_instance_of Hotel::Block + end + it 'must add the block to the blocks collection' do + @new_hotel.blocks_collection.must_include(@new_block) + end + it 'must have a collection of rooms' do + @new_block.block_rooms_collection.must_be_kind_of Array + end + it 'must have the correct number of rooms in the collection' do + @new_block.block_rooms_collection.length.must_equal 5 + end + end + + describe 'list block rooms by date' do + before do + @new_hotel.clear_reservations + @new_block = @new_hotel.new_block("2018-01-01", "2018-01-10", "Heritage", 5) + end + it 'must list the correct number of rooms for a given date' do + @new_hotel.list_blocked_rooms_by_date(Date.parse("2018-01-02")).length.must_equal 5 + end + end + + describe 'reserve a room in a block' do + before do + @new_hotel_with_blocks = Hotel::Reservations.new + @new_booking1 = @new_hotel_with_blocks.new_reservation("2018-01-01", "2018-01-05", 1) + @new_booking2 = @new_hotel_with_blocks.new_reservation("2018-01-01", "2018-01-04", 2) + @new_booking3 = @new_hotel_with_blocks.new_reservation("2018-01-01", "2018-01-05", 3) + @new_booking4 = @new_hotel_with_blocks.new_reservation("2018-01-01", "2018-01-13", 4) + @new_block = @new_hotel_with_blocks.new_block("2018-01-01", "2018-01-10", "Heritage", 5) + @new_block_reservation = @new_hotel_with_blocks.new_reservation_in_block("2018-01-01", "2018-01-05", "Heritage", 6) + end + it 'must be an instance of Hotel Booking' do + @new_block_reservation.must_be_instance_of Hotel::Booking + end + it 'must raise an error if the room is not in the block' do + proc {@new_block_reservation1 = @new_hotel_with_blocks.new_reservation_in_block("2018-01-01", "2018-01-05", "Heritage", 20)}.must_raise ArgumentError + end + it 'must raise an error if the room selected is not available' do + proc { @new_block_reservation1 = @new_hotel_with_blocks.new_reservation_in_block("2018-01-01", "2018-01-05", "Heritage", 6)}.must_raise ArgumentError + end + end + + describe 'block has rooms available' do + before do + @new_hotel_with_blocks1 = Hotel::Reservations.new + @new_booking1 = @new_hotel_with_blocks1.new_reservation("2018-01-01", "2018-01-05", 1) + @new_booking2 = @new_hotel_with_blocks1.new_reservation("2018-01-01", "2018-01-04", 2) + @new_booking3 = @new_hotel_with_blocks1.new_reservation("2018-01-01", "2018-01-05", 3) + @new_booking4 = @new_hotel_with_blocks1.new_reservation("2018-01-01", "2018-01-13", 4) + @new_block = @new_hotel_with_blocks1.new_block("2018-01-01", "2018-01-10", "Heritage", 5) + @new_block_reservation = @new_hotel_with_blocks1.new_reservation_in_block("2018-01-01", "2018-01-05", "Heritage", 6) + @new_block_reservation2 = @new_hotel_with_blocks1.new_reservation_in_block("2018-01-01", "2018-01-05", "Heritage", 7) + end + it 'must return true if there are rooms available in block to be booked' do + @new_block.has_rooms_available?.must_equal true + end + it 'must return false if there are NOT any rooms available in block to be booked' do + @new_block_reservation3 = @new_hotel_with_blocks1.new_reservation_in_block("2018-01-01", "2018-01-05", "Heritage", 8) + @new_block_reservation4 = @new_hotel_with_blocks1.new_reservation_in_block("2018-01-01", "2018-01-05", "Heritage", 9) + @new_block_reservation5 = @new_hotel_with_blocks1.new_reservation_in_block("2018-01-01", "2018-01-05", "Heritage", 5) + + @new_block.has_rooms_available?.must_equal false + end + end + + describe 'block room reservation will match with block date range' do + it 'must raise an arugment error if the dates are outside of the range' do + new_hotel = Hotel::Reservations.new + new_block = new_hotel.new_block("2018-01-01", "2018-01-10", "Heritage", 5) + proc {new_block_reservation = new_hotel.new_reservation_in_block("2018-01-01", "2018-01-15", "Heritage", 5)}.must_raise ArgumentError + end + end +end diff --git a/specs/room_specs.rb b/specs/room_specs.rb new file mode 100644 index 000000000..77639e698 --- /dev/null +++ b/specs/room_specs.rb @@ -0,0 +1,31 @@ +require_relative 'spec_helper' + +describe 'Room' do + before do + @new_room = Hotel::Room.new("1") + end + describe 'initialize' do + it "must be an instance of Room" do + @new_room.must_be_instance_of Hotel::Room + end + end + + describe 'room number' do + + it "must have a room number" do + @new_room.must_respond_to :room_number + end + it "must output its correct room number" do + @new_room.room_number.must_equal "1" + end + end + + describe 'room rate' do + it "must have a designated room rate" do + @new_room.must_respond_to :room_rate + end + it "must default to 200" do + @new_room.room_rate.must_equal 200 + end + end +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 000000000..c4f788cf4 --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,15 @@ + +require 'SimpleCov' +SimpleCov.start +require 'minitest' +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/skip_dsl' +require 'pry' +require 'date' + +require_relative '../lib/room.rb' +require_relative '../lib/reservations.rb' +require_relative '../lib/booking.rb' +require_relative '../lib/date_range.rb' +require_relative '../lib/block.rb'