90 lines
2.7 KiB
Dart
90 lines
2.7 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:archive/archive.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:miaoji_zhang/shared/services/local_export_service.dart';
|
|
|
|
void main() {
|
|
test('local export creates readable CSV and privacy-safe JSON', () {
|
|
final bytes = LocalExportService.buildZipFromSnapshot(
|
|
{
|
|
'schemaVersion': 1,
|
|
'exportedAt': '2026-07-21T00:00:00.000Z',
|
|
'ledgers': [
|
|
{
|
|
'id': 1,
|
|
'name': '日常账本',
|
|
'iconKey': 'wallet',
|
|
'isDefault': true,
|
|
'updatedAt': '2026-07-21T00:00:00.000Z',
|
|
},
|
|
],
|
|
'categories': [
|
|
{
|
|
'id': 2,
|
|
'name': '餐饮',
|
|
'iconKey': 'food',
|
|
'colorKey': 'coral',
|
|
'type': 'expense',
|
|
'sortOrder': 10,
|
|
'isCustom': false,
|
|
'isDeleted': false,
|
|
'updatedAt': '2026-07-21T00:00:00.000Z',
|
|
},
|
|
],
|
|
'transactions': [
|
|
{
|
|
'id': 3,
|
|
'ledgerId': 1,
|
|
'categoryId': 2,
|
|
'categoryName': '餐饮',
|
|
'categoryIcon': 'food',
|
|
'categoryColor': 'coral',
|
|
'type': 'expense',
|
|
'amount': 12.5,
|
|
'note': '午饭,"套餐"\n已报销',
|
|
'paymentMethod': '微信',
|
|
'source': 'manual',
|
|
'sourceText': null,
|
|
'occurredAt': '2026-07-21T04:00:00.000Z',
|
|
'isDeleted': false,
|
|
'updatedAt': '2026-07-21T04:00:00.000Z',
|
|
},
|
|
],
|
|
'budgets': [
|
|
{
|
|
'ledgerId': 1,
|
|
'period': 202607,
|
|
'categoryId': 2,
|
|
'amount': 800.0,
|
|
'recurring': true,
|
|
'updatedAt': '2026-07-21T00:00:00.000Z',
|
|
},
|
|
],
|
|
},
|
|
profile: const {'mode': 'guest', 'nickname': '游客'},
|
|
);
|
|
|
|
final archive = ZipDecoder().decodeBytes(bytes);
|
|
expect(
|
|
archive.map((file) => file.name),
|
|
containsAll(['transactions.csv', 'budgets.csv', 'jizhi-backup.json']),
|
|
);
|
|
|
|
final transactionCsv = utf8.decode(
|
|
archive.findFile('transactions.csv')!.readBytes()!,
|
|
);
|
|
expect(transactionCsv, contains('12.50'));
|
|
expect(transactionCsv, contains('"午饭,""套餐""\n已报销"'));
|
|
|
|
final json = utf8.decode(
|
|
archive.findFile('jizhi-backup.json')!.readBytes()!,
|
|
);
|
|
final document = jsonDecode(json) as Map<String, dynamic>;
|
|
expect(document['transactions'], hasLength(1));
|
|
expect((document['profile'] as Map)['mode'], 'guest');
|
|
expect(json, isNot(contains('passwordHash')));
|
|
expect(json, isNot(contains('local_db_key')));
|
|
});
|
|
}
|