mp3info 0.6.17

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/mp3info.gemspec ADDED
@@ -0,0 +1,17 @@
1
+ # encoding: UTF-8
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'mp3info'
5
+ s.version = '0.6.17'
6
+ s.summary = %q{Read low-level informations and manipulate tags on mp3 files.}
7
+ s.homepage = "http://github.com/toy/#{s.name}"
8
+ s.authors = ['Guillaume Pierronnet', 'Ivan Kuchin']
9
+ s.license = 'ruby'
10
+
11
+ s.rubyforge_project = s.name
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = %w[lib]
17
+ end
data/test/fixtures.yml ADDED
@@ -0,0 +1,86 @@
1
+ empty_mp3: !binary |
2
+ eJz7/3tCCgP/BwaGTAYGBg4GBl4FBgZGIFoC5AKZJg0MDCw+jr6uxnqW5qEj
3
+ EAy43///npSyrx9/BA2Y4wYDGBQx9H80hnCD0Rga7GA0hkYBAQAA8NuaUA==
4
+ 2_2_tagged: !binary |
5
+ eNrtlrlOw0AQhn8QZ4E4CioK90jO2k58dGxs5xBxYiWbgiqKiAUWSmLZBFEi
6
+ XgDEM/AcPBN9imDHOBEIEB1H9tMW/8zO7szqb7ZqKcuI2T1gTAbWUR1chkMw
7
+ VwL2UQ69fiTQi67QGgVe2PdPkz1aAzZB/VBwutdgzWNgDVJO0uJjFFhNNNiJ
8
+ naRlQlQwswFsoeIHQmUY5JrdAGbDAXbgDc58Nhq4ZeqCAMyuA3tIUl4kXGki
9
+ EWVRUtPq86y63mg6EEiKlQnysZBmmdJ8y6ZToduKNK1R84oxE2m326xby3GL
10
+ eHe3LL0Kw5h3I6SgFaj6pr38nRE/EekcR9kcXtQxLavYqVoRJO1QpqZVMqgt
11
+ 23aeqKqu5PXkRfNhdEUr6LIGDofD4XD+KpPxfQ/bz4AfBxvxX0IAluL1GIex
12
+ zN8AKzXq2IpoaO0F5MffPhk/9J7uvjaovcj8Cocm3CHuEHeIO/RveQFv4P/e
13
+ vbr: !binary |
14
+ eNrt0F1k1XEYB/DnWHI0x0kiTTIzZqyRTS8jlV4kHSMdLdJFjuaQKYmMlCUm
15
+ siSbSBcZqbGNGYnpIimzRBKJLpKYmJFIU6f/uegyZ1f/yOfr4fc8PHwev8rS
16
+ jVLUSE+5rzd58hENuVg1PB91K7P1ufyatevWb9jY1NzS2ta+uWPLtq4dO/fs
17
+ P3Cw0H34yNFjx0+cLPWWT/edPXf+Qv/FS1euDl67PnTz1sjtO3fvjd5/MDY+
18
+ OTX96PHMk6fPXsy+fPX6zdt37z98/PR5/svC4tdv33/8TLyuQ7sL+zrat29t
19
+ rJuonrHpV0TnmebsrkJk5qp3DGTGn8f/nsrS6lLkFyPKyZCNyDVGZJIaTcak
20
+ 7bwcseLPRxX/lpoLxWLVaarhFGtlmc7elJxTKTmDKTkPU3LmUnIWUnIqQxwO
21
+ h8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8Ph
22
+ cDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgc
23
+ DofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD
24
+ 4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4
25
+ HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6H
26
+ w+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+Fw
27
+ OBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwO
28
+ h8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8Ph
29
+ cDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgc
30
+ DofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD
31
+ 4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4
32
+ HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6H
33
+ w+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+Fw
34
+ OBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwO
35
+ h8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8Ph
36
+ cDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgc
37
+ DofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD
38
+ 4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4
39
+ HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6H
40
+ w+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+Fw
41
+ OBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwO
42
+ h8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8Ph
43
+ cDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgc
44
+ DofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD
45
+ 4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4
46
+ HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6H
47
+ w+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+Fw
48
+ OBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwO
49
+ h8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8Ph
50
+ cDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgc
51
+ DofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD
52
+ 4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4
53
+ HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6H
54
+ w+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+Fw
55
+ OBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwO
56
+ h8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8Ph
57
+ cDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgc
58
+ DofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD
59
+ 4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4
60
+ HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6H
61
+ w+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+Fw
62
+ OBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwO
63
+ h8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8Ph
64
+ cDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgc
65
+ DofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD
66
+ 4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4
67
+ HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6H
68
+ w+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+Fw
69
+ OBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwO
70
+ h8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8Ph
71
+ cDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgc
72
+ DofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD4XA4HA6Hw+FwOBwOh8PhcDgcDofD
73
+ 4XA4HM4/dJYRDidN5zc6LQlL
74
+ audio_content_fixture: !binary |
75
+ SUQzAwAAAAABDFRBTEIAAAAnAAAB//5SAG8AZAByAGkAZwBvACAAeQAgAEcA
76
+ YQBiAHIAaQBlAGwAYQBUUkNLAAAABQAAAf/+MQBUSVQyAAAAEQAAAf/+VABh
77
+ AG0AYQBjAHUAbgBUUEUxAAAAJwAAAf/+UgBvAGQAcgBpAGcAbwAgAHkAIABH
78
+ AGEAYgByAGkAZQBsAGEA//uQZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
79
+ AAAAAAAAWGluZwAAAA8AAB7IAFw7mAADBQgKDQ8SFBcZHB4gIyUoKi4wMzU4
80
+ Oj1AQkVIS01QUlVYW11gYmRoam1vcnR3en1/gYSGiYuOkZSWmZueoKKmqKut
81
+ sLO2uLu9wMLFyMrNz9LU2Nrd3+Pl5+rs7/H19/r8//8AAABOTEFNRTMuOTAu
82
+ A74AAAAAAAAAADSAJAV8TQAAAABcO5gcQelNAAAAAAAAAAAAAAAAAAAAAAAA
83
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
84
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
85
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
86
+ AAAAAAAAAAAAAAAAAAAAAAA=
@@ -0,0 +1,572 @@
1
+ #!/usr/bin/env ruby1.9
2
+ # coding:utf-8
3
+
4
+ $:.unshift("lib/")
5
+
6
+ require "test/unit"
7
+ require "mp3info"
8
+ require "fileutils"
9
+ require "tempfile"
10
+ require "zlib"
11
+ require "yaml"
12
+
13
+ system("which id3v2 > /dev/null") || raise("id3v2 not found")
14
+
15
+ class Mp3InfoTest < Test::Unit::TestCase
16
+
17
+ TEMP_FILE = File.join(File.dirname(__FILE__), "test_mp3info.mp3")
18
+
19
+ DUMMY_TAG2 = {
20
+ "COMM" => "comments",
21
+ #"TCON" => "genre_s"
22
+ "TIT2" => "title",
23
+ "TPE1" => "artist",
24
+ "TALB" => "album",
25
+ "TYER" => "year",
26
+ "TRCK" => "tracknum"
27
+ }
28
+
29
+ DUMMY_TAG1 = {
30
+ "title" => "toto",
31
+ "artist" => "artist 123",
32
+ "album" => "ALBUMM",
33
+ "year" => 1934,
34
+ "tracknum" => 14,
35
+ "comments" => "comment me",
36
+ "genre" => 233
37
+ }
38
+
39
+ FIXTURES = YAML::load_file( File.join(File.dirname(__FILE__), "fixtures.yml") )
40
+
41
+ def setup
42
+ # Command to create a gzip'ed dummy MP3
43
+ # $ dd if=/dev/zero bs=1024 count=15 | \
44
+ # lame --quiet --preset cbr 128 -r -s 44.1 --bitwidth 16 - - | \
45
+ # ruby -rbase64 -rzlib -ryaml -e 'print(Zlib::Deflate.deflate($stdin.read)'
46
+ # vbr:
47
+ # $ dd if=/dev/zero of=#{tempfile.path} bs=1024 count=30000 |
48
+ # system("lame -h -v -b 112 -r -s 44.1 --bitwidth 16 - /tmp/vbr.mp3
49
+ @valid_mp3, @valid_mp3_2_2, @vbr_mp3 = %w{empty_mp3 2_2_tagged vbr}.collect do |fixture_key|
50
+ Zlib::Inflate.inflate(FIXTURES[fixture_key])
51
+ end
52
+
53
+ @tag = {
54
+ "title" => "title",
55
+ "artist" => "artist",
56
+ "album" => "album",
57
+ "year" => 1921,
58
+ "comments" => "comments",
59
+ "genre" => 0,
60
+ "genre_s" => "Blues",
61
+ "tracknum" => 36
62
+ }
63
+ File.open(TEMP_FILE, "w") { |f| f.write(@valid_mp3) }
64
+ end
65
+
66
+ def teardown
67
+ FileUtils.rm_f(TEMP_FILE)
68
+ end
69
+
70
+ def test_to_s
71
+ Mp3Info.open(TEMP_FILE) { |info| assert(info.to_s.is_a?(String)) }
72
+ end
73
+
74
+ def test_not_an_mp3
75
+ File.open(TEMP_FILE, "w") do |f|
76
+ str = "0"*1024*1024
77
+ f.write(str)
78
+ end
79
+ assert_raises(Mp3InfoError) do
80
+ mp3 = Mp3Info.new(TEMP_FILE)
81
+ end
82
+ end
83
+
84
+ def test_is_an_mp3
85
+ assert_nothing_raised do
86
+ Mp3Info.new(TEMP_FILE).close
87
+ end
88
+ end
89
+
90
+ def test_detected_info
91
+ Mp3Info.open(TEMP_FILE) do |mp3|
92
+ assert_mp3_info_are_ok(mp3)
93
+ end
94
+ end
95
+
96
+ def test_vbr_mp3_length
97
+ File.open(TEMP_FILE, "w") { |f| f.write(@vbr_mp3) }
98
+
99
+ Mp3Info.open(TEMP_FILE) do |info|
100
+ assert(info.vbr)
101
+ assert_in_delta(174.210612, info.length, 0.000001)
102
+ end
103
+ end
104
+
105
+ def test_removetag1
106
+ Mp3Info.open(TEMP_FILE) { |info| info.tag1 = @tag }
107
+ assert(Mp3Info.hastag1?(TEMP_FILE))
108
+ Mp3Info.removetag1(TEMP_FILE)
109
+ assert(! Mp3Info.hastag1?(TEMP_FILE))
110
+ end
111
+
112
+ def test_writetag1
113
+ Mp3Info.open(TEMP_FILE) { |info| info.tag1 = @tag }
114
+ Mp3Info.open(TEMP_FILE) { |info| assert_equal(info.tag1, @tag) }
115
+ end
116
+
117
+ def test_valid_tag1_1
118
+ tag = [ "title", "artist", "album", "1921", "comments", 36, 0].pack('A30A30A30A4a29CC')
119
+ valid_tag = {
120
+ "title" => "title",
121
+ "artist" => "artist",
122
+ "album" => "album",
123
+ "year" => 1921,
124
+ "comments" => "comments",
125
+ "genre" => "Blues",
126
+ #"version" => "1",
127
+ "tracknum" => 36
128
+ }
129
+ id3_test(tag, valid_tag)
130
+ end
131
+
132
+ def test_valid_tag1_0
133
+ tag = [ "title", "artist", "album", "1921", "comments", 0].pack('A30A30A30A4A30C')
134
+ valid_tag = {
135
+ "title" => "title",
136
+ "artist" => "artist",
137
+ "album" => "album",
138
+ "year" => 1921,
139
+ "comments" => "comments",
140
+ "genre" => "Blues",
141
+ #"version" => "0"
142
+ }
143
+ id3_test(tag, valid_tag)
144
+ end
145
+
146
+ def id3_test(tag_str, valid_tag)
147
+ tag = "TAG" + tag_str
148
+ File.open(TEMP_FILE, "w") do |f|
149
+ f.write(@valid_mp3)
150
+ f.write(tag)
151
+ end
152
+ assert(Mp3Info.hastag1?(TEMP_FILE))
153
+ #info = Mp3Info.new(TEMP_FILE)
154
+ #FIXME validate this test
155
+ #assert_equal(info.tag1, valid_tag)
156
+ end
157
+
158
+ def test_removetag2
159
+ w = write_tag2_to_temp_file({"TIT2" => "sdfqdsf"})
160
+
161
+ assert( Mp3Info.hastag2?(TEMP_FILE) )
162
+ Mp3Info.removetag2(TEMP_FILE)
163
+ assert( ! Mp3Info.hastag2?(TEMP_FILE) )
164
+ end
165
+
166
+ def test_hastags
167
+ Mp3Info.open(TEMP_FILE) do |info|
168
+ info.tag1 = @tag
169
+ end
170
+ assert(Mp3Info.hastag1?(TEMP_FILE))
171
+
172
+ written_tag = write_tag2_to_temp_file(DUMMY_TAG2)
173
+ assert(Mp3Info.hastag2?(TEMP_FILE))
174
+ end
175
+
176
+ def test_universal_tag
177
+ 2.times do
178
+ tag = {"title" => "title"}
179
+ Mp3Info.open(TEMP_FILE) do |mp3|
180
+ tag.each { |k,v| mp3.tag[k] = v }
181
+ end
182
+ w = Mp3Info.open(TEMP_FILE) { |m| m.tag }
183
+ assert_equal(tag, w)
184
+ end
185
+ end
186
+
187
+ def test_id3v2_universal_tag
188
+ tag = {}
189
+ %w{comments title artist album}.each { |k| tag[k] = k }
190
+ tag["tracknum"] = 34
191
+ Mp3Info.open(TEMP_FILE) do |mp3|
192
+ tag.each { |k,v| mp3.tag[k] = v }
193
+ end
194
+ w = Mp3Info.open(TEMP_FILE) { |m| m.tag }
195
+ w.delete("genre")
196
+ w.delete("genre_s")
197
+ assert_equal(tag, w)
198
+ # id3v2_prog_test(tag, w)
199
+ end
200
+
201
+ def test_id3v2_version
202
+ written_tag = write_tag2_to_temp_file(DUMMY_TAG2)
203
+ assert_equal( "2.#{ID3v2::WRITE_VERSION}.0", written_tag.version )
204
+ end
205
+
206
+ def test_id3v2_methods
207
+ tag = { "TIT2" => "tit2", "TPE1" => "tpe1" }
208
+ Mp3Info.open(TEMP_FILE) do |mp3|
209
+ tag.each do |k, v|
210
+ mp3.tag2.send("#{k}=".to_sym, v)
211
+ end
212
+ assert_equal(tag, mp3.tag2)
213
+ end
214
+ end
215
+
216
+ def test_id3v2_basic
217
+ w = write_tag2_to_temp_file(DUMMY_TAG2)
218
+ assert_equal(DUMMY_TAG2, w)
219
+ id3v2_prog_test(DUMMY_TAG2, w)
220
+ end
221
+
222
+ #test the tag with the "id3v2" program
223
+ def id3v2_prog_test(tag, written_tag)
224
+ return if RUBY_PLATFORM =~ /win32/
225
+ return if `which id3v2`.empty?
226
+ start = false
227
+ id3v2_output = {}
228
+ `id3v2 -l #{TEMP_FILE}`.split(/\n/).each do |line|
229
+ if m = /^(.{4}) \(.+\): (.+)$/.match(line)
230
+ k, v = m[1, 2]
231
+ case k
232
+ when "COMM"
233
+ v.sub!(/\(\)\[.{3}\]: (.+)/, '\1')
234
+ end
235
+ id3v2_output[k] = v
236
+ end
237
+ end
238
+
239
+ assert_equal( id3v2_output, written_tag, "id3v2 program output doesn't match")
240
+ end
241
+
242
+ def test_id3v2_trash
243
+ end
244
+
245
+ def test_id3v2_complex
246
+ tag = {}
247
+ #ID3v2::TAGS.keys.each do |k|
248
+ ["PRIV", "APIC"].each do |k|
249
+ tag[k] = random_string(50)
250
+ end
251
+
252
+ got_tag = write_tag2_to_temp_file(tag)
253
+ assert_equal(tag, got_tag)
254
+ end
255
+
256
+ def test_id3v2_bigtag
257
+ tag = {"APIC" => random_string(1024) }
258
+ assert_equal(tag, write_tag2_to_temp_file(tag))
259
+ end
260
+
261
+ def test_infinite_loop_on_seek_to_v2_end
262
+
263
+ end
264
+
265
+ def test_leading_char_gets_chopped
266
+ tag2 = DUMMY_TAG2.dup
267
+ tag2["WOAR"] = "http://foo.bar"
268
+ w = write_tag2_to_temp_file(tag2)
269
+ assert_equal("http://foo.bar", w["WOAR"])
270
+
271
+ system(%(id3v2 --WOAR "http://foo.bar" "#{TEMP_FILE}"))
272
+
273
+ Mp3Info.open(TEMP_FILE) do |mp3|
274
+ assert_equal "http://foo.bar", mp3.tag2["WOAR"]
275
+ end
276
+ end
277
+
278
+ def test_reading2_2_tags
279
+ File.open(TEMP_FILE, "w") { |f| f.write(@valid_mp3_2_2) }
280
+
281
+ Mp3Info.open(TEMP_FILE) do |mp3|
282
+ assert_equal "2.2.0", mp3.tag2.version
283
+ expected_tag = {
284
+ "TCO" => "Hip Hop/Rap",
285
+ "TP1" => "Grems Aka Supermicro",
286
+ "TT2" => "Intro",
287
+ "TAL" => "Air Max",
288
+ "TEN" => "iTunes v7.0.2.16",
289
+ "TYE" => "2006",
290
+ "TRK" => "1/17",
291
+ "TPA" => "1/1" }
292
+ tag = mp3.tag2.dup
293
+ assert_equal 4, tag["COM"].size
294
+ tag.delete("COM")
295
+ assert_equal expected_tag, tag
296
+
297
+ expected_tag = {
298
+ "genre_s" => "Hip Hop/Rap",
299
+ "title" => "Intro",
300
+ #"comments" => "\000engiTunPGAP\0000\000\000",
301
+ "comments" => "0",
302
+ "year" => 2006,
303
+ "album" => "Air Max",
304
+ "artist" => "Grems Aka Supermicro",
305
+ "tracknum" => 1 }
306
+ # test universal tag
307
+ assert_equal expected_tag, mp3.tag
308
+ end
309
+ end
310
+
311
+ def test_writing_universal_tag_from_2_2_tags
312
+ File.open(TEMP_FILE, "w") { |f| f.write(@valid_mp3_2_2) }
313
+ Mp3Info.open(TEMP_FILE) do |mp3|
314
+ mp3.tag.artist = "toto"
315
+ mp3.tag.comments = "comments"
316
+ mp3.flush
317
+ expected_tag = {
318
+ "artist" => "toto",
319
+ "genre_s" => "Hip Hop/Rap",
320
+ "title" => "Intro",
321
+ "comments" => "comments",
322
+ "year" => 2006,
323
+ "album" => "Air Max",
324
+ "tracknum" => 1}
325
+
326
+ assert_equal expected_tag, mp3.tag
327
+ end
328
+ end
329
+
330
+ def test_remove_tag
331
+ Mp3Info.open(TEMP_FILE) do |mp3|
332
+ tag = mp3.tag
333
+ tag.title = "title"
334
+ tag.artist = "artist"
335
+ mp3.close
336
+ mp3.reload
337
+ assert !mp3.tag1.empty?, "tag is empty"
338
+ mp3.removetag1
339
+ mp3.flush
340
+ assert mp3.tag1.empty?, "tag is not empty"
341
+ end
342
+ end
343
+
344
+ def test_good_parsing_of_a_pathname
345
+ fn = "Freak On `(Stone´s Club Mix).mp3"
346
+ FileUtils.cp(TEMP_FILE, fn)
347
+ begin
348
+ Mp3Info.open(fn) do |mp3|
349
+ mp3.tag.title = fn
350
+ mp3.flush
351
+ if RUBY_VERSION < "1.9.0"
352
+ assert_equal fn, mp3.tag.title
353
+ else
354
+ assert_equal fn, mp3.tag.title.force_encoding("utf-8")
355
+ end
356
+ end
357
+ ensure
358
+ File.delete(fn)
359
+ end
360
+ end
361
+
362
+ def test_validity_of_id3v2_options
363
+ info = Mp3Info.new(TEMP_FILE)
364
+ expected_hash = { :lang => "ENG", :encoding => "iso-8859-1" }
365
+ assert_equal( expected_hash, info.tag2.options)
366
+
367
+ assert_raises(ArgumentError) do
368
+ Mp3Info.new(TEMP_FILE, :encoding => "bad encoding")
369
+ end
370
+ end
371
+
372
+ def test_encoding_read
373
+ Mp3Info.open(TEMP_FILE) do |mp3|
374
+ mp3.tag2['TEST'] = "all\xe9"
375
+ end
376
+
377
+ Mp3Info.open(TEMP_FILE, :encoding => "utf-8") do |mp3|
378
+ assert_equal "allé", mp3.tag2['TEST']
379
+ end
380
+
381
+ Mp3Info.open(TEMP_FILE, :encoding => "iso-8859-1") do |mp3|
382
+ if RUBY_VERSION < "1.9.0"
383
+ assert_equal "all\xe9", mp3.tag2['TEST']
384
+ else
385
+ assert_equal "all\xe9".force_encoding("binary"), mp3.tag2['TEST']
386
+ end
387
+ end
388
+ end
389
+
390
+ def test_encoding_write
391
+ Mp3Info.open(TEMP_FILE, :encoding => 'utf-8') do |mp3|
392
+ mp3.tag2['TEST'] = "all\xc3\xa9"
393
+ end
394
+
395
+ Mp3Info.open(TEMP_FILE, :encoding => "iso-8859-1") do |mp3|
396
+ if RUBY_VERSION < "1.9.0"
397
+ assert_equal "all\xe9", mp3.tag2['TEST']
398
+ else
399
+ assert_equal "all\xe9".force_encoding("iso-8859-1"), mp3.tag2['TEST']
400
+ end
401
+ end
402
+ end
403
+
404
+ =begin
405
+ def test_should_raises_exception_when_writing_badly_encoded_frames
406
+ assert_raises(Iconv::Failure) do
407
+ Mp3Info.open(TEMP_FILE, :encoding => 'utf-8') do |mp3|
408
+ mp3.tag2['TEST'] = "all\xc3"
409
+ end
410
+ end
411
+ end
412
+ =end
413
+
414
+ def test_audio_content
415
+ require "digest/md5"
416
+
417
+ expected_digest = nil
418
+ Mp3Info.open(TEMP_FILE) do |mp3|
419
+ mp3.tag1.update(DUMMY_TAG1)
420
+ mp3.tag2.update(DUMMY_TAG2)
421
+ mp3.flush
422
+ assert mp3.hastag1?
423
+ assert mp3.hastag2?
424
+ assert mp3.tag2.io_position != 0
425
+ expected_digest = compute_audio_content_mp3_digest(mp3)
426
+ end
427
+
428
+ Mp3Info.open(TEMP_FILE) do |mp3|
429
+ mp3.removetag1
430
+ mp3.removetag2
431
+ mp3.flush
432
+ assert !mp3.hastag1?
433
+ assert !mp3.hastag2?
434
+ got_digest = compute_audio_content_mp3_digest(mp3)
435
+ assert_equal expected_digest, got_digest
436
+ end
437
+ end
438
+
439
+ def test_audio_content_problematic
440
+ File.open(TEMP_FILE, "w") { |f| f.write(FIXTURES["audio_content_fixture"]) }
441
+ Mp3Info.open(TEMP_FILE) do |mp3|
442
+ expected_pos = 150
443
+ audio_content_pos, audio_content_size = mp3.audio_content
444
+ assert_equal expected_pos, audio_content_pos
445
+ assert_equal File.size(TEMP_FILE) - expected_pos, audio_content_size
446
+ end
447
+ end
448
+
449
+ def test_headerless_vbr_file
450
+ mp3_length = 3
451
+ # this will generate a 15 sec mp3 file (44100hz*16bit*2channels) = 60/4 = 15
452
+ system("dd if=/dev/urandom bs=44100 count=#{mp3_length*4} 2>/dev/null | \
453
+ lame -v -m s --vbr-new --preset 128 -r -s 44.1 --bitwidth 16 - - > #{TEMP_FILE} 2>/dev/null")
454
+
455
+ Mp3Info.open(TEMP_FILE) do |mp3|
456
+ assert mp3.vbr
457
+ assert_in_delta(mp3_length, mp3.length, 0.1)
458
+ assert_in_delta(128, mp3.bitrate, 8)
459
+ end
460
+ end
461
+
462
+ def test_parse_tags_disabled
463
+ write_tag2_to_temp_file(DUMMY_TAG2)
464
+ Mp3Info.open(TEMP_FILE, :parse_tags => false) do |mp3|
465
+ assert mp3.tag.empty?
466
+ assert mp3.tag1.empty?
467
+ assert mp3.tag2.empty?
468
+ mp3.tag["artist"] = "some dummy tag"
469
+ mp3.tag2["TIT2"] = "title 2"
470
+ mp3.flush
471
+ # tag should not be written
472
+ assert mp3.tag.empty?
473
+ assert mp3.tag1.empty?
474
+ assert mp3.tag2.empty?
475
+ end
476
+ end
477
+
478
+ def test_string_io
479
+ io = load_string_io
480
+ Mp3Info.open(io) do |mp3|
481
+ assert_mp3_info_are_ok(mp3)
482
+ end
483
+ end
484
+
485
+ def test_trying_to_rename_a_stringio_should_raise_an_error
486
+ io = load_string_io
487
+ Mp3Info.open(io) do |mp3|
488
+ assert_raises(Mp3InfoError) do
489
+ mp3.rename("whatever_filename_is_error_should_be_raised.mp3")
490
+ end
491
+ end
492
+ end
493
+
494
+ def test_hastag_class_methods_with_a_stringio
495
+ Mp3Info.open(TEMP_FILE) do |info|
496
+ info.tag1 = @tag
497
+ end
498
+ io = load_string_io
499
+ assert(Mp3Info.hastag1?(io))
500
+
501
+ written_tag = write_tag2_to_temp_file(DUMMY_TAG2)
502
+ io = load_string_io
503
+ assert(Mp3Info.hastag2?(io))
504
+ end
505
+
506
+ def compute_audio_content_mp3_digest(mp3)
507
+ pos, size = mp3.audio_content
508
+ data = File.open(mp3.filename) do |f|
509
+ f.seek(pos, IO::SEEK_SET)
510
+ f.read(size)
511
+ end
512
+ Digest::MD5.new.update(data).hexdigest
513
+ end
514
+
515
+ def write_tag2_to_temp_file(tag)
516
+ Mp3Info.open(TEMP_FILE) do |mp3|
517
+ mp3.tag2.update(tag)
518
+ end
519
+ return Mp3Info.open(TEMP_FILE) { |m| m.tag2 }
520
+ #system("cp -v #{TEMP_FILE} #{TEMP_FILE}.test")
521
+ end
522
+
523
+ def random_string(size)
524
+ out = ""
525
+ size.times { out << rand(256).chr }
526
+ out
527
+ end
528
+
529
+ def assert_mp3_info_are_ok(mp3)
530
+ assert_equal(1, mp3.mpeg_version)
531
+ assert_equal(3, mp3.layer)
532
+ assert_equal(false, mp3.vbr)
533
+ assert_equal(128, mp3.bitrate)
534
+ assert_equal("JStereo", mp3.channel_mode)
535
+ assert_equal(44100, mp3.samplerate)
536
+ assert_equal(0.1305625, mp3.length)
537
+ assert_equal({:original => true,
538
+ :error_protection => false,
539
+ :padding => false,
540
+ :emphasis => 0,
541
+ :private => true,
542
+ :mode_extension => 2,
543
+ :copyright => false}, mp3.header)
544
+ end
545
+
546
+ def load_string_io(filename = TEMP_FILE)
547
+ io = StringIO.new
548
+ data = File.read(filename)
549
+ io.write(data)
550
+ io.rewind
551
+ io
552
+ end
553
+
554
+ =begin
555
+
556
+ def test_encoder
557
+ write_to_temp
558
+ info = Mp3Info.new(TEMP_FILE)
559
+ assert(info.encoder == "Lame 3.93")
560
+ end
561
+
562
+ def test_vbr
563
+ mp3_vbr = Base64.decode64 <<EOF
564
+
565
+ EOF
566
+ File.open(TEMP_FILE, "w") { |f| f.write(mp3_vbr) }
567
+ info = Mp3Info.new(TEMP_FILE)
568
+ assert_equal(info.vbr, true)
569
+ assert_equal(info.bitrate, 128)
570
+ end
571
+ =end
572
+ end