test: scaffolding + first provider test (hidden_libraries)

This commit is contained in:
edde746
2026-04-25 12:56:38 +02:00
parent 87696d77d1
commit edff1f29db
5 changed files with 136 additions and 1 deletions
@@ -56,6 +56,15 @@ abstract class BaseSharedPreferencesService {
}();
}
/// Drop all cached singleton instances and the shared cache future so the
/// next `getInstance()` call rebuilds against the current
/// `SharedPreferences.setMockInitialValues(...)`. Test-only.
@visibleForTesting
static void resetForTesting() {
_instances.clear();
_cacheFuture = null;
}
/// Typed read helpers — return the stored value or [defaultValue] when missing.
bool readBool(String key, {bool defaultValue = false}) => _cache.getBool(key) ?? defaultValue;
int readInt(String key, {int defaultValue = 0}) => _cache.getInt(key) ?? defaultValue;
+1 -1
View File
@@ -1063,7 +1063,7 @@ packages:
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
dependency: "direct dev"
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
+1
View File
@@ -79,6 +79,7 @@ dev_dependencies:
slang_build_runner: ^4.14.0
dart_code_linter: ^3.2.1
drift_dev: ^2.28.3
shared_preferences_platform_interface: ^2.4.0
dependency_overrides:
auto_updater_platform_interface:
@@ -0,0 +1,109 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/providers/hidden_libraries_provider.dart';
import 'package:plezy/services/base_shared_preferences_service.dart';
import 'package:plezy/services/storage_service.dart';
import '../test_helpers/prefs.dart';
void main() {
setUp(resetSharedPreferencesForTest);
group('HiddenLibrariesProvider', () {
test('starts uninitialized and exposes empty set', () async {
final p = HiddenLibrariesProvider();
expect(p.isInitialized, isFalse);
expect(p.hiddenLibraryKeys, isEmpty);
await p.ensureInitialized();
expect(p.isInitialized, isTrue);
expect(p.hiddenLibraryKeys, isEmpty);
p.dispose();
});
test('hideLibrary persists key and notifies listeners', () async {
final p = HiddenLibrariesProvider();
await p.ensureInitialized();
var notified = 0;
p.addListener(() => notified++);
await p.hideLibrary('lib-1');
expect(p.isLibraryHidden('lib-1'), isTrue);
expect(p.hiddenLibraryKeys, contains('lib-1'));
expect(notified, 1);
// Same key again → no-op, no extra notification
await p.hideLibrary('lib-1');
expect(notified, 1);
p.dispose();
});
test('persists across provider instances via SharedPreferences', () async {
final first = HiddenLibrariesProvider();
await first.ensureInitialized();
await first.hideLibrary('lib-A');
await first.hideLibrary('lib-B');
first.dispose();
// Reset only the cached singleton, NOT SharedPreferences — values survive.
BaseSharedPreferencesService.resetForTesting();
final second = HiddenLibrariesProvider();
await second.ensureInitialized();
expect(second.isLibraryHidden('lib-A'), isTrue);
expect(second.isLibraryHidden('lib-B'), isTrue);
expect(second.isLibraryHidden('lib-C'), isFalse);
second.dispose();
});
test('unhideLibrary removes the key', () async {
final p = HiddenLibrariesProvider();
await p.ensureInitialized();
await p.hideLibrary('lib-1');
await p.hideLibrary('lib-2');
await p.unhideLibrary('lib-1');
expect(p.isLibraryHidden('lib-1'), isFalse);
expect(p.isLibraryHidden('lib-2'), isTrue);
// Unhiding an already-absent key is a no-op
await p.unhideLibrary('lib-3');
expect(p.hiddenLibraryKeys, equals({'lib-2'}));
p.dispose();
});
test('refresh re-reads from storage', () async {
final p = HiddenLibrariesProvider();
await p.ensureInitialized();
expect(p.hiddenLibraryKeys, isEmpty);
// Mutate underlying storage out-of-band, then refresh.
final storage = await StorageService.getInstance();
await storage.saveHiddenLibraries({'external-1', 'external-2'});
await p.refresh();
expect(p.hiddenLibraryKeys, equals({'external-1', 'external-2'}));
p.dispose();
});
test('hiddenLibraryKeys returns an unmodifiable view', () async {
final p = HiddenLibrariesProvider();
await p.ensureInitialized();
await p.hideLibrary('lib-1');
expect(() => p.hiddenLibraryKeys.add('mutated'), throwsUnsupportedError);
p.dispose();
});
test('safeNotifyListeners no-ops after dispose', () async {
final p = HiddenLibrariesProvider();
await p.ensureInitialized();
p.dispose();
// Should not throw, even though notifyListeners after dispose normally does.
await p.refresh();
});
});
}
+16
View File
@@ -0,0 +1,16 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/services/base_shared_preferences_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart';
/// Reset shared-prefs platform mocks AND the cached singleton instances.
/// Call from `setUp` so each test starts with a clean slate.
void resetSharedPreferencesForTest({Map<String, Object> initialAsync = const {}}) {
TestWidgetsFlutterBinding.ensureInitialized();
SharedPreferences.setMockInitialValues({});
SharedPreferencesAsyncPlatform.instance = initialAsync.isEmpty
? InMemorySharedPreferencesAsync.empty()
: InMemorySharedPreferencesAsync.withData(initialAsync);
BaseSharedPreferencesService.resetForTesting();
}