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,59 +1,94 @@
1
1
  # coding: utf-8
2
2
  #
3
3
  describe Hallon::Album do
4
- it { should be_a Hallon::Loadable }
4
+ let(:album) do
5
+ Hallon::Album.new(mock_albums[:default])
6
+ end
7
+
8
+ let(:empty_album) do
9
+ Hallon::Album.new(mock_albums[:empty])
10
+ end
11
+
12
+ specify { album.should be_a Hallon::Loadable }
5
13
 
6
14
  it_should_behave_like "a Linkable object" do
7
15
  let(:spotify_uri) { "spotify:album:1xvnWMz2PNFf7mXOSRuLws" }
8
16
  end
9
17
 
10
- let(:album) { Hallon::Album.new(mock_album) }
11
- subject { album }
18
+ describe ".types" do
19
+ subject { Hallon::Album.types }
12
20
 
13
- its(:name) { should eq "Finally Woken" }
14
- its(:release_year) { should be 2004 }
15
- its(:type) { should be :single }
16
- its(:browse) do
17
- mock_session { should eq Hallon::AlbumBrowse.new(album) }
21
+ it { should be_an Array }
22
+ it { should include :single }
18
23
  end
19
24
 
20
- it { should be_available }
21
- it { should be_loaded }
25
+ describe "#name" do
26
+ it "returns the album’s name" do
27
+ album.name.should eq "Finally Woken"
28
+ end
22
29
 
23
- describe "artist" do
24
- it "should be nil if there is no artist" do
25
- Spotify.should_receive(:album_artist).and_return(null_pointer)
26
- album.artist.should be_nil
30
+ it "returns an empty string if the album is not loaded" do
31
+ empty_album.name.should be_empty
32
+ end
33
+ end
34
+
35
+ describe "#release_year" do
36
+ it "returns the album’s release year" do
37
+ album.release_year.should eq 2004
38
+ end
39
+ end
40
+
41
+ describe "#type" do
42
+ it "returns the album’s type" do
43
+ album.type.should eq :single
44
+ end
45
+ end
46
+
47
+ describe "#browse" do
48
+ it "returns the album’s browser object" do
49
+ album.browse.should eq Hallon::AlbumBrowse.new(album)
27
50
  end
51
+ end
28
52
 
53
+ describe "#available?" do
54
+ it "returns true when the album is available" do
55
+ album.should be_available
56
+ end
57
+ end
58
+
59
+ describe "#loaded?" do
60
+ it "returns true when the album is loaded" do
61
+ album.should be_loaded
62
+ end
63
+ end
64
+
65
+ describe "artist" do
29
66
  it "should be an artist if it exists" do
30
67
  album.artist.should eq Hallon::Artist.new(mock_artist)
31
68
  end
32
- end
33
69
 
34
- describe "#cover" do
35
- it "should be nil if there is no image" do
36
- Spotify.should_receive(:album_cover).and_return(null_pointer)
37
- album.cover.should be_nil
70
+ it "should be nil if there is no artist" do
71
+ empty_album.artist.should be_nil
38
72
  end
73
+ end
39
74
 
75
+ describe "#cover" do
40
76
  it "should be an image if it exists" do
41
- stub_session { album.cover.should eq Hallon::Image.new(mock_image_id) }
77
+ album.cover.should eq Hallon::Image.new(mock_image_id)
42
78
  end
43
- end
44
79
 
45
- describe "#cover_link" do
46
80
  it "should be nil if there is no image" do
47
- Spotify.should_receive(:link_create_from_album_cover).and_return(null_pointer)
48
- album.cover_link.should be_nil
81
+ empty_album.cover.should be_nil
49
82
  end
83
+ end
50
84
 
85
+ describe "#cover_link" do
51
86
  it "should be a link if it exists" do
52
87
  album.cover_link.should eq Hallon::Link.new("spotify:image:3ad93423add99766e02d563605c6e76ed2b0e400")
53
88
  end
54
- end
55
89
 
56
- describe ".types" do
57
- specify { Hallon::Album.types.should_not be_empty }
90
+ it "should be nil if there is no image" do
91
+ empty_album.cover_link.should be_nil
92
+ end
58
93
  end
59
94
  end
@@ -1,11 +1,22 @@
1
1
  # coding: utf-8
2
+
2
3
  describe Hallon::ArtistBrowse do
3
- it { should be_a Hallon::Loadable }
4
+ let(:browse) do
5
+ artist = Hallon::Artist.new(mock_artists[:default])
6
+ Hallon::ArtistBrowse.new(artist)
7
+ end
8
+
9
+ let(:empty_browse) do
10
+ artist = Hallon::Artist.new(mock_artists[:empty])
11
+ Hallon::ArtistBrowse.new(artist)
12
+ end
13
+
14
+ specify { browse.should be_a Hallon::Loadable }
4
15
 
5
16
  describe ".new" do
6
17
  it "should raise an error if the browse request failed" do
7
18
  Spotify.should_receive(:artistbrowse_create).and_return(null_pointer)
8
- expect { mock_session { Hallon::ArtistBrowse.new(mock_artist) } }.to raise_error(FFI::NullPointerError)
19
+ expect { Hallon::ArtistBrowse.new(mock_artist) }.to raise_error(FFI::NullPointerError)
9
20
  end
10
21
 
11
22
  it "should raise an error given a non-album spotify pointer" do
@@ -13,48 +24,112 @@ describe Hallon::ArtistBrowse do
13
24
  end
14
25
  end
15
26
 
16
- let(:browse) do
17
- artist = Hallon::Artist.new(mock_artist)
18
- mock_session { Hallon::ArtistBrowse.new(artist) }
27
+ describe '.types' do
28
+ subject { Hallon::ArtistBrowse.types }
29
+
30
+ it { should be_an Array }
31
+ it { should include :full }
32
+ end
33
+
34
+ describe "#loaded?" do
35
+ it "is true when the artist browser is loaded" do
36
+ browse.should be_loaded
37
+ end
19
38
  end
20
39
 
21
- subject { browse }
40
+ describe "#status" do
41
+ it "returns the artist browser’s status" do
42
+ browse.status.should eq :ok
43
+ end
44
+ end
22
45
 
23
- it { should be_loaded }
24
- its(:status) { should eq :ok }
25
- its(:artist) { should eq Hallon::Artist.new(mock_artist) }
46
+ describe "#biography" do
47
+ it "returns the artist’s biography" do
48
+ browse.biography.should eq 'grew up in DA BLOCK'
49
+ end
26
50
 
27
- its('portraits.size') { should eq 2 }
28
- its('portraits.to_a') do
29
- stub_session { should eq instantiate(Hallon::Image, mock_image_id, mock_image_id) }
51
+ it "returns an empty string when the artist browser is not loaded" do
52
+ empty_browse.biography.should be_empty
53
+ end
30
54
  end
31
55
 
32
- its('portrait_links.size') { should eq 2 }
33
- its('portrait_links.to_a') { should eq instantiate(Hallon::Link, mock_image_link, mock_image_link) }
56
+ describe "#artist" do
57
+ it "returns the artist" do
58
+ browse.artist.should eq Hallon::Artist.new(mock_artists[:default])
59
+ end
34
60
 
35
- its('tracks.size') { should eq 2 }
36
- its('tracks.to_a') { should eq [mock_track, mock_track_two].map{ |p| Hallon::Track.new(p) } }
37
- its('albums.size') { should eq 1 }
38
- its('albums.to_a') { should eq [Hallon::Album.new(mock_album)] }
39
- its('similar_artists.size') { should eq 2 }
40
- its('similar_artists.to_a') { should eq [mock_artist, mock_artist_two].map{ |p| Hallon::Artist.new(p) } }
41
- its(:biography) { should eq 'grew up in DA BLOCK' }
61
+ it "returns nil if the artist browser is not loaded" do
62
+ empty_browse.artist.should be_nil
63
+ end
64
+ end
42
65
 
43
- describe "#request_duration" do
44
- it "should return the request duration in seconds" do
45
- browse.request_duration.should eq 2.751
66
+ describe "#portraits" do
67
+ it "returns an enumerator of the artist’s portraits" do
68
+ browse.portraits.to_a.should eq instantiate(Hallon::Image, mock_image_id, mock_image_id)
46
69
  end
47
70
 
48
- it "should be nil if the request was fetched from local cache" do
49
- Spotify.should_receive(:artistbrowse_backend_request_duration).and_return(-1)
50
- browse.request_duration.should be_nil
71
+ it "returns an empty enumerator when the artist browser is not loaded" do
72
+ empty_browse.portraits.size.should eq 0
51
73
  end
52
74
  end
53
75
 
54
- describe '.types' do
55
- subject { Hallon::ArtistBrowse.types }
76
+ describe "#portrait_links" do
77
+ it "returns an enumerator of the artist’s portrait links" do
78
+ browse.portrait_links.to_a.should eq instantiate(Hallon::Link, mock_image_link, mock_image_link)
79
+ end
56
80
 
57
- it { should be_an Array }
58
- it { should include :full }
81
+ it "returns an empty enumerator when the artist browser is not loaded" do
82
+ empty_browse.portrait_links.size.should eq 0
83
+ end
84
+ end
85
+
86
+ describe "#tracks" do
87
+ it "returns an enumerator of the artist’s tracks" do
88
+ browse.tracks.to_a.should eq instantiate(Hallon::Track, mock_track, mock_track_two)
89
+ end
90
+
91
+ it "returns an empty enumerator when the artist browser is not loaded" do
92
+ empty_browse.tracks.size.should eq 0
93
+ end
94
+ end
95
+
96
+ describe "#albums" do
97
+ it "returns an enumerator of the artist’s albums" do
98
+ browse.albums.to_a.should eq instantiate(Hallon::Album, mock_album)
99
+ end
100
+
101
+ it "returns an empty enumerator when the artist browser is not loaded" do
102
+ empty_browse.albums.size.should eq 0
103
+ end
104
+ end
105
+
106
+ describe "#similar_artists" do
107
+ it "returns an enumerator of the artist’s albums" do
108
+ browse.similar_artists.to_a.should eq instantiate(Hallon::Artist, mock_artist, mock_artist_two)
109
+ end
110
+
111
+ it "returns an empty enumerator when the artist browser is not loaded" do
112
+ empty_browse.similar_artists.size.should eq 0
113
+ end
114
+ end
115
+
116
+ describe "#top_hits" do
117
+ it "returns an enumerator of the artist’s top hits" do
118
+ browse.top_hits.to_a.should eq instantiate(Hallon::Track, mock_track)
119
+ end
120
+
121
+ it "returns an empty enumerator when the artist browser is not loaded" do
122
+ empty_browse.top_hits.should be_empty
123
+ end
124
+ end
125
+
126
+ describe "#request_duration" do
127
+ it "should return the request duration in seconds" do
128
+ browse.request_duration.should eq 2.751
129
+ end
130
+
131
+ it "should be zero if the request was fetched from local cache" do
132
+ empty_browse.request_duration.should eq 0
133
+ end
59
134
  end
60
135
  end
@@ -1,20 +1,38 @@
1
1
  # coding: utf-8
2
2
  describe Hallon::Artist do
3
- it { should be_a Hallon::Loadable }
3
+ let(:artist) do
4
+ Hallon::Artist.new(mock_artists[:default])
5
+ end
6
+
7
+ let(:empty_artist) do
8
+ Hallon::Artist.new(mock_artists[:empty])
9
+ end
10
+
11
+ specify { artist.should be_a Hallon::Loadable }
4
12
 
5
13
  it_should_behave_like "a Linkable object" do
6
14
  let(:spotify_uri) { "spotify:artist:3bftcFwl4vqRNNORRsqm1G" }
7
15
  end
8
16
 
9
- let(:artist) { Hallon::Artist.new(mock_artist) }
10
- subject { artist }
17
+ describe "#loaded?" do
18
+ it "returns true when the artist is loaded" do
19
+ artist.should be_loaded
20
+ end
21
+ end
11
22
 
12
- it { should be_loaded }
13
- its(:name) { should eq "Jem" }
23
+ describe "#name" do
24
+ it "returns the artist’s name" do
25
+ artist.name.should eq "Jem"
26
+ end
27
+
28
+ it "returns an empty string if the artist is not loaded" do
29
+ empty_artist.name.should be_empty
30
+ end
31
+ end
14
32
 
15
33
  describe "#browse" do
16
34
  it "should return an artist browsing object" do
17
- mock_session(2) { subject.browse.should eq Hallon::ArtistBrowse.new(mock_artist) }
35
+ artist.browse.should eq Hallon::ArtistBrowse.new(mock_artist)
18
36
  end
19
37
 
20
38
  it "should default to full browsing" do
@@ -29,26 +47,22 @@ describe Hallon::Artist do
29
47
  end
30
48
 
31
49
  describe "#portrait" do
32
- let(:link) { Hallon::Link.new(mock_image_uri) }
33
-
34
- it "should be nil if an image is not available" do
35
- Spotify.should_receive(:artist_portrait).and_return(null_pointer)
36
- artist.portrait.should be_nil
37
- end
38
-
39
50
  it "should be an image if it exists" do
40
- stub_session { artist.portrait.should eq Hallon::Image.new(mock_image_id) }
51
+ artist.portrait.should eq Hallon::Image.new(mock_image_id)
41
52
  end
42
- end
43
53
 
44
- describe "#portrait_link" do
45
54
  it "should be nil if an image is not available" do
46
- Spotify.should_receive(:link_create_from_artist_portrait).and_return(null_pointer)
47
- artist.portrait_link.should be_nil
55
+ empty_artist.portrait.should be_nil
48
56
  end
57
+ end
49
58
 
59
+ describe "#portrait_link" do
50
60
  it "should be a link if it exists" do
51
61
  artist.portrait_link.should eq Hallon::Link.new(mock_image_uri)
52
62
  end
63
+
64
+ it "should be nil if an image is not available" do
65
+ empty_artist.portrait_link.should be_nil
66
+ end
53
67
  end
54
68
  end
@@ -0,0 +1,6 @@
1
+ describe Hallon::Blob do
2
+ it "is infectious" do
3
+ Hallon::Blob("string").should be_a Hallon::Blob
4
+ Hallon::Blob("string").should be_a String
5
+ end
6
+ end
@@ -50,6 +50,16 @@ describe Hallon::Enumerator do
50
50
  end
51
51
  end
52
52
 
53
+ describe "#empty?" do
54
+ it "returns true if the enumerator is empty" do
55
+ enumerator(0).should be_empty
56
+ end
57
+
58
+ it "returns false if the enumerator is not empty" do
59
+ enum.should_not be_empty
60
+ end
61
+ end
62
+
53
63
  describe "#[]" do
54
64
  it "should return nil if #[x] is not within the enumerators’ size (no matter if the value exists or not)" do
55
65
  enum.should_receive(:size).and_return(1)
@@ -3,7 +3,7 @@ describe Hallon::Error do
3
3
 
4
4
  it { should <= RuntimeError }
5
5
 
6
- describe "::disambiguate" do
6
+ describe ".disambiguate" do
7
7
  it "should not fail on invalid numbers" do
8
8
  subject.disambiguate(10000).should eq [-1, nil]
9
9
  end
@@ -13,7 +13,7 @@ describe Hallon::Error do
13
13
  end
14
14
  end
15
15
 
16
- describe "::explain" do
16
+ describe ".explain" do
17
17
  it "should work properly given an integer" do
18
18
  subject.explain(0).should eq 'sp_error: 0'
19
19
  end
@@ -23,7 +23,7 @@ describe Hallon::Error do
23
23
  end
24
24
  end
25
25
 
26
- describe "::maybe_raise" do
26
+ describe ".maybe_raise" do
27
27
  it "should not raise error when given 0 as error code" do
28
28
  expect { subject.maybe_raise(0) }.to_not raise_error
29
29
  end
@@ -47,7 +47,7 @@ describe Hallon::Error do
47
47
  end
48
48
  end
49
49
 
50
- describe "::table" do
50
+ describe ".table" do
51
51
  it "should return a hash of symbol to integer" do
52
52
  Hallon::Error.table[:ok].should eq 0
53
53
  end
@@ -18,7 +18,7 @@ describe Hallon do
18
18
  end
19
19
  end
20
20
 
21
- describe "#load_timeout" do
21
+ describe ".load_timeout" do
22
22
  it "should raise an error given a negative timeout" do
23
23
  expect { Hallon.load_timeout = -1 }.to raise_error(ArgumentError)
24
24
  end
@@ -2,76 +2,87 @@
2
2
  require 'ostruct'
3
3
 
4
4
  describe Hallon::Image do
5
- it { described_class.should include Hallon::Loadable }
5
+ let(:image) do
6
+ Hallon::Image.new(mock_image)
7
+ end
8
+
9
+ let(:empty_image) do
10
+ Hallon::Image.new(mock_empty_image)
11
+ end
6
12
 
7
13
  it_should_behave_like "a Linkable object" do
8
14
  let(:spotify_uri) { "spotify:image:#{mock_image_hex}" }
9
15
  let(:custom_object) { mock_image_hex }
16
+ let(:described_class) { Hallon::Image }
17
+ end
10
18
 
11
- let(:described_class) do
12
- real_session = session
13
- Hallon::Image.dup.tap do |klass|
14
- klass.class_eval do
15
- define_method(:session) { real_session }
16
- end
17
- end
19
+ specify { image.should be_a Hallon::Loadable }
20
+
21
+ describe "#loaded?" do
22
+ it "returns true when the image is loaded" do
23
+ image.should be_loaded
18
24
  end
19
25
  end
20
26
 
21
- describe "an image instance" do
22
- subject { image }
23
- let(:image) { Hallon::Image.new(mock_image) }
27
+ describe "#status" do
28
+ it "returns the image’s status" do
29
+ image.status.should eq :ok
30
+ end
31
+ end
24
32
 
25
- it { should be_loaded }
26
- its(:status) { should be :ok }
27
- its(:format) { should be :jpeg }
33
+ describe "#format" do
34
+ it "returns the image’s format" do
35
+ image.format.should eq :jpeg
36
+ end
37
+ end
28
38
 
29
- describe "#id" do
30
- it "should return the image id as a hexadecimal string" do
31
- image.id.should eq mock_image_hex
32
- end
39
+ describe "#id" do
40
+ it "returns the image id as a hexadecimal string" do
41
+ image.id.should eq mock_image_hex
33
42
  end
43
+ end
34
44
 
35
- describe "#raw_id" do
36
- it "should return the image id as a binary string" do
37
- image.raw_id.should eq mock_image_id
38
- end
45
+ describe "#raw_id" do
46
+ it "returns the image id as a binary string" do
47
+ image.raw_id.should eq mock_image_id
39
48
  end
49
+ end
40
50
 
41
- describe "#data" do
42
- subject { image.data }
51
+ describe "#data" do
52
+ it "returns the image’s data" do
53
+ image.data.should eq File.open(fixture_image_path, 'r:binary', &:read)
54
+ end
43
55
 
44
- it "should correspond to the fixture image" do
45
- should eq File.open(fixture_image_path, 'r:binary', &:read)
46
- end
56
+ it "has a binary encoding" do
57
+ image.data.encoding.name.should eq 'ASCII-8BIT'
58
+ end
47
59
 
48
- it "should have a binary encoding" do
49
- subject.encoding.name.should eq 'ASCII-8BIT'
50
- end
60
+ it "returns an empty string if the image is not loaded" do
61
+ empty_image.data.should be_empty
51
62
  end
63
+ end
52
64
 
53
- describe "#to_link" do
54
- it "should retrieve the Spotify URI" do
55
- image.to_link.should eq Hallon::Link.new("spotify:image:#{image.id}")
56
- end
65
+ describe "#to_link" do
66
+ it "should retrieve the Spotify URI" do
67
+ image.to_link.should eq Hallon::Link.new("spotify:image:#{image.id}")
57
68
  end
69
+ end
58
70
 
59
- describe "#===" do
60
- it "should compare ids (but only if other is an Image)" do
61
- other = double
62
- other.should_receive(:is_a?).with(Hallon::Image).and_return(true)
63
- other.should_receive(:raw_id).and_return(image.raw_id)
71
+ describe "#===" do
72
+ it "should compare ids (but only if other is an Image)" do
73
+ other = double
74
+ other.should_receive(:is_a?).with(Hallon::Image).and_return(true)
75
+ other.should_receive(:raw_id).and_return(image.raw_id)
64
76
 
65
- image.should eq other
66
- image.should_not eq double
67
- end
77
+ image.should eq other
78
+ image.should_not eq double
79
+ end
68
80
 
69
- it "should not call #id if other is not an image" do
70
- other = double
71
- other.should_not_receive(:raw_id)
81
+ it "should not call #id if other is not an image" do
82
+ other = double
83
+ other.should_not_receive(:raw_id)
72
84
 
73
- image.should_not eq other
74
- end
85
+ image.should_not eq other
75
86
  end
76
87
  end
77
88
  end