diff --git a/design-activity.md b/design-activity.md new file mode 100644 index 000000000..c3077492d --- /dev/null +++ b/design-activity.md @@ -0,0 +1,55 @@ +# What classes does each implementation include? Are the lists the same? +IMPLEMENTATION A includes the CartEntry class, the ShoppingCart class, and the Order class + +IMPLEMENTATION B includes the CartEntry class, the ShoppingCart class, and the Order class +The both have the same classes' names +# Write down a sentence to describe each class. +CartEntry class initializes a instance of an entry, it has price of the entry and the quantity of this entry +ShoppingCart class initializes an instance of a Cart, it has the an array of entries +The Order class calculates the total cost for the entries in 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: The Order class depends on the ShoppingCart class to create the cart with an entries array. The Order class, calculates the total price for all entries in the cart. + +IMPLEMENTATION B: The Order class depends on the ShoppingCart class to create the cart with an entries array. The ShoppingCart class calculates the price for all the items in the cart +# What data does each class store? How (if at all) does this differ between the two implementations? +IMPLEMENTATION A: +CartEntry stores unit price and quantity of an entry +ShoppingCart stores all the entries in an array +Order stores the cart that contains all the entries + +IMPLEMENTATION B: +CartEntry stores the unit price and quantity of an entry +ShoppingCart stores the all the entries in an array +Order stores the cart that contains all the entries +This does not 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: no methods +ShoppingCart: no methods +Order: total_price method to calculate the price for each entry, the price for all entries, and the total price including tax + +IMPLEMENTATION B: +CartEntry: price method to calculate the price for the entry (quantity and unit price) +ShoppingCart: price method to calculate total price for the cart (all entries) +Order: total price method to calculate the total price including tax + +#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? +#Does total_price directly manipulate the instance variables of other classes? +IMPLEMENTATION A: It's retained in Order +total_price directly manipulate instance variables of other classes (it calls the unit price and quantity instance variables from the Cart Entry, and the entries instance variable from the ShoppingCart class) + +IMPLEMENTATION B: It computes the price delegated to "lower lever" classes. The computes the total cost by applying the tax. +total_price doesn't directly manipulate instance variables of other classes (it calls the price method, but it is not an instance variable) + +#If we decide items are cheaper if bought in bulk, how would this change the code? Which implementation is easier to modify? +IMPLEMENTATION A: you will have to add an if statement in the do loop to calculate a discount if entry.quantity is of a certain number before adding it to the sum variable + +IMPLEMENTATION B: you will need to change the price method in the CartEntry class by calculating a discount if quantity is of certain items. + +IMPLEMENTATION B is easier to modify +#Which implementation better adheres to the single responsibility principle? +IMPLEMENTATION B because code that reads or modifies the instance variables of a class is wrapped in a method of that class +#Bonus question once you've read Metz ch. 3: Which implementation is more loosely coupled? +IMPLEMENTATION B is more loosely coupled because code that reads or modifies the instance variables of a class is wrapped in an instance method on that class. diff --git a/design-analysis-of-my-hotel.md b/design-analysis-of-my-hotel.md new file mode 100644 index 000000000..7743aba69 --- /dev/null +++ b/design-analysis-of-my-hotel.md @@ -0,0 +1,36 @@ +#What is this class's responsibility? +ROOM class: it keeps track of the rooms are reserved in a block reservation or in a regular reservation +Behaviors: +-it adds the range to the instance variable range +-it adds the block to the instance variable block +-it adds the reservation status of "booked" to the block variable instance + +RESERVATION class: it calculates cost of a reservation by creating instance variables + +ADMIN class: It holds the rooms and the reservations, checks if rooms are available for block reservations or regular reservations, and provides views for current reservations. +Behaviors: +-it creates the rooms instances +-it creates the reservation instances +-it reserves a room by calling the methods in the ROOM class +-it views vacant rooms by reading the instance variable "ranges" of the ROOM class ---improve here +-it views all the rooms by reading it's instance variable: rooms +-it finds a reservation by reading it's instance variable: reservation +-it finds the cost of a reservation by reading the instance variable of the RESERVATION class. +-it creates a block of rooms, by modifying the block instance variable of the ROOM class --- improve here +-it finds vacant rooms available for a block by reading the instance variable, ranges, of the ROOM class --- improve here +-it reserves a room in a block by modifying the block instance variable of the ROOM class --- improve here + +#Is this class responsible for exactly one thing? +ROOM class: not sure. I think no because it keeps track of blocks and regular reservation, and reserves rooms; but it doesn't change the instance variable of other classes so it is loosely coupled. +RESERVATION class: yes +ADMIN class: no (it checks if two reservations clashes before calling the reservation method in the ROOM class) + +#Does this class take on any responsibility that should be delegated to "lower level" classes? +ROOM class: no +RESERVATION class: no +ADMIN class: yes, viewing vacant rooms should be moved to the ROOM class, creating a block of rooms should be moved to the ROOM class, and reserving a room should be move to the ROOM class + +#Is there code in other classes that directly manipulates this class's instance variables? +ROOM class: yes, range and block are modified by methods in the ADMIN class (create block of rooms, and reserve a room) +RESERVATION class: no +ADMIN: no diff --git a/lib/admin.rb b/lib/admin.rb new file mode 100644 index 000000000..9ac150920 --- /dev/null +++ b/lib/admin.rb @@ -0,0 +1,277 @@ +require 'csv' +require 'pry' + +#REFACTOR_IDEAS: +# create helper method that creates instance of time, and a range + +class Admin + attr_reader :reservations, :find_reservation, :rooms, :vacant_rooms, :booked_rooms + def initialize + @reservations = load_reservations('spec/test_data/test_reservation.csv') + @rooms = create_rooms(20) + sort_reservations + end + + def create_rooms(number) + rooms = [] + number.times do |num| + input_data = {} + room_number = num + 1 + input_data[:number] = room_number + rooms << Room.new(input_data) + end + return rooms + end + + def load_reservations(filename) + reservations = [] + + CSV.read(filename, headers: true).each do |line| + data = line.to_h + input_data = {} + input_data[:id] = data["id"].to_i + input_data[:start_time] = Time.parse(data["start_time"]) + input_data[:end_time] = Time.parse(data["end_time"]) # no need to subtract last day because reservation class only calculates cost + # REFACTOR idea: make the reservation instance a separate method - isolating dependencies + reservations << Reservation.new(input_data) + end + + return reservations + end + + #As an administrator, I can reserve a room for a given date range + # uses view_vacant_rooms create range with one day less + def reserve_room(start_date, end_date) + start_date = Time.parse(start_date) + end_date = Time.parse(end_date) + range = create_hotel_range(start_date, end_date) # for hotel + e_date = end_date - 1 # rooms do not keep track of last night + vacant_rooms = view_vacant_rooms(start_date, e_date) + if vacant_rooms.nil? + # REFACTOR idea: begin rescue block, exception handleing + raise StandardError, "no rooms are available" + else + room = vacant_rooms.first + room.add_range(range) + input_data = {} + input_data[:start_time] = start_date + input_data[:end_time] = end_date + input_data[:room_num] = room.number + reservations << Reservation.new(input_data) + end + end + + #As an administrator, I can view a list of rooms that are not reserved for a given date range + ## expects dates to be instances of time + def view_vacant_rooms(start_date, end_date) + # I am editing the rooms! it's not making a copy + # I am just creating a new pointer that points to the same data as what rooms points to + vacant_rooms = @rooms + target_range = create_hotel_range(start_date, end_date) + vacant_rooms.each do |room| + ranges = room.ranges + ranges.each do |range| + # nil means no intersection + if intersection(target_range, range) != nil # there was a overlap + vacant_rooms.delete(room) + break # where does this go? it goes to the next room, if one range conflicts, I do not have to check if the others conflicts + end + end + end + + + # remove rooms that have a block in them + vacant_rooms_result = vacant_rooms.select do | room | + if room.blocks.empty? + room.blocks.empty? + else + intersection(target_range, room.blocks.first[:range]) == nil + end + end + + return vacant_rooms_result + + # QUEstion for later: how come this does not work without using select: Can't escape from eval with next + + # vacant_rooms.each do |room| + # if room.blocks.empty? == false + # if intersection(target_range, room.blocks.first[:range]) != nil # there was a overlap + # vacant_rooms.delete(room) + # end + # else # it does not have a block + # next # go to the next room + # end + # end + end + + # As an administrator, I can access the list of all of the rooms in the hotel + def view_all_rooms + return @rooms + end + + #As an administrator, I can access the list of reservations for a specific date + # I do not have to return a reservation that has specific date at the end + # In my program, the reservations have real checkout date + # In my program, the room class have real dates, not including the last check out date + # REFACTOR idea: to keep take out -1 day when you load reservation, but reservations calculates the cost based of nights - I wil have to fix that too + def find_reservations(date) + date = Time.parse(date) + reservations = @reservations.select do |instance| + start_date = instance.start_time + end_date = instance.end_time + end_date = end_date - 1 + if date_in_range(start_date, end_date, date) + instance + end + end + return reservations + end + + #As an administrator, I can get the total cost for a given reservation + #input is a reservation instance + def find_cost(reservation) + cost = reservation.cost + return cost + end + + #As an administrator, I can create a block of rooms + def create_block_rooms(data) + start_date = Time.parse(data[:start_date]) + end_date = Time.parse(data[:end_date]) + e_date = end_date - 1 + range = (start_date..e_date) + rooms = data[:rooms] + raise StandardError if rooms > 5 #max block size + discounted_rate = data[:discounted_rate] + # view vacant_rooms - current method + available_rooms = view_vacant_rooms_for_blocks(start_date, e_date) + + if available_rooms.length < rooms + return "no available rooms for block" + else + max = rooms - 1 # because of the 0 index + block_rooms = available_rooms[0 .. max] + input_data = {} + input_data[:discounted_rate] = discounted_rate + input_data[:range] = range + input_data[:status] = "available" + block_rooms.each do |room| + room.add_block(input_data) + end + end + end + + def view_vacant_rooms_for_blocks(start_date, end_date) + vacant_rooms = @rooms + target_range = create_hotel_range(start_date, end_date) + vacant_rooms.each do |room| + ranges = room.ranges + blocks = room.blocks + ranges.each do |range| + # nil means no intersection + if intersection(target_range, range) != nil # there was a overlap + vacant_rooms.delete(room) + break + end + end + blocks.each do |block| + # nil means no intersection + if intersection(target_range, blocks[:range]) != nil # there was a overlap + vacant_rooms.delete(room) + break + end + end + end + return vacant_rooms + end + +# As an administrator, I can reserve a room from within a block of rooms + def reserve_room_in_block(data) + room_num = data[:room_num] + range = data[:range] + room = @rooms.select { |room| room.number == room_num}[0] + room.reserve_room_block(range) + ### FUTURE WORK: 1. use method view_vacant_rooms_in_block before making a reservation + # => 2. create isntance of reservation + end + + # As an administrator, I can check whether a given block has any rooms available + def view_vacant_rooms_in_block(range) + available_rooms = [] + block_rooms = find_block(range) + block_rooms.each do |room| + #blocks variable is an array + blocks = room.blocks + blocks.each do |block| + if block[:status] == "available" + available_rooms << room + end + end + end + return available_rooms + end + # it is used in view_vacant_rooms_in_block method + def find_block(range) + #find block + rooms_with_blocks = @rooms.select { |room| room.blocks.empty? == false} + #blocks variable are an array + block_set = [] + rooms_with_blocks.each do |room| + blocks = room.blocks + blocks.each do |block| + if block[:range] == range + block_set << room + end + end + end + end + + #last day not counted + #expect input to be time instances + def create_hotel_range(start_date, end_date) + end_date = end_date - 1 + range = (start_date .. end_date) + return range + end + + # expects input to be time instances + def create_array_of_dates(start_date, end_date) + dates = [] + difference = end_date - start_date + difference = difference/86400 + difference.to_i.times do |i| + dates << start_date + (1+i) + end + return dates + end + + private + #never used currently + def sort_reservations + @reservations.sort_by { |object| object.start_time } + end + + def intersection(range, range2) + if (range.max < range2.begin or range2.max < range.begin) + return nil + else + return [range.begin, range2.begin].max..[range.max, range2.max].min + end + end + + def date_in_range(start_date, end_date, date) + range = (start_date .. end_date) + range.include?(date) + end + + # find range in an array of ranges, + #NOT USEFUL you need to check every day in the range not just that the ranges are not equal + def range_search(ranges, target) + ranges.each do |range| + if range == target + return true + end + end + return false + end +end diff --git a/lib/reservation.rb b/lib/reservation.rb new file mode 100644 index 000000000..b0145f5ec --- /dev/null +++ b/lib/reservation.rb @@ -0,0 +1,16 @@ +# the roal of this class is to calculate cost of a reservation, and check for invalid range +class Reservation + attr_reader :start_time, :end_time, :nights, :cost, :reservations, :id, :room_num + + def initialize(data) + #@id = data[:id] || 0 + @start_time = data[:start_time] + @end_time = data[:end_time] + @room_num = data[:room_num] || 0 + sec = @end_time - @start_time + @nights = sec.to_i / 86400 + rate = 200 if data[:rate].nil? + @cost = @nights * rate + raise StandardError if sec < 0 #invalid range + end +end diff --git a/lib/room.rb b/lib/room.rb new file mode 100644 index 000000000..1abf6117a --- /dev/null +++ b/lib/room.rb @@ -0,0 +1,30 @@ +class Room + attr_reader :number, :status, :ranges, :blocks + + def initialize(data) + @number = data[:number] + # rooms do not store the last day. Last day is reservation last day - 1 + @ranges = [] + @blocks = [] + end + + def add_range(range) + @ranges << range + end + + def add_block(data) + input_data = {} + input_data[:range] = data[:range] + input_data[:discounted_rate] = data[:discounted_rate] + input_data[:status] = data[:status] + @blocks << input_data + end + + def reserve_room_block(range) + target_block = blocks.select {|block| block[:range] == range}[0] + target_block[:status] = "booked" + end + # def sort_ranges + # @ranges.sort_by { |range| object.start_time } + # end +end diff --git a/refactor-analysis.md b/refactor-analysis.md new file mode 100644 index 000000000..5cc64c1d5 --- /dev/null +++ b/refactor-analysis.md @@ -0,0 +1,7 @@ +#How easy is it to follow your own instructions? +They make sense because I wrote them, but they could be more explicit for other to understand +5 bullet point, it's not clear where it appears. It should have something like "when you create a date range, if you don't want to include the last item in this case date, use 3 dots" +#Do these refactors improve the clarity of your code? +Mostly, some of them are not accurate like 4.2, the add_range does not add a block, it makes a reservation so it should be called create_reservation +#Do you still agree with your previous assesment, or could your refactor be further improved? +It could try to make sure that method from one class do not read or modifies instance variables loose coupled. diff --git a/refactor.txt b/refactor.txt new file mode 100644 index 000000000..fe2930611 --- /dev/null +++ b/refactor.txt @@ -0,0 +1,12 @@ +1. Room number variable same across all classes +3. Test spec file: use let when possible to make it faster +3.2 used nested describes (check if it works first) to create an instance of admin only once +4.In the room class, rename the add_range method to add_block +4.2 explore difference of creating a hash or a key word argument, and apply it when you only have two key-word pairs like +5. for range use ... to not include the last day (this way you don't have to keep subtracting) +6. move all helper methods into it's own class and keep admin tasks in its class + +one refactor can be the bug that I have where a reserve_room - check this method is grabbing the two rooms from my block +-check if room -> block <- is the @number here, the room for the block? verify this! Yes, it is the room number + +finish the reservation to reflect current reservations including the block room diff --git a/spec/admin_spec.rb b/spec/admin_spec.rb new file mode 100644 index 000000000..a503a8575 --- /dev/null +++ b/spec/admin_spec.rb @@ -0,0 +1,299 @@ +require_relative 'spec_helper' +# REFACTOR IDEAS: +# replace before with let inside of it, use a nested describe that way I only have to create a single let variable +# + +# runs from project directory +xdescribe "#Admin - initializer" do + before do + @admin = Admin.new + end + it "is an instance of Admin" do + dispatcher = Admin.new + expect(dispatcher).must_be_kind_of Admin + end + + it "accurately loads reservation information into reservations array" do + first_reservation = @admin.reservations.first + last_reservation = @admin.reservations.last + + expect(first_reservation.start_time).must_equal Time.parse("2018-08-08 00:00:00 -0700") + expect(first_reservation.end_time).must_equal Time.parse("2018-08-09 00:00:00 -0700") + expect(first_reservation.nights).must_equal 1 + expect(first_reservation.cost).must_equal 200 + + expect(last_reservation.start_time).must_equal Time.parse("2018-08-07 00:00:00 -0700") + expect(last_reservation.end_time).must_equal Time.parse("2018-08-09 00:00:00 -0700") + expect(last_reservation.nights).must_equal 2 + expect(last_reservation.cost).must_equal 400 + end + + it "accurately create_rooms" do + first_room = @admin.rooms.first + last_room = @admin.rooms.last + expect(first_room.number).must_equal 1 + expect(last_room.number).must_equal 20 + end +end + +xdescribe "#reservation information" do + before do + @admin = Admin.new + end + it "return the reservations that have a specific date, not including the last day" do + #arrange + # reservations are from test file + # 2,2018-08-07,2018-08-09 + # 1,2018-08-08,2018-08-09 + + date = "2018-08-08 00:00:00 -0700" + reservations = @admin.find_reservations(date) + + expect(reservations).must_be_kind_of Array + expect(reservations.length).must_equal 2 + end + + it "return the cost of a reservation" do + #arrange + reservation = @admin.reservations.first + reservation_cost = @admin.find_cost(reservation) + + expect(reservation_cost).must_be_kind_of Integer + expect(reservation_cost).must_equal 200 + end + +end + +xdescribe "#rooms information and reservation" do + before do + @admin = Admin.new + end + it "view all of the rooms" do + + rooms = @admin.view_all_rooms + expect(rooms).must_be_kind_of Array + end + + # REFACTOR idea: + # before and after count of rooms from driver + ## FUTURE WORK: needs a test for this case + # reservation is 1 - 2 + # and another one is 1 - 3, should include 2 rooms + # needs a test with arrange to have block rooms and to check result + + ## FUTURE WORK: needs a test that reservation was made # checked in binding.pry, but needs the test + it "can make a reservation" do + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + @admin.reserve_room(start_date, end_date) + + # reserve room removes last day because it is not counted as a paying night for my reservation class + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + start_date = Time.parse(start_date) + end_date = Time.parse(end_date) + end_date = end_date - 1 + range = [(start_date..end_date)] + expect(@admin.rooms.first.ranges). must_equal range + end + + it "no rooms available for 20 reservations" do + start_date = Time.parse("2018-08-07 00:00:00 -0700") + end_date = Time.parse("2018-08-09 00:00:00 -0700") + expect { + 20.times do + @admin.make_reservation(start_date, end_date) + end + }.must_raise StandardError + end + + it "view vacant rooms" do + # for reserve_room + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + @admin.reserve_room(start_date, end_date) + # for range and testing view vacant_rooms + s_date = Time.parse("2018-08-07 00:00:00 -0700") + # one day less because the last night is not payed and view_vacant_rooms takes care of that + e_date = Time.parse("2018-08-08 00:00:00 -0700") + e_date = e_date - 1 + vacant_rooms_result = @admin.view_vacant_rooms(s_date, e_date) + expect(vacant_rooms_result.length).must_equal 19 + # do I delete rooms from rooms? check for that + end +end + +xdescribe "#range tests" do + before do + @admin = Admin.new + end + + it "does not count the last day" do + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + start_date = Time.parse(start_date) + end_date = Time.parse(end_date) + test_date = Time.parse("2018-08-09 00:00:00 -0700") # last day + + result = @admin.create_hotel_range(start_date, end_date) + expect(result.include?(test_date)).must_equal false + end + + it "it creates an array of dates" do + start_date = Time.parse("2018-08-07 00:00:00 -0700") + end_date = Time.parse("2018-08-10 00:00:00 -0700") + result = @admin.create_array_of_dates(start_date, end_date) + expect(result.length).must_equal 3 + end +end + +describe "#blocks" do + before do + @admin = Admin.new + end + + it "create a block of rooms" do + skip + # reserve a normal room + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + @admin.reserve_room(start_date, end_date) + + # reserve a block room + data = {} + data[:block_id] = 1 + data[:start_date] = start_date + data[:end_date] = end_date + data[:rooms] = 4 + data[:discounted_rate] = 100 + @admin.create_block_rooms(data) + (0..3).each do |i| + expect(@admin.rooms[i].blocks).wont_be_empty + end + end + + it "raises an Standard error for invalid rooms for block" do + skip + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + @admin.reserve_room(start_date, end_date) + # for range and testing view vacant_rooms + # one day less because the last night is not payed and view_vacant_rooms takes care of that + + data = {} + data[:block_id] = 1 + data[:start_date] = start_date + data[:end_date] = end_date + data[:rooms] = 6 + data[:discounted_rate] = 100 + expect{ + @admin.create_block_rooms(data) + }.must_raise StandardError + end + + it "updates status of room block" do + skip + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + @admin.reserve_room(start_date, end_date) + # for range and testing view vacant_rooms + # one day less because the last night is not payed and view_vacant_rooms takes care of that + + data = {} + data[:block_id] = 1 + data[:start_date] = start_date + data[:end_date] = end_date + data[:rooms] = 4 + data[:discounted_rate] = 100 + @admin.create_block_rooms(data) + info = {} + + start_date = Time.parse("2018-08-07 00:00:00 -0700") + end_date = Time.parse("2018-08-09 00:00:00 -0700") + e_date = end_date - 1 + range = (start_date .. e_date) + info = {} + info[:room_num] = 2 + info[:range] = range + @admin.reserve_room_in_block(info) + room = @admin.rooms.select {|room| room.number == 2}.first + blocks = room.blocks + target_block = blocks.select {|block| block[:range] == range}[0] + expect(target_block[:status]).must_equal "booked" + end + + it "find a block" do + skip + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + data = {} + data[:block_id] = 1 + data[:start_date] = start_date + data[:end_date] = end_date + data[:rooms] = 4 + data[:discounted_rate] = 100 + @admin.create_block_rooms(data) + info = {} + + start_date = Time.parse("2018-08-07 00:00:00 -0700") + end_date = Time.parse("2018-08-09 00:00:00 -0700") + e_date = end_date - 1 + range = (start_date .. e_date) + info = {} + info[:room_num] = 2 + info[:range] = range + @admin.reserve_room_in_block(info) + rooms = @admin.find_block(range) + expect(rooms.length).must_equal 4 + end + + it "view_vacant_rooms_in_block" do + skip + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + data = {} + data[:block_id] = 1 + data[:start_date] = start_date + data[:end_date] = end_date + data[:rooms] = 4 + data[:discounted_rate] = 100 + @admin.create_block_rooms(data) + info = {} + + start_date = Time.parse("2018-08-07 00:00:00 -0700") + end_date = Time.parse("2018-08-09 00:00:00 -0700") + e_date = end_date - 1 + range = (start_date .. e_date) + info = {} + info[:room_num] = 2 + info[:range] = range + @admin.reserve_room_in_block(info) + rooms = @admin.view_vacant_rooms_in_block(range) + expect(rooms.length).must_equal 3 + end + + it "an outsider of a party can't reserve a room in a block" do + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + data = {} + data[:block_id] = 1 + data[:start_date] = start_date + data[:end_date] = end_date + data[:rooms] = 4 + data[:discounted_rate] = 100 + # it creates 4 room blocks + @admin.create_block_rooms(data) + + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + @admin.reserve_room(start_date, end_date) + # to test the expected result + start_date = "2018-08-07 00:00:00 -0700" + end_date = "2018-08-09 00:00:00 -0700" + start_date = Time.parse(start_date) + end_date = Time.parse(end_date) + range = [(start_date...end_date)] + # 4 is 5 room - index starts at 0 + expect(@admin.rooms[4].ranges).wont_be_empty + end +end diff --git a/spec/reservation_spec.rb b/spec/reservation_spec.rb new file mode 100644 index 000000000..e074d0f64 --- /dev/null +++ b/spec/reservation_spec.rb @@ -0,0 +1,29 @@ +require_relative 'spec_helper' + +describe "#initialize method in reservation class" do + before do + @reservation = Reservation.new(start_time: Time.parse("2016-08-08"), end_time: Time.parse("2016-08-09")) + end + + it "is an instance of a reservation" do + expect(@reservation).must_be_kind_of Reservation + end + + it "calculate number of nights" do + expect(@reservation.nights).must_equal 1 + end + + it "calculate cost" do + expect(@reservation.cost).must_equal 200 + end + + it "raises an Standard error for invalid date range, end time before start time" do + @reservation = {start_time: Time.parse("2016-08-09"), end_time: Time.parse("2016-08-08")} + expect{ + Reservation.new(@reservation) + }.must_raise StandardError + end +end + + + # diff --git a/spec/room_spec.rb b/spec/room_spec.rb new file mode 100644 index 000000000..e4af4b1c3 --- /dev/null +++ b/spec/room_spec.rb @@ -0,0 +1,15 @@ +require_relative 'spec_helper' + +describe "#Room - initialize method" do + before do + @Room = Room.new(number: 1) + end + + it "is an instance of a Room" do + expect(@Room).must_be_kind_of Room + end + + it "has a room number" do + expect(@Room.number).must_equal 1 + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4d1e3fdc8..e36f0d897 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,8 +1,17 @@ +require 'time' +require 'simplecov' +SimpleCov.start require 'minitest' require 'minitest/autorun' require 'minitest/reporters' +require 'minitest/skip_dsl' + # Add simplecov + Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new # Require_relative your lib files here! +require_relative '../lib/reservation' +require_relative '../lib/admin' +require_relative '../lib/room' diff --git a/spec/test_data/test_reservation.csv b/spec/test_data/test_reservation.csv new file mode 100644 index 000000000..60744fbdb --- /dev/null +++ b/spec/test_data/test_reservation.csv @@ -0,0 +1,3 @@ +id,start_time,end_time +1,2018-08-08,2018-08-09 +2,2018-08-07,2018-08-09