144 긴 경로 지우기: 휴지통에 넣지 못한 이유는 한 줄 · 이름만 · [그대로 두기] / [영구 삭제 (n개, 되돌릴 수 없음)]
- 휴지통이 받지 않는 긴 경로 (260자 넘음) 는 LongPathException 으로 따로 모아, 실패 창 위에 이유 한 줄과 이름만 - [영구 삭제] 는 그 항목만 지우고 결과를 알림. 긴 경로가 없으면 예전처럼 [확인] - 시험: 긴 경로 폴더 → 이유 한 줄 · [그대로 두기] 면 남음 · [영구 삭제] 면 지움 - recycle_bin_test: 148 의 "원래 폴더 없음" 시험이 휴지통에 남긴 것을 정확히 그 폴더로 찾아 지우게 (사용자 휴지통에 남던 것) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>묶음3
parent
e1e3316d8d
commit
f97f63df79
|
|
@ -333,6 +333,7 @@
|
|||
"{0}개는 휴지통보다 커서 영구 삭제했습니다 (Windows 가 물은 대로).": "{0} were too large for the Recycle Bin and were deleted permanently (as Windows asked).",
|
||||
"{0}개는 휴지통에 들어가지 않아 영구 삭제했습니다 (Windows 가 묻고 고른 대로).": "{0} didn't fit in the Recycle Bin and were deleted permanently (as chosen when Windows asked).",
|
||||
"{0}개를 \"기타 즐겨찾기\" 에 가져왔습니다.": "Imported {0} into \"Other bookmarks\".",
|
||||
"{0}개를 영구 삭제했습니다.": "Permanently deleted {0} item(s).",
|
||||
"{0}개를 옮겼습니다 → {1}": "Moved {0} → {1}",
|
||||
"{0}개를 옮겼습니다 → {1} ({2})": "Moved {0} → {1} ({2})",
|
||||
"{0}개를 찾아 여기서 멈췄습니다. 이름을 더 자세히 넣거나 아래 폴더로 들어가 찾으세요.": "Stopped after finding {0}. Enter a more specific name or search inside a subfolder.",
|
||||
|
|
@ -406,6 +407,7 @@
|
|||
"경로": "Path",
|
||||
"경로 입력": "Enter path",
|
||||
"경로 입력 (예: D:\\영상 · \\\\NAS\\공유)": "Enter path (e.g. D:\\Videos · \\\\NAS\\share)",
|
||||
"경로가 너무 길어 휴지통에 넣을 수 없습니다 (Windows 의 휴지통은 260자 넘는 경로를 받지 않습니다).": "The path is too long for the Recycle Bin (the Windows Recycle Bin does not accept paths over 260 characters).",
|
||||
"경로가 너무 깁니다 (Windows 의 휴지통은 260자 넘는 경로를 받지 않습니다) - 영구 삭제로 지울 수 있습니다": "The path is too long (the Windows Recycle Bin doesn't accept paths over 260 characters) - you can delete it permanently",
|
||||
"계속": "Always",
|
||||
"계속 (앱이 켜져 있는 동안)": "Always (while the app is running)",
|
||||
|
|
@ -434,6 +436,7 @@
|
|||
"권한 허용 화면 열기": "Open the permission screen",
|
||||
"권한이 없습니다": "No permission",
|
||||
"그 파일 하나만": "Only that file",
|
||||
"그대로 두기": "Keep",
|
||||
"그래도 맞추기 ({0}개 지움)": "Sync anyway (delete {0})",
|
||||
"그리는 중 {0}/{1}": "Drawing {0}/{1}",
|
||||
"그리려면 {0} 를 받아야 합니다 (모델은 받은 뒤 이 기기에만 있고, 그림 · 프롬프트는 밖으로 나가지 않습니다).": "To draw, {0} must be downloaded (the model stays on this device, and images and prompts never leave it).",
|
||||
|
|
@ -1153,6 +1156,7 @@
|
|||
"열 수 없습니다: {0}": "Cannot open: {0}",
|
||||
"열기": "Open",
|
||||
"영구 삭제": "Delete permanently",
|
||||
"영구 삭제 ({0}개, 되돌릴 수 없음)": "Delete permanently ({0}, cannot be undone)",
|
||||
"영상 {0}": "Video {0}",
|
||||
"영상 · 음성 합치는 중": "Merging video · audio",
|
||||
"영상 재생 오류: {0}": "Video playback error: {0}",
|
||||
|
|
@ -1601,6 +1605,7 @@
|
|||
"지우기가 들어간 실행이라, 지울 목록이 나온 뒤에 실행할 수 있습니다.": "This run deletes files, so you can run it after the list of deletions appears.",
|
||||
"지우면 휴지통으로": "Delete to the Recycle Bin",
|
||||
"지우지 못한 파일: {0}": "Couldn't delete: {0}",
|
||||
"지우지 못함: {0}": "Could not delete: {0}",
|
||||
"지우지 못했습니다: {0}": "Could not delete: {0}",
|
||||
"지우지 않고 맞춤 · 대상에만 있는 {0}개를 지울지 확인 필요": "Synced without deleting · confirm whether to delete {0} items only in the target",
|
||||
"지우지 않기 (지우기 끄기)": "Don't delete (turn off delete)",
|
||||
|
|
|
|||
|
|
@ -333,6 +333,7 @@
|
|||
"{0}개는 휴지통보다 커서 영구 삭제했습니다 (Windows 가 물은 대로).": "{0} 個はごみ箱より大きいため完全に削除しました (Windows の確認どおり)。",
|
||||
"{0}개는 휴지통에 들어가지 않아 영구 삭제했습니다 (Windows 가 묻고 고른 대로).": "{0} 件はごみ箱に入らなかったため完全に削除しました (Windows の確認で選んだとおり)。",
|
||||
"{0}개를 \"기타 즐겨찾기\" 에 가져왔습니다.": "{0}個を「その他のブックマーク」に取り込みました。",
|
||||
"{0}개를 영구 삭제했습니다.": "{0} 件を完全に削除しました。",
|
||||
"{0}개를 옮겼습니다 → {1}": "{0}個を移動しました → {1}",
|
||||
"{0}개를 옮겼습니다 → {1} ({2})": "{0}個を移動しました → {1}({2})",
|
||||
"{0}개를 찾아 여기서 멈췄습니다. 이름을 더 자세히 넣거나 아래 폴더로 들어가 찾으세요.": "{0} 件見つけたところで止めました。名前をより詳しく入力するか、下のフォルダーに入って探してください。",
|
||||
|
|
@ -406,6 +407,7 @@
|
|||
"경로": "パス",
|
||||
"경로 입력": "パスを入力",
|
||||
"경로 입력 (예: D:\\영상 · \\\\NAS\\공유)": "パスを入力 (例: D:\\動画・\\\\NAS\\共有)",
|
||||
"경로가 너무 길어 휴지통에 넣을 수 없습니다 (Windows 의 휴지통은 260자 넘는 경로를 받지 않습니다).": "パスが長すぎてごみ箱に入れられません (Windows のごみ箱は 260 文字を超えるパスを受け付けません)。",
|
||||
"경로가 너무 깁니다 (Windows 의 휴지통은 260자 넘는 경로를 받지 않습니다) - 영구 삭제로 지울 수 있습니다": "パスが長すぎます (Windows のごみ箱は 260 文字を超えるパスを受け付けません) - 完全に削除はできます",
|
||||
"계속": "常時",
|
||||
"계속 (앱이 켜져 있는 동안)": "常時 (アプリの起動中)",
|
||||
|
|
@ -434,6 +436,7 @@
|
|||
"권한 허용 화면 열기": "権限の許可画面を開く",
|
||||
"권한이 없습니다": "権限がありません",
|
||||
"그 파일 하나만": "そのファイルだけ",
|
||||
"그대로 두기": "そのままにする",
|
||||
"그래도 맞추기 ({0}개 지움)": "それでも同期 ({0} 個を削除)",
|
||||
"그리는 중 {0}/{1}": "描画中 {0}/{1}",
|
||||
"그리려면 {0} 를 받아야 합니다 (모델은 받은 뒤 이 기기에만 있고, 그림 · 프롬프트는 밖으로 나가지 않습니다).": "描くには {0} のダウンロードが必要です (モデルはこの端末にだけ置かれ、画像・プロンプトは外に出ません)。",
|
||||
|
|
@ -1153,6 +1156,7 @@
|
|||
"열 수 없습니다: {0}": "開けません: {0}",
|
||||
"열기": "開く",
|
||||
"영구 삭제": "完全に削除",
|
||||
"영구 삭제 ({0}개, 되돌릴 수 없음)": "完全に削除 ({0} 件、元に戻せません)",
|
||||
"영상 {0}": "映像 {0}",
|
||||
"영상 · 음성 합치는 중": "映像・音声を結合中",
|
||||
"영상 재생 오류: {0}": "動画再生エラー: {0}",
|
||||
|
|
@ -1601,6 +1605,7 @@
|
|||
"지우기가 들어간 실행이라, 지울 목록이 나온 뒤에 실행할 수 있습니다.": "削除を含む実行のため、削除一覧が表示されてから実行できます。",
|
||||
"지우면 휴지통으로": "削除するとごみ箱へ",
|
||||
"지우지 못한 파일: {0}": "削除できなかったファイル: {0}",
|
||||
"지우지 못함: {0}": "削除できません: {0}",
|
||||
"지우지 못했습니다: {0}": "削除できませんでした: {0}",
|
||||
"지우지 않고 맞춤 · 대상에만 있는 {0}개를 지울지 확인 필요": "削除せずに同期・対象にだけある {0} 個を削除するか確認が必要",
|
||||
"지우지 않기 (지우기 끄기)": "削除しない (削除をオフ)",
|
||||
|
|
|
|||
|
|
@ -333,6 +333,7 @@
|
|||
"{0}개는 휴지통보다 커서 영구 삭제했습니다 (Windows 가 물은 대로).": "{0} 个超出回收站容量,已永久删除 (按 Windows 的提示)。",
|
||||
"{0}개는 휴지통에 들어가지 않아 영구 삭제했습니다 (Windows 가 묻고 고른 대로).": "{0} 个项目无法放入回收站,已永久删除 (按 Windows 询问时的选择)。",
|
||||
"{0}개를 \"기타 즐겨찾기\" 에 가져왔습니다.": "已将 {0} 个导入“其他书签”。",
|
||||
"{0}개를 영구 삭제했습니다.": "已永久删除 {0} 个项目。",
|
||||
"{0}개를 옮겼습니다 → {1}": "已移动 {0} 个 → {1}",
|
||||
"{0}개를 옮겼습니다 → {1} ({2})": "已移动 {0} 个 → {1}({2})",
|
||||
"{0}개를 찾아 여기서 멈췄습니다. 이름을 더 자세히 넣거나 아래 폴더로 들어가 찾으세요.": "找到 {0} 个后已停止。请输入更具体的名称或进入下级文件夹查找。",
|
||||
|
|
@ -406,6 +407,7 @@
|
|||
"경로": "路径",
|
||||
"경로 입력": "输入路径",
|
||||
"경로 입력 (예: D:\\영상 · \\\\NAS\\공유)": "输入路径 (例: D:\\视频 · \\\\NAS\\共享)",
|
||||
"경로가 너무 길어 휴지통에 넣을 수 없습니다 (Windows 의 휴지통은 260자 넘는 경로를 받지 않습니다).": "路径过长,无法放入回收站 (Windows 回收站不接受超过 260 个字符的路径)。",
|
||||
"경로가 너무 깁니다 (Windows 의 휴지통은 260자 넘는 경로를 받지 않습니다) - 영구 삭제로 지울 수 있습니다": "路径过长 (Windows 回收站不接受超过 260 个字符的路径) - 可以永久删除",
|
||||
"계속": "持续",
|
||||
"계속 (앱이 켜져 있는 동안)": "持续 (应用运行期间)",
|
||||
|
|
@ -434,6 +436,7 @@
|
|||
"권한 허용 화면 열기": "打开权限授予界面",
|
||||
"권한이 없습니다": "没有权限",
|
||||
"그 파일 하나만": "仅该文件",
|
||||
"그대로 두기": "保留",
|
||||
"그래도 맞추기 ({0}개 지움)": "仍然同步 (删除 {0} 个)",
|
||||
"그리는 중 {0}/{1}": "正在绘制 {0}/{1}",
|
||||
"그리려면 {0} 를 받아야 합니다 (모델은 받은 뒤 이 기기에만 있고, 그림 · 프롬프트는 밖으로 나가지 않습니다).": "要绘制,需要下载 {0} (模型只保存在本设备上,图片和提示词不会离开设备)。",
|
||||
|
|
@ -1153,6 +1156,7 @@
|
|||
"열 수 없습니다: {0}": "无法打开: {0}",
|
||||
"열기": "打开",
|
||||
"영구 삭제": "永久删除",
|
||||
"영구 삭제 ({0}개, 되돌릴 수 없음)": "永久删除 ({0} 个,无法撤销)",
|
||||
"영상 {0}": "视频 {0}",
|
||||
"영상 · 음성 합치는 중": "正在合并视频 · 音频",
|
||||
"영상 재생 오류: {0}": "视频播放错误: {0}",
|
||||
|
|
@ -1601,6 +1605,7 @@
|
|||
"지우기가 들어간 실행이라, 지울 목록이 나온 뒤에 실행할 수 있습니다.": "此操作包含删除,需在显示删除列表后才能执行。",
|
||||
"지우면 휴지통으로": "删除时移到回收站",
|
||||
"지우지 못한 파일: {0}": "无法删除的文件: {0}",
|
||||
"지우지 못함: {0}": "无法删除: {0}",
|
||||
"지우지 못했습니다: {0}": "无法删除: {0}",
|
||||
"지우지 않고 맞춤 · 대상에만 있는 {0}개를 지울지 확인 필요": "已同步但未删除 · 需确认是否删除仅在目标中的 {0} 个项目",
|
||||
"지우지 않기 (지우기 끄기)": "不删除 (关闭删除)",
|
||||
|
|
|
|||
|
|
@ -214,6 +214,11 @@ String recycleErrorText(int code) => switch (code) {
|
|||
_ => trf('Windows 오류 0x{0}', [code.toRadixString(16)]),
|
||||
};
|
||||
|
||||
/// 144: 경로가 너무 길어 휴지통이 받지 않는 것 (영구 삭제는 사용자가 따로 고른다). [path] 는 그 긴 경로
|
||||
class LongPathException extends FileSystemException {
|
||||
const LongPathException(super.message, super.path);
|
||||
}
|
||||
|
||||
/// Windows 휴지통으로 보내기 (SHFileOperationW, FO_DELETE + FOF_ALLOWUNDO). 65: 탐색기의 기본 지우기.
|
||||
/// 하나씩 보내 어느 것이 실패했는지 알 수 있게 한다. 실패하면 [FileSystemException] (이유는 읽을 수 있는 말).
|
||||
/// 휴지통보다 커서 들어가지 않으면 Windows 가 묻게 하고 (FOF_WANTNUKEWARNING), 실제로 어떻게 됐는지 돌려준다 (94).
|
||||
|
|
@ -223,7 +228,7 @@ RecycleResult moveToRecycleBin(String path) {
|
|||
// 휴지통은 260자 넘는 경로를 받지 않고, 그때 Windows 는 묻지 않고 영구 삭제해 버린다 (시험에서 확인).
|
||||
// 그래서 보내기 전에 (폴더면 안의 것까지) 긴 경로가 있으면 지우지 않고 이유를 알린다 - 영구 삭제는 사용자가 따로 고른다.
|
||||
final long = longPathInside(path);
|
||||
if (long != null) throw FileSystemException(recycleErrorText(0x7C), long);
|
||||
if (long != null) throw LongPathException(recycleErrorText(0x7C), long);
|
||||
final shell32 = DynamicLibrary.open('shell32.dll');
|
||||
final op = shell32.lookupFunction<Int32 Function(Pointer<_ShFileOp>), int Function(Pointer<_ShFileOp>)>('SHFileOperationW');
|
||||
final before = _binCount(path);
|
||||
|
|
|
|||
|
|
@ -1332,6 +1332,8 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
|||
if (ok != true) return;
|
||||
// 하나씩: 실패해도 나머지는 계속. 실제로 어떻게 됐는지 세어 그대로 알린다 (94)
|
||||
final failed = <(String, String)>[];
|
||||
// 144: 경로가 너무 길어 휴지통이 받지 않은 것 (이유는 한 번, [영구 삭제] 로 바로 지울 수 있게)
|
||||
final tooLong = <String>[];
|
||||
var recycled = 0, nuked = 0, kept = 0;
|
||||
// 148: 휴지통으로 보낸 것 (되돌리기용) - 정보 파일 시각은 초 단위라 조금 앞에서부터
|
||||
final since = DateTime.now().subtract(const Duration(seconds: 2));
|
||||
|
|
@ -1351,18 +1353,29 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
|||
} else {
|
||||
await FileOps().delete([x]);
|
||||
}
|
||||
} on LongPathException {
|
||||
tooLong.add(x);
|
||||
} catch (e) {
|
||||
failed.add((x, e is FileSystemException ? (e.osError?.message ?? e.message) : '$e'));
|
||||
}
|
||||
}
|
||||
if (failed.isNotEmpty && mounted) {
|
||||
await showDialog<void>(
|
||||
if ((failed.isNotEmpty || tooLong.isNotEmpty) && mounted) {
|
||||
final nukeLong = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
scrollable: true,
|
||||
icon: const Icon(Icons.error_outline, color: Colors.redAccent),
|
||||
title: Text(trf('{0}개 중 {1}개를 지우지 못했습니다', [paths.length, failed.length])),
|
||||
title: Text(trf('{0}개 중 {1}개를 지우지 못했습니다', [paths.length, failed.length + tooLong.length])),
|
||||
content: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
// 144: 긴 경로는 이유 한 줄 + 이름만 (영구 삭제는 아래 버튼으로)
|
||||
if (tooLong.isNotEmpty) ...[
|
||||
Text(tr('경로가 너무 길어 휴지통에 넣을 수 없습니다 (Windows 의 휴지통은 260자 넘는 경로를 받지 않습니다).'),
|
||||
style: const TextStyle(fontWeight: FontWeight.w600)),
|
||||
const SizedBox(height: 4),
|
||||
for (final x in tooLong.take(30)) Text('· ${vBasename(x)}', style: const TextStyle(fontSize: 12)),
|
||||
if (tooLong.length > 30) Text(trf('… 외 {0}개', [tooLong.length - 30])),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
for (final (x, why) in failed.take(30)) ...[
|
||||
Text(vBasename(x), style: const TextStyle(fontWeight: FontWeight.w600)),
|
||||
Text('${vDirname(x)} · $why', style: const TextStyle(fontSize: 12, color: JjColors.textDim)),
|
||||
|
|
@ -1371,11 +1384,36 @@ class _ExplorerPageState extends State<ExplorerPage> {
|
|||
if (failed.length > 30) Text(trf('… 외 {0}개', [failed.length - 30])),
|
||||
const SizedBox(height: 6),
|
||||
// 이유를 이미 위에 적었으므로 짐작하는 말은 빼고, 실제로 지운 것이 있을 때만 "나머지는 지웠습니다"
|
||||
if (failed.length < paths.length) Text(tr('나머지는 지웠습니다.'), style: const TextStyle(fontSize: 12)),
|
||||
if (failed.length + tooLong.length < paths.length) Text(tr('나머지는 지웠습니다.'), style: const TextStyle(fontSize: 12)),
|
||||
]),
|
||||
actions: [FilledButton(onPressed: () => Navigator.pop(ctx), child: Text(tr('확인')))],
|
||||
actions: [
|
||||
if (tooLong.isNotEmpty) ...[
|
||||
TextButton(onPressed: () => Navigator.pop(ctx, false), child: Text(tr('그대로 두기'))),
|
||||
FilledButton(
|
||||
style: FilledButton.styleFrom(backgroundColor: Colors.redAccent),
|
||||
onPressed: () => Navigator.pop(ctx, true),
|
||||
child: Text(trf('영구 삭제 ({0}개, 되돌릴 수 없음)', [tooLong.length])),
|
||||
),
|
||||
] else
|
||||
FilledButton(onPressed: () => Navigator.pop(ctx), child: Text(tr('확인'))),
|
||||
],
|
||||
),
|
||||
);
|
||||
// 144: 사용자가 [영구 삭제] 를 고른 긴 경로만 지운다
|
||||
if (nukeLong == true) {
|
||||
final notDeleted = <String>[];
|
||||
for (final x in tooLong) {
|
||||
try {
|
||||
await FileOps().delete([x]);
|
||||
} catch (e) {
|
||||
notDeleted.add('${vBasename(x)}: ${e is FileSystemException ? (e.osError?.message ?? e.message) : e}');
|
||||
}
|
||||
}
|
||||
_snack([
|
||||
if (tooLong.length > notDeleted.length) trf('{0}개를 영구 삭제했습니다.', [tooLong.length - notDeleted.length]),
|
||||
if (notDeleted.isNotEmpty) trf('지우지 못함: {0}', [notDeleted.take(3).join(' · ')]),
|
||||
].join(' '));
|
||||
}
|
||||
} else if (!permanent && mounted) {
|
||||
final text = [
|
||||
if (recycled > 0) trf('{0}개 항목을 휴지통으로 보냈습니다.', [recycled]),
|
||||
|
|
|
|||
|
|
@ -166,6 +166,44 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
}, skip: !Platform.isWindows);
|
||||
|
||||
testWidgets('144: 긴 경로는 휴지통에 넣지 못한 이유 한 줄과 [영구 삭제] - 누르면 지운다 · [그대로 두기] 면 남는다', (tester) async {
|
||||
String lp(String s) => r'\\?\' + s;
|
||||
var deep = p.join(left, 'deep');
|
||||
while (deep.length < 250) {
|
||||
deep = p.join(deep, 'd' * 30);
|
||||
}
|
||||
Directory(lp(deep)).createSync(recursive: true);
|
||||
File(lp(p.join(deep, 'a_file_name_that_makes_it_longer.txt'))).writeAsStringSync('x');
|
||||
tester.view.physicalSize = const Size(1600, 900);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.reset);
|
||||
await tester.runAsync(() => tester.pumpWidget(MaterialApp(home: ExplorerPage(c: c))));
|
||||
await settle(tester, () => find.text('deep').evaluate().isNotEmpty);
|
||||
Future<void> deleteDeep() async {
|
||||
await tester.runAsync(() => tester.tap(find.text('deep').first));
|
||||
await settle(tester, () => false, rounds: 10);
|
||||
await tester.runAsync(() => tester.tap(find.text('삭제').first));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.runAsync(() => tester.tap(find.widgetWithText(FilledButton, '휴지통으로')));
|
||||
await settle(tester, () => find.textContaining('경로가 너무 길어').evaluate().isNotEmpty);
|
||||
}
|
||||
|
||||
await deleteDeep();
|
||||
// 이유는 한 줄, 항목은 이름만, 버튼은 [그대로 두기] · [영구 삭제]
|
||||
expect(find.textContaining('경로가 너무 길어 휴지통에 넣을 수 없습니다'), findsOneWidget);
|
||||
expect(find.text('· deep'), findsOneWidget);
|
||||
expect(find.textContaining('영구 삭제로 지울 수 있습니다'), findsNothing, reason: '긴 설명을 항목마다 되풀이하지 않음');
|
||||
await tester.tap(find.text('그대로 두기'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(Directory(lp(deep)).existsSync(), isTrue);
|
||||
// 다시 → [영구 삭제]
|
||||
await deleteDeep();
|
||||
await tester.runAsync(() => tester.tap(find.textContaining('영구 삭제 (1개, 되돌릴 수 없음)')));
|
||||
await settle(tester, () => find.textContaining('영구 삭제했습니다').evaluate().isNotEmpty);
|
||||
expect(Directory(p.join(left, 'deep')).existsSync(), isFalse);
|
||||
expect(find.textContaining('1개를 영구 삭제했습니다.'), findsOneWidget);
|
||||
}, skip: !Platform.isWindows);
|
||||
|
||||
testWidgets('48: 건너뛰기를 고르면 그대로 두고 건너뛴 것을 알린다', (tester) async {
|
||||
await startCopy(tester);
|
||||
await tester.tap(find.text('건너뛰기'));
|
||||
|
|
|
|||
|
|
@ -84,12 +84,13 @@ void main() {
|
|||
test('148: 원래 폴더가 그사이 지워졌으면 다시 만들지 않고 알린다 · 이 사용자 (SID) 의 휴지통에서만 찾는다', () async {
|
||||
expect(currentUserSid(), matches(RegExp(r'^S-1-5-')));
|
||||
final tmp = Directory.systemTemp.createTempSync('jj_undo_');
|
||||
final folder = Directory(p.join(tmp.absolute.path, 'gone'))..createSync();
|
||||
addTearDown(() async {
|
||||
await _purgeFromRecycleBin(tmp.absolute.path);
|
||||
// 휴지통에 남긴 x.txt 의 원래 위치는 gone 폴더 (정확히 그 폴더로 찾아 지운다)
|
||||
expect(await _purgeFromRecycleBin(folder.path), 1);
|
||||
if (tmp.existsSync()) tmp.deleteSync(recursive: true);
|
||||
});
|
||||
final since = DateTime.now().subtract(const Duration(seconds: 2));
|
||||
final folder = Directory(p.join(tmp.absolute.path, 'gone'))..createSync();
|
||||
final f = File(p.join(folder.path, 'x.txt'))..writeAsStringSync('x');
|
||||
expect(moveToRecycleBin(f.path), RecycleResult.recycled);
|
||||
folder.deleteSync(); // 사용자가 그 폴더를 지움
|
||||
|
|
|
|||
Loading…
Reference in New Issue