124 lines
5.7 KiB
Dart
124 lines
5.7 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:jj_mkvmaker/core/file_ops.dart' show SourceUnreadableException;
|
|
import 'package:jj_mkvmaker/core/sync_preview.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
/// 72: Rsync 실행 전 비교
|
|
void main() {
|
|
late Directory tmp;
|
|
late String a, b;
|
|
final old = DateTime(2020), newer = DateTime(2024);
|
|
void f(String dir, String rel, String text, DateTime t) => (File(p.join(dir, rel))
|
|
..createSync(recursive: true)
|
|
..writeAsStringSync(text))
|
|
.setLastModifiedSync(t);
|
|
setUp(() {
|
|
tmp = Directory.systemTemp.createTempSync('jj_preview_');
|
|
a = p.join(tmp.path, 'a');
|
|
b = p.join(tmp.path, 'b');
|
|
f(a, 'new.txt', 'n', newer); // 왼쪽에만
|
|
f(a, 'sub/changed.txt', 'left', newer); // 양쪽, 왼쪽이 새것
|
|
f(b, 'sub/changed.txt', 'r', old);
|
|
f(a, 'same.txt', 's', old);
|
|
f(b, 'same.txt', 's', old);
|
|
f(a, 'leftold.txt', 'aaaa', old); // 양쪽, 오른쪽이 새것
|
|
f(b, 'leftold.txt', 'bb', newer);
|
|
f(b, 'only_b.txt', 'o', old); // 오른쪽에만
|
|
f(b, 'half.mkv.jjpart', 'x', old); // 만들다 만 파일은 세지 않음
|
|
});
|
|
tearDown(() => tmp.deleteSync(recursive: true));
|
|
|
|
Map<String, PreviewAction> m(List<PreviewItem> xs) => {for (final x in xs) x.rel: x.action};
|
|
|
|
test('옵션: --delete · -u 알아보기', () {
|
|
expect(optionsDelete('-avPog --delete'), isTrue);
|
|
expect(optionsDelete('-avPog --delete-after'), isTrue);
|
|
expect(optionsDelete('-avPog'), isFalse);
|
|
expect(optionsUpdate('-avPogu'), isTrue);
|
|
expect(optionsUpdate('-avPog --update'), isTrue);
|
|
expect(optionsUpdate('-avPog'), isFalse);
|
|
// 97: --del (--delete-during 별칭) 도 지우기
|
|
expect(optionsDelete('-avPog --del'), isTrue);
|
|
expect(optionsDelete('-avPog --delete-excluded'), isTrue);
|
|
expect(withoutDeleteOptions('-av --del --delete-after -u'), '-av -u');
|
|
// 106: 따옴표는 그대로 (제외할 폴더가 둘로 갈라지지 않게)
|
|
expect(withoutDeleteOptions('-av --exclude="My Folder" --delete'), '-av --exclude="My Folder"');
|
|
expect(withoutDeleteOptions("-av --exclude='a b' --del"), "-av --exclude='a b'");
|
|
});
|
|
|
|
test('→ 지우기 없이: 새로 · 바뀜 · 받는 쪽에만 있음 (그대로)', () async {
|
|
final r = m(await previewSync(a, b, toRight: true));
|
|
expect(r, {
|
|
'new.txt': PreviewAction.add,
|
|
'sub/changed.txt': PreviewAction.update,
|
|
'leftold.txt': PreviewAction.update,
|
|
'only_b.txt': PreviewAction.onlyTarget,
|
|
});
|
|
});
|
|
|
|
test('→ --delete -u: 받는 쪽에만 있는 것은 지워짐 · 받는 쪽이 새것이면 건너뜀', () async {
|
|
final r = m(await previewSync(a, b, toRight: true, delete: true, update: true));
|
|
expect(r['only_b.txt'], PreviewAction.delete);
|
|
// 229: 건너뛰는 것도 목록에 "받는 쪽이 더 새것 - 건너뜀" 으로 (예전에는 빠져 있었다)
|
|
expect(r['leftold.txt'], PreviewAction.skipNewer);
|
|
expect(r.containsKey('half.mkv.jjpart'), isFalse);
|
|
});
|
|
|
|
test('⇄: 한쪽에만 있는 것은 서로 건너가고, 다른 파일은 새것 쪽에서 (한 번만)', () async {
|
|
final xs = await previewBoth(a, b);
|
|
final r = {for (final x in xs) x.rel: (x.action, x.toRight)};
|
|
expect(r, {
|
|
'new.txt': (PreviewAction.add, true),
|
|
'sub/changed.txt': (PreviewAction.update, true),
|
|
'leftold.txt': (PreviewAction.update, false),
|
|
'only_b.txt': (PreviewAction.add, false),
|
|
});
|
|
});
|
|
|
|
test('231: 원본의 링크 · junction 은 안으로 들어가지 않는다 - 앱이 직접이면 "건너뜀 (링크)", rsync 면 링크 하나', () async {
|
|
final outside = p.join(tmp.path, 'outside');
|
|
f(outside, 'big.bin', 'x', old);
|
|
Link(p.join(a, 'linked')).createSync(outside); // Windows 는 junction
|
|
final direct = await previewSync(a, b, toRight: true, skipLinks: true);
|
|
expect([for (final x in direct) if (x.rel.startsWith('linked')) (x.rel, x.action)], [('linked', PreviewAction.skipLink)]);
|
|
final viaRsync = await previewSync(a, b, toRight: true);
|
|
expect([for (final x in viaRsync) if (x.rel.startsWith('linked')) (x.rel, x.action)], [('linked', PreviewAction.add)]);
|
|
// 받는 쪽에 같은 이름이 있으면 지울 것으로 세지 않는다 (맞추기도 지우지 않음 - 214)
|
|
Directory(p.join(b, 'linked')).createSync();
|
|
final del = await previewSync(a, b, toRight: true, delete: true, skipLinks: true);
|
|
expect([for (final x in del) if (x.rel == 'linked') x.action], [PreviewAction.skipLink]);
|
|
});
|
|
|
|
test('93: 원본 폴더를 읽지 못하면 비교 실패 (지우는 실행을 막는다)', () async {
|
|
await expectLater(previewSync(p.join(tmp.path, 'none'), b, toRight: true, delete: true),
|
|
throwsA(isA<SourceUnreadableException>()));
|
|
});
|
|
|
|
test('⇄ + --delete: 먼저 도는 → 에서 오른쪽에만 있는 것이 지워지고 ← 로 건너가지 않는다', () async {
|
|
final r = {for (final x in await previewBoth(a, b, delete: true)) x.rel: (x.action, x.toRight)};
|
|
expect(r['only_b.txt'], (PreviewAction.delete, true));
|
|
expect(r['new.txt'], (PreviewAction.add, true));
|
|
});
|
|
test('M2 (10/19): optionsFilter - 거르기 옵션이 있는지 (원격 확인 창의 경고)', () {
|
|
for (final o in [
|
|
'-av --exclude=*.tmp',
|
|
'-av --exclude "My Folder"',
|
|
'-a --include=*.mkv --exclude=*',
|
|
'--filter="- *.bak"',
|
|
'-a -f "- x"',
|
|
'--exclude-from=list.txt',
|
|
'--include-from list.txt',
|
|
'-avC',
|
|
'--cvs-exclude',
|
|
'-aF',
|
|
]) {
|
|
expect(optionsFilter(o), isTrue, reason: o);
|
|
}
|
|
for (final o in ['-avPog', '-a --delete', '-avu --remove-source-files', '--delete-excluded', '-e "ssh -C"', '']) {
|
|
expect(optionsFilter(o), isFalse, reason: o);
|
|
}
|
|
});
|
|
}
|