import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:jj_mkvmaker/app/delete_ops.dart'; import 'package:jj_mkvmaker/core/app_trash.dart'; import 'package:path/path.dart' as p; import 'support/fake_recycle_bin.dart' show realRecycleSkip; /// E5b 약속 시험: lib/app/delete_ops.dart 맨 위 약속. 시험 폴더의 실제 파일 · 실제 앱 휴지통 (가짜 없음). /// Windows 휴지통은 실제 사용자 휴지통이라 JJ_TEST_REAL_RECYCLE=1 일 때만 (끝나면 되살려 흔적 없음). void main() { if (!Platform.isWindows) return; // 열려 있는 파일을 못 지우는 것은 Windows late Directory tmp; late String a, b, dir, locked; late RandomAccessFile hold; setUp(() { tmp = Directory.systemTemp.createTempSync('jj_del_'); a = p.join(tmp.path, 'a.txt'); b = p.join(tmp.path, 'b.txt'); dir = p.join(tmp.path, 'Show'); locked = p.join(tmp.path, 'locked.txt'); File(a).writeAsStringSync('a'); File(b).writeAsStringSync('b'); Directory(dir).createSync(); File(p.join(dir, 'ep.mkv')).writeAsStringSync('x'); File(locked).writeAsStringSync('l'); hold = File(locked).openSync(mode: FileMode.append); // Windows: 열려 있는 파일은 지울 수 없다 }); tearDown(() { hold.closeSync(); tmp.deleteSync(recursive: true); }); test('영구: 하나가 실패해도 나머지는 지우고 실패를 이유와 함께 (열려 있는 파일)', () async { final r = await deletePaths([a, locked, dir], permanent: true); expect(File(a).existsSync(), isFalse); expect(Directory(dir).existsSync(), isFalse); expect([for (final (x, _) in r.failed) x], [locked]); expect(File(locked).existsSync(), isTrue); expect(r.failed.single.$2, isNotEmpty); expect([r.sent, r.trashed, r.tooLong], everyElement(isEmpty)); }); test('앱 휴지통: 보내고 되살림 · 못 보낸 것은 몰래 지우지 않고 보고 · deleteForever', () async { final trash = AppTrash([tmp.path]); final outside = Directory.systemTemp.createTempSync('jj_del_out_'); addTearDown(() => outside.deleteSync(recursive: true)); final far = p.join(outside.path, 'far.txt'); File(far).writeAsStringSync('f'); final r = await deletePaths([a, dir, far], permanent: false, trash: trash); expect([File(a).existsSync(), Directory(dir).existsSync()], [false, false]); expect(r.undoable, [a, dir]); expect(r.recycled, 2); expect([for (final (x, _) in r.notTrashed) x], [far], reason: '저장 장치 밖'); expect(File(far).existsSync(), isTrue, reason: '몰래 영구 삭제하지 않음'); final back = await undoTrash(trash, r.trashed); expect(back.length, 2); expect([File(a).existsSync(), File(p.join(dir, 'ep.mkv')).existsSync()], [true, true]); expect([for (final (x, _) in await deleteForever([far, locked])) x], [locked]); expect(File(far).existsSync(), isFalse); expect(deleteFailReason(const FileSystemException('x', 'y', OSError('잠김', 32))), '잠김'); }); test('Windows 휴지통: 보내고 되돌림 (실제 휴지통)', () async { final r = await deletePaths([a, b], permanent: false); expect(r.sent, [a, b]); expect(r.recycled, 2); expect(File(a).existsSync(), isFalse); final u = undoRecycle(r.sent, r.since); expect(u.back, 2); expect(u.failed, isEmpty); expect([File(a).existsSync(), File(b).existsSync()], [true, true]); }, skip: realRecycleSkip); }