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..b9d2a8d24 --- /dev/null +++ b/design-activity.md @@ -0,0 +1,43 @@ +###### What classes does each implementation include? Are the lists the same? +Both implementations include CartEntry, ShoppingCart, and Order classes. + +###### Write down a sentence to describe each class. +Implementation A: +* CartEntry stores the unit price and quantity for each item in a cart. +* ShoppingCart stores a list of the items in a cart. +* Order calculates the subtotal of all items in a cart, the sales tax, and the total. + +Implementation B: +* CartEntry stores the unit price and quantity for each item in a cart and calculates the price of that item. +* ShoppingCart stores a list of the items in a cart and calculates the subtotal for all items in the cart. +* Order calculates the sales tax and total for the cart. + +###### How do the classes relate to each other? It might be helpful to draw a diagram on a whiteboard or piece of paper. +Implementation A: CartEntry and ShoppingCart are not dependent on any other class. Order is dependent on both ShoppingCart (to provide the list of items) and CartEntry (to provide the unit prices and quantities for each item). + +Implementation B: CartEntry is not dependent on any other class. ShoppingCart is dependent on CartEntry to provide prices for the items in the cart. Order is dependent on ShoppingCart to provide a list of items in the cart and the cart subtotal. + +###### What data does each class store? How (if at all) does this differ between the two implementations? +In both implementations CartEntry stores unit prices and quantities, Shopping Cart stores the list of items entered in the cart, and Order stores an instance of ShoppingCart. + +###### What methods does each class have? How (if at all) does this differ between the two implementations? +In Implementation A, CartEntry and ShoppingCart have only initialization methods, and Order has an initialization method and method to calculate the total price of the order. + +In Implementation B, CartEntry, ShoppingCart, and Order all have initialization methods and methods to calculate the price of an item, the subtotal for items in a shopping cart, and the total price of an order, respectively. + +###### 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, the logic to compute the total price is all retained in the Order class. In Implementation B, the logic is delegated to the 'lower level' ShoppingCart and CartEntry classes. + +* **Does total_price directly manipulate the instance variables of other classes?** +I'm a little confused by what is meant by 'manipulation' -- to my mind, manipulation implies that the value assigned to an instance variable is modified. The total_price method does not modify the value of another classes' instance variable in either implementation. However, in Implementation A, the total_price method reads the values of the CartEntry classes' instance variables. In Implementation B, the total_price method does not directly read the values of other classes' instance variables. + +###### If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify? +If items are cheaper if bought in bulk, we would need to modify the code to include a unit price that is dependent on the quantity. It would be easier to make the modification in Implementation B because the unit price could be altered within the existing CartEntry#price method (or alternatively, in a new CartEntry instance method), and no other changes to ShoppingCart or Order would be necessary. In Implementation A, a new instance method would probably be added to CartEntry to calculate the unit price based on the quantity, and the Order#total_price method would have to be modified to call that method rather than reading the value of CartEntry's unit price instance variable. + +###### Which implementation better adheres to the single responsibility principle? +Implementation B better adheres to the single responsibility principle because the purpose of each class is better encapsulated (more wholly contained) within that class than in Implementation A. + +###### Which implementation is more loosely coupled? +Implementation B is more loosely coupled. + diff --git a/lib/admin.rb b/lib/admin.rb new file mode 100644 index 000000000..b2310bfde --- /dev/null +++ b/lib/admin.rb @@ -0,0 +1,119 @@ +require_relative 'date_range' +require_relative 'room' +require_relative 'reservation' + +module Hotel + class Admin + attr_reader :rooms, :reservations + + def initialize + @rooms = load_rooms + @reservations = [] + end + + def load_rooms + rooms = [] + (1..20).each do |num| + rooms << Room.new(num) + end + + return rooms + end + + def find_reservations(date) + reservations_by_date = @reservations.select do |res| + res.date_range.range.include?(date) + end + + return reservations_by_date + end + + def find_available_rooms(date_range) + conflicts = @reservations.select do |reservation| + reservation.overlap?(date_range) + end + + unavailable_rooms = conflicts.map { |res| res.room } + available_rooms = @rooms - unavailable_rooms + + return available_rooms + end + + def reserve_room(date_range) + if find_available_rooms(date_range).empty? + raise StandardError.new("There are no available rooms for that date range.") + end + + reservation_data = { + id: next_reservation_id, + date_range: date_range, + room: find_available_rooms(date_range).sample + } + + new_reservation = Reservation.new(reservation_data) + @reservations << new_reservation + + return new_reservation + end + + def next_reservation_id + return 1 if @reservations.empty? + return @reservations.map { |res| res.id }.max + 1 + end + + def next_block_id + block_reservations = @reservations.select { |res| res.block_id != nil } + + if block_reservations.empty? + return 1 + else + max_block_id = block_reservations.map { |res| res.block_id }.max + return max_block_id + 1 + end + end + + def create_block(num_rooms, date_range) + if num_rooms > 5 + raise ArgumentError.new("A block can include a maximum of 5 rooms.") + end + + if find_available_rooms(date_range).length < num_rooms + raise StandardError.new("There are not enough available rooms to block for those dates.") + end + + block_id = next_block_id + + num_rooms.times do + reservation_data = { + id: next_reservation_id, + date_range: date_range, + room: find_available_rooms(date_range).sample, + block_id: block_id, + block_status: :blocked + } + new_block_reservation = Reservation.new(reservation_data) + @reservations << new_block_reservation + end + end + + def find_available_block_rooms(block_id) + available_block_rooms = @reservations.select do |res| + res.block_id == block_id && res.block_status == :blocked + end + + return available_block_rooms + end + + def reserve_block_room(block_id) + available_rooms = find_available_block_rooms(block_id) + + if available_rooms.empty? + raise StandardError.new("There are no available rooms in Block #{block_id}.") + end + + available_rooms.first.change_status + end + + + end +end diff --git a/lib/date_range.rb b/lib/date_range.rb new file mode 100644 index 000000000..ce13cb140 --- /dev/null +++ b/lib/date_range.rb @@ -0,0 +1,30 @@ +module Hotel + class DateRange + + attr_reader :start_date, :end_date + + def initialize(start_date, end_date) + @start_date = Date.parse(start_date) + @end_date = Date.parse(end_date) + + [@start_date, @end_date].each do |date| + if date.class != Date + raise StandardError.new("Invalid date format. Accepted formats include 'YYYY-MM-DD' or 'YYYY/MM/DD'.") + end + end + + if @end_date <= @start_date + raise StandardError.new("End date must be at least one day later than start date.") + end + end + + def range + return (@start_date...@end_date).to_a + end + + def overlap?(other) + return !(other.range & self.range).empty? + end + + end +end diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..1bdf66d2f --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,37 @@ +module Hotel + class Reservation + + attr_reader :id, :date_range, :room, :block_id, :block_status + + COST_PER_NIGHT = 200.0 + BLOCK_DISCOUNT = 0.25 + + def initialize(input) + @id = input[:id] + @date_range = input[:date_range] + @room = input[:room] + @block_id = input[:block_id] + @block_status = input[:block_status] + end + + def cost + nights = @date_range.range.count + cost = nights * COST_PER_NIGHT + cost *= (1 - BLOCK_DISCOUNT) if @block_id != nil + + return cost + end + + def overlap?(date_range) + return @date_range.overlap?(date_range) + end + + def change_status + if @block_status == :blocked + @block_status = :reserved + elsif @block_status == :reserved + @block_status = :blocked + end + end + end +end diff --git a/lib/room.rb b/lib/room.rb new file mode 100644 index 000000000..3fc1c5c74 --- /dev/null +++ b/lib/room.rb @@ -0,0 +1,15 @@ +module Hotel + class Room + + attr_reader :number + + def initialize(num) + + if num < 1 || num > 20 + raise ArgumentError.new("Room number must be between 1 and 20") + end + + @number = num + end + end +end diff --git a/specs/admin_spec.rb b/specs/admin_spec.rb new file mode 100644 index 000000000..0911f8720 --- /dev/null +++ b/specs/admin_spec.rb @@ -0,0 +1,282 @@ +require_relative 'spec_helper' + +describe 'Admin class' do + describe 'initialize method' do + before do + @hotel = Hotel::Admin.new + end + + it 'can be created' do + @hotel.must_be_instance_of Hotel::Admin + @hotel.must_respond_to :rooms + @hotel.must_respond_to :reservations + end + + it 'includes an array of rooms' do + @hotel.rooms.must_be_kind_of Array + @hotel.rooms.length.must_equal 20 + @hotel.rooms.each do |room| + room.must_be_instance_of Hotel::Room + end + end + + it 'includes an empty array of reservations' do + @hotel.reservations.must_be_kind_of Array + @hotel.reservations.must_be_empty + end + end + + describe 'find_reservations method' do + before do + @hotel = Hotel::Admin.new + range_1 = Hotel::DateRange.new("May 6, 1982", "May 10, 1982") + range_2 = Hotel::DateRange.new("April 30, 1982", "May 1, 1982") + range_3 = Hotel::DateRange.new("May 5, 1982", "May 8, 1982") + @reservation_1 = @hotel.reserve_room(range_1) + @reservation_2 = @hotel.reserve_room(range_2) + @reservation_3 = @hotel.reserve_room(range_3) + end + + it 'returns an array of reservations' do + reservations = @hotel.find_reservations(Date.parse("May 6, 1982")) + reservations.must_be_kind_of Array + reservations.each do |reservation| + reservation.must_be_instance_of Hotel::Reservation + end + end + + it 'accurately accounts for the number of reservations that overlap the given date' do + reservations = @hotel.find_reservations(Date.parse("May 6, 1982")) + reservations.length.must_equal 2 + reservations.must_include @reservation_1 + reservations.must_include @reservation_3 + reservations.wont_include @reservation_2 + end + + it 'does not include reservations that end on the given date' do + reservations = @hotel.find_reservations(Date.parse("May 8, 1982")) + reservations.length.must_equal 1 + reservations.wont_include @reservation_3 + end + + it 'returns an empty array if the date does not overlap any reservations' do + @hotel.find_reservations(Date.parse("May 2, 1982")).must_equal [] + end + end + + describe 'find_available_rooms method' do + before do + @hotel = Hotel::Admin.new + date_range_1 = Hotel::DateRange.new("May 6, 1982", "May 10, 1982") + date_range_2 = Hotel::DateRange.new("May 5, 1982", "May 8, 1982") + @date_range_3 = Hotel::DateRange.new("May 6, 1982", "May 8, 1982") + @reservation_1 = @hotel.reserve_room(date_range_1) + @reservation_2 = @hotel.reserve_room(date_range_2) + end + + it 'returns an array of rooms' do + available_rooms = @hotel.find_available_rooms(@date_range_3) + available_rooms.must_be_kind_of Array + available_rooms.each do |room| + room.must_be_instance_of Hotel::Room + end + end + + it 'accurately accounts for the number of available rooms' do + available_rooms = @hotel.find_available_rooms(@date_range_3) + available_rooms.length.must_equal 18 + available_rooms.wont_include @reservation_1.room + available_rooms.wont_include @reservation_2.room + end + + it 'returns an empty array if there are no available rooms' do + date_range = Hotel::DateRange.new("March 17, 2018", "March 18, 2018") + 20.times do + @hotel.reserve_room(date_range) + end + + @hotel.find_available_rooms(date_range).must_equal [] + end + end + + describe 'reserve_room method' do + before do + @hotel = Hotel::Admin.new + @date_range = Hotel::DateRange.new("Dec 31, 1999", "Jan 2, 2000") + @reservation = @hotel.reserve_room(@date_range) + end + + it 'creates a new reservation' do + @reservation.must_be_instance_of Hotel::Reservation + end + + it 'accurately loads reservation data' do + @reservation.id.must_be_kind_of Integer + @reservation.id.must_equal 1 + @reservation.date_range.must_be_instance_of Hotel::DateRange + @reservation.room.must_be_instance_of Hotel::Room + end + + it 'adds the reservation to the hotels list of reservations' do + @hotel.reservations.must_include @reservation + end + + it 'throws an error if there are no available rooms' do + 19.times do + @hotel.reserve_room(@date_range) + end + + proc { @hotel.reserve_room(@date_range) }.must_raise StandardError + end + + it 'throws an error if all rooms have been blocked' do + 3.times do + @hotel.create_block(5, @date_range) + end + @hotel.create_block(4, @date_range) + + proc { @hotel.reserve_room(@date_range) }.must_raise StandardError + end + end + + describe 'next_reservation_id helper method' do + it 'assigns an id of 1 if there are no existing reservations' do + hotel = Hotel::Admin.new + hotel.next_reservation_id.must_equal 1 + end + + it 'assigns an id one higher than the highest existing reservation id' do + hotel = Hotel::Admin.new + range_1 = Hotel::DateRange.new("May 6, 1982", "May 10, 1982") + range_2 = Hotel::DateRange.new("April 30, 1982", "May 1, 1982") + hotel.reserve_room(range_1) + hotel.reserve_room(range_2) + + hotel.next_reservation_id.must_equal 3 + end + + describe 'next_block_id helper method' do + before do + @hotel = Hotel::Admin.new + @date_range = Hotel::DateRange.new("May 6, 1982", "May 10, 1982") + end + + it 'assigns an id of 1 if there are no existing block reservations' do + @hotel.next_block_id.must_equal 1 + end + + it 'assigns an id one higher than the highest existing block id' do + reservation_data_1 = { + id: 100, + date_range: @date_range, + room: 15, + block_id: 1, + block_status: :blocked + } + reservation_data_2 = { + id: 200, + date_range: @date_range, + room: 16, + block_id: 4, + block_status: :blocked + } + reservation_1 = Hotel::Reservation.new(reservation_data_1) + reservation_2 = Hotel::Reservation.new(reservation_data_2) + @hotel.reservations.push(reservation_1, reservation_2) + @hotel.next_block_id.must_equal 5 + end + end + + describe 'create_block method' do + before do + @hotel = Hotel::Admin.new + @date_range = Hotel::DateRange.new("May 6, 1982", "May 10, 1982") + end + + it 'throws an error if the user tries to block more than 5 rooms' do + proc { @hotel.create_block(6, @date_range) }.must_raise ArgumentError + end + + it 'adds the block reservations to the hotels reservations' do + @hotel.create_block(3, @date_range) + @hotel.reservations.length.must_equal 3 + end + + it 'creates reservations with distinct reservation ids and rooms' do + @hotel.create_block(3, @date_range) + @hotel.reservations.map { |res| res.id }.uniq.length.must_equal 3 + @hotel.reservations.map { |res| res.room }.uniq.length.must_equal 3 + end + + it 'creates reservations with the same date ranges and block_ids' do + @hotel.create_block(3, @date_range) + @hotel.reservations.map { |res| res.date_range }.uniq.length.must_equal 1 + @hotel.reservations.map { |res| res.block_id }.uniq.length.must_equal 1 + end + + it 'throws an error if there are not enough rooms to create the block' do + 16.times do + @hotel.reserve_room(@date_range) + end + + proc { @hotel.create_block(5, @date_range) }.must_raise StandardError + end + end + + describe 'find_available_block_rooms method' do + before do + @hotel = Hotel::Admin.new + @date_range = Hotel::DateRange.new("May 6, 1982", "May 10, 1982") + end + + it 'returns an array of block reservations' do + @hotel.create_block(3, @date_range) + @hotel.find_available_block_rooms(1).must_be_kind_of Array + @hotel.find_available_block_rooms(1).each do |reservation| + reservation.must_be_instance_of Hotel::Reservation + reservation.block_id.wont_be_nil + reservation.block_status.wont_be_nil + end + end + + it 'finds the number of available rooms in a block given a block id' do + @hotel.create_block(3, @date_range) + @hotel.find_available_block_rooms(1).length.must_equal 3 + @hotel.reservations[0].change_status + @hotel.find_available_block_rooms(1).length.must_equal 2 + end + + it 'returns an empty array if there are no available rooms in the block' do + @hotel.create_block(1, @date_range) + @hotel.reservations[0].change_status + @hotel.find_available_block_rooms(1).must_equal [] + end + end + + describe 'reserve_block_room method' do + before do + @hotel = Hotel::Admin.new + @date_range = Hotel::DateRange.new("May 6, 1982", "May 10, 1982") + @hotel.create_block(2, @date_range) + end + + it 'throws an error if there are no availabe rooms in the requested block' do + @hotel.reservations[0].change_status + @hotel.reservations[1].change_status + proc { @hotel.reserve_block_room(1) }.must_raise StandardError + end + + it 'changes the block_status of the first available room from blocked to reserved' do + @hotel.reservations[0].block_status.must_equal :blocked + @hotel.reserve_block_room(1) + @hotel.reservations[0].block_status.must_equal :reserved + end + + it 'changes the number of available rooms in the block' do + @hotel.find_available_block_rooms(1).length.must_equal 2 + @hotel.reserve_block_room(1) + @hotel.find_available_block_rooms(1).length.must_equal 1 + end + end + end +end diff --git a/specs/date_range_spec.rb b/specs/date_range_spec.rb new file mode 100644 index 000000000..7d4fd5335 --- /dev/null +++ b/specs/date_range_spec.rb @@ -0,0 +1,93 @@ +require_relative 'spec_helper' + +describe 'DateRange class' do + + describe 'initialize method' do + it 'can be created' do + date_range = Hotel::DateRange.new('2018-03-09', '2018-03-12') + date_range.must_be_instance_of Hotel::DateRange + [:start_date, :end_date].each do |prop| + date_range.must_respond_to prop + end + end + + it 'throws an error if the date entry is an invalid format' do + proc { Hotel::DateRange.new('','') }.must_raise StandardError + proc { Hotel::DateRange.new(4, 5) }.must_raise StandardError + proc { Hotel::DateRange.new('33', '4') }.must_raise StandardError + end + + it 'throws an error if the starting and ending dates are the same' do + proc { Hotel::DateRange.new('2018-03-09', '2018-03-09') }.must_raise StandardError + end + + it 'throws an error if the ending date is earlier than the starting date' do + proc { Hotel::DateRange.new('2018-03-09', '2018-03-08') }.must_raise StandardError + end + end + + describe 'range method' do + before do + @date_range = Hotel::DateRange.new('2018-03-09', '2018-03-12') + end + + it 'returns an array of dates' do + @date_range.range.must_be_kind_of Array + @date_range.range.each do |date| + date.must_be_kind_of Date + end + end + + it 'includes the starting date and intermediate dates' do + @date_range.range.must_include @date_range.start_date + @date_range.range.must_include @date_range.start_date + 1 + @date_range.range.must_include @date_range.start_date + 2 + end + + it 'does not include the ending date' do + @date_range.range.wont_include @date_range.end_date + end + end + + describe 'overlap? method' do + before do + @room = Hotel::Room.new(1) + @date_range = Hotel::DateRange.new('2018-03-09', '2018-03-16') + end + + it 'returns false if there is no overlap between the date ranges' do + other = Hotel::DateRange.new('2018-04-09', '2018-04-16') + @date_range.overlap?(other).must_equal false + end + + it 'returns false if the given date range ends on the start date of the date range instance' do + other = Hotel::DateRange.new('2018-03-16', '2018-03-18') + @date_range.overlap?(other).must_equal false + end + + it 'returns false if the given date range begins on the end date of the date range instance' do + other = Hotel::DateRange.new('2018-03-07', '2018-03-09') + @date_range.overlap?(other).must_equal false + end + + it 'returns true if the given date range overlaps the beginning of the date range instance' do + other = Hotel::DateRange.new('2018-03-15', '2018-03-17') + @date_range.overlap?(other).must_equal true + end + + it 'returns true if the given date range overlaps the end of the date range instance' do + other = Hotel::DateRange.new('2018-03-07', '2018-03-10') + @date_range.overlap?(other).must_equal true + end + + it 'returns true if the given date range is completely contained by the date range instance' do + other = Hotel::DateRange.new('2018-03-07', '2018-03-18') + @date_range.overlap?(other).must_equal true + end + + it 'returns true if the given date range contains the date range instance' do + other = Hotel::DateRange.new('2018-03-11', '2018-03-13') + @date_range.overlap?(other).must_equal true + end + end +end diff --git a/specs/reservation_spec.rb b/specs/reservation_spec.rb new file mode 100644 index 000000000..670f7090f --- /dev/null +++ b/specs/reservation_spec.rb @@ -0,0 +1,100 @@ +require_relative 'spec_helper' + +describe 'Reservation class' do + describe 'initialize method' do + before do + @room = Hotel::Room.new(1) + @date_range = Hotel::DateRange.new('2018-03-09', '2018-03-12') + reservation_data = { + id: 100, + date_range: @date_range, + room: @room, + block_id: 1, + block_status: :blocked + } + @reservation = Hotel::Reservation.new(reservation_data) + end + + it 'creates an instance of Reservation' do + @reservation.must_be_instance_of Hotel::Reservation + + [:id, :date_range, :room, :block_id, :block_status].each do |prop| + @reservation.must_respond_to prop + end + + @reservation.id.must_be_kind_of Integer + @reservation.date_range.must_be_instance_of Hotel::DateRange + @reservation.room.must_be_instance_of Hotel::Room + @reservation.block_id.must_be_kind_of Integer + @reservation.block_status.must_be_kind_of Symbol + end + end + + describe 'cost method' do + it 'calculates the projected cost of the reservation' do + room = Hotel::Room.new(1) + date_range = Hotel::DateRange.new('2018-03-09', '2018-03-12') + reservation_data = { + id: 100, + date_range: date_range, + room: room + } + reservation = Hotel::Reservation.new(reservation_data) + + reservation.cost.must_be_kind_of Float + reservation.cost.must_equal 600.0 + end + + it 'calculates the projected cost of the reservation if it is part of a block' do + room = Hotel::Room.new(1) + date_range = Hotel::DateRange.new('2018-03-09', '2018-03-12') + reservation_data = { + id: 100, + date_range: date_range, + room: room, + block_id: 1 + } + reservation = Hotel::Reservation.new(reservation_data) + + reservation.cost.must_be_kind_of Float + reservation.cost.must_equal 450.0 + end + end + + # Reservation#overlap? method not tested because it only calls the DateRange#overlap method + # Tests for DateRange#overlap? included in date_range_spec file + + describe 'change_status method' do + before do + @hotel = Hotel::Admin.new + @date_range = Hotel::DateRange.new('2018-03-09', '2018-03-12') + @hotel.create_block(1, @date_range) + end + + it 'changes a block status to reserved if initially blocked' do + @hotel.reservations.first.block_status.must_equal :blocked + @hotel.reservations.first.change_status + @hotel.reservations.first.block_status.must_equal :reserved + end + + it 'changes a block status to blocked if initially reserved' do + @hotel.reservations.first.change_status + @hotel.reservations.first.block_status.must_equal :reserved + @hotel.reservations.first.change_status + @hotel.reservations.first.block_status.must_equal :blocked + end + + it 'does not change the block status of a reservation that is not part of a block' do + room = Hotel::Room.new(1) + reservation_data = { + id: 100, + date_range: @date_range, + room: room, + } + reservation = Hotel::Reservation.new(reservation_data) + reservation.block_status.must_be_nil + reservation.change_status + reservation.block_status.must_be_nil + end + end +end diff --git a/specs/room_spec.rb b/specs/room_spec.rb new file mode 100644 index 000000000..c762e0515 --- /dev/null +++ b/specs/room_spec.rb @@ -0,0 +1,24 @@ +require_relative 'spec_helper' + +describe 'Room class' do + + describe 'initialize method' do + before do + @room = Hotel::Room.new(1) + end + + it 'creates an instance of Room' do + @room.must_be_instance_of Hotel::Room + @room.must_respond_to :number + end + + it 'has a number' do + @room.number.must_be_kind_of Integer + end + + it 'throws an error if the room number is not between 1 and 20' do + proc { Hotel::Room.new(0) }.must_raise ArgumentError + proc { Hotel::Room.new(21) }.must_raise ArgumentError + end + end +end diff --git a/specs/spec_helper.rb b/specs/spec_helper.rb new file mode 100644 index 000000000..ad294f30e --- /dev/null +++ b/specs/spec_helper.rb @@ -0,0 +1,13 @@ +require 'simplecov' +SimpleCov.start + +require 'minitest' +require 'minitest/autorun' +require 'minitest/reporters' + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new + +require_relative '../lib/admin' +require_relative '../lib/date_range' +require_relative '../lib/reservation' +require_relative '../lib/room'