Files
mail-hub/test/imap_integration_test.dart
hz4th_coder 6c1225f588 MailHub v1.0.0: 跨平台邮箱客户端(纯 Dart IMAP/SMTP/MIME 协议栈)
- 登录: QQ/163/126/189/搜狐/Gmail/Outlook/Yahoo/iCloud/企业邮/自定义, 自动识别+测试连接
- 收信: IMAP 多文件夹同步/未读/星标/搜索(本地+服务器)
- 读信: HTML渲染/CID内嵌图/原文查看/附件下载
- 写信: 收件人/抄送/密送/附件/富文本/草稿/回复转发
- 存储: SQLite + 系统安全存储(DPAPI/Keychain/Keystore)
- 测试: 单元测试 + Mock IMAP/SMTP 服务器集成测试(23项全过)
- 可迁移: Windows/Android/iOS/macOS/Linux 一套代码
2026-08-18 01:10:11 +08:00

108 lines
3.1 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:mail_hub/core/protocol/imap/imap_client.dart';
import 'package:mail_hub/core/protocol/imap/imap_exception.dart';
/// IMAP 客户端集成测试:连接本地 Mock 服务器,验证完整协议交互
void main() {
Process? server;
int port = 0;
setUpAll(() async {
// 找一个可用端口
final probe = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
port = probe.port;
await probe.close();
server = await Process.start('python3', [
'test/mock_imap_server.py',
'$port',
'--auth-user',
'test@example.com',
'--auth-pass',
'secret',
]);
// 等待就绪
await server!.stdout.transform(utf8.decoder).first;
});
tearDownAll(() async {
server?.kill();
});
test('完整流程:连接→登录→列文件夹→选收件箱→搜索→抓元数据→抓全文→置标→登出',
() async {
final client = ImapClient();
await client.connect('127.0.0.1', port, ssl: false);
expect(client.isConnected, true);
// 登录(AUTH=PLAIN
await client.login('test@example.com', 'secret');
expect(client.hasCapability('AUTH=PLAIN'), true);
// 列文件夹
final folders = await client.listFolders();
expect(folders.length, 3);
expect(folders[0].name, 'INBOX');
expect(folders[2].name, '[Gmail]');
expect(folders[2].attrs, contains(r'\Noselect'));
// 选收件箱
final info = await client.select('INBOX');
expect(info.exists, 3);
expect(info.uidNext, 10);
expect(info.readWrite, true);
// 搜索
final all = await client.search('ALL');
expect(all, [1, 2, 3]);
// 抓元数据(含 HEADER.FIELDS 字面量)
final metas = await client.fetchMeta([1, 2, 3]);
expect(metas.length, 3);
final m1 = metas.firstWhere((m) => m.uid == 1);
expect(m1.seen, true);
expect(m1.flagged, false);
expect(m1.size, 1234);
expect(m1.internalDate, isNotNull);
// 抓全文(HEADER + TEXT 两段字面量)
final full = await client.fetchFull(1);
expect(full.bodies.containsKey('HEADER'), true);
expect(full.bodies.containsKey('TEXT'), true);
final headerText = latin1.decode(full.bodies['HEADER']!);
expect(headerText, contains('Subject:'));
expect(headerText, contains('zhangsan@example.com'));
// 置标
await client.markSeen([2]);
await client.markFlagged([1, 2]);
// 登出
client.logout();
client.disconnect();
expect(client.isConnected, false);
});
test('认证失败抛出 ImapAuthException', () async {
final client = ImapClient();
await client.connect('127.0.0.1', port, ssl: false);
await expectLater(
client.login('test@example.com', 'wrong-password'),
throwsA(isA<ImapAuthException>()),
);
client.disconnect();
});
test('连接被拒抛出 ImapConnectionException', () async {
final client = ImapClient();
// 端口 1 (tcpmux) 通常无服务 → 连接拒绝
await expectLater(
client.connect('127.0.0.1', 1, ssl: false),
throwsA(isA<ImapConnectionException>()),
);
});
}