JJ_MKVMaker/test/file_ops_modules_contract_t...

139 lines
7.3 KiB
Dart

import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:jj_mkvmaker/core/files/any_transfer.dart';
import 'package:jj_mkvmaker/core/files/file_listing.dart';
import 'package:jj_mkvmaker/core/files/local_transfer.dart';
import 'package:jj_mkvmaker/core/files/name_ops.dart';
import 'package:jj_mkvmaker/core/files/path_rules.dart';
import 'package:jj_mkvmaker/core/files/transfer_control.dart';
import 'package:jj_mkvmaker/core/files/transfer_guard.dart';
import 'package:jj_mkvmaker/core/files/windows_drives.dart';
import 'package:path/path.dart' as p;
/// 나누기 file_ops 약속 시험: lib/core/files/ 모듈마다 맨 위 약속 (입력 · 출력 · 오류) - 실제 시험 폴더 · 실제 파일.
void main() {
late Directory tmp;
setUp(() => tmp = Directory.systemTemp.createTempSync('jj_files_'));
tearDown(() => tmp.deleteSync(recursive: true));
String mk(String rel, [String text = 'x']) {
final f = File(p.join(tmp.path, rel))..createSync(recursive: true);
f.writeAsStringSync(text);
return f.path;
}
test('file_listing: 읽기 · 숨김 · 정렬 (폴더 먼저 · 숫자) · 찾기 · 읽지 못함은 던짐 · 크기 글', () async {
mk('d/file10.txt');
mk('d/file2.txt');
mk('d/.hidden');
Directory(p.join(tmp.path, 'd', 'sub')).createSync();
final d = p.join(tmp.path, 'd');
final list = await listEntries(d);
expect(list.map((e) => e.name).toSet(), {'file10.txt', 'file2.txt', 'sub'});
expect((await listEntries(d, showHidden: true)).length, 4);
expect(sortEntries(list, SortBy.name).map((e) => e.name), ['sub', 'file2.txt', 'file10.txt']);
expect(await searchFiles(tmp.path, 'FILE*').map((e) => e.name).toList(), ['file2.txt', 'file10.txt']);
await expectLater(listEntries(p.join(tmp.path, 'none')), throwsA(isA<FileSystemException>()));
expect([formatSize(-1), formatSize(12), formatSize(2048), formatSize(3 * 1024 * 1024 * 1024)], ['—', '12B', '2KB', '3.0GB']);
});
test('windows_drives: 목록은 비지 않음 · 종류는 열지 않고 숫자 · 공유 맨 위', () {
final drives = windowsDrives();
expect(drives, isNotEmpty);
if (Platform.isWindows) expect(driveType(drives.first.$1), greaterThan(0));
expect(uncRoot(r'\\nas\share\a\b'), r'\\nas\share');
expect(uncRoot('x'), 'x');
});
test('path_rules: 겹치지 않는 이름 · 같은 경로 · 안에 있음 · 바깥 것만 · 전송 전 확인', () {
mk('a.txt');
expect(p.basename(uniqueTarget(tmp.path, 'a.txt')), 'a (2).txt');
final a = p.join(tmp.path, 'A'), inner = p.join(a, 'b');
Directory(inner).createSync(recursive: true);
expect(isSameOrInside(inner, a), isTrue);
expect(isSameOrInside(a, inner), isFalse);
expect(outermostPaths([inner, a, a]), [a]);
if (Platform.isWindows) expect(samePath(a, a.toLowerCase()), isTrue);
expect(transferProblem([a], inner, move: false), isNotNull, reason: '자기 안으로');
expect(transferProblem([p.join(tmp.path, 'none')], tmp.path, move: false), isNotNull, reason: '원본 없음');
expect(transferProblem([p.join(tmp.path, 'a.txt')], a, move: true), isNull);
expect(isAppTempName('~jjren_1') && isPartialFile('x.jjpart'), isTrue);
});
test('name_ops: 쓸 수 없는 이름 · 이름 바꾸기 · 새 폴더 · 같은 이름은 던짐', () async {
expect(nameProblem('a/b', windowsRules: false), isNotNull);
expect(nameProblem('CON.txt', windowsRules: true), isNotNull);
expect(nameProblem('ok.txt', windowsRules: true), isNull);
final f = mk('x.txt');
mk('y.txt');
expect(p.basename(await renameInPlace(f, ' z.txt ')), 'z.txt');
await expectLater(renameInPlace(p.join(tmp.path, 'z.txt'), 'y.txt'), throwsA(isA<FileSystemException>()));
final dir = await createFolder(tmp.path, '새 폴더');
expect(Directory(dir).existsSync(), isTrue);
await expectLater(createFolder(tmp.path, '새 폴더'), throwsA(isA<FileSystemException>()));
});
test('transfer_guard: 원본 없음 · 빈 원본은 던지고 지우지 않음 · 빈 폴더 정리', () async {
final src = p.join(tmp.path, 'src'), dst = p.join(tmp.path, 'dst');
mk('dst/keep.txt');
await expectLater(ensureSourceForDelete(src, dst), throwsA(isA<SourceUnreadableException>()));
Directory(src).createSync();
await expectLater(ensureSourceForDelete(src, dst), throwsA(isA<SourceUnreadableException>().having((e) => e.empty, 'empty', isTrue)));
await ensureSourceForDelete(src, dst, allowEmpty: true);
Directory(p.join(src, 'e1', 'e2')).createSync(recursive: true);
expect(await removeEmptyDirs(src), 2);
expect(Directory(src).existsSync(), isTrue);
});
test('transfer_control: 같은 이름 건너뛰기는 null 과 기록 · 취소 뒤 check 는 던짐', () async {
final f = mk('s/a.txt');
mk('d/a.txt');
final c = TransferControl(conflict: NameConflict.skip);
expect(await c.targetFor(f, p.join(tmp.path, 'd')), isNull);
expect(c.skipped, [f]);
c.check();
c.cancel();
expect(c.cancelled, isTrue);
expect(c.check, throwsA(isA<FileOpCancelled>()));
});
test('local_transfer: 복사 (진행 · 바뀐 때) · 이동 · 맞추기 (지우기) · 취소는 반쯤 쓴 파일을 남기지 않음', () async {
final a = mk('s/dir/a.txt', 'hello');
final dst = p.join(tmp.path, 'd');
Directory(dst).createSync();
var last = 0;
final made = await localCopy(TransferControl(), [p.join(tmp.path, 's', 'dir')], dst, onProgress: (_, done, _) => last = done);
expect(File(p.join(made.single, 'a.txt')).readAsStringSync(), 'hello');
expect(last, 5);
expect(await localTotalSize([p.join(tmp.path, 's')]), 5);
final moved = await localMove(TransferControl(), [a], dst);
expect(File(a).existsSync(), isFalse);
expect(File(moved.single).readAsStringSync(), 'hello');
final m = p.join(tmp.path, 'm');
mk('m/old.txt');
expect(await localMirror(TransferControl(), p.join(tmp.path, 'd'), m, delete: true), 2);
expect(File(p.join(m, 'old.txt')).existsSync(), isFalse);
final c = TransferControl()..cancel();
await expectLater(localCopy(c, [moved.single], p.join(tmp.path, 's')), throwsA(isA<FileOpCancelled>()));
expect(Directory(p.join(tmp.path, 's')).listSync(recursive: true).where((e) => e.path.endsWith('.jjpart')), isEmpty);
});
test('any_transfer: 로컬 경로로도 복사 · 이동 · 맞추기 · 크기, 원본 없음은 던짐', () async {
mk('s/x/b.txt', 'abc');
final dst = p.join(tmp.path, 'd');
Directory(dst).createSync();
expect(await anyTotalSize([p.join(tmp.path, 's')]), 3);
final made = await anyCopy(TransferControl(), [p.join(tmp.path, 's', 'x')], dst);
expect(File(p.join(made.single, 'b.txt')).readAsStringSync(), 'abc');
final m = p.join(tmp.path, 'm');
expect(await anyMirror(TransferControl(), p.join(tmp.path, 's'), m), 1);
expect(await anyMirror(TransferControl(), p.join(tmp.path, 's'), m), 0, reason: '같으면 다시 보내지 않음');
final m2 = Directory(p.join(tmp.path, 'm2'))..createSync();
final moved = await anyMove(TransferControl(), [p.join(tmp.path, 's', 'x')], m2.path);
expect(Directory(p.join(tmp.path, 's', 'x')).existsSync(), isFalse);
expect(File(p.join(moved.single, 'b.txt')).readAsStringSync(), 'abc');
await expectLater(anyCopy(TransferControl(), [p.join(tmp.path, 'none')], dst), throwsA(isA<FileSystemException>()));
});
}