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..32b9e9338 --- /dev/null +++ b/design-activity.md @@ -0,0 +1,37 @@ +#Hotel Revisited +***** +### Questions for Online Shopping Cart Code Implementations: +* What classes does each implementation include? Are the lists the same? + - Both implementations have the same classes: CartEntry, ShoppingCart, and Order. +* Write down a sentence to describe each class. + - CartEntry appears to be a class for containing information about a specific item or product. + - ShoppingCart appears to be a class that stores a list of items or products. + - Order appears to be class for calculating total cost of the ShoppingCart, including SALES_TAX. +* How do the classes relate to each other? It might be helpful to draw a diagram. + - There doesn't appear to be any explicit relationship between the CartEntry and any of the other classes, but I would assume a ShoppingCart could potentially have one or more CartEntry instances. + - An instance of a Order within this implementation has-a ShoppingCart. +* What data does each class store? How (if at all) does this differ between the two implementations? + - The appears to be no difference between the two implementations for the data each class stores: CartEntry stores the \@quantity (of the product) and \@unit_price (cost per product), ShoppingCart stores \@entries (a list of some entries, in this code, like CartEntry instances), and Order stores \@cart (a ShoppingCart) and the constant, SALES_TAX. +* What methods does each class have? How (if at all) does this differ between the two implementations? + - Each implementation as an initialize method for the three classes. + - Implementation A: uses helper methods in each "lower level" class, CartEntry and ShoppingCart. Then, Order#total_price calculates the sum all entries together and adds on sales tax. + - Implementation B: uses no helper methods in any class. Instead, CartEntry and ShoppingCart have price instance methods that calculate the their own prices. Then, Order only has to add the sales tax cost to the price in Order#total_price. +* Consider the Order#total_price method. In each implementation: + * Is logic to compute the price delegated to "lower level" classes like ShoppingCart and CartEntry, or is it retained in Order? + - In Implementation A, I would say the logic is solely retained in Order. + - In Implementation B, the logic is shared between all three classes, as such delegated to the "lower level" classes: ShoppingCart and CartEntry. + * Does total_price directly manipulate the instance variables of other classes? + - In Implementation A, yes, it does (helper methods). + - In Implementation B, no, it does not seem to. +* If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify? + - You would need to add some conditional if quantity > some_amount then unit_price = unit_price * some_discount. This code could be added into the each loop of total_price for Implementation A or the instance method for price of CartEntry in Implementation B. + - As far as difficulty to modify the code to make this possible, I think it would be possible to apply to either method just as easily. It also depends on how complicated the discount logic is. You would need some type of discount for above a certain quantity. If the discount is the same no matter what the item, either method can be changed as easily as the other. If the discount is changes item to item, I think it would be easier to change Implementation B. +* Which implementation better adheres to the single responsibility principle? + - I believe Implementation B adheres better. The Order doesn't have to the responsibility of calculating each CartEntry price then summing all the Entries in the ShoppingCart together to then add on sales tax. +* Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? + - Also, Implementation B. It doesn't have to call on the instance variables of CartEntry or ShoppingCart to find the total price for the order. +***** +### The Hotel Revision +I had a few unnecessary helper methods, so want to change the code, so the classes only have access to the ids of the other classes. This means changing the code so Room doesn't respond to :calendar or :cost, Reservation doesn't respond to :room or :date_range, and Block doesn't respond to :reservations. This is better because if later I change all the information in a class, I can just change that method within the class and the other classes wont know what know any different as long as it is getting the information it needs. + +To revise Hotel, I changed the initialize arguments for Block and Reservation to take a hash instead of separate arguments. I changed the way the classes assign and track ids. Then, I worked on changing all the different classes approach to instance variables of other classes, so that except for ids and room_num, the other classes don't know too much about the others. (hopefully) diff --git a/lib/block.rb b/lib/block.rb new file mode 100644 index 000000000..5ddd52a91 --- /dev/null +++ b/lib/block.rb @@ -0,0 +1,47 @@ +require 'date' +require 'pry' + +module Hotel + class Block < Reservation + @@id = 1 + attr_reader :id + def initialize block_args + super(block_args) + @party = block_args[:party] + @rooms = block_args[:rooms] + @discount = block_args[:discount] + @reservations = [] + @reserved_rooms = [] + end + + def find_available_rooms + available_rooms = [] + return @rooms if @reserved_rooms.empty? + @rooms.each do |room| + next if @reserved_rooms.any? { |reserved_room| reserved_room == room } + available_rooms << room + end + raise StandardError.new("no rooms available") if available_rooms.empty? + available_rooms + end + + def reserve_room(room_num, guest) + room = @rooms[room_num - 1] + raise StandardError.new("room not available") if !find_available_rooms.include?(room) + new_reservation = Reservation.new({id: @@id, room: room, guest: guest, date_range: @date_range}) + @@id += 1 + @reserved_rooms << room + @reservations << new_reservation + new_reservation + end + + def calculate_reservation_cost(reservation_id) + reservation = find_reservation(reservation_id) + ((1 - @discount) * reservation.calculate_reservation_cost).round(2) + end + + def find_reservation(reservation_id) + @reservations.find { |reservation| reservation.id == reservation_id } + end + end +end diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..2d3725769 --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,25 @@ +require 'date' + +module Hotel + class Reservation + attr_reader :id + def initialize reservation_args + @id = reservation_args[:id] + @room = reservation_args[:room] + @guest = reservation_args[:guest] + @date_range = reservation_args[:date_range] + end + + def calculate_nights + @date_range.to_a.length + end + + def find_all_dates + @date_range.to_a + end + + def calculate_reservation_cost + @room.calculate_cost(calculate_nights) + end + end +end diff --git a/lib/room.rb b/lib/room.rb new file mode 100644 index 000000000..205f7260f --- /dev/null +++ b/lib/room.rb @@ -0,0 +1,27 @@ +require 'date' +require 'pry' + +module Hotel + class Room + attr_reader :room_num + def initialize(room_num, cost) + @room_num = room_num + @cost = cost + @calendar = [] + end + + def add_to_calendar(date_range) + dates = date_range.to_a + dates.each { | date | @calendar << date } + end + + def is_available date_range + return false if @calendar.any?(date_range) + true + end + + def calculate_cost nights + @cost * nights + end + end +end diff --git a/lib/user.rb b/lib/user.rb new file mode 100644 index 000000000..99a1801a7 --- /dev/null +++ b/lib/user.rb @@ -0,0 +1,100 @@ +require 'date' +require 'pry' + +module Hotel + TOTAL_ROOMS = 20 + class User + @@id = 1 + attr_reader :rooms + def initialize(rooms) + if rooms.size != TOTAL_ROOMS + raise StandardError.new("incorrect number of rooms") + end + @rooms = rooms + @reservations = [] + @calendar = {} + end + def find_available_rooms(start_date, end_date) + date_range = (start_date...end_date) + available_rooms = [] + @rooms.each do |room| + available_rooms << room if room.is_available(date_range) + end + available_rooms + # need to deal with no rooms available + end + + def reserve_room(room_num, guest, start_date, end_date) + valid_dates(start_date, end_date) + date_range = (start_date...end_date) + check_room_availibility(room_num, date_range) + room = @rooms[room_num - 1] + id = @reservations.length + 1 + new_reservation = Reservation.new({id: @@id, room: room, guest: guest, date_range: date_range}) + @@id += 1 + add_to_calendar(new_reservation, date_range) + room.add_to_calendar(date_range) + @reservations << new_reservation + new_reservation + end + + def valid_dates(start_date, end_date) + if start_date.class != Date || end_date.class != Date + raise StandardError.new("not a date") + elsif end_date < start_date + raise StandardError.new("End date (#{end_date}) comes before start date (#{start_date})") + elsif end_date == start_date + raise StandardError.new("End date (#{end_date}) is same as start date (#{start_date})") + end + end + + def check_room_availibility(room_num, date_range) + calendar = @rooms[room_num - 1].is_available(date_range) + return true if calendar + if !calendar + raise StandardError.new("room already reserved") if date_range.include?(date) + end + end + + def add_to_calendar(reservation, date_range) + date_range.each do |date| + @calendar[date] ? @calendar[date].push(reservation) : @calendar[date] = [reservation] + end + end + + def find_reservations_for_given_date(date) + @calendar[date] + end + + def find_reservation_cost(reservation_id) + reservation = find_reservation(reservation_id) + reservation.calculate_reservation_cost + end + def find_reservation(reservation_id) + @reservations.find { |reservation| reservation.id == reservation_id } + end + + def create_room_block(rooms, party, start_date, end_date, discount) + raise StandardError.new('too many rooms for a block') if rooms.length > 5 + raise StandardError.new('too few rooms for a block') if rooms.length < 2 + valid_dates(start_date, end_date) + date_range = (start_date...end_date) + rooms.each { |room| check_room_availibility(room.room_num, date_range) } + id = @reservations.length + 1 + new_block = Block.new({id: @@id, rooms: rooms, party: party, date_range: date_range, discount: discount}) + @@id += 1 + add_to_calendar(new_block, date_range) + rooms.each { |room| room.add_to_calendar(date_range) } + @reservations << new_block + new_block + end + + def reserve_room_from_block(block, room_num, guest) + block.reserve_room(room_num, guest) + end + + def check_block_room_availibility(block) + block.find_available_rooms + end + end +end diff --git a/specs/block_spec.rb b/specs/block_spec.rb new file mode 100644 index 000000000..00e74192c --- /dev/null +++ b/specs/block_spec.rb @@ -0,0 +1,85 @@ +require_relative 'spec_helper' +require 'date' +require 'pry' + +describe 'Block class' do + describe 'instantiation' do + before do + rooms = [] + 4.times {|x| rooms << Hotel::Room.new(x+1, 200) } + date_range = (Date.new(2018,3,22)...Date.new(2018,3,26)) + @block = Hotel::Block.new({id: 1, rooms: rooms, party: "Fanime", date_range: date_range, discount: 0.2}) + end + it 'can be initialized' do + @block.must_be_instance_of Hotel::Block + end + it 'inherits from User' do + @block.must_be_kind_of Hotel::Reservation + end + it 'has attributes: id, list of some rooms, reservations, party, date range, discount' do + # may not need this test stub.... + @block.must_respond_to :id + @block.id.must_equal 1 + end + end + describe 'find_available_rooms' do + before do + @rooms = [] + 4.times {|x| @rooms << Hotel::Room.new(x+1, 200) } + date_range = (Date.new(2018,3,22)...Date.new(2018,3,26)) + @block = Hotel::Block.new({id: 1, rooms: @rooms, party: "Fanime", date_range: date_range, discount: 0.2}) + end + it 'returns array of rooms available in block' do + available_rooms_in_block = @block.find_available_rooms + + available_rooms_in_block.must_be_kind_of Array + available_rooms_in_block.must_equal @rooms + end + it 'handles (throw exception or returns nil) no rooms available' do + 4.times do |x| + @block.reserve_room(x+1, "fan #{x+1}") + end + + proc { @block.find_available_rooms }.must_raise StandardError + end + it 'exclude rooms that are already reserved' do + @block.reserve_room(1, "Fan 543") + @block.reserve_room(3, "Fan 564") + + available_rooms_in_block = @block.find_available_rooms + + available_rooms_in_block.wont_include @rooms[0] + available_rooms_in_block.wont_include @rooms[2] + end + end + describe 'reserve_room' do + before do + rooms = [] + 4.times {|x| rooms << Hotel::Room.new(x+1, 200) } + date_range = (Date.new(2018,3,22)...Date.new(2018,3,26)) + @block = Hotel::Block.new({id: 1, rooms: rooms, party: "Fanime", date_range: date_range, discount: 0.2}) + end + it 'returns a reservation for an available room' do + reservation = @block.reserve_room(1, "Fan 1") + + reservation.must_be_instance_of Hotel::Reservation + end + it 'throws exception if room is unavailable' do + @block.reserve_room(2, "Jace Poe") + proc { @block.reserve_room(2, "Jade Poe")}.must_raise StandardError + end + end + describe 'calculate_reservation_cost' do + before do + rooms = [] + 4.times {|x| rooms << Hotel::Room.new(x+1, 200) } + date_range = (Date.new(2018,3,22)...Date.new(2018,3,26)) + @block = Hotel::Block.new({id: 1, rooms: rooms, party: "Fanime", date_range: date_range, discount: 0.2}) + end + it 'returns discounted cost for the reservation' do + reservation = @block.reserve_room(1, "Meka Starbright") + + @block.calculate_reservation_cost(reservation.id).must_equal 640 + end + end +end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb new file mode 100644 index 000000000..c57ce1fdf --- /dev/null +++ b/specs/reservation_spec.rb @@ -0,0 +1,54 @@ +require_relative 'spec_helper' +require 'date' + +describe 'Reservation' do + before do + date_range = (Date.new(2018,3,18)...Date.new(2018,3,26)) + room = Hotel::Room.new(4, 200) + @reservation = Hotel::Reservation.new({id: 1, room: room, guest: "Bob", date_range: date_range}) + end + describe 'initialization' do + it 'can be initialized' do + @reservation.must_be_instance_of Hotel::Reservation + end + it 'has attributes: id, room, guest, date_range' do + @reservation.id.must_equal 1 + @reservation.id.must_be_kind_of Integer + # @reservation.room.must_be_instance_of Hotel::Room + end + end + describe 'calculate_nights' do + before do + date_range = (Date.new(2018,3,18)...Date.new(2018,3,26)) + room = Hotel::Room.new(4, 200) + @reservation = Hotel::Reservation.new({id: 1, room: room, guest: "Bob", date_range: date_range}) + end + it 'returns the number of nights' do + nights = @reservation.calculate_nights + + nights.must_be_kind_of Integer + nights.must_equal 8 + end + end + describe 'find_all_dates' do + it 'returns an array of all dates in reservation' do + date_range = (Date.new(2018,3,20)...Date.new(2018,3,22)) + room = Hotel::Room.new(4, 200) + reservation = Hotel::Reservation.new({id: 1, room: room, guest: "Kaeli", date_range: date_range}) + all_dates = reservation.find_all_dates + + all_dates.must_be_kind_of Array + all_dates.must_equal [Date.new(2018,3,20), Date.new(2018,3,21)] + end + end + + describe 'calculate_reservation_cost' do + it 'returns the cost of the reservation' do + date_range = (Date.new(2018,3,20)...Date.new(2018,3,25)) + room = Hotel::Room.new(4, 200) + reservation = Hotel::Reservation.new({id: 1, room: room, guest: "Bob", date_range: date_range}) + + reservation.calculate_reservation_cost.must_equal 1000 + end + end +end diff --git a/specs/room_spec.rb b/specs/room_spec.rb new file mode 100644 index 000000000..7d68cedc7 --- /dev/null +++ b/specs/room_spec.rb @@ -0,0 +1,31 @@ +require_relative 'spec_helper' +require 'date' + +describe 'Room class' do + describe 'initialize' do + it 'can be initialized' do + room_2 = Hotel::Room.new(2, 200) + + room_2.must_be_instance_of Hotel::Room + end + + it 'has empty calendar and room number' do + room_2 = Hotel::Room.new(2, 200) + + room_2.must_respond_to :room_num + room_2.room_num.must_be_kind_of Integer + room_2.room_num.must_equal 2 + end + end + describe 'add_to_calendar' do + it 'can add a date_range to its calendar' do + room = Hotel::Room.new(2, 200) + date_range = (Date.new(2018,3,8)...Date.new(2018,3,10)) + + room.add_to_calendar(date_range) + + room.is_available(Date.new(2018,3,9)).must_equal false + room.is_available(Date.new(2018,3,10)).must_equal true + end + end +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 000000000..b883b0291 --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,15 @@ +require 'simplecov' +SimpleCov.start + + +require 'minitest' +require 'minitest/autorun' +require 'minitest/reporters' +require 'minitest/skip_dsl' + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new + +require_relative '../lib/user' +require_relative '../lib/reservation' +require_relative '../lib/room' +require_relative '../lib/block' diff --git a/specs/user_spec.rb b/specs/user_spec.rb new file mode 100644 index 000000000..6d8ab5667 --- /dev/null +++ b/specs/user_spec.rb @@ -0,0 +1,214 @@ +require_relative 'spec_helper' +require 'date' + +describe 'User' do + describe 'initialization' do + before do + rooms = [] + 20.times {|x| rooms << Hotel::Room.new(x+1, 200) } + @admin = Hotel::User.new(rooms) + end + it 'can be initialized' do + @admin.must_be_instance_of Hotel::User + end + it 'has a list of rooms' do + @admin.must_respond_to :rooms + @admin.rooms[0].must_be_instance_of Hotel::Room + @admin.rooms.last.must_be_instance_of Hotel::Room + end + + it 'wont allow User to initialize with different number of rooms from TOTAL_ROOMS' do + rooms_1 = [] + rooms_2 = [] + 19.times {|x| rooms_1 << Hotel::Room.new(x+1, 200) } + 21.times {|x| rooms_2 << Hotel::Room.new(x+1, 200) } + + proc { Hotel::User.new(rooms_1) }.must_raise StandardError + proc { Hotel::User.new(rooms_2) }.must_raise StandardError + end + end + describe 'find_available_rooms' do + before do + rooms = [] + 20.times {|x| rooms << Hotel::Room.new(x+1, 200) } + @admin = Hotel::User.new(rooms) + @start_date = Date.new(2018,3,15) + @end_date = Date.new(2018,3,20) + end + it 'returns a list of rooms that are available for a range of dates' do + available_rooms = @admin.find_available_rooms(@start_date, @end_date) + + available_rooms.must_be_kind_of Array + available_rooms.length.must_equal 20 + available_rooms[0].must_be_instance_of Hotel::Room + available_rooms[8].must_be_instance_of Hotel::Room + available_rooms[-1].must_be_instance_of Hotel::Room + end + it 'handles (throw exception or returns nil) if no rooms available' do + end + it 'excludes rooms that arent available for given dates' do + reservation1 = @admin.reserve_room(1, "Jane Doe", Date.new(2018,3,12), Date.new(2018,3,18)) + reservation2 = @admin.reserve_room(2, "John Smith", Date.new(2018,3,18), Date.new(2018,3,25)) + reservation3 = @admin.reserve_room(3, "Sam Sole", Date.new(2018,3,1), Date.new(2018,3,30)) + reservation4 = @admin.reserve_room(4, "Alex Whitt", Date.new(2018,3,15), Date.new(2018,3,20)) + reservation5 = @admin.reserve_room(5, "Kael Dear", Date.new(2018,3,16), Date.new(2018,3,18)) + + available_rooms = @admin.find_available_rooms(@start_date, @end_date) + + available_rooms.wont_include @admin.rooms[0] + available_rooms.wont_include @admin.rooms[1] + available_rooms.wont_include @admin.rooms[2] + available_rooms.wont_include @admin.rooms[3] + available_rooms.wont_include @admin.rooms[4] + end + it 'includes rooms that have same end_date as new start date' do + reservation1 = @admin.reserve_room(3, "Sam Sole", Date.new(2018,3,1), Date.new(2018,3,30)) + reservation2 = @admin.reserve_room(4, "Alex Whitt", Date.new(2018,3,12), Date.new(2018,3,15)) + + available_rooms = @admin.find_available_rooms(@start_date, @end_date) + + available_rooms.wont_include @admin.rooms[2] + available_rooms.must_include @admin.rooms[3] + end + end + describe 'reserve_room' do + before do + rooms = [] + 20.times {|x| rooms << Hotel::Room.new(x+1, 200) } + @admin = Hotel::User.new(rooms) + @new_reservation = @admin.reserve_room(5, "Jade Poe", Date.new(2018, 3, 20), Date.new(2018, 3, 25)) + end + it 'throws StandardError for invalidate dates' do + proc { @admin.reserve_room(3, "Jade Poe", nil, Date.new(2018,3,5))}.must_raise StandardError + proc { @admin.reserve_room(4, "Jade Poe", Date.new(2018,3,5), nil)}.must_raise StandardError + end + it 'throws StandardError if end_date occurs before start_date' do + proc { @admin.reserve_room(1, "Jade Poe", Date.new(2018, 3, 10), Date.new(2018, 3, 5))}.must_raise StandardError + end + it 'throws StandardError if start_date is same as end_date' do + proc { @admin.reserve_room(2, "Jade Poe", Date.new(2018, 3, 10), Date.new(2018, 3, 10))}.must_raise StandardError + end + it 'throws StandardError if room has any other reservation that overlaps with new reservation' do + @admin.reserve_room(2, "Jace Poe", Date.new(2018, 3, 10), Date.new(2018, 3, 12)) + proc { @admin.reserve_room(2, "Jade Poe", Date.new(2018, 3, 10), Date.new(2018, 3, 12))}.must_raise StandardError + end + it 'returns an instance of a reservation' do + @new_reservation.must_be_instance_of Hotel::Reservation + end + it 'allows reservation of room with same start_date as previous reservations end_date' do + proc { @admin.reserve_room(5, "Kaeli Smit", Date.new(2018, 3, 25), Date.new(2018, 3, 27)) }.must_be_silent + end + end + describe 'find_reservation_cost' do + it 'returns cost for reservation with reservation id' do + rooms = [] + 20.times {|x| rooms << Hotel::Room.new(x+1, 200) } + admin = Hotel::User.new(rooms) + reservation = admin.reserve_room(5, "Kaeli Poe", Date.new(2018, 3, 20), Date.new(2018, 3, 25)) + + admin.find_reservation_cost(reservation.id).must_equal 1000 + end + end + describe 'find_reservations_for_given_date' do + before do + rooms = [] + 20.times {|x| rooms << Hotel::Room.new(x+1, 200) } + @admin = Hotel::User.new(rooms) + @new_reservation = @admin.reserve_room(5, "Jade Poe", Date.new(2018, 3, 20), Date.new(2018, 3, 25)) + @new_reservation_2 = @admin.reserve_room(8, "Kal Smith", Date.new(2018, 3, 20), Date.new(2018, 3, 25)) + @date = Date.new(2018, 3, 23) + end + it 'returns array of reservations for a given date' do + reservations_of_day = @admin.find_reservations_for_given_date(@date) + + reservations_of_day.must_be_kind_of Array + reservations_of_day.must_equal [@new_reservation, @new_reservation_2] + end + end + describe 'create_room_block' do + before do + rooms = [] + 20.times {|x| rooms << Hotel::Room.new(x+1, 200) } + @admin = Hotel::User.new(rooms) + @start_date = Date.new(2018,3,15) + @end_date = Date.new(2018,3,20) + @available_rooms = @admin.find_available_rooms(@start_date, @end_date) + end + it 'creates a block that is stored in reservations' do + rooms = @available_rooms.first(5) + block = @admin.create_room_block(rooms, "Comicon", @start_date, @end_date, 0.2) + + block.must_be_instance_of Hotel::Block + @admin.find_reservations_for_given_date(@start_date).must_include block + end + it 'doesnt allow more than 5 rooms per block' do + rooms = @available_rooms.first(6) + proc { @admin.create_room_block(rooms, "Comicon", @start_date, @end_date, 0.2)}.must_raise StandardError + end + it 'doesnt allow less than 2 rooms per block' do + rooms = @available_rooms.first + + proc { @admin.create_room_block(rooms, "Comicon", @start_date, @end_date, 0.2)}.must_raise StandardError + end + it 'doesnt allow rooms that are unavailable when block is made' do + 20.times { |x| @admin.reserve_room(x+1, 'Guest #{x+1}', @start_date, @end_date) } + rooms = @available_rooms.first(5) + + proc {@admin.create_room_block(rooms, "Comicon", @start_date, @end_date, 0.2)}.must_raise StandardError + end + it 'deals with if there are not enough rooms for the block' do + # edge case to think about + 17.times { |x| @admin.reserve_room(x+1, 'Guest #{x+1}', @start_date, @end_date) } + rooms = @available_rooms.last(5) + + proc {@admin.create_room_block(rooms, "Comicon", @start_date, @end_date, 0.2)}.must_raise StandardError + end + it 'doesnt allow rooms to be used for another block or single reservation from general public' do + rooms = @available_rooms.first(5) + @admin.create_room_block(rooms, "Comicon", @start_date, @end_date, 0.2) + + proc {@admin.create_room_block(rooms, "Fanime", @start_date, @end_date, 0.2)}.must_raise StandardError + proc {@admin.reserve_room(rooms.first, "Random Author", @start_date, @end_date)}.must_raise StandardError + end + end + describe 'reserve_room_from_block' do + before do + rooms = [] + 20.times {|x| rooms << Hotel::Room.new(x+1, 200) } + @admin = Hotel::User.new(rooms) + @start_date = Date.new(2018,3,15) + @end_date = Date.new(2018,3,20) + @available_rooms = @admin.find_available_rooms(@start_date, @end_date) + @block = @admin.create_room_block(@available_rooms.first(5), "Comicon", @start_date, @end_date, 0.2) + end + it 'returns reservation of a room within a block' do + room_num = @available_rooms[0].room_num + reservation = @admin.reserve_room_from_block(@block, room_num, "Spiderman") + + reservation.must_be_instance_of Hotel::Reservation + end + end + describe 'check_block_room_availibility' do + before do + rooms = [] + 20.times {|x| rooms << Hotel::Room.new(x+1, 200) } + @admin = Hotel::User.new(rooms) + @start_date = Date.new(2018,3,15) + @end_date = Date.new(2018,3,20) + @available_rooms = @admin.find_available_rooms(@start_date, @end_date) + @block = @admin.create_room_block(@available_rooms.first(5), "Comicon", @start_date, @end_date, 0.2) + end + it 'returns an array of rooms' do + before_available_rooms_in_block = @admin.check_block_room_availibility(@block) + room_num = @available_rooms[0].room_num + reservation = @admin.reserve_room_from_block(@block, room_num, "Spiderman") + after_available_rooms_in_block = @admin.check_block_room_availibility(@block) + + before_available_rooms_in_block.length.must_equal 5 + before_available_rooms_in_block.must_include @available_rooms[0] + after_available_rooms_in_block.length.must_equal 4 + after_available_rooms_in_block.wont_include @available_rooms[0] + end + # rest of this method is tested in the block_spec + end +end