import 'package:flutter_test/flutter_test.dart'; import 'package:miaoji_zhang/shared/services/local_database.dart'; void main() { test('本地转账按方向统计并按稳定身份幂等', () { final database = LocalDatabase.inMemoryForTesting(); addTearDown(database.close); database.upsertBudget(2026, 7, 1, null, 100, false); database.upsertBudget(2026, 7, 1, 1, 80, false); final transferOut = { 'ledgerId': 1, 'categoryId': 1, 'type': 'transfer', 'transferDirection': 'out', 'counterparty': '张三', 'amount': 40, 'occurredAt': '2026-07-25T03:00:00.000Z', 'source': 'accessibility', 'clientRequestId': 'wx-event-out-a', 'provider': 'wechat', 'providerTransactionId': 'wx-order-out-001', 'recognitionOccurrenceId': 'wx-occurrence-out-a', }; final createdOut = database.createTransaction(transferOut); final providerRetry = database.createTransaction({ ...transferOut, 'clientRequestId': 'wx-event-out-b', 'recognitionOccurrenceId': 'wx-occurrence-out-b', }); expect(providerRetry['id'], createdOut['id']); final transferIn = { 'ledgerId': 1, 'categoryId': 101, 'type': 'transfer', 'transferDirection': 'in', 'counterparty': '张三', 'amount': 75, 'occurredAt': '2026-07-25T03:05:00.000Z', 'source': 'accessibility', 'clientRequestId': 'wx-event-in-a', 'recognitionOccurrenceId': 'wx-occurrence-in-001', }; final createdIn = database.createTransaction(transferIn); final occurrenceRetry = database.createTransaction({ ...transferIn, 'clientRequestId': 'wx-event-in-b', }); expect(occurrenceRetry['id'], createdIn['id']); final month = database.monthSummary(2026, 7, 1); expect(month['count'], 2); expect(month['expense'], 40); expect(month['income'], 75); expect(month['balance'], 35); final stats = database.periodStats('month', DateTime(2026, 7, 25), 1); expect(stats['totalExpense'], 40); expect(stats['totalIncome'], 75); final budgets = database.budgets(2026, 7, 1); expect((budgets['total'] as Map)['spent'], 40); expect( ((budgets['categories'] as List).single as Map)['spent'], 40, ); }); test('本地数据库拒绝缺少方向的转账', () { final database = LocalDatabase.inMemoryForTesting(); addTearDown(database.close); expect( () => database.createTransaction({ 'ledgerId': 1, 'categoryId': 1, 'type': 'transfer', 'amount': 20, 'occurredAt': '2026-07-25T03:00:00.000Z', }), throwsStateError, ); }); test('云端回写失败时保留待同步的本地账单', () { final database = LocalDatabase.inMemoryForTesting(); addTearDown(database.close); final local = database.createTransaction({ 'ledgerId': 1, 'categoryId': 1, 'type': 'expense', 'amount': 28, 'occurredAt': '2026-07-25T03:00:00.000Z', 'source': 'manual', }); final localId = local['id'] as int; expect( () => database.replaceLocalTransaction(localId, { ...local, 'id': 42, 'occurredAt': 'invalid-time', }), throwsFormatException, ); expect(database.transaction(localId), isNotNull); expect(database.transaction(42), isNull); }); }