mr_eko 0.2.4.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|