1
This commit is contained in:
@@ -120,33 +120,33 @@ void main() {
|
||||
await tester.tap(finder);
|
||||
}
|
||||
|
||||
testWidgets('未下载:显示使用按钮,点击后下载完成自动变为已使用', (tester) async {
|
||||
testWidgets('未下载:显示下载按钮,点击后下载完成自动变为使用中', (tester) async {
|
||||
final m = manager([_item()]);
|
||||
await tester.runAsync(() => m.refresh());
|
||||
await pumpSection(tester, m);
|
||||
|
||||
expect(find.text('数据集A'), findsOneWidget);
|
||||
expect(find.text('使用'), findsOneWidget);
|
||||
expect(find.text('下载'), findsOneWidget);
|
||||
|
||||
await tapVisible(tester, find.text('使用'));
|
||||
await tapVisible(tester, find.text('下载'));
|
||||
await tester.pump(); // 下载启动,进度条出现
|
||||
// 驱动下载 + 自动激活的 IO 链走完,直至 UI 呈现「已使用」
|
||||
await pumpUntilFound(tester, find.text('已使用'));
|
||||
// 驱动下载 + 自动激活的 IO 链走完,直至 UI 呈现「使用中」
|
||||
await pumpUntilFound(tester, find.text('使用中'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(m.isDownloaded(7, kVariantS), isTrue);
|
||||
expect(m.isActive(7, kVariantS), isTrue);
|
||||
expect(find.text('已使用'), findsOneWidget);
|
||||
expect(find.text('使用中'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('已激活:再次点击取消使用', (tester) async {
|
||||
testWidgets('已激活:点击使用中取消使用', (tester) async {
|
||||
final m = manager([_item()]);
|
||||
await tester.runAsync(() => m.refresh());
|
||||
await tester.runAsync(() => m.downloadModel(m.catalog.first));
|
||||
await pumpSection(tester, m);
|
||||
|
||||
expect(find.text('已使用'), findsOneWidget);
|
||||
await tapVisible(tester, find.text('已使用'));
|
||||
expect(find.text('使用中'), findsOneWidget);
|
||||
await tapVisible(tester, find.text('使用中'));
|
||||
// 排空 setActive 的激活集重载与落盘 IO,直至 UI 呈现「使用」
|
||||
await pumpUntilFound(tester, find.text('使用'));
|
||||
await tester.pumpAndSettle();
|
||||
@@ -169,7 +169,7 @@ void main() {
|
||||
expect(find.text('暂无已发布模型'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('下载中:显示进度和取消按钮,取消后恢复使用', (tester) async {
|
||||
testWidgets('下载中:显示进度和取消按钮,取消后恢复下载', (tester) async {
|
||||
final m = ModelManager(
|
||||
baseUrl: 'http://test.local',
|
||||
client: _StreamingClient(),
|
||||
@@ -178,83 +178,156 @@ void main() {
|
||||
await tester.runAsync(() => m.refresh());
|
||||
await pumpSection(tester, m);
|
||||
|
||||
await tapVisible(tester, find.text('使用'));
|
||||
await tapVisible(tester, find.text('下载'));
|
||||
// 首个分块到达,进度条与取消按钮出现(IO 链需交替驱动)
|
||||
await pumpUntilFound(tester, find.text('取消'),
|
||||
fake: const Duration(milliseconds: 400));
|
||||
expect(find.text('取消'), findsOneWidget);
|
||||
|
||||
await tapVisible(tester, find.text('取消'));
|
||||
// 推进 fake 时钟触发延迟分块 → 取消分支清场(.part 删除等真实 IO),直至恢复「使用」
|
||||
await pumpUntilFound(tester, find.text('使用'),
|
||||
// 推进 fake 时钟触发延迟分块 → 取消分支清场(.part 删除等真实 IO),直至恢复「下载」
|
||||
await pumpUntilFound(tester, find.text('下载'),
|
||||
fake: const Duration(milliseconds: 400));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(m.isDownloaded(7, kVariantS), isFalse);
|
||||
expect(m.isActive(7, kVariantS), isFalse);
|
||||
expect(find.text('使用'), findsOneWidget);
|
||||
expect(find.text('下载'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('双档位:s/n 两卡独立,n 档下载备好后切档即用', (tester) async {
|
||||
final m =
|
||||
manager([_item(), _item(variant: kVariantN, name: '数据集B')]);
|
||||
testWidgets('双档位:同物种合并一张卡,下载只启用目标档,使用即停旧档', (tester) async {
|
||||
final m = manager([_item(), _item(variant: kVariantN)]);
|
||||
await tester.runAsync(() => m.refresh());
|
||||
await pumpSection(tester, m);
|
||||
|
||||
// 分段控件默认 s;两卡并排,s 卡按钮「使用」,非当前档 n 卡按钮「下载」
|
||||
expect(find.text('s 高识别'), findsOneWidget);
|
||||
// 合并卡:同一数据集只一张卡,无双卡/无档位角标;双档行标注两档
|
||||
expect(find.text('数据集A'), findsOneWidget);
|
||||
expect(find.text('数据集B'), findsOneWidget);
|
||||
expect(find.text('s'), findsOneWidget, reason: '档位角标');
|
||||
expect(find.text('n'), findsOneWidget, reason: '档位角标');
|
||||
expect(find.text('使用'), findsOneWidget);
|
||||
expect(find.text('下载'), findsOneWidget, reason: '非当前档入口为「下载」');
|
||||
expect(find.text('下载'), findsOneWidget, reason: '合并卡只有一个主按钮');
|
||||
expect(find.textContaining('高精度 v1.0.0'), findsOneWidget);
|
||||
expect(find.textContaining('高性能 v1.0.0'), findsOneWidget);
|
||||
|
||||
// 先激活 s 档
|
||||
await tapVisible(tester, find.text('使用'));
|
||||
await pumpUntilFound(tester, find.text('已使用'));
|
||||
expect(m.isActive(7, kVariantS), isTrue);
|
||||
|
||||
// 下载 n 档:完成后自动备好(n 非当前档),显示「已备好」而非「已使用」
|
||||
// 一次下载取回双档:同物种只启用目标档(默认高精度 s),n 档备好不启用。
|
||||
// 双档下载收尾链交错,等 models 真正重载完成再断言
|
||||
await tapVisible(tester, find.text('下载'));
|
||||
await pumpUntilFound(tester, find.text('已备好'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(m.isActive(7, kVariantN), isTrue);
|
||||
expect(m.mode, kVariantS, reason: '下载非当前档不应改变识别档位');
|
||||
expect(m.models.length, 1);
|
||||
expect(m.models.first.variant, kVariantS, reason: '当前仍只加载 s 档');
|
||||
|
||||
// 点「已备好」切换档位 → n 档立即生效(已使用),s 档转为备好态
|
||||
await tapVisible(tester, find.text('已备好'));
|
||||
// 「已使用」切换前后都在场(s 使用 → n 使用),须等 manager 状态真正切档
|
||||
await pumpUntilFound(tester, find.text('使用中'));
|
||||
for (var i = 0;
|
||||
i < 50 &&
|
||||
!(m.mode == kVariantN &&
|
||||
m.models.isNotEmpty &&
|
||||
m.models.first.variant == kVariantN);
|
||||
!(m.isDownloaded(7, kVariantS) &&
|
||||
m.isDownloaded(7, kVariantN) &&
|
||||
m.isActive(7, kVariantS) &&
|
||||
!m.isActive(7, kVariantN) &&
|
||||
m.models.length == 1 &&
|
||||
m.models.first.variant == kVariantS);
|
||||
i++) {
|
||||
await pumpRealIo(tester);
|
||||
}
|
||||
await tester.pumpAndSettle();
|
||||
expect(m.mode, kVariantN);
|
||||
|
||||
expect(m.isDownloaded(7, kVariantS), isTrue);
|
||||
expect(m.isDownloaded(7, kVariantN), isTrue);
|
||||
expect(m.isActive(7, kVariantS), isTrue);
|
||||
expect(m.isActive(7, kVariantN), isFalse,
|
||||
reason: '同物种同时只运行目标档,另一档备好不叠加启用');
|
||||
expect(m.mode, kVariantS, reason: '下载双档不应改变目标档');
|
||||
expect(m.models.length, 1);
|
||||
expect(m.models.first.variant, kVariantN, reason: '切档后热加载 n 档模型');
|
||||
expect(find.text('已使用'), findsOneWidget, reason: 'n 档卡已使用');
|
||||
expect(find.text('已备好'), findsOneWidget, reason: 's 档转为备好态');
|
||||
expect(m.models.first.variant, kVariantS);
|
||||
expect(find.text('使用中'), findsOneWidget);
|
||||
|
||||
// 目标档切到高性能:运行中的 s 不受影响;n 已下载未启用 → 主按钮「使用」
|
||||
// (保存目标档偏好是真实 IO,等按钮呈现才算 UI 落定;2026-09-03 简化:
|
||||
// 不再叫「改用X」、不显示「当前使用 X」提示)
|
||||
await tapVisible(tester, find.text('高性能'));
|
||||
await pumpUntilFound(tester, find.text('使用'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(m.mode, kVariantN);
|
||||
expect(m.isActive(7, kVariantS), isTrue,
|
||||
reason: '切换目标档不应改变运行中的模型');
|
||||
expect(find.text('使用'), findsOneWidget);
|
||||
expect(find.textContaining('当前使用'), findsNothing);
|
||||
|
||||
// 点「使用」:同物种 s 自动停用,n 热启用(setActive 尾部的落盘
|
||||
// 与 notify 是真实 IO,等 UI 呈现「使用中」才算整链落定)
|
||||
await tapVisible(tester, find.text('使用'));
|
||||
await pumpUntilFound(tester, find.text('使用中'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(m.isActive(7, kVariantS), isFalse, reason: '启用目标档自动停用另一档');
|
||||
expect(m.isActive(7, kVariantN), isTrue);
|
||||
expect(m.models.length, 1);
|
||||
expect(m.models.first.variant, kVariantN);
|
||||
expect(find.text('使用中'), findsOneWidget, reason: '主按钮跟随当前档');
|
||||
});
|
||||
|
||||
testWidgets('识别模式分段控件:点击切档生效', (tester) async {
|
||||
final m = manager([_item(), _item(variant: kVariantN, name: '数据集A')]);
|
||||
testWidgets('不同动物可用不同档位:使用只作用于点击的动物', (tester) async {
|
||||
final m = manager([
|
||||
_item(datasetId: 7, name: '数据集A'),
|
||||
_item(datasetId: 7, variant: kVariantN, name: '数据集A'),
|
||||
_item(datasetId: 8, name: '数据集B'),
|
||||
_item(datasetId: 8, variant: kVariantN, name: '数据集B'),
|
||||
]);
|
||||
await tester.runAsync(() => m.refresh());
|
||||
// 两个物种都下载并运行默认档(高精度 s),各自 n 档备好
|
||||
for (final it in m.catalog) {
|
||||
await tester.runAsync(() => m.downloadModel(it));
|
||||
}
|
||||
await pumpSection(tester, m);
|
||||
|
||||
await tapVisible(tester, find.text('n 高性能'));
|
||||
for (var i = 0; i < 50 && m.mode != kVariantN; i++) {
|
||||
expect(m.models.length, 2);
|
||||
expect(find.text('使用中'), findsNWidgets(2));
|
||||
|
||||
// 目标档切高性能:两卡主按钮都变「使用」(各自 s 仍在运行、n 已备好)
|
||||
await tapVisible(tester, find.text('高性能'));
|
||||
await pumpUntilFound(tester, find.text('使用'));
|
||||
expect(find.text('使用'), findsNWidgets(2));
|
||||
|
||||
// 只点第一张卡(数据集 7,目录序在前):该动物切到高性能,另一动物保持高精度
|
||||
await tapVisible(tester, find.text('使用').first);
|
||||
await pumpUntilFound(tester, find.text('使用中')); // 数据集 7 的卡先翻为使用中
|
||||
for (var i = 0;
|
||||
i < 50 &&
|
||||
!(m.models.length == 2 &&
|
||||
m.models.firstWhere((b) => b.datasetId == 7).variant ==
|
||||
kVariantN &&
|
||||
m.models.firstWhere((b) => b.datasetId == 8).variant ==
|
||||
kVariantS);
|
||||
i++) {
|
||||
await pumpRealIo(tester);
|
||||
}
|
||||
await tester.pumpAndSettle();
|
||||
expect(m.mode, kVariantN, reason: '点击分段控件应切档');
|
||||
// 档位持久化(重启恢复)由 model_manager_test「识别档位持久化」覆盖;
|
||||
|
||||
expect(m.isActive(7, kVariantN), isTrue);
|
||||
expect(m.isActive(7, kVariantS), isFalse, reason: '启用目标档自动停用同动物另一档');
|
||||
expect(m.isActive(8, kVariantS), isTrue, reason: '未点击的动物保持原档位');
|
||||
expect(m.isActive(8, kVariantN), isFalse);
|
||||
expect(m.models.length, 2, reason: '两个动物仍同时识别');
|
||||
expect(m.models.firstWhere((b) => b.datasetId == 7).variant, kVariantN);
|
||||
expect(m.models.firstWhere((b) => b.datasetId == 8).variant, kVariantS);
|
||||
expect(find.text('使用中'), findsOneWidget, reason: '只有数据集 7 的卡使用中');
|
||||
expect(find.text('使用'), findsOneWidget,
|
||||
reason: '数据集 8 目标档已备好:按钮就是使用(不叫改用)');
|
||||
expect(find.textContaining('当前使用'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('识别模式分段控件:只改目标档偏好,不影响已在运行的模型', (tester) async {
|
||||
final m = manager([_item(), _item(variant: kVariantN)]);
|
||||
await tester.runAsync(() => m.refresh());
|
||||
await tester.runAsync(() => m.downloadModel(m.catalog.first)); // s 启用
|
||||
await pumpSection(tester, m);
|
||||
|
||||
expect(find.text('高精度'), findsOneWidget, reason: '分段控件选中默认档');
|
||||
expect(find.text('高性能'), findsOneWidget);
|
||||
expect(find.text('使用中'), findsOneWidget);
|
||||
|
||||
await tapVisible(tester, find.text('高性能'));
|
||||
// 目标档 n 尚未下载(之前只下了 s)→ 主按钮变为「下载」:仍不切运行模型
|
||||
await pumpUntilFound(tester, find.text('下载'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(m.mode, kVariantN, reason: '点击分段控件应改目标档');
|
||||
expect(m.isActive(7, kVariantS), isTrue, reason: '只改偏好不切运行模型');
|
||||
expect(m.models.length, 1);
|
||||
expect(m.models.first.variant, kVariantS, reason: '没有热加载/切换');
|
||||
expect(find.text('下载'), findsOneWidget, reason: '卡片按钮面向新目标档');
|
||||
expect(find.textContaining('当前使用'), findsNothing);
|
||||
// 目标档偏好持久化由 model_manager_test「识别目标档位偏好持久化」覆盖;
|
||||
// widget 测试内 tap 触发的文件写与真实 IO 交错不可控,不在本层断言重启
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user