import 'dart:typed_data'; import 'package:flutter/widgets.dart'; import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/domain/models/album/album.model.dart'; import 'package:immich_mobile/domain/models/album/local_album.model.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/asset_edit.model.dart'; import 'package:immich_mobile/domain/models/exif.model.dart'; import 'package:immich_mobile/domain/models/tag.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/platform/native_sync_api.g.dart'; import 'package:immich_mobile/services/foreground_upload.service.dart'; import 'package:immich_mobile/utils/option.dart'; import 'package:maplibre_gl/maplibre_gl.dart'; import 'package:mocktail/mocktail.dart' as mock; import 'package:mocktail/mocktail.dart'; import '../infrastructure/repository.mock.dart'; import '../repository.mocks.dart'; import '../service.mocks.dart'; import 'factories/local_album_factory.dart'; import 'factories/local_asset_factory.dart'; import 'factories/remote_album_factory.dart'; import 'factories/user_factory.dart'; class RepositoryMocks { final localAlbum = LocalAlbumRepositoryStub(MockLocalAlbumRepository()); final localAsset = LocalAssetRepositoryStub(MockDriftLocalAssetRepository()); final remoteAsset = RemoteAssetRepositoryStub(MockRemoteAssetRepository()); final remoteExif = RemoteExifRepositoryStub(MockRemoteExifRepository()); final trashedAsset = MockTrashedLocalAssetRepository(); final remoteAlbum = MockRemoteAlbumRepository(); final albumApi = MockDriftAlbumApiRepository(); final nativeApi = NativeSyncApiStub(MockNativeSyncApi()); final assetApi = AssetApiRepositoryStub(MockAssetApiRepository()); final assetMedia = AssetMediaRepositoryStub(MockAssetMediaRepository()); final download = DownloadRepositoryStub(MockDownloadRepository()); RepositoryMocks() { resetAll(); } void resetAll() { _registerFallbacks(); localAlbum.reset(); localAsset.reset(); remoteAsset.reset(); remoteExif.reset(); reset(trashedAsset); reset(remoteAlbum); reset(albumApi); nativeApi.reset(); assetApi.reset(); assetMedia.reset(); download.reset(); _stubLocalAlbumRepository(); _stubLocalAssetRepository(); _stubRemoteAssetRepository(); _stubRemoteExifRepository(); _stubNativeSyncApi(); _stubAssetApiRepository(); _stubAssetMediaRepository(); _stubDownloadRepository(); } void _stubRemoteAssetRepository() { when(remoteAsset.getExif).thenAnswer((_) async => null); when(remoteAsset.getAssetEdits).thenAnswer((_) async => const []); when(remoteAsset.update).thenAnswer((_) async {}); } void _stubRemoteExifRepository() { when(remoteExif.update).thenAnswer((_) async {}); } void _stubLocalAlbumRepository() { when(localAlbum.getBackupAlbums).thenAnswer((_) async => []); when(localAlbum.getAssetsToHash).thenAnswer((_) async => []); } void _stubLocalAssetRepository() { when(localAsset.reconcileHashesFromCloudId).thenAnswer((_) async => {}); when(localAsset.updateHashes).thenAnswer((_) async => {}); } void _stubNativeSyncApi() { when(nativeApi.hashAssets).thenAnswer((_) async => []); } void _stubAssetApiRepository() { when(assetApi.update).thenAnswer((_) async => {}); } void _stubAssetMediaRepository() { when(assetMedia.shareAssets).thenAnswer((_) async => 1); when(assetMedia.getOriginalFilename).thenAnswer((_) async => null); } void _stubDownloadRepository() { when(download.downloadAllAssets).thenAnswer((_) async => const []); } } class ServiceMocks { final partner = PartnerServiceStub(MockPartnerService()); final user = UserServiceStub(MockUserService()); final asset = AssetServiceStub(MockAssetService()); final album = RemoteAlbumServiceStub(MockRemoteAlbumService()); final cleanup = CleanupServiceStub(MockCleanupService()); final tag = TagServiceStub(MockTagService()); final backgroundSync = MockBackgroundSyncManager(); final upload = MockForegroundUploadService(); final cast = MockGCastService(); final serverInfo = MockServerInfoService(); final toast = MockToastService(); ServiceMocks() { resetAll(); } void resetAll() { _registerFallbacks(); partner.reset(); user.reset(); asset.reset(); album.reset(); cleanup.reset(); tag.reset(); reset(cast); reset(serverInfo); reset(backgroundSync); reset(upload); reset(toast); _stubUserService(); _stubPartnerService(); _stubAssetService(); _stubRemoteAlbumService(); _stubCleanupService(); _stubTagService(); _stubBackgroundSync(); _stubForegroundUpload(); } void _stubUserService() { when(user.getMyUser).thenReturn(UserFactory.createDto()); when(user.tryGetMyUser).thenReturn(null); when(user.watchMyUser).thenAnswer((_) => const Stream.empty()); when(user.refreshMyUser).thenAnswer((_) async => null); when(user.createProfileImage).thenAnswer((_) async => null); } void _stubPartnerService() { registerFallbackValue(PartnerDirection.sharedBy); when(partner.getCandidates).thenAnswer((_) => const Stream.empty()); when(partner.search).thenAnswer((_) => const Stream.empty()); when(partner.update).thenAnswer((_) async {}); when(partner.create).thenAnswer((_) async {}); when(partner.delete).thenAnswer((_) async {}); } void _stubAssetService() { when(asset.update).thenAnswer((_) async {}); when(asset.stack).thenAnswer((_) async {}); when(asset.unstack).thenAnswer((_) async {}); when(asset.restoreTrash).thenAnswer((_) async {}); when(asset.trash).thenAnswer((_) async {}); when(asset.delete).thenAnswer((_) async {}); when(asset.applyEdits).thenAnswer((_) async {}); when(asset.deleteLocal).thenAnswer((_) async => 0); } void _stubRemoteAlbumService() { when(album.removeAssets).thenAnswer((_) async => 0); when(album.updateAlbum).thenAnswer((_) async => RemoteAlbumFactory.create()); } void _stubCleanupService() { when(cleanup.deleteLocalAssets).thenAnswer((_) async => 0); } void _stubTagService() { when(tag.bulkTagAssets).thenAnswer((_) async => 0); when(tag.upsertTags).thenAnswer((_) async => const []); when(tag.getAllTags).thenAnswer((_) async => const {}); } void _stubBackgroundSync() { when(() => backgroundSync.syncLocal()).thenAnswer((_) async {}); when(() => backgroundSync.hashAssets()).thenAnswer((_) async {}); } void _stubForegroundUpload() { when( () => upload.uploadManual( any(), cancelToken: any(named: 'cancelToken'), callbacks: any(named: 'callbacks'), ), ).thenAnswer((_) async {}); } } void _registerFallbacks() { registerFallbackValue(LocalAlbumFactory.create()); registerFallbackValue(LocalAssetFactory.create()); registerFallbackValue(Uint8List(0)); registerFallbackValue(AssetVisibility.timeline); registerFallbackValue(const LatLng(0, 0)); registerFallbackValue([]); registerFallbackValue(const Option.none()); registerFallbackValue(const Option.none()); registerFallbackValue(const Option.none()); registerFallbackValue(const Option.none()); registerFallbackValue(const Option.none()); registerFallbackValue([]); registerFallbackValue([]); registerFallbackValue([]); registerFallbackValue(ShareAssetType.original); registerFallbackValue(const UploadCallbacks()); registerFallbackValue(_FakeBuildContext()); } class _FakeBuildContext extends Fake implements BuildContext {} extension type const Stub(T mockedClass) { void reset() => mock.reset(mockedClass); } extension type const LocalAlbumRepositoryStub(MockLocalAlbumRepository repo) implements Stub { Future> Function() get getBackupAlbums => () => repo.getBackupAlbums(); Future> Function() get getAssetsToHash => () => repo.getAssetsToHash(any()); } extension type const LocalAssetRepositoryStub(MockDriftLocalAssetRepository repo) implements Stub { Future Function() get reconcileHashesFromCloudId => () => repo.reconcileHashesFromCloudId(); Future Function() get updateHashes => () => repo.updateHashes(any()); } extension type const RemoteAssetRepositoryStub(MockRemoteAssetRepository repo) implements Stub { Future Function() get getExif => () => repo.getExif(any()); Future> Function() get getAssetEdits => () => repo.getAssetEdits(any()); Future Function() get update => () => repo.update( any(), isFavorite: any(named: 'isFavorite'), visibility: any(named: 'visibility'), createdAt: any(named: 'createdAt'), ); } extension type const RemoteExifRepositoryStub(MockRemoteExifRepository repo) implements Stub { Future Function() get update => () => repo.update( any(), dateTimeOriginal: any(named: 'dateTimeOriginal'), timeZone: any(named: 'timeZone'), location: any(named: 'location'), ); } extension type const PartnerServiceStub(MockPartnerService service) implements Stub { Stream> Function() get getCandidates => () => service.getCandidates(any()); Stream> Function() get search => () => service.search(any(), any()); Future Function() get create => () => service.create( sharedById: any(named: 'sharedById'), sharedWithId: any(named: 'sharedWithId'), inTimeline: any(named: 'inTimeline'), ); Future Function() get update => () => service.update( sharedById: any(named: 'sharedById'), sharedWithId: any(named: 'sharedWithId'), inTimeline: any(named: 'inTimeline'), ); Future Function() get delete => () => service.delete( sharedById: any(named: 'sharedById'), sharedWithId: any(named: 'sharedWithId'), ); } extension type const UserServiceStub(MockUserService service) implements Stub { UserDto Function() get getMyUser => () => service.getMyUser(); UserDto? Function() get tryGetMyUser => () => service.tryGetMyUser(); Stream Function() get watchMyUser => () => service.watchMyUser(); Future Function() get refreshMyUser => () => service.refreshMyUser(); Future Function() get createProfileImage => () => service.createProfileImage(any(), any()); } extension type const AssetServiceStub(MockAssetService service) implements Stub { Future Function() get update => () => service.update( any(), isFavorite: any(named: 'isFavorite'), visibility: any(named: 'visibility'), dateTime: any(named: 'dateTime'), location: any(named: 'location'), ); Future Function() get stack => () => service.stack(any(), any()); Future Function() get unstack => () => service.unstack(any()); Future Function() get restoreTrash => () => service.restoreTrash(any()); Future Function() get trash => () => service.trash(any()); Future Function() get delete => () => service.delete(any()); Future Function() get applyEdits => () => service.applyEdits(any(), any()); Future Function() get deleteLocal => () => service.deleteLocal(any()); } extension type const RemoteAlbumServiceStub(MockRemoteAlbumService service) implements Stub { Future Function() get removeAssets => () => service.removeAssets( albumId: any(named: 'albumId'), assetIds: any(named: 'assetIds'), ); Future Function() get updateAlbum => () => service.updateAlbum(any(), thumbnailAssetId: any(named: 'thumbnailAssetId')); } extension type const CleanupServiceStub(MockCleanupService service) implements Stub { Future Function() get deleteLocalAssets => () => service.deleteLocalAssets(any()); } extension type const NativeSyncApiStub(MockNativeSyncApi api) implements Stub { Future> Function() get hashAssets => () => api.hashAssets(any(), allowNetworkAccess: any(named: 'allowNetworkAccess')); } extension type const AssetApiRepositoryStub(MockAssetApiRepository api) implements Stub { Future Function() get update => () => api.update( any(), isFavorite: any(named: 'isFavorite'), visibility: any(named: 'visibility'), dateTimeOriginal: any(named: 'dateTimeOriginal'), location: any(named: 'location'), ); } extension type const AssetMediaRepositoryStub(MockAssetMediaRepository api) implements Stub { Future Function() get shareAssets => () => api.shareAssets( any(), any(), fileType: any(named: 'fileType'), cancelCompleter: any(named: 'cancelCompleter'), onAssetDownloadProgress: any(named: 'onAssetDownloadProgress'), ); Future Function() get getOriginalFilename => () => api.getOriginalFilename(any()); } extension type const DownloadRepositoryStub(MockDownloadRepository repo) implements Stub { Future> Function() get downloadAllAssets => () => repo.downloadAllAssets(any()); } extension type const TagServiceStub(MockTagService service) implements Stub { Future Function() get bulkTagAssets => () => service.bulkTagAssets(any(), any()); Future> Function() get upsertTags => () => service.upsertTags(any()); Future> Function() get getAllTags => () => service.getAllTags(); }