123 lines
4.3 KiB
Dart
123 lines
4.3 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:sharedinbox/core/models/account.dart';
|
|
import 'package:sharedinbox/core/storage/secure_storage.dart';
|
|
import 'package:sharedinbox/data/repositories/account_repository_impl.dart';
|
|
|
|
import 'db_test_helper.dart';
|
|
|
|
// ── Fake ──────────────────────────────────────────────────────────────────────
|
|
|
|
class MapSecureStorage implements SecureStorage {
|
|
final _map = <String, String>{};
|
|
|
|
@override
|
|
Future<void> write({required String key, required String? value}) async {
|
|
if (value == null) {
|
|
_map.remove(key);
|
|
} else {
|
|
_map[key] = value;
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<String?> read({required String key}) async => _map[key];
|
|
|
|
@override
|
|
Future<void> delete({required String key}) async => _map.remove(key);
|
|
}
|
|
|
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
|
|
const _account = Account(
|
|
id: 'acc-1',
|
|
displayName: 'Alice',
|
|
email: 'alice@example.com',
|
|
imapHost: 'imap.example.com',
|
|
smtpHost: 'smtp.example.com',
|
|
);
|
|
|
|
AccountRepositoryImpl _makeRepo() =>
|
|
AccountRepositoryImpl(openTestDatabase(), MapSecureStorage());
|
|
|
|
// ── Tests ─────────────────────────────────────────────────────────────────────
|
|
|
|
void main() {
|
|
setUpAll(configureSqliteForTests);
|
|
|
|
group('AccountRepositoryImpl', () {
|
|
test('observeAccounts emits empty list initially', () async {
|
|
final repo = _makeRepo();
|
|
final accounts = await repo.observeAccounts().first;
|
|
expect(accounts, isEmpty);
|
|
});
|
|
|
|
test('addAccount then observeAccounts emits the account', () async {
|
|
final repo = _makeRepo();
|
|
await repo.addAccount(_account, 'secret');
|
|
final accounts = await repo.observeAccounts().first;
|
|
expect(accounts, hasLength(1));
|
|
expect(accounts.first.id, 'acc-1');
|
|
expect(accounts.first.email, 'alice@example.com');
|
|
});
|
|
|
|
test('getAccount returns null for unknown id', () async {
|
|
final repo = _makeRepo();
|
|
expect(await repo.getAccount('unknown'), isNull);
|
|
});
|
|
|
|
test('getAccount returns the account after addAccount', () async {
|
|
final repo = _makeRepo();
|
|
await repo.addAccount(_account, 'secret');
|
|
final result = await repo.getAccount('acc-1');
|
|
expect(result, isNotNull);
|
|
expect(result!.displayName, 'Alice');
|
|
});
|
|
|
|
test('getPassword returns stored password', () async {
|
|
final repo = _makeRepo();
|
|
await repo.addAccount(_account, 'mypassword');
|
|
expect(await repo.getPassword('acc-1'), 'mypassword');
|
|
});
|
|
|
|
test('getPassword throws StateError when no password stored', () async {
|
|
final repo = _makeRepo();
|
|
expect(() => repo.getPassword('missing'), throwsA(isA<StateError>()));
|
|
});
|
|
|
|
test('removeAccount deletes account and password', () async {
|
|
final repo = _makeRepo();
|
|
await repo.addAccount(_account, 'secret');
|
|
await repo.removeAccount('acc-1');
|
|
|
|
expect(await repo.getAccount('acc-1'), isNull);
|
|
expect(() => repo.getPassword('acc-1'), throwsA(isA<StateError>()));
|
|
});
|
|
|
|
test('addAccount is idempotent (upsert)', () async {
|
|
final repo = _makeRepo();
|
|
await repo.addAccount(_account, 'v1');
|
|
const updated = Account(
|
|
id: 'acc-1',
|
|
displayName: 'Alice Updated',
|
|
email: 'alice@example.com',
|
|
imapHost: 'imap.example.com',
|
|
smtpHost: 'smtp.example.com',
|
|
);
|
|
await repo.addAccount(updated, 'v2');
|
|
final accounts = await repo.observeAccounts().first;
|
|
expect(accounts, hasLength(1));
|
|
expect(accounts.first.displayName, 'Alice Updated');
|
|
expect(await repo.getPassword('acc-1'), 'v2');
|
|
});
|
|
|
|
test('observeAccounts reflects removal', () async {
|
|
final repo = _makeRepo();
|
|
await repo.addAccount(_account, 'secret');
|
|
await repo.removeAccount('acc-1');
|
|
final accounts = await repo.observeAccounts().first;
|
|
expect(accounts, isEmpty);
|
|
});
|
|
});
|
|
}
|