apetag 1.1.4 → 1.1.5

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.
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