apetag 1.1.4 → 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/apetag.rb +65 -43
  3. data/test/test_apetag.rb +161 -12
  4. metadata +33 -57
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 36144161c33f413d750ae832dbec6ba9612a0001
4
+ data.tar.gz: b9831a6a7e4b30aa0796a2a8fa9f0a229cdf6ce0
5
+ SHA512:
6
+ metadata.gz: 45ed5df49bcd11636c6bf51d37c6eee643b283536850b2f91b3ef3459ba61cc162cf01f4da32252e36b86082ea654df292b4fc5043e5bf5b65da7d2bf5f04e07
7
+ data.tar.gz: 844c79409f01a86b9cf21becc3c62a5b643bb023314ea0c90ef08b8659f78f23cca193de5c84af87a5a0bc31297971411ed28e85086e15b40848e42460f35930
data/apetag.rb CHANGED
@@ -69,7 +69,9 @@ class ApeItem < Array
69
69
  return value
70
70
  end
71
71
  value = [value] unless value.is_a?(Array)
72
- new(key, value)
72
+ item = new(key, value)
73
+ item.valid?
74
+ item
73
75
  end
74
76
 
75
77
  # Parse an ApeItem from the given data string starting at the provided offset.
@@ -84,12 +86,10 @@ class ApeItem < Array
84
86
  raise ApeTagError, "Missing key-value separator at offset #{offset}" unless key_end
85
87
  raise ApeTagError, "Invalid item length at offset #{offset}" if (next_item_start=length + key_end + 1) > data.length
86
88
  begin
87
- item = ApeItem.new_from_parse(data[offset...key_end], data[(key_end+1)...next_item_start].split("\0"))
89
+ item = ApeItem.new_from_parse(data[offset...key_end], data[(key_end+1)...next_item_start].split("\0"), flags)
88
90
  rescue ArgumentError =>e
89
91
  raise ApeTagError, "ArgumentError: #{e.message}"
90
92
  end
91
- item.read_only = flags & 1 > 0
92
- item.ape_type = ITEM_TYPES[flags/2]
93
93
  return [item, next_item_start]
94
94
  end
95
95
 
@@ -101,7 +101,6 @@ class ApeItem < Array
101
101
  self.read_only = false
102
102
  self.ape_type = ITEM_TYPES[0]
103
103
  super(value)
104
- raise ApeTagError, "Invalid item value encoding (non UTF-8)" unless valid_value?
105
104
  end
106
105
 
107
106
  # Set ape_type if valid, otherwise raise ApeTagError.
@@ -162,14 +161,16 @@ class ApeItem < Array
162
161
  # Check if the string value is valid UTF-8.
163
162
  def valid_value?
164
163
  begin
165
- if RUBY_VERSION >= '1.9'
166
- begin
167
- map!{|v| v.to_s.encode('UTF-8')}
168
- rescue EncodingError
169
- return false
164
+ if ape_type == 'utf8' || ape_type == 'external'
165
+ if RUBY_VERSION >= '1.9'
166
+ begin
167
+ map!{|v| v.to_s.encode('UTF-8')}
168
+ rescue EncodingError
169
+ return false
170
+ end
170
171
  end
172
+ string_value.unpack('U*')
171
173
  end
172
- string_value.unpack('U*') if ape_type == 'utf8' || ape_type == 'external'
173
174
  rescue ArgumentError
174
175
  false
175
176
  else
@@ -177,11 +178,26 @@ class ApeItem < Array
177
178
  end
178
179
  end
179
180
 
180
- if RUBY_VERSION >= '1.9.0'
181
- def self.new_from_parse(key, value)
182
- new(key.force_encoding('US-ASCII'), value.map{|v| v.to_s.force_encoding('UTF-8')})
181
+ def self.new_from_parse(key, value, flags)
182
+ ape_type = flags/2
183
+ if RUBY_VERSION >= '1.9.0'
184
+ key.force_encoding('US-ASCII')
185
+ case ape_type
186
+ when 0, 2
187
+ value = value.map{|v| v.to_s.force_encoding('UTF-8')}
188
+ when 1
189
+ value = value.map{|v| v.to_s.force_encoding('BINARY')}
190
+ end
183
191
  end
192
+ value = [''] if value.empty?
193
+ item = new(key, value)
194
+ item.read_only = flags & 1 > 0
195
+ item.ape_type = ITEM_TYPES[ape_type]
196
+ raise ApeTagError, "Invalid item value encoding (non UTF-8)" unless item.valid_value?
197
+ item
198
+ end
184
199
 
200
+ if RUBY_VERSION >= '1.9.0'
185
201
  def encoded_key(key)
186
202
  begin
187
203
  key.encode('US-ASCII')
@@ -191,14 +207,12 @@ class ApeItem < Array
191
207
  end
192
208
 
193
209
  def normalize_encodings
194
- map!{|v| v.to_s.encode('UTF-8')}
210
+ map!{|v| v.to_s.encode('UTF-8')} if ape_type == 'utf8' || ape_type == 'external'
195
211
  self
212
+ rescue Encoding::UndefinedConversionError => e
213
+ raise ApeTagError, "#{e.class}: #{e.message}"
196
214
  end
197
215
  else
198
- def self.new_from_parse(key, value)
199
- new(key, value)
200
- end
201
-
202
216
  def encoded_key(key)
203
217
  key
204
218
  end
@@ -242,7 +256,7 @@ class ApeTag
242
256
  Goa, Drum & Bass, Club-House, Hardcore, Terror, Indie, BritPop, Negerpunk,
243
257
  Polsk Punk, Beat, Christian Gangsta Rap, Heavy Metal, Black Metal,
244
258
  Crossover, Contemporary Christian, Christian Rock, Merengue, Salsa,
245
- Trash Meta, Anime, Jpop, Synthpop'.split(',').collect{|g| g.strip}
259
+ Thrash Metal, Anime, Jpop, Synthpop'.split(',').collect{|g| g.strip}
246
260
  ID3_GENRES_HASH = CICPHash.new(255.chr)
247
261
  ID3_GENRES.each_with_index{|g,i| ID3_GENRES_HASH[g] = i.chr }
248
262
  FILE_OBJ_METHODS = %w'close seek read pos write truncate'
@@ -275,7 +289,7 @@ class ApeTag
275
289
  @check_id3 = check_id3.nil? ? @@check_id3 : check_id3
276
290
  else
277
291
  @filename = filename.to_s
278
- @check_id3 = check_id3.nil? ? !MP3_RE.match(@filename).nil? : check_id3
292
+ @check_id3 = check_id3.nil? ? (MP3_RE.match(@filename) ? true : nil) : check_id3
279
293
  end
280
294
  end
281
295
 
@@ -284,10 +298,16 @@ class ApeTag
284
298
  @has_tag.nil? ? access_file('rb'){has_tag} : @has_tag
285
299
  end
286
300
 
301
+ # Check the file for an ID3 tag. Returns true or false. Raises ApeTagError for corrupt tags.
302
+ def has_id3?
303
+ exists?
304
+ id3 != ''
305
+ end
306
+
287
307
  # Remove an APE tag from a file, if one exists.
288
308
  # Returns true. Raises ApeTagError for corrupt tags.
289
309
  def remove!
290
- access_file('rb+'){file.truncate(tag_start) if has_tag}
310
+ access_file('rb+'){file.truncate(tag_start) if has_tag || has_id3?}
291
311
  @has_tag, @fields, @id3, @tag_size, @tag_start, @tag_data, @tag_header, @tag_footer, @tag_item_count = []
292
312
  true
293
313
  end
@@ -302,8 +322,8 @@ class ApeTag
302
322
  def pretty_print
303
323
  begin
304
324
  fields.values.sort_by{|value| value.key}.collect{|value| "#{value.key}: #{value.join(', ')}"}.join("\n")
305
- rescue ApeTagError
306
- "CORRUPT TAG!"
325
+ rescue ApeTagError => e
326
+ "CORRUPT TAG!: #{e.message}"
307
327
  rescue Errno::ENOENT, Errno::EINVAL
308
328
  "FILE NOT FOUND!"
309
329
  end
@@ -464,27 +484,29 @@ class ApeTag
464
484
  # If the file doesn't have an ID3 and the file already has an APE tag or
465
485
  # check_id3 is not set, an ID3 won't be added.
466
486
  def update_id3
467
- return if id3.length == 0 && (has_tag || check_id3 == false)
468
- id3_fields = CICPHash.new('')
469
- id3_fields['genre'] = 255.chr
470
- fields.values.each do |value|
471
- case value.key
472
- when /\Atrack/i
473
- id3_fields['track'] = value.string_value.to_i
474
- id3_fields['track'] = 0 if id3_fields['track'] > 255
475
- id3_fields['track'] = id3_fields['track'].chr
476
- when /\Agenre/i
477
- id3_fields['genre'] = ID3_GENRES_HASH[value.first]
478
- when /\Adate\z/i
479
- match = YEAR_RE.match(value.string_value)
480
- id3_fields['year'] = match[0] if match
481
- when /\A(title|artist|album|year|comment)\z/i
482
- id3_fields[value.key] = value.join(', ')
487
+ return if id3.empty? && has_tag
488
+ if !id3.empty? || check_id3
489
+ id3_fields = CICPHash.new('')
490
+ id3_fields['genre'] = 255.chr
491
+ fields.values.each do |value|
492
+ case value.key
493
+ when /\Atrack/i
494
+ id3_fields['track'] = value.string_value.to_i
495
+ id3_fields['track'] = 0 if id3_fields['track'] > 255
496
+ id3_fields['track'] = id3_fields['track'].chr
497
+ when /\Agenre/i
498
+ id3_fields['genre'] = ID3_GENRES_HASH[value.first]
499
+ when /\Adate\z/i
500
+ match = YEAR_RE.match(value.string_value)
501
+ id3_fields['year'] = match[0] if match
502
+ when /\A(title|artist|album|year|comment)\z/i
503
+ id3_fields[value.key] = value.join(', ')
504
+ end
483
505
  end
506
+ @id3 = ["TAG", id3_fields['title'], id3_fields['artist'], id3_fields['album'],
507
+ id3_fields['year'], id3_fields['comment'], "\0", id3_fields['track'],
508
+ id3_fields['genre']].pack("a3a30a30a30a4a28a1a1a1")
484
509
  end
485
- @id3 = ["TAG", id3_fields['title'], id3_fields['artist'], id3_fields['album'],
486
- id3_fields['year'], id3_fields['comment'], "\0", id3_fields['track'],
487
- id3_fields['genre']].pack("a3a30a30a30a4a28a1a1a1")
488
510
  end
489
511
 
490
512
  # Write the APEv2 and ID3v1.1 tags to disk.
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'rubygems'
3
3
  require 'apetag'
4
- require 'stringio'
5
4
  require 'test/unit'
5
+ require 'stringio'
6
+ require 'fileutils'
6
7
 
7
8
  EMPTY_APE_TAG = "APETAGEX\320\a\0\0 \0\0\0\0\0\0\0\0\0\0\240\0\0\0\0\0\0\0\0APETAGEX\320\a\0\0 \0\0\0\0\0\0\0\0\0\0\200\0\0\0\0\0\0\0\0TAG\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377"
8
9
  EXAMPLE_APE_TAG = "APETAGEX\xd0\x07\x00\x00\xb0\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00Track\x001\x04\x00\x00\x00\x00\x00\x00\x00Date\x002007\t\x00\x00\x00\x00\x00\x00\x00Comment\x00XXXX-0000\x0b\x00\x00\x00\x00\x00\x00\x00Title\x00Love Cheese\x0b\x00\x00\x00\x00\x00\x00\x00Artist\x00Test Artist\x16\x00\x00\x00\x00\x00\x00\x00Album\x00Test Album\x00Other AlbumAPETAGEX\xd0\x07\x00\x00\xb0\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00TAGLove Cheese\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Test Artist\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Test Album, Other Album\x00\x00\x00\x00\x00\x00\x002007XXXX-0000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff"
@@ -13,19 +14,169 @@ EXAMPLE_APE_FIELDS = {"Track"=>["1"], "Comment"=>["XXXX-0000"], "Album"=>["Test
13
14
  EXAMPLE_APE_FIELDS2 = {"Blah"=>["Blah"], "Comment"=>["XXXX-0000"], "Album"=>["Test Album", "Other Album"], "Artist"=>["Test Artist"], "Date"=>["2007"]}
14
15
  EXAMPLE_APE_TAG_PRETTY_PRINT = "Album: Test Album, Other Album\nArtist: Test Artist\nComment: XXXX-0000\nDate: 2007\nTitle: Love Cheese\nTrack: 1"
15
16
 
16
- class String
17
- if RUBY_VERSION > '1.9.0'
18
- def binary
19
- force_encoding('binary')
20
- end
17
+ class ApeTagTest < Test::Unit::TestCase
18
+ def binary(str)
19
+ str.force_encoding('BINARY') if str.respond_to?(:force_encoding)
20
+ str
21
+ end
22
+
23
+ def utf8(str)
24
+ str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
25
+ str
26
+ end
27
+
28
+ def tagname(name)
29
+ "../test-files/#{name}#{'.tag' unless name =~ /\./}"
30
+ end
31
+
32
+ def tag(name)
33
+ ApeTag.new(tagname(name))
34
+ end
35
+
36
+ def assert_apetag_raised(name, msg)
37
+ yield tag(name)
38
+ rescue ApeTagError => e
39
+ assert(e.message.include?(msg), "Expected: #{msg.inspect}, received: #{e.message.inspect}")
21
40
  else
22
- def binary
23
- self
41
+ assert(false, "#{name} did not raise ApeTagError: #{msg}")
42
+ end
43
+
44
+ def corrupt(name, msg)
45
+ assert_apetag_raised(name, msg){|tag| tag.fields}
46
+ end
47
+
48
+ def with_test_file(before, opts={})
49
+ temp_name = tagname(opts[:name] || 'test')
50
+ FileUtils.copy(tagname(before), temp_name)
51
+ yield temp_name
52
+ File.delete(temp_name)
53
+ end
54
+
55
+ def assert_files_equal(before, after, opts={})
56
+ with_test_file(before, opts) do |temp_name|
57
+ yield(opts[:yield] == :name ? temp_name : ApeTag.new(temp_name))
58
+ assert_equal(File.read(tagname(after)), File.read(temp_name))
24
59
  end
25
60
  end
26
- end
27
61
 
28
- class ApeTagTest < Test::Unit::TestCase
62
+ def test_corrupt
63
+ corrupt("corrupt-count-larger-than-possible", "Item count (1) is larger than possible")
64
+ corrupt("corrupt-count-mismatch", "Header and footer item count does not match")
65
+ corrupt("corrupt-count-over-max-allowed", "Item count (97) is larger than 64")
66
+ corrupt("corrupt-data-remaining", "Data remaining after specified number of items parsed")
67
+ corrupt("corrupt-duplicate-item-key", "Multiple items with same key (\"name\")")
68
+ corrupt("corrupt-finished-without-parsing-all-items", "End of tag reached but more items specified")
69
+ corrupt("corrupt-footer-flags", "Tag has bad footer flags")
70
+ corrupt("corrupt-header", "Missing header")
71
+ corrupt("corrupt-item-flags-invalid", "Invalid item flags at offset 0")
72
+ corrupt("corrupt-item-length-invalid", "Invalid item length at offset 0")
73
+ corrupt("corrupt-key-invalid", "Invalid APE key")
74
+ corrupt("corrupt-key-too-short", "Invalid APE key")
75
+ corrupt("corrupt-key-too-long", "Invalid APE key")
76
+ corrupt("corrupt-min-size", "Tag size (57) smaller than minimum size")
77
+ corrupt("corrupt-missing-key-value-separator", "Missing key-value separator at offset 8")
78
+ corrupt("corrupt-next-start-too-large", "Invalid item length at offset 8")
79
+ corrupt("corrupt-size-larger-than-possible", "Tag size (65) larger than possible")
80
+ corrupt("corrupt-size-mismatch", "Header and footer size does not match")
81
+ corrupt("corrupt-size-over-max-allowed", "Tag size (61504) larger than possible")
82
+ corrupt("corrupt-value-not-utf8", "Invalid item value encoding (non UTF-8)")
83
+ end
84
+
85
+ def test_exists?
86
+ assert_equal(false, tag("missing-ok").exists?)
87
+ assert_equal(true, tag("good-empty").exists?)
88
+ assert_equal(false, tag("good-empty-id3-only").exists?)
89
+ assert_equal(true, tag("good-empty-id3").exists?)
90
+ end
91
+
92
+ def test_has_id3?
93
+ assert_equal(false, tag("missing-ok").has_id3?)
94
+ assert_equal(false, tag("good-empty").has_id3?)
95
+ assert_equal(true, tag("good-empty-id3-only").has_id3?)
96
+ assert_equal(true, tag("good-empty-id3").has_id3?)
97
+ end
98
+
99
+ def test_parsing
100
+ assert_equal({}, tag("good-empty").fields)
101
+ assert_equal({'name'=>['value']}, tag("good-simple-1").fields)
102
+ assert_equal(['value'], tag("good-simple-1").fields['Name'])
103
+
104
+ assert_equal(63, tag("good-many-items").fields.size)
105
+ assert_equal([''], tag("good-many-items").fields['0n'])
106
+ assert_equal(['a'], tag("good-many-items").fields['1n'])
107
+ assert_equal(['a' * 62], tag("good-many-items").fields['62n'])
108
+
109
+ assert_equal({'name'=>['va', 'ue']}, tag("good-multiple-values").fields)
110
+
111
+ assert_equal('name', tag("good-simple-1").fields['name'].key)
112
+ assert_equal('utf8', tag("good-simple-1").fields['name'].ape_type)
113
+ assert_equal(false, tag("good-simple-1").fields['name'].read_only)
114
+
115
+ assert_equal('name', tag("good-simple-1-ro-external").fields['name'].key)
116
+ assert_equal(['value'], tag("good-simple-1-ro-external").fields['name'])
117
+ assert_equal('external', tag("good-simple-1-ro-external").fields['name'].ape_type)
118
+ assert_equal(true, tag("good-simple-1-ro-external").fields['name'].read_only)
119
+
120
+ assert_equal('name', tag("good-binary-non-utf8-value").fields['name'].key)
121
+ assert_equal(binary("v\x81lue"), tag("good-binary-non-utf8-value").fields['name'][0])
122
+ assert_equal('binary', tag("good-binary-non-utf8-value").fields['name'].ape_type)
123
+ assert_equal(false, tag("good-binary-non-utf8-value").fields['name'].read_only)
124
+
125
+ assert_equal({'name'=>['value']}, ApeTag.new(File.open(tagname("good-simple-1"), 'rb')).fields)
126
+ end
127
+
128
+ def test_remove!
129
+ assert_files_equal('good-empty', 'missing-ok'){|tag| tag.remove!}
130
+ assert_files_equal('good-empty-id3', 'missing-ok'){|tag| tag.remove!}
131
+ assert_files_equal('good-empty-id3-only', 'missing-ok'){|tag| tag.remove!}
132
+ assert_files_equal('missing-10k', 'missing-10k'){|tag| tag.remove!}
133
+ assert_files_equal('good-empty-id3', 'missing-ok', :yield=>:name){|temp_name| ApeTag.new(File.open(temp_name, 'rb+')).remove!}
134
+ end
135
+
136
+ def test_update
137
+ assert_files_equal('good-empty', 'good-empty'){|tag| tag.update{|f|}}
138
+ assert_files_equal('missing-ok', 'good-empty'){|tag| tag.update{|f|}}
139
+ assert_files_equal('good-empty', 'good-simple-1'){|tag| tag.update{|f| f['name'] = 'value'}}
140
+ assert_files_equal('good-simple-1', 'good-empty'){|tag| tag.update{|f| f.delete('name')}}
141
+ assert_files_equal('good-simple-1', 'good-empty'){|tag| tag.update{|f| f.delete('Name')}}
142
+ assert_files_equal('good-empty', 'good-simple-1-ro-external'){|tag| tag.update{|f| ai = ApeItem.new('name', ['value']); ai.read_only = true; ai.ape_type = 'external'; f['name'] = ai}}
143
+ assert_files_equal('good-empty', 'good-binary-non-utf8-value'){|tag| tag.update{|f| ai = ApeItem.new('name', [binary("v\x81lue")]); ai.ape_type = 'binary'; f['name'] = ai}}
144
+ assert_files_equal('good-empty', 'good-many-items'){|tag| tag.update{|f| 63.times{|i| f["#{i}n"] = "a" * i}}}
145
+ assert_files_equal('good-empty', 'good-multiple-values'){|tag| tag.update{|f| f['name'] = ['va', 'ue']}}
146
+ assert_files_equal('good-multiple-values', 'good-simple-1-uc'){|tag| tag.update{|f| f['NAME'] = 'value'}}
147
+ assert_files_equal('good-empty', 'good-simple-1-utf8'){|tag| tag.update{|f| f['name'] = [utf8("v\xc3\x82\xc3\x95")]}}
148
+
149
+ assert_apetag_raised('good-empty', 'Updated tag has too many items (65)'){|tag| tag.update{|f| 65.times{|i| f["#{i}n"] = "a" * i}}}
150
+ assert_apetag_raised('good-empty', 'Updated tag too large (8193)'){|tag| tag.update{|f| f['xn'] = "a" * 8118}}
151
+ assert_apetag_raised('good-empty', 'Invalid APE key'){|tag| tag.update{|f| f['n'] = "a"}}
152
+ assert_apetag_raised('good-empty', 'Invalid APE key'){|tag| tag.update{|f| f['n' * 256] = "a"}}
153
+ assert_apetag_raised('good-empty', 'Invalid APE key'){|tag| tag.update{|f| f["n\0"] = "a"}}
154
+ assert_apetag_raised('good-empty', 'Invalid APE key'){|tag| tag.update{|f| f["n\x1f"] = "a"}}
155
+ assert_apetag_raised('good-empty', 'Invalid APE key'){|tag| tag.update{|f| f[binary("n\x80")] = "a"}}
156
+ assert_apetag_raised('good-empty', 'Invalid APE key'){|tag| tag.update{|f| f[binary("n\xff")] = "a"}}
157
+ assert_apetag_raised('good-empty', 'Invalid APE key'){|tag| tag.update{|f| f["tag"] = "a"}}
158
+ assert_apetag_raised('good-empty', 'Invalid key, value, APE type, or Read-Only Flag'){|tag| tag.update{|f| f["ab"] = utf8("v\xff")}}
159
+ assert_apetag_raised('good-empty', 'Invalid APE type'){|tag| tag.update{|f| ai = ApeItem.new('name', [binary("v\x81lue")]); ai.ape_type = 'foo'; f['name'] = ai}}
160
+
161
+ assert_files_equal('good-empty', 'good-simple-1', :yield=>:name){|temp_name| ApeTag.new(File.open(temp_name, 'rb+'), false).update{|f| f["name"] = 'value'}}
162
+ end
163
+
164
+ def test_id3
165
+ assert_files_equal('missing-ok', 'good-empty'){|tag| tag.update{|f|}}
166
+ assert_files_equal('missing-ok', 'good-empty-id3', :yield=>:name){|temp_name| ApeTag.new(temp_name, true).update{|f|}}
167
+ assert_files_equal('missing-ok', 'good-empty-id3', :name=>'test.mp3'){|tag| tag.update{|f|}}
168
+ assert_files_equal('missing-ok', 'good-empty', :name=>'test.mp3', :yield=>:name){|temp_name| ApeTag.new(temp_name, false).update{|f|}}
169
+
170
+ assert_files_equal('good-empty-id3-only', 'good-empty-id3'){|tag| tag.update{|f|}}
171
+ assert_files_equal('good-empty-id3', 'good-simple-4'){|tag| tag.update{|f| f.merge!('track'=>'1', 'genre'=>'Game', 'year'=>'1999', 'title'=>'Test Title', 'artist'=>'Test Artist', 'album'=>'Test Album', 'comment'=>'Test Comment')}}
172
+ assert_files_equal('good-empty-id3', 'good-simple-4-uc'){|tag| tag.update{|f| f.merge!('Track'=>'1', 'Genre'=>'Game', 'Year'=>'1999', 'Title'=>'Test Title', 'Artist'=>'Test Artist', 'Album'=>'Test Album', 'Comment'=>'Test Comment')}}
173
+ assert_files_equal('good-empty-id3', 'good-simple-4-date'){|tag| tag.update{|f| f.merge!('track'=>'1', 'genre'=>'Game', 'date'=>'12/31/1999', 'title'=>'Test Title', 'artist'=>'Test Artist', 'album'=>'Test Album', 'comment'=>'Test Comment')}}
174
+ assert_files_equal('good-empty-id3', 'good-simple-4-long'){|tag| tag.update{|f| f.merge!('track'=>'1', 'genre'=>'Game', 'year'=>'1999'*2, 'title'=>'Test Title'*5, 'artist'=>'Test Artist'*5, 'album'=>'Test Album'*5, 'comment'=>'Test Comment'*5)}}
175
+
176
+ assert_equal(false, ApeTag.new(tagname('good-empty-id3'), false).exists?)
177
+ assert_equal(false, ApeTag.new(tagname('good-empty-id3'), false).has_id3?)
178
+ end
179
+
29
180
  def get_ape_tag(f, check_id3)
30
181
  f.is_a?(ApeTag) ? f : ApeTag.new(f, check_id3)
31
182
  end
@@ -165,8 +316,6 @@ class ApeTagTest < Test::Unit::TestCase
165
316
 
166
317
  # Test create fails with invalid key
167
318
  assert_raises(ApeTagError){ApeItem.create('', ai)}
168
- # Test create fails with invalid UTF-8 value
169
- assert_raises(ApeTagError){ApeItem.create('xx',["\xfe"])}
170
319
  # Test create doesn't fail with valid UTF-8 value
171
320
  assert_nothing_raised{ApeItem.create('xx',[[12345, 1345].pack('UU')])}
172
321
 
metadata CHANGED
@@ -1,83 +1,59 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: apetag
3
- version: !ruby/object:Gem::Version
4
- hash: 27
5
- prerelease: false
6
- segments:
7
- - 1
8
- - 1
9
- - 4
10
- version: 1.1.4
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.5
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Jeremy Evans
14
8
  autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
-
18
- date: 2011-01-21 00:00:00 -08:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
11
+ date: 2013-02-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
22
14
  name: cicphash
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 23
30
- segments:
31
- - 1
32
- - 0
33
- - 0
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
34
19
  version: 1.0.0
35
20
  type: :runtime
36
- version_requirements: *id001
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0
37
27
  description:
38
28
  email: code@jeremyevans.net
39
29
  executables: []
40
-
41
30
  extensions: []
42
-
43
31
  extra_rdoc_files: []
44
-
45
- files:
32
+ files:
46
33
  - apetag.rb
47
34
  - test/test_apetag.rb
48
- has_rdoc: true
49
35
  homepage: http://apetag.rubyforge.org
50
36
  licenses: []
51
-
37
+ metadata: {}
52
38
  post_install_message:
53
39
  rdoc_options: []
54
-
55
- require_paths:
40
+ require_paths:
56
41
  - .
57
- required_ruby_version: !ruby/object:Gem::Requirement
58
- none: false
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- hash: 3
63
- segments:
64
- - 0
65
- version: "0"
66
- required_rubygems_version: !ruby/object:Gem::Requirement
67
- none: false
68
- requirements:
69
- - - ">="
70
- - !ruby/object:Gem::Version
71
- hash: 3
72
- segments:
73
- - 0
74
- version: "0"
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
75
52
  requirements: []
76
-
77
53
  rubyforge_project: apetag
78
- rubygems_version: 1.3.7
54
+ rubygems_version: 2.0.0
79
55
  signing_key:
80
- specification_version: 3
56
+ specification_version: 4
81
57
  summary: APEv2 Tag Reader/Writer
82
- test_files:
58
+ test_files:
83
59
  - test/test_apetag.rb