213 lines
7.7 KiB
Dart
213 lines
7.7 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:http/testing.dart';
|
|
import 'package:plezy/media/media_kind.dart';
|
|
import 'package:plezy/models/catalog/catalog_item.dart';
|
|
import 'package:plezy/models/seerr/seerr_session.dart';
|
|
import 'package:plezy/services/catalog/catalog_source.dart';
|
|
import 'package:plezy/services/catalog/seerr_catalog_source.dart';
|
|
import 'package:plezy/services/seerr/seerr_client.dart';
|
|
import 'package:plezy/utils/external_ids.dart';
|
|
|
|
SeerrCatalogSource _source(MockClient mock) {
|
|
final client = SeerrClient(
|
|
const SeerrSession(
|
|
baseUrl: 'https://seerr.example.com',
|
|
method: SeerrAuthMethod.local,
|
|
identifier: 'a@b.c',
|
|
secret: 'pw',
|
|
cookie: 'cookie',
|
|
userId: 1,
|
|
permissions: 2,
|
|
displayName: 'Alice',
|
|
instanceLabel: 'Seerr',
|
|
createdAt: 0,
|
|
),
|
|
onSessionInvalidated: () {},
|
|
httpClient: mock,
|
|
);
|
|
final source = SeerrCatalogSource(client);
|
|
addTearDown(() {
|
|
source.dispose();
|
|
client.dispose();
|
|
});
|
|
return source;
|
|
}
|
|
|
|
http.Response _json(Object body) => http.Response(jsonEncode(body), 200, headers: {'content-type': 'application/json'});
|
|
|
|
void main() {
|
|
group('SeerrCatalogSource', () {
|
|
test('trending row keeps movies and shows, drops people, maps TMDB images', () async {
|
|
final source = _source(
|
|
MockClient((request) async {
|
|
expect(request.url.path, '/api/v1/discover/trending');
|
|
return _json({
|
|
'page': 1,
|
|
'totalPages': 3,
|
|
'results': [
|
|
{
|
|
'id': 603,
|
|
'mediaType': 'movie',
|
|
'title': 'The Matrix',
|
|
'releaseDate': '1999-03-30',
|
|
'posterPath': '/matrix.jpg',
|
|
'backdropPath': '/matrix-backdrop.jpg',
|
|
'voteAverage': 8.2,
|
|
'voteCount': 26000,
|
|
},
|
|
{'id': 9, 'mediaType': 'person', 'name': 'Keanu Reeves'},
|
|
{'id': 1396, 'mediaType': 'tv', 'name': 'Breaking Bad', 'firstAirDate': '2008-01-20'},
|
|
],
|
|
});
|
|
}),
|
|
);
|
|
|
|
final page = await source.fetchRow(CatalogRowId.trending);
|
|
expect(page.hasMore, isTrue);
|
|
expect(page.items, hasLength(2));
|
|
|
|
final matrix = page.items.first;
|
|
expect(matrix.source, CatalogSourceId.seerr);
|
|
expect(matrix.kind, MediaKind.movie);
|
|
expect(matrix.title, 'The Matrix');
|
|
expect(matrix.year, 1999);
|
|
expect(matrix.rating, 8.2);
|
|
expect(matrix.votes, 26000);
|
|
expect(matrix.ids.tmdb, 603);
|
|
expect(matrix.posterUrl, 'https://image.tmdb.org/t/p/w600_and_h900_bestv2/matrix.jpg');
|
|
expect(matrix.backdropUrl, 'https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/matrix-backdrop.jpg');
|
|
|
|
expect(page.items.last.kind, MediaKind.show);
|
|
expect(page.items.last.title, 'Breaking Bad');
|
|
});
|
|
|
|
test('single-type rows hit their endpoint and coerce the kind', () async {
|
|
final paths = <String>[];
|
|
final source = _source(
|
|
MockClient((request) async {
|
|
paths.add('${request.url.path}?${request.url.query}');
|
|
return _json({
|
|
'page': 2,
|
|
'totalPages': 2,
|
|
'results': [
|
|
{'id': 335984, 'title': 'Blade Runner 2049', 'releaseDate': '2017-10-04'},
|
|
],
|
|
});
|
|
}),
|
|
);
|
|
|
|
final page = await source.fetchRow(CatalogRowId.upcomingMovies, page: 2);
|
|
expect(paths.single, '/api/v1/discover/movies/upcoming?page=2');
|
|
expect(page.items.single.kind, MediaKind.movie);
|
|
expect(page.hasMore, isFalse);
|
|
});
|
|
|
|
test('rows Seerr does not serve throw', () {
|
|
final source = _source(MockClient((request) async => _json({})));
|
|
expect(() => source.fetchRow(CatalogRowId.watchlist), throwsArgumentError);
|
|
expect(() => source.fetchRow(CatalogRowId.suggestedAnime), throwsArgumentError);
|
|
});
|
|
|
|
test('resolveItemIds needs a tmdb id', () async {
|
|
final source = _source(MockClient((request) async => _json({})));
|
|
final resolved = await source.resolveItemIds(MediaKind.movie, const ExternalIds(tmdb: 603, imdb: 'tt0133093'));
|
|
expect(resolved?.tmdb, 603);
|
|
expect(resolved?.imdb, 'tt0133093');
|
|
expect(await source.resolveItemIds(MediaKind.movie, const ExternalIds(imdb: 'tt0133093')), isNull);
|
|
});
|
|
|
|
test('fetchCast reads credits off the detail endpoint', () async {
|
|
final source = _source(
|
|
MockClient((request) async {
|
|
expect(request.url.path, '/api/v1/tv/1396');
|
|
return _json({
|
|
'id': 1396,
|
|
'name': 'Breaking Bad',
|
|
'credits': {
|
|
'cast': [
|
|
{'name': 'Bryan Cranston', 'character': 'Walter White', 'profilePath': '/bc.jpg'},
|
|
{'name': '', 'character': 'nobody'},
|
|
{'name': 'Aaron Paul', 'character': 'Jesse Pinkman'},
|
|
],
|
|
},
|
|
});
|
|
}),
|
|
);
|
|
|
|
final item = CatalogItem(
|
|
source: CatalogSourceId.seerr,
|
|
kind: MediaKind.show,
|
|
title: 'Breaking Bad',
|
|
ids: const CatalogItemIds(tmdb: 1396),
|
|
);
|
|
final cast = await source.fetchCast(item);
|
|
expect(cast, hasLength(2));
|
|
expect(cast.first.name, 'Bryan Cranston');
|
|
expect(cast.first.secondary, 'Walter White');
|
|
expect(cast.first.imageUrl, 'https://image.tmdb.org/t/p/w300/bc.jpg');
|
|
expect(cast.last.imageUrl, isNull);
|
|
});
|
|
|
|
test('search proxies /search and filters persons', () async {
|
|
final source = _source(
|
|
MockClient((request) async {
|
|
expect(request.url.path, '/api/v1/search');
|
|
expect(request.url.queryParameters['query'], 'the matrix');
|
|
return _json({
|
|
'page': 1,
|
|
'totalPages': 1,
|
|
'results': [
|
|
{'id': 603, 'mediaType': 'movie', 'title': 'The Matrix', 'releaseDate': '1999-03-30'},
|
|
{'id': 6384, 'mediaType': 'person', 'name': 'Keanu Reeves'},
|
|
],
|
|
});
|
|
}),
|
|
);
|
|
final items = await source.search('the matrix');
|
|
expect(items.single.title, 'The Matrix');
|
|
expect(items.single.ids.tmdb, 603);
|
|
});
|
|
|
|
test('fetchRelated proxies the recommendations endpoint and coerces the kind', () async {
|
|
final source = _source(
|
|
MockClient((request) async {
|
|
expect(request.url.path, '/api/v1/movie/603/recommendations');
|
|
return _json({
|
|
'page': 1,
|
|
'totalPages': 1,
|
|
'results': [
|
|
{'id': 604, 'title': 'The Matrix Reloaded', 'releaseDate': '2003-05-15'},
|
|
],
|
|
});
|
|
}),
|
|
);
|
|
final item = CatalogItem(
|
|
source: CatalogSourceId.seerr,
|
|
kind: MediaKind.movie,
|
|
title: 'The Matrix',
|
|
ids: const CatalogItemIds(tmdb: 603),
|
|
);
|
|
final related = await source.fetchRelated(item);
|
|
expect(related.single.title, 'The Matrix Reloaded');
|
|
expect(related.single.kind, MediaKind.movie);
|
|
});
|
|
|
|
test('canRequest honors the per-kind permission split', () {
|
|
// permissions: 2 = ADMIN in the fixture session → everything allowed.
|
|
final source = _source(MockClient((request) async => _json({})));
|
|
expect(source.canRequest(MediaKind.movie), isTrue);
|
|
expect(source.canRequest(MediaKind.show), isTrue);
|
|
});
|
|
|
|
test('has no watchlist: membership unknown, mutations unsupported', () async {
|
|
final source = _source(MockClient((request) async => _json({})));
|
|
expect(source.supportsWatchlist, isFalse);
|
|
expect(source.isOnWatchlist(MediaKind.movie, const CatalogItemIds(tmdb: 603)), isNull);
|
|
expect(() => source.addToWatchlist(MediaKind.movie, const CatalogItemIds(tmdb: 603)), throwsUnsupportedError);
|
|
});
|
|
});
|
|
}
|