// ai_jobs.dart 약속 시험: 실제 시험 폴더에 파일을 쓰는 할 일로 runTask 의 진행 · 끝 · 오류 · 취소를 본다. import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:jj_mkvmaker/app/ai_jobs.dart'; import 'package:jj_mkvmaker/services/image_ai.dart'; import 'package:path/path.dart' as p; void main() { late Directory dir; setUp(() => dir = Directory.systemTemp.createTempSync('jj_ai_jobs_')); tearDown(() => dir.deleteSync(recursive: true)); test('runTask: 장마다 할 일 · 진행 · "n장 중 m장째" · 끝나면 비움', () async { final jobs = AiJobs(); final lines = []; final done = await jobs.runTask('일', 3, (i, progress) async { File(p.join(dir.path, '$i.txt')).writeAsStringSync('$i'); progress(0.5); lines.add(jobs.statusLine); }, onCancel: () {}, uses: {'sd15'}); expect(done, 3); expect(dir.listSync().length, 3); expect(lines.first, contains('3장 중 1장째')); expect(lines.last, contains('3장 중 3장째')); expect(jobs.busy, isFalse); expect(jobs.inUse, isEmpty); expect(jobs.statusLine, isNull); }); test('runTask: 작업 중에 또 부르면 오류 · 취소하면 그 뒤 장은 하지 않음', () async { final jobs = AiJobs(); var cancelled = false; final run = jobs.runTask('일', 5, (i, _) async { await expectLater(jobs.runTask('또', 1, (_, _) async {}, onCancel: () {}), throwsA(isA())); if (i == 1) jobs.cancel(); }, onCancel: () => cancelled = true); expect(await run, 2); expect(cancelled, isTrue); expect(jobs.busy, isFalse); }); test('runTask: 할 일의 오류는 그대로 · 끝나면 비움', () async { final jobs = AiJobs(); await expectLater(jobs.runTask('일', 2, (_, _) async => throw const FileSystemException('x'), onCancel: () {}), throwsA(isA())); expect(jobs.busy, isFalse); }); test('done · clearDoneView: 다음 일을 시작하면 남긴 것의 dispose 를 부른다', () async { final jobs = AiJobs(); var disposed = 0; jobs.done('끝', dir: dir.path, view: () async {}, dispose: () => disposed++); expect((jobs.lastDone, jobs.lastDoneDir, jobs.lastDoneView != null), ('끝', dir.path, true)); await jobs.runTask('일', 1, (_, _) async {}, onCancel: () {}); expect(disposed, 1); expect(jobs.lastDone, isNull); expect(AiJobs.durationText(const Duration(seconds: 90)), '2분'); expect(AiJobs.durationText(const Duration(seconds: 20)), '20초'); }); }