diff --git a/lib/date_range.rb b/lib/date_range.rb new file mode 100644 index 000000000..dac2a8fa9 --- /dev/null +++ b/lib/date_range.rb @@ -0,0 +1,39 @@ +module Hotel + class DateRange + attr_accessor :start_date, :end_date + + def initialize(start_date, end_date) + if !(start_date.is_a? Date) || !(end_date.is_a? Date) + raise ArgumentError.new("If the start_date and end_date is not a Date") + end + + if end_date < start_date + raise ArgumentError.new("If the start_date is biger then the end_date") + end + + if start_date == end_date + raise ArgumentError.new("If the start_date date is same with end_date") + end + + @start_date = start_date + @end_date = end_date + end + + def ==(other) + start_date == other.start_date && end_date == other.end_date + end + + def overlap?(other) + start_date < other.end_date && other.start_date < end_date + end + + def include?(date) + start_date <= date && date < end_date + end + + def calculate_nights + nights = (end_date - start_date).to_i + return nights + end + end +end \ No newline at end of file diff --git a/lib/hotel_controller.rb b/lib/hotel_controller.rb new file mode 100644 index 000000000..1af905526 --- /dev/null +++ b/lib/hotel_controller.rb @@ -0,0 +1,71 @@ +require_relative "room" +require_relative "date_range" +require_relative "reservation" +require_relative "no_room_available" + + +module Hotel + class HotelController + attr_accessor :reservations + attr_reader :rooms + + def initialize + @rooms = Array.new(20){|i| Hotel::Room.new(i+1)} + @reservations = [] + end + + #I can access the list of reservations for a specific date, so that I can track reservations by date + def reservation(date) + result = [] + @reservations.each do |reservation| + if reservation.date_range.include?(date) + result << reservation + end + end + return result + end + + # Cost for giving reservation + def total_cost(reservation) + total_cost = reservation.cost + return total_cost + end + + #Make new reservation + def reserve_room(start_date, end_date) + avalable_room = available_rooms(start_date, end_date) + raise NoRoomAvailable.new ("No room available") if avalable_room == [] + + new_restervation = Hotel::Reservation.new(start_date, end_date, avalable_room.first) + reservations << new_restervation + return new_restervation + end + + #I access the list of reservations for a specified room and a given date range + def reservations_for_room(date_range, room) + result = [] + reservations.each do |reservation| + if reservation.date_range.overlap?(date_range) && room.room_nr == reservation.room.room_nr + result << reservation + end + end + return result + end + + # Avalable rooms + def available_rooms(start_date, end_date) + unavalable_room = [] + another_range = Hotel::DateRange.new(start_date, end_date) + + @reservations.each do |reservation| + if reservation.date_range.overlap?(another_range) + unavalable_room << reservation.room + end + end + + avalable_room = @rooms - unavalable_room + return avalable_room + end + + end +end diff --git a/lib/no_room_available.rb b/lib/no_room_available.rb new file mode 100644 index 000000000..37187aadd --- /dev/null +++ b/lib/no_room_available.rb @@ -0,0 +1,4 @@ +module Hotel + class NoRoomAvailable < StandardError + end +end \ No newline at end of file diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..d76a935a3 --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,21 @@ +require_relative "date_range" +require_relative "room" + + +module Hotel + class Reservation + + # Feel free to change this method signature as needed. Make sure to update the tests! + attr_reader :id, :date_range, :room + def initialize(start_date, end_date, room) + @date_range = Hotel::DateRange.new(start_date, end_date) + @room = room + end + + def cost + total = date_range.calculate_nights * 200.00 + return total + 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..e74ca7f7f --- /dev/null +++ b/lib/room.rb @@ -0,0 +1,15 @@ + +module Hotel + class Room + attr_reader :room_nr, :cost + def initialize(room_nr, cost = 200) + @room_nr = room_nr + @cost = cost + end + end + + # def ==(other) + # room_nr == other.room_nr + # end + +end \ 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..85d554bcb --- /dev/null +++ b/test/date_range_test.rb @@ -0,0 +1,170 @@ +require_relative "test_helper" + +describe Hotel::DateRange do + + describe "consructor" do + + it "Creates an instance of date_range" do + start_date = Date.new(2020, 01, 20) + end_date = Date.new(2020, 01, 25) + date_range = Hotel::DateRange.new(start_date, end_date) + date_range.must_be_kind_of Hotel::DateRange + end + + it "Keeps track of start_date and end_date" do + start_date = Date.today + end_date = start_date + 3 + + range = Hotel::DateRange.new(start_date, end_date) + + expect(range).must_respond_to :start_date + expect(range.start_date).must_equal start_date + expect(range).must_respond_to :end_date + expect(range.end_date).must_equal end_date + end + + it " Rais an argument ArgumentError if end_date is smaller then a start date" do + start_date = Date.today + end_date = Date.today - 3 + expect{Hotel::DateRange.new(start_date, end_date)}.must_raise ArgumentError + end + + it "is an an error for negative-lenght ranges" do + start_date = Date.today -5 + end_date = Date.today + expect{Hotel::DateRange.new(start_date, end_date)}.must_raise ArgumentError + + end + + it "is an error to create a 0-length range" do + start_date = Date.today + end_date = Date.today + expect{Hotel::DateRange.new(start_date, end_date)}.must_raise ArgumentError + end + + it "is an error if the start and end date are not the Date" do + start_date = Date.today + 10 + end_date = Date.today + 15 + expect{Hotel::DateRange.new("2020/03/25", end_date)}.must_raise ArgumentError + expect{Hotel::DateRange.new(start_date, 20200325)}.must_raise ArgumentError + end + end + + describe "==other" do + before do + start_date = Date.today + 5 + end_date = start_date + 3 + @range = Hotel::DateRange.new(start_date, end_date) + end + it "returne true if other start_date is not equal with start_date" do + start_date = @range.start_date + end_date = @range.end_date + test_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.==(test_range)).must_equal true + end + + it "returne false if other start_date is not equal with start_date" do + start_date = Date.today + end_date = Date.today + 3 + test_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.==(test_range)).must_equal false + end + end + + describe "overlap?" do + before do + start_date = Date.today + 5 + end_date = start_date + 3 + @range = Hotel::DateRange.new(start_date, end_date) + end + it "returns true for the same range" do + start_date = @range.start_date + end_date = @range.end_date + test_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(test_range)).must_equal true + end + it "returns true for a contained range" do + start_date = Date.today + 3 + end_date = start_date + 9 + test_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(test_range)).must_equal true + end + it "returns true for a range that overlaps in front" do + start_date = Date.today + 3 + end_date = start_date + 6 + test_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(test_range)).must_equal true + end + it "returns true for a range that overlaps in the back" do + start_date = Date.today + 6 + end_date = start_date + 4 + test_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(test_range)).must_equal true + end + it "returns true for a containing range" do + start_date = Date.today + 6 + end_date = start_date + 1 + test_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(test_range)).must_equal true + end + it "returns false for a range starting on the end_date date" do + start_date = Date.today + 8 + end_date = start_date + 2 + test_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(test_range)).must_equal false + end + it "returns false for a range ending on the start_date date" do + start_date = Date.today + 1 + end_date = start_date + 4 + test_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(test_range)).must_equal false + end + it "returns false for a range completely before" do + start_date = Date.today + 9 + end_date = start_date + 3 + test_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(test_range)).must_equal false + end + it "returns false for a date completely after" do + start_date = Date.today + 1 + end_date = start_date + 2 + test_range = Hotel::DateRange.new(start_date, end_date) + expect(@range.overlap?(test_range)).must_equal false + end + end + + + describe "include?" do + before do + start_date = Date.new(2017, 02, 15) + end_date = start_date + 3 + @range = Hotel::DateRange.new(start_date, end_date) + end + it "reutrns false if the date is clearly out" do + date = Date.new(2017, 03, 15) + expect(@range.include?(date)).must_equal false + end + + it "returns true for dates in the range" do + date = Date.new(2017, 02, 17) + expect(@range.include?(date)).must_equal true + end + + it "returns false for the end_date date" do + date = Date.new(2017, 02, 18) + expect(@range.include?(date)).must_equal false + end + end + + describe "calculate nights" do + it "returns the correct number of nights" do + start_date = Date.today + end_date = start_date + 3 + + range = Hotel::DateRange.new(start_date, end_date) + + expect(range.calculate_nights).must_equal 3 + expect(range.calculate_nights).must_be_kind_of Integer + end + end +end \ No newline at end of file diff --git a/test/hotel_controller_test.rb b/test/hotel_controller_test.rb new file mode 100644 index 000000000..d86b603ef --- /dev/null +++ b/test/hotel_controller_test.rb @@ -0,0 +1,123 @@ +require_relative "test_helper" + +describe Hotel::HotelController do + before do + @hotel_controller = Hotel::HotelController.new + @date = Date.parse("2020-08-04") + @rooms = Array.new(20){|i| Hotel::Room.new(i+1)} + end + describe "wave 1" do + describe "initializer" do + it "Creates an instance of hotel controler" do + @hotel_controller.must_be_kind_of Hotel::HotelController + end + + it "create the rooms" do + rooms = @hotel_controller.rooms + expect(rooms).must_be_kind_of Array + end + + it "create 20 rooms" do + rooms = @hotel_controller.rooms + expect(rooms.length).must_equal 20 + end + + it "create an empty array for reservatios" do + reservations = @hotel_controller.reservations + expect(reservations).must_equal [] + end + end + + describe "reservations" do + it "takes a Date and returns a list of Reservations" do + reservation_list = @hotel_controller.reservation(@date) + expect(reservation_list).must_be_kind_of Array + reservation_list.each do |res| + res.must_be_kind_of Hotel::Reservation + end + end + end + + describe "total_cost" do + it "takes a reservation and returns the cost for that reservation" do + today = Date.today + room_one = @hotel_controller.rooms.first + + new_reservation = Hotel::Reservation.new(today + 6, today + 9, room_one) + + total_cost_for_reservation = @hotel_controller.total_cost(new_reservation) + expect(total_cost_for_reservation).must_be_kind_of Numeric + + end + end + + + describe "reserve_room" do + it "takes two Date objects and returns a Reservation" do + today = Date.today + + new_reservation = @hotel_controller.reserve_room(today + 6, today + 9) + expect(new_reservation).must_be_kind_of Hotel::Reservation + end + + it "is an NoRoomAvalable if avalable_room is nil" do + start_date = Date.new(2020, 4, 10) + end_date = Date.new(2020, 4, 12) + room_number = 0 + while room_number < 20 do + @hotel_controller.reserve_room(start_date, end_date) + room_number += 1 + end + + #avalable_room = @hotel_controller.reserve_room(start_date, end_date) + expect{(@hotel_controller.reserve_room(start_date, end_date))}.must_raise Hotel::NoRoomAvailable + end + end + + describe "reservations_for" do + it "takes a date_range and room returns a list of Reservations" do + today = Date.today + room_one = Hotel::Room.new(1) + room_two = Hotel::Room.new(2) + + reservation = Hotel::Reservation.new(today + 6, today + 9, room_one) + + @hotel_controller.reservations = [ + Hotel::Reservation.new(today + 1, today + 2, room_one), + Hotel::Reservation.new(today + 6, today + 9, room_two), + reservation, + Hotel::Reservation.new(today + 10, today + 13, room_one) + ] + + reservation_list = @hotel_controller.reservations_for_room(Hotel::DateRange.new(today + 5, today + 9), room_one) + expect(reservation_list).must_be_kind_of Array + expect(reservation_list).must_equal [reservation] + + end + end + + describe "wave 2" do + describe "available_rooms" do + it "takes two dates and returns a list" do + start_date = Date.new(2020, 4, 10) + end_date = Date.new(2020, 4, 12) + + room_one = @hotel_controller.rooms[0] + room_two = @hotel_controller.rooms[1] + + + @hotel_controller.reservations = [ + Hotel::Reservation.new(start_date, end_date, room_one), + Hotel::Reservation.new(start_date, end_date, room_two), + ] + + room_list = @hotel_controller.available_rooms(start_date + 1 , end_date + 1) + + expect(room_list).must_be_kind_of Array + expect(room_list.length).must_equal 18 + expect(room_list[-1].room_nr).must_equal 20 + end + end + 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..cb0cc280c --- /dev/null +++ b/test/reservation_test.rb @@ -0,0 +1,36 @@ +require_relative "test_helper" + +describe Hotel::Reservation do + describe "consructor" do + + it "Creates an instance of reservation" do + reservation = Hotel::Reservation.new(Date.today, Date.today + 1, Hotel::Room.new(1)) + reservation.must_be_kind_of Hotel::Reservation + end + + it "Keeps track of date_range" do + start_date = Date.today + end_date = Date.today + 1 + date_range = Hotel::DateRange.new(start_date, end_date) + + reservation = Hotel::Reservation.new(start_date, end_date, Hotel::Room.new(1)) + reservation.must_respond_to :date_range + reservation.date_range.must_equal date_range + end + + end + + describe "cost" do + it "returns a number" do + start_date = Date.today + end_date = start_date + 3 + room = Hotel::Room.new(1, 200) + + @reservation = Hotel::Reservation.new(start_date, end_date, room) + + expect(@reservation.cost).must_be_kind_of Numeric + expect(@reservation.cost).must_equal 600 + end + end + +end \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb index c3a7695cf..93fef04f8 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,8 +1,21 @@ # Add simplecov +require 'simplecov' +SimpleCov.start do + add_filter 'test/' # Tests should not be checked for coverage. +end + require "minitest" require "minitest/autorun" require "minitest/reporters" +require "minitest/skip_dsl" Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new # require_relative your lib files here! +require_relative "../lib/hotel_controller.rb" +require_relative "../lib/reservation.rb" +require_relative "../lib/date_range.rb" +require_relative "../lib/room.rb" +require_relative "../lib/no_room_available.rb" + + diff --git a/test/test_room.rb b/test/test_room.rb new file mode 100644 index 000000000..fb2cd7771 --- /dev/null +++ b/test/test_room.rb @@ -0,0 +1,26 @@ +require_relative "test_helper" + + +describe Hotel::Room do + describe "consructor" do + + it "Creates an instance of room" do + room = Hotel::Room.new(1, 200) + room.must_be_kind_of Hotel::Room + end + + it "Keeps track of room nr" do + room_nr = 1 + room = Hotel::Room.new(room_nr, 200) + room.must_respond_to :room_nr + room.room_nr.must_equal room_nr + end + + it "Keeps track of cost" do + cost = 200 + room = Hotel::Room.new(1, cost) + room.must_respond_to :cost + room.cost.must_equal cost + end + end +end