id3tag 0.8.0 → 0.9.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.
- checksums.yaml +4 -4
- data/.gitignore +3 -46
- data/.travis.yml +6 -5
- data/id3tag.gemspec +8 -8
- data/lib/id3tag/audio_file.rb +24 -6
- data/lib/id3tag/id3_v2_tag_header.rb +4 -4
- data/lib/id3tag/number_util.rb +1 -0
- data/lib/id3tag/tag.rb +2 -2
- data/lib/id3tag/version.rb +1 -1
- data/spec/features/can_read_non_audio_files_spec.rb +8 -7
- data/spec/features/can_read_tag_v1_spec.rb +6 -6
- data/spec/lib/id3tag/audio_file_spec.rb +85 -15
- data/spec/lib/id3tag/frames/util/genre_name_by_id_finder_spec.rb +2 -2
- data/spec/lib/id3tag/frames/v1/comments_frame_spec.rb +7 -7
- data/spec/lib/id3tag/frames/v1/genre_frame_spec.rb +3 -3
- data/spec/lib/id3tag/frames/v1/text_frame_spec.rb +2 -2
- data/spec/lib/id3tag/frames/v1/track_nr_frame_spec.rb +3 -3
- data/spec/lib/id3tag/frames/v2/basic_frame_spec.rb +56 -16
- data/spec/lib/id3tag/frames/v2/comments_frame_spec.rb +5 -5
- data/spec/lib/id3tag/frames/v2/frame_fabricator_spec.rb +8 -8
- data/spec/lib/id3tag/frames/v2/frame_flags_spec.rb +539 -108
- data/spec/lib/id3tag/frames/v2/genre_frame/genre_parser_24_spec.rb +3 -3
- data/spec/lib/id3tag/frames/v2/genre_frame/genre_parser_pre_24_spec.rb +8 -8
- data/spec/lib/id3tag/frames/v2/genre_frame_spec.rb +9 -9
- data/spec/lib/id3tag/frames/v2/picture_frame_spec.rb +37 -17
- data/spec/lib/id3tag/frames/v2/text_frame_spec.rb +7 -7
- data/spec/lib/id3tag/frames/v2/unique_file_id_frame_spec.rb +4 -4
- data/spec/lib/id3tag/frames/v2/user_text_frame_spec.rb +19 -4
- data/spec/lib/id3tag/id3_v1_frame_parser_spec.rb +10 -10
- data/spec/lib/id3tag/id3_v2_frame_parser_spec.rb +6 -6
- data/spec/lib/id3tag/id3_v2_tag_header_spec.rb +105 -21
- data/spec/lib/id3tag/id3tag_spec.rb +1 -1
- data/spec/lib/id3tag/io_util_spec.rb +4 -4
- data/spec/lib/id3tag/number_util_spec.rb +10 -2
- data/spec/lib/id3tag/string_util_spec.rb +10 -10
- data/spec/lib/id3tag/synchsafe_integer_spec.rb +6 -6
- data/spec/lib/id3tag/tag_spec.rb +192 -91
- metadata +28 -29
- data/Gemfile.lock +0 -77
@@ -6,60 +6,144 @@ describe ID3Tag::ID3v2TagHeader do
|
|
6
6
|
describe "#major_version_number" do
|
7
7
|
context "when first bit represent 3" do
|
8
8
|
let(:header_data) { "ID3\03\00..." }
|
9
|
-
|
9
|
+
|
10
|
+
describe '#major_version_number' do
|
11
|
+
subject { super().major_version_number }
|
12
|
+
it { is_expected.to eq(3) }
|
13
|
+
end
|
10
14
|
end
|
11
15
|
end
|
12
16
|
|
13
17
|
describe "#minor_version_number" do
|
14
18
|
context "when 2nd bit represent 2" do
|
15
19
|
let(:header_data) { "ID3\03\02..." }
|
16
|
-
|
20
|
+
|
21
|
+
describe '#minor_version_number' do
|
22
|
+
subject { super().minor_version_number }
|
23
|
+
it { is_expected.to eq(2) }
|
24
|
+
end
|
17
25
|
end
|
18
26
|
end
|
19
27
|
|
20
28
|
describe "#version_number" do
|
21
29
|
let(:header_data) { "ID3\02\03..." }
|
22
|
-
|
30
|
+
|
31
|
+
describe '#version_number' do
|
32
|
+
subject { super().version_number }
|
33
|
+
it { is_expected.to eq("2.3") }
|
34
|
+
end
|
23
35
|
end
|
24
36
|
|
25
37
|
describe "header flags" do
|
26
38
|
context "when flags bite is 0b10000000" do
|
27
39
|
let(:header_data) { "ID3\03\00#{0b10000000.chr}" }
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
40
|
+
|
41
|
+
describe '#unsynchronisation?' do
|
42
|
+
subject { super().unsynchronisation? }
|
43
|
+
it { is_expected.to eq(true) }
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#extended_header?' do
|
47
|
+
subject { super().extended_header? }
|
48
|
+
it { is_expected.to eq(false) }
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#experimental?' do
|
52
|
+
subject { super().experimental? }
|
53
|
+
it { is_expected.to eq(false) }
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#footer_present?' do
|
57
|
+
subject { super().footer_present? }
|
58
|
+
it { is_expected.to eq(false) }
|
59
|
+
end
|
32
60
|
end
|
33
61
|
context "when flags bite is 0b01000000" do
|
34
62
|
let(:header_data) { "ID3\03\00#{0b01000000.chr}" }
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
63
|
+
|
64
|
+
describe '#unsynchronisation?' do
|
65
|
+
subject { super().unsynchronisation? }
|
66
|
+
it { is_expected.to eq(false) }
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#extended_header?' do
|
70
|
+
subject { super().extended_header? }
|
71
|
+
it { is_expected.to eq(true) }
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#experimental?' do
|
75
|
+
subject { super().experimental? }
|
76
|
+
it { is_expected.to eq(false) }
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#footer_present?' do
|
80
|
+
subject { super().footer_present? }
|
81
|
+
it { is_expected.to eq(false) }
|
82
|
+
end
|
39
83
|
end
|
40
84
|
context "when flags bite is 0b00100000" do
|
41
85
|
let(:header_data) { "ID3\03\00#{0b00100000.chr}" }
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
86
|
+
|
87
|
+
describe '#unsynchronisation?' do
|
88
|
+
subject { super().unsynchronisation? }
|
89
|
+
it { is_expected.to eq(false) }
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#extended_header?' do
|
93
|
+
subject { super().extended_header? }
|
94
|
+
it { is_expected.to eq(false) }
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '#experimental?' do
|
98
|
+
subject { super().experimental? }
|
99
|
+
it { is_expected.to eq(true) }
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#footer_present?' do
|
103
|
+
subject { super().footer_present? }
|
104
|
+
it { is_expected.to eq(false) }
|
105
|
+
end
|
46
106
|
end
|
47
107
|
context "when flags bite is 0b00010000" do
|
48
108
|
let(:header_data) { "ID3\03\00#{0b00010000.chr}" }
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
109
|
+
|
110
|
+
describe '#unsynchronisation?' do
|
111
|
+
subject { super().unsynchronisation? }
|
112
|
+
it { is_expected.to eq(false) }
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#extended_header?' do
|
116
|
+
subject { super().extended_header? }
|
117
|
+
it { is_expected.to eq(false) }
|
118
|
+
end
|
119
|
+
|
120
|
+
describe '#experimental?' do
|
121
|
+
subject { super().experimental? }
|
122
|
+
it { is_expected.to eq(false) }
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#footer_present?' do
|
126
|
+
subject { super().footer_present? }
|
127
|
+
it { is_expected.to eq(true) }
|
128
|
+
end
|
53
129
|
end
|
54
130
|
end
|
55
131
|
|
56
132
|
describe "#tag_size" do
|
57
133
|
let(:header_data) { "ID3abc\x00\x00\x01\x7F" }
|
58
|
-
|
134
|
+
|
135
|
+
describe '#tag_size' do
|
136
|
+
subject { super().tag_size }
|
137
|
+
it { is_expected.to eq(255) }
|
138
|
+
end
|
59
139
|
end
|
60
140
|
|
61
141
|
describe "#inspect" do
|
62
142
|
let(:header_data) { "ID3\u0003\u0000\u0000\u0000\u0000\u0000\u0000" }
|
63
|
-
|
143
|
+
|
144
|
+
describe '#inspect' do
|
145
|
+
subject { super().inspect }
|
146
|
+
it { is_expected.to eq "<ID3Tag::ID3v2TagHeader version:2.3.0 size:0 unsync:false ext.header:false experimental:false footer:false>" }
|
147
|
+
end
|
64
148
|
end
|
65
149
|
end
|
@@ -8,11 +8,11 @@ describe ID3Tag::IOUtil do
|
|
8
8
|
let(:group_size) { 1 }
|
9
9
|
context "when only 1 null byte present" do
|
10
10
|
let(:io) { StringIO.new("abcd\x00ef") }
|
11
|
-
it {
|
11
|
+
it { is_expected.to eq("abcd") }
|
12
12
|
end
|
13
13
|
context "when no null bytes are present" do
|
14
14
|
let(:io) { StringIO.new("abcdef") }
|
15
|
-
it {
|
15
|
+
it { is_expected.to eq("abcdef") }
|
16
16
|
end
|
17
17
|
end
|
18
18
|
context "when reading IO and looking for UTF-16 terminator - 2 null bytes" do
|
@@ -20,8 +20,8 @@ describe ID3Tag::IOUtil do
|
|
20
20
|
context "when only 1 null byte present" do
|
21
21
|
let(:io) { StringIO.new("a\x00b\x00\x00\x00c\x00") }
|
22
22
|
it "should return content until terminator and leave cursor just right after" do
|
23
|
-
subject.
|
24
|
-
io.read.
|
23
|
+
expect(subject).to eq("a\x00b\x00")
|
24
|
+
expect(io.read).to eq("c\x00")
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -3,7 +3,7 @@ describe ID3Tag::NumberUtil do
|
|
3
3
|
describe "#convert_string_to_32bit_integer" do
|
4
4
|
context "when string with 4 bytes given" do
|
5
5
|
it "should return integer" do
|
6
|
-
described_class.convert_string_to_32bit_integer("abcd").
|
6
|
+
expect(described_class.convert_string_to_32bit_integer("abcd")).to eq(1633837924)
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
@@ -14,11 +14,19 @@ describe ID3Tag::NumberUtil do
|
|
14
14
|
end.to raise_error(ArgumentError)
|
15
15
|
end
|
16
16
|
end
|
17
|
+
|
18
|
+
context "when non-string argument is given" do
|
19
|
+
it "should raise Argument error" do
|
20
|
+
expect do
|
21
|
+
described_class.convert_string_to_32bit_integer(Object.new)
|
22
|
+
end.to raise_error(ArgumentError)
|
23
|
+
end
|
24
|
+
end
|
17
25
|
end
|
18
26
|
|
19
27
|
describe "#convert_32bit_integer_to_string" do
|
20
28
|
it "should return 4 byte string" do
|
21
|
-
described_class.convert_32bit_integer_to_string(1633837924).
|
29
|
+
expect(described_class.convert_32bit_integer_to_string(1633837924)).to eq("abcd")
|
22
30
|
end
|
23
31
|
end
|
24
32
|
end
|
@@ -5,17 +5,17 @@ describe ID3Tag::StringUtil do
|
|
5
5
|
subject { described_class.blank?(test_string) }
|
6
6
|
context "when test string is like ''" do
|
7
7
|
let(:test_string) { "" }
|
8
|
-
it {
|
8
|
+
it { is_expected.to eq(true) }
|
9
9
|
end
|
10
10
|
|
11
11
|
context "when test string is like ' '" do
|
12
12
|
let(:test_string) { " " }
|
13
|
-
it {
|
13
|
+
it { is_expected.to eq(true) }
|
14
14
|
end
|
15
15
|
|
16
16
|
context "when test string is like 'foo'" do
|
17
17
|
let(:test_string) { "foo" }
|
18
|
-
it {
|
18
|
+
it { is_expected.to eq(false) }
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -25,11 +25,11 @@ describe ID3Tag::StringUtil do
|
|
25
25
|
|
26
26
|
context "when a false synchronization is present" do
|
27
27
|
let(:input) { "\xFF\xEE" }
|
28
|
-
it {
|
28
|
+
it { is_expected.to eq("\xFF\x00\xEE") }
|
29
29
|
end
|
30
30
|
context "when a false synchronization is not present" do
|
31
31
|
let(:input) { "\xEE\xEE" }
|
32
|
-
it {
|
32
|
+
it { is_expected.to eq("\xEE\xEE") }
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -39,11 +39,11 @@ describe ID3Tag::StringUtil do
|
|
39
39
|
|
40
40
|
context "when unsynchronization in present" do
|
41
41
|
let(:input) { "\xFF\x00\xEE\xEE" }
|
42
|
-
it {
|
42
|
+
it { is_expected.to eq("\xFF\xEE\xEE") }
|
43
43
|
end
|
44
44
|
context "when unsynchronization in not present" do
|
45
45
|
let(:input) { "\xEE\xEE" }
|
46
|
-
it {
|
46
|
+
it { is_expected.to eq("\xEE\xEE") }
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -52,15 +52,15 @@ describe ID3Tag::StringUtil do
|
|
52
52
|
subject { described_class.split_by_null_byte(input) }
|
53
53
|
context "when content have only 1 null byte" do
|
54
54
|
let(:input) { "a\u0000b" }
|
55
|
-
it {
|
55
|
+
it { is_expected.to eq(["a", "b"]) }
|
56
56
|
end
|
57
57
|
context "when content have multiple null bytes" do
|
58
58
|
let(:input) { "a\u0000\u0000b" }
|
59
|
-
it {
|
59
|
+
it { is_expected.to eq(["a", "\u0000b"]) }
|
60
60
|
end
|
61
61
|
context "when content have multiple null bytes" do
|
62
62
|
let(:input) { "abc" }
|
63
|
-
it {
|
63
|
+
it { is_expected.to eq(["abc", ""]) }
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
describe ID3Tag::SynchsafeInteger do
|
3
3
|
it "encodes regular integers" do
|
4
|
-
described_class.encode(255).
|
5
|
-
described_class.encode(5).
|
6
|
-
described_class.encode(128).
|
4
|
+
expect(described_class.encode(255)).to eq(383)
|
5
|
+
expect(described_class.encode(5)).to eq(5)
|
6
|
+
expect(described_class.encode(128)).to eq(256)
|
7
7
|
end
|
8
8
|
|
9
9
|
it "decodes synchsafe integers" do
|
10
|
-
described_class.decode(383).
|
11
|
-
described_class.decode(5).
|
12
|
-
described_class.decode(256).
|
10
|
+
expect(described_class.decode(383)).to eq(255)
|
11
|
+
expect(described_class.decode(5)).to eq(5)
|
12
|
+
expect(described_class.decode(256)).to eq(128)
|
13
13
|
end
|
14
14
|
end
|
data/spec/lib/id3tag/tag_spec.rb
CHANGED
@@ -7,7 +7,7 @@ describe ID3Tag::Tag do
|
|
7
7
|
subject { described_class.read(nil) }
|
8
8
|
context "when more that one frame by that ID exists" do
|
9
9
|
before :each do
|
10
|
-
subject.
|
10
|
+
allow(subject).to receive(:get_frames) { [:frame, :frame] }
|
11
11
|
end
|
12
12
|
it "should raise MultipleFrameError" do
|
13
13
|
expect { subject.get_frame(:some_unique_frame) }.to raise_error(ID3Tag::Tag::MultipleFrameError)
|
@@ -16,10 +16,10 @@ describe ID3Tag::Tag do
|
|
16
16
|
|
17
17
|
context "when only one frame by that ID exists" do
|
18
18
|
before :each do
|
19
|
-
subject.
|
19
|
+
allow(subject).to receive(:get_frames) { [:frame] }
|
20
20
|
end
|
21
21
|
it "should return the frame" do
|
22
|
-
subject.get_frame(:some_unique_frame).
|
22
|
+
expect(subject.get_frame(:some_unique_frame)).to eq(:frame)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -30,21 +30,21 @@ describe ID3Tag::Tag do
|
|
30
30
|
let(:a2) { ID3Tag::Frames::V1::TextFrame.new(:A, 'a2') }
|
31
31
|
let(:b) { ID3Tag::Frames::V1::TextFrame.new(:B, 'b') }
|
32
32
|
before :each do
|
33
|
-
subject.
|
33
|
+
allow(subject).to receive(:frames) { [a1, a2, b] }
|
34
34
|
end
|
35
35
|
it "returns frames with specific IDs" do
|
36
|
-
subject.get_frames(:A).
|
36
|
+
expect(subject.get_frames(:A)).to eq([a1, a2])
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
describe "#frames" do
|
41
41
|
subject { described_class.read(nil) }
|
42
42
|
before do
|
43
|
-
subject.
|
44
|
-
subject.
|
43
|
+
allow(subject).to receive(:v1_frames) { [:v1_frame1, :v1_frame2] }
|
44
|
+
allow(subject).to receive(:v2_frames) { [:v2_frame1, :v2_frame2] }
|
45
45
|
end
|
46
46
|
it "returns v2 frames and v1 frames" do
|
47
|
-
subject.frames.
|
47
|
+
expect(subject.frames).to eq([:v2_frame1, :v2_frame2, :v1_frame1, :v1_frame2])
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
@@ -53,10 +53,10 @@ describe ID3Tag::Tag do
|
|
53
53
|
let(:frame_1) { ID3Tag::Frames::V1::TextFrame.new(:AA, 'a1') }
|
54
54
|
let(:frame_2) { ID3Tag::Frames::V1::TextFrame.new(:BB, 'a2') }
|
55
55
|
before do
|
56
|
-
subject.
|
56
|
+
allow(subject).to receive(:frames) { [frame_1, frame_2] }
|
57
57
|
end
|
58
58
|
it "returns frames ids" do
|
59
|
-
subject.frame_ids.
|
59
|
+
expect(subject.frame_ids).to eq([:AA, :BB])
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -65,22 +65,22 @@ describe ID3Tag::Tag do
|
|
65
65
|
subject { described_class.read(nil, :v1) }
|
66
66
|
context "when file has v1 tag" do
|
67
67
|
before do
|
68
|
-
ID3Tag::AudioFile.
|
69
|
-
ID3Tag::AudioFile.
|
70
|
-
ID3Tag::ID3V1FrameParser.
|
68
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v1_tag_present?) { true }
|
69
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v1_tag_body) { '' }
|
70
|
+
allow_any_instance_of(ID3Tag::ID3V1FrameParser).to receive(:frames) { [:v1_frame] }
|
71
71
|
end
|
72
72
|
it "reads v1 tags" do
|
73
|
-
subject.v1_frames.
|
73
|
+
expect(subject.v1_frames).to eq([:v1_frame])
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
77
|
context "when file does not have v1 tag" do
|
78
78
|
before do
|
79
|
-
ID3Tag::AudioFile.
|
80
|
-
ID3Tag::AudioFile.
|
79
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v1_tag_present?) { false }
|
80
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v1_tag_body) { '' }
|
81
81
|
end
|
82
82
|
it "returns empty array" do
|
83
|
-
subject.v1_frames.
|
83
|
+
expect(subject.v1_frames).to eq([])
|
84
84
|
end
|
85
85
|
end
|
86
86
|
end
|
@@ -89,11 +89,11 @@ describe ID3Tag::Tag do
|
|
89
89
|
subject { described_class.read(nil, :v2) }
|
90
90
|
context "when file has v1 tag" do
|
91
91
|
before do
|
92
|
-
ID3Tag::AudioFile.
|
93
|
-
ID3Tag::AudioFile.
|
92
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v1_tag_present?) { true }
|
93
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v1_tag_body) { '' }
|
94
94
|
end
|
95
95
|
it "reads v1 tags" do
|
96
|
-
subject.v1_frames.
|
96
|
+
expect(subject.v1_frames).to eq([])
|
97
97
|
end
|
98
98
|
end
|
99
99
|
end
|
@@ -102,12 +102,12 @@ describe ID3Tag::Tag do
|
|
102
102
|
subject { described_class.read(nil, :all) }
|
103
103
|
context "when file has v1 tag" do
|
104
104
|
before do
|
105
|
-
ID3Tag::AudioFile.
|
106
|
-
ID3Tag::AudioFile.
|
107
|
-
ID3Tag::ID3V1FrameParser.
|
105
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v1_tag_present?) { true }
|
106
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v1_tag_body) { '' }
|
107
|
+
allow_any_instance_of(ID3Tag::ID3V1FrameParser).to receive(:frames) { [:v1_frame] }
|
108
108
|
end
|
109
109
|
it "reads v1 tags" do
|
110
|
-
subject.v1_frames.
|
110
|
+
expect(subject.v1_frames).to eq([:v1_frame])
|
111
111
|
end
|
112
112
|
end
|
113
113
|
end
|
@@ -115,28 +115,29 @@ describe ID3Tag::Tag do
|
|
115
115
|
|
116
116
|
describe "#v2_frames" do
|
117
117
|
before do
|
118
|
-
ID3Tag::AudioFile.
|
118
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v2_tag_major_version_number) { 3 }
|
119
119
|
end
|
120
120
|
context "when tag reading initialized with v2 tag only" do
|
121
121
|
subject { described_class.read(nil, :v2) }
|
122
122
|
context "when file has v2 tag" do
|
123
123
|
before do
|
124
|
-
ID3Tag::AudioFile.
|
125
|
-
ID3Tag::AudioFile.
|
126
|
-
ID3Tag::
|
124
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v2_tag_present?) { true }
|
125
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v2_tag_body) { '' }
|
126
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v2_tag_size) { 120 }
|
127
|
+
allow_any_instance_of(ID3Tag::ID3V2FrameParser).to receive(:frames) { [:v2_frame] }
|
127
128
|
end
|
128
129
|
it "reads v2 tags" do
|
129
|
-
subject.v2_frames.
|
130
|
+
expect(subject.v2_frames).to eq([:v2_frame])
|
130
131
|
end
|
131
132
|
end
|
132
133
|
|
133
134
|
context "when file does not have v2 tag" do
|
134
135
|
before do
|
135
|
-
ID3Tag::AudioFile.
|
136
|
-
ID3Tag::AudioFile.
|
136
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v2_tag_present?) { false }
|
137
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v2_tag_body) { '' }
|
137
138
|
end
|
138
139
|
it "returns empty array" do
|
139
|
-
subject.v2_frames.
|
140
|
+
expect(subject.v2_frames).to eq([])
|
140
141
|
end
|
141
142
|
end
|
142
143
|
end
|
@@ -145,11 +146,11 @@ describe ID3Tag::Tag do
|
|
145
146
|
subject { described_class.read(nil, :v1) }
|
146
147
|
context "when file has v2 tag" do
|
147
148
|
before do
|
148
|
-
ID3Tag::AudioFile.
|
149
|
-
ID3Tag::AudioFile.
|
149
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v2_tag_present?) { true }
|
150
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v2_tag_body) { '' }
|
150
151
|
end
|
151
152
|
it "returns empty array" do
|
152
|
-
subject.v2_frames.
|
153
|
+
expect(subject.v2_frames).to eq([])
|
153
154
|
end
|
154
155
|
end
|
155
156
|
end
|
@@ -158,12 +159,13 @@ describe ID3Tag::Tag do
|
|
158
159
|
subject { described_class.read(nil, :all) }
|
159
160
|
context "when file has v2 tag" do
|
160
161
|
before do
|
161
|
-
ID3Tag::AudioFile.
|
162
|
-
ID3Tag::AudioFile.
|
163
|
-
ID3Tag::
|
162
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v2_tag_present?) { true }
|
163
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v2_tag_body) { '' }
|
164
|
+
allow_any_instance_of(ID3Tag::AudioFile).to receive(:v2_tag_size) { 120 }
|
165
|
+
allow_any_instance_of(ID3Tag::ID3V2FrameParser).to receive(:frames) { [:v2_frame] }
|
164
166
|
end
|
165
167
|
it "reads v2 tags" do
|
166
|
-
subject.v2_frames.
|
168
|
+
expect(subject.v2_frames).to eq([:v2_frame])
|
167
169
|
end
|
168
170
|
end
|
169
171
|
end
|
@@ -172,78 +174,177 @@ describe ID3Tag::Tag do
|
|
172
174
|
describe "Tests with real-world tags" do
|
173
175
|
let(:audio_file) { double("Fake Audio file") }
|
174
176
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
audio_file.stub({
|
179
|
-
:v1_tag_present? => true,
|
180
|
-
:v2_tag_present? => true,
|
181
|
-
:v2_tag_body => mp3_fixture("signals_1.mp3.v2_3_tag_body").read,
|
182
|
-
:v2_tag_major_version_number => 3
|
183
|
-
})
|
177
|
+
subject do
|
178
|
+
described_class.new(nil, scope_version).tap do |obj|
|
179
|
+
allow(obj).to receive(:audio_file) { audio_file }
|
184
180
|
end
|
181
|
+
end
|
182
|
+
|
183
|
+
before do
|
184
|
+
allow(audio_file).to receive_messages({
|
185
|
+
:v1_tag_present? => v1_tag_present_flag,
|
186
|
+
:v2_tag_present? => v2_tag_present_flag,
|
187
|
+
:v1_tag_body => v1_tag_body,
|
188
|
+
:v1_tag_size => v1_tag_body.to_s.size,
|
189
|
+
:v2_tag_body => v2_tag_body,
|
190
|
+
:v2_tag_size => v2_tag_body.to_s.size,
|
191
|
+
:v2_tag_major_version_number => v2_tag_major_version_number
|
192
|
+
})
|
193
|
+
end
|
194
|
+
|
195
|
+
context "signals_1.mp3.v2_3_tag_body" do
|
196
|
+
let(:v1_tag_present_flag) { true }
|
197
|
+
let(:v2_tag_present_flag) { true }
|
198
|
+
let(:v1_tag_body) { }
|
199
|
+
let(:v2_tag_body) { mp3_fixture("signals_1.mp3.v2_3_tag_body").read }
|
200
|
+
let(:v2_tag_major_version_number) { 3 }
|
201
|
+
|
185
202
|
context "Reading only v2" do
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
203
|
+
let(:scope_version) { :v2 }
|
204
|
+
|
205
|
+
describe '#artist' do
|
206
|
+
subject { super().artist }
|
207
|
+
it { is_expected.to eq("Sabled Sun") }
|
208
|
+
end
|
209
|
+
|
210
|
+
describe '#title' do
|
211
|
+
subject { super().title }
|
212
|
+
it { is_expected.to eq("Sabled Sun - Signals I") }
|
213
|
+
end
|
214
|
+
|
215
|
+
describe '#album' do
|
216
|
+
subject { super().album }
|
217
|
+
it { is_expected.to eq("Signals I") }
|
218
|
+
end
|
219
|
+
|
220
|
+
describe '#year' do
|
221
|
+
subject { super().year }
|
222
|
+
it { is_expected.to eq("2013") }
|
223
|
+
end
|
224
|
+
|
225
|
+
describe '#track_nr' do
|
226
|
+
subject { super().track_nr }
|
227
|
+
it { is_expected.to eq "1" }
|
228
|
+
end
|
229
|
+
|
230
|
+
describe '#genre' do
|
231
|
+
subject { super().genre }
|
232
|
+
it { is_expected.to eq "Jazz" }
|
233
|
+
end
|
234
|
+
|
235
|
+
describe '#comments' do
|
236
|
+
subject { super().comments }
|
237
|
+
it { is_expected.to eq("Visit http://cryochamber.bandcamp.com") }
|
238
|
+
end
|
194
239
|
it "should return eng comment" do
|
195
|
-
subject.comments(:eng).
|
240
|
+
expect(subject.comments(:eng)).to eq("Visit http://cryochamber.bandcamp.com")
|
196
241
|
end
|
197
242
|
it "should read private frames" do
|
198
|
-
subject.get_frames(:PRIV).find { |f| f.owner_identifier.force_encoding(Encoding::UTF_8) == "WM/MediaClassPrimaryID" }.
|
243
|
+
expect(subject.get_frames(:PRIV).find { |f| f.owner_identifier.force_encoding(Encoding::UTF_8) == "WM/MediaClassPrimaryID" }).to be_kind_of(ID3Tag::Frames::V2::PrivateFrame)
|
199
244
|
end
|
200
245
|
end
|
201
246
|
end
|
202
247
|
|
203
248
|
context "pov_20131018-2100a.mp3" do
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
:v2_tag_body => mp3_fixture("pov_20131018-2100a.mp3.v2_3_tag_body").read,
|
211
|
-
:v2_tag_major_version_number => 3
|
212
|
-
})
|
213
|
-
end
|
249
|
+
let(:v1_tag_present_flag) { true }
|
250
|
+
let(:v2_tag_present_flag) { true }
|
251
|
+
let(:v1_tag_body) { mp3_fixture("pov_20131018-2100a.mp3.v1_tag_body").read }
|
252
|
+
let(:v2_tag_body) { mp3_fixture("pov_20131018-2100a.mp3.v2_3_tag_body").read }
|
253
|
+
let(:v2_tag_major_version_number) { 3 }
|
254
|
+
|
214
255
|
context "Reading only v1" do
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
256
|
+
let(:scope_version) { :v1 }
|
257
|
+
|
258
|
+
describe '#artist' do
|
259
|
+
subject { super().artist }
|
260
|
+
it { is_expected.to eq("") }
|
261
|
+
end
|
262
|
+
|
263
|
+
describe '#title' do
|
264
|
+
subject { super().title }
|
265
|
+
it { is_expected.to eq("pov_20131018-2100a.mp3") }
|
266
|
+
end
|
267
|
+
|
268
|
+
describe '#album' do
|
269
|
+
subject { super().album }
|
270
|
+
it { is_expected.to eq("") }
|
271
|
+
end
|
272
|
+
|
273
|
+
describe '#year' do
|
274
|
+
subject { super().year }
|
275
|
+
it { is_expected.to eq("") }
|
276
|
+
end
|
277
|
+
|
278
|
+
describe '#track_nr' do
|
279
|
+
subject { super().track_nr }
|
280
|
+
it { is_expected.to be_nil }
|
281
|
+
end
|
282
|
+
|
283
|
+
describe '#genre' do
|
284
|
+
subject { super().genre }
|
285
|
+
it { is_expected.to eq("Blues") }
|
286
|
+
end
|
287
|
+
|
288
|
+
describe '#comments' do
|
289
|
+
subject { super().comments }
|
290
|
+
it { is_expected.to be_nil }
|
291
|
+
end
|
292
|
+
|
293
|
+
describe '#frame_ids' do
|
294
|
+
subject { super().frame_ids }
|
295
|
+
it { is_expected.to eq [:title, :artist, :album, :year, :comments, :genre] }
|
296
|
+
end
|
224
297
|
end
|
225
298
|
context "Reading only v2" do
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
299
|
+
let(:scope_version) { :v2 }
|
300
|
+
|
301
|
+
describe '#artist' do
|
302
|
+
subject { super().artist }
|
303
|
+
it { is_expected.to eq("BBC Radio 4") }
|
304
|
+
end
|
305
|
+
|
306
|
+
describe '#title' do
|
307
|
+
subject { super().title }
|
308
|
+
it { is_expected.to eq("PoV: Lisa Jardine: Machine Intelligence: 18 Oct 13") }
|
309
|
+
end
|
310
|
+
|
311
|
+
describe '#album' do
|
312
|
+
subject { super().album }
|
313
|
+
it { is_expected.to eq("A Point of View") }
|
314
|
+
end
|
315
|
+
|
316
|
+
describe '#year' do
|
317
|
+
subject { super().year }
|
318
|
+
it { is_expected.to eq("2013") }
|
319
|
+
end
|
320
|
+
|
321
|
+
describe '#track_nr' do
|
322
|
+
subject { super().track_nr }
|
323
|
+
it { is_expected.to be_nil }
|
324
|
+
end
|
232
325
|
it "should return nil for genre as this tag have incorect genre frame" do
|
233
|
-
subject.genre.
|
326
|
+
expect(subject.genre).to eq("")
|
327
|
+
end
|
328
|
+
|
329
|
+
describe '#comments' do
|
330
|
+
subject { super().comments }
|
331
|
+
it { is_expected.to eq("Lisa Jardine compares the contributions of Ada Lovelace and Alan Turing a century later to computer science and contrasts their views on the potential of and limits to machine intelligence. \r\nProducer: Sheila Cook") }
|
234
332
|
end
|
235
|
-
its(:comments) { should eq("Lisa Jardine compares the contributions of Ada Lovelace and Alan Turing a century later to computer science and contrasts their views on the potential of and limits to machine intelligence. \r\nProducer: Sheila Cook") }
|
236
333
|
it "should return eng comment" do
|
237
|
-
subject.comments(:eng).
|
334
|
+
expect(subject.comments(:eng)).to eq("Lisa Jardine compares the contributions of Ada Lovelace and Alan Turing a century later to computer science and contrasts their views on the potential of and limits to machine intelligence. \r\nProducer: Sheila Cook")
|
238
335
|
end
|
239
336
|
it "should return blank string for latvian comments" do
|
240
|
-
subject.comments(:lav).
|
337
|
+
expect(subject.comments(:lav)).to be_nil
|
338
|
+
end
|
339
|
+
|
340
|
+
describe '#frame_ids' do
|
341
|
+
subject { super().frame_ids }
|
342
|
+
it { is_expected.to eq [:TALB, :TPE1, :COMM, :USLT, :TCON, :TIT2, :TYER, :TCOP, :APIC] }
|
241
343
|
end
|
242
|
-
its(:frame_ids) { should eq [:TALB, :TPE1, :COMM, :USLT, :TCON, :TIT2, :TYER, :TCOP, :APIC] }
|
243
344
|
it "should have comments frame with short desc and language code" do
|
244
|
-
subject.get_frames(:COMM).size.
|
245
|
-
subject.get_frame(:COMM).language.
|
246
|
-
subject.get_frame(:COMM).description.
|
345
|
+
expect(subject.get_frames(:COMM).size).to eq(1)
|
346
|
+
expect(subject.get_frame(:COMM).language).to eq("eng")
|
347
|
+
expect(subject.get_frame(:COMM).description).to eq("")
|
247
348
|
end
|
248
349
|
end
|
249
350
|
end
|