c0785cf894
Field names mirror web/src/lib/api/types.ts and the server JSON shape (internal/api/types.go's HomePayload). Hand-written DTOs per spec section 10 -- codegen revisits at ~30 models. Adopts server contract over plan-body mock: - cover_url (not cover_art_url) for artist/album refs - duration_sec (not duration_ms) for albums and tracks - stream_url, disc_number on TrackRef - sort_name/album_count on ArtistRef; sort_title/year/track_count on AlbumRef HomeData section keys match server: recently_added_albums, rediscover_albums, rediscover_artists, most_played_tracks, last_played_artists.
169 lines
5.0 KiB
Dart
169 lines
5.0 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:minstrel/models/album.dart';
|
|
import 'package:minstrel/models/artist.dart';
|
|
import 'package:minstrel/models/home_data.dart';
|
|
import 'package:minstrel/models/track.dart';
|
|
import 'package:minstrel/models/user.dart';
|
|
|
|
void main() {
|
|
group('User.fromJson', () {
|
|
test('parses canonical UserView shape', () {
|
|
final u = User.fromJson({
|
|
'id': 'usr-1',
|
|
'username': 'alice',
|
|
'is_admin': true,
|
|
});
|
|
expect(u.id, 'usr-1');
|
|
expect(u.username, 'alice');
|
|
expect(u.isAdmin, isTrue);
|
|
});
|
|
|
|
test('defaults is_admin to false when missing', () {
|
|
final u = User.fromJson({'id': 'usr-2', 'username': 'bob'});
|
|
expect(u.isAdmin, isFalse);
|
|
});
|
|
});
|
|
|
|
group('ArtistRef.fromJson', () {
|
|
test('parses full payload using server cover_url field', () {
|
|
final a = ArtistRef.fromJson({
|
|
'id': 'art-1',
|
|
'name': 'Boards of Canada',
|
|
'sort_name': 'Boards of Canada',
|
|
'album_count': 7,
|
|
'cover_url': '/api/albums/al-1/cover',
|
|
});
|
|
expect(a.name, 'Boards of Canada');
|
|
expect(a.sortName, 'Boards of Canada');
|
|
expect(a.albumCount, 7);
|
|
expect(a.coverUrl, '/api/albums/al-1/cover');
|
|
});
|
|
|
|
test('tolerates missing optional fields', () {
|
|
final a = ArtistRef.fromJson({'id': 'art-2', 'name': 'Aphex Twin'});
|
|
expect(a.sortName, '');
|
|
expect(a.albumCount, 0);
|
|
expect(a.coverUrl, '');
|
|
});
|
|
});
|
|
|
|
group('AlbumRef.fromJson', () {
|
|
test('parses full payload with year and duration_sec', () {
|
|
final a = AlbumRef.fromJson({
|
|
'id': 'al-1',
|
|
'title': 'Geogaddi',
|
|
'sort_title': 'Geogaddi',
|
|
'artist_id': 'art-1',
|
|
'artist_name': 'Boards of Canada',
|
|
'year': 2002,
|
|
'track_count': 23,
|
|
'duration_sec': 4020,
|
|
'cover_url': '/api/albums/al-1/cover',
|
|
});
|
|
expect(a.title, 'Geogaddi');
|
|
expect(a.year, 2002);
|
|
expect(a.trackCount, 23);
|
|
expect(a.durationSec, 4020);
|
|
expect(a.coverUrl, '/api/albums/al-1/cover');
|
|
});
|
|
|
|
test('leaves year null when absent', () {
|
|
final a = AlbumRef.fromJson({
|
|
'id': 'al-2',
|
|
'title': 'Untitled',
|
|
'artist_id': 'art-1',
|
|
});
|
|
expect(a.year, isNull);
|
|
expect(a.trackCount, 0);
|
|
expect(a.durationSec, 0);
|
|
});
|
|
});
|
|
|
|
group('TrackRef.fromJson', () {
|
|
test('parses full payload including stream_url', () {
|
|
final t = TrackRef.fromJson({
|
|
'id': 'tr-1',
|
|
'title': 'Music Is Math',
|
|
'album_id': 'al-1',
|
|
'album_title': 'Geogaddi',
|
|
'artist_id': 'art-1',
|
|
'artist_name': 'Boards of Canada',
|
|
'track_number': 5,
|
|
'disc_number': 1,
|
|
'duration_sec': 379,
|
|
'stream_url': '/api/tracks/tr-1/stream',
|
|
});
|
|
expect(t.title, 'Music Is Math');
|
|
expect(t.trackNumber, 5);
|
|
expect(t.discNumber, 1);
|
|
expect(t.durationSec, 379);
|
|
expect(t.streamUrl, '/api/tracks/tr-1/stream');
|
|
});
|
|
|
|
test('leaves track_number and disc_number null when omitted', () {
|
|
final t = TrackRef.fromJson({
|
|
'id': 'tr-2',
|
|
'title': 'Hidden',
|
|
'album_id': 'al-1',
|
|
'artist_id': 'art-1',
|
|
});
|
|
expect(t.trackNumber, isNull);
|
|
expect(t.discNumber, isNull);
|
|
});
|
|
});
|
|
|
|
group('HomeData.fromJson', () {
|
|
test('handles missing sections as empty lists', () {
|
|
final h = HomeData.fromJson({});
|
|
expect(h.recentlyAddedAlbums, isEmpty);
|
|
expect(h.rediscoverAlbums, isEmpty);
|
|
expect(h.rediscoverArtists, isEmpty);
|
|
expect(h.mostPlayedTracks, isEmpty);
|
|
expect(h.lastPlayedArtists, isEmpty);
|
|
});
|
|
|
|
test('parses populated payload across all five sections', () {
|
|
final h = HomeData.fromJson({
|
|
'recently_added_albums': [
|
|
{
|
|
'id': 'al-1',
|
|
'title': 'Geogaddi',
|
|
'artist_id': 'art-1',
|
|
'artist_name': 'Boards of Canada',
|
|
'cover_url': '/api/albums/al-1/cover',
|
|
}
|
|
],
|
|
'rediscover_albums': [
|
|
{
|
|
'id': 'al-2',
|
|
'title': 'Music Has the Right to Children',
|
|
'artist_id': 'art-1',
|
|
'artist_name': 'Boards of Canada',
|
|
}
|
|
],
|
|
'rediscover_artists': [
|
|
{'id': 'art-2', 'name': 'Aphex Twin'}
|
|
],
|
|
'most_played_tracks': [
|
|
{
|
|
'id': 'tr-1',
|
|
'title': 'Roygbiv',
|
|
'album_id': 'al-2',
|
|
'artist_id': 'art-1',
|
|
'duration_sec': 150,
|
|
}
|
|
],
|
|
'last_played_artists': [
|
|
{'id': 'art-3', 'name': 'Tycho'}
|
|
],
|
|
});
|
|
expect(h.recentlyAddedAlbums.single.title, 'Geogaddi');
|
|
expect(h.recentlyAddedAlbums.single.coverUrl, '/api/albums/al-1/cover');
|
|
expect(h.rediscoverAlbums.single.id, 'al-2');
|
|
expect(h.rediscoverArtists.single.name, 'Aphex Twin');
|
|
expect(h.mostPlayedTracks.single.durationSec, 150);
|
|
expect(h.lastPlayedArtists.single.name, 'Tycho');
|
|
});
|
|
});
|
|
}
|