mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
test: add blacklist provider test
This commit is contained in:
parent
252edfb73f
commit
95ee8e694e
@ -25,7 +25,7 @@ import 'package:spotube/extensions/image.dart';
|
||||
import 'package:spotube/models/database/database.dart';
|
||||
import 'package:spotube/models/local_track.dart';
|
||||
import 'package:spotube/provider/authentication/authentication.dart';
|
||||
import 'package:spotube/provider/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/blacklist/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/download_manager_provider.dart';
|
||||
import 'package:spotube/provider/local_tracks/local_tracks_provider.dart';
|
||||
import 'package:spotube/provider/audio_player/audio_player.dart';
|
||||
|
@ -23,7 +23,7 @@ import 'package:spotube/extensions/image.dart';
|
||||
import 'package:spotube/models/local_track.dart';
|
||||
import 'package:spotube/provider/audio_player/querying_track_info.dart';
|
||||
import 'package:spotube/provider/audio_player/state.dart';
|
||||
import 'package:spotube/provider/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/blacklist/blacklist_provider.dart';
|
||||
import 'package:spotube/utils/platform.dart';
|
||||
|
||||
class TrackTile extends HookConsumerWidget {
|
||||
|
@ -65,12 +65,12 @@ Future<void> main(List<String> rawArgs) async {
|
||||
|
||||
AppLogger.runZoned(() async {
|
||||
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
||||
MediaKit.ensureInitialized();
|
||||
|
||||
getIt.registerSingleton(await SharedPreferences.getInstance());
|
||||
getIt.registerSingletonWithDependencies(
|
||||
() => KVStoreService.init(),
|
||||
dependsOn: [SharedPreferences],
|
||||
getIt.registerSingleton<SharedPreferences>(
|
||||
await SharedPreferences.getInstance(),
|
||||
);
|
||||
getIt.registerSingleton(KVStoreService.init());
|
||||
getIt.registerLazySingleton<AppDatabase>(() => AppDatabase());
|
||||
getIt.registerSingleton(SpotubeAudioPlayer());
|
||||
getIt.registerSingleton<WindowManager>(windowManager);
|
||||
@ -81,8 +81,6 @@ Future<void> main(List<String> rawArgs) async {
|
||||
|
||||
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
||||
|
||||
MediaKit.ensureInitialized();
|
||||
|
||||
await migrateMacOsFromSandboxToNoSandbox();
|
||||
|
||||
// force High Refresh Rate on some Android devices (like One Plus)
|
||||
|
@ -10,7 +10,7 @@ import 'package:spotube/components/image/universal_image.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/extensions/image.dart';
|
||||
|
||||
import 'package:spotube/provider/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/blacklist/blacklist_provider.dart';
|
||||
|
||||
class ArtistCard extends HookConsumerWidget {
|
||||
final Artist artist;
|
||||
|
@ -11,7 +11,7 @@ import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/extensions/image.dart';
|
||||
import 'package:spotube/models/database/database.dart';
|
||||
import 'package:spotube/provider/authentication/authentication.dart';
|
||||
import 'package:spotube/provider/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/blacklist/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/spotify/spotify.dart';
|
||||
import 'package:spotube/utils/primitive_utils.dart';
|
||||
|
||||
|
@ -10,7 +10,7 @@ import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart';
|
||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||
import 'package:spotube/components/ui/button_tile.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/provider/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/blacklist/blacklist_provider.dart';
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
|
||||
@RoutePage()
|
||||
|
@ -10,7 +10,7 @@ import 'package:spotube/extensions/track.dart';
|
||||
import 'package:spotube/models/database/database.dart';
|
||||
import 'package:spotube/models/local_track.dart';
|
||||
import 'package:spotube/provider/audio_player/state.dart';
|
||||
import 'package:spotube/provider/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/blacklist/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/discord_provider.dart';
|
||||
import 'package:spotube/provider/server/sourced_track.dart';
|
||||
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||
|
@ -1,128 +0,0 @@
|
||||
// ignore_for_file: unused_local_variable, unused_import
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift_dev/api/migrations.dart';
|
||||
import 'package:spotube/models/database/database.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'generated/schema.dart';
|
||||
|
||||
import 'generated/schema_v1.dart' as v1;
|
||||
import 'generated/schema_v2.dart' as v2;
|
||||
|
||||
void main() {
|
||||
driftRuntimeOptions.dontWarnAboutMultipleDatabases = true;
|
||||
late SchemaVerifier verifier;
|
||||
|
||||
setUpAll(() {
|
||||
verifier = SchemaVerifier(GeneratedHelper());
|
||||
});
|
||||
|
||||
group('simple database migrations', () {
|
||||
// These simple tests verify all possible schema updates with a simple (no
|
||||
// data) migration. This is a quick way to ensure that written database
|
||||
// migrations properly alter the schema.
|
||||
const versions = GeneratedHelper.versions;
|
||||
for (final (i, fromVersion) in versions.indexed) {
|
||||
group('from $fromVersion', () {
|
||||
for (final toVersion in versions.skip(i + 1)) {
|
||||
test('to $toVersion', () async {
|
||||
final schema = await verifier.schemaAt(fromVersion);
|
||||
final db = AppDatabase(schema.newConnection());
|
||||
await verifier.migrateAndValidate(db, toVersion);
|
||||
await db.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Simple tests ensure the schema is transformed correctly, but some
|
||||
// migrations benefit from a test verifying that data is transformed correctly
|
||||
// too. This is particularly true for migrations that change existing columns
|
||||
// (e.g. altering their type or constraints). Migrations that only add tables
|
||||
// or columns typically don't need these advanced tests.
|
||||
// TODO: Check whether you have migrations that could benefit from these tests
|
||||
// and adapt this example to your database if necessary:
|
||||
test("migration from v1 to v2 does not corrupt data", () async {
|
||||
// Add data to insert into the old database, and the expected rows after the
|
||||
// migration.
|
||||
final oldAuthenticationTableData = <v1.AuthenticationTableData>[];
|
||||
final expectedNewAuthenticationTableData = <v2.AuthenticationTableData>[];
|
||||
|
||||
final oldBlacklistTableData = <v1.BlacklistTableData>[];
|
||||
final expectedNewBlacklistTableData = <v2.BlacklistTableData>[];
|
||||
|
||||
final oldPreferencesTableData = <v1.PreferencesTableData>[];
|
||||
final expectedNewPreferencesTableData = <v2.PreferencesTableData>[];
|
||||
|
||||
final oldScrobblerTableData = <v1.ScrobblerTableData>[];
|
||||
final expectedNewScrobblerTableData = <v2.ScrobblerTableData>[];
|
||||
|
||||
final oldSkipSegmentTableData = <v1.SkipSegmentTableData>[];
|
||||
final expectedNewSkipSegmentTableData = <v2.SkipSegmentTableData>[];
|
||||
|
||||
final oldSourceMatchTableData = <v1.SourceMatchTableData>[];
|
||||
final expectedNewSourceMatchTableData = <v2.SourceMatchTableData>[];
|
||||
|
||||
final oldAudioPlayerStateTableData = <v1.AudioPlayerStateTableData>[];
|
||||
final expectedNewAudioPlayerStateTableData =
|
||||
<v2.AudioPlayerStateTableData>[];
|
||||
|
||||
final oldPlaylistTableData = <v1.PlaylistTableData>[];
|
||||
final expectedNewPlaylistTableData = <v2.PlaylistTableData>[];
|
||||
|
||||
final oldPlaylistMediaTableData = <v1.PlaylistMediaTableData>[];
|
||||
final expectedNewPlaylistMediaTableData = <v2.PlaylistMediaTableData>[];
|
||||
|
||||
final oldHistoryTableData = <v1.HistoryTableData>[];
|
||||
final expectedNewHistoryTableData = <v2.HistoryTableData>[];
|
||||
|
||||
final oldLyricsTableData = <v1.LyricsTableData>[];
|
||||
final expectedNewLyricsTableData = <v2.LyricsTableData>[];
|
||||
|
||||
await verifier.testWithDataIntegrity(
|
||||
oldVersion: 1,
|
||||
newVersion: 2,
|
||||
createOld: v1.DatabaseAtV1.new,
|
||||
createNew: v2.DatabaseAtV2.new,
|
||||
openTestedDatabase: (x) => AppDatabase(),
|
||||
createItems: (batch, oldDb) {
|
||||
batch.insertAll(oldDb.authenticationTable, oldAuthenticationTableData);
|
||||
batch.insertAll(oldDb.blacklistTable, oldBlacklistTableData);
|
||||
batch.insertAll(oldDb.preferencesTable, oldPreferencesTableData);
|
||||
batch.insertAll(oldDb.scrobblerTable, oldScrobblerTableData);
|
||||
batch.insertAll(oldDb.skipSegmentTable, oldSkipSegmentTableData);
|
||||
batch.insertAll(oldDb.sourceMatchTable, oldSourceMatchTableData);
|
||||
batch.insertAll(
|
||||
oldDb.audioPlayerStateTable, oldAudioPlayerStateTableData);
|
||||
batch.insertAll(oldDb.playlistTable, oldPlaylistTableData);
|
||||
batch.insertAll(oldDb.playlistMediaTable, oldPlaylistMediaTableData);
|
||||
batch.insertAll(oldDb.historyTable, oldHistoryTableData);
|
||||
batch.insertAll(oldDb.lyricsTable, oldLyricsTableData);
|
||||
},
|
||||
validateItems: (newDb) async {
|
||||
expect(expectedNewAuthenticationTableData,
|
||||
await newDb.select(newDb.authenticationTable).get());
|
||||
expect(expectedNewBlacklistTableData,
|
||||
await newDb.select(newDb.blacklistTable).get());
|
||||
expect(expectedNewPreferencesTableData,
|
||||
await newDb.select(newDb.preferencesTable).get());
|
||||
expect(expectedNewScrobblerTableData,
|
||||
await newDb.select(newDb.scrobblerTable).get());
|
||||
expect(expectedNewSkipSegmentTableData,
|
||||
await newDb.select(newDb.skipSegmentTable).get());
|
||||
expect(expectedNewSourceMatchTableData,
|
||||
await newDb.select(newDb.sourceMatchTable).get());
|
||||
expect(expectedNewAudioPlayerStateTableData,
|
||||
await newDb.select(newDb.audioPlayerStateTable).get());
|
||||
expect(expectedNewPlaylistTableData,
|
||||
await newDb.select(newDb.playlistTable).get());
|
||||
expect(expectedNewPlaylistMediaTableData,
|
||||
await newDb.select(newDb.playlistMediaTable).get());
|
||||
expect(expectedNewHistoryTableData,
|
||||
await newDb.select(newDb.historyTable).get());
|
||||
expect(expectedNewLyricsTableData,
|
||||
await newDb.select(newDb.lyricsTable).get());
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
250
test/providers/blacklist/blacklist_provider_test.dart
Normal file
250
test/providers/blacklist/blacklist_provider_test.dart
Normal file
@ -0,0 +1,250 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:riverpod/riverpod.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/collections/fake.dart';
|
||||
import 'package:spotube/collections/vars.dart';
|
||||
import 'package:spotube/models/current_playlist.dart';
|
||||
import 'package:spotube/models/database/database.dart';
|
||||
import 'package:spotube/provider/blacklist/blacklist_provider.dart';
|
||||
|
||||
import '../create_container.dart';
|
||||
|
||||
void main() {
|
||||
group('BlacklistProvider', () {
|
||||
late ProviderContainer container;
|
||||
|
||||
setUp(() {
|
||||
getIt.registerLazySingleton<AppDatabase>(() {
|
||||
final database = AppDatabase(NativeDatabase.memory());
|
||||
|
||||
addTearDown(() {
|
||||
database.close();
|
||||
});
|
||||
|
||||
return database;
|
||||
});
|
||||
|
||||
container = createContainer();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
getIt.reset();
|
||||
});
|
||||
|
||||
test('initially should return empty list', () async {
|
||||
final blackList = container.read(blacklistProvider.future);
|
||||
|
||||
await expectLater(blackList, completion(isEmpty));
|
||||
});
|
||||
|
||||
test('add should add item to blacklist', () async {
|
||||
final blacklistRef =
|
||||
container.listen(blacklistProvider.future, (_, __) {});
|
||||
|
||||
await expectLater(blacklistRef.read(), completion(isEmpty));
|
||||
|
||||
final item = BlacklistTableCompanion.insert(
|
||||
id: const Value(20),
|
||||
name: 'Test',
|
||||
elementId: 'test',
|
||||
elementType: BlacklistedType.track,
|
||||
);
|
||||
|
||||
final res = container.read(blacklistProvider.notifier).add(item);
|
||||
|
||||
await expectLater(res, completes);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
await expectLater(blacklistRef.read(), completion(isNotEmpty));
|
||||
|
||||
await expectLater(
|
||||
blacklistRef.read(),
|
||||
completion(
|
||||
contains(
|
||||
predicate<BlacklistTableData>(
|
||||
(e) =>
|
||||
e.name == 'Test' &&
|
||||
e.elementId == 'test' &&
|
||||
e.elementType == BlacklistedType.track,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('remove should remove item from blacklist', () async {
|
||||
final blacklistRef =
|
||||
container.listen(blacklistProvider.future, (_, __) {});
|
||||
|
||||
await expectLater(blacklistRef.read(), completion(isEmpty));
|
||||
|
||||
final item = BlacklistTableCompanion.insert(
|
||||
id: const Value(20),
|
||||
name: 'Test',
|
||||
elementId: 'test',
|
||||
elementType: BlacklistedType.track,
|
||||
);
|
||||
|
||||
final res = container.read(blacklistProvider.notifier).add(item);
|
||||
|
||||
await expectLater(res, completes);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
await expectLater(blacklistRef.read(), completion(isNotEmpty));
|
||||
|
||||
final removeRes = container
|
||||
.read(blacklistProvider.notifier)
|
||||
.remove(item.elementId.value);
|
||||
|
||||
await expectLater(removeRes, completes);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
await expectLater(blacklistRef.read(), completion(isEmpty));
|
||||
});
|
||||
|
||||
group('contains', () {
|
||||
test('should be true if track exists', () async {
|
||||
final item = BlacklistTableCompanion.insert(
|
||||
id: const Value(20),
|
||||
name: 'Test',
|
||||
elementId: FakeData.track.id!,
|
||||
elementType: BlacklistedType.track,
|
||||
);
|
||||
|
||||
final res = container.read(blacklistProvider.notifier).add(item);
|
||||
|
||||
await expectLater(res, completes);
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
final track = FakeData.track as TrackSimple;
|
||||
|
||||
final contains =
|
||||
container.read(blacklistProvider.notifier).contains(track);
|
||||
|
||||
expect(contains, isTrue);
|
||||
});
|
||||
|
||||
test('should be true if track does not exist but artist of track exists',
|
||||
() async {
|
||||
final item = BlacklistTableCompanion.insert(
|
||||
id: const Value(20),
|
||||
name: 'Test',
|
||||
elementId: FakeData.track.artists!.first.id!,
|
||||
elementType: BlacklistedType.artist,
|
||||
);
|
||||
|
||||
final res = container.read(blacklistProvider.notifier).add(item);
|
||||
|
||||
await expectLater(res, completes);
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
final contains =
|
||||
container.read(blacklistProvider.notifier).contains(FakeData.track);
|
||||
|
||||
expect(contains, isTrue);
|
||||
});
|
||||
});
|
||||
|
||||
group('containsArtist', () {
|
||||
test('should be true for artist that exists', () async {
|
||||
final item = BlacklistTableCompanion.insert(
|
||||
id: const Value(20),
|
||||
name: 'Test',
|
||||
elementId: FakeData.artist.id!,
|
||||
elementType: BlacklistedType.artist,
|
||||
);
|
||||
|
||||
final res = container.read(blacklistProvider.notifier).add(item);
|
||||
|
||||
await expectLater(res, completes);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
expect(
|
||||
container
|
||||
.read(blacklistProvider.notifier)
|
||||
.containsArtist(FakeData.artist),
|
||||
isTrue);
|
||||
});
|
||||
|
||||
test('should be false for artist that is not blacklisted', () async {
|
||||
await expectLater(container.read(blacklistProvider.future), completes);
|
||||
|
||||
expect(
|
||||
container
|
||||
.read(blacklistProvider.notifier)
|
||||
.containsArtist(FakeData.artist),
|
||||
isFalse,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('filter', () {
|
||||
test('should return non-blacklisted tracks only', () async {
|
||||
final tracks = List.generate(
|
||||
10,
|
||||
(e) => Track.fromJson({
|
||||
...FakeData.track.toJson(),
|
||||
'id': 'test-$e',
|
||||
}),
|
||||
);
|
||||
|
||||
final blacklist = container.read(blacklistProvider.future);
|
||||
|
||||
await expectLater(blacklist, completion(isEmpty));
|
||||
|
||||
final item = BlacklistTableCompanion.insert(
|
||||
id: const Value(20),
|
||||
name: 'Test',
|
||||
elementId: tracks.first.id!,
|
||||
elementType: BlacklistedType.track,
|
||||
);
|
||||
final res = container.read(blacklistProvider.notifier).add(item);
|
||||
await expectLater(res, completes);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
final filteredTracks =
|
||||
container.read(blacklistProvider.notifier).filter(tracks);
|
||||
|
||||
expect(filteredTracks, isNotEmpty);
|
||||
expect(filteredTracks.length, 9);
|
||||
expect(
|
||||
filteredTracks,
|
||||
isNot(contains(
|
||||
predicate<Track>(
|
||||
(e) => e.id == tracks.first.id,
|
||||
),
|
||||
)),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('filterPlaylist should not modify anything but tracks', () async {
|
||||
final playlist = CurrentPlaylist(
|
||||
id: "lol",
|
||||
name: "name",
|
||||
thumbnail: "thumbnail",
|
||||
tracks: [],
|
||||
);
|
||||
|
||||
final blacklist = container.read(blacklistProvider.future);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
await expectLater(blacklist, completion(isEmpty));
|
||||
|
||||
final res =
|
||||
container.read(blacklistProvider.notifier).filterPlaylist(playlist);
|
||||
|
||||
expect(res.id, playlist.id);
|
||||
expect(res.name, playlist.name);
|
||||
expect(res.thumbnail, playlist.thumbnail);
|
||||
});
|
||||
});
|
||||
}
|
@ -32,7 +32,7 @@ void main() {
|
||||
getIt.registerSingleton<SpotubeAudioPlayer>(MockSpotubeAudioPlayer());
|
||||
getIt.registerSingleton<KVStoreService>(MockKVStoreService());
|
||||
getIt.registerSingleton<WindowManager>(mockWindowManager);
|
||||
getIt.registerLazySingleton(
|
||||
getIt.registerLazySingleton<AppDatabase>(
|
||||
() {
|
||||
final database = AppDatabase(NativeDatabase.memory());
|
||||
|
||||
@ -69,8 +69,12 @@ void main() {
|
||||
getIt.reset();
|
||||
});
|
||||
|
||||
test('Initial value should be equal the default values', () {
|
||||
test('Initial value should be equal the default values', () async {
|
||||
when(() => audioPlayer.setAudioNormalization(any()))
|
||||
.thenAnswer((_) async {});
|
||||
|
||||
final preferences = container.read(userPreferencesProvider);
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
final defaultPreferences = PreferencesTable.defaults();
|
||||
|
||||
expect(preferences, defaultPreferences);
|
||||
|
@ -26,5 +26,5 @@ void main() {
|
||||
// Verify that our counter has incremented.
|
||||
expect(find.text('0'), findsNothing);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}, skip: true);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user