mr_eko 0.2.4.1 → 0.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/Gemfile +1 -2
- data/README.md +2 -2
- data/Rakefile +2 -2
- data/TODO +1 -0
- data/bin/mreko +23 -17
- data/ext/enmfp/README +23 -11
- data/ext/enmfp/RELEASE_NOTES +3 -3
- data/ext/enmfp/codegen.Darwin +0 -0
- data/ext/enmfp/codegen.Linux-i686 +0 -0
- data/ext/enmfp/codegen.Linux-x86_64 +0 -0
- data/ext/enmfp/codegen.windows.exe +0 -0
- data/ext/enmfp/old/codegen.Darwin +0 -0
- data/ext/enmfp/old/codegen.Linux-i686 +0 -0
- data/ext/enmfp/old/codegen.Linux-x86_64 +0 -0
- data/ext/enmfp/old/codegen.windows.exe +0 -0
- data/lib/mr_eko/ext/numeric.rb +11 -0
- data/lib/mr_eko/ext/object.rb +5 -0
- data/lib/mr_eko/playlist.rb +57 -31
- data/lib/mr_eko/presets.rb +4 -4
- data/lib/mr_eko/song.rb +181 -85
- data/lib/mr_eko/timed_playlist.rb +149 -0
- data/lib/mr_eko.rb +40 -5
- data/mr_eko.gemspec +16 -4
- data/test/mr_eko_test.rb +40 -11
- data/test/playlist_test.rb +85 -78
- data/test/song_test.rb +158 -0
- data/test/test.rb +36 -2
- data/test/timed_playlist_test.rb +130 -0
- metadata +71 -24
data/test/playlist_test.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
class PlaylistTest < Test::Unit::TestCase
|
2
|
-
|
1
|
+
class PlaylistTest < Test::Unit::TestCase
|
2
|
+
|
3
3
|
context "a new playlist" do
|
4
4
|
setup do
|
5
5
|
@playlist = MrEko::Playlist.new
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
should "have no songs" do
|
9
9
|
assert_equal 0, @playlist.songs.size
|
10
10
|
end
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
context "create_from_options" do
|
14
|
-
|
14
|
+
|
15
15
|
setup do
|
16
16
|
@options = {:tempo => 100..200}
|
17
17
|
MrEko::Song.delete
|
@@ -23,113 +23,120 @@ class PlaylistTest < Test::Unit::TestCase
|
|
23
23
|
assert_raise(MrEko::Playlist::NoSongsError){ MrEko::Playlist.create_from_options(@options) }
|
24
24
|
assert_equal @playlist_count, MrEko::Playlist.count
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
should "create a playlist when there are songs found" do
|
28
|
-
assert
|
29
|
-
|
30
|
-
:artist => 'Tool',
|
31
|
-
:title => 'Third Eye',
|
32
|
-
:md5 => Digest::MD5.hexdigest(Time.now.to_s),
|
33
|
-
:created_on => Time.now,
|
34
|
-
:duration => 567
|
35
|
-
)
|
36
|
-
|
28
|
+
assert create_song(:tempo => @options[:tempo].max)
|
29
|
+
|
37
30
|
assert MrEko::Playlist.create_from_options(@options)
|
38
31
|
assert_equal @playlist_count + 1, MrEko::Playlist.count
|
39
32
|
end
|
40
|
-
|
33
|
+
|
41
34
|
should "filter out certain options before querying for songs" do
|
42
35
|
unfiltered_options = {:name => "Rock You in Your Face mix #{rand(1000)}", :time_signature => 4}
|
43
36
|
MrEko::Song.expects(:where).with(Not(has_key(:name))).once.returns(sequel_dataset_stub)
|
44
37
|
assert_raise(MrEko::Playlist::NoSongsError){ MrEko::Playlist.create_from_options(unfiltered_options) }
|
45
38
|
end
|
46
|
-
end
|
47
|
-
|
48
|
-
context
|
49
|
-
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'output' do
|
42
|
+
setup do
|
43
|
+
@playlist = MrEko::Playlist.create(:name => "Best Playlist#{rand(1000)}")
|
44
|
+
@song1 = create_song(:title => 'Song A')
|
45
|
+
@song2 = create_song(:title => 'Song B')
|
46
|
+
@playlist.songs << @song1
|
47
|
+
@playlist.songs << @song2
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'default format' do
|
51
|
+
|
52
|
+
should 'be PLS' do
|
53
|
+
assert @playlist.output.match /^\[playlist\]/
|
54
|
+
assert @playlist.output.match /NumberOfEntries/
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'text format' do
|
59
|
+
|
60
|
+
should 'contain a comma-sep list of the song name and file path' do
|
61
|
+
assert @playlist.output(:text).match /#{@song1.filename}\, #{@song1.title}/
|
62
|
+
assert @playlist.output(:text).match /#{@song2.filename}\, #{@song2.title}/
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "prepare_options" do
|
68
|
+
|
50
69
|
context "when passed a preset option" do
|
51
|
-
|
70
|
+
|
52
71
|
should "only use the presets' options, not the others passed" do
|
53
72
|
opts = { :time_signature => 4, :preset => :gym }
|
54
|
-
MrEko::Playlist.prepare_options
|
55
|
-
|
56
|
-
|
73
|
+
transformed = MrEko::Playlist.prepare_options(opts)
|
74
|
+
|
75
|
+
assert_nil transformed.detect{ |opt| opt.has_key?(:time_signature) }
|
76
|
+
assert_equal MrEko::Presets::FACTORY[:gym].detect{ |opt| opt.has_key?(:tempo) }[:tempo],
|
77
|
+
transformed.detect{ |opt| opt.has_key?(:tempo) }[:tempo]
|
57
78
|
end
|
58
79
|
end
|
59
|
-
|
60
|
-
context "
|
61
|
-
|
62
|
-
should "
|
63
|
-
|
64
|
-
|
65
|
-
assert_equal 160..180, opts[:tempo]
|
80
|
+
|
81
|
+
context "transformation" do
|
82
|
+
|
83
|
+
should "handle less-than sign" do
|
84
|
+
transformed = MrEko::Playlist.prepare_options({:duration => "<20"})
|
85
|
+
assert_equal "duration < 20".lit, transformed.last
|
66
86
|
end
|
67
|
-
|
68
|
-
should "
|
69
|
-
|
70
|
-
|
71
|
-
assert opts.has_key? :tempo
|
87
|
+
|
88
|
+
should "handle greater-than sign" do
|
89
|
+
transformed = MrEko::Playlist.prepare_options({:tempo => ">151"})
|
90
|
+
assert_equal "tempo > 151".lit, transformed.last
|
72
91
|
end
|
73
92
|
|
74
|
-
should "
|
75
|
-
|
76
|
-
|
77
|
-
assert !opts.has_key?(:min_tempo)
|
78
|
-
assert !opts.has_key?(:max_tempo)
|
93
|
+
should "handle basic assignment" do
|
94
|
+
transformed = MrEko::Playlist.prepare_options({:artist => "Radiohead"})
|
95
|
+
assert_equal( {:artist => "Radiohead"}, transformed.last )
|
79
96
|
end
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
97
|
+
|
98
|
+
context "percentage values" do
|
99
|
+
[:loudness, :energy, :danceability].each do |attribute|
|
100
|
+
should "translate #{attribute} into decimal form" do
|
101
|
+
transformed = MrEko::Playlist.prepare_options({attribute => 32})
|
102
|
+
assert_equal( {attribute => 0.32}, transformed.last )
|
103
|
+
end
|
104
|
+
end
|
85
105
|
end
|
86
106
|
end
|
87
|
-
|
88
|
-
context "
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
MrEko::Playlist.prepare_options!(opts)
|
93
|
-
assert_equal 200..2010, opts[:duration]
|
94
|
-
end
|
95
|
-
|
96
|
-
should "transform even when there aren't any passed duration opts" do
|
97
|
-
opts = {:time_signature => 4}
|
98
|
-
MrEko::Playlist.prepare_options!(opts)
|
99
|
-
assert opts.has_key? :duration
|
107
|
+
|
108
|
+
context "defaults" do
|
109
|
+
should "be overridable" do
|
110
|
+
transformed = MrEko::Playlist.prepare_options({:tempo => 180})
|
111
|
+
assert_equal 180, transformed.detect{ |opt| opt.has_key?(:tempo) }[:tempo]
|
100
112
|
end
|
101
113
|
|
102
|
-
should "
|
103
|
-
|
104
|
-
|
105
|
-
assert !opts.has_key?(:min_duration)
|
106
|
-
assert !opts.has_key?(:max_duration)
|
114
|
+
should "be set for tempo" do
|
115
|
+
transformed = MrEko::Playlist.prepare_options({})
|
116
|
+
assert_equal 0..500, transformed.detect{ |opt| opt.has_key?(:tempo) }[:tempo]
|
107
117
|
end
|
108
118
|
|
109
|
-
should "
|
110
|
-
|
111
|
-
|
112
|
-
assert_equal 100..2000, opts[:duration]
|
119
|
+
should "be set for duration" do
|
120
|
+
transformed = MrEko::Playlist.prepare_options({})
|
121
|
+
assert_equal 10..1200, transformed.detect{ |opt| opt.has_key?(:duration) }[:duration]
|
113
122
|
end
|
114
123
|
end
|
115
|
-
|
124
|
+
|
116
125
|
context "for mode" do
|
117
|
-
|
126
|
+
|
118
127
|
should "transform into numeric representation" do
|
119
|
-
|
120
|
-
|
121
|
-
assert_equal 0, opts[:mode]
|
128
|
+
transformed = MrEko::Playlist.prepare_options(:mode => 'minor')
|
129
|
+
assert_equal 0, transformed.detect{ |opt| opt.key?(:mode) }[:mode]
|
122
130
|
end
|
123
131
|
end
|
124
132
|
|
125
133
|
context "for key" do
|
126
|
-
|
134
|
+
|
127
135
|
should "transform into numeric representation" do
|
128
|
-
|
129
|
-
|
130
|
-
assert_equal 1, opts[:key]
|
136
|
+
transformed = MrEko::Playlist.prepare_options(:key => 'C#')
|
137
|
+
assert_equal 1, transformed.detect{ |opt| opt.key?(:key) }[:key]
|
131
138
|
end
|
132
139
|
end
|
133
140
|
|
134
141
|
end
|
135
|
-
end
|
142
|
+
end
|
data/test/song_test.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
class SongTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
TEST_MP3 = File.join(File.dirname(__FILE__), 'data', 'they_want_a_test.mp3')
|
4
|
+
TAGLESS_MP3 = File.join(File.dirname(__FILE__), 'data', 'tagless.mp3')
|
5
|
+
|
6
|
+
def enmfp_data_stub(overrides={})
|
7
|
+
opts = {
|
8
|
+
'code' => '98ouhajsnd081oi2he0da8sdoihjasdi2y9e8aASD3e8yaushdjQWD',
|
9
|
+
'tag' => 0,
|
10
|
+
'raw_data' => "[]", # JSON returned from EN
|
11
|
+
'metadata' => {
|
12
|
+
'artist' => 'SebastiAn',
|
13
|
+
'title' => 'Ross Ross Ross',
|
14
|
+
'release' => 'Total',
|
15
|
+
'genre' => 'Electronic',
|
16
|
+
'filename' => '/Users/you/Music/sebastian-ross_ross_ross.mp3',
|
17
|
+
'bitrate' => 320,
|
18
|
+
'sample_rate' => 44100,
|
19
|
+
'codegen_time' => 9.221,
|
20
|
+
'duration' => 219,
|
21
|
+
}
|
22
|
+
}.merge(overrides)
|
23
|
+
|
24
|
+
Hashie::Mash.new(opts)
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup
|
28
|
+
MrEko::Song.delete
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
context 'create_from_file!' do
|
33
|
+
|
34
|
+
should 'catalog from tags by default' do
|
35
|
+
MrEko::Song.expects(:catalog_via_tags).with(TEST_MP3, kind_of(Hash)).returns(MrEko::Song.new)
|
36
|
+
MrEko::Song.create_from_file!(TEST_MP3)
|
37
|
+
end
|
38
|
+
|
39
|
+
should 'try cataloging via ENMFP when tags dont work' do
|
40
|
+
MrEko::Song.expects(:catalog_via_tags).with(TEST_MP3, kind_of(Hash)).returns(nil)
|
41
|
+
MrEko::Song.expects(:catalog_via_enmfp).with(TEST_MP3, kind_of(Hash)).returns(MrEko::Song.new)
|
42
|
+
MrEko::Song.create_from_file!(TEST_MP3)
|
43
|
+
end
|
44
|
+
|
45
|
+
should 'not try cataloging if we have it stored already' do
|
46
|
+
md5 = MrEko.md5(TEST_MP3)
|
47
|
+
stub = MrEko::Song.new
|
48
|
+
|
49
|
+
MrEko::Song.expects(:where).with(:md5 => md5).returns( [stub] )
|
50
|
+
MrEko::Song.expects(:catalog_via_enmfp).never
|
51
|
+
MrEko::Song.expects(:catalog_via_tags).never
|
52
|
+
|
53
|
+
assert_equal stub, MrEko::Song.create_from_file!(TEST_MP3)
|
54
|
+
end
|
55
|
+
|
56
|
+
should 'not atempt to catalog via ENMFP if the tags_only option is passed in' do
|
57
|
+
MrEko::Song.expects(:catalog_via_tags).with(TEST_MP3, kind_of(Hash)).returns(nil)
|
58
|
+
MrEko::Song.expects(:catalog_via_enmfp).never
|
59
|
+
|
60
|
+
MrEko::Song.create_from_file!(TEST_MP3, :tags_only => true)
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
context 'catalog_via_enmfp' do
|
67
|
+
|
68
|
+
should 'raise an error if the ENMFP fingerprint contains errors' do
|
69
|
+
MrEko::Song.stubs(:enmfp_data).returns(enmfp_data_stub('error' => 'BOOM'))
|
70
|
+
assert_raise(MrEko::Song::EnmfpError){ MrEko::Song.catalog_via_enmfp(TEST_MP3) }
|
71
|
+
end
|
72
|
+
|
73
|
+
should 'try to upload when no songs are returned from the Song#identify call' do
|
74
|
+
stub_data = enmfp_data_stub
|
75
|
+
empty_profile_stub = stub(:songs => [])
|
76
|
+
id_opts = {
|
77
|
+
:code => stub_data.raw_data,
|
78
|
+
:artist => stub_data.metadata.artist,
|
79
|
+
:title => stub_data.metadata.title,
|
80
|
+
:release => stub_data.metadata.release,
|
81
|
+
:bucket => 'audio_summary'
|
82
|
+
}
|
83
|
+
MrEko::Song.stubs(:enmfp_data).returns(stub_data)
|
84
|
+
Echonest::ApiMethods::Song.any_instance.expects(:identify).with(id_opts).returns(empty_profile_stub)
|
85
|
+
MrEko::Song.expects(:get_datapoints_by_upload).returns([stub_everything, stub_everything(:id => 'whatever')])
|
86
|
+
MrEko::Song.catalog_via_enmfp(TEST_MP3)
|
87
|
+
end
|
88
|
+
|
89
|
+
should 'try to get the profile data when a song is returned from the Song#identify call' do
|
90
|
+
stub_data = enmfp_data_stub
|
91
|
+
profile_stub = stub(:songs => [stub_everything(:id => 'FJJ299KLOP')])
|
92
|
+
profile_details_stub = stub(:songs => [stub(:audio_summary => stub_everything)])
|
93
|
+
|
94
|
+
MrEko::Song.stubs(:enmfp_data).returns(stub_data)
|
95
|
+
Echonest::ApiMethods::Song.any_instance.expects(:identify).returns(profile_stub)
|
96
|
+
Echonest::ApiMethods::Song.any_instance.expects(:profile).with(:id => 'FJJ299KLOP', :bucket => 'audio_summary').returns(profile_details_stub)
|
97
|
+
MrEko::Song.expects(:get_datapoints_by_upload).never
|
98
|
+
|
99
|
+
|
100
|
+
assert_difference 'MrEko::Song.count' do
|
101
|
+
MrEko::Song.catalog_via_enmfp(TEST_MP3)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'catalog_via_tags' do
|
107
|
+
|
108
|
+
context 'for a mp3 with no useful tag information' do
|
109
|
+
|
110
|
+
setup do
|
111
|
+
@mp3 = MrEko::Song.parse_id3_tags(TAGLESS_MP3)
|
112
|
+
assert_nil @mp3.artist
|
113
|
+
assert_nil @mp3.title
|
114
|
+
end
|
115
|
+
|
116
|
+
should 'return nil' do
|
117
|
+
assert_nil MrEko::Song.catalog_via_tags(TAGLESS_MP3)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'for a mp3 with the required tag information' do
|
122
|
+
|
123
|
+
setup do
|
124
|
+
@mp3 = MrEko::Song.parse_id3_tags(TEST_MP3)
|
125
|
+
assert_not_nil @mp3.artist
|
126
|
+
assert_not_nil @mp3.title
|
127
|
+
end
|
128
|
+
|
129
|
+
should 'create a Song' do
|
130
|
+
songs_stub = [stub(:audio_summary => stub_everything, :artist => @mp3.artist, :title => @mp3.title, :id => 'xxx')]
|
131
|
+
Echonest::ApiMethods::Song.any_instance.expects(:search).returns(stub(:songs => songs_stub))
|
132
|
+
|
133
|
+
assert_difference 'MrEko::Song.count' do
|
134
|
+
MrEko::Song.catalog_via_tags(TEST_MP3)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'cleaning funky ID3 tags' do
|
141
|
+
|
142
|
+
should "decode iTunes' crazy tags" do
|
143
|
+
dm = Iconv.conv('UTF-16', 'LATIN1', 'Dead Meadow')
|
144
|
+
tag_stub = OpenStruct.new(:artist => dm, :title => 'Good Moaning')
|
145
|
+
ID3Lib::Tag.expects(:new).once.returns(tag_stub)
|
146
|
+
parsed_tags = MrEko::Song.parse_id3_tags(TEST_MP3)
|
147
|
+
|
148
|
+
assert_equal "Dead Meadow", parsed_tags.artist
|
149
|
+
end
|
150
|
+
|
151
|
+
should "not blow up when there isn't any crazy encoding" do
|
152
|
+
tag_stub = OpenStruct.new(:artist => 'Dead Meadow', :title => 'Good Moaning')
|
153
|
+
ID3Lib::Tag.expects(:new).once.returns(tag_stub)
|
154
|
+
|
155
|
+
assert_nothing_raised{ MrEko::Song.parse_id3_tags(TEST_MP3) }
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
data/test/test.rb
CHANGED
@@ -6,12 +6,17 @@ require 'test/unit'
|
|
6
6
|
require 'shoulda'
|
7
7
|
require 'mocha'
|
8
8
|
require "mr_eko"
|
9
|
+
require "ruby-debug"
|
9
10
|
|
10
11
|
require 'sequel/extensions/migration'
|
11
12
|
Sequel::Migrator.apply(MrEko.connection, File.join(File.dirname(__FILE__), "..", "db", "migrate"))
|
13
|
+
# Clear the tables out
|
14
|
+
(MrEko.connection.tables - [:schema_info]).each do |table|
|
15
|
+
MrEko.connection.run "DELETE FROM #{table}"
|
16
|
+
end
|
12
17
|
|
13
18
|
class Test::Unit::TestCase
|
14
|
-
|
19
|
+
|
15
20
|
# Could be fleshed out some more.
|
16
21
|
def sequel_dataset_stub
|
17
22
|
data = mock()
|
@@ -19,4 +24,33 @@ class Test::Unit::TestCase
|
|
19
24
|
data
|
20
25
|
end
|
21
26
|
|
22
|
-
|
27
|
+
def create_song(opts={})
|
28
|
+
defaults = {
|
29
|
+
:filename => 'third_eye.mp3',
|
30
|
+
:artist => 'Tool',
|
31
|
+
:title => 'Third Eye',
|
32
|
+
:md5 => Digest::MD5.hexdigest(Time.now.to_s + rand(10000000).to_s),
|
33
|
+
:created_on => Time.now,
|
34
|
+
:duration => 567,
|
35
|
+
:tempo => 143
|
36
|
+
}.merge(opts)
|
37
|
+
|
38
|
+
MrEko::Song.create(defaults)
|
39
|
+
end
|
40
|
+
|
41
|
+
def assert_difference(expression, difference = 1, message = nil, &block)
|
42
|
+
b = block.send(:binding)
|
43
|
+
exps = expression.is_a?(Array) ? expression : [expression]
|
44
|
+
before = exps.map { |e| eval(e, b) }
|
45
|
+
|
46
|
+
yield
|
47
|
+
|
48
|
+
exps.each_with_index do |e, i|
|
49
|
+
error = "#{e.inspect} didn't change by #{difference}"
|
50
|
+
error = "#{message}.\n#{error}" if message
|
51
|
+
assert_equal(before[i] + difference, eval(e, b), error)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
class TimedPlaylistTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
context 'a new TimedPlaylist' do
|
4
|
+
|
5
|
+
should 'accept a hash of options' do
|
6
|
+
assert MrEko::TimedPlaylist.new(:length => 600, :name => 'whatever')
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'set those options as expected' do
|
10
|
+
pl = MrEko::TimedPlaylist.new(:length => 600, :name => 'Awesome')
|
11
|
+
assert_equal 600, pl.length
|
12
|
+
assert_equal 'Awesome', pl.name
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'initial' do
|
18
|
+
|
19
|
+
should 'add the attribute to the list of initial attributes' do
|
20
|
+
MrEko::TimedPlaylist.new(:length => 600, :name => 'sad shit') do |pl|
|
21
|
+
assert pl.initial(:mode, :minor)
|
22
|
+
assert_equal :minor, pl.attributes[:initial][:mode]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'final' do
|
28
|
+
|
29
|
+
should 'add the attribute to the list of final attributes' do
|
30
|
+
MrEko::TimedPlaylist.new(:length => 200, :name => 'Rock') do |pl|
|
31
|
+
assert pl.final(:tempo, 120)
|
32
|
+
assert_equal 120, pl.attributes[:final][:tempo]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'static' do
|
38
|
+
|
39
|
+
should 'add the attribute to the list of static attributes' do
|
40
|
+
MrEko::TimedPlaylist.new(:length => 1000, :name => 'Bump') do |pl|
|
41
|
+
assert pl.static(:genre, 'HipHop')
|
42
|
+
assert_equal 'HipHop', pl.attributes[:static][:genre]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'save' do
|
48
|
+
|
49
|
+
should 'populate the step_map' do
|
50
|
+
list = MrEko::TimedPlaylist.new(:length => 360) do |pl|
|
51
|
+
pl.initial(:tempo, 100)
|
52
|
+
pl.final(:tempo, 106)
|
53
|
+
end
|
54
|
+
|
55
|
+
assert list.step_map.empty?
|
56
|
+
assert list.save
|
57
|
+
assert !list.step_map.empty?
|
58
|
+
end
|
59
|
+
|
60
|
+
should 'increase the step length to 4.minutes if value is less that that' do
|
61
|
+
list = MrEko::TimedPlaylist.new(:length => 300) do |pl|
|
62
|
+
pl.initial(:tempo, 60)
|
63
|
+
pl.final(:tempo, 80)
|
64
|
+
end
|
65
|
+
|
66
|
+
assert list.save
|
67
|
+
assert_equal [20, 240], list.step_map[:tempo]
|
68
|
+
end
|
69
|
+
|
70
|
+
should 'populate the step_map with the proper mode step data' do
|
71
|
+
list = MrEko::TimedPlaylist.new(:length => 3060) do |pl|
|
72
|
+
pl.initial(:mode, :major)
|
73
|
+
pl.final(:mode, :minor)
|
74
|
+
end
|
75
|
+
|
76
|
+
assert list.save
|
77
|
+
assert_equal [2, 3060.to_f/2], list.step_map[:mode]
|
78
|
+
end
|
79
|
+
|
80
|
+
should 'populate the step_map with the proper tempo and loudness step data' do
|
81
|
+
list = MrEko::TimedPlaylist.new(:length => 3600) do |pl|
|
82
|
+
pl.initial(:tempo, 60)
|
83
|
+
pl.final(:tempo, 70)
|
84
|
+
|
85
|
+
pl.initial(:loudness, -13)
|
86
|
+
pl.final(:loudness, -9)
|
87
|
+
end
|
88
|
+
|
89
|
+
assert list.save
|
90
|
+
assert_equal [10, 3600.to_f/10], list.step_map[:tempo]
|
91
|
+
assert_equal [4, 3600.to_f/4], list.step_map[:loudness]
|
92
|
+
end
|
93
|
+
|
94
|
+
should 'populate the step_map with the proper energy and danceability fractional step data' do
|
95
|
+
list = MrEko::TimedPlaylist.new(:length => 3600) do |pl|
|
96
|
+
pl.initial(:energy, 0.622)
|
97
|
+
pl.final(:energy, 0.888)
|
98
|
+
|
99
|
+
pl.initial(:danceability, 0.22)
|
100
|
+
pl.final(:danceability, 0.88)
|
101
|
+
end
|
102
|
+
|
103
|
+
assert list.save
|
104
|
+
assert_equal [3, (3600.to_f/3).round], list.step_map[:energy]
|
105
|
+
assert_equal [7, (3600.to_f/7).round], list.step_map[:danceability]
|
106
|
+
end
|
107
|
+
|
108
|
+
should 'populate the step_map with the proper key step data' do
|
109
|
+
list = MrEko::TimedPlaylist.new(:length => 3060) do |pl|
|
110
|
+
pl.initial(:key, 'C#')
|
111
|
+
pl.final(:key, 'A#')
|
112
|
+
end
|
113
|
+
|
114
|
+
step = MrEko.key_lookup('A#') - MrEko.key_lookup('C#')
|
115
|
+
assert list.save
|
116
|
+
assert_equal [step, 3060.to_f/step], list.step_map[:key]
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
context 'validation' do
|
121
|
+
should "raise an exception when initial and final attribute keys don't match" do
|
122
|
+
pl = MrEko::TimedPlaylist.new(:length => 1000) do |pl|
|
123
|
+
assert pl.initial(:tempo, 66)
|
124
|
+
end
|
125
|
+
|
126
|
+
assert_raise(MrEko::TimedPlaylist::InvalidAttributes){ pl.save }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|