diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..1a69ece39 Binary files /dev/null and b/.DS_Store differ diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..deb52f2cd --- /dev/null +++ b/Rakefile @@ -0,0 +1,9 @@ +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.libs = ["lib"] + t.warning = true + 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..cb63f1a7b --- /dev/null +++ b/design-activity.md @@ -0,0 +1,82 @@ +# Hotel Revisited + +## Prompts: Responses + +* What classes does each implementation include? Are the lists the same? + +While both implementations A & B have the following classes: CartEntry, ShoppingCart, their list of classes are not the same. Implementation A's CartEntry class uses attr accessors for its unit_price and quantity, so its Order class can access those values when calculating the total price for each entry in the cart. Implementation B on the other hand does not use attr accessors and instead, has a price calculation method for each class such that: CartEntry has a price method to calculate each price per cart entry, the ShoppingCart has a price method to sum all cart entries in the cart (subtotal), and Order has a total_price method that adds SALES_TAX to the ShoppingCart's subtotal. + +* Write down a sentence to describe each class. + * CartEntry defines the state (unit_price and quantity) and behavior (price in implementation B) of each cart entry requested. + * ShoppingCart defines the ShoppingCart object that's initialized as an array to store cart entries for one order. + * Order creates an order (initialized as an instance of a ShoppingCart) and handles total_price calculation (using the SALES_TAX). + +* How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper. + +The classes relate to each in that an instance of an Order is made up of an instance of a ShoppingCart (called cart), where the cart is an array that stores any number of CartEntry instances. + +* What data does each class store? How (if at all) does this differ between the two implementations? +* What methods does each class have? How (if at all) does this differ between the two implementations? + + * Implementation A: + CartEntry: unit_price and quantity (with attr accessors) + ShoppingCart: entries (array - with attr accessors) + Order: SALES_TAX, total_price method + + * Implementation B: + CartEntry: unit_price, quantity, CartEntry price method + ShoppingCart: entries (array - no attr accessors), ShoppingCart subtotal price method + Order: SALES_TAX, total_price method + + * Differences: + - Implementation A delegates all price calculation to the Order class, while B has some level of price calculated within each class. + - Implementation A makes use of attr accessors (interestingly rather than attr readers) and only uses one pricing method (total_price) in the Order class. Conversely, B does not us any attr accessors (I'm assuming to limit users ability to manipulate CartEntry data) and implements a price method for both CartEntry and ShoppingCart to access each objects' prices. + +* 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 does not delegate the price computation responsibility to "lower level" classes; it is all retained in Order. B does delegate price computation to ShoppingCart and CartEntry so that its Order class only deals with adding the SALES_TAX to the ShoppingCart price. + + * Does total_price directly manipulate the instance variables of other classes? + A's total_price directly references the instance variables for the ShoppingCart (entries) and CartEntry (unit_price and quantity), but it takes their values and stores it in the variable sum. So in that way, while it is not directly changing the variables, there is potential to manipulate them because they are being accessed using attr accessors. B only references the ShoppingCart price (using the price method), so this implementation does not directly manipulate any instance variables. + +* If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify? + +Implementation B would be easier to change because you could add additional code in CartEntry to account for cheaper cost when buying items in bulk. + +* Which implementation better adheres to the single responsibility principle? + +Implementation B appears to better adhere to the single responsibility principle because its classes (particularly Order and its total_price method) have less dependencies on its other classes. For example, it doesn't know/reference nearly as many objects and instance variables as A does in its total_price method. This is ideal because it reduces the potential for bugs and makes the code more adaptable. + +Furthermore, before considering how we'd modify the code to consider bulk items, I thought A good in that it appeared DRY because it was consolidating and delegating all price calculations in Order (so you could just update price calculations all in one place), but now that I've had to also consider buying items in bulk and potential areas of price changes, it makes sense to break up the price calculation responsibilities. + +* Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? +Implementation B is more loosely coupled because its Order class does not reference and knows less about the other classes (e.g. it doesn't reference any CartEntry objects like A). + + +## Revisiting Hotel Activity: + +HotelAdmin is currently tightly coupled with my block and reservation classes. For example, I had date validation for reservations made in both my HotelAdmin and Reservation. I've changed it so now only my Reservation class handles date validation. Previously, I'd also planned for the HotelAdmin class to check if a block would conflict with an existing reservation before attempting to create the block. To decouple this area of logic, now the HotelAdmin class just creates a block while the block class performs the validation to decide if there is a conflict with an existing reservation. + + + + + + + + + + + + + + + + + + + + + + + +######## diff --git a/guest.rb b/guest.rb new file mode 100644 index 000000000..8ee0603f0 --- /dev/null +++ b/guest.rb @@ -0,0 +1,15 @@ +module BookingSystem + class Guest + + attr_reader :first_name, :last_name + + def initialize(first_name, last_name) + raise ArgumentError.new("first name must be a string") if !first_name.is_a? String + @first_name = first_name + + raise ArgumentError.new("last name must be a string") if !last_name.is_a? String + @last_name = last_name + end + + end#of_Guest_class +end#of_module_BookingSystem diff --git a/guest_spec.rb b/guest_spec.rb new file mode 100644 index 000000000..3a5c99360 --- /dev/null +++ b/guest_spec.rb @@ -0,0 +1,25 @@ +require_relative 'spec_helper' + +describe "Guest" do + before do + @guest_test = BookingSystem::Guest.new("Jane", "Doe") + end + + describe "initialize" do + it "can create an instance of Guess class" do + @guest_test.class.must_equal BookingSystem::Guest + end + + it "can access a guest's first name and last name" do + @guest_test.first_name.must_equal "Jane" + @guest_test.last_name.must_equal "Doe" + end + + it "ensures first name and last name are strings" do + proc { BookingSystem::Guest.new([], "Doe") }.must_raise ArgumentError + proc { BookingSystem::Guest.new("Jane", 2) }.must_raise ArgumentError + end + + end + +end#_of_"Guest" diff --git a/lib/.keep b/lib/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/lib/BookingSystem_Errors.rb b/lib/BookingSystem_Errors.rb new file mode 100644 index 000000000..9fced9b35 --- /dev/null +++ b/lib/BookingSystem_Errors.rb @@ -0,0 +1,11 @@ +class UnavailableRoomError < StandardError +end + +class InvalidDateRangeError < StandardError +end + +class InvalidDateError = date_range.last || reservation.end_date <= date_range.first) + reservation.date_range.overlaps?(date_range) && date_range.first < reservation.end_date + } + + raise ArgumentError.new("Block ID must be a string") if !block_id.is_a? String + @block_id = block_id + + raise InvalidDateRangeError.new("Date range must be a DateRange object") if !date_range.is_a? DateRange + @date_range = date_range + + raise ArgumentError.new("Rooms collection must be an Array") if !rooms_array.is_a? Array + raise BlockError.new("Rooms array cannot have more than 5 rooms") if rooms_array.length > 5 + @rooms_array = rooms_array + + raise ArgumentError.new("Room rate discount must be a float") if !discount_room_rate.is_a? Float + @discount_room_rate = discount_room_rate + end + + def list_room_ids + room_ids = @rooms_array.map { |room| room.id } + return room_ids + end + + end#of_Block_class +end#of_module_BookingSystem diff --git a/lib/hotel_admin.rb b/lib/hotel_admin.rb new file mode 100644 index 000000000..14059240f --- /dev/null +++ b/lib/hotel_admin.rb @@ -0,0 +1,133 @@ +require 'date' +require 'date_range' +require_relative 'room' +require_relative 'reservation' +require_relative 'BookingSystem_Errors' + +module BookingSystem + class HotelAdmin + + attr_reader :room_list, :reservation_list, :block_list + + def initialize + #hotel admin knows all reservations (non-block and block) + @reservation_list = [] + @block_list = [] + #hotel admin knows all rooms in hotel + @room_list = BookingSystem::Room.all + end + + def reserve_room(first_name, last_name, room_id, room_rate, start_date, end_date, block_id = nil) + + requested_range = DateRange.new(start_date, end_date) + + if block_id.nil? #if a room doesn't have a block_id, blacklist all rooms that are blocked + raise UnavailableRoomError.new("Room is unavailable") if @block_list.any? do |block| + block.date_range.overlaps?(requested_range) && block.rooms_array.any? { |room| room.id == room_id } + end + end + + raise UnavailableRoomError.new("Room is unavailable") if @reservation_list.any? {|reservation| + reservation.room_id == room_id && reservation.date_range.overlaps?(requested_range) && start_date < reservation.end_date + #overlaps? same as: + # reservation.room_id == room_id && + # !(reservation.start_date >= end_date || reservation.end_date <= start_date) + } + + reservation = BookingSystem::Reservation.new(first_name, last_name, room_id, room_rate, start_date, end_date, block_id) + @reservation_list << reservation + end + + # Hotel Revisted Changes + def reserve_block(block_id, date_range, rooms_array, discount_room_rate, reservation_list) + + if @block_list.any? { |block| block.date_range.overlaps?(date_range) } + @block_list.each do |block| + rooms_array.each do |room| + if block.list_room_ids.include?(room.id) + raise UnavailableRoomError.new("Room is unavailable") + end + end + end + end + + block = BookingSystem::Block.new(block_id, date_range, rooms_array, discount_room_rate, reservation_list) + @block_list << block + end + + def find_reservations_by_date(specific_date) + reservations_on_date = [] + @reservation_list.each do |reservation| + if reservation.date_range.include?(specific_date) + reservations_on_date << reservation + end + end + + return reservations_on_date + end + + def rooms_available_for_date_range(date_range) + + raise InvalidDateRangeError.new("Range must be a DateRange object") if !date_range.is_a? DateRange + + unavailable_room_ids = [] + + @reservation_list.each do |reservation| + if reservation.date_range.overlaps?(date_range) + unavailable_room_ids << reservation.room_id + end + end + + available_rooms = @room_list.reject { |room| unavailable_room_ids.include?(room.id) } + + return available_rooms + end + + end#of_HotelAdmin_class +end#of_module_BookingSystem + + + + + + + + + + + +# REFACTORED METHODS: +# def rooms_available_for_date_range(date_range) +# raise InvalidDateRangeError.new("Range must be a DateRange object") if !date_range.is_a? DateRange +# +# unavailable_room_ids = [] +# +# @reservation_list.each do |reservation| +# if reservation.date_range.include?(date_range) +# unavailable_room_ids << reservation.room_id +# end +# end +# +# available_rooms = [] +# +# @room_list.each do |room| +# if unavailable_room_ids.include?(room.id) == false +# available_rooms << room +# end +# end +# +# return available_rooms +# end + + + + +=begin +Date notes: + +< +source: https://stackoverflow.com/questions/3296539/comparision-of-date-in-ruby + +.between?(start_date, end_date) +source: https://stackoverflow.com/questions/4521921/how-to-know-if-todays-date-is-in-a-date-range +=end diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..b6a304b99 --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,60 @@ +require 'date' +require 'date_range' + +module BookingSystem + class Reservation + attr_reader :first_name, :last_name, :room_id, :room_rate, :start_date, :end_date, :total_cost, :date_range + + def initialize(first_name, last_name, room_id, room_rate, start_date, end_date, block_id = nil) + + @first_name = first_name + @last_name = last_name + + @room_id = room_id + @room_rate = room_rate + + raise InvalidDateError.new("Start date is not a valid date object") if !start_date.is_a? Date + @start_date = start_date + + raise InvalidDateError.new("End date is not a valid date object") if !end_date.is_a? Date + @end_date = end_date + + @date_range = get_date_range + @total_cost = get_total_cost + end + + def get_total_cost + date_diff = @end_date - @start_date + grand_total = date_diff * @room_rate + return grand_total + end + + def get_date_range + raise InvalidDateRangeError.new("Invalid date range") if @end_date <= @start_date #if end_date is older or equal to start_date, raise error + range = DateRange.new(@start_date, @end_date) + return range + end + + end#of_Reservation_class +end#of_module_BookingSystem + + + + + + + + + + + +=begin +NOTES: +#DATE RANGE METHOD (VERSION1) +# def make_date_range_array +# return (@start_date .. @end_date).map{|day| day} +# end +#Modify: @date_range = make_date_range_array + +#OUTPUTS: an array of the date range +=end diff --git a/lib/room.rb b/lib/room.rb new file mode 100644 index 000000000..768e73fe2 --- /dev/null +++ b/lib/room.rb @@ -0,0 +1,34 @@ +require 'csv' + +module BookingSystem + class Room + attr_accessor :id, :cost + + def initialize(id, cost) + @id = id + @cost = cost + end + + def self.all + room_info = CSV.read('./support/rooms.csv', converters: :numeric) + + all_rooms = [] + room_info.each do |row| + id = row[0] + cost = row[1] + all_rooms << Room.new(id, cost) + end + + return all_rooms + end + + end#of_Reservation_class +end#of_module_BookingSystem + +#TESTING +# Hotel::Room.all #will access the list of all of the rooms in the hotel + +#Jans-MBP:hotel janedrozo$ ruby lib/room.rb + +#SPEC TESTING +#Jans-MBP:hotel janedrozo$ rake diff --git a/specs/.keep b/specs/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/specs/block_spec.rb b/specs/block_spec.rb new file mode 100644 index 000000000..99bd1e578 --- /dev/null +++ b/specs/block_spec.rb @@ -0,0 +1,46 @@ +require_relative 'spec_helper' +require 'date_range' + +describe "Block Class" do + + describe "#initialize" do + before do + @block_id = "Block1" + @date_range = DateRange.new(Date.new(2017, 9, 1), Date.new(2017, 9, 5)) + @rooms_array = [ + BookingSystem::Room.new(1, 200.00), + BookingSystem::Room.new(2, 200.00), + BookingSystem::Room.new(3, 200.00), + BookingSystem::Room.new(4, 200.00), + BookingSystem::Room.new(5, 200.00)] + @discount_room_rate = 0.20 + @reservation_list = [] + + @block = BookingSystem::Block.new(@block_id, @date_range, @rooms_array, @discount_room_rate, @reservation_list) + end + + it "can create a block of rooms using a date range, collection of rooms and a discounted room rate" do + @block.must_be_instance_of BookingSystem::Block + end + + it "ensures block_id argument is a String" do + proc { BookingSystem::Block.new(12345, @date_range, @rooms_array, @discount_room_rate, @reservation_list) }.must_raise ArgumentError + end + + it "ensures date range argument is a DateRange object" do + proc { BookingSystem::Block.new(@block_id, "date_range", @rooms_array, @discount_room_rate, @reservation_list) }.must_raise InvalidDateRangeError + end + + it "ensures collection of rooms argument is an array" do + proc { BookingSystem::Block.new(@block_id, @date_range, "rooms_array", @discount_room_rate, @reservation_list) }.must_raise ArgumentError + end + + it "ensures collection of rooms argument array length cannot be greater than 5" do + proc { BookingSystem::Block.new(@block_id, @date_range, [1, 2, 3, 4, 5, 6], @discount_room_rate, @reservation_list) }.must_raise BlockError + end + + it "ensures room discount argument is a float" do + proc { BookingSystem::Block.new(@block_id, @date_range, @rooms_array, "discount_room_rate", @reservation_list) }.must_raise ArgumentError + end + end +end#of_"Block Class" diff --git a/specs/hotel_admin_spec.rb b/specs/hotel_admin_spec.rb new file mode 100644 index 000000000..041ad1257 --- /dev/null +++ b/specs/hotel_admin_spec.rb @@ -0,0 +1,175 @@ +require_relative 'spec_helper' +require 'date_range' + +describe "HotelAdmin" do + before do + @hotel_admin_test = BookingSystem::HotelAdmin.new + + @first_name = "Jane" + @last_name = "Doe" + @room_id = 1 + @room_rate = 200.00 + @start_date = Date.new(2017, 9, 1) + @end_date = Date.new(2017, 9, 5) + + @hotel_admin_test.reserve_room(@first_name, @last_name, @room_id, @room_rate, @start_date, @end_date) + end + + describe "initialize" do + it "can create an instance of HotelAdmin class" do + @hotel_admin_test.class.must_equal BookingSystem::HotelAdmin + end + + it "can access list of all rooms in the hotel" do + @hotel_admin_test.room_list.must_be_instance_of Array + end + + it "can access list of all (non-block) reservations in hotel" do + @hotel_admin_test.reservation_list.must_be_instance_of Array + end + + it "can access list of blocks in hotel" do + @hotel_admin_test.block_list.must_be_instance_of Array + end + end + + describe "#find_reservations_by_date" do + before do + #include: @hotel_admin_test.reserve_room(@first_name, @last_name, 1, @room_rate, Date.new(2017, 9, 1), Date.new(2017, 9, 5)) + @hotel_admin_test.reserve_room(@first_name, @last_name, 1, @room_rate, Date.new(2017, 9, 5), Date.new(2017, 9, 6)) + @hotel_admin_test.reserve_room(@first_name, @last_name, 2, @room_rate, Date.new(2017, 9, 5), Date.new(2017, 9, 6)) + @hotel_admin_test.reserve_room(@first_name, @last_name, 3, @room_rate, Date.new(2017, 9, 5), Date.new(2017, 9, 6)) + @hotel_admin_test.reserve_room(@first_name, @last_name, 4, @room_rate, Date.new(2017, 9, 1), Date.new(2017, 9, 6)) + end + + it "provides list of reservations for a specific date" do + @hotel_admin_test.find_reservations_by_date(Date.new(2017, 9, 5)).must_be_instance_of Array + @hotel_admin_test.find_reservations_by_date(Date.new(2017, 9, 5)).length.must_equal 5 + end + end + + describe "#rooms_available_for_date_range" do + before do + #include: @hotel_admin_test.reserve_room(@first_name, @last_name, 1, @room_rate, Date.new(2017, 9, 1), Date.new(2017, 9, 5)) + @hotel_admin_test.reserve_room(@first_name, @last_name, 2, @room_rate, Date.new(2017, 9, 1), Date.new(2017, 9, 5)) + @hotel_admin_test.reserve_room(@first_name, @last_name, 3, @room_rate, Date.new(2017, 9, 1), Date.new(2017, 9, 5)) + @hotel_admin_test.reserve_room(@first_name, @last_name, 4, @room_rate, Date.new(2017, 9, 1), Date.new(2017, 9, 5)) + end + + it "ensures given date range argument is a DateRange object" do + proc { @hotel_admin_test.rooms_available_for_date_range("range") }.must_raise InvalidDateRangeError + end + + it "provides list of rooms available for a given date range " do + start_date = Date.new(2017, 9, 1) + end_date = Date.new(2017, 9, 5) + range = DateRange.new(start_date, end_date) + @hotel_admin_test.rooms_available_for_date_range(range).must_be_instance_of Array + @hotel_admin_test.rooms_available_for_date_range(range).length.must_equal(16) + end + end + + describe "#reserve_room" do + before do + @block_id = "Block1" + @date_range = DateRange.new(Date.new(2017, 9, 1), Date.new(2017, 9, 5)) + @rooms_array = [ + BookingSystem::Room.new(10, 200.00), + BookingSystem::Room.new(11, 200.00), + BookingSystem::Room.new(12, 200.00), + BookingSystem::Room.new(13, 200.00), + BookingSystem::Room.new(14, 200.00)] + @discount_room_rate = 0.20 + + #Hotel Revisted Changes + @hotel_admin_test.reservation_list << BookingSystem::Reservation.new("Jane", "Doe", 10, 200.00, Date.new(2017, 9, 1), Date.new(2017, 9, 5), "Block1") + + @block = BookingSystem::Block.new(@block_id, @date_range, @rooms_array, @discount_room_rate, @hotel_admin_test.reservation_list) + end + + it "ensures that reservation is added to all_reservations" do + @hotel_admin_test.reservation_list.any? { |reservation| + reservation.first_name == @first_name && + reservation.last_name == @last_name && + reservation.room_id == @room_id && + reservation.room_rate == @room_rate && + reservation.start_date == @start_date && + reservation.end_date == @end_date + }.must_equal true + end + + it "makes a reservation and adds it to hotel's list of reservations" do + @hotel_admin_test.reservation_list.length.must_equal 2 + end + + it "raises an error for an invalid date range" do + proc { @hotel_admin_test.reserve_room(@first_name, @last_name, @room_id, @room_rate, Date.new(2017, 9, 1), Date.new(2015, 9, 5)) }.must_raise InvalidDateRangeError + end + + it "raises an error if another reservation requests an unavailable room because of dates overlapping" do + #this should raise an error because the same reservation was booked in the before block + proc { @hotel_admin_test.reserve_room(@first_name, @last_name, @room_id, @room_rate, @start_date, @end_date) }.must_raise UnavailableRoomError + + proc { @hotel_admin_test.reserve_room(@first_name, @last_name, @room_id, @room_rate, Date.new(2017, 9, 1), Date.new(2017, 9, 2)) }.must_raise UnavailableRoomError + end + + it "cannot reserve a room that's in a block with same date range and room id" do + proc { @hotel_admin_test.reserve_room(@first_name, @last_name, 10, @room_rate, Date.new(2017, 9, 1), Date.new(2017, 9, 5)) }.must_raise UnavailableRoomError + end + + it "will allow booking for a room if requested start_date is on the end_date of a previous booking" do + @hotel_admin_test.reserve_room(@first_name, @last_name, @room_id, @room_rate, Date.new(2017, 9, 5), Date.new(2017, 9, 6)) + @hotel_admin_test.reservation_list.length.must_equal 3 + end + + end + + describe "#reserve_block" do + before do + @hotel_admin_test = BookingSystem::HotelAdmin.new + + @block_id = "Block1" + @date_range = DateRange.new(Date.new(2017, 9, 1), Date.new(2017, 9, 5)) + @rooms_array = [ + BookingSystem::Room.new(1, 200.00), + BookingSystem::Room.new(2, 200.00), + BookingSystem::Room.new(3, 200.00), + BookingSystem::Room.new(4, 200.00), + BookingSystem::Room.new(5, 200.00)] + @discount_room_rate = 0.20 + + @hotel_admin_test.reserve_block(@block_id, @date_range, @rooms_array, @discount_room_rate, @hotel_admin_test.reservation_list) + end + + it "makes a block reservation and adds it to hotel's list of block reservations" do + @hotel_admin_test.block_list.length.must_equal 1 + end + + end + + end#of_"HotelAdmin" + + + + + + + + + + + + + + + + + + + + + + + + + # diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb new file mode 100644 index 000000000..6fd284c37 --- /dev/null +++ b/specs/reservation_spec.rb @@ -0,0 +1,80 @@ +require 'date' +require_relative 'spec_helper' + + +describe "Reservation" do + before do + @first_name = "Jane" + @last_name = "Doe" + + @room_id = 1 + @room_rate = 200.00 + + @start_date = Date.new(2017, 9, 1) #Date.new(YYYY, M, D) + @end_date = Date.new(2017, 9, 5) + + @block_id = "Block1" + + @reservation_test = BookingSystem::Reservation.new(@first_name, @last_name, @room_id, @room_rate, @start_date, @end_date, @block_id) + end + + describe "#initialize" do + it "can create an instance of Reservation class" do + @reservation_test.class.must_equal BookingSystem::Reservation + end + + it "can take in reserver's identity info as arguments: first_name, last_name" do + #@reservation_test.must_respond_to(first_name) #? not sure why this gives an error + @reservation_test.first_name.must_equal("Jane") + @reservation_test.first_name.must_be_instance_of String + + @reservation_test.last_name.must_equal("Doe") + @reservation_test.last_name.must_be_instance_of String + end + + it "can take in room info as arguments: room_id, room_rate" do + @reservation_test.room_id.must_equal 1 + @reservation_test.room_id.must_be_instance_of Integer + + @reservation_test.room_rate.must_equal 200.00 + @reservation_test.room_rate.must_be_instance_of Float + end + + it "can take in reservation date objects as arguments: start_date, end_date" do + @reservation_test.start_date.must_equal(Date.new(2017, 9, 1)) + @reservation_test.start_date.must_be_instance_of Date + + @reservation_test.end_date.must_equal(Date.new(2017, 9, 5)) + @reservation_test.end_date.must_be_instance_of Date + end + + it "raises an error if start_date and end_date are not date objects" do + proc { BookingSystem::Reservation.new("Jane", "Doe", 20, 200.00, "2017, 9, 1", 952017) }.must_raise InvalidDateError + end + + it "#date_range: must return a DateRange object" do + @reservation_test.must_respond_to :date_range + @reservation_test.date_range.must_be_instance_of DateRange + end + + it "raises an error if date range is invalid" do + + start_date = Date.new(2017, 9, 1) + end_date = Date.new(2015, 9, 5) + + proc {BookingSystem::Reservation.new(@first_name, @last_name, @room_id, @room_rate, start_date, end_date)}.must_raise InvalidDateRangeError + end + end + + describe "#get_total_cost" do + it "can calculate a total" do + + @reservation_test.get_total_cost.must_equal 800.00 + @reservation_test.get_total_cost.must_be_instance_of Float + + @reservation_test.total_cost.must_equal 800.00 + @reservation_test.total_cost.must_be_instance_of Float + end + end + +end#of_"Reservation" diff --git a/specs/room_spec.rb b/specs/room_spec.rb new file mode 100644 index 000000000..e1369e53a --- /dev/null +++ b/specs/room_spec.rb @@ -0,0 +1,31 @@ +require_relative 'spec_helper' +require_relative '../lib/room' + +describe "Room" do + before do + @room_test = BookingSystem::Room.new(1, 200.00) + end + + describe "initialize" do + it "can create an instance of Room class" do + @room_test.class.must_equal BookingSystem::Room + end + + it "#id: can give correct room id number" do + @room_test.id.must_equal 1 + @room_test.id.must_be_instance_of Integer + end + + it "#cost: can give correct cost" do + @room_test.cost.must_equal 200.00 + @room_test.cost.must_be_instance_of Float + end + end + + describe "Room.all" do + it "returns a list of all room instances as an array" do + all_rooms = BookingSystem::Room.all + all_rooms.must_be_instance_of Array + end + end +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 000000000..98ed1de41 --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,15 @@ +require 'simplecov' +SimpleCov.start + +require 'minitest' +require 'minitest/autorun' +require 'minitest/reporters' +require_relative '../lib/block' +require_relative '../lib/BookingSystem_Errors' +require_relative '../lib/room' +require_relative '../lib/hotel_admin' +require_relative '../lib/reservation' + + + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new diff --git a/support/rooms.csv b/support/rooms.csv new file mode 100644 index 000000000..2ff747506 --- /dev/null +++ b/support/rooms.csv @@ -0,0 +1,20 @@ +1, 200.00 +2, 200.00 +3, 200.00 +4, 200.00 +5, 200.00 +6, 200.00 +7, 200.00 +8, 200.00 +9, 200.00 +10, 200.00 +11, 200.00 +12, 200.00 +13, 200.00 +14, 200.00 +15, 200.00 +16, 200.00 +17, 200.00 +18, 200.00 +19, 200.00 +20, 200.00