acts_as_bookable 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +43 -0
  6. data/Appraisals +21 -0
  7. data/Gemfile +21 -0
  8. data/Gemfile.lock +168 -0
  9. data/Guardfile +5 -0
  10. data/MIT-LICENSE +20 -0
  11. data/README.md +473 -0
  12. data/Rakefile +19 -0
  13. data/acts_as_bookable.gemspec +41 -0
  14. data/app/assets/images/acts_as_bookable/.keep +0 -0
  15. data/app/assets/javascripts/acts_as_bookable/application.js +13 -0
  16. data/app/assets/stylesheets/acts_as_bookable/application.css +15 -0
  17. data/app/controllers/acts_as_bookable/application_controller.rb +4 -0
  18. data/app/helpers/acts_as_bookable/application_helper.rb +4 -0
  19. data/app/views/layouts/acts_as_bookable/application.html.erb +14 -0
  20. data/bin/rails +12 -0
  21. data/config/locales/en.yml +12 -0
  22. data/config/routes.rb +2 -0
  23. data/db/migrate/20160217085200_create_acts_as_bookable_bookings.rb +14 -0
  24. data/gemfiles/activerecord_3.2.gemfile +16 -0
  25. data/gemfiles/activerecord_4.0.gemfile +16 -0
  26. data/gemfiles/activerecord_4.1.gemfile +16 -0
  27. data/gemfiles/activerecord_4.2.gemfile +17 -0
  28. data/gemfiles/activerecord_5.0.gemfile +17 -0
  29. data/lib/acts_as_bookable/bookable/core.rb +285 -0
  30. data/lib/acts_as_bookable/bookable.rb +56 -0
  31. data/lib/acts_as_bookable/booker.rb +70 -0
  32. data/lib/acts_as_bookable/booking.rb +54 -0
  33. data/lib/acts_as_bookable/db_utils.rb +39 -0
  34. data/lib/acts_as_bookable/engine.rb +5 -0
  35. data/lib/acts_as_bookable/t.rb +11 -0
  36. data/lib/acts_as_bookable/time_utils.rb +135 -0
  37. data/lib/acts_as_bookable/version.rb +3 -0
  38. data/lib/acts_as_bookable.rb +42 -0
  39. data/lib/tasks/acts_as_bookable_tasks.rake +4 -0
  40. data/spec/acts_as_bookable/acts_as_bookable_spec.rb +52 -0
  41. data/spec/acts_as_bookable/acts_as_booker_spec.rb +57 -0
  42. data/spec/acts_as_bookable/bookable/core_spec.rb +593 -0
  43. data/spec/acts_as_bookable/bookable_spec.rb +124 -0
  44. data/spec/acts_as_bookable/booker_spec.rb +140 -0
  45. data/spec/acts_as_bookable/booking_spec.rb +241 -0
  46. data/spec/acts_as_bookable/schedule_spec.rb +137 -0
  47. data/spec/acts_as_bookable/time_utils_spec.rb +525 -0
  48. data/spec/factories/bookable.rb +7 -0
  49. data/spec/factories/booker.rb +5 -0
  50. data/spec/factories/room.rb +11 -0
  51. data/spec/internal/app/models/Bookable.rb +3 -0
  52. data/spec/internal/app/models/Booker.rb +3 -0
  53. data/spec/internal/app/models/Event.rb +3 -0
  54. data/spec/internal/app/models/Generic.rb +2 -0
  55. data/spec/internal/app/models/NotBooker.rb +2 -0
  56. data/spec/internal/app/models/Room.rb +3 -0
  57. data/spec/internal/app/models/Show.rb +3 -0
  58. data/spec/internal/app/models/Unbookable.rb +2 -0
  59. data/spec/internal/config/database.yml.sample +17 -0
  60. data/spec/internal/db/schema.rb +51 -0
  61. data/spec/spec_helper.rb +26 -0
  62. data/spec/support/0-helpers.rb +32 -0
  63. data/spec/support/1-database.rb +42 -0
  64. data/spec/support/2-database_cleaner.rb +21 -0
  65. data/spec/support/3-factory_girl.rb +12 -0
  66. metadata +296 -0
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Bookable model' do
4
+ before(:each) do
5
+ @bookable = build(:bookable)
6
+ end
7
+
8
+ describe 'conditional validations' do
9
+ it 'should be valid with all required fields set' do
10
+ expect(@bookable).to be_valid
11
+ end
12
+
13
+ it 'should save a bookable' do
14
+ expect(@bookable.save).to be_truthy
15
+ end
16
+
17
+ describe 'when capacity is required' do
18
+ before(:each) do
19
+ Bookable.booking_opts[:capacity_type] = :closed
20
+ Bookable.initialize_acts_as_bookable_core
21
+ end
22
+ after(:all) do
23
+ Bookable.booking_opts = {}
24
+ Bookable.initialize_acts_as_bookable_core
25
+ end
26
+
27
+ it 'should not validate with capacity < 0 if capacity is required' do
28
+ @bookable.capacity = -1
29
+ expect(@bookable.valid?).to be_falsy
30
+ end
31
+
32
+ it 'should not validate without capacity' do
33
+ @bookable.capacity = nil
34
+ expect(@bookable.valid?).to be_falsy
35
+ end
36
+ end
37
+
38
+ describe 'when capacity is not required' do
39
+ before(:each) do
40
+ Bookable.booking_opts[:capacity_type] = :none
41
+ Bookable.initialize_acts_as_bookable_core
42
+ end
43
+ after(:all) do
44
+ Bookable.booking_opts = {}
45
+ Bookable.initialize_acts_as_bookable_core
46
+ end
47
+
48
+ it 'should validate with capacity < 0' do
49
+ @bookable.capacity = -1
50
+ expect(@bookable.valid?).to be_truthy
51
+ end
52
+
53
+ it 'should validate without capacity if it\'s not required' do
54
+ @bookable.capacity = nil
55
+ expect(@bookable.valid?).to be_truthy
56
+ end
57
+ end
58
+
59
+ describe 'when schedule is required' do
60
+ before(:each) do
61
+ Bookable.booking_opts[:time_type] = :range
62
+ Bookable.initialize_acts_as_bookable_core
63
+ end
64
+ after(:all) do
65
+ Bookable.booking_opts = {}
66
+ Bookable.initialize_acts_as_bookable_core
67
+ end
68
+
69
+ it 'should not validate without schedule' do
70
+ @bookable.schedule = nil
71
+ expect(@bookable.valid?).to be_falsy
72
+ end
73
+ end
74
+
75
+ describe 'when schedule is not required' do
76
+ before(:each) do
77
+ Bookable.booking_opts[:time_type] = :none
78
+ Bookable.initialize_acts_as_bookable_core
79
+ end
80
+ after(:all) do
81
+ Bookable.booking_opts = {}
82
+ Bookable.initialize_acts_as_bookable_core
83
+ end
84
+
85
+ it 'should validate without schedule if it\'s not required' do
86
+ @bookable.schedule = nil
87
+ expect(@bookable.valid?).to be_truthy
88
+ end
89
+ end
90
+ end
91
+
92
+
93
+ describe 'has_many :bookings' do
94
+ before(:each) do
95
+ @bookable.save!
96
+ booker1 = create(:booker, name: 'Booker 1')
97
+ booker2 = create(:booker, name: 'Booker 2')
98
+ booking1 = ActsAsBookable::Booking.create!(booker: booker1, bookable: @bookable)
99
+ booking2 = ActsAsBookable::Booking.create!(booker: booker1, bookable: @bookable)
100
+ @bookable.reload
101
+ end
102
+
103
+ it 'should have many bookings' do
104
+ expect(@bookable.bookings).to be_present
105
+ expect(@bookable.bookings.count).to eq 2
106
+ end
107
+
108
+ it 'dependent: :destroy' do
109
+ count = ActsAsBookable::Booking.count
110
+ @bookable.destroy
111
+ expect(ActsAsBookable::Booking.count).to eq count -2
112
+ end
113
+ end
114
+
115
+ describe '#schedule' do
116
+ it 'allows for creation of a bookable with a IceCube schedule' do
117
+ schedule = IceCube::Schedule.new
118
+ # Every Monday,Tuesday and Friday
119
+ schedule.add_recurrence_rule IceCube::Rule.weekly.day(:monday, :tuesday, :friday)
120
+ @bookable.schedule = schedule
121
+ expect(@bookable.save).to be_truthy
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,140 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Booker model' do
4
+ before(:each) do
5
+ @booker = build(:booker)
6
+ end
7
+
8
+ it 'should be valid with all required fields set' do
9
+ expect(@booker).to be_valid
10
+ end
11
+
12
+ it 'should save a booker' do
13
+ expect(@booker.save).to be_truthy
14
+ end
15
+
16
+ describe 'has_many :bookings' do
17
+ before(:each) do
18
+ @booker.save!
19
+ bookable1 = create(:bookable)
20
+ bookable2 = create(:bookable)
21
+ booking1 = ActsAsBookable::Booking.create(bookable: bookable1, booker: @booker)
22
+ booking2 = ActsAsBookable::Booking.create(bookable: bookable2, booker: @booker)
23
+ @booker.reload
24
+ end
25
+
26
+ it 'should have many bookings' do
27
+ expect(@booker.bookings).to be_present
28
+ expect(@booker.bookings.count).to eq 2
29
+ end
30
+
31
+ it 'dependent: :destroy' do
32
+ count = ActsAsBookable::Booking.count
33
+ @booker.destroy
34
+ expect(ActsAsBookable::Booking.count).to eq count -2
35
+ end
36
+ end
37
+
38
+ describe '#book!' do
39
+ before(:each) do
40
+ @bookable = create(:room)
41
+
42
+ end
43
+
44
+ it 'should respond to #book!' do
45
+ expect(@booker).to respond_to :book!
46
+ end
47
+
48
+ it 'should create a new booking' do
49
+ count = @booker.bookings.count
50
+ new_booking = @booker.book!(@bookable, time_start: Date.today, time_end: Date.today + 1.day, amount: 2)
51
+ expect(@booker.bookings.count).to eq count+1
52
+ expect(new_booking.class.to_s).to eq "ActsAsBookable::Booking"
53
+ end
54
+
55
+ it 'new booking should have all fields set' do
56
+ new_booking = @booker.book!(@bookable, time_start: Date.today, time_end: Date.today + 1.day, amount: 2)
57
+ new_booking.reload
58
+ expect(new_booking.time_start).to be_present
59
+ expect(new_booking.time_end).to be_present
60
+ expect(new_booking.amount).to be_present
61
+ end
62
+
63
+ it 'should raise ActiveRecord::RecordInvalid if new booking is not valid' do
64
+ expect{ @booker.book!(Generic.new) }.to raise_error ActiveRecord::RecordInvalid
65
+ end
66
+
67
+ it 'should not create a new booking if it\'s not valid' do
68
+ count = @booker.bookings.count
69
+ begin
70
+ @booker.book!(Generic.new)
71
+ rescue ActiveRecord::RecordInvalid => er
72
+ end
73
+ expect(@booker.bookings.count).to eq count
74
+ end
75
+
76
+ it 'should raise ActsAsBookable::AvailabilityError if the bookable is not available' do
77
+ @booker.book!(@bookable, time_start: Date.today, time_end: Date.today + 1.day, amount: 2)
78
+ expect{ @booker.book!(@bookable, time_start: Date.today, time_end: Date.today + 1.day, amount: 2)}.to raise_error ActsAsBookable::AvailabilityError
79
+ end
80
+ end
81
+
82
+
83
+
84
+ # describe 'Booker Method Generation' do
85
+ # before :each do
86
+ # Generic.acts_as_booker
87
+ # @booker = Generic.new()
88
+ # end
89
+ #
90
+ # it "should responde 'true' to booker?" do
91
+ # expect(@booker.class).to be_booker
92
+ # end
93
+ # end
94
+ #
95
+ # describe 'class configured as Booker' do
96
+ # before(:each) do
97
+ # @booker = Booker.new
98
+ # end
99
+ #
100
+ # it 'should add #booker? query method to the class-side' do
101
+ # expect(Booker).to respond_to(:booker?)
102
+ # end
103
+ #
104
+ # it 'should return true from the class-side #booker?' do
105
+ # expect(Booker.booker?).to be_truthy
106
+ # end
107
+ #
108
+ # it 'should return false from the base #booker?' do
109
+ # expect(ActiveRecord::Base.booker?).to be_falsy
110
+ # end
111
+ #
112
+ # it 'should add #booker? query method to the singleton' do
113
+ # expect(@booker).to respond_to(:booker?)
114
+ # end
115
+ #
116
+ # it 'should add #booker? query method to the instance-side' do
117
+ # expect(@booker).to respond_to(:booker?)
118
+ # end
119
+ #
120
+ # it 'should add #booker? query method to the instance-side' do
121
+ # expect(@booker.booker?).to be_truthy
122
+ # end
123
+ #
124
+ # # it 'should add #tag method on the instance-side' do
125
+ # # expect(@booker).to respond_to(:tag)
126
+ # # end
127
+ #
128
+ # # it 'should generate an association for #owned_taggings and #owned_tags' do
129
+ # # expect(@booker).to respond_to(:owned_taggings, :owned_tags)
130
+ # # end
131
+ # end
132
+ #
133
+ # describe 'Reloading' do
134
+ # it 'should save a model instantiated by Model.find' do
135
+ # booker = Generic.create!(name: 'Booker')
136
+ # found_booker = Generic.find(booker.id)
137
+ # expect(found_booker.save).to eq true
138
+ # end
139
+ # end
140
+ end
@@ -0,0 +1,241 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Booking model' do
4
+ before(:each) do
5
+ @booking = ActsAsBookable::Booking.new(amount: 2)
6
+ @booker = create(:booker)
7
+ @bookable = create(:bookable)
8
+ @booking.booker = @booker
9
+ @booking.bookable = @bookable
10
+ end
11
+
12
+ it 'should be valid with all required fields set' do
13
+ expect(@booking).to be_valid
14
+ end
15
+
16
+ it 'should save a booking' do
17
+ expect(@booking.save).to be_truthy
18
+ end
19
+
20
+ it 'should not be valid without a booker' do
21
+ @booking.booker = nil
22
+ expect(@booking).not_to be_valid
23
+ end
24
+
25
+ it 'should not be valid without a bookable' do
26
+ @booking.bookable = nil
27
+ expect(@booking).not_to be_valid
28
+ end
29
+
30
+ it 'should not be valid if booking.booker.booker? is false' do
31
+ not_booker = Generic.create(name: 'New generic model')
32
+ @booking.booker = not_booker
33
+ expect(@booking).not_to be_valid
34
+ expect(@booking.errors.messages[:booker]).to be_present
35
+ expect(@booking.errors.messages[:booker][0]).to include "Generic"
36
+ expect(@booking.errors.messages).not_to include "missing translation"
37
+ end
38
+
39
+ it 'should not be valid if booking.bookable.bookable? is false' do
40
+ bookable = Generic.create(name: 'New generic model')
41
+ @booking.bookable = bookable
42
+ expect(@booking).not_to be_valid
43
+ expect(@booking.errors.messages[:bookable]).to be_present
44
+ expect(@booking.errors.messages[:bookable][0]).to include "Generic"
45
+ expect(@booking.errors.messages).not_to include "missing translation"
46
+ end
47
+
48
+ it 'should belong to booker' do
49
+ expect(@booking.booker.id).to eq @booker.id
50
+ end
51
+
52
+ it 'should belong to bookable' do
53
+ expect(@booking.bookable.id).to eq @bookable.id
54
+ end
55
+
56
+ describe "overlapped scope" do
57
+
58
+ describe "without time" do
59
+ it "returns a booking without checking the time" do
60
+ time = Date.today.to_time
61
+ booking = ActsAsBookable::Booking.create!(time_start: nil, time_end: nil, time: time, bookable: @bookable, booker: @booker)
62
+ opts = {}
63
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts).count).to eq 1
64
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[0].id).to eq booking.id
65
+ end
66
+
67
+ it "returns all the bookings without checking the time" do
68
+ booking1 = ActsAsBookable::Booking.create!(time_start: nil, time_end: nil, time: Time.now, bookable: @bookable, booker: @booker)
69
+ booking2 = ActsAsBookable::Booking.create!(time_start: Time.now, time_end: Time.now + 3.hours, time: nil, bookable: @bookable, booker: @booker)
70
+ booking3 = ActsAsBookable::Booking.create!(time_start: Time.now - 10.days, time_end: Time.now - 9.days, time: nil, bookable: @bookable, booker: @booker)
71
+ opts = {}
72
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts).count).to eq 3
73
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[0].id).to eq booking1.id
74
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[1].id).to eq booking2.id
75
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[2].id).to eq booking3.id
76
+ end
77
+ end
78
+
79
+ describe "with fixed time" do
80
+ it "returns overlapped booking" do
81
+ time = Date.today.to_time
82
+ booking = ActsAsBookable::Booking.create!(time_start: nil, time_end: nil, time: time, bookable: @bookable, booker: @booker)
83
+ opts = {time: time}
84
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts).count).to eq 1
85
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[0].id).to eq booking.id
86
+ end
87
+
88
+ it "returns all the overlapped bookings" do
89
+ time = Date.today.to_time
90
+ booking1 = ActsAsBookable::Booking.create!(time_start: nil, time_end: nil, time: time, bookable: @bookable, booker: @booker)
91
+ booking2 = ActsAsBookable::Booking.create!(time_start: nil, time_end: nil, time: time, bookable: @bookable, booker: @booker)
92
+ booking3 = ActsAsBookable::Booking.create!(time_start: nil, time_end: nil, time: time + 1.hour, bookable: @bookable, booker: @booker)
93
+ opts = {time: time}
94
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts).count).to eq 2
95
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[0].id).to eq booking1.id
96
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[1].id).to eq booking2.id
97
+ end
98
+
99
+ it "returns no overlapped booking if time is wrong" do
100
+ time = Date.today.to_time
101
+ booking = ActsAsBookable::Booking.create!(time_start: nil, time_end: nil, time: time, bookable: @bookable, booker: @booker)
102
+ opts = {time: (time + 1.hour)}
103
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts).count).to eq 0
104
+ end
105
+ end
106
+
107
+ describe "with time range" do
108
+ it "returns overlapped booking" do
109
+ time_start = Date.today.to_time
110
+ time_end = Date.today.to_time + 10.hours
111
+ booking = ActsAsBookable::Booking.create!(time_start: time_start, time_end: time_end, time: nil, bookable: @bookable, booker: @booker)
112
+ opts = { time_start: time_start, time_end: time_end }
113
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts).count).to eq 1
114
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[0].id).to eq booking.id
115
+ end
116
+
117
+ it "returns more overlapped bookings" do
118
+ time_start = Date.today.to_time
119
+ time_end = Date.today.to_time + 10.hours
120
+ booking1 = ActsAsBookable::Booking.create!(time_start: time_start, time_end: time_end, time: nil, bookable: @bookable, booker: @booker)
121
+ booking2 = ActsAsBookable::Booking.create!(time_start: time_start, time_end: time_end, time: nil, bookable: @bookable, booker: @booker)
122
+ booking3 = ActsAsBookable::Booking.create!(time_start: time_start-10.days, time_end: time_end-10.days, time: nil, bookable: @bookable, booker: @booker)
123
+ opts = { time_start: time_start, time_end: time_end }
124
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts).count).to eq 2
125
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[0].id).to eq booking1.id
126
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[1].id).to eq booking2.id
127
+ end
128
+
129
+ it "doesn't return any booking if time is wrong" do
130
+ time_start = Date.today.to_time
131
+ time_end = Date.today.to_time + 10.hours
132
+ booking = ActsAsBookable::Booking.create!(time_start: time_start - 10.days, time_end: time_end - 10.days, time: nil, bookable: @bookable, booker: @booker)
133
+ opts = { time_start: time_start, time_end: time_end }
134
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts).count).to eq 0
135
+ end
136
+
137
+ it "returns also a booking overlapping but with time_start outside interval" do
138
+ time_start = Date.today.to_time
139
+ time_end = Date.tomorrow.to_time
140
+ booking = ActsAsBookable::Booking.create!(time_start: time_start - 10.hours, time_end: time_end, bookable: @bookable, booker: @booker)
141
+ opts = { time_start: time_start, time_end: time_end }
142
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts).count).to eq 1
143
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[0].id).to eq booking.id
144
+ end
145
+
146
+ it "returns also a booking overlapping but with time_end outside interval" do
147
+ time_start = Date.today.to_time
148
+ time_end = Date.tomorrow.to_time
149
+ booking = ActsAsBookable::Booking.create!(time_start: time_start, time_end: time_end + 10.hours, bookable: @bookable, booker: @booker)
150
+ opts = { time_start: time_start, time_end: time_end }
151
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts).count).to eq 1
152
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[0].id).to eq booking.id
153
+ end
154
+
155
+ it "returns more overlapped bookings, some of them not completely overlapping" do
156
+ time_start = Date.today.to_time
157
+ time_end = Date.today.to_time + 10.hours
158
+ booking1 = ActsAsBookable::Booking.create!(time_start: time_start - 5.hours, time_end: time_end - 5.hours, time: nil, bookable: @bookable, booker: @booker)
159
+ booking2 = ActsAsBookable::Booking.create!(time_start: time_start + 5.hours, time_end: time_end + 5.hours, time: nil, bookable: @bookable, booker: @booker)
160
+ booking3 = ActsAsBookable::Booking.create!(time_start: time_start + 2.hours, time_end: time_end - 2.hours, time: nil, bookable: @bookable, booker: @booker)
161
+ booking4 = ActsAsBookable::Booking.create!(time_start: time_start-10.days, time_end: time_end-10.days, time: nil, bookable: @bookable, booker: @booker)
162
+ booking4 = ActsAsBookable::Booking.create!(time_start: time_start+10.days, time_end: time_end+10.days, time: nil, bookable: @bookable, booker: @booker)
163
+ opts = { time_start: time_start, time_end: time_end }
164
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts).count).to eq 3
165
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[0].id).to eq booking1.id
166
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[1].id).to eq booking2.id
167
+ expect(ActsAsBookable::Booking.overlapped(@bookable,opts)[2].id).to eq booking3.id
168
+ end
169
+
170
+ describe "should handle limit cases" do
171
+ before :each do
172
+ @time_start = Date.today.to_time
173
+ @time_end = Date.today.to_time + 10.hours
174
+
175
+ @time_before_start = @time_start - 1.second
176
+ @time_after_start = @time_start + 1.second
177
+ @time_before_end = @time_end - 1.second
178
+ @time_after_end = @time_end + 1.second
179
+
180
+ @opts = { time_start: @time_start, time_end: @time_end }
181
+ end
182
+
183
+ it "excludes intervals with end before time_start and start after time_end" do
184
+ booking1 = ActsAsBookable::Booking.create!(time_start: @time_start - 5.hours, time_end: @time_before_start, time: nil, bookable: @bookable, booker: @booker)
185
+ booking2 = ActsAsBookable::Booking.create!(time_start: @time_after_end, time_end: @time_end + 5.hours, time: nil, bookable: @bookable, booker: @booker)
186
+ expect(ActsAsBookable::Booking.overlapped(@bookable,@opts).count).to eq 0
187
+ end
188
+
189
+ it "excludes intervals with start matching exactly with time_end" do
190
+ booking1 = ActsAsBookable::Booking.create!(time_start: @time_end, time_end: @time_end + 2.hours, time: nil, bookable: @bookable, booker: @booker)
191
+ expect(ActsAsBookable::Booking.overlapped(@bookable,@opts).count).to eq 0
192
+ end
193
+
194
+ it "includes intervals with end after time_start" do
195
+ booking1 = ActsAsBookable::Booking.create!(time_start: @time_start - 5.hours, time_end: @time_after_start, time: nil, bookable: @bookable, booker: @booker)
196
+ expect(ActsAsBookable::Booking.overlapped(@bookable,@opts).count).to eq 1
197
+ end
198
+
199
+ it "includes intervals with end exactly at time_start" do
200
+ booking1 = ActsAsBookable::Booking.create!(time_start: @time_start - 5.hours, time_end: @time_start, time: nil, bookable: @bookable, booker: @booker)
201
+ expect(ActsAsBookable::Booking.overlapped(@bookable,@opts).count).to eq 1
202
+ end
203
+ end
204
+
205
+ describe "should convert dates to times" do
206
+ before :each do
207
+ @time_start = Date.today
208
+ @time_end = Date.tomorrow
209
+
210
+ @time_before_start = @time_start - 1.second
211
+ @time_after_start = @time_start + 1.second
212
+ @time_before_end = @time_end - 1.second
213
+ @time_after_end = @time_end + 1.second
214
+
215
+ @opts = { time_start: @time_start, time_end: @time_end }
216
+ end
217
+
218
+ it "excludes intervals with end before time_start and start after time_end" do
219
+ booking1 = ActsAsBookable::Booking.create!(time_start: @time_start - 5.hours, time_end: @time_before_start, time: nil, bookable: @bookable, booker: @booker)
220
+ booking2 = ActsAsBookable::Booking.create!(time_start: @time_after_end, time_end: @time_end + 5.hours, time: nil, bookable: @bookable, booker: @booker)
221
+ expect(ActsAsBookable::Booking.overlapped(@bookable,@opts).count).to eq 0
222
+ end
223
+
224
+ it "excludes intervals with start matching exactly with time_end" do
225
+ booking1 = ActsAsBookable::Booking.create!(time_start: @time_end, time_end: @time_end + 2.hours, time: nil, bookable: @bookable, booker: @booker)
226
+ expect(ActsAsBookable::Booking.overlapped(@bookable,@opts).count).to eq 0
227
+ end
228
+
229
+ it "includes intervals with end after time_start" do
230
+ booking1 = ActsAsBookable::Booking.create!(time_start: @time_start - 5.hours, time_end: @time_after_start, time: nil, bookable: @bookable, booker: @booker)
231
+ expect(ActsAsBookable::Booking.overlapped(@bookable,@opts).count).to eq 1
232
+ end
233
+
234
+ it "includes intervals with end exactly at time_start" do
235
+ booking1 = ActsAsBookable::Booking.create!(time_start: @time_start - 5.hours, time_end: @time_start, time: nil, bookable: @bookable, booker: @booker)
236
+ expect(ActsAsBookable::Booking.overlapped(@bookable,@opts).count).to eq 1
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Schedules' do
4
+ describe "Room schedules" do
5
+ before :each do
6
+ @test_from = '2016-02-01'.to_date # it's a monday
7
+ @schedule = IceCube::Schedule.new @test_from
8
+ @schedule.add_recurrence_rule IceCube::Rule.weekly.day(:monday,:tuesday,:wednesday,:thursday,:friday)
9
+ end
10
+
11
+ it "Weekly, From monday to friday" do
12
+ # Weekly, From monday to friday
13
+ expect(@schedule.occurring_at?(@test_from)).to be true
14
+ expect(@schedule.occurring_at?(@test_from + 1.day)).to be true
15
+ expect(@schedule.occurring_at?(@test_from + 2.day)).to be true
16
+ expect(@schedule.occurring_at?(@test_from + 3.day)).to be true
17
+ expect(@schedule.occurring_at?(@test_from + 4.day)).to be true
18
+ expect(@schedule.occurring_at?(@test_from + 5.day)).to be false
19
+ expect(@schedule.occurring_at?(@test_from + 6.day)).to be false
20
+ end
21
+
22
+ it "doesn't match if not at exact minute" do
23
+ expect(@schedule.occurring_at?(@test_from + 1.minute)).to be false
24
+ end
25
+
26
+ describe "with daily duration" do
27
+ before :each do
28
+ @test_from = '2016-02-01'.to_date # it's a monday
29
+ @schedule = IceCube::Schedule.new @test_from
30
+ @schedule.add_recurrence_rule IceCube::Rule.weekly.day(:monday,:tuesday,:wednesday,:thursday,:friday)
31
+ @schedule.duration = 1.day
32
+ end
33
+
34
+ it "match with the exact minute" do
35
+ # Weekly, From monday to friday
36
+ expect(@schedule.occurring_at?(@test_from)).to be true
37
+ end
38
+
39
+ it "matches if not at exact minute" do
40
+ expect(@schedule.occurring_at?(@test_from + 1.minute)).to be true
41
+ end
42
+
43
+ it "matches if at end of day" do
44
+ expect(@schedule.occurring_at?(@test_from + 1.day - 1.minute)).to be true
45
+ expect(@schedule.occurring_at?(@test_from + 1.day - 1.minute)).to be true
46
+ expect(@schedule.occurring_at?(@test_from + 4.day - 1.second)).to be true
47
+ expect(@schedule.occurring_at?(@test_from + 4.day - 1.second)).to be true
48
+ end
49
+
50
+ it "doesn't match at the first second of the first day not included" do
51
+ expect(@schedule.occurring_at?(@test_from + 5.days)).to be false
52
+ expect(@schedule.occurring_at?(@test_from + 5.days + 1.second)).to be false
53
+ end
54
+ end
55
+
56
+ describe "except the first and the last day of the month" do
57
+ before :each do
58
+ @test_from = '2016-02-01'.to_date # it's a monday
59
+ @schedule = IceCube::Schedule.new @test_from
60
+ @schedule.add_recurrence_rule IceCube::Rule.weekly.day(:monday,:tuesday,:wednesday,:thursday,:friday)
61
+ @schedule.add_exception_rule IceCube::Rule.monthly.day_of_month(1, -1)
62
+ end
63
+
64
+ it "doesn't match on the first of the month" do
65
+ expect(@schedule.occurring_at?(@test_from)).to be false
66
+ expect(@schedule.occurring_at?(@test_from.end_of_month)).to be false
67
+ expect(@schedule.occurring_at?(@test_from + 1.month)).to be false
68
+ expect(@schedule.occurring_at?((@test_from + 1.month).end_of_month)).to be false
69
+ expect(@schedule.occurring_at?('2017-01-01'.to_date)).to be false # sunday
70
+ expect(@schedule.occurring_at?('2017-01-01'.to_date + 1.second)).to be false # sunday
71
+ expect(@schedule.occurring_at?('2017-01-01'.to_date + 1.day)).to be true # monday
72
+ end
73
+ end
74
+ end
75
+
76
+ describe "Gym schedules" do
77
+ before :each do
78
+ # Mon | Tue | Wed | Thu | Fri | Sat |Sun
79
+ # 9-10 | 10-11 | 9-10 | 10-11 | | 14-15 |
80
+ # 18:10-19:10 | 20-21 | 18:10-19:10 | 20-21 | | |
81
+ # Except for the third saturday of the month
82
+ @test_from = '2016-02-01'.to_date # it's a monday
83
+ @schedule = IceCube::Schedule.new(@test_from, duration: 1.hour)
84
+ @schedule.add_recurrence_rule IceCube::Rule.weekly.day(:monday,:wednesday).hour_of_day(9)
85
+ @schedule.add_recurrence_rule IceCube::Rule.weekly.day(:monday,:wednesday).hour_of_day(18).minute_of_hour(10)
86
+ @schedule.add_recurrence_rule IceCube::Rule.weekly.day(:tuesday,:thursday).hour_of_day(10,20)
87
+ @schedule.add_recurrence_rule IceCube::Rule.weekly.day(:saturday).hour_of_day(14)
88
+ @schedule.add_exception_rule IceCube::Rule.monthly.day_of_week(saturday: [3]).hour_of_day(14)
89
+ @schedule.add_exception_rule IceCube::Rule.monthly.day_of_week(wednesday: [3]).hour_of_day(9)
90
+ end
91
+
92
+ it "matches at the occurrences" do
93
+ (0...12).each do |i|
94
+ minute = (i * 5).minutes
95
+ expect(@schedule.occurring_at?(@test_from + 9.hours + minute)).to be true # monday
96
+ expect(@schedule.occurring_at?(@test_from + 18.hours + 10.minutes + minute)).to be true # monday
97
+ expect(@schedule.occurring_at?(@test_from + 5.days + 14.hours + minute)).to be true # tuesday
98
+ end
99
+ end
100
+
101
+ it "doesn't match close to the occurrences" do
102
+ expect(@schedule.occurring_at?(@test_from + 9.hours - 1.minute)).to be false # monday
103
+ expect(@schedule.occurring_at?(@test_from + 10.hours)).to be false # monday
104
+ expect(@schedule.occurring_at?(@test_from + 18.hours + 9.minutes)).to be false # monday
105
+ expect(@schedule.occurring_at?(@test_from + 19.hours + 9.minutes)).to be true # monday
106
+ expect(@schedule.occurring_at?(@test_from + 19.hours + 10.minutes)).to be false # monday
107
+ end
108
+
109
+ it "doesn't match the saturday of the third week of the month" do
110
+ (0...12).each do |i|
111
+ minute = (i * 5).minutes
112
+ expect(@schedule.occurring_at?('2016-02-20'.to_date + 14.hours + minute)).to be false # monday
113
+ end
114
+ end
115
+
116
+ describe "borderline matchings" do
117
+ before :each do
118
+ # Except the third wednesday of the month
119
+ @test_from = '2016-02-01'.to_date # it's a monday
120
+ @schedule = IceCube::Schedule.new(@test_from)
121
+ @schedule.add_recurrence_rule IceCube::Rule.monthly.day_of_week(wednesday: [3])
122
+ end
123
+
124
+ it "matches the third wednesday of the month, in normal conditions" do
125
+ expect(@schedule.occurring_at?('2016-02-17'.to_date)).to be true
126
+ end
127
+
128
+ it "matches the third wednesday of the month, if the month starts on friday" do
129
+ expect(@schedule.occurring_at?('2016-04-20'.to_date)).to be true
130
+ end
131
+
132
+ it "doesn't match the wednesday of the third week of the month, if the month starts on friday" do
133
+ expect(@schedule.occurring_at?('2016-04-13'.to_date)).to be false
134
+ end
135
+ end
136
+ end
137
+ end