Skip to content

Commit 3183769

Browse files
committed
test(provider): Validate entity type mapping and ID serialization logic
1 parent 16361b6 commit 3183769

File tree

6 files changed

+40
-1
lines changed

6 files changed

+40
-1
lines changed

providers/Beatport/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export default class BeatportProvider extends MetadataProvider {
2727
artist: 'artist',
2828
label: 'label',
2929
release: 'release',
30+
recording: 'track',
3031
};
3132

3233
readonly releaseLookup = BeatportReleaseLookup;

providers/Deezer/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export default class DeezerProvider extends MetadataApiProvider {
5454
readonly entityTypeMap = {
5555
artist: 'artist',
5656
release: 'album',
57+
recording: 'track',
5758
};
5859

5960
override readonly availableRegions = new Set(availableRegions);

providers/Spotify/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export default class SpotifyProvider extends MetadataApiProvider {
6161
readonly entityTypeMap = {
6262
artist: 'artist',
6363
release: 'album',
64+
recording: 'track',
6465
};
6566

6667
override readonly availableRegions = new Set(availableRegions);

providers/Tidal/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export default class TidalProvider extends MetadataApiProvider {
6363
readonly entityTypeMap = {
6464
artist: 'artist',
6565
release: ['album', 'video'],
66+
recording: 'track',
6667
};
6768

6869
readonly defaultRegion: CountryCode = 'US';

providers/iTunes/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export default class iTunesProvider extends MetadataApiProvider {
3838
readonly entityTypeMap = {
3939
artist: 'artist',
4040
release: 'album',
41+
recording: 'song', // ['song', 'music-video'],
4142
};
4243

4344
override readonly availableRegions = new Set(availableRegions);

providers/test_spec.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
import type { MetadataProvider, ProviderOptions } from './base.ts';
2-
import type { EntityId, HarmonyRelease, ReleaseOptions, ReleaseSpecifier } from '@/harmonizer/types.ts';
2+
import type {
3+
EntityId,
4+
HarmonyEntityType,
5+
HarmonyRelease,
6+
ReleaseOptions,
7+
ReleaseSpecifier,
8+
} from '@/harmonizer/types.ts';
39
import { downloadMode } from '@/utils/fetch_stub.ts';
410
import { isDefined } from '@/utils/predicate.ts';
511

12+
import { assert } from 'std/assert/assert.ts';
613
import { assertEquals } from 'std/assert/assert_equals.ts';
714
import { filterValues } from '@std/collections/filter-values';
815
import { describe, it } from '@std/testing/bdd';
16+
import { preferArray } from 'utils/array/scalar.js';
917

1018
/** Specification which describes the expected behavior of a {@linkcode MetadataProvider}. */
1119
export interface ProviderSpecification {
@@ -51,6 +59,19 @@ export interface EntityUrlTest {
5159

5260
function describeEntityUrlExtraction(provider: MetadataProvider, tests: EntityUrlTest[]) {
5361
describe('extraction of entity type and ID from an URL', () => {
62+
// Construct the inverse entity type mapping.
63+
const inverseEntityTypeMap: Record<string, HarmonyEntityType> = {};
64+
for (const [harmonyType, providerTypes] of Object.entries(provider.entityTypeMap)) {
65+
for (const providerType of preferArray(providerTypes)) {
66+
const mappedHarmonyType = inverseEntityTypeMap[providerType];
67+
assert(
68+
!mappedHarmonyType,
69+
`Entity type "${providerType}" has an ambiguous mapping, it can be ${mappedHarmonyType} or ${harmonyType}`,
70+
);
71+
inverseEntityTypeMap[providerType] = harmonyType as HarmonyEntityType;
72+
}
73+
}
74+
5475
for (const test of tests) {
5576
it(`${test.id ? 'supports' : 'ignores'} ${test.description ?? test.url}`, () => {
5677
let actualId = provider.extractEntityFromUrl(test.url);
@@ -62,6 +83,19 @@ function describeEntityUrlExtraction(provider: MetadataProvider, tests: EntityUr
6283
const serializedId = test.serializedId ?? test.id?.id;
6384
if (serializedId && actualId) {
6485
assertEquals(provider.serializeProviderId(actualId), serializedId, 'Serialized entity ID is wrong');
86+
const harmonyType = inverseEntityTypeMap[actualId.type];
87+
assert(harmonyType, `Type "${actualId.type}" is missing from the provider's entity type mapping`);
88+
if (harmonyType === 'release') {
89+
// ID deserialization is only needed for releases so far.
90+
// We should not yet force providers to implement it for other ambiguous entity types.
91+
const deserializedId = provider.parseProviderId(serializedId, harmonyType);
92+
assertEquals(deserializedId.id, actualId.id, 'Failed to parse serialized provider ID');
93+
assertEquals(
94+
deserializedId.type,
95+
actualId.type,
96+
'Failed to extract entity type from serialized provider ID',
97+
);
98+
}
6599
}
66100
});
67101
}

0 commit comments

Comments
 (0)