import 'dart:convert'; import 'package:flutter_test/flutter_test.dart'; import 'package:nontonki/core/data/models/engagement_snapshot.dart'; import 'package:nontonki/core/data/repositories/engagement_repository.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'; /// Mirrors the private key used by [SharedPreferencesEngagementRepository]. const _key = 'engagement.v1.demo-local-v1'; void main() { late SharedPreferencesAsync preferences; setUp(() { SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.empty(); preferences = SharedPreferencesAsync(); }); SharedPreferencesEngagementRepository repository() => SharedPreferencesEngagementRepository(preferences: preferences); Future loadRaw(String raw) async { await preferences.setString(_key, raw); return repository().load(); } test('a first launch reads an empty snapshot', () async { final snapshot = await repository().load(); expect(snapshot.savedDramaIds, isEmpty); expect(snapshot.likedDramaIds, isEmpty); expect(snapshot.commentsByDrama, isEmpty); }); test('a snapshot survives a save and reload round trip', () async { await repository().save( const EngagementSnapshot( savedDramaIds: {'signal', 'city'}, likedDramaIds: {'city'}, commentsByDrama: { 'signal': ['first note', 'second note'], }, ), ); final loaded = await repository().load(); expect(loaded.savedDramaIds, {'signal', 'city'}); expect(loaded.likedDramaIds, {'city'}); expect(loaded.commentsByDrama, { 'signal': ['first note', 'second note'], }); }); test('an empty snapshot round trips as empty collections', () async { await repository().save(const EngagementSnapshot()); final loaded = await repository().load(); expect(loaded.savedDramaIds, isEmpty); expect(loaded.likedDramaIds, isEmpty); expect(loaded.commentsByDrama, isEmpty); }); test('corrupt or non-object payloads fall back to an empty snapshot', () async { for (final raw in [ '', 'not json at all', '[]', '"a bare string"', '42', 'null', ]) { final snapshot = await loadRaw(raw); expect(snapshot.savedDramaIds, isEmpty, reason: raw); expect(snapshot.likedDramaIds, isEmpty, reason: raw); expect(snapshot.commentsByDrama, isEmpty, reason: raw); } }); test('wrongly typed fields are dropped instead of throwing', () async { final snapshot = await loadRaw( jsonEncode({ 'saved': 'signal', 'liked': {'city': true}, 'comments': { 'signal': 'a plain string', 'city': ['kept', 7, null, true], 'town': [], }, }), ); expect(snapshot.savedDramaIds, isEmpty); expect(snapshot.likedDramaIds, isEmpty); expect(snapshot.commentsByDrama, { 'city': ['kept'], 'town': [], }); }); test('a payload missing keys falls back per field', () async { final snapshot = await loadRaw(jsonEncode({'saved': ['signal']})); expect(snapshot.savedDramaIds, {'signal'}); expect(snapshot.likedDramaIds, isEmpty); expect(snapshot.commentsByDrama, isEmpty); }); test('save writes only json primitives', () async { await repository().save( const EngagementSnapshot( savedDramaIds: {'signal'}, likedDramaIds: {'city'}, commentsByDrama: { 'signal': ['note'], }, ), ); final raw = await preferences.getString(_key); expect(raw, isNotNull); final decoded = jsonDecode(raw!) as Map; expect(decoded['saved'], ['signal']); expect(decoded['liked'], ['city']); expect(decoded['comments'], { 'signal': ['note'], }); }); }