hallon 0.15.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
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,69 +1,77 @@
1
1
  describe Hallon::Link do
2
- subject { Hallon::Link.new("spotify:user:burgestrand") }
2
+ let(:link) do
3
+ Hallon::Link.new("spotify:user:burgestrand")
4
+ end
3
5
 
4
- context "class methods" do
5
- describe "::new" do
6
- it "should raise an ArgumentError on an invalid link" do
7
- expect { Hallon::Link.new("omgwtfbbq") }.to raise_error(ArgumentError, /omgwtfbbq/)
8
- end
6
+ describe ".new" do
7
+ it "should raise an ArgumentError on an invalid link" do
8
+ expect { Hallon::Link.new("omgwtfbbq") }.to raise_error(ArgumentError, /omgwtfbbq/)
9
+ end
9
10
 
10
- it "should not raise error on valid links" do
11
- expect { Hallon::Link.new("spotify:user:burgestrand") }.to_not raise_error
12
- end
11
+ it "should not raise error on valid links" do
12
+ expect { Hallon::Link.new("spotify:user:burgestrand") }.to_not raise_error
13
+ end
13
14
 
14
- it "should raise an error given a null pointer" do
15
- expect { Hallon::Link.new(Spotify::Pointer.new(null_pointer, :link, false)) }.to raise_error(ArgumentError)
16
- end
15
+ it "should raise an error given a null pointer" do
16
+ expect { Hallon::Link.new(Spotify::Pointer.new(null_pointer, :link, false)) }.to raise_error(ArgumentError)
17
+ end
17
18
 
18
- it "should raise an error when no session instance is about" do
19
- # this is due to a bug in libspotify, it will segfault otherwise
20
- Hallon::Session.stub(:instance?).and_return(false)
21
- expect { Hallon::Link.new("spotify:user:burgestrand") }.to raise_error(/session/i)
22
- end
19
+ it "should raise an error when no session instance is about" do
20
+ # this is due to a bug in libspotify, it will segfault otherwise
21
+ Hallon::Session.stub(:instance?).and_return(false)
22
+ expect { Hallon::Link.new("spotify:user:burgestrand") }.to raise_error(Hallon::NoSessionError)
23
+ end
23
24
 
24
- it "should accept any object that supplies a #to_link method" do
25
- link = Hallon::Link.new("spotify:user:burgestrand")
25
+ it "should accept any object that supplies a #to_link method" do
26
+ link = Hallon::Link.new("spotify:user:burgestrand")
26
27
 
27
- to_linkable = double
28
- to_linkable.should_receive(:to_link).and_return(link)
28
+ to_linkable = double
29
+ to_linkable.should_receive(:to_link).and_return(link)
29
30
 
30
- Hallon::Link.new(to_linkable).should eq link
31
- end
31
+ Hallon::Link.new(to_linkable).should eq link
32
32
  end
33
+ end
33
34
 
34
- describe "::valid?" do
35
- it "should be true for a valid link" do
36
- Hallon::Link.valid?("spotify:user:burgestrand").should be_true
37
- end
35
+ describe ".valid?" do
36
+ it "should be true for a valid link" do
37
+ Hallon::Link.valid?("spotify:user:burgestrand").should be_true
38
+ end
38
39
 
39
- it "should be false for an invalid link" do
40
- Hallon::Link.valid?("omgwtfbbq").should be_false
41
- end
40
+ it "should be false for an invalid link" do
41
+ Hallon::Link.valid?("omgwtfbbq").should be_false
42
+ end
43
+
44
+ it "raises an error when no session has been initialized" do
45
+ # this is due to a bug in libspotify, it will segfault otherwise
46
+ Hallon::Session.stub(:instance?).and_return(false)
47
+ expect { Hallon::Link.valid?("omgwtfbbq") }.to raise_error(Hallon::NoSessionError)
42
48
  end
43
49
  end
44
50
 
45
51
  describe "#to_str" do
46
52
  it "should return the Spotify URI as a string" do
47
- subject.to_str.should == "spotify:user:burgestrand"
53
+ link.to_str.should == "spotify:user:burgestrand"
48
54
  end
49
55
 
50
56
  it "should truncate if given a small maximum length" do
51
- subject.to_str(7).should == "spotify"
57
+ link.to_str(7).should == "spotify"
52
58
  end
53
59
 
54
60
  it "should be in UTF-8 encoding" do
55
- subject.to_str.encoding.should eq Encoding::UTF_8
61
+ link.to_str.encoding.should eq Encoding::UTF_8
56
62
  end
57
63
  end
58
64
 
59
65
  describe "#to_url" do
60
66
  it "should return the correct http URL" do
61
- subject.to_url.should == "http://open.spotify.com/user/burgestrand"
67
+ link.to_url.should == "http://open.spotify.com/user/burgestrand"
62
68
  end
63
69
  end
64
70
 
65
71
  describe "#length" do
66
- it { subject.length.should == "spotify:user:burgestrand".length }
72
+ it "returns the image length" do
73
+ link.length.should == "spotify:user:burgestrand".length
74
+ end
67
75
  end
68
76
 
69
77
  describe "#type" do
@@ -75,8 +83,8 @@ describe Hallon::Link do
75
83
  end
76
84
 
77
85
  describe "#to_s" do
78
- it("should include the Spotify URI") do
79
- subject.to_s.should include subject.to_str
86
+ it "includes the image URI" do
87
+ link.to_s.should include link.to_uri
80
88
  end
81
89
  end
82
90
 
@@ -85,23 +93,23 @@ describe Hallon::Link do
85
93
  objA = double
86
94
  objA.should_not_receive(:to_str)
87
95
 
88
- objB = Hallon::Link.new(subject.to_str)
96
+ objB = Hallon::Link.new(link.to_str)
89
97
  objB.should_receive(:pointer).and_return(null_pointer)
90
- objB.should_receive(:to_str).and_return(subject.to_str)
98
+ objB.should_receive(:to_str).and_return(link.to_str)
91
99
 
92
- subject.should_not eq objA
93
- subject.should eq objB
100
+ link.should_not eq objA
101
+ link.should eq objB
94
102
  end
95
103
 
96
104
  it "should compare underlying pointers if #to_str is unavailable" do
97
- object = Hallon::Link.new(subject.pointer)
105
+ object = Hallon::Link.new(link.pointer)
98
106
 
99
107
  def object.respond_to?(o)
100
108
  return false if o == :to_str
101
109
  super
102
110
  end
103
111
 
104
- subject.should eq object
112
+ link.should eq object
105
113
  end
106
114
  end
107
115
 
@@ -2,6 +2,6 @@ describe Hallon::Observable::AlbumBrowse do
2
2
  specification_for_callback "load" do
3
3
  let(:type) { :albumbrowse_complete_cb }
4
4
  let(:input) { [a_pointer, :userdata] }
5
- let(:output) { [subject] }
5
+ let(:output) { [] }
6
6
  end
7
7
  end
@@ -2,6 +2,6 @@ describe Hallon::Observable::ArtistBrowse do
2
2
  specification_for_callback "load" do
3
3
  let(:type) { :artistbrowse_complete_cb }
4
4
  let(:input) { [a_pointer, :userdata] }
5
- let(:output) { [subject] }
5
+ let(:output) { [] }
6
6
  end
7
7
  end
@@ -2,7 +2,7 @@ describe Hallon::Observable::Image do
2
2
  specification_for_callback "load" do
3
3
  let(:type) { :image_loaded_cb }
4
4
  let(:input) { [a_pointer, :userdata] }
5
- let(:output) { [subject] }
5
+ let(:output) { [] }
6
6
  end
7
7
  end
8
8
 
@@ -1,21 +1,21 @@
1
1
  describe Hallon::Observable::PlaylistContainer do
2
2
  specification_for_callback "playlist_added" do
3
3
  let(:input) { [a_pointer, mock_playlist_raw, 3, :userdata] }
4
- let(:output) { [Hallon::Playlist.new(mock_playlist), 3, subject] }
4
+ let(:output) { [Hallon::Playlist.new(mock_playlist), 3] }
5
5
  end
6
6
 
7
7
  specification_for_callback "playlist_removed" do
8
8
  let(:input) { [a_pointer, mock_playlist_raw, 3, :userdata] }
9
- let(:output) { [Hallon::Playlist.new(mock_playlist), 3, subject] }
9
+ let(:output) { [Hallon::Playlist.new(mock_playlist), 3] }
10
10
  end
11
11
 
12
12
  specification_for_callback "playlist_moved" do
13
13
  let(:input) { [a_pointer, mock_playlist_raw, 3, 8, :userdata] }
14
- let(:output) { [Hallon::Playlist.new(mock_playlist), 3, 8, subject] }
14
+ let(:output) { [Hallon::Playlist.new(mock_playlist), 3, 8] }
15
15
  end
16
16
 
17
17
  specification_for_callback "container_loaded" do
18
18
  let(:input) { [a_pointer, :userdata] }
19
- let(:output) { [subject] }
19
+ let(:output) { [] }
20
20
  end
21
21
  end
@@ -18,67 +18,67 @@ describe Hallon::Observable::Playlist do
18
18
 
19
19
  specification_for_callback "tracks_added" do
20
20
  let(:input) { [a_pointer, trackpointers, trackpointers_size, 0, :userdata] }
21
- let(:output) { [tracks, 0, subject] }
21
+ let(:output) { [tracks, 0] }
22
22
  end
23
23
 
24
24
  specification_for_callback "tracks_removed" do
25
25
  let(:input) { [a_pointer, track_index_pointers, trackpointers_size, :userdata] }
26
- let(:output) { [[0, 1], subject] }
26
+ let(:output) { [[0, 1]] }
27
27
  end
28
28
 
29
29
  specification_for_callback "tracks_moved" do
30
30
  let(:input) { [a_pointer, track_index_pointers, trackpointers_size, 7, :userdata] }
31
- let(:output) { [[0, 1], 7, subject] }
31
+ let(:output) { [[0, 1], 7] }
32
32
  end
33
33
 
34
34
  specification_for_callback "playlist_renamed" do
35
35
  let(:input) { [a_pointer, :userdata] }
36
- let(:output) { [subject] }
36
+ let(:output) { [] }
37
37
  end
38
38
 
39
39
  specification_for_callback "playlist_state_changed" do
40
40
  let(:input) { [a_pointer, :userdata] }
41
- let(:output) { [subject] }
41
+ let(:output) { [] }
42
42
  end
43
43
 
44
44
  specification_for_callback "playlist_update_in_progress" do
45
45
  let(:input) { [a_pointer, true, :userdata] }
46
- let(:output) { [true, subject] }
46
+ let(:output) { [true] }
47
47
  end
48
48
 
49
49
  specification_for_callback "playlist_metadata_updated" do
50
50
  let(:input) { [a_pointer, :userdata] }
51
- let(:output) { [subject] }
51
+ let(:output) { [] }
52
52
  end
53
53
 
54
54
  specification_for_callback "track_created_changed" do
55
55
  let(:input) { [a_pointer, 7, mock_user_raw, 15, :userdata] }
56
- let(:output) { [7, Hallon::User.new(mock_user), Time.at(15), subject] }
56
+ let(:output) { [7, Hallon::User.new(mock_user), Time.at(15)] }
57
57
  end
58
58
 
59
59
  specification_for_callback "track_seen_changed" do
60
60
  let(:input) { [a_pointer, 0, true, :userdata] }
61
- let(:output) { [0, true, subject] }
61
+ let(:output) { [0, true] }
62
62
  end
63
63
 
64
64
  specification_for_callback "track_message_changed" do
65
65
  let(:input) { [a_pointer, 13, "I LUFF JOO!", :userdata] }
66
- let(:output) { [13, "I LUFF JOO!", subject] }
66
+ let(:output) { [13, "I LUFF JOO!"] }
67
67
  end
68
68
 
69
69
  specification_for_callback "description_changed" do
70
70
  let(:input) { [a_pointer, "Merily merily merily bong", :userdata] }
71
- let(:output) { ["Merily merily merily bong", subject] }
71
+ let(:output) { ["Merily merily merily bong"] }
72
72
  end
73
73
 
74
74
  specification_for_callback "image_changed" do
75
75
  before { Hallon::Session.stub!(:instance => session) }
76
76
  let(:input) { [a_pointer, mock_image_id, :userdata] }
77
- let(:output) { [Hallon::Image.new(mock_image), subject] }
77
+ let(:output) { [Hallon::Image.new(mock_image)] }
78
78
 
79
79
  it "should not fail if the image has been *removed*" do
80
80
  block = proc { |image| }
81
- block.should_receive(:call).with(nil, subject)
81
+ block.should_receive(:call).with(nil)
82
82
  subject.on(:image_changed, &block)
83
83
  subject_callback.call(a_pointer, null_pointer, :userdata)
84
84
  end
@@ -86,6 +86,6 @@ describe Hallon::Observable::Playlist do
86
86
 
87
87
  specification_for_callback "subscribers_changed" do
88
88
  let(:input) { [a_pointer, :userdata] }
89
- let(:output) { [subject] }
89
+ let(:output) { [] }
90
90
  end
91
91
  end
@@ -2,7 +2,7 @@ describe Hallon::Observable::Post do
2
2
  specification_for_callback "complete" do
3
3
  let(:type) { :inboxpost_complete_cb }
4
4
  let(:input) { [a_pointer, :userdata] }
5
- let(:output) { [subject] }
5
+ let(:output) { [] }
6
6
  end
7
7
  end
8
8
 
@@ -2,6 +2,6 @@ describe Hallon::Observable::Search do
2
2
  specification_for_callback "load" do
3
3
  let(:type) { :search_complete_cb }
4
4
  let(:input) { [a_pointer, :userdata] }
5
- let(:output) { [subject] }
5
+ let(:output) { [] }
6
6
  end
7
7
  end
@@ -5,32 +5,32 @@ describe Hallon::Observable::Session do
5
5
 
6
6
  specification_for_callback "logged_in" do
7
7
  let(:input) { [a_pointer, :ok] }
8
- let(:output) { [:ok, subject] }
8
+ let(:output) { [:ok] }
9
9
  end
10
10
 
11
11
  specification_for_callback "logged_out" do
12
12
  let(:input) { [a_pointer] }
13
- let(:output) { [subject] }
13
+ let(:output) { [] }
14
14
  end
15
15
 
16
16
  specification_for_callback "metadata_updated" do
17
17
  let(:input) { [a_pointer] }
18
- let(:output) { [subject] }
18
+ let(:output) { [] }
19
19
  end
20
20
 
21
21
  specification_for_callback "connection_error" do
22
22
  let(:input) { [a_pointer, :ok] }
23
- let(:output) { [:ok, subject] }
23
+ let(:output) { [:ok] }
24
24
  end
25
25
 
26
26
  specification_for_callback "message_to_user" do
27
27
  let(:input) { [a_pointer, "ALL UR BASE"] }
28
- let(:output) { ["ALL UR BASE", subject] }
28
+ let(:output) { ["ALL UR BASE"] }
29
29
  end
30
30
 
31
31
  specification_for_callback "notify_main_thread" do
32
32
  let(:input) { [a_pointer] }
33
- let(:output) { [subject] }
33
+ let(:output) { [] }
34
34
  end
35
35
 
36
36
  specification_for_callback "music_delivery" do
@@ -58,7 +58,7 @@ describe Hallon::Observable::Session do
58
58
  end
59
59
 
60
60
  let(:input) { [a_pointer, format, frames, num_frames] }
61
- let(:output) { [{rate: 44100, type: :int16, channels: 2}, data.each_slice(2), subject] }
61
+ let(:output) { [{rate: 44100, type: :int16, channels: 2}, data.each_slice(2)] }
62
62
 
63
63
  it "should return the resulting value" do
64
64
  subject.on(:music_delivery) { 7 }
@@ -76,27 +76,27 @@ describe Hallon::Observable::Session do
76
76
 
77
77
  specification_for_callback "play_token_lost" do
78
78
  let(:input) { [a_pointer] }
79
- let(:output) { [subject] }
79
+ let(:output) { [] }
80
80
  end
81
81
 
82
82
  specification_for_callback "end_of_track" do
83
83
  let(:input) { [a_pointer] }
84
- let(:output) { [subject] }
84
+ let(:output) { [] }
85
85
  end
86
86
 
87
87
  specification_for_callback "start_playback" do
88
88
  let(:input) { [a_pointer] }
89
- let(:output) { [subject] }
89
+ let(:output) { [] }
90
90
  end
91
91
 
92
92
  specification_for_callback "stop_playback" do
93
93
  let(:input) { [a_pointer] }
94
- let(:output) { [subject] }
94
+ let(:output) { [] }
95
95
  end
96
96
 
97
97
  specification_for_callback "get_audio_buffer_stats" do
98
98
  let(:input) { [a_pointer, Spotify::AudioBufferStats.new.pointer] }
99
- let(:output) { [subject] }
99
+ let(:output) { [] }
100
100
 
101
101
  it "should return the resulting audio buffer stats" do
102
102
  stats = Spotify::AudioBufferStats.new
@@ -122,26 +122,26 @@ describe Hallon::Observable::Session do
122
122
 
123
123
  specification_for_callback "streaming_error" do
124
124
  let(:input) { [a_pointer, :ok] }
125
- let(:output) { [:ok, subject] }
125
+ let(:output) { [:ok] }
126
126
  end
127
127
 
128
128
  specification_for_callback "userinfo_updated" do
129
129
  let(:input) { [a_pointer] }
130
- let(:output) { [subject] }
130
+ let(:output) { [] }
131
131
  end
132
132
 
133
133
  specification_for_callback "log_message" do
134
134
  let(:input) { [a_pointer, "WATCHING U!"] }
135
- let(:output) { ["WATCHING U!", subject] }
135
+ let(:output) { ["WATCHING U!"] }
136
136
  end
137
137
 
138
138
  specification_for_callback "offline_status_updated" do
139
139
  let(:input) { [a_pointer] }
140
- let(:output) { [subject] }
140
+ let(:output) { [] }
141
141
  end
142
142
 
143
143
  specification_for_callback "offline_error" do
144
144
  let(:input) { [a_pointer, :ok] }
145
- let(:output) { [:ok, subject] }
145
+ let(:output) { [:ok] }
146
146
  end
147
147
  end
@@ -2,6 +2,6 @@ describe Hallon::Observable::Toplist do
2
2
  specification_for_callback "load" do
3
3
  let(:type) { :toplistbrowse_complete_cb }
4
4
  let(:input) { [a_pointer, :userdata] }
5
- let(:output) { [subject] }
5
+ let(:output) { [] }
6
6
  end
7
7
  end
@@ -45,6 +45,10 @@ describe Hallon::Observable do
45
45
  def pointer
46
46
  FFI::Pointer.new(0xDEADBEEF)
47
47
  end
48
+
49
+ def session
50
+ Hallon::Session.instance
51
+ end
48
52
  end
49
53
  end
50
54
 
@@ -159,12 +163,42 @@ describe Hallon::Observable do
159
163
  end
160
164
  end
161
165
 
162
- describe "#trigger" do
163
- it "should always append self to the arguments" do
164
- block = proc {}
165
- subject.on(:testing, &block)
166
- block.should_receive(:call).with(subject)
167
- subject.send(:trigger, :testing)
166
+ describe "#wait_for" do
167
+ around(:each) do |example|
168
+ Timeout.timeout(0.5, SlowTestError, &example)
169
+ end
170
+
171
+ it "should not call the given block on notify main thread event" do
172
+ notified = false
173
+ counter = 0
174
+
175
+ session.should_receive(:process_events).twice.and_return do
176
+ if notified
177
+ subject.class.send(:testing_callback, subject.pointer)
178
+ else
179
+ session.class.send(:notify_main_thread_callback, session.pointer)
180
+ notified = true
181
+ end
182
+
183
+ 0
184
+ end
185
+
186
+ subject.wait_for(:testing) do |event|
187
+ event.should eq :testing if (counter += 1) > 1
188
+ end
189
+ end
190
+
191
+ it "should time out if waiting for events too long" do
192
+ counter = 0
193
+ session.should_receive(:process_events).once.and_return(0) # and do nothing
194
+ subject.wait_for(:testing) do |event|
195
+ event.should be_nil if (counter += 1) > 1
196
+ end
197
+ end
198
+
199
+ it "should call the given block once before waiting" do
200
+ session.should_not_receive(:process_events)
201
+ subject.wait_for { true }
168
202
  end
169
203
  end
170
204