diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..774aa4d69 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 5e1422c9c..964590134 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ /test/tmp/ /test/version_tmp/ /tmp/ +/lib/main.rb # Used by dotenv library to load environment variables. # .env diff --git a/lib/date_range.rb b/lib/date_range.rb new file mode 100644 index 000000000..bd78cbedf --- /dev/null +++ b/lib/date_range.rb @@ -0,0 +1,25 @@ +module Hotel + class DateRange + attr_reader :start_date, :end_date + + def initialize(start_date:, end_date:) + #TODO: validate dates' input + #TODO: add defaults (for example, one year from/before Date.today) + @start_date = Date.parse(start_date) + @end_date = Date.parse(end_date) + + raise ArgumentError.new("End date cannot be equal to or come before start date.") if @end_date <= @start_date + end + + def overlap?(date_range) + raise ArgumentError.new("Must provide a date range.") unless date_range.is_a? DateRange + + #TODO: efficient date checking (first compare years? months?) + start_date < date_range.end_date && end_date > date_range.start_date + end + + def nights + (end_date - start_date).to_i + end + end +end \ No newline at end of file diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..c3272df92 --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,22 @@ +require "date" + +module Hotel + class Reservation + attr_reader :date_range, :room_id, :rate + + def initialize(room_id: , start_date:, end_date:, rate: :default) + unless (rate == :default || rate.respond_to?(:>) && rate >= 0) + raise ArgumentError.new("Invalid rate.") + end + + @date_range = DateRange.new(start_date: start_date, end_date: end_date) + @room_id = room_id + @rate = (rate == :default) ? 200 : rate + end + + def cost + date_range.nights * rate + end + end +end + diff --git a/lib/reservation_desk.rb b/lib/reservation_desk.rb new file mode 100644 index 000000000..5c656118a --- /dev/null +++ b/lib/reservation_desk.rb @@ -0,0 +1,119 @@ +module Hotel + class ReservationDesk + # Class responsibility: to organize reservations across hotel + attr_reader :room_num, :rooms, :reservations, :blocks + + def initialize(room_num: 20) + @room_num = room_num + @rooms = make_rooms + @blocks = {} + end + + def find_room_by_id(id) + rooms.find {|room| room.id == id} + end + + def find_reservations(room_id: nil , start_date: , end_date: ) + date_range = DateRange.new(start_date: start_date, end_date: end_date) + + if room_id + room = rooms.find { |room| room.id == room_id} + return nil if room == nil + reservations = room.select_reservations(date_range) + else + reservations = [] + rooms.each do |room| + room_reservations = room.select_reservations(date_range) + reservations += room_reservations + end + end + return reservations + end + + def find_available_rooms(start_date:, end_date:) + available_rooms = [] + rooms.each do |room| + available_rooms << room if room.available?(start_date: start_date, end_date: end_date) + end + return available_rooms.empty? ? nil : available_rooms + end + + def make_reservation(room_id: nil, start_date:, end_date:, rate: :default) + if room_id + room = find_room_by_id(room_id) + raise ArgumentError.new("Invalid room ID.") if room == nil + else + room = find_available_rooms(start_date: start_date, end_date: end_date)[0] + raise StandardError.new("No rooms available for these dates.") if room == nil + end + room.reserve(start_date: start_date, end_date: end_date, rate: rate) + end + + def make_block(room_ids:, start_date:, end_date:, rate: :default) + #TODO: add no rooms given scenario + raise ArgumentError.new("Blocks should contain 2-5 rooms.") if (room_ids.length > 5 || room_ids.length < 2) + + block_id = create_block(start_date: start_date, end_date: end_date) + room_ids.each do |id| + room = find_room_by_id(id) + raise ArgumentError.new("Invalid room ID.") if room == nil + room.reserve(start_date: start_date, end_date: end_date, block: block_id, rate: rate) + blocks[block_id][:rooms] << room + end + end + + def reserve_from_block(room_id: , block_id: ) + raise ArgumentError.new("Invalid block ID.") unless blocks[block_id] + + blocks[block_id][:rooms].each do |room| + if room.id == room_id + start_date = blocks[block_id][:date_range][0] + end_date = blocks[block_id][:date_range][1] + unless room.reserved?(start_date: start_date, end_date: end_date) + room.block_participation.each do |block_part| + if block_part.date_range.start_date == Date.parse(start_date) + room.reservations << block_part + return true + end + end + end + raise StandardError.new("This room has already been reserved.") + end + end + raise ArgumentError.new("Invalid room ID.") + end + + def check_block_availability(block_id) + raise ArgumentError.new("Invalid block ID.") unless blocks[block_id] + available_rooms = [] + start_date = blocks[block_id][:date_range][0] + end_date = blocks[block_id][:date_range][1] + + blocks[block_id][:rooms].each do |room| + available_rooms << room unless room.reserved?(start_date: start_date, end_date: end_date) + end + return available_rooms + end + + private + def make_rooms + rooms = [] + room_num.times do |i| + rooms << Room.new(i+1) + end + return rooms + end + + def generate_block_id + blocks.length + 1 + end + + def create_block(start_date:, end_date:) + block_id = generate_block_id + blocks[block_id] = {} + blocks[block_id][:date_range] = [start_date, end_date] + blocks[block_id][:rooms] = [] + return block_id + end + end +end \ No newline at end of file diff --git a/lib/room.rb b/lib/room.rb new file mode 100644 index 000000000..e220d0e0e --- /dev/null +++ b/lib/room.rb @@ -0,0 +1,64 @@ +module Hotel + + class Room + # Class responsibility: to reserve individual rooms + attr_reader :id, :reservations, :block_participation + + def initialize(id) + @id = id + @reservations = [] + @block_participation = [] + end + + # available? helper method / public interface + def reserved?(start_date:, end_date:) + date_range = DateRange.new(start_date: start_date, end_date: end_date) + reservations.each do |reservation| + if reservation.date_range.overlap? (date_range) + return true + end + end + return false + end + + # available? helper method / public interface + def in_block?(start_date:, end_date:) + date_range = DateRange.new(start_date: start_date, end_date: end_date) + block_participation.each do |block_reservation| + if block_reservation.date_range.overlap? (date_range) + return true + end + end + return false + end + + def available?(start_date:, end_date:) + (reserved?(start_date: start_date, end_date: end_date) || in_block?(start_date: start_date, end_date: end_date)) ? false : true + end + + def reserve(start_date:, end_date:, block: nil, rate: :default) + unless available?(start_date: start_date, end_date: end_date) + raise StandardError.new("Room #{id} is unavailabe for requested dates.") + end + reservation = new_reservation(start_date: start_date, end_date: end_date, rate: rate) + block ? add_block_participation(reservation) : add_reservation(reservation) + end + + def select_reservations(date_range) + reservations.select { |reservation| reservation.date_range.overlap? (date_range)} + end + + private + def new_reservation(start_date:, end_date:, rate: :default) + reservation = Reservation.new(room_id: id, start_date: start_date, end_date: end_date, rate: rate) + end + + def add_reservation(reservation) + reservations << reservation + end + + def add_block_participation(reservation) + block_participation << reservation + end + end +end diff --git a/refactors.txt b/refactors.txt new file mode 100644 index 000000000..ea4cf9548 --- /dev/null +++ b/refactors.txt @@ -0,0 +1,17 @@ +1. Consider adding Block Class instead of hash structure in ReservationDesk +- ReservationDesk will have a blocks array of Block objects. +- ReservationDesk will have find_block_by_id method. +- Block object will have block_id, rooms (array of Room objects), date_range variables. +- Block object will have reserve_from_block and check_room_availability methods which will be called from inside current ReservationDesk methods. + +2. Add date input validation. + +3. Add defaults for start and end dates. +(gives functionality to select all reservations from/until specific date) + +4. Find a more efficient way to compare dates. +(sort and compare years/months first?..) + +5. Consider moving away from having start and end_date as arguments towards using date_range. + +6. Implement "no rooms given" scenario for make_block. \ No newline at end of file diff --git a/test/date_range_test.rb b/test/date_range_test.rb new file mode 100644 index 000000000..0d39bc64f --- /dev/null +++ b/test/date_range_test.rb @@ -0,0 +1,76 @@ +require_relative "test_helper" + +describe "DateRange class" do + describe "DateRange instatiation" do + # before do + # date_range = Hotel::DateRange.new() + # end + it "is an instance of DateRange" do + expect(Hotel::DateRange.new(start_date: "2020-3-1", end_date: "2020-3-10")).must_be_kind_of Hotel::DateRange + end + + it "converts its start_date and end_date attributes to Date objects" do + date_range = Hotel::DateRange.new(start_date: "2020-3-1", end_date: "2020-3-10") + expect(date_range.start_date).must_be_kind_of Date + expect(date_range.end_date).must_be_kind_of Date + end + + it "raises an ArgumentError if end_date is equal to or comes before start_date" do + expect {Hotel::DateRange.new(start_date: "2020-3-1", end_date: "2020-2-10")}.must_raise ArgumentError + expect {Hotel::DateRange.new(start_date: "2020-3-1", end_date: "2020-3-1")}.must_raise ArgumentError + end + + # TODO + # it "can be instantiated with no arguments" do + # expect(Hotel::DateRange.new()).must_be_kind_of Hotel::DateRange + # end + end + + describe "overlap?" do + let (:date_range) { + Hotel::DateRange.new(start_date: "2020-3-1", end_date: "2020-3-20") + } + + it "expects a DateRange as an argument" do + expect {date_range.overlap?(50)}.must_raise ArgumentError + end + + it "returns true if the dates overlap and false if not" do + # TODO: each one should be a new test? + second_date_range = Hotel::DateRange.new(start_date: "2020-3-2", end_date: "2020-3-10") + expect(date_range.overlap?(second_date_range)).must_equal true + + third_date_range = Hotel::DateRange.new(start_date: "2020-3-13", end_date: "2020-3-25") + expect(date_range.overlap?(third_date_range)).must_equal true + + forth_date_range = Hotel::DateRange.new(start_date: "2020-2-10", end_date: "2020-2-26") + expect(date_range.overlap?(forth_date_range)).must_equal false + + fifth_date_range = Hotel::DateRange.new(start_date: "2020-3-23", end_date: "2020-3-25") + expect(date_range.overlap?(fifth_date_range)).must_equal false + + six_date_range = Hotel::DateRange.new(start_date: "2020-3-20", end_date: "2020-3-21") + expect(date_range.overlap?(six_date_range)).must_equal false + end + + # TODO: + # it "expects a DateRange provided as an argument to have start_date and end_date rather than nil" do + # other_date_range_1 = Hotel::DateRange.new(end_date: "2020-5-10") + # expect {date_range.overlap? (other_date_range_1)}.must_raise ArgumentError + + # other_date_range_2 = Hotel::DateRange.new(start_date: "2020-5-10") + # expect {date_range.overlap? (other_date_range_2)}.must_raise ArgumentError + # end + end + + describe "nights" do + it "calculates the number of nights for the date range" do + date_range = Hotel::DateRange.new(start_date: "2020-3-1", end_date: "2020-3-10") + expect(date_range.nights).must_equal 9 + + date_range = Hotel::DateRange.new(start_date: "2020-3-1", end_date: "2020-3-2") + expect(date_range.nights).must_equal 1 + end + end + +end \ No newline at end of file diff --git a/test/reservation_desk_test.rb b/test/reservation_desk_test.rb new file mode 100644 index 000000000..34b25e8da --- /dev/null +++ b/test/reservation_desk_test.rb @@ -0,0 +1,317 @@ +require_relative "test_helper" + +describe "ReservationDesk class" do + before do + @reservation_desk = Hotel::ReservationDesk.new() + end + + describe "ReservationDesk instantiation" do + it "is an instance of ReservationDesk" do + expect(@reservation_desk).must_be_kind_of Hotel::ReservationDesk + end + end + + describe "rooms" do + it "returns an array" do + expect(@reservation_desk.rooms).must_be_kind_of Array + end + + it "returns an array of Rooms" do + expect(@reservation_desk.rooms[0]).must_be_kind_of Hotel::Room + expect(@reservation_desk.rooms.last).must_be_kind_of Hotel::Room + end + + it "includes 20 rooms by default" do + expect(@reservation_desk.rooms.length).must_equal 20 + end + + it "the first room has an id of 1" do + expect(@reservation_desk.rooms[0].id).must_equal 1 + end + + it "the last room has an id which is equal to the number of rooms" do + reservation_desk = Hotel::ReservationDesk.new(room_num: 134) + expect(reservation_desk.rooms.last.id).must_equal 134 + end + end + + describe "find_room_by_id" do + it "returns an instanse of Room" do + expect(@reservation_desk.find_room_by_id(2)).must_be_kind_of Hotel::Room + end + + it "returns a Room with a matching ID" do + expect(@reservation_desk.find_room_by_id(2).id).must_equal 2 + end + + it "returns nill if there is no Room with a matching ID" do + assert_nil @reservation_desk.find_room_by_id(20000000) + end + end + + describe "find_reservations" do + before do + @reservation_desk.rooms[0].reserve(start_date: "2020-3-1", end_date: "2020-3-5") + @reservation_desk.rooms[1].reserve(start_date: "2020-3-1", end_date: "2020-3-10") + @reservation_desk.rooms[2].reserve(start_date: "2020-3-1", end_date: "2020-3-25") + @reservation_desk.rooms[0].reserve(start_date: "2020-3-10", end_date: "2020-3-15") + + end + + it "returns an array" do + result = @reservation_desk.find_reservations(room_id: 1, start_date: "2020-3-1", end_date: "2020-3-17") + expect(result).must_be_kind_of Array + end + + it "returns an array of reservations" do + result = @reservation_desk.find_reservations(room_id: 1, start_date: "2020-3-1", end_date: "2020-3-17") + expect(result[0]).must_be_kind_of Hotel::Reservation + end + + it "ID provided: returns nil if room ID doesn't exist" do + assert_nil @reservation_desk.find_reservations(room_id: 100000, start_date: "2020-3-1", end_date: "2020-3-17") + end + + it "ID provided: returns reservations for requested dates" do + result_1 = @reservation_desk.find_reservations(room_id: 1, start_date: "2020-3-1", end_date: "2020-3-17") + expect(result_1.length).must_equal 2 + result_2 = @reservation_desk.find_reservations(room_id: 1, start_date: "2020-3-1", end_date: "2020-3-10") + expect(result_2.length).must_equal 1 + result_3 = @reservation_desk.find_reservations(room_id: 1, start_date: "2020-3-3", end_date: "2020-3-8") + expect(result_3.length).must_equal 1 + result_4 = @reservation_desk.find_reservations(room_id: 1, start_date: "2020-3-11", end_date: "2020-3-13") + expect(result_4.length).must_equal 1 + end + + it "No ID provided: returns reservations for specific dates for all rooms" do + @reservation_desk.rooms[3].reserve(start_date: "2020-3-1", end_date: "2020-3-5") + @reservation_desk.rooms[4].reserve(start_date: "2020-3-10", end_date: "2020-3-15") + @reservation_desk.rooms[5].reserve(start_date: "2020-3-20", end_date: "2020-3-25") + @reservation_desk.rooms[6].reserve(start_date: "2020-5-20", end_date: "2020-5-25") + + result = @reservation_desk.find_reservations(start_date: "2020-3-1", end_date: "2020-3-30") + expect(result.length).must_equal 7 + end + + it "takes into account reservertions from a block" do + @reservation_desk.make_block(room_ids:[7, 8, 9], start_date: "2020-3-4", end_date: "2020-3-8") + @reservation_desk.reserve_from_block(block_id: 1, room_id: 9) + + result = @reservation_desk.find_reservations(room_id: 9, start_date: "2020-3-1", end_date: "2020-3-30") + expect(result.length).must_equal 1 + + result_2 = @reservation_desk.find_reservations(start_date: "2020-3-1", end_date: "2020-3-30") + expect(result_2.length).must_equal 5 + end + + it "No ID provided: returns empty array if there are no reservations for the room/dates" do + result = @reservation_desk.find_reservations(room_id: 1, start_date: "2020-4-1", end_date: "2020-4-17") + expect(result.length).must_equal 0 + end + end + + describe "find_available_rooms" do + before do + @reservation_desk.rooms[0].reserve(start_date: "2020-3-1", end_date: "2020-3-5") + @reservation_desk.rooms[1].reserve(start_date: "2020-3-1", end_date: "2020-3-10") + @reservation_desk.rooms[2].reserve(start_date: "2020-3-1", end_date: "2020-3-25") + + @request = @reservation_desk.find_available_rooms(start_date: "2020-2-27", end_date: "2020-4-2") + end + + it "returns an Array" do + expect(@request).must_be_kind_of Array + end + + it "returns an Array of Rooms" do + expect(@request[0]).must_be_kind_of Hotel::Room + end + + it "returns an array of Rooms which don't have Reservations for requested dates" do + expect(@request.length).must_equal 17 + expect(@request[0].id).must_equal 4 + end + + it "returns nil if there are no Rooms available for requested dates" do + @reservation_desk.rooms.each do |room| + room.reserve(start_date: "2020-6-1", end_date: "2020-6-30") + end + search = @reservation_desk.find_available_rooms(start_date: "2020-6-5", end_date: "2020-6-10") + assert_nil search + end + end + + describe "make_reservation" do + it "ID provided: makes a new reservation and add it into the Room's reservations array" do + @reservation_desk.make_reservation(room_id: 5, start_date: "2020-5-5", end_date: "2020-5-7") + @reservation_desk.make_reservation(room_id: 5, start_date: "2020-6-5", end_date: "2020-6-7") + expect(@reservation_desk.rooms[4].reservations.length).must_equal 2 + expect(@reservation_desk.rooms[4].available?(start_date: "2020-5-5", end_date: "2020-5-6")).must_equal false + end + + it "ID provided: Raises an ArgumentError if ID is invalid" do + expect { + @reservation_desk.make_reservation(room_id: 999999, start_date: "2020-5-5", end_date: "2020-5-7") + }.must_raise ArgumentError + end + + it "No ID provided: reserves the first available room down the list for requested dates" do + @reservation_desk.rooms[0].reserve(start_date: "2020-3-1", end_date: "2020-3-5") + @reservation_desk.rooms[1].reserve(start_date: "2020-3-1", end_date: "2020-3-10") + + @request = @reservation_desk.make_reservation(start_date: "2020-3-4", end_date: "2020-3-15") + expect(@reservation_desk.rooms[2].reservations.length).must_equal 1 + expect(@reservation_desk.rooms[2].available?(start_date: "2020-3-1", end_date: "2020-3-5")).must_equal false + end + + it "No ID provided: raises an Exception if no rooms are available for requested dates" do + 20.times do + @reservation_desk.make_reservation(start_date: "2020-6-1", end_date: "2020-6-30") + end + expect { + @reservation_desk.make_reservation(start_date: "2020-6-1", end_date: "2020-6-30") + }.must_raise StandardError + end + + it "reserves a room at a default rate if no other specified" do + @reservation_desk.make_reservation(room_id: 1, start_date: "2020-5-5", end_date: "2020-5-7") + rate = @reservation_desk.rooms[0].reservations[0].rate + expect(rate).must_equal 200 + end + + it "reserves a room at a specified rate" do + @reservation_desk.make_reservation(room_id: 1, start_date: "2020-5-5", end_date: "2020-5-7", rate: 310.05) + rate = @reservation_desk.rooms[0].reservations[0].rate + expect(rate).must_equal 310.05 + end + end + + describe "make_block" do + it "Room IDs provided: it creates Reservations and adds them to requested rooms' block_participation array" do + @reservation_desk.make_block(room_ids: [1, 2, 3], start_date: "2020-9-1", end_date: "2020-9-10") + expect(@reservation_desk.rooms[0].block_participation.length).must_equal 1 + expect(@reservation_desk.rooms[1].block_participation.length).must_equal 1 + expect(@reservation_desk.rooms[2].block_participation.length).must_equal 1 + expect(@reservation_desk.rooms[3].block_participation.length).must_equal 0 + end + + it "Rooms IDs provided: it adds block information to the block hash" do + @reservation_desk.make_block(room_ids: [1, 2, 3], start_date: "2020-9-1", end_date: "2020-9-10") + expect(@reservation_desk.blocks.length).must_equal 1 + expect(@reservation_desk.blocks[1][:rooms].length).must_equal 3 + expect(@reservation_desk.blocks[1][:rooms][0]).must_be_kind_of Hotel::Room + end + + it "Rooms IDs provided: raises an ArgumentError if any of IDs are invalid" do + expect { + @reservation_desk.make_block(room_ids: [1, 2, "love"], start_date: "2020-9-1", end_date: "2020-9-10") + }.must_raise ArgumentError + end + + it "Rooms IDs provided: raises ArgumentError if the room_ids array includes less than 2 rooms" do + expect { + @reservation_desk.make_block(room_ids: [1], start_date: "2020-9-1", end_date: "2020-9-10") + }.must_raise ArgumentError + end + + it "Rooms IDs provided: raises ArgumentError if the room_ids array includes more than 5 rooms" do + expect { + @reservation_desk.make_block(room_ids: [1, 2, 3, 4, 5, 6], start_date: "2020-9-1", end_date: "2020-9-10") + }.must_raise ArgumentError + end + + it "Rooms IDs provided: it raises an Exception if any of the rooms are unavailable on requested dates" do + @reservation_desk.make_reservation(start_date: "2020-10-1", end_date: "2020-10-5") + + expect { + @reservation_desk.make_block(room_ids: [4, 5, 6, 7, 1], start_date: "2020-10-2", end_date: "2020-10-16") + }.must_raise StandardError + + @reservation_desk.make_block(room_ids: [1, 2, 3], start_date: "2020-9-1", end_date: "2020-9-10") + + expect { + @reservation_desk.make_block(room_ids: [4, 5, 6, 7, 1], start_date: "2020-9-2", end_date: "2020-9-5") + }.must_raise StandardError + end + + it "creates reservations with default rate if no discount specified" do + @reservation_desk.make_block(room_ids: [1, 2, 3], start_date: "2020-9-1", end_date: "2020-9-10") + rate = @reservation_desk.rooms[0].block_participation[0].rate + expect(rate).must_equal 200 + end + + it "creates reservations with a different rate if specified" do + @reservation_desk.make_block(room_ids: [1, 2, 3], start_date: "2020-9-1", end_date: "2020-9-10", rate: 150) + rate = @reservation_desk.rooms[0].block_participation[0].rate + expect(rate).must_equal 150 + end + end + + describe "reserve_from_block" do + before do + @reservation_desk.make_block(room_ids: [1, 2, 3, 4], start_date: "2020-9-1", end_date: "2020-9-10") + @reservation = @reservation_desk.reserve_from_block(room_id: 2, block_id: 1) + end + + it "returns true if reservation was successful" do + expect(@reservation).must_equal true + end + + it "raises ArgumentError if room ID was not valid or wasn't part of the block" do + expect { + @reservation_desk.reserve_from_block(room_id: 6, block_id: 1) + }.must_raise ArgumentError + end + + it "raises ArgumentError if the block ID is invalid" do + expect { + @reservation_desk.reserve_from_block(room_id: 6, block_id: 1000) + }.must_raise ArgumentError + end + + it "raises StandardError if the room has already been reserved" do + expect { + @reservation_desk.reserve_from_block(room_id: 2, block_id: 1) + }.must_raise StandardError + end + + it "adds the original block reservation for the room to reservations array" do + expect(@reservation_desk.rooms[0].reservations.length).must_equal 0 + @reservation_desk.reserve_from_block(room_id: 1, block_id: 1) + expect(@reservation_desk.rooms[0].reservations.length).must_equal 1 + end + end + + describe "check_block_availability" do + before do + @reservation_desk.make_block(room_ids: [1, 2, 3, 4, 5], start_date: "2020-9-1", end_date: "2020-9-10") + @reservation_desk.reserve_from_block(room_id: 3, block_id: 1) + end + + it "returns an Array" do + expect(@reservation_desk.check_block_availability(1)).must_be_kind_of Array + end + + it "returns an array of unreserved rooms in requested block" do + expect(@reservation_desk.check_block_availability(1).length).must_equal 4 + end + + it "returns empty array if no rooms are available" do + @reservation_desk.reserve_from_block(room_id: 1, block_id: 1) + @reservation_desk.reserve_from_block(room_id: 2, block_id: 1) + @reservation_desk.reserve_from_block(room_id: 4, block_id: 1) + @reservation_desk.reserve_from_block(room_id: 5, block_id: 1) + expect(@reservation_desk.check_block_availability(1).empty?).must_equal true + end + + it "throws an ArgumentError if there is no block with a given ID" do + expect { + @reservation_desk.reserve_from_block(room_id: 1, block_id: 2) + }.must_raise ArgumentError + + expect { + @reservation_desk.reserve_from_block(room_id: 1, block_id: "Nataliya") + }.must_raise ArgumentError + end + end +end \ No newline at end of file diff --git a/test/reservation_test.rb b/test/reservation_test.rb new file mode 100644 index 000000000..19ec211e1 --- /dev/null +++ b/test/reservation_test.rb @@ -0,0 +1,63 @@ +require_relative "test_helper" + +describe "Reservation class" do + before do + @room_id = 1 + @start_date = "2020-4-1" + @end_date = "2020-4-5" + @reservation = Hotel::Reservation.new(room_id: @room_id, start_date: @start_date, end_date: @end_date) + end + + describe "Reservation instatiation" do + it "is an instance of reservation" do + expect(@reservation).must_be_kind_of Hotel::Reservation + end + + it "has date_range variable which holds an instance of DateRange" do + expect(@reservation.date_range).must_be_kind_of Hotel::DateRange + end + + it "has a rate of 200 if no argument provided" do + expect(@reservation.rate).must_equal 200 + end + + it "can be instantiated with a different rate" do + reservation = Hotel::Reservation.new(room_id: 2, start_date: "2020-5-1", end_date: "2020-5-6", rate: 210) + expect(reservation.rate).must_equal 210 + end + + it "zero rate is fine" do + reservation = Hotel::Reservation.new(room_id: 2, start_date: "2020-5-1", end_date: "2020-5-6", rate: 0) + expect(reservation.rate).must_equal 0 + end + + it "raises an Argument error if rate provided is invalid (not a number)" do + expect { + reservation = Hotel::Reservation.new(room_id: 2, start_date: "2020-5-1", end_date: "2020-5-6", rate: "Cody") + }.must_raise ArgumentError + end + + it "raises an Argument error if rate provided is smaller than 0" do + expect { + reservation = Hotel::Reservation.new(room_id: 2, start_date: "2020-5-1", end_date: "2020-5-6", rate: -1) + }.must_raise ArgumentError + end + end + + describe "cost" do + it "returns an integer" do + expect(@reservation.cost).must_be_kind_of Integer + end + + it "calculates cost at Reservation's rate" do + expect(@reservation.cost).must_equal 800 + + room_id = 1 + start_date = "2020-5-1" + end_date = "2020-5-5" + rate = 180 + reservation = Hotel::Reservation.new(room_id: room_id, start_date: start_date, end_date: end_date, rate: rate) + expect(reservation.cost).must_equal 720 + end + end +end \ No newline at end of file diff --git a/test/room_test.rb b/test/room_test.rb new file mode 100644 index 000000000..8643ddb02 --- /dev/null +++ b/test/room_test.rb @@ -0,0 +1,116 @@ +require_relative 'test_helper' + +describe "Room Class" do + describe "Room instantiation" do + before do + @room = Hotel::Room.new(1) + end + + it "is an instance of Room" do + expect(@room).must_be_kind_of Hotel::Room + end + + it "stores an id" do + expect(@room.id).must_equal 1 + end + + it "starts with an empty array for reservations" do + expect(@room.reservations).must_be_kind_of Array + expect(@room.reservations.empty?).must_equal true + end + + it "starts with an empty array for block participation" do + expect(@room.block_participation).must_be_kind_of Array + expect(@room.block_participation.empty?).must_equal true + end + end + + describe "reserved?" do + before do + @room = Hotel::Room.new(1) + @room.reserve(start_date: "2020-3-1", end_date: "2020-3-10") + end + + it "returns true if the room is reserved for requested dates" do + expect(@room.reserved?(start_date: "2020-3-2", end_date: "2020-3-25")).must_equal true + end + + it "returns false if the room is not reserved for requested dates" do + expect(@room.reserved?(start_date: "2020-3-22", end_date: "2020-3-25")).must_equal false + end + end + + describe "in_block?" do + before do + @room = Hotel::Room.new(1) + @room.reserve(start_date: "2020-3-1", end_date: "2020-3-10", block: 2) + end + + it "returns true if the room is in a block for requested dates" do + expect(@room.in_block?(start_date: "2020-3-2", end_date: "2020-3-25")).must_equal true + end + + it "returns false if the room is not in a block for requested dates" do + expect(@room.in_block?(start_date: "2020-3-22", end_date: "2020-3-25")).must_equal false + end + end + + describe "available?" do + before do + @room = Hotel::Room.new(1) + @room.reserve(start_date: "2020-3-1", end_date: "2020-3-10") + end + + it "returns true if the room is available for requested dates" do + expect(@room.available?(start_date: "2020-3-22", end_date: "2020-3-25")).must_equal true + end + + it "returns false if the room is unavailable for requested dates" do + expect(@room.available?(start_date: "2020-3-2", end_date: "2020-3-5")).must_equal false + end + end + + describe "reserve" do + it "creates a new reservation and add it to the Room's reservations array" do + @room = Hotel::Room.new(10) + @room.reserve(start_date: "2020-3-1", end_date: "2020-3-10") + expect(@room.reservations.length).must_equal 1 + expect(@room.reservations[0]).must_be_kind_of Hotel::Reservation + expect(@room.reservations[0].room_id).must_equal 10 + end + + it "reserves a room at default rate if no other specified" do + room = Hotel::Room.new(10) + room.reserve(start_date: "2020-3-1", end_date: "2020-3-10") + rate = room.reservations[0].rate + expect(rate).must_equal 200 + end + + it "reserves room at a specified rate" do + room = Hotel::Room.new(10) + room.reserve(start_date: "2020-3-1", end_date: "2020-3-10", rate: 339.99) + rate = room.reservations[0].rate + expect(rate).must_equal 339.99 + end + end + + describe "select_reservations" do + before do + @room = Hotel::Room.new(10) + @room.reserve(start_date: "2020-3-1", end_date: "2020-3-10") + @room.reserve(start_date: "2020-3-12", end_date: "2020-3-13") + @room.reserve(start_date: "2020-3-15", end_date: "2020-3-20") + + end + it "returnes reservations which match requested date range" do + date_range = Hotel::DateRange.new(start_date: "2020-3-1", end_date: "2020-3-25") + expect(@room.select_reservations(date_range).length).must_equal 3 + end + + it "returns empty array if no reservations were made for requested dates" do + date_range = Hotel::DateRange.new(start_date: "2020-4-1", end_date: "2020-4-25") + expect(@room.select_reservations(date_range).empty?).must_equal true + end + end +end + diff --git a/test/test_helper.rb b/test/test_helper.rb index c3a7695cf..4896bd827 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,4 +1,7 @@ -# Add simplecov +require 'simplecov' +SimpleCov.start do + add_filter 'test/' +end require "minitest" require "minitest/autorun" require "minitest/reporters" @@ -6,3 +9,7 @@ Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new # require_relative your lib files here! +require_relative "../lib/room" +require_relative "../lib/reservation_desk" +require_relative "../lib/reservation" +require_relative "../lib/date_range" \ No newline at end of file