spotify 12.2.0 → 12.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -1
- data/.rspec +5 -0
- data/CHANGELOG.md +45 -27
- data/Gemfile +4 -0
- data/README.markdown +52 -19
- data/Rakefile +16 -7
- data/lib/spotify.rb +109 -8
- data/lib/spotify/api.rb +61 -0
- data/lib/spotify/api/album.rb +14 -0
- data/lib/spotify/api/album_browse.rb +18 -0
- data/lib/spotify/api/artist.rb +10 -0
- data/lib/spotify/api/artist_browse.rb +23 -0
- data/lib/spotify/api/error.rb +6 -0
- data/lib/spotify/api/image.rb +16 -0
- data/lib/spotify/api/inbox.rb +9 -0
- data/lib/spotify/api/link.rb +25 -0
- data/lib/spotify/api/playlist.rb +39 -0
- data/lib/spotify/api/playlist_container.rb +23 -0
- data/lib/spotify/api/search.rb +27 -0
- data/lib/spotify/api/session.rb +46 -0
- data/lib/spotify/api/toplist_browse.rb +17 -0
- data/lib/spotify/api/track.rb +26 -0
- data/lib/spotify/api/user.rb +10 -0
- data/lib/spotify/defines.rb +109 -0
- data/lib/spotify/error.rb +62 -0
- data/lib/spotify/managed_pointer.rb +90 -0
- data/lib/spotify/objects.rb +16 -0
- data/lib/spotify/objects/album.rb +5 -0
- data/lib/spotify/objects/album_browse.rb +5 -0
- data/lib/spotify/objects/artist.rb +5 -0
- data/lib/spotify/objects/artist_browse.rb +5 -0
- data/lib/spotify/objects/image.rb +5 -0
- data/lib/spotify/objects/inbox.rb +5 -0
- data/lib/spotify/objects/link.rb +5 -0
- data/lib/spotify/objects/playlist.rb +5 -0
- data/lib/spotify/objects/playlist_container.rb +5 -0
- data/lib/spotify/objects/search.rb +5 -0
- data/lib/spotify/objects/session.rb +20 -0
- data/lib/spotify/objects/toplist_browse.rb +5 -0
- data/lib/spotify/objects/track.rb +5 -0
- data/lib/spotify/objects/user.rb +5 -0
- data/lib/spotify/structs.rb +46 -0
- data/lib/spotify/structs/audio_buffer_stats.rb +10 -0
- data/lib/spotify/structs/audio_format.rb +12 -0
- data/lib/spotify/structs/offline_sync_status.rb +24 -0
- data/lib/spotify/structs/playlist_callbacks.rb +32 -0
- data/lib/spotify/structs/playlist_container_callbacks.rb +14 -0
- data/lib/spotify/structs/session_callbacks.rb +48 -0
- data/lib/spotify/structs/session_config.rb +64 -0
- data/lib/spotify/structs/subscribers.rb +31 -0
- data/lib/spotify/types.rb +3 -0
- data/lib/spotify/types/image_id.rb +5 -0
- data/lib/spotify/types/nul_string.rb +51 -0
- data/lib/spotify/types/utf8_string.rb +24 -28
- data/lib/spotify/util.rb +36 -0
- data/lib/spotify/version.rb +7 -2
- data/spec/api-linux.xml +1887 -0
- data/spec/api-mac.xml +1886 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/spotify/api_spec.rb +62 -0
- data/spec/spotify/defines_spec.rb +22 -0
- data/spec/spotify/enums_spec.rb +9 -0
- data/spec/spotify/managed_pointer_spec.rb +75 -0
- data/spec/spotify/spotify_spec.rb +69 -0
- data/spec/spotify/structs/session_config_spec.rb +20 -0
- data/spec/spotify/structs/struct_spec.rb +34 -0
- data/spec/spotify/structs/subscribers_spec.rb +31 -0
- data/spec/spotify/structs_spec.rb +19 -0
- data/spec/spotify/types/image_id_spec.rb +44 -0
- data/spec/spotify/types/nul_string_spec.rb +31 -0
- data/spec/spotify/types/utf8_string_spec.rb +24 -0
- data/spec/support/hook_spotify.rb +37 -0
- data/spec/support/spotify_util.rb +17 -0
- data/spotify.gemspec +6 -11
- metadata +99 -26
- data/lib/spotify/error_wrappers.rb +0 -165
- data/lib/spotify/functions.rb +0 -755
- data/lib/spotify/gc_wrappers.rb +0 -105
- data/lib/spotify/types/pointer.rb +0 -59
- data/spec/spotify_spec.rb +0 -467
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rbgccxml'
|
3
|
+
require 'rspec'
|
4
|
+
require 'pry'
|
5
|
+
|
6
|
+
require 'spec/support/hook_spotify'
|
7
|
+
require 'spec/support/spotify_util'
|
8
|
+
|
9
|
+
# You can pregenerate new XML files through:
|
10
|
+
# gccxml spec/api-mac.h -fxml=spec/api-mac.xml
|
11
|
+
# gccxml spec/api-linux.h -fxml=spec/api-linux.xml
|
12
|
+
API_H_PATH = File.expand_path("../api-#{Spotify.platform}.h", __FILE__)
|
13
|
+
API_H_SRC = File.read(API_H_PATH)
|
14
|
+
API_H_XML = RbGCCXML.parse_xml(API_H_PATH.sub('.h', '.xml'))
|
15
|
+
|
16
|
+
RSpec.configure do |config|
|
17
|
+
def api
|
18
|
+
Spotify::API
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
describe "Spotify functions" do
|
2
|
+
API_H_XML.functions.each do |func|
|
3
|
+
next unless func["name"] =~ /\Asp_/
|
4
|
+
attached_name = func["name"].sub(/\Asp_/, '')
|
5
|
+
|
6
|
+
def type_of(type, return_type = false)
|
7
|
+
return case type.to_cpp
|
8
|
+
when "const char*"
|
9
|
+
Spotify::UTF8String
|
10
|
+
when /\A(::)?(char|int|size_t|bool|sp_scrobbling_state|sp_session\*|byte)\*/
|
11
|
+
return_type ? :pointer : :buffer_out
|
12
|
+
when /::(.+_cb)\*/
|
13
|
+
$1.to_sym
|
14
|
+
when /::(\w+)\*\*/
|
15
|
+
:array
|
16
|
+
when /::sp_(\w+)\*/
|
17
|
+
const_name = $1.delete('_')
|
18
|
+
real_const = Spotify.constants.find { |const| const =~ /#{const_name}\z/i }
|
19
|
+
Spotify.const_get(real_const)
|
20
|
+
else
|
21
|
+
:pointer
|
22
|
+
end if type.is_a?(RbGCCXML::PointerType)
|
23
|
+
|
24
|
+
case type["name"]
|
25
|
+
when "unsigned int"
|
26
|
+
:uint
|
27
|
+
else
|
28
|
+
type["name"].sub(/\Asp_/, '').to_sym
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# We test several things in this test because if we make the assertions
|
33
|
+
# into separate tests there’s just too much noise on failure.
|
34
|
+
specify(func["name"]) do
|
35
|
+
# it should be attached
|
36
|
+
Spotify.should respond_to attached_name
|
37
|
+
|
38
|
+
# expect the correct number of arguments
|
39
|
+
$attached_methods[attached_name][:args].count.
|
40
|
+
should eq func.arguments.count
|
41
|
+
|
42
|
+
# each argument has the right type
|
43
|
+
current = $attached_methods[attached_name][:args]
|
44
|
+
actual = func.arguments.map { |arg| type_of(arg.cpp_type) }
|
45
|
+
|
46
|
+
current = current.map { |x| Spotify.resolve_type(x) }
|
47
|
+
actual = actual.map { |x| Spotify.resolve_type(x) }
|
48
|
+
|
49
|
+
current.should eq actual
|
50
|
+
|
51
|
+
# returns the correct type
|
52
|
+
current_type = $attached_methods[attached_name][:returns]
|
53
|
+
actual_type = type_of(func.return_type, true)
|
54
|
+
|
55
|
+
# loosen restraints on some return types, we don’t have enough info from header file
|
56
|
+
current_type = Spotify.resolve_type(current_type)
|
57
|
+
actual_type = Spotify.resolve_type(actual_type)
|
58
|
+
|
59
|
+
current_type.should eq actual_type
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
describe "Spotify enums" do
|
2
|
+
API_H_XML.enumerations.each do |enum|
|
3
|
+
attached_enum = Spotify.enum_type enum["name"].sub(/\Asp_/, '').to_sym
|
4
|
+
original_enum = enum.values.map { |v| [v["name"].downcase, v["init"]] }
|
5
|
+
|
6
|
+
describe enum["name"] do
|
7
|
+
it "should exist" do
|
8
|
+
attached_enum.should_not be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should match the definition" do
|
12
|
+
attached_enum_map = attached_enum.symbol_map.dup
|
13
|
+
original_enum.each do |(name, value)|
|
14
|
+
a_name, a_value = attached_enum_map.max_by { |(n, v)| (n.to_s.length if name.match(n.to_s)).to_i }
|
15
|
+
attached_enum_map.delete(a_name)
|
16
|
+
a_value.to_s.should eq value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
describe Spotify::ManagedPointer do
|
3
|
+
it "is equal to it’s retaining class" do
|
4
|
+
Spotify::User.should eq Spotify::User.retaining_class
|
5
|
+
Spotify::User.retaining_class.should eq Spotify::User
|
6
|
+
end
|
7
|
+
|
8
|
+
it "adds a ref if it is a retaining class" do
|
9
|
+
api.should_receive(:user_add_ref)
|
10
|
+
ptr = Spotify::User.retaining_class.new(FFI::Pointer.new(1))
|
11
|
+
ptr.autorelease = false # avoid auto-GC after test
|
12
|
+
end
|
13
|
+
|
14
|
+
it "does not add or release when the pointer is null" do
|
15
|
+
api.should_not_receive(:user_add_ref)
|
16
|
+
api.should_not_receive(:user_release)
|
17
|
+
|
18
|
+
ptr = Spotify::User.retaining_class.new(FFI::Pointer::NULL)
|
19
|
+
ptr.free
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "garbage collection" do
|
23
|
+
module Spotify
|
24
|
+
class << API
|
25
|
+
def bogus_add_ref(pointer)
|
26
|
+
end
|
27
|
+
|
28
|
+
def bogus_release(pointer)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Bogus < ManagedPointer
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:my_pointer) { FFI::Pointer.new(1) }
|
37
|
+
|
38
|
+
it "should work" do
|
39
|
+
api.stub(:bogus_add_ref)
|
40
|
+
|
41
|
+
# GC tests are a bit funky, but as long as we garbage_release at least once, then
|
42
|
+
# we can assume our GC works properly, but up the stakes just for the sake of it
|
43
|
+
api.should_receive(:bogus_release).at_least(1).times
|
44
|
+
|
45
|
+
5.times { Spotify::Bogus.retaining_class.new(FFI::Pointer.new(1)) }
|
46
|
+
5.times { GC.start; sleep 0.01 }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "all managed pointers" do
|
51
|
+
Spotify.constants.each do |const|
|
52
|
+
klass = Spotify.const_get(const)
|
53
|
+
next unless klass.is_a?(Class)
|
54
|
+
next unless klass < Spotify::ManagedPointer
|
55
|
+
|
56
|
+
it "#{klass.name} has a valid retain method" do
|
57
|
+
Spotify.should_receive(:public_send).and_return do |method, *args|
|
58
|
+
Spotify.should respond_to(method)
|
59
|
+
method.should match /_add_ref$/
|
60
|
+
end
|
61
|
+
|
62
|
+
klass.retain(FFI::Pointer.new(1))
|
63
|
+
end unless klass == Spotify::Session # has no valid retain
|
64
|
+
|
65
|
+
it "#{klass.name} has a valid release method" do
|
66
|
+
Spotify.should_receive(:public_send).and_return do |method, *args|
|
67
|
+
Spotify.should respond_to(method)
|
68
|
+
method.should match /_release$/
|
69
|
+
end
|
70
|
+
|
71
|
+
klass.release(FFI::Pointer.new(1))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
describe Spotify do
|
2
|
+
describe "VERSION" do
|
3
|
+
it "is defined" do
|
4
|
+
defined?(Spotify::VERSION).should eq "constant"
|
5
|
+
end
|
6
|
+
|
7
|
+
it "is the same version as in api.h" do
|
8
|
+
spotify_version = API_H_SRC.match(/#define\s+SPOTIFY_API_VERSION\s+(\d+)/)[1]
|
9
|
+
Spotify::API_VERSION.to_i.should eq spotify_version.to_i
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "proxying" do
|
14
|
+
it "responds to the spotify methods" do
|
15
|
+
Spotify.should respond_to :error_message
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".try" do
|
20
|
+
it "raises an error when the result is not OK" do
|
21
|
+
api.should_receive(:error_example).and_return(:bad_application_key)
|
22
|
+
expect { Spotify.try(:error_example) }.to raise_error(Spotify::Error, /BAD_APPLICATION_KEY/)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "does not raise an error when the result is OK" do
|
26
|
+
api.should_receive(:error_example).and_return(:ok)
|
27
|
+
Spotify.try(:error_example).should eq :ok
|
28
|
+
end
|
29
|
+
|
30
|
+
it "does not raise an error when the result is not an error-type" do
|
31
|
+
result = Object.new
|
32
|
+
api.should_receive(:error_example).and_return(result)
|
33
|
+
Spotify.try(:error_example).should eq result
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe ".enum_value!" do
|
38
|
+
it "raises an error if given an invalid enum value" do
|
39
|
+
expect { Spotify.enum_value!(:moo, "error value") }.to raise_error(ArgumentError)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "gives back the enum value for that enum" do
|
43
|
+
Spotify.enum_value!(:ok, "error value").should eq 0
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe ".attach_function" do
|
48
|
+
it "is a retaining class if the method is not creating" do
|
49
|
+
begin
|
50
|
+
Spotify::API.attach_function :whatever, [], Spotify::User
|
51
|
+
rescue FFI::NotFoundError
|
52
|
+
# expected, this method does not exist
|
53
|
+
end
|
54
|
+
|
55
|
+
$attached_methods["whatever"][:returns].should eq Spotify::User.retaining_class
|
56
|
+
end
|
57
|
+
|
58
|
+
it "is a non-retaining class if the method is creating" do
|
59
|
+
begin
|
60
|
+
Spotify::API.attach_function :whatever_create, [], Spotify::User
|
61
|
+
rescue FFI::NotFoundError
|
62
|
+
# expected, this method does not exist
|
63
|
+
end
|
64
|
+
|
65
|
+
$attached_methods["whatever_create"][:returns].should be Spotify::User
|
66
|
+
$attached_methods["whatever_create"][:returns].should_not be Spotify::User.retaining_class
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
describe Spotify::SessionConfig do
|
2
|
+
let(:config) { Spotify::SessionConfig.new }
|
3
|
+
|
4
|
+
it "allows SessionCallbacks as a member value (by reference)" do
|
5
|
+
config[:callbacks] = Spotify::SessionCallbacks.new
|
6
|
+
config[:callbacks].should be_a Spotify::SessionCallbacks
|
7
|
+
end
|
8
|
+
|
9
|
+
it "automatically sets application key size when setting application key from string" do
|
10
|
+
config[:application_key] = "h\x00e\x00y"
|
11
|
+
|
12
|
+
config[:application_key_size].should eq 5
|
13
|
+
config[:application_key].read_string(5).should eq "h\x00e\x00y"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "does not automatically set application key size when setting application key from pointer" do
|
17
|
+
expect { config[:application_key] = FFI::MemoryPointer.from_string("yay") }
|
18
|
+
.to_not change { config[:application_key_size] }
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
describe Spotify::Struct do
|
2
|
+
let(:klass) do
|
3
|
+
Class.new(Spotify::Struct) do
|
4
|
+
layout :api_version => :int,
|
5
|
+
:cache_location => Spotify::NULString,
|
6
|
+
:user_agent => Spotify::NULString,
|
7
|
+
:compress_playlists => :bool
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:options) do
|
12
|
+
{
|
13
|
+
:api_version => 1,
|
14
|
+
:cache_location => "Yay",
|
15
|
+
:user_agent => nil,
|
16
|
+
:compress_playlists => false
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it "allows initializing the struct with a hash" do
|
21
|
+
struct = klass.new(options)
|
22
|
+
options.each_pair { |key, value| struct[key].should eq value }
|
23
|
+
end
|
24
|
+
|
25
|
+
it "allows initializing the struct with a pointer" do
|
26
|
+
original = klass.new(options)
|
27
|
+
struct = klass.new(original.pointer)
|
28
|
+
options.each_pair { |key, value| struct[key].should eq value }
|
29
|
+
end
|
30
|
+
|
31
|
+
it "allows initializing the struct with nothing" do
|
32
|
+
expect { klass.new }.to_not raise_error
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
describe Spotify::Subscribers do
|
2
|
+
it "should create the subscribers array using count" do
|
3
|
+
# Memory looks like this:
|
4
|
+
#
|
5
|
+
# 00 00 00 00 <- count of subscribers
|
6
|
+
# 00 00 00 00 <- pointer to subscriber 1
|
7
|
+
# …… …… …… ……
|
8
|
+
# 00 00 00 00 <- pointer to subscriber n
|
9
|
+
real_struct = Spotify::Subscribers.new(2)
|
10
|
+
real_struct[:count] = 2
|
11
|
+
real_struct[:subscribers][0] = FFI::MemoryPointer.from_string("a")
|
12
|
+
real_struct[:subscribers][1] = FFI::MemoryPointer.from_string("bb")
|
13
|
+
|
14
|
+
struct = Spotify::Subscribers.new(real_struct.pointer)
|
15
|
+
struct[:count].should eq 2
|
16
|
+
struct[:subscribers].size.should eq 2
|
17
|
+
struct[:subscribers][0].read_string.should eq "a"
|
18
|
+
struct[:subscribers][1].read_string.should eq "bb"
|
19
|
+
expect { struct[:subscribers][2] }.to raise_error(IndexError)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
it "should not fail given an empty subscribers struct" do
|
24
|
+
subscribers = FFI::MemoryPointer.new(:uint)
|
25
|
+
subscribers.write_uint(0)
|
26
|
+
|
27
|
+
subject = Spotify::Subscribers.new(subscribers)
|
28
|
+
subject[:count].should eq 0
|
29
|
+
expect { subject[:subscribers] }.to raise_error(ArgumentError)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
describe "Spotify structs" do
|
2
|
+
API_H_XML.structs.each do |struct|
|
3
|
+
next if struct["incomplete"]
|
4
|
+
|
5
|
+
attached_struct = Spotify.structs.find do |const|
|
6
|
+
struct["name"].delete('_').match(/#{const}/i)
|
7
|
+
end
|
8
|
+
|
9
|
+
attached_members = Spotify.const_get(attached_struct).members.map(&:to_s)
|
10
|
+
|
11
|
+
describe struct["name"] do
|
12
|
+
it "should contain the same attributes in the same order" do
|
13
|
+
struct.variables.map(&:name).each_with_index do |member, index|
|
14
|
+
attached_members[index].should eq member
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
describe Spotify::ImageID do
|
2
|
+
let(:context) { nil }
|
3
|
+
let(:subject) { Spotify::API.find_type(Spotify::ImageID) }
|
4
|
+
let(:null_pointer) { FFI::Pointer::NULL }
|
5
|
+
|
6
|
+
let(:image_id_pointer) do
|
7
|
+
pointer = FFI::MemoryPointer.new(:char, 20)
|
8
|
+
pointer.write_string(image_id)
|
9
|
+
pointer
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:image_id) do
|
13
|
+
# deliberate NULL in middle of string
|
14
|
+
image_id = ":\xD94#\xAD\xD9\x97f\xE0\x00V6\x05\xC6\xE7n\xD2\xB0\xE4P"
|
15
|
+
image_id.force_encoding("BINARY")
|
16
|
+
image_id
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "from_native" do
|
20
|
+
it "should be nil given a null pointer" do
|
21
|
+
subject.from_native(null_pointer, context).should be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be an image id given a non-null pointer" do
|
25
|
+
subject.from_native(image_id_pointer, context).should eq image_id
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "to_native" do
|
30
|
+
it "should be a null pointer given nil" do
|
31
|
+
subject.to_native(nil, context).should be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should be a 20-byte C string given an actual string" do
|
35
|
+
pointer = subject.to_native(image_id, context)
|
36
|
+
pointer.read_string(20).should eq image_id_pointer.read_string(20)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should raise an error given more or less than a 20 byte string" do
|
40
|
+
expect { subject.to_native(image_id + image_id, context) }.to raise_error(ArgumentError)
|
41
|
+
expect { subject.to_native(image_id[0..10], context) }.to raise_error(ArgumentError)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
describe Spotify::NULString do
|
2
|
+
describe ".to_native" do
|
3
|
+
it "returns a memory pointer containing the given string" do
|
4
|
+
pointer = Spotify::NULString.to_native("coolio", nil)
|
5
|
+
pointer.read_string.should eq "coolio"
|
6
|
+
end
|
7
|
+
|
8
|
+
it "returns a null pointer when given nil" do
|
9
|
+
pointer = Spotify::NULString.to_native(nil, nil)
|
10
|
+
pointer.should be_null
|
11
|
+
end
|
12
|
+
|
13
|
+
it "raises an error when given a non-string" do
|
14
|
+
expect { Spotify::NULString.to_native({}, nil) }
|
15
|
+
.to raise_error(TypeError)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".from_native" do
|
20
|
+
it "returns an empty string if given a null pointer" do
|
21
|
+
value = Spotify::NULString.from_native(FFI::Pointer::NULL, nil)
|
22
|
+
value.should be_nil
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns the string value of the string pointer" do
|
26
|
+
pointer = FFI::MemoryPointer.from_string("hey")
|
27
|
+
value = Spotify::NULString.from_native(pointer, nil)
|
28
|
+
value.should eq "hey"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|