spotify 12.2.0 → 12.3.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/.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
|