VulpesOS/gaia/apps/music/test/unit/metadata/id3v2_test.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

389 lines
15 KiB
JavaScript
Executable file

/* global ID3v2Metadata, fetchBlobView, fetchBuffer, makeBlobView,
MockLazyLoader, readBlob, readPicSlice, assertBuffersEqual,
pass, fail, suite, setup, teardown, test, assert */
'use strict';
require('/test/unit/metadata/utils.js');
require('/js/metadata/id3v1.js');
require('/js/metadata/id3v2.js');
suite('id3v2 tags', function() {
// We have a bunch of otherwise-identical mp3 files using different ID3
// versions, covering all valid character encodings. Test them all.
[2, 3, 4].forEach(function(version) {
var tag_format = 'id3v2.' + version + '.0';
suite('simple id3v2.' + version, function() {
test('latin1', function(done) {
var filename = '/test-data/id3v2.' + version + '-simple-latin1.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, tag_format);
assert.strictEqual(metadata.artist, 'AC/DC');
assert.strictEqual(metadata.album, 'Dirty Deeds Done Dirt Cheap');
assert.strictEqual(metadata.title, 'Problem Child');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.trackcount, 9);
assert.strictEqual(metadata.discnum, 1);
assert.strictEqual(metadata.disccount, 1);
})
.then(pass(done), fail(done));
});
test('utf16', function(done) {
var filename = '/test-data/id3v2.' + version + '-simple-utf16.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, tag_format);
assert.strictEqual(metadata.artist, 'Mötley Crüe');
assert.strictEqual(metadata.album, 'Dr. Feelgood');
assert.strictEqual(metadata.title, 'Kickstart My Heart');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.trackcount, 11);
assert.strictEqual(metadata.discnum, 1);
assert.strictEqual(metadata.disccount, 1);
})
.then(pass(done), fail(done));
});
if (version === 4) {
test('utf16be', function(done) {
var filename = '/test-data/id3v2.' + version + '-simple-utf16be.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, tag_format);
assert.strictEqual(metadata.artist, 'Gåte');
assert.strictEqual(metadata.album, 'Jygri');
assert.strictEqual(metadata.title, 'Bruremarsj frå Jämtland');
assert.strictEqual(metadata.tracknum, 8);
assert.strictEqual(metadata.trackcount, 12);
assert.strictEqual(metadata.discnum, 1);
assert.strictEqual(metadata.disccount, 1);
})
.then(pass(done), fail(done));
});
test('utf8', function(done) {
var filename = '/test-data/id3v2.' + version + '-simple-utf8.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, tag_format);
assert.strictEqual(metadata.artist, 'Lunar Aurora');
assert.strictEqual(metadata.album, 'Hoagascht');
assert.strictEqual(metadata.title, 'Håbergoaß');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.trackcount, 8);
assert.strictEqual(metadata.discnum, 1);
assert.strictEqual(metadata.disccount, 1);
})
.then(pass(done), fail(done));
});
}
});
});
suite('simple id3v1+2', function() {
test('id3v1+2', function(done) {
var filename = '/test-data/id3v1+2-simple.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
// Here we should have the v2 tag content.
assert.strictEqual(metadata.tag_format, 'id3v2.3.0');
assert.strictEqual(metadata.artist, 'AC/DC');
assert.strictEqual(metadata.album, 'Dirty Deeds Done Dirt Cheap');
assert.strictEqual(metadata.title, 'Problem Child');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.trackcount, undefined);
})
.then(pass(done), fail(done));
});
});
suite('album art', function() {
var expectedPicture;
setup(function(done) {
fetchBuffer('/test-data/album-art.jpg').then(function(buffer) {
expectedPicture = buffer;
done();
});
});
[2, 3, 4].forEach(function(version) {
test('id3v2.' + version, function(done) {
var blob, filename = '/test-data/id3v2.' + version + '-picture.mp3';
fetchBuffer(filename)
.then(function(buffer) {
return (blob = new Blob([buffer]));
})
.then(makeBlobView)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.artist, 'AC/DC');
assert.strictEqual(metadata.album, 'Dirty Deeds Done Dirt Cheap');
assert.strictEqual(metadata.title, 'Problem Child');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.picture.flavor, 'embedded');
assert.strictEqual(metadata.picture.type, 'image/jpeg');
return readPicSlice(blob, metadata.picture);
})
.then(function(buffer) {
assertBuffersEqual(buffer, expectedPicture);
})
.then(pass(done), fail(done));
});
});
test('id3v2.4 with utf-16 and odd size', function(done) {
var blob, filename = '/test-data/id3v2.4-picture-utf16-odd-size.mp3';
fetchBuffer(filename)
.then(function(buffer) {
return (blob = new Blob([buffer]));
})
.then(makeBlobView)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.artist, 'AC/DC');
assert.strictEqual(metadata.album, 'Dirty Deeds Done Dirt Cheap');
assert.strictEqual(metadata.title, 'Problem Child');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.picture.flavor, 'embedded');
assert.strictEqual(metadata.picture.type, 'image/jpeg');
return readPicSlice(blob, metadata.picture);
})
.then(function(buffer) {
var pic = new TextEncoder('utf-8').encode('odd number of bytes');
assertBuffersEqual(buffer, pic);
})
.then(pass(done), fail(done));
});
});
suite('extended header', function() {
[3, 4].forEach(function(version) {
var tag_format = 'id3v2.' + version + '.0';
test('id3v2.' + version, function(done) {
var filename = '/test-data/id3v2.' + version + '-extheader.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, tag_format);
assert.strictEqual(metadata.artist, 'AC/DC');
assert.strictEqual(metadata.album, 'Dirty Deeds Done Dirt Cheap');
assert.strictEqual(metadata.title, 'Problem Child');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.trackcount, 9);
})
.then(pass(done), fail(done));
});
});
});
suite('unsynchronized data', function() {
var expectedPicture;
setup(function(done) {
fetchBuffer('/test-data/album-art.jpg').then(function(buffer) {
expectedPicture = buffer;
done();
});
});
[3, 4].forEach(function(version) {
var tag_format = 'id3v2.' + version + '.0';
test('id3v2.' + version + ' whole tag', function(done) {
var filename = '/test-data/id3v2.' + version + '-allunsync.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, tag_format);
assert.strictEqual(metadata.artist, 'AC/DC');
assert.strictEqual(metadata.album, 'Dirty Deeds Done Dirt Cheap');
assert.strictEqual(metadata.title, 'Problem Child');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.trackcount, 9);
assert.strictEqual(metadata.picture.flavor, 'unsynced');
assert.strictEqual(metadata.picture.blob.type, 'image/jpeg');
return readBlob(metadata.picture.blob);
})
.then(function(buffer) {
assertBuffersEqual(buffer, expectedPicture);
})
.then(pass(done), fail(done));
});
});
test('id3v2.4 selected frames', function(done) {
var filename = '/test-data/id3v2.4-framesunsync.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, 'id3v2.4.0');
assert.strictEqual(metadata.artist, 'AC/DC');
assert.strictEqual(metadata.album, 'Dirty Deeds Done Dirt Cheap');
assert.strictEqual(metadata.title, 'Problem Child');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.trackcount, 9);
assert.strictEqual(metadata.picture.flavor, 'unsynced');
assert.strictEqual(metadata.picture.blob.type, 'image/jpeg');
return readBlob(metadata.picture.blob);
})
.then(function(buffer) {
assertBuffersEqual(buffer, expectedPicture);
})
.then(pass(done), fail(done));
});
test('id3v2.4 selected frames with data length indicator', function(done) {
var filename = '/test-data/id3v2.4-framesunsync-datalen.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, 'id3v2.4.0');
assert.strictEqual(metadata.artist, 'AC/DC');
assert.strictEqual(metadata.album, 'Dirty Deeds Done Dirt Cheap');
assert.strictEqual(metadata.title, 'Problem Child');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.trackcount, 9);
assert.strictEqual(metadata.picture.flavor, 'unsynced');
assert.strictEqual(metadata.picture.blob.type, 'image/jpeg');
return readBlob(metadata.picture.blob);
})
.then(function(buffer) {
assertBuffersEqual(buffer, expectedPicture);
})
.then(pass(done), fail(done));
});
});
suite('multivalue frames', function() {
['latin1', 'utf16', 'utf16be', 'utf8'].forEach(function(encoding) {
test('id3v2.4 ' + encoding, function(done) {
var filename = '/test-data/id3v2.4-multivalue-' + encoding + '.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, 'id3v2.4.0');
assert.strictEqual(metadata.artist, 'Dynatron / Perturbator');
assert.strictEqual(metadata.album, 'I Am the Night');
assert.strictEqual(metadata.title, 'Volcanic Machinery');
assert.strictEqual(metadata.tracknum, 13);
assert.strictEqual(metadata.trackcount, 15);
})
.then(pass(done), fail(done));
});
});
});
suite('invalid files', function() {
var RealLazyLoader;
setup(function() {
RealLazyLoader = window.LazyLoader;
window.LazyLoader = MockLazyLoader;
});
teardown(function() {
window.LazyLoader = RealLazyLoader;
});
[2, 3, 4].forEach(function(version) {
suite('invalid id3v2.' + version, function() {
test('invalid frame size', function(done) {
var filename = '/test-data/id3v2.' + version +
'-invalid-frame-size.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, undefined);
assert.strictEqual(metadata.artist, undefined);
assert.strictEqual(metadata.album, undefined);
assert.strictEqual(metadata.title, undefined);
assert.strictEqual(metadata.tracknum, undefined);
assert.strictEqual(metadata.trackcount, undefined);
assert.strictEqual(metadata.discnum, undefined);
assert.strictEqual(metadata.disccount, undefined);
})
.then(pass(done), fail(done));
});
test('invalid skipped frame', function(done) {
var filename = '/test-data/id3v2.' + version +
'-invalid-skipped-frame-size.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, undefined);
assert.strictEqual(metadata.artist, undefined);
assert.strictEqual(metadata.album, undefined);
assert.strictEqual(metadata.title, undefined);
assert.strictEqual(metadata.tracknum, undefined);
assert.strictEqual(metadata.trackcount, undefined);
assert.strictEqual(metadata.discnum, undefined);
assert.strictEqual(metadata.disccount, undefined);
})
.then(pass(done), fail(done));
});
if (version === 4) {
test('invalid utf8', function(done) {
var filename = '/test-data/id3v2.4-invalid-utf8.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
assert.strictEqual(metadata.tag_format, 'id3v2.4.0');
assert.strictEqual(metadata.artist, 'AC/DC\uFFFD');
assert.strictEqual(metadata.album,
'Dirty Deeds Done Dirt Cheap');
assert.strictEqual(metadata.title, 'Problem Child');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.trackcount, 9);
assert.strictEqual(metadata.discnum, undefined);
assert.strictEqual(metadata.disccount, undefined);
})
.then(pass(done), fail(done));
});
}
});
});
test('id3v1+2 with invalid ID3v2 frame size', function(done) {
var filename = '/test-data/id3v1+2-invalid-frame-size.mp3';
fetchBlobView(filename)
.then(ID3v2Metadata.parse)
.then(function(metadata) {
// Here we should have the v1 tag content.
assert.strictEqual(metadata.tag_format, 'id3v1');
assert.strictEqual(metadata.artist, 'AC/DC');
assert.strictEqual(metadata.album, 'Dirty Deeds Done Dirt Cheap');
assert.strictEqual(metadata.title, 'Problem Child OLD');
assert.strictEqual(metadata.tracknum, 5);
assert.strictEqual(metadata.trackcount, undefined);
})
.then(pass(done), fail(done));
});
});
});