acts_as_bookable 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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