hallon 0.15.0 → 0.16.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 (65) hide show
  1. data/CHANGELOG.md +40 -0
  2. data/README.markdown +1 -1
  3. data/dev/application_key_converter.rb +11 -0
  4. data/examples/example_support.rb +4 -0
  5. data/examples/playing_audio.rb +1 -1
  6. data/lib/hallon.rb +11 -0
  7. data/lib/hallon/album_browse.rb +3 -3
  8. data/lib/hallon/artist_browse.rb +20 -4
  9. data/lib/hallon/blob.rb +11 -0
  10. data/lib/hallon/enumerator.rb +5 -0
  11. data/lib/hallon/ext/spotify.rb +2 -0
  12. data/lib/hallon/image.rb +7 -1
  13. data/lib/hallon/link.rb +5 -2
  14. data/lib/hallon/observable.rb +48 -1
  15. data/lib/hallon/player.rb +15 -26
  16. data/lib/hallon/playlist.rb +16 -25
  17. data/lib/hallon/playlist_container.rb +38 -0
  18. data/lib/hallon/search.rb +75 -4
  19. data/lib/hallon/session.rb +31 -42
  20. data/lib/hallon/toplist.rb +3 -3
  21. data/lib/hallon/track.rb +28 -10
  22. data/lib/hallon/version.rb +1 -1
  23. data/spec/hallon/album_browse_spec.rb +68 -18
  24. data/spec/hallon/album_spec.rb +62 -27
  25. data/spec/hallon/artist_browse_spec.rb +106 -31
  26. data/spec/hallon/artist_spec.rb +32 -18
  27. data/spec/hallon/blob_spec.rb +6 -0
  28. data/spec/hallon/enumerator_spec.rb +10 -0
  29. data/spec/hallon/error_spec.rb +4 -4
  30. data/spec/hallon/hallon_spec.rb +1 -1
  31. data/spec/hallon/image_spec.rb +58 -47
  32. data/spec/hallon/link_spec.rb +51 -43
  33. data/spec/hallon/observable/album_browse_spec.rb +1 -1
  34. data/spec/hallon/observable/artist_browse_spec.rb +1 -1
  35. data/spec/hallon/observable/image_spec.rb +1 -1
  36. data/spec/hallon/observable/playlist_container_spec.rb +4 -4
  37. data/spec/hallon/observable/playlist_spec.rb +14 -14
  38. data/spec/hallon/observable/post_spec.rb +1 -1
  39. data/spec/hallon/observable/search_spec.rb +1 -1
  40. data/spec/hallon/observable/session_spec.rb +17 -17
  41. data/spec/hallon/observable/toplist_spec.rb +1 -1
  42. data/spec/hallon/observable_spec.rb +40 -6
  43. data/spec/hallon/player_spec.rb +1 -1
  44. data/spec/hallon/playlist_container_spec.rb +96 -13
  45. data/spec/hallon/playlist_spec.rb +180 -45
  46. data/spec/hallon/search_spec.rb +211 -28
  47. data/spec/hallon/session_spec.rb +44 -38
  48. data/spec/hallon/toplist_spec.rb +31 -14
  49. data/spec/hallon/track_spec.rb +159 -50
  50. data/spec/hallon/user_post_spec.rb +10 -5
  51. data/spec/hallon/user_spec.rb +60 -50
  52. data/spec/spec_helper.rb +40 -15
  53. data/spec/support/album_mocks.rb +30 -0
  54. data/spec/support/artist_mocks.rb +36 -0
  55. data/spec/support/common_objects.rb +0 -201
  56. data/spec/support/image_mocks.rb +34 -0
  57. data/spec/support/playlist_container_mocks.rb +36 -0
  58. data/spec/support/playlist_mocks.rb +70 -0
  59. data/spec/support/search_mocks.rb +23 -0
  60. data/spec/support/session_mocks.rb +33 -0
  61. data/spec/support/toplist_mocks.rb +19 -0
  62. data/spec/support/track_mocks.rb +28 -0
  63. data/spec/support/user_mocks.rb +20 -0
  64. metadata +40 -18
  65. data/spec/support/context_stub_session.rb +0 -5
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
  describe Hallon::Player do
3
- let(:player) { Hallon::Player.new(session, AudioDriverMock) }
3
+ let(:player) { Hallon::Player.new(AudioDriverMock) }
4
4
  let(:track) { Hallon::Track.new(mock_track) }
5
5
  let(:driver) { player.instance_variable_get('@driver') }
6
6
  let(:queue) { player.instance_variable_get('@queue') } # black box? WHAT?
@@ -1,14 +1,48 @@
1
1
  # coding: utf-8
2
2
  describe Hallon::PlaylistContainer do
3
- it { should be_a Hallon::Loadable }
3
+ let(:container) do
4
+ Hallon::PlaylistContainer.new(mock_containers[:default])
5
+ end
6
+
7
+ let(:empty_container) do
8
+ Hallon::PlaylistContainer.new(mock_containers[:empty])
9
+ end
10
+
11
+ let(:empty_playlist) do
12
+ Hallon::Playlist.new(mock_playlists[:empty])
13
+ end
14
+
15
+ let(:playlist) do
16
+ Hallon::Playlist.new(mock_playlists[:default])
17
+ end
4
18
 
5
- let(:container) { Hallon::PlaylistContainer.new(mock_container) }
19
+ specify { container.should be_a Hallon::Loadable }
6
20
 
7
- subject { container }
21
+ describe "#loaded?" do
22
+ it "returns true if the playlist container is loaded" do
23
+ container.should be_loaded
24
+ end
25
+ end
8
26
 
9
- it { should be_loaded }
10
- its(:owner) { should eq Hallon::User.new("burgestrand") }
11
- its(:size) { should eq 4 }
27
+ describe "#owner" do
28
+ it "returns the playlist container’s owner" do
29
+ container.owner.should eq Hallon::User.new("burgestrand")
30
+ end
31
+
32
+ it "returns nil if the playlist container is not loaded" do
33
+ empty_container.owner.should be_nil
34
+ end
35
+ end
36
+
37
+ describe "#size" do
38
+ it "returns the number of playlists inside the container" do
39
+ container.size.should eq 4
40
+ end
41
+
42
+ it "returns zero if the container is empty" do
43
+ empty_container.size.should eq 0
44
+ end
45
+ end
12
46
 
13
47
  describe "#add" do
14
48
  context "given a string that’s not a valid spotify playlist uri" do
@@ -29,7 +63,7 @@ describe Hallon::PlaylistContainer do
29
63
  context "given a string that’s a valid spotify playlist uri" do
30
64
  it "should add the existing Playlist at the end of the container" do
31
65
  playlist_uri = "spotify:user:burgestrand:playlist:07AX9IY9Hqmj1RqltcG0fi"
32
- playlist = mock_session { Hallon::Playlist.new(playlist_uri) }
66
+ playlist = Hallon::Playlist.new(playlist_uri)
33
67
 
34
68
  expect do
35
69
  new_playlist = container.add(playlist_uri)
@@ -169,13 +203,31 @@ describe Hallon::PlaylistContainer do
169
203
  end
170
204
 
171
205
  describe Hallon::PlaylistContainer::Folder do
172
- subject { container.contents[1] }
173
- let(:folder) { subject }
206
+ let(:folder) { container.contents[1] }
207
+
208
+ describe "#id" do
209
+ it "returns the folder’s ID" do
210
+ folder.id.should eq 1337
211
+ end
212
+ end
213
+
214
+ describe "#name" do
215
+ it "returns the folder’s name" do
216
+ folder.name.should eq "Boogie"
217
+ end
218
+ end
219
+
220
+ describe "#begin" do
221
+ it "returns the folder’s starting index" do
222
+ folder.begin.should eq 1
223
+ end
224
+ end
174
225
 
175
- its(:id) { should be 1337 }
176
- its(:name) { should eq "Boogie" }
177
- its(:begin) { should be 1 }
178
- its(:end) { should be 3 }
226
+ describe "#end" do
227
+ it "returns the folder’s ending index" do
228
+ folder.end.should eq 3
229
+ end
230
+ end
179
231
 
180
232
  describe "#moved?" do
181
233
  it "should return true if the folder has moved" do
@@ -222,4 +274,35 @@ describe Hallon::PlaylistContainer do
222
274
  end
223
275
  end
224
276
  end
277
+
278
+ describe "#unseen_tracks_count_for" do
279
+ it "returns the number of unseen tracks for the given playlist" do
280
+ container.unseen_tracks_count_for(playlist).should eq 4
281
+ end
282
+
283
+ it "raises an error if the result was an error" do
284
+ expect { container.unseen_tracks_count_for(empty_playlist) }.to raise_error(Hallon::OperationFailedError)
285
+ end
286
+ end
287
+
288
+ describe "#unseen_tracks_for" do
289
+ it "returns an array of unseen tracks" do
290
+ container.unseen_tracks_for(playlist).should eq playlist.tracks.to_a
291
+ end
292
+
293
+ it "returns an array of unseen tracks, no bigger than the given count" do
294
+ container.unseen_tracks_for(playlist, 2).should eq playlist.tracks.to_a[0, 2]
295
+ end
296
+
297
+ it "raises an error if the result was an error (but count was not)" do
298
+ Spotify.should_receive(:playlistcontainer_get_unseen_tracks).and_return(4, -1)
299
+ expect { container.unseen_tracks_for(empty_playlist) }.to raise_error(Hallon::OperationFailedError)
300
+ end
301
+ end
302
+
303
+ describe "#clear_unseen_tracks_for" do
304
+ it "raises an error if the operation failed" do
305
+ expect { container.clear_unseen_tracks_for(empty_playlist) }.to raise_error(Hallon::OperationFailedError)
306
+ end
307
+ end
225
308
  end
@@ -2,16 +2,19 @@
2
2
  require 'time'
3
3
 
4
4
  describe Hallon::Playlist do
5
- it { should be_a Hallon::Loadable }
5
+ let(:playlist) do
6
+ Hallon::Playlist.new(mock_playlists[:default])
7
+ end
6
8
 
7
- it_should_behave_like "a Linkable object" do
8
- let(:spotify_uri) { "spotify:user:burgestrand:playlist:07AX9IY9Hqmj1RqltcG0fi" }
9
- let(:described_class) { stub_session(Hallon::Playlist) }
9
+ let(:empty_playlist) do
10
+ Hallon::Playlist.new(mock_playlists[:empty])
10
11
  end
11
12
 
12
- subject { playlist }
13
- let(:playlist) do
14
- Hallon::Playlist.new(mock_playlist)
13
+ specify { playlist.should be_a Hallon::Loadable }
14
+
15
+ it_should_behave_like "a Linkable object" do
16
+ let(:spotify_uri) { "spotify:user:burgestrand:playlist:07AX9IY9Hqmj1RqltcG0fi" }
17
+ let(:described_class) { Hallon::Playlist }
15
18
  end
16
19
 
17
20
  describe ".invalid_name?" do
@@ -28,31 +31,164 @@ describe Hallon::Playlist do
28
31
  end
29
32
  end
30
33
 
31
- it { should be_loaded }
32
- it { should be_collaborative }
33
- it { should_not be_pending }
34
- it { stub_session { should be_in_ram } }
35
- it { stub_session { should_not be_available_offline } }
34
+ describe "#loaded?" do
35
+ it "is true when the playlist is loaded" do
36
+ playlist.should be_loaded
37
+ end
38
+
39
+ it "is false when the playlist is not loaded" do
40
+ empty_playlist.should_not be_loaded
41
+ end
42
+ end
43
+
44
+ describe "#name" do
45
+ it "returns the playlist’s name as a string" do
46
+ playlist.name.should eq "Megaplaylist"
47
+ end
48
+
49
+ it "returns an empty string when the playlist is not loaded" do
50
+ empty_playlist.name.should be_empty
51
+ end
52
+ end
53
+
54
+ describe "#owner" do
55
+ it "returns the playlist’s owner" do
56
+ playlist.owner.should eq Hallon::User.new(mock_user)
57
+ end
58
+
59
+ it "returns nil when the playlist is not loaded" do
60
+ empty_playlist.owner.should be_nil
61
+ end
62
+ end
63
+
64
+ describe "#description" do
65
+ it "returns the playlist’s description" do
66
+ playlist.description.should eq "Playlist description...?"
67
+ end
68
+
69
+ it "returns an empty string if the playlist is not loaded" do
70
+ empty_playlist.description.should be_empty
71
+ end
72
+ end
73
+
74
+ describe "#image" do
75
+ it "returns the playlists’s image as an image" do
76
+ playlist.image.should eq Hallon::Image.new("spotify:image:3ad93423add99766e02d563605c6e76ed2b0e400")
77
+ end
78
+
79
+ it "returns nil if the playlist is not loaded" do
80
+ empty_playlist.image.should be_nil
81
+ end
82
+ end
83
+
84
+ describe "#total_subscribers" do
85
+ it "returns the total number of subscribers to the playlist" do
86
+ playlist.total_subscribers.should eq 1000
87
+ end
88
+
89
+ it "returns zero if the playlist is not loaded" do
90
+ empty_playlist.total_subscribers.should eq 0
91
+ end
92
+ end
93
+
94
+ describe "#sync_progress" do
95
+ it "returns the completed percentage of the playlist download" do
96
+ playlist.sync_progress.should eq 67
97
+ end
98
+
99
+ it "returns zero if the playlist is not loaded" do
100
+ empty_playlist.sync_progress.should eq 0
101
+ end
102
+ end
103
+
104
+ describe "#size" do
105
+ it "returns the number of tracks in the playlist" do
106
+ playlist.size.should eq 4
107
+ end
108
+
109
+ it "returns zero if the playlist is not loaded" do
110
+ empty_playlist.size.should eq 0
111
+ end
112
+ end
113
+
114
+ describe "#collaborative?" do
115
+ it "is true when the playlist is set to be collaborative" do
116
+ playlist.should be_collaborative
117
+ end
118
+ end
119
+
120
+ describe "#pending?" do
121
+ it "is false when the playlist does not have pending updates" do
122
+ playlist.should_not be_pending
123
+ end
124
+ end
125
+
126
+ describe "#in_ram?" do
127
+ it "is true when the playlist is loaded in memory" do
128
+ playlist.should be_in_ram
129
+ end
130
+ end
131
+
132
+ describe "#available_offline?" do
133
+ it "is false when the playlist is not enabled for offline use" do
134
+ playlist.should_not be_available_offline
135
+ end
136
+ end
137
+
138
+ describe "#tracks" do
139
+ it "returns an enumerator of the playlist’s tracks" do
140
+ playlist.tracks.to_a.should eq instantiate(Hallon::Playlist::Track, *(0...4).map { |index| [Spotify.playlist_track!(playlist.pointer, index), playlist.pointer, index] })
141
+ end
142
+
143
+ it "returns an empty enumerator if the playlist has no tracks" do
144
+ empty_playlist.tracks.should be_empty
145
+ end
146
+ end
147
+
148
+ describe "#tracks entries" do
149
+ let(:track) do
150
+ playlist.tracks[0]
151
+ end
152
+
153
+ let(:empty_track) do
154
+ playlist.tracks[3]
155
+ end
156
+
157
+ describe "#seen?" do
158
+ it "returns true if the track is seen" do
159
+ track.should be_seen
160
+ end
161
+ end
162
+
163
+ describe "#create_time" do
164
+ it "returns the time the track was added to the playlist" do
165
+ track.added_at.should eq Time.parse("2009-11-04")
166
+ end
36
167
 
37
- its(:name) { should eq "Megaplaylist" }
38
- its(:owner) { should eq Hallon::User.new(mock_user) }
39
- its(:description) { should eq "Playlist description...?" }
40
- its(:image) { stub_session { should eq Hallon::Image.new(mock_image_id) } }
41
- its(:total_subscribers) { should eq 1000 }
42
- its(:sync_progress) { stub_session { should eq 67 } }
43
- its(:size) { should eq 4 }
168
+ it "returns the time in UTC" do
169
+ track.added_at.utc_offset.should eq 0
170
+ end
171
+ end
44
172
 
45
- its('tracks.size') { should eq 4 }
46
- its('tracks.to_a') { should eq instantiate(Hallon::Playlist::Track, *(0...4).map { |index| [Spotify.playlist_track!(playlist.pointer, index), playlist.pointer, index] }) }
173
+ describe "#creator" do
174
+ it "returns the track’s creator" do
175
+ track.adder.should eq Hallon::User.new(mock_user)
176
+ end
47
177
 
48
- describe "tracks#[]" do
49
- let(:track) { subject }
50
- subject { playlist.tracks[0] }
178
+ it "returns nil if there is no track creator available" do
179
+ empty_track.adder.should be_nil
180
+ end
181
+ end
51
182
 
52
- it { should be_seen }
53
- its(:create_time) { should eq Time.parse("2009-11-04") }
54
- its(:creator) { should eq Hallon::User.new(mock_user) }
55
- its(:message) { should eq "message this, YO!" }
183
+ describe "#message" do
184
+ it "returns the message attached to the track" do
185
+ track.message.should eq "message this, YO!"
186
+ end
187
+
188
+ it "returns an empty message if there is none for the given track" do
189
+ empty_track.message.should be_empty
190
+ end
191
+ end
56
192
 
57
193
  describe "#seen=" do
58
194
  it "should raise an error if the track has moved" do
@@ -78,34 +214,33 @@ describe Hallon::Playlist do
78
214
  end
79
215
  end
80
216
 
81
- describe "#upload", :stub_session do
217
+ describe "#upload" do
82
218
  around(:each) do |example|
83
- Timeout.timeout(1) { example.run }
219
+ Timeout.timeout(1, SlowTestError, &example)
84
220
  end
85
221
 
86
222
  it "should raise an error if the playlist takes too long to load" do
87
223
  playlist.stub(:pending? => true)
88
- expect { playlist.upload(0.01) }.to raise_error(Hallon::TimeoutError)
224
+ expect { playlist.upload(0.1) }.to raise_error(Hallon::TimeoutError)
89
225
  end
90
226
  end
91
227
 
92
228
  describe "#subscribers" do
93
229
  it "should return an array of names for the subscribers" do
94
- subject.subscribers.should eq %w[Kim Elin Ylva]
230
+ playlist.subscribers.should eq %w[Kim Elin Ylva]
95
231
  end
96
232
 
97
233
  it "should return an empty array when there are no subscribers" do
98
234
  Spotify.should_receive(:playlist_subscribers).and_return(mock_empty_subscribers)
99
- subject.subscribers.should eq []
235
+ playlist.subscribers.should eq []
100
236
  end
101
237
 
102
- it "should return nil when subscriber fetching failed" do
103
- Spotify.should_receive(:playlist_subscribers).and_return(null_pointer)
104
- playlist.subscribers.should be_nil
238
+ it "should return an empty array when subscriber fetching failed" do
239
+ empty_playlist.subscribers.should eq []
105
240
  end
106
241
  end
107
242
 
108
- describe "#insert", :stub_session do
243
+ describe "#insert" do
109
244
  let(:tracks) { instantiate(Hallon::Track, mock_track, mock_track_two) }
110
245
 
111
246
  it "should add the given tracks to the playlist at correct index" do
@@ -192,7 +327,7 @@ describe Hallon::Playlist do
192
327
  end
193
328
  end
194
329
 
195
- describe "#in_ram=", :stub_session do
330
+ describe "#in_ram=" do
196
331
  it "should set in_ram status" do
197
332
  playlist.should be_in_ram
198
333
  playlist.in_ram = false
@@ -200,7 +335,7 @@ describe Hallon::Playlist do
200
335
  end
201
336
  end
202
337
 
203
- describe "#offline_mode=", :stub_session do
338
+ describe "#offline_mode=" do
204
339
  it "should set offline mode" do
205
340
  playlist.should_not be_available_offline
206
341
  playlist.offline_mode = true
@@ -208,7 +343,7 @@ describe Hallon::Playlist do
208
343
  end
209
344
  end
210
345
 
211
- describe "#update_subscribers", :stub_session do
346
+ describe "#update_subscribers" do
212
347
  it "should ask libspotify to update the subscribers" do
213
348
  expect { playlist.update_subscribers }.to_not raise_error
214
349
  end
@@ -218,29 +353,29 @@ describe Hallon::Playlist do
218
353
  end
219
354
  end
220
355
 
221
- describe "offline status methods", :stub_session do
356
+ describe "offline status methods" do
222
357
  def symbol_for(number)
223
358
  Spotify.enum_type(:playlist_offline_status)[number]
224
359
  end
225
360
 
226
361
  specify "#available_offline?" do
227
362
  Spotify.should_receive(:playlist_get_offline_status).and_return symbol_for(1)
228
- should be_available_offline
363
+ playlist.should be_available_offline
229
364
  end
230
365
 
231
366
  specify "#syncing?" do
232
367
  Spotify.should_receive(:playlist_get_offline_status).and_return symbol_for(2)
233
- should be_syncing
368
+ playlist.should be_syncing
234
369
  end
235
370
 
236
371
  specify "#waiting?" do
237
372
  Spotify.should_receive(:playlist_get_offline_status).and_return symbol_for(3)
238
- should be_waiting
373
+ playlist.should be_waiting
239
374
  end
240
375
 
241
376
  specify "#offline_mode?" do
242
377
  Spotify.should_receive(:playlist_get_offline_status).and_return symbol_for(0)
243
- should_not be_offline_mode
378
+ playlist.should_not be_offline_mode
244
379
  end
245
380
  end
246
381
  end