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..1db1f05c0 --- /dev/null +++ b/design-activity.md @@ -0,0 +1,26 @@ +###What classes does each implementation include? Are the lists the same? +Both implementations use three classes: CartEntry, ShoppingCart and Order. However, they differ in that B's classes has price methods instead of attr_accessors. +###Write down a sentence to describe each class. +CartEntry: Is initialized with a unit price and quantity. B's can tell you the price, while A's gives you attr_accessors to the price and quantity. +ShoppingCart: Is initialized with an empty array to called entries. B's can tell you the total price of the all of the entries, while A's gives your attr_accessor to the entries. +Order: Creates an instance of a shopping cart and has a constant variable to store 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. +Orders hold a shopping cart, they can tell you the total price with sales tax included. A shopping cart holds CartEntry objects in an array. +###What data does each class store? How (if at all) does this differ between the two implementations? +Order holds sales tax as a constant variable and an instance of a cart as an instance variable. ShoppingCart holds multiples instances of CartEntry objects as an instance variable within an array. CartEntry has a unit price and quantity as instance variables. The two implementations do not differ on this. +###What methods does each class have? How (if at all) does this differ between the two implementations? +A's gives you attr_accessors for their object's instance variables. However, B's has a separate method for "price." This allows for the data to remain private and from being modified. +###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's computes the the total price by accessing the unit price and quantity for the objects and directly computing using those numbers. However, B's implementation has a price method that gives you the price for each objects, so it just needs to grab the cart's price to use as a subtotal before adding the sales tax. +###Does total_price directly manipulate the instance variables of other classes? +A's method does not currently change the instance variables, but they could if they make a mistake writing a method in Order. However, it would be impossible to do so in B's. +###If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify? +B's implementation would be easiest because you could just modify the price method to adjust when the quantity is above a certain number. In A's implementation you would have to check it for each entry within the total price loop. +###Which implementation better adheres to the single responsibility principle? +B! +###Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? +###Once you've responded to the prompts, git add design-activity.md and git commit! + +### Hotel +My hotel module is doing a lot! It creates, modifies, and finds rooms, reservations and blocks. Some of it can definitely be moved into the classes. I refactored the available_rooms and blocked_rooms method to not rely so heavily on attr_readers from the classes. Instead of manually checking the check in and check out date within the Hotel module, I updated it so the blocks and reservations can tell you if they are available or not within that date range. diff --git a/lib/block.rb b/lib/block.rb new file mode 100644 index 000000000..620a69106 --- /dev/null +++ b/lib/block.rb @@ -0,0 +1,48 @@ +require 'csv' +require_relative 'room' +require_relative 'reservation' +require_relative 'hotel' + +module Hotel + class Block < Reservation + attr_accessor :reservations + attr_reader :block_id, :discount_rate, :num_of_rooms, :rooms + def initialize(input_id, input_room_number, check_in_date, check_out_date, input_block_id = 0 ) + super + @block_id = input_block_id.to_i + @discount_rate = input_id.to_f + @num_of_rooms = input_room_number.to_i + raise ArgumentError.new "Blocks can contain a maximum of 5 rooms" if @num_of_rooms > 5 + @id = nil + @room_number = nil + @room = nil + @rooms = add_rooms(check_in_date, check_out_date) + @reservations = [] + end + + + def add_rooms(begin_date, end_date) + block_rooms = [] + available_rooms = Hotel.available_rooms(begin_date, end_date) + i = 0 + num_of_rooms.times do + block_rooms << available_rooms[i] + i+= 1 + end + return block_rooms + end + + def add_reservations + reservations.replace(Hotel.find_reservation_by_block_id(block_id)) + end + + def available(begin_search, end_search) + if (begin_search >= @check_in) && (begin_search < @check_out) && (end_search >= @check_in) && (end_search <= @check_out) + return false + else + return true + end + end + + end # => end of Block +end # => end of module diff --git a/lib/hotel.rb b/lib/hotel.rb new file mode 100644 index 000000000..a590b2761 --- /dev/null +++ b/lib/hotel.rb @@ -0,0 +1,172 @@ +require 'csv' +require_relative 'room' +require_relative 'reservation' + +module Hotel + + ROOM_NUMBERS = (1..20) + + HOTEL_ROOMS = ROOM_NUMBERS.map {|num| Hotel::Room.new(num, 200)} + + + def self.all_rooms + return HOTEL_ROOMS + end + + def self.find_room(input_id) + HOTEL_ROOMS.each do |room| + return room if room.id == input_id + end + end + + + def self.find_reservation(input_id) + raise ArgumentError.new "Invalid input. Please enter Reservation ID as an Integer" if !(input_id.is_a? Integer) + all_reservations = self.all_reservations + all_reservations.each do |reservation| + return reservation if reservation.id == input_id + end + raise ArgumentError.new "Reservation ID does not exist" + end + + def self.find_reservation_by_block_id(input_id) + raise ArgumentError.new "Invalid input. Please enter Block ID as an Integer" if !(input_id.is_a? Integer) + blocked_reservations = [] + all_reservations = self.all_reservations + all_reservations.each do |reservation| + blocked_reservations << reservation if reservation.block_id == input_id + end + raise ArgumentError.new "No Reservations found under that Block ID" if blocked_reservations.length == 0 + return blocked_reservations + end + + def self.find_block(input_id) + all_blocks = self.all_blocks + all_blocks.each do |block| + return block if block.block_id == input_id + end + end + + def self.all_reservations + all_reservations = [] + CSV.read('support/reservations.csv').each do |row| + reservation_id = row[0] + room_num = row[1] + check_in_date = row[2].split + check_out_date = row[3].split + block_id = row[4] ? row[4] : 0 + all_reservations.push(Hotel::Reservation.new(reservation_id, room_num, check_in_date, check_out_date, block_id)) + end + return all_reservations + end + + def self.all_blocks + all_blocks =[] + CSV.read('support/blocks.csv').each do |row| + block_rate = row[0] + num_of_rooms = row[1] + check_in_date = row[2].split + check_out_date = row[3].split + block_id = row[4] + all_blocks.push(Hotel::Block.new(block_rate, num_of_rooms, check_in_date, check_out_date, block_id)) + end + return all_blocks + end + + def self.cost(input_reservation_id) + raise ArgumentError.new "Invalid reservation ID. Must be Integer." if !(input_reservation_id.is_a? Integer) + all_reservations = self.all_reservations + all_reservations.each do |reservation| + return (reservation.total_cost) if reservation.id == input_reservation_id + end + raise ArgumentError.new "Reservation ID does not exist" + end + + def self.access_reservation(input_date) + search_date = Date.new(input_date[0], input_date[1], input_date[2]) + search_reservations = [] + all_reservations = self.all_reservations + all_reservations.each do |reservation| + search_reservations << reservation if search_date.between?(reservation.check_in, reservation.check_out - 1) + end + raise ArgumentError.new "No Reservations are present on that date" if search_reservations.length == 0 + return search_reservations + end + + def self.available_rooms(begin_date, end_date) + begin_search = Date.new(begin_date[0].to_i, begin_date[1].to_i, begin_date[2].to_i) + end_search = Date.new(end_date[0].to_i, end_date[1].to_i, end_date[2].to_i) + unavailable_rooms = [] + all_reservations = self.all_reservations + all_reservations.each do |reservation| + if reservation.available(begin_search, end_search) == false + unavailable_rooms << reservation.room + end + end + # if (begin_search >= reservation.check_in) && (begin_search < reservation.check_out) && (end_search >= reservation.check_in) && (end_search <= reservation.check_out) + # unavailable_rooms<< reservation.room + # end + available_rooms = HOTEL_ROOMS - unavailable_rooms + return available_rooms + end + + def self.blocked_rooms(begin_date, end_date) + begin_search = Date.new(begin_date[0].to_i, begin_date[1].to_i, begin_date[2].to_i) + end_search = Date.new(end_date[0].to_i, end_date[1].to_i, end_date[2].to_i) + blocked_rooms = [] + all_the_blocks = self.all_blocks + all_the_blocks.each do |block| + # if (begin_search >= block.check_in) && (begin_search < block.check_out) && (end_search >= block.check_in) && (end_search <= block.check_out) + if block.available(begin_search, end_search) == false + block.rooms.each do |room| + blocked_rooms << room + end + end + end + return blocked_rooms + end + + def self.truly_available(begin_date, end_date) + available_rooms = self.available_rooms(begin_date, end_date) + blocked_rooms = self.blocked_rooms(begin_date, end_date) + truly_available = available_rooms - blocked_rooms + return truly_available + end + + + def self.reserve_room(begin_date, end_date) + # begin_reservation = Date.new(begin_date[0], begin_date[1], begin_date[2]) + # end_reservation = Date.new(end_date[0], end_date[1], end_date[2]) + available_rooms = self.available_rooms(begin_date, end_date) + raise ArgumentError.new "No rooms are available for this date range" if available_rooms.length == 0 + return Hotel::Reservation.new(10, available_rooms[0].id, begin_date, end_date) + end + + def self.reserve_block(rate, num_of_rooms, check_in_date, check_out_date, input_block_id) + available_rooms = truly_available(check_in_date, check_out_date) + raise ArgumentError.new "Not enough rooms are available for this date range" if available_rooms.length < num_of_rooms.to_i + return Hotel::Block.new(rate, num_of_rooms, check_in_date, check_out_date, input_block_id) + end + + def self.block_available(block_id) + block = self.find_block(block_id) + rooms = block.rooms.length + taken = self.find_reservation_by_block_id(block_id) + return rooms - taken.length + end + + def self.reserve_block_room(block_id) + raise ArgumentError.new "Invalid input. Please enter Block ID as an Integer" if !(block_id.is_a? Integer) + block = self.find_block(block_id) + raise ArgumentError.new "Block ID is not found" if !(block.is_a? Hotel::Block) + # block.add_rooms + availability = block_available(block_id) + raise ArgumentError.new "No rooms available in Block #{block_id}" if availability == 0 + array_check_in = [block.check_in.year, block.check_in.month, block.check_in.day] + array_check_out =[block.check_out.year, block.check_out.month, block.check_out.day] + new_reservation = Hotel::Reservation.new(5, block.rooms[0].id, array_check_in, array_check_out, block.block_id) + # block.add_reservations # => does nothing currently, would work if I was writing new reservations to CSV...)-':' + block.reservations << (new_reservation) + return new_reservation + end +end diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..126345bc3 --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,42 @@ +require_relative 'hotel' +require_relative 'room' + +module Hotel + class Reservation + # @@reservation_id_max = 0 + attr_reader :id, :room_number, :room, :check_in, :check_out, :total_cost, :block_id + def initialize(input_id, input_room_number, check_in_date, check_out_date, input_block_id = 0) + @id = input_id.to_i + + @room_number = input_room_number.to_i + + @room = Hotel.find_room(@room_number) + + @check_in = Date.new(check_in_date[0].to_i, check_in_date[1].to_i, check_in_date[2].to_i) + + @check_out = Date.new(check_out_date[0].to_i, check_out_date[1].to_i, check_out_date[2].to_i) + + @total_cost = cost + @block_id = input_block_id.to_i + raise ArgumentError.new "Invalid date range" if @check_in >= @check_out + end + + def available(begin_search, end_search) + if (begin_search >= @check_in) && (begin_search < @check_out) && (end_search >= @check_in) && (end_search <= @check_out) + return false + else + return true + end + end + private + def cost + length_of_stay = (@check_out - @check_in).to_i + cost_of_stay = length_of_stay * @room.cost + return cost_of_stay + end + # def generate_id + # @@reservation_id_max += 1 + # return @@reservation_id_max + # end + end +end diff --git a/lib/room.rb b/lib/room.rb new file mode 100644 index 000000000..0fffee197 --- /dev/null +++ b/lib/room.rb @@ -0,0 +1,16 @@ +require_relative 'hotel' + +module Hotel + class Room + attr_reader :id, :cost + def initialize(input_id, cost) + @id = input_id + @cost = cost + end # => end of initialize + + # def is_available?(begin_date, end_date) + # @availablility.each do |reservation_id, dates| + # if (begin_date >= check_in) && (begin_date <= check_out) || (end_date >= check_in) && (end_date <= check_out) + + end # => end of class +end # => end of module diff --git a/pseudocode_wave3.rb b/pseudocode_wave3.rb new file mode 100644 index 000000000..361c12ea8 --- /dev/null +++ b/pseudocode_wave3.rb @@ -0,0 +1,25 @@ +require_relative 'lib/hotel.rb' +require_relative 'lib/room.rb' +require_relative 'lib/reservation.rb' + +# Wave 3 +# User Stories + +# As an administrator, I can create a block of rooms + +# => To create a block you need a date range, collection of rooms and a discounted room rate +Hotel::Block.new(begin_date, end_date, num_of_rooms, discount_rate) +# => The collection of rooms should only include rooms that are available for the given date range +Block.rooms.each +# => If a room is set aside in a block, it is not available for reservation by the general public, nor can it be included in another block + + +# As an administrator, I can check whether a given block has any rooms available +Hotel.block_available(input_id) +# As an administrator, I can reserve a room from within a block of rooms +Hotel.reserve_block_room(input_id) + +#Constraints +# => A block can contain a maximum of 5 rooms +# => When a room is reserved from a block of room, the reservation dates will always match the date range of the block +# => All of the availablility checking logic from Wave 2 should now respect room blocks as well as an individual diff --git a/pseudocode_wave_1.rb b/pseudocode_wave_1.rb new file mode 100644 index 000000000..5a178f96c --- /dev/null +++ b/pseudocode_wave_1.rb @@ -0,0 +1,28 @@ +require_relative 'lib/hotel.rb' +require_relative 'lib/room.rb' +require_relative 'lib/reservation.rb' + +# Wave 1 +# User Stories +# => As an administrator, I can access the list of all of the rooms in the hotel +Hotel.rooms # => list of all rooms +[Room1, Room2, Room3, Room4...Room20] +# => As an administrator, I can reserve a room for a given date range +Hotel::Reservation.new(input_room, check_in_date, check_out_date] # => creates instance of a reservation +Hotel::Reservation.new(Room1, 10222017, 10242017) + +# => As an administrator, I can access the list of reservations for a specific date +Hotel.find_by_date(input_date) +Hotel::Reservation.find_by_date(10232017) #=> should return my reservation + +# => As an administrator, I can get the total cost for a given reservation +Hotel.reservation_cost(input_id) +Hotel.find_by_id(input_id).total_cost (?) +# Constraints +# => The hotel has 20 rooms, and they are numbered 1 through 20 +# => Every room is identical and a room always costs $200/night +# => The last day of a reservation is the checkoutday, so the guest should not be charged for that night +# => For this wave, any room can be reserved at any time, so you don't need to worry about double booking (-: +# +# Error Handling +# => Your code should raise an error when an invalid date range is provided diff --git a/pseudocode_wave_2.rb b/pseudocode_wave_2.rb new file mode 100644 index 000000000..f2e1fedf4 --- /dev/null +++ b/pseudocode_wave_2.rb @@ -0,0 +1,22 @@ +require_relative 'lib/hotel.rb' +require_relative 'lib/room.rb' +require_relative 'lib/reservation.rb' + +# Wave 2 +# User Stories + +# => As an administrator, I can view a list of rooms that are not reserved for a given date range +Hotel.available_rooms(begin_date, end_date) +#=> returns array [Room Object.available true for date range] +# => As an administrator, I can reserve an available room for a given date range +Hotel.reserve_room(begin_date, end_date) + + +# Constraints + +# => A reservation is allowed to start on the same day that another reservation for the same room ends + + +# Error Handling + +# => Your code should raise an exception when asked to reserve a room that is not available diff --git a/specs/block_spec.rb b/specs/block_spec.rb new file mode 100644 index 000000000..603ead76d --- /dev/null +++ b/specs/block_spec.rb @@ -0,0 +1,45 @@ +require 'pry' +require_relative 'spec_helper' +# Hotel::Block.new(begin_date, end_date, num_of_rooms, discount_rate) + +describe "Block" do + describe "initialize" do + it "should return an instance of a block" do + output = Hotel::Block.new(0.5, 3, [2017,10,22], [2017,10,24], 60) + output.must_be_instance_of Hotel::Block + end + it "should have a date range, num of rooms and discount rate" do + output = Hotel::Block.new(0.5, 3, [2017,10,22], [2017,10,24], 60) + output.must_respond_to :check_in + output.must_respond_to :check_out + output.must_respond_to :num_of_rooms + output.must_respond_to :discount_rate + output.must_respond_to :rooms + end + it "should raise error if intitalized with more than 5 rooms" do + proc {Hotel::Block.new(0.5, 6, [2017,10,22], [2017,10,24], 60)}.must_raise ArgumentError + end + it "should contain rooms in an array" do + output = Hotel::Block.new(0.5, 3, [2017,10,22], [2017,10,24], 60) + output.rooms.must_be_instance_of Array + (output.rooms[0]).must_be_instance_of Hotel::Room + + end + it "should contain reservations in an array" do + output = Hotel::Block.new(0.5, 3, [2017,10,22], [2017,10,24], 60) + output.reservations.must_be_instance_of Array + end + it "should contain reservations if there are any for block" do + output = Hotel.find_block(75) + output.reservations.must_be_instance_of Array + output.reservations.length.must_equal 0 + output.add_reservations + output.reservations[0].must_be_instance_of Hotel::Reservation + + end + it "should only include rooms that are available for the given date range" do + output = Hotel::Block.new(0.5, 3, [2017,10,3], [2017,10,5], 60) + (output.rooms.include? Hotel::HOTEL_ROOMS[0]).must_equal false + end + end +end diff --git a/specs/hotel_spec.rb b/specs/hotel_spec.rb new file mode 100644 index 000000000..67b203f7d --- /dev/null +++ b/specs/hotel_spec.rb @@ -0,0 +1,280 @@ +require 'pry' +require_relative 'spec_helper' + +describe "hotel" do + describe "ROOM_NUMBERS" do + it "should have room numbers from 1-20" do + Hotel::ROOM_NUMBERS.each do |num| + (1..20).must_include num + end + end + it "should have 20 hotel rooms" do + Hotel::HOTEL_ROOMS.length.must_equal 20 + end + it "should have 20 hotel rooms numbered 1-20" do + Hotel::HOTEL_ROOMS.each do |room| + (1..20).must_include room.id + end + end + it "should have instances of rooms" do + Hotel::HOTEL_ROOMS.each do |room| + room.must_be_instance_of Hotel::Room + end + end + end + + describe "self.all_rooms" do + it "should return an array of 20 rooms" do + (Hotel.all_rooms).must_be_instance_of Array + (Hotel.all_rooms).length.must_equal 20 + end + it "everything in array should be instance of a room" do + all_the_rooms = Hotel.all_rooms + all_the_rooms.each {|element| element.must_be_instance_of Hotel::Room} + end + end + + describe "self.find_room(input_id)" do + it "should return room matching room number" do + room_1 = Hotel.find_room(1) + room_1.must_equal Hotel::HOTEL_ROOMS[0] + (Hotel::HOTEL_ROOMS[0]).id.must_equal 1 + room_5 = Hotel.find_room(5) + room_5.must_equal Hotel::HOTEL_ROOMS[4] + (Hotel::HOTEL_ROOMS[4]).id.must_equal 5 + end + end + + + describe "self.find_reservation(input_id)" do + it "should return reservation with mathching reservation id" do + reservation1 = Hotel.find_reservation(1785) + reservation1.id.must_equal 1785 + end + it "should return instance of reservation" do + reservation1 = Hotel.find_reservation(1785) + reservation1.must_be_instance_of Hotel::Reservation + end + it "should raise error if reservation does not exist" do + proc {Hotel.find_reservation(100000)}.must_raise ArgumentError + proc {Hotel.find_reservation(8585858)}.must_raise ArgumentError + end + it "should raise error if id is given as not an Integer" do + proc {Hotel.find_reservation("8585858")}.must_raise ArgumentError + proc {Hotel.find_reservation(:eighty_five)}.must_raise ArgumentError + proc {Hotel.find_reservation([85, 90])}.must_raise ArgumentError + proc {Hotel.find_reservation({"room" => 20})}.must_raise ArgumentError + proc {Hotel.find_reservation("")}.must_raise ArgumentError + proc {Hotel.find_reservation()}.must_raise ArgumentError + + + + + + + end + end + + describe "self.find_reservation_by_block_id(input_id)" do + it "should return an array" do + output = Hotel.find_reservation_by_block_id(75) + output.must_be_instance_of Array + end + it "should return an array of reservations" do + output = Hotel.find_reservation_by_block_id(75) + output.each do |element| + element.must_be_instance_of Hotel::Reservation + end + end + it "should return an array of reservations with correct block_id" do + output = Hotel.find_reservation_by_block_id(75) + output.each do |element| + element.block_id.must_equal 75 + end + output.length.must_equal 2 + end + end + + describe "self.find_block(input_id)" do + it "should return a block" do + output = Hotel.find_block(75) + output.must_be_instance_of Hotel::Block + end + it "should return a block with matching ID" do + output = Hotel.find_block(75) + output.block_id.must_equal 75 + end + end + + describe "self.all_reservations" do + it "returns an array" do + output = Hotel.all_reservations + output.must_be_instance_of Array + end + + it "everthing in the array is a reservation" do + output = Hotel.all_reservations + output.each do |element| + element.must_be_instance_of Hotel::Reservation + end + end + + it "should match what is currently in csv" do + output = Hotel.all_reservations + output.length.must_equal 21 + output[0].room_number.must_equal 1 + output[0].total_cost.must_equal 600 + end + + end + + describe "self.all_blocks" do + it "returns an array" do + output = Hotel.all_blocks + output.must_be_instance_of Array + end + it "total amount of blocks should match what is currently in the csv" do + output = Hotel.all_blocks + output.length.must_equal 1 + end + it "should be filled with block objects" do + output = Hotel.all_blocks + output[0].must_be_instance_of Hotel::Block + end + it "first element should match what is in csv " do + output = Hotel.all_blocks + expected_output = Date.new(2017, 9, 20) + output[0].check_in.must_equal expected_output + end + end + + describe "self.cost(input_reservation)" do + it "should return total_cost of a reservation when given id" do + output = Hotel.cost(99) + output.must_equal 600 + end + it "should raise error if reservation ID does not exist" do + proc{Hotel.cost(1000)}.must_raise ArgumentError + proc{Hotel.cost(868584)}.must_raise ArgumentError + + end + it "should raise type error if reservation ID is not given as an Integer" do + proc{Hotel.cost("45")}.must_raise ArgumentError + proc{Hotel.cost("")}.must_raise ArgumentError + proc{Hotel.cost(:forty_five)}.must_raise ArgumentError + proc{Hotel.cost([45])}.must_raise ArgumentError + end + end + + describe "self.access_reservation(input_date)" do + it "should return array" do + output = Hotel.access_reservation([2017,10,3]) + output.must_be_instance_of Array + end + it "everything in array should be a reservation" do + output = Hotel.access_reservation([2017,10,3]) + output.each do |element| + element.must_be_instance_of Hotel::Reservation + end + end + it "should return an error if an invalid date is passed" do + proc {Hotel.access_reservation([2011,10,3])}.must_raise ArgumentError + end + end + + describe "self.available_rooms(begin_date, end_date)" do + it "should respond to available_rooms" do + Hotel.must_respond_to :available_rooms + end + it "should return an array of available_rooms" do + output = Hotel.available_rooms([2017,10,2], [2017,10,4]) + output.must_be_instance_of Array + end + it "should give a list of rooms 2- 20 as available" do + output = Hotel.available_rooms([2017,10,2], [2017,10,4]) + (output.length).must_equal 19 + end + it "should give 20 rooms available" do + output = Hotel.available_rooms([2017,2,10], [2017,2,14]) + (output.length).must_equal 20 + start_on_checkout = Hotel.available_rooms([2017,10,5], [2017,10,6]) + (start_on_checkout.length).must_equal 20 + end + it "should give 19 rooms available" do + output = Hotel.available_rooms([2017,10,3], [2017,10,4]) + (output.length).must_equal 19 + end + it "everything in the array should be a room" do + output = Hotel.available_rooms([2017,10,2], [2017,10,4]) + output.each {|element| element.must_be_instance_of Hotel::Room} + end + it "should check blocks to see if room is available" do + output = Hotel.truly_available([2017,9,20],[2017,9,22]) + output[0].id.must_equal 5 + end + end + describe "Hotel.reserve_room(begin_date, end_date)" do + it "should respond to reserve_room" do + Hotel.must_respond_to :reserve_room + end + it "should return an instance of a reservation" do + output = Hotel.reserve_room([2017,12,22], [2017,12, 25]) + output.must_be_instance_of Hotel::Reservation + end + it "should raise an error if there are unavailable_rooms" do + proc {Hotel.reserve_room([2017,11,24], [2017,11, 25])}.must_raise ArgumentError + end + end + describe "Hotel.block_available(input_id)" do + it "should return number of rooms available" do + output = Hotel.block_available(75) + output.must_be_instance_of Integer + end + it "should return 1" do + output = Hotel.block_available(75) + output.must_equal 2 + end + end + + describe "Hotel.reserve_block()" do + it "should return a block" do + output = Hotel.reserve_block(0.5, 3, [2018, 11, 5], [2018, 11,10], 83) + output.must_be_instance_of Hotel::Block + end + it "should raise error if not enough rooms are available during that reservation" do + proc {Hotel.reserve_block(0.5, 3, [2017, 11, 24], [2017, 11, 25], 83)}.must_raise ArgumentError + end + end + + describe "Hotel.reserve_block_room(input_id)" do + it "should return a reservation" do + output = Hotel.reserve_block_room(75) + output.must_be_instance_of Hotel::Reservation + end + it "should have the same check in and checkout dates as the block" do + output = Hotel.reserve_block_room(75) + block_check_in = Date.new(2017, 9, 20) + block_check_out = Date.new(2017, 9, 22) + output.check_in.must_equal block_check_in + output.check_out.must_equal block_check_out + end + it "should raise return an error if block does not exist" do + proc {Hotel.reserve_block_room(85858)}.must_raise ArgumentError + + end + # it "should raise an error if no rooms are available in the block" do + # Hotel.reserve_block_room(75) + # Hotel.reserve_block_room(75) + # # binding.pry + # proc {Hotel.reserve_block_room(75)}.must_raise ArgumentError + # # binding.pry + # end + it "should raise an error if input id is not Integer" do + proc {Hotel.reserve_block_room("")}.must_raise ArgumentError + proc {Hotel.reserve_block_room("hey")}.must_raise ArgumentError + proc {Hotel.reserve_block_room("545")}.must_raise ArgumentError + proc {Hotel.reserve_block_room(:block)}.must_raise ArgumentError + proc {Hotel.reserve_block_room(["why"])}.must_raise ArgumentError + end + end + end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb new file mode 100644 index 000000000..9e73a07a3 --- /dev/null +++ b/specs/reservation_spec.rb @@ -0,0 +1,43 @@ +require_relative 'spec_helper' + +describe "reservation" do + describe "initialize" do + it "should be an instance of reservation" do + input = Hotel::Reservation.new(10, 1, [2017,10,22], [2017,10,24]) + input.must_be_instance_of Hotel::Reservation + end + it "should have a room number, check_in date and check_out date" do + input = Hotel::Reservation.new(10, 1, [2017,10,22], [2017,10,24]) + input.must_respond_to :room_number + input.must_respond_to :check_in + input.must_respond_to :check_out + end + it "should have a unique ID" do + reserve_1 = Hotel::Reservation.new(10, 1, [2017,10,22], [2017,10,24]) + reserve_1.must_respond_to :id + + reserve_2 = Hotel::Reservation.new(25, 1, [2017,10,22], [2017,10,24]) + reserve_2.must_respond_to :id + (reserve_1.id).must_be :!=, reserve_2.id + + end + it "should have an instance of a room" do + input = Hotel::Reservation.new(10, 1, [2017,10,22], [2017,10,24]) + input.must_respond_to :room + (input.room).must_be_instance_of Hotel::Room + end + it "should have a total cost of 400 for a 2 day stay" do + input = Hotel::Reservation.new(10, 1, [2017,10,22], [2017,10,24]) + input.must_respond_to :total_cost + (input.total_cost).must_equal 400 + end + it "should raise an error for invalid date range" do + proc {Hotel::Reservation.new(10,1,[2017,10,24], [2017,10,24])}.must_raise ArgumentError + proc {Hotel::Reservation.new(10,1,[2017,10,24], [2017,10,22])}.must_raise ArgumentError + end + # it "room should not be available for that date range" do + # output = Hotel.all_reservations + # (output[0].avaiability(begin_date, end_date)).must_equal false + # end + end +end diff --git a/specs/room_spec.rb b/specs/room_spec.rb new file mode 100644 index 000000000..514b86bb7 --- /dev/null +++ b/specs/room_spec.rb @@ -0,0 +1,29 @@ +require_relative 'spec_helper' + +describe "room" do + describe "initialize" do + it "should be an instance of a room" do + input = Hotel::Room.new(1,200) + input.must_be_instance_of Hotel::Room + end + it "should respond to id" do + input = Hotel::Room.new(1, 200) + input.must_respond_to :id + end + # it "should have a room number from 1 - 20" do + # skip + # hotel_rooms = 20.times {Hotel::Room.new} + # hotel_rooms.each do |room| + # (1..20).must_include room.id + # end + # end + it "should have a cost" do + input = Hotel::Room.new(1, 200) + input.must_respond_to :cost + end + # it "should have respond to avaiability" do + # input = Hotel::Room.new(1, 200) + # input.must_respond_to :avaiability + # end + end +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 000000000..49c15ada2 --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,19 @@ +require 'simplecov' +SimpleCov.start + +require 'minitest' +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/pride' + + + +# Require any classes +# ex require_relative 'lib/foo.rb' +require_relative '../lib/hotel.rb' +require_relative '../lib/room.rb' +require_relative '../lib/reservation.rb' +require_relative '../lib/block.rb' + + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new diff --git a/support/blocks.csv b/support/blocks.csv new file mode 100644 index 000000000..475a2ec11 --- /dev/null +++ b/support/blocks.csv @@ -0,0 +1 @@ +15,4,2017 9 20,2017 9 22,75 diff --git a/support/reservations.csv b/support/reservations.csv new file mode 100644 index 000000000..de9305859 --- /dev/null +++ b/support/reservations.csv @@ -0,0 +1,21 @@ +99,1,2017 10 2,2017 10 5, 75 +1,1,2017 11 24,2017 11 26 +1,2,2017 11 24,2017 11 26 +1,3,2017 11 24,2017 11 26 +1,4,2017 11 24,2017 11 26 +1,5,2017 11 24,2017 11 26 +1,6,2017 11 24,2017 11 26 +1,7,2017 11 24,2017 11 26 +1,8,2017 11 24,2017 11 26 +1,9,2017 11 24,2017 11 26 +1,10,2017 11 24,2017 11 26 +1,11,2017 11 24,2017 11 26 +1,12,2017 11 24,2017 11 26 +1,13,2017 11 24,2017 11 26 +1,14,2017 11 24,2017 11 26 +1,15,2017 11 24,2017 11 26 +1,16,2017 11 24,2017 11 26 +1,17,2017 11 24,2017 11 26, 75 +1,18,2017 11 24,2017 11 26 +1,19,2017 11 24,2017 11 26 +1785,20,2017 11 24,2017 11 26