simple_pvr 0.0.1
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.
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +133 -0
- data/LICENSE.txt +13 -0
- data/README.md +169 -0
- data/Rakefile +16 -0
- data/bin/pvr_server +10 -0
- data/bin/pvr_xmltv +18 -0
- data/features/channel_overview.feature +48 -0
- data/features/programme_search.feature +20 -0
- data/features/scheduling.feature +112 -0
- data/features/step_definitions/pvr_steps.rb +104 -0
- data/features/step_definitions/web_steps.rb +219 -0
- data/features/support/env.rb +28 -0
- data/features/support/paths.rb +17 -0
- data/features/week_overview.feature +39 -0
- data/lib/simple_pvr/ffmpeg.rb +22 -0
- data/lib/simple_pvr/hdhomerun.rb +103 -0
- data/lib/simple_pvr/hdhomerun_save.sh +10 -0
- data/lib/simple_pvr/model/channel.rb +72 -0
- data/lib/simple_pvr/model/database_initializer.rb +36 -0
- data/lib/simple_pvr/model/programme.rb +58 -0
- data/lib/simple_pvr/model/recording.rb +45 -0
- data/lib/simple_pvr/model/schedule.rb +33 -0
- data/lib/simple_pvr/pvr_initializer.rb +47 -0
- data/lib/simple_pvr/pvr_logger.rb +14 -0
- data/lib/simple_pvr/recorder.rb +25 -0
- data/lib/simple_pvr/recording_manager.rb +101 -0
- data/lib/simple_pvr/recording_planner.rb +72 -0
- data/lib/simple_pvr/scheduler.rb +124 -0
- data/lib/simple_pvr/server/app_controller.rb +13 -0
- data/lib/simple_pvr/server/base_controller.rb +94 -0
- data/lib/simple_pvr/server/channels_controller.rb +68 -0
- data/lib/simple_pvr/server/config.ru +8 -0
- data/lib/simple_pvr/server/programmes_controller.rb +46 -0
- data/lib/simple_pvr/server/rack_maps.rb +7 -0
- data/lib/simple_pvr/server/schedules_controller.rb +71 -0
- data/lib/simple_pvr/server/shows_controller.rb +63 -0
- data/lib/simple_pvr/server/status_controller.rb +11 -0
- data/lib/simple_pvr/server/upcoming_recordings_controller.rb +18 -0
- data/lib/simple_pvr/version.rb +3 -0
- data/lib/simple_pvr/xmltv_reader.rb +83 -0
- data/lib/simple_pvr.rb +22 -0
- data/public/css/bootstrap-responsive.min.css +9 -0
- data/public/css/bootstrap.min.css +9 -0
- data/public/css/simplepvr.css +11 -0
- data/public/img/glyphicons-halflings-white.png +0 -0
- data/public/img/glyphicons-halflings.png +0 -0
- data/public/index.html +55 -0
- data/public/js/angular/angular-resource.min.js +10 -0
- data/public/js/angular/angular.min.js +157 -0
- data/public/js/app.js +145 -0
- data/public/js/bootstrap/bootstrap.min.js +6 -0
- data/public/js/controllers.js +156 -0
- data/public/js/services.js +27 -0
- data/public/partials/about.html +5 -0
- data/public/partials/channels.html +41 -0
- data/public/partials/programme.html +20 -0
- data/public/partials/programmeListing.html +18 -0
- data/public/partials/schedule.html +80 -0
- data/public/partials/schedules.html +44 -0
- data/public/partials/search.html +17 -0
- data/public/partials/show.html +21 -0
- data/public/partials/shows.html +7 -0
- data/public/partials/status.html +6 -0
- data/simple_pvr.gemspec +30 -0
- data/spec/resources/channels.txt +11 -0
- data/spec/resources/programs-without-icon.xmltv +95 -0
- data/spec/resources/programs.xmltv +98 -0
- data/spec/simple_pvr/ffmpeg_spec.rb +26 -0
- data/spec/simple_pvr/hdhomerun_spec.rb +82 -0
- data/spec/simple_pvr/model/channel_spec.rb +114 -0
- data/spec/simple_pvr/model/programme_spec.rb +110 -0
- data/spec/simple_pvr/model/schedule_spec.rb +47 -0
- data/spec/simple_pvr/pvr_initializer_spec.rb +50 -0
- data/spec/simple_pvr/recorder_spec.rb +32 -0
- data/spec/simple_pvr/recording_manager_spec.rb +158 -0
- data/spec/simple_pvr/recording_planner_spec.rb +104 -0
- data/spec/simple_pvr/scheduler_spec.rb +201 -0
- data/spec/simple_pvr/xmltv_reader_spec.rb +49 -0
- data/test/config/jsTestDriver-scenario.conf +10 -0
- data/test/config/jsTestDriver.conf +12 -0
- data/test/config/jstd-scenario-adapter-config.js +6 -0
- data/test/filtersSpec.js +97 -0
- data/test/lib/angular/angular-mocks.js +1719 -0
- data/test/lib/angular/angular-scenario.js +25937 -0
- data/test/lib/angular/jstd-scenario-adapter.js +185 -0
- data/test/lib/angular/version.txt +1 -0
- data/test/lib/jasmine/MIT.LICENSE +20 -0
- data/test/lib/jasmine/index.js +180 -0
- data/test/lib/jasmine/jasmine-html.js +190 -0
- data/test/lib/jasmine/jasmine.css +166 -0
- data/test/lib/jasmine/jasmine.js +2476 -0
- data/test/lib/jasmine/jasmine_favicon.png +0 -0
- data/test/lib/jasmine/version.txt +1 -0
- data/test/lib/jasmine-jstd-adapter/JasmineAdapter.js +196 -0
- data/test/lib/jasmine-jstd-adapter/version.txt +1 -0
- data/test/lib/jstestdriver/JsTestDriver.jar +0 -0
- data/test/lib/jstestdriver/version.txt +1 -0
- data/test/scripts/test-server.sh +14 -0
- data/test/scripts/test.sh +8 -0
- metadata +342 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
require 'simple_pvr'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
|
|
4
|
+
describe SimplePvr::RecordingManager do
|
|
5
|
+
before do
|
|
6
|
+
@recording_dir = File.dirname(__FILE__) + '/../resources/recordings'
|
|
7
|
+
FileUtils.rm_rf(@recording_dir) if Dir.exists?(@recording_dir)
|
|
8
|
+
FileUtils.mkdir_p(@recording_dir + "/series 1/1")
|
|
9
|
+
FileUtils.mkdir_p(@recording_dir + "/series 1/3")
|
|
10
|
+
FileUtils.mkdir_p(@recording_dir + "/Another series/10")
|
|
11
|
+
|
|
12
|
+
@manager = SimplePvr::RecordingManager.new(@recording_dir)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'knows which shows are recorded' do
|
|
16
|
+
@manager.shows.should == ['Another series', 'series 1']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'can delete all episodes of a given show' do
|
|
20
|
+
@manager.delete_show('series 1')
|
|
21
|
+
File.exists?(@recording_dir + '/series 1').should be_false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'knows which episodes of a given show exists' do
|
|
25
|
+
episodes = @manager.episodes_of('series 1')
|
|
26
|
+
|
|
27
|
+
episodes.length.should == 2
|
|
28
|
+
episodes[0].episode.should == '1'
|
|
29
|
+
episodes[1].episode.should == '3'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'reads metadata for recordings if present' do
|
|
33
|
+
start_time = Time.now
|
|
34
|
+
metadata = {
|
|
35
|
+
channel: 'Channel 4',
|
|
36
|
+
subtitle: 'A subtitle',
|
|
37
|
+
description: 'A description',
|
|
38
|
+
start_time: start_time,
|
|
39
|
+
duration: 10.minutes
|
|
40
|
+
}
|
|
41
|
+
File.open(@recording_dir + '/series 1/3/metadata.yml', 'w') {|f| f.write(metadata.to_yaml) }
|
|
42
|
+
|
|
43
|
+
episodes = @manager.episodes_of('series 1')
|
|
44
|
+
|
|
45
|
+
episodes.length.should == 2
|
|
46
|
+
|
|
47
|
+
episodes[0].show_name.should == 'series 1'
|
|
48
|
+
episodes[0].episode.should == '1'
|
|
49
|
+
|
|
50
|
+
episodes[1].show_name.should == 'series 1'
|
|
51
|
+
episodes[1].episode.should == '3'
|
|
52
|
+
episodes[1].channel.should == 'Channel 4'
|
|
53
|
+
episodes[1].subtitle.should == 'A subtitle'
|
|
54
|
+
episodes[1].description.should == 'A description'
|
|
55
|
+
episodes[1].start_time.should == start_time
|
|
56
|
+
episodes[1].duration == 10.minutes
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'knows when no thumbnail exists' do
|
|
60
|
+
episodes = @manager.episodes_of('series 1')
|
|
61
|
+
|
|
62
|
+
episodes[0].has_thumbnail.should == false
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'knows when thumbnail exists' do
|
|
66
|
+
FileUtils.touch(@recording_dir + "/series 1/1/thumbnail.png")
|
|
67
|
+
episodes = @manager.episodes_of('series 1')
|
|
68
|
+
|
|
69
|
+
episodes[0].has_thumbnail.should == true
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'knows when no webm file exists' do
|
|
73
|
+
episodes = @manager.episodes_of('series 1')
|
|
74
|
+
|
|
75
|
+
episodes[0].has_webm.should == false
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'knows when a webm file exists' do
|
|
79
|
+
FileUtils.touch(@recording_dir + "/series 1/1/stream.webm")
|
|
80
|
+
episodes = @manager.episodes_of('series 1')
|
|
81
|
+
|
|
82
|
+
episodes[0].has_webm.should == true
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'can delete an episode of a given show' do
|
|
86
|
+
@manager.delete_show_episode('series 1', '3')
|
|
87
|
+
File.exists?(@recording_dir + '/series 1/3').should be_false
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
context 'when creating recording directories' do
|
|
91
|
+
before do
|
|
92
|
+
@start_time = Time.local(2012, 7, 23, 15, 30, 15)
|
|
93
|
+
@recording = SimplePvr::Model::Recording.new(double(name: 'Channel 4'), 'Star Trek', @start_time, 50.minutes)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'records to directory with number 1 if nothing exists' do
|
|
97
|
+
@manager.create_directory_for_recording(@recording)
|
|
98
|
+
|
|
99
|
+
File.exists?(@recording_dir + '/Star Trek/1').should be_true
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it 'removes some potentially harmful characters from directory name' do
|
|
103
|
+
@recording.show_name = "Some... harmful/irritating\\ characters in: '*title\""
|
|
104
|
+
@manager.create_directory_for_recording(@recording)
|
|
105
|
+
|
|
106
|
+
File.exists?(@recording_dir + '/Some harmfulirritating characters in title/1').should be_true
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'finds a directory name for titles which would otherwise get an empty directory name' do
|
|
110
|
+
@recording.show_name = '/.'
|
|
111
|
+
@manager.create_directory_for_recording(@recording)
|
|
112
|
+
|
|
113
|
+
File.exists?(@recording_dir + '/Unnamed/1').should be_true
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it 'finds next number in sequence for new directory' do
|
|
117
|
+
FileUtils.mkdir_p(@recording_dir + "/Star Trek/1")
|
|
118
|
+
FileUtils.mkdir_p(@recording_dir + "/Star Trek/2")
|
|
119
|
+
FileUtils.mkdir_p(@recording_dir + "/Star Trek/3")
|
|
120
|
+
@manager.create_directory_for_recording(@recording)
|
|
121
|
+
|
|
122
|
+
File.exists?(@recording_dir + '/Star Trek/4').should be_true
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it 'ignores random directories which are not sequence numbers' do
|
|
126
|
+
FileUtils.mkdir_p(@recording_dir + "/Star Trek/4")
|
|
127
|
+
FileUtils.mkdir_p(@recording_dir + "/Star Trek/random directory name")
|
|
128
|
+
@manager.create_directory_for_recording(@recording)
|
|
129
|
+
|
|
130
|
+
File.exists?(@recording_dir + '/Star Trek/5').should be_true
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'stores simple metadata if no programme information exists' do
|
|
134
|
+
@manager.create_directory_for_recording(@recording)
|
|
135
|
+
|
|
136
|
+
metadata = YAML.load_file(@recording_dir + '/Star Trek/1/metadata.yml')
|
|
137
|
+
metadata[:title].should == 'Star Trek'
|
|
138
|
+
metadata[:channel].should == 'Channel 4'
|
|
139
|
+
metadata[:start_time].should == @start_time
|
|
140
|
+
metadata[:duration].should == 50.minutes
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it 'stores extensive metadata if programme information exists' do
|
|
144
|
+
start_time = Time.local(2012, 7, 23, 15, 30, 15)
|
|
145
|
+
recording = SimplePvr::Model::Recording.new(double(name: 'Channel 4'), 'Extensive Metadata', start_time, 50.minutes)
|
|
146
|
+
recording.programme = SimplePvr::Model::Programme.new(subtitle: 'A subtitle', description: "A description,\nspanning several lines")
|
|
147
|
+
@manager.create_directory_for_recording(recording)
|
|
148
|
+
|
|
149
|
+
metadata = YAML.load_file(@recording_dir + '/Extensive Metadata/1/metadata.yml')
|
|
150
|
+
metadata[:title].should == 'Extensive Metadata'
|
|
151
|
+
metadata[:channel].should == 'Channel 4'
|
|
152
|
+
metadata[:start_time].should == start_time
|
|
153
|
+
metadata[:duration].should == 50.minutes
|
|
154
|
+
metadata[:subtitle].should == 'A subtitle'
|
|
155
|
+
metadata[:description].should == "A description,\nspanning several lines"
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
require 'simple_pvr'
|
|
2
|
+
|
|
3
|
+
describe SimplePvr::RecordingPlanner do
|
|
4
|
+
before do
|
|
5
|
+
SimplePvr::Model::DatabaseInitializer.prepare_for_test
|
|
6
|
+
SimplePvr::Model::DatabaseInitializer.clear
|
|
7
|
+
@dr_1 = SimplePvr::Model::Channel.create(name: 'DR 1')
|
|
8
|
+
@dr_k = SimplePvr::Model::Channel.create(name: 'DR K')
|
|
9
|
+
@start_time_1, @start_time_2 = Time.local(2012, 7, 10, 20, 50), Time.local(2012, 7, 17, 20, 50)
|
|
10
|
+
@programme_title = 'Borgias'
|
|
11
|
+
@programme_duration = 60.minutes.to_i
|
|
12
|
+
|
|
13
|
+
@scheduler = double('Scheduler')
|
|
14
|
+
SimplePvr::PvrInitializer.stub(scheduler: @scheduler)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'resets the recordings when no schedules exist' do
|
|
18
|
+
SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_k, start_time: @start_time_1, duration: @programme_duration)
|
|
19
|
+
SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_k, start_time: @start_time_2, duration: @programme_duration)
|
|
20
|
+
SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_1, start_time: @start_time_2, duration: @programme_duration)
|
|
21
|
+
SimplePvr::Model::Programme.create(title: @programme_title + "-", channel: @dr_k, start_time: @start_time_2, duration: @programme_duration)
|
|
22
|
+
|
|
23
|
+
@scheduler.should_receive(:recordings=).with([])
|
|
24
|
+
|
|
25
|
+
SimplePvr::RecordingPlanner.read
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'can set up schedules from channel and programme title' do
|
|
29
|
+
SimplePvr::Model::Schedule.create(type: :specification, title: 'Borgias', channel: @dr_k)
|
|
30
|
+
@programme_1 = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_k, start_time: @start_time_1, duration: @programme_duration)
|
|
31
|
+
@programme_2 = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_k, start_time: @start_time_2, duration: @programme_duration)
|
|
32
|
+
SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_1, start_time: @start_time_2, duration: @programme_duration)
|
|
33
|
+
SimplePvr::Model::Programme.create(title: @programme_title + "-", channel: @dr_k, start_time: @start_time_2, duration: @programme_duration)
|
|
34
|
+
|
|
35
|
+
@scheduler.should_receive(:recordings=).with([
|
|
36
|
+
SimplePvr::Model::Recording.new(@dr_k, 'Borgias', Time.local(2012, 7, 10, 20, 48), 67.minutes, @programme_1),
|
|
37
|
+
SimplePvr::Model::Recording.new(@dr_k, 'Borgias', Time.local(2012, 7, 17, 20, 48), 67.minutes, @programme_2)
|
|
38
|
+
])
|
|
39
|
+
|
|
40
|
+
SimplePvr::RecordingPlanner.read
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'can set up schedules from channel, programme title, and start time' do
|
|
44
|
+
SimplePvr::Model::Schedule.create(type: :specification, title: 'Borgias', channel: @dr_k, start_time: @start_time_2)
|
|
45
|
+
SimplePvr::Model::Programme.create(title: @programme_title, channel:@dr_k, start_time: @start_time_1, duration: @programme_duration)
|
|
46
|
+
@programme_to_be_recorded = SimplePvr::Model::Programme.create(title: @programme_title, channel:@dr_k, start_time: @start_time_2, duration: @programme_duration)
|
|
47
|
+
|
|
48
|
+
@scheduler.should_receive(:recordings=).with([
|
|
49
|
+
SimplePvr::Model::Recording.new(@dr_k, @programme_title, @start_time_2.advance(minutes: -2), 2.minutes + @programme_duration + 5.minutes, @programme_to_be_recorded)
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
SimplePvr::RecordingPlanner.read
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'can set up schedules from programme title only' do
|
|
56
|
+
SimplePvr::Model::Schedule.create(type: :specification, title: 'Borgias')
|
|
57
|
+
@programme_1 = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_1, start_time: @start_time_1, duration: @programme_duration)
|
|
58
|
+
@programme_2 = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_k, start_time: @start_time_2, duration: @programme_duration)
|
|
59
|
+
SimplePvr::Model::Programme.create(title: @programme_title + '-', channel: @dr_k, start_time: @start_time_2, duration: @programme_duration)
|
|
60
|
+
|
|
61
|
+
@scheduler.should_receive(:recordings=).with([
|
|
62
|
+
SimplePvr::Model::Recording.new(@dr_1, 'Borgias', Time.local(2012, 7, 10, 20, 48), 67.minutes, @programme_1),
|
|
63
|
+
SimplePvr::Model::Recording.new(@dr_k, 'Borgias', Time.local(2012, 7, 17, 20, 48), 67.minutes, @programme_2)
|
|
64
|
+
])
|
|
65
|
+
|
|
66
|
+
SimplePvr::RecordingPlanner.read
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'can set up schedules for specific days of the week' do
|
|
70
|
+
@monday = Time.local(2012, 12, 10, 20, 50)
|
|
71
|
+
@tuesday, @wednesday, @thursday, @friday, @saturday, @sunday = @monday + 1.day, @monday + 2.days, @monday + 3.days, @monday + 4.days, @monday + 5.days, @monday + 6.days
|
|
72
|
+
@monday_programme = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_1, start_time: @monday, duration: @programme_duration)
|
|
73
|
+
@tuesday_programme = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_1, start_time: @tuesday, duration: @programme_duration)
|
|
74
|
+
@wednesday_programme = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_1, start_time: @wednesday, duration: @programme_duration)
|
|
75
|
+
@thursday_programme = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_1, start_time: @thursday, duration: @programme_duration)
|
|
76
|
+
@friday_programme = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_1, start_time: @friday, duration: @programme_duration)
|
|
77
|
+
@saturday_programme = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_1, start_time: @saturday, duration: @programme_duration)
|
|
78
|
+
@sunday_programme = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_1, start_time: @sunday, duration: @programme_duration)
|
|
79
|
+
|
|
80
|
+
SimplePvr::Model::Schedule.create(type: :specification, title: @programme_title, filter_by_weekday: true, monday: false, tuesday: true, wednesday: true, thursday: false, friday: false, saturday: true, sunday: true)
|
|
81
|
+
|
|
82
|
+
@scheduler.should_receive(:recordings=).with([
|
|
83
|
+
SimplePvr::Model::Recording.new(@dr_1, @programme_title, @tuesday - 2.minutes, 67.minutes, @tuesday_programme),
|
|
84
|
+
SimplePvr::Model::Recording.new(@dr_1, @programme_title, @wednesday - 2.minutes, 67.minutes, @wednesday_programme),
|
|
85
|
+
SimplePvr::Model::Recording.new(@dr_1, @programme_title, @saturday - 2.minutes, 67.minutes, @saturday_programme),
|
|
86
|
+
SimplePvr::Model::Recording.new(@dr_1, @programme_title, @sunday - 2.minutes, 67.minutes, @sunday_programme),
|
|
87
|
+
])
|
|
88
|
+
|
|
89
|
+
SimplePvr::RecordingPlanner.read
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it 'ignores programmes for which exceptions exist' do
|
|
93
|
+
SimplePvr::Model::Schedule.create(type: :specification, title: 'Borgias')
|
|
94
|
+
SimplePvr::Model::Schedule.create(type: :exception, title: 'Borgias', channel: @dr_1, start_time: @start_time_1)
|
|
95
|
+
SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_1, start_time: @start_time_1, duration: @programme_duration)
|
|
96
|
+
@programme_to_be_recorded = SimplePvr::Model::Programme.create(title: @programme_title, channel: @dr_k, start_time: @start_time_2, duration: @programme_duration)
|
|
97
|
+
|
|
98
|
+
@scheduler.should_receive(:recordings=).with([
|
|
99
|
+
SimplePvr::Model::Recording.new(@dr_k, 'Borgias', Time.local(2012, 7, 17, 20, 48), 67.minutes, @programme_to_be_recorded)
|
|
100
|
+
])
|
|
101
|
+
|
|
102
|
+
SimplePvr::RecordingPlanner.read
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
require 'simple_pvr'
|
|
2
|
+
|
|
3
|
+
describe SimplePvr::Scheduler do
|
|
4
|
+
before do
|
|
5
|
+
@channel = double('Channel DR K', name: 'DR K', frequency: 282000000, channel_id: 1098)
|
|
6
|
+
@channel_dr1 = double('Channel DR 1', name: 'DR 1', frequency: 290000000, channel_id: 1099)
|
|
7
|
+
|
|
8
|
+
@scheduler = SimplePvr::Scheduler.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'leaves recordings that are in the future' do
|
|
12
|
+
start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
13
|
+
Time.stub(:now => start_time.advance(hours: -1))
|
|
14
|
+
|
|
15
|
+
@scheduler.recordings = [SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time, 60.minutes)]
|
|
16
|
+
@scheduler.process
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'marks conflicting future recordings' do
|
|
20
|
+
first_start_time = Time.now.advance(days: 1)
|
|
21
|
+
second_start_time = Time.now.advance(days: 1, minutes: 10)
|
|
22
|
+
third_start_time = Time.now.advance(days: 1, minutes: 20)
|
|
23
|
+
fourth_start_time = Time.now.advance(days: 2)
|
|
24
|
+
first_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', first_start_time, 60.minutes)
|
|
25
|
+
second_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', second_start_time, 60.minutes)
|
|
26
|
+
third_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', third_start_time, 60.minutes)
|
|
27
|
+
fourth_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', fourth_start_time, 60.minutes)
|
|
28
|
+
|
|
29
|
+
@scheduler.recordings = [first_recording, third_recording, second_recording]
|
|
30
|
+
|
|
31
|
+
first_recording.should_not be_conflicting
|
|
32
|
+
second_recording.should_not be_conflicting
|
|
33
|
+
third_recording.should be_conflicting
|
|
34
|
+
fourth_recording.should_not be_conflicting
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'starts recordings at start time' do
|
|
38
|
+
start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
39
|
+
starting_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time, 60.minutes)
|
|
40
|
+
Time.stub(:now => start_time)
|
|
41
|
+
SimplePvr::Recorder.stub(:new).with(0, starting_recording).and_return(@recorder = double('Recorder'))
|
|
42
|
+
@recorder.should_receive(:start!)
|
|
43
|
+
|
|
44
|
+
@scheduler.recordings = [starting_recording]
|
|
45
|
+
@scheduler.process
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'starts recordings that are in progress' do
|
|
49
|
+
start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
50
|
+
recording_in_progress = SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time, 60.minutes)
|
|
51
|
+
Time.stub(:now => start_time.advance(minutes: 30))
|
|
52
|
+
SimplePvr::Recorder.stub(:new).with(0, recording_in_progress).and_return(@recorder = double('Recorder'))
|
|
53
|
+
@recorder.should_receive(:start!)
|
|
54
|
+
|
|
55
|
+
@scheduler.recordings = [recording_in_progress]
|
|
56
|
+
@scheduler.process
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'can start two recordings at once' do
|
|
60
|
+
first_start_time = Time.local(2012, 7, 15, 19, 45, 30)
|
|
61
|
+
second_start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
62
|
+
recording_in_progress = SimplePvr::Model::Recording.new(@channel, 'Borgia', first_start_time, 60.minutes)
|
|
63
|
+
starting_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', second_start_time, 60.minutes)
|
|
64
|
+
Time.stub(:now => second_start_time)
|
|
65
|
+
SimplePvr::Recorder.stub(:new).with(0, recording_in_progress).and_return(@recorder0 = double('Recorder'))
|
|
66
|
+
SimplePvr::Recorder.stub(:new).with(1, starting_recording).and_return(@recorder1 = double('Recorder'))
|
|
67
|
+
@recorder0.should_receive(:start!)
|
|
68
|
+
@recorder1.should_receive(:start!)
|
|
69
|
+
|
|
70
|
+
@scheduler.recordings = [recording_in_progress, starting_recording]
|
|
71
|
+
@scheduler.process
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'rejects third recording at once, and marks the third recording as conflicting' do
|
|
75
|
+
first_start_time = Time.local(2012, 7, 15, 19, 45, 30)
|
|
76
|
+
second_start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
77
|
+
third_start_time = Time.local(2012, 7, 15, 20, 20, 0)
|
|
78
|
+
recording_in_progress = SimplePvr::Model::Recording.new(@channel, 'Borgia', first_start_time, 60.minutes)
|
|
79
|
+
starting_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', second_start_time, 60.minutes)
|
|
80
|
+
rejected_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', third_start_time, 60.minutes)
|
|
81
|
+
Time.stub(:now => second_start_time)
|
|
82
|
+
SimplePvr::Recorder.stub(:new).with(0, recording_in_progress).and_return(@recorder0 = double('Recorder'))
|
|
83
|
+
SimplePvr::Recorder.stub(:new).with(1, starting_recording).and_return(@recorder1 = double('Recorder'))
|
|
84
|
+
@recorder0.should_receive(:start!)
|
|
85
|
+
@recorder1.should_receive(:start!)
|
|
86
|
+
|
|
87
|
+
@scheduler.recordings = [recording_in_progress, starting_recording, rejected_recording]
|
|
88
|
+
@scheduler.process
|
|
89
|
+
|
|
90
|
+
recording_in_progress.should_not be_conflicting
|
|
91
|
+
starting_recording.should_not be_conflicting
|
|
92
|
+
rejected_recording.should be_conflicting
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it 'ends recordings at end time' do
|
|
96
|
+
start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
97
|
+
ending_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time, 60.minutes)
|
|
98
|
+
SimplePvr::Recorder.stub(:new).with(0, ending_recording).and_return(@recorder = double('Recorder'))
|
|
99
|
+
@recorder.should_receive(:start!)
|
|
100
|
+
Time.stub(:now => start_time)
|
|
101
|
+
|
|
102
|
+
@scheduler.recordings = [ending_recording]
|
|
103
|
+
@scheduler.process
|
|
104
|
+
|
|
105
|
+
@recorder.should_receive(:stop!)
|
|
106
|
+
Time.stub(:now => start_time.advance(hours: 1, minutes: 1))
|
|
107
|
+
|
|
108
|
+
@scheduler.process
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'skips recordings that have passed' do
|
|
112
|
+
start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
113
|
+
passed_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time - 65.minutes, 60.minutes)
|
|
114
|
+
Time.stub(:now => start_time)
|
|
115
|
+
|
|
116
|
+
@scheduler.recordings = [passed_recording]
|
|
117
|
+
@scheduler.process
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'knows which programmes are being recorded' do
|
|
121
|
+
start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
122
|
+
Time.stub(:now => start_time.advance(hours: -1))
|
|
123
|
+
scheduled_programme = double(id: 2)
|
|
124
|
+
unscheduled_programme = double(id: 3)
|
|
125
|
+
|
|
126
|
+
@scheduler.recordings = [SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time, 60.minutes, scheduled_programme)]
|
|
127
|
+
@scheduler.is_scheduled?(scheduled_programme).should be_true
|
|
128
|
+
@scheduler.is_scheduled?(unscheduled_programme).should be_false
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it 'gives idle status when nothing is recording' do
|
|
132
|
+
@scheduler.recordings = []
|
|
133
|
+
@scheduler.process
|
|
134
|
+
|
|
135
|
+
@scheduler.status_text.should == 'Idle'
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'gives recording status when recording' do
|
|
139
|
+
start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
140
|
+
Time.stub(:now => start_time.advance(minutes: 30))
|
|
141
|
+
SimplePvr::Recorder.stub(new: (@recorder = double('Recorder')))
|
|
142
|
+
@recorder.stub(:start!)
|
|
143
|
+
|
|
144
|
+
@scheduler.recordings = [SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time, 60.minutes)]
|
|
145
|
+
@scheduler.process
|
|
146
|
+
|
|
147
|
+
@scheduler.status_text.should == "Recording 'Borgia' on channel 'DR K'"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
context 'when updating existing recordings' do
|
|
151
|
+
it 'leaves running recording if new recording is equal' do
|
|
152
|
+
start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
153
|
+
continuing_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time, 60.minutes)
|
|
154
|
+
Time.stub(:now => start_time)
|
|
155
|
+
SimplePvr::Recorder.stub(:new).with(0, continuing_recording).and_return(@recorder = double('Recorder'))
|
|
156
|
+
@recorder.should_receive(:start!)
|
|
157
|
+
|
|
158
|
+
@scheduler.recordings = [continuing_recording]
|
|
159
|
+
@scheduler.process
|
|
160
|
+
|
|
161
|
+
@scheduler.recordings = [SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time, 60.minutes)]
|
|
162
|
+
@scheduler.process
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it 'stops existing recording if not present in new recording list' do
|
|
166
|
+
start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
167
|
+
stopping_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time, 60.minutes)
|
|
168
|
+
upcoming_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time + 10.minutes, 60.minutes)
|
|
169
|
+
Time.stub(:now => start_time)
|
|
170
|
+
SimplePvr::Recorder.stub(:new).with(0, stopping_recording).and_return(@recorder = double('Recorder'))
|
|
171
|
+
@recorder.should_receive(:start!)
|
|
172
|
+
|
|
173
|
+
@scheduler.recordings = [stopping_recording]
|
|
174
|
+
@scheduler.process
|
|
175
|
+
|
|
176
|
+
@recorder.should_receive(:stop!)
|
|
177
|
+
|
|
178
|
+
@scheduler.recordings = [upcoming_recording]
|
|
179
|
+
@scheduler.process
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it 'stops existing recording and starts new recording if new recording list has other current recording' do
|
|
183
|
+
start_time = Time.local(2012, 7, 15, 20, 15, 30)
|
|
184
|
+
stopping_recording = SimplePvr::Model::Recording.new(@channel, 'Borgia', start_time, 60.minutes)
|
|
185
|
+
starting_recording = SimplePvr::Model::Recording.new(@channel_dr1, 'Sports', start_time, 60.minutes)
|
|
186
|
+
Time.stub(:now => start_time)
|
|
187
|
+
SimplePvr::Recorder.stub(:new).with(0, stopping_recording).and_return(@old_recorder = double('Recorder'))
|
|
188
|
+
SimplePvr::Recorder.stub(:new).with(0, starting_recording).and_return(@new_recorder = double('New recorder'))
|
|
189
|
+
@old_recorder.should_receive(:start!)
|
|
190
|
+
|
|
191
|
+
@scheduler.recordings = [stopping_recording]
|
|
192
|
+
@scheduler.process
|
|
193
|
+
|
|
194
|
+
@old_recorder.should_receive(:stop!)
|
|
195
|
+
@new_recorder.should_receive(:start!)
|
|
196
|
+
|
|
197
|
+
@scheduler.recordings = [starting_recording]
|
|
198
|
+
@scheduler.process
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#encoding: UTF-8
|
|
2
|
+
require 'simple_pvr'
|
|
3
|
+
|
|
4
|
+
describe SimplePvr::XmltvReader do
|
|
5
|
+
before do
|
|
6
|
+
@dr_1 = double(name: 'DR 1')
|
|
7
|
+
@dr_1.stub(:icon_url=)
|
|
8
|
+
|
|
9
|
+
SimplePvr::Model::Channel.stub(all: [@dr_1])
|
|
10
|
+
SimplePvr::Model::Programme.stub(:transaction).and_yield
|
|
11
|
+
SimplePvr::Model::Programme.stub(:destroy)
|
|
12
|
+
@xmltv_reader = SimplePvr::XmltvReader.new({'www.ontv.dk/tv/1' => 'DR 1'})
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'populates programme information through the DAO' do
|
|
16
|
+
SimplePvr::Model::Programme.stub(:add)
|
|
17
|
+
SimplePvr::Model::Programme.should_receive(:add).with(
|
|
18
|
+
@dr_1,
|
|
19
|
+
'Noddy',
|
|
20
|
+
'Bare vær dig selv, Noddy.',
|
|
21
|
+
"Tegnefilm.\nHer kommer Noddy - så kom ud og leg! Den lille dreng af træ har altid travlt med at køre sine venner rundt i Legebyen - og du kan altid høre, når han er på vej!",
|
|
22
|
+
Time.new(2012, 7, 17, 6, 0, 0, "+02:00"),
|
|
23
|
+
10.minutes,
|
|
24
|
+
' .2/12. ')
|
|
25
|
+
|
|
26
|
+
@xmltv_reader.read(File.new(File.dirname(__FILE__) + '/../resources/programs.xmltv'))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'ignores programmes for channels with no mapping' do
|
|
30
|
+
# There are two channels in the XMLTV file, but only one with a mapping
|
|
31
|
+
SimplePvr::Model::Programme.should_receive(:add).exactly(5).times
|
|
32
|
+
|
|
33
|
+
@xmltv_reader.read(File.new(File.dirname(__FILE__) + '/../resources/programs.xmltv'))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'adds channel icons to existing channels' do
|
|
37
|
+
SimplePvr::Model::Programme.stub(:add) # necessary to deal with the way Programme setup its relation to Channel
|
|
38
|
+
@dr_1.should_receive(:icon_url=).with("http://ontv.dk/imgs/epg/logos/dr1_big.png")
|
|
39
|
+
|
|
40
|
+
@xmltv_reader.read(File.new(File.dirname(__FILE__) + '/../resources/programs.xmltv'))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'has no problem with xml with no channel icons' do
|
|
44
|
+
SimplePvr::Model::Programme.stub(:add) # necessary to deal with the way Programme setup its relation to Channel
|
|
45
|
+
@dr_1.should_not_receive(:icon_url=)
|
|
46
|
+
|
|
47
|
+
@xmltv_reader.read(File.new(File.dirname(__FILE__) + '/../resources/programs-without-icon.xmltv'))
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
server: http://localhost:9877
|
|
2
|
+
|
|
3
|
+
load:
|
|
4
|
+
- test/lib/angular/angular-scenario.js
|
|
5
|
+
- test/config/jstd-scenario-adapter-config.js
|
|
6
|
+
- test/lib/angular/jstd-scenario-adapter.js
|
|
7
|
+
- test/e2e/scenarios.js
|
|
8
|
+
|
|
9
|
+
proxy:
|
|
10
|
+
- {matcher: "*", server: "http://localhost:8000"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
server: http://localhost:9876
|
|
2
|
+
|
|
3
|
+
load:
|
|
4
|
+
- test/lib/jasmine/jasmine.js
|
|
5
|
+
- test/lib/jasmine-jstd-adapter/JasmineAdapter.js
|
|
6
|
+
- public/js/angular/angular.min.js
|
|
7
|
+
- public/js/angular/angular-resource.min.js
|
|
8
|
+
- test/lib/angular/angular-mocks.js
|
|
9
|
+
- public/js/*.js
|
|
10
|
+
- test/*.js
|
|
11
|
+
|
|
12
|
+
exclude:
|
data/test/filtersSpec.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
describe('filters', function() {
|
|
4
|
+
beforeEach(module('simplePvr'));
|
|
5
|
+
|
|
6
|
+
describe('chunk', function() {
|
|
7
|
+
it('should let non-Array input pass through', inject(function(chunkFilter) {
|
|
8
|
+
var input = 'this is not an array';
|
|
9
|
+
expect(chunkFilter(input)).toBe(input);
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
it('should let empty arrays pass through', inject(function(chunkFilter) {
|
|
13
|
+
expect(chunkFilter([], 3)).toEqual([]);
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
it('should chunk up arrays and give them hashKeys corresponding to the chunk numbers', inject(function(chunkFilter) {
|
|
17
|
+
var input = [1, 2, 3, 4, 5, 6, 7];
|
|
18
|
+
var firstChunk = [1, 2, 3];
|
|
19
|
+
var secondChunk = [4, 5, 6];
|
|
20
|
+
var thirdChunk = [7];
|
|
21
|
+
|
|
22
|
+
firstChunk.$$hashKey = 0;
|
|
23
|
+
secondChunk.$$hashKey = 1;
|
|
24
|
+
thirdChunk.$$hashKey = 2;
|
|
25
|
+
|
|
26
|
+
expect(chunkFilter(input, 3)).toEqual([firstChunk, secondChunk, thirdChunk]);
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
it('should create equal outputs given equal inputs', inject(function(chunkFilter) {
|
|
30
|
+
var output1 = chunkFilter([1, 2, 3, 4], 3);
|
|
31
|
+
var output2 = chunkFilter([1, 2, 3, 4], 3);
|
|
32
|
+
expect(angular.equals(output1, output2)).toBeTruthy();
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
it('should create non-equal outputs given non-equal inputs', inject(function(chunkFilter) {
|
|
36
|
+
var output1 = chunkFilter([1, 2, 3, 4], 3);
|
|
37
|
+
var output2 = chunkFilter([4, 3, 2, 1], 3);
|
|
38
|
+
expect(angular.equals(output1, output2)).toBeFalsy();
|
|
39
|
+
}));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('weekdayFilter', function() {
|
|
43
|
+
it('should be blank when there is no weekday filtering', inject(function(filteredWeekdaysFilter) {
|
|
44
|
+
var scheduleWithNoWeekdayFiltering = { filter_by_weekday: false };
|
|
45
|
+
expect(filteredWeekdaysFilter(scheduleWithNoWeekdayFiltering)).toEqual('');
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
it('should name a single weekday if only one is selected', inject(function(filteredWeekdaysFilter) {
|
|
49
|
+
var scheduleWithOneWeekdayFiltering = {
|
|
50
|
+
filter_by_weekday: true,
|
|
51
|
+
monday: false,
|
|
52
|
+
tuesday: false,
|
|
53
|
+
wednesday: true,
|
|
54
|
+
thursday: false,
|
|
55
|
+
friday: false,
|
|
56
|
+
saturday: false,
|
|
57
|
+
sunday: false
|
|
58
|
+
};
|
|
59
|
+
expect(filteredWeekdaysFilter(scheduleWithOneWeekdayFiltering)).toEqual('(Wednesdays)');
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
it('should name two weekdays if exactly two are selected', inject(function(filteredWeekdaysFilter) {
|
|
63
|
+
var scheduleWithTwoWeekdayFilterings = {
|
|
64
|
+
filter_by_weekday: true,
|
|
65
|
+
monday: true,
|
|
66
|
+
tuesday: false,
|
|
67
|
+
wednesday: true,
|
|
68
|
+
thursday: false,
|
|
69
|
+
friday: false,
|
|
70
|
+
saturday: false,
|
|
71
|
+
sunday: false
|
|
72
|
+
};
|
|
73
|
+
expect(filteredWeekdaysFilter(scheduleWithTwoWeekdayFilterings)).toEqual('(Mondays and Wednesdays)');
|
|
74
|
+
}));
|
|
75
|
+
|
|
76
|
+
it('should list all weekdays for three and more allowed weekdays', inject(function(filteredWeekdaysFilter) {
|
|
77
|
+
var scheduleWithSeveralWeekdayFilterings = {
|
|
78
|
+
filter_by_weekday: true,
|
|
79
|
+
monday: true,
|
|
80
|
+
tuesday: false,
|
|
81
|
+
wednesday: true,
|
|
82
|
+
thursday: false,
|
|
83
|
+
friday: true,
|
|
84
|
+
saturday: false,
|
|
85
|
+
sunday: false
|
|
86
|
+
};
|
|
87
|
+
expect(filteredWeekdaysFilter(scheduleWithSeveralWeekdayFilterings)).toEqual('(Mondays, Wednesdays, and Fridays)');
|
|
88
|
+
scheduleWithSeveralWeekdayFilterings.saturday = true;
|
|
89
|
+
expect(filteredWeekdaysFilter(scheduleWithSeveralWeekdayFilterings)).toEqual('(Mondays, Wednesdays, Fridays, and Saturdays)');
|
|
90
|
+
scheduleWithSeveralWeekdayFilterings.tuesday = true;
|
|
91
|
+
scheduleWithSeveralWeekdayFilterings.thursday = true;
|
|
92
|
+
scheduleWithSeveralWeekdayFilterings.saturday = true;
|
|
93
|
+
scheduleWithSeveralWeekdayFilterings.sunday = true;
|
|
94
|
+
expect(filteredWeekdaysFilter(scheduleWithSeveralWeekdayFilterings)).toEqual('(Mondays, Tuesdays, Wednesdays, Thursdays, Fridays, Saturdays, and Sundays)')
|
|
95
|
+
}));
|
|
96
|
+
});
|
|
97
|
+
});
|