import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:path/path.dart' as path; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:app_boilerplate/core/exceptions/session_exception.dart'; import 'package:app_boilerplate/data/session/session_service.dart'; import 'package:app_boilerplate/data/local/local_storage_service.dart'; import 'package:app_boilerplate/data/local/models/item.dart'; void main() { // Initialize Flutter bindings and sqflite for testing TestWidgetsFlutterBinding.ensureInitialized(); sqfliteFfiInit(); databaseFactory = databaseFactoryFfi; late LocalStorageService localStorage; late SessionService sessionService; late Directory tempDir; late String tempDbPath; setUp(() async { // Create temporary directory for test files tempDir = await Directory.systemTemp.createTemp('session_test_'); tempDbPath = path.join(tempDir.path, 'test_storage.db'); // Initialize local storage service localStorage = LocalStorageService( testDbPath: tempDbPath, testCacheDir: Directory(path.join(tempDir.path, 'cache')), ); await localStorage.initialize(); // Initialize session service with test paths // Each user will get their own subdirectory under tempDir sessionService = SessionService( localStorage: localStorage, syncEngine: null, // No sync engine for basic tests testDbPath: path.join(tempDir.path, 'user_storage.db'), testCacheDir: Directory(path.join(tempDir.path, 'user_cache')), ); }); tearDown(() async { // Close and cleanup try { await localStorage.close(); } catch (_) { // Ignore cleanup errors } // Clean up temporary directory if (await tempDir.exists()) { await tempDir.delete(recursive: true); } }); group('SessionService - Login', () { test('login - success', () async { // Arrange const userId = 'user1'; const username = 'testuser'; // Act final user = await sessionService.login( id: userId, username: username, ); // Assert expect(sessionService.isLoggedIn, isTrue); expect(sessionService.currentUser, isNotNull); expect(sessionService.currentUser!.id, equals(userId)); expect(sessionService.currentUser!.username, equals(username)); expect(user.id, equals(userId)); expect(user.username, equals(username)); }); test('login - with token', () async { // Arrange const userId = 'user1'; const username = 'testuser'; const token = 'auth-token-123'; // Act final user = await sessionService.login( id: userId, username: username, token: token, ); // Assert expect(sessionService.currentUser!.token, equals(token)); expect(user.token, equals(token)); }); test('login - fails when already logged in', () async { // Arrange await sessionService.login(id: 'user1', username: 'user1'); // Act & Assert expect( () => sessionService.login(id: 'user2', username: 'user2'), throwsA(isA()), ); }); }); group('SessionService - Logout', () { test('logout - success', () async { // Arrange await sessionService.login(id: 'user1', username: 'user1'); expect(sessionService.isLoggedIn, isTrue); // Act await sessionService.logout(); // Assert expect(sessionService.isLoggedIn, isFalse); expect(sessionService.currentUser, isNull); }); test('logout - clears cache when clearCache is true', () async { // Arrange await sessionService.login(id: 'user1', username: 'user1'); // Add some data to storage final item = Item( id: 'item1', data: {'test': 'data'}, ); await localStorage.insertItem(item); // Verify data exists final itemsBefore = await localStorage.getAllItems(); expect(itemsBefore.length, equals(1)); // Act await sessionService.logout(clearCache: true); // Assert - data should be cleared // Note: We need to reinitialize storage to check since it was cleared await localStorage.initialize(); final itemsAfter = await localStorage.getAllItems(); expect(itemsAfter.length, equals(0)); }); test('logout - preserves cache when clearCache is false', () async { // Arrange await sessionService.login(id: 'user1', username: 'user1'); // Add some data to storage final item = Item( id: 'item1', data: {'test': 'data'}, ); await localStorage.insertItem(item); // Act await sessionService.logout(clearCache: false); // Assert - data should still exist (in user-specific storage) // Note: Since we're using test paths, the data persists expect(sessionService.isLoggedIn, isFalse); }); test('logout - fails when no user logged in', () async { // Act & Assert expect( () => sessionService.logout(), throwsA(isA()), ); }); }); group('SessionService - Session Switching', () { test('switchSession - success', () async { // Arrange await sessionService.login(id: 'user1', username: 'user1'); expect(sessionService.currentUser!.id, equals('user1')); // Act final newUser = await sessionService.switchSession( id: 'user2', username: 'user2', ); // Assert expect(sessionService.isLoggedIn, isTrue); expect(sessionService.currentUser!.id, equals('user2')); expect(newUser.id, equals('user2')); }); test('switchSession - clears previous user data when clearCache is true', () async { // Arrange await sessionService.login(id: 'user1', username: 'user1'); // Add data for user1 final item1 = Item( id: 'item1', data: {'user': 'user1'}, ); await localStorage.insertItem(item1); // Act - switch to user2 with cache clearing await sessionService.switchSession( id: 'user2', username: 'user2', clearCache: true, ); // Assert - user1 data should be cleared // Reinitialize to check await localStorage.initialize(); final items = await localStorage.getAllItems(); expect(items.length, equals(0)); }); test( 'switchSession - preserves previous user data when clearCache is false', () async { // Arrange await sessionService.login(id: 'user1', username: 'user1'); // Add data for user1 final item1 = Item( id: 'item1', data: {'user': 'user1'}, ); await localStorage.insertItem(item1); // Act - switch to user2 without clearing cache await sessionService.switchSession( id: 'user2', username: 'user2', clearCache: false, ); // Assert - user1 data should still exist in user1's storage // (Note: user2 will have a different storage path) expect(sessionService.currentUser!.id, equals('user2')); }); test('switchSession - works when no user logged in', () async { // Arrange expect(sessionService.isLoggedIn, isFalse); // Act final user = await sessionService.switchSession( id: 'user1', username: 'user1', ); // Assert expect(sessionService.isLoggedIn, isTrue); expect(user.id, equals('user1')); }); }); group('SessionService - Data Isolation', () { test('data isolation - users have separate storage', () async { // Arrange & Act - Login user1 and add data await sessionService.login(id: 'user1', username: 'user1'); final item1 = Item( id: 'item1', data: {'user': 'user1'}, ); await localStorage.insertItem(item1); final user1Items = await localStorage.getAllItems(); expect(user1Items.length, equals(1)); expect(user1Items.first.id, equals('item1')); // Switch to user2 (this will create a new database for user2) await sessionService.switchSession( id: 'user2', username: 'user2', clearCache: false, // Don't clear to test isolation ); // Add data for user2 (should be in user2's database) final item2 = Item( id: 'item2', data: {'user': 'user2'}, ); await localStorage.insertItem(item2); final user2Items = await localStorage.getAllItems(); expect(user2Items.length, equals(1)); expect(user2Items.first.id, equals('item2')); // Switch back to user1 (this will reload user1's database) await sessionService.switchSession( id: 'user1', username: 'user1', clearCache: false, ); // Assert - user1 should only see their data (item1, not item2) final user1ItemsAfter = await localStorage.getAllItems(); expect(user1ItemsAfter.length, equals(1)); expect(user1ItemsAfter.first.id, equals('item1')); expect(user1ItemsAfter.first.data['user'], equals('user1')); }); }); group('SessionService - Cache Clearing', () { test('cache clearing - clears all items on logout', () async { // Arrange await sessionService.login(id: 'user1', username: 'user1'); // Add multiple items await localStorage.insertItem(Item(id: 'item1', data: {'test': '1'})); await localStorage.insertItem(Item(id: 'item2', data: {'test': '2'})); await localStorage.insertItem(Item(id: 'item3', data: {'test': '3'})); final itemsBefore = await localStorage.getAllItems(); expect(itemsBefore.length, equals(3)); // Act await sessionService.logout(clearCache: true); // Assert await localStorage.initialize(); final itemsAfter = await localStorage.getAllItems(); expect(itemsAfter.length, equals(0)); }); }); }