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.
- data/CHANGELOG.md +40 -0
- data/README.markdown +1 -1
- data/dev/application_key_converter.rb +11 -0
- data/examples/example_support.rb +4 -0
- data/examples/playing_audio.rb +1 -1
- data/lib/hallon.rb +11 -0
- data/lib/hallon/album_browse.rb +3 -3
- data/lib/hallon/artist_browse.rb +20 -4
- data/lib/hallon/blob.rb +11 -0
- data/lib/hallon/enumerator.rb +5 -0
- data/lib/hallon/ext/spotify.rb +2 -0
- data/lib/hallon/image.rb +7 -1
- data/lib/hallon/link.rb +5 -2
- data/lib/hallon/observable.rb +48 -1
- data/lib/hallon/player.rb +15 -26
- data/lib/hallon/playlist.rb +16 -25
- data/lib/hallon/playlist_container.rb +38 -0
- data/lib/hallon/search.rb +75 -4
- data/lib/hallon/session.rb +31 -42
- data/lib/hallon/toplist.rb +3 -3
- data/lib/hallon/track.rb +28 -10
- data/lib/hallon/version.rb +1 -1
- data/spec/hallon/album_browse_spec.rb +68 -18
- data/spec/hallon/album_spec.rb +62 -27
- data/spec/hallon/artist_browse_spec.rb +106 -31
- data/spec/hallon/artist_spec.rb +32 -18
- data/spec/hallon/blob_spec.rb +6 -0
- data/spec/hallon/enumerator_spec.rb +10 -0
- data/spec/hallon/error_spec.rb +4 -4
- data/spec/hallon/hallon_spec.rb +1 -1
- data/spec/hallon/image_spec.rb +58 -47
- data/spec/hallon/link_spec.rb +51 -43
- data/spec/hallon/observable/album_browse_spec.rb +1 -1
- data/spec/hallon/observable/artist_browse_spec.rb +1 -1
- data/spec/hallon/observable/image_spec.rb +1 -1
- data/spec/hallon/observable/playlist_container_spec.rb +4 -4
- data/spec/hallon/observable/playlist_spec.rb +14 -14
- data/spec/hallon/observable/post_spec.rb +1 -1
- data/spec/hallon/observable/search_spec.rb +1 -1
- data/spec/hallon/observable/session_spec.rb +17 -17
- data/spec/hallon/observable/toplist_spec.rb +1 -1
- data/spec/hallon/observable_spec.rb +40 -6
- data/spec/hallon/player_spec.rb +1 -1
- data/spec/hallon/playlist_container_spec.rb +96 -13
- data/spec/hallon/playlist_spec.rb +180 -45
- data/spec/hallon/search_spec.rb +211 -28
- data/spec/hallon/session_spec.rb +44 -38
- data/spec/hallon/toplist_spec.rb +31 -14
- data/spec/hallon/track_spec.rb +159 -50
- data/spec/hallon/user_post_spec.rb +10 -5
- data/spec/hallon/user_spec.rb +60 -50
- data/spec/spec_helper.rb +40 -15
- data/spec/support/album_mocks.rb +30 -0
- data/spec/support/artist_mocks.rb +36 -0
- data/spec/support/common_objects.rb +0 -201
- data/spec/support/image_mocks.rb +34 -0
- data/spec/support/playlist_container_mocks.rb +36 -0
- data/spec/support/playlist_mocks.rb +70 -0
- data/spec/support/search_mocks.rb +23 -0
- data/spec/support/session_mocks.rb +33 -0
- data/spec/support/toplist_mocks.rb +19 -0
- data/spec/support/track_mocks.rb +28 -0
- data/spec/support/user_mocks.rb +20 -0
- metadata +40 -18
- data/spec/support/context_stub_session.rb +0 -5
data/spec/hallon/link_spec.rb
CHANGED
@@ -1,69 +1,77 @@
|
|
1
1
|
describe Hallon::Link do
|
2
|
-
|
2
|
+
let(:link) do
|
3
|
+
Hallon::Link.new("spotify:user:burgestrand")
|
4
|
+
end
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
25
|
-
|
25
|
+
it "should accept any object that supplies a #to_link method" do
|
26
|
+
link = Hallon::Link.new("spotify:user:burgestrand")
|
26
27
|
|
27
|
-
|
28
|
-
|
28
|
+
to_linkable = double
|
29
|
+
to_linkable.should_receive(:to_link).and_return(link)
|
29
30
|
|
30
|
-
|
31
|
-
end
|
31
|
+
Hallon::Link.new(to_linkable).should eq link
|
32
32
|
end
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
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
|
-
|
57
|
+
link.to_str(7).should == "spotify"
|
52
58
|
end
|
53
59
|
|
54
60
|
it "should be in UTF-8 encoding" do
|
55
|
-
|
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
|
-
|
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
|
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
|
79
|
-
|
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(
|
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(
|
98
|
+
objB.should_receive(:to_str).and_return(link.to_str)
|
91
99
|
|
92
|
-
|
93
|
-
|
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(
|
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
|
-
|
112
|
+
link.should eq object
|
105
113
|
end
|
106
114
|
end
|
107
115
|
|
@@ -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
|
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
|
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
|
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) { [
|
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
|
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]
|
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
|
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) { [
|
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) { [
|
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
|
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) { [
|
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)
|
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
|
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!"
|
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"
|
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)
|
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
|
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) { [
|
89
|
+
let(:output) { [] }
|
90
90
|
end
|
91
91
|
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
|
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) { [
|
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) { [
|
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
|
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"
|
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) { [
|
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)
|
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) { [
|
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) { [
|
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) { [
|
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) { [
|
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) { [
|
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
|
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) { [
|
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!"
|
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) { [
|
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
|
145
|
+
let(:output) { [:ok] }
|
146
146
|
end
|
147
147
|
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 "#
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
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
|
|