// 2026-04-22 | test_export_import.dart | 数据导出/导入逻辑验证 | 验证JSON格式正确性和导入识别 // 运行: dart run scripts/test_export_import.dart import 'dart:convert'; import 'dart:io'; // ─── 模拟核心逻辑 ─── enum DataSource { favorites('❤️ 收藏', 'favorites'), shoppingList('🛒 购物清单', 'shopping_list'), mealRecords('🍽️ 饮食记录', 'meal_records'), cookingNotes('📝 烹饪笔记', 'cooking_notes'), weeklyMenu('📅 每周菜单', 'weekly_menu'), browseHistory('👀 浏览记录', 'browse_history'); final String label; final String fileName; const DataSource(this.label, this.fileName); } String _exportSingleSourceJson(DataSource source) { switch (source) { case DataSource.favorites: return const JsonEncoder.withIndent(' ').convert([ {'id': 1, 'title': '红烧肉', 'favoriteType': 'recipe', 'favoriteAt': '2026-04-22'}, ]); case DataSource.shoppingList: return const JsonEncoder.withIndent(' ').convert([ {'name': '鸡蛋', 'amount': '3', 'unit': '个', 'isChecked': false}, ]); case DataSource.mealRecords: return const JsonEncoder.withIndent(' ').convert([ {'date': '2026-04-22', 'mealType': 'lunch', 'recipeId': 1}, ]); case DataSource.cookingNotes: return const JsonEncoder.withIndent(' ').convert([ {'recipeId': 1, 'content': '少放盐', 'tags': ['tips']}, ]); case DataSource.weeklyMenu: return const JsonEncoder.withIndent(' ').convert({ 'weekStart': '2026-04-21', 'dailyMenus': {'Mon': {'breakfast': 1}}, }); case DataSource.browseHistory: return const JsonEncoder.withIndent(' ').convert([ {'recipeId': 1, 'title': '红烧肉', 'viewCount': 3, 'viewedAt': '2026-04-22'}, ]); } } /// 新版 exportAll:先构建Map再编码 String exportAllNew() { final Map allData = {}; for (final source in DataSource.values) { final content = _exportSingleSourceJson(source); try { allData[source.fileName] = jsonDecode(content); } catch (e) { print(' ⚠️ 解码 ${source.fileName} 失败: $e'); } } return const JsonEncoder.withIndent(' ').convert(allData); } /// previewImport:标准格式识别 + List格式自动推断 ({Map sourceCounts, String? error}) previewImport(String jsonContent) { final result = {}; try { final decoded = jsonDecode(jsonContent); if (decoded is Map) { for (final source in DataSource.values) { if (decoded.containsKey(source.fileName)) { final data = decoded[source.fileName]; if (data is List) { result[source] = data.length; } else if (data is Map && source == DataSource.weeklyMenu) { result[source] = data.length; } } } } else if (decoded is List) { if (decoded.isNotEmpty && decoded.first is Map) { final inferred = _inferDataSource(decoded.first as Map); result[inferred ?? DataSource.favorites] = decoded.length; } else { result[DataSource.favorites] = decoded.length; } } } catch (e) { return (sourceCounts: result, error: e.toString()); } return (sourceCounts: result, error: null); } DataSource? _inferDataSource(Map item) { if (item.containsKey('favoriteType') || item.containsKey('favoriteAt')) return DataSource.favorites; if (item.containsKey('isChecked') && item.containsKey('amount')) return DataSource.shoppingList; if (item.containsKey('mealType') && item.containsKey('date')) return DataSource.mealRecords; if (item.containsKey('recipeId') && item.containsKey('content')) return DataSource.cookingNotes; if (item.containsKey('dailyMenus') || item.containsKey('weekStart')) return DataSource.weeklyMenu; if (item.containsKey('viewCount') && item.containsKey('viewedAt')) return DataSource.browseHistory; return null; } // ─── 测试 ─── void main() { print('╔══════════════════════════════════════════════════╗'); print('║ 📦 数据导出/导入 逻辑验证 ║'); print('╚══════════════════════════════════════════════════╝\n'); testFullExport(); testSingleSourceImport(); print('\n╔══════════════════════════════════════════════════╗'); print('║ ✅ 全部测试完成 ║'); print('╚══════════════════════════════════════════════════╝'); } void testFullExport() { print('━━━ 1. 全量导出JSON格式验证 ━━━'); final json = exportAllNew(); try { final decoded = jsonDecode(json) as Map; print(' ✅ JSON可解析,${decoded.length} 个数据源'); for (final key in decoded.keys) { final val = decoded[key]; final count = val is List ? val.length : (val is Map ? val.length : 0); print(' - "$key": ${val.runtimeType} ($count项)'); } } catch (e) { print(' ❌ JSON解析失败: $e'); return; } final preview = previewImport(json); if (preview.error != null) { print(' ❌ previewImport失败: ${preview.error}'); } else { print(' ✅ 识别 ${preview.sourceCounts.length}/${DataSource.values.length} 个数据源'); for (final entry in preview.sourceCounts.entries) { print(' - ${entry.key.label}: ${entry.value} 条'); } } print(''); } void testSingleSourceImport() { print('━━━ 2. 单数据源导入自动推断 ━━━'); for (final source in DataSource.values) { final json = _exportSingleSourceJson(source); final preview = previewImport(json); if (preview.sourceCounts.isNotEmpty) { final e = preview.sourceCounts.entries.first; final ok = e.key == source ? '✅' : '⚠️ 偏移'; print(' $ok ${source.label} → 推断为 ${e.key.label} (${e.value}条)'); } else { print(' ❌ ${source.label} 无法识别'); } } print(''); }