import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:jj_mkvmaker/app/transfer_job.dart'; import 'package:jj_mkvmaker/core/webdav.dart'; import 'package:path/path.dart' as p; import 'support/dav_server.dart'; /// 214: 앱이 직접 하는 "안의 것" 이동 (WebDAV 가 낄 때 · 현재 방식) 은 대상에 맞춘 원본 파일만 지운다. /// 예전에는 맞춘 뒤 원본 폴더를 다시 읽어 모든 파일을 지웠다 (건너뛴 것 · 도중에 생긴 것 · 링크 너머까지). void main() { late Directory tmp; late String src, dst; setUp(() { tmp = Directory.systemTemp.createTempSync('jj_move_settled_'); src = p.join(tmp.path, 'src'); dst = p.join(tmp.path, 'dst'); File(p.join(src, 'a.txt')) ..createSync(recursive: true) ..writeAsStringSync('a'); Directory(dst).createSync(); }); tearDown(() { if (tmp.existsSync()) tmp.deleteSync(recursive: true); }); TransferJob moveJob({String options = ''}) => TransferJob(sources: [src], dest: dst, move: true, contents: true, options: options); test('214 a: -u 로 건너뛴 파일 (대상이 더 새것) 은 원본에 남는다 (rsync 처럼)', () async { final old = File(p.join(src, 'keep.txt'))..writeAsStringSync('old source'); old.setLastModifiedSync(DateTime(2020)); File(p.join(dst, 'keep.txt')).writeAsStringSync('newer target'); final job = moveJob(options: '-u'); await job.run(); expect(job.error, isNull); expect(File(p.join(dst, 'a.txt')).readAsStringSync(), 'a'); expect(File(p.join(src, 'a.txt')).existsSync(), isFalse, reason: '맞춘 것은 지움'); expect(old.existsSync(), isTrue, reason: '건너뛴 것은 남김 (예전에는 지웠다)'); expect(File(p.join(dst, 'keep.txt')).readAsStringSync(), 'newer target'); // 216 · 212: 원본에 남은 것을 다시 세어 끝 알림에 expect(job.leftInSource, 1); expect(job.doneSummary(), contains('이동 끝: 1개 · src → dst')); expect(job.doneSummary(), contains('1개는 원본에 남음 (건너뜀)')); }); test('214 c: 맞추는 동안 원본에 새로 생긴 파일은 지우지 않는다', () async { // 천천히 보내는 큰 파일 (맞추는 동안 새 파일을 만든다) File(p.join(src, 'big.bin')).writeAsBytesSync(List.filled(300 * 1024, 7)); final job = TransferJob(sources: [src], dest: dst, move: true, contents: true, bandwidthKBps: 400); final running = job.run(); await Future.delayed(const Duration(milliseconds: 250)); File(p.join(src, 'arrived.txt')).writeAsStringSync('new'); await running; expect(job.error, isNull); expect(File(p.join(dst, 'big.bin')).lengthSync(), 300 * 1024); expect(File(p.join(src, 'big.bin')).existsSync(), isFalse); expect(File(p.join(src, 'arrived.txt')).existsSync(), isTrue, reason: '복사하지 않은 것은 남김'); }); test('214 d: 원본 안의 링크 (junction) 는 따라가지 않는다 - 링크가 가리키는 바깥 폴더의 파일은 그대로', () async { final outside = Directory(p.join(tmp.path, 'outside'))..createSync(); final precious = File(p.join(outside.path, 'precious.txt'))..writeAsStringSync('keep me'); try { Link(p.join(src, 'jn')).createSync(outside.path); } on FileSystemException { markTestSkipped('이 환경에서는 링크를 만들 수 없음'); return; } final job = moveJob(); await job.run(); expect(job.error, isNull); expect(precious.existsSync(), isTrue); expect(precious.readAsStringSync(), 'keep me'); expect(File(p.join(src, 'a.txt')).existsSync(), isFalse); }); group('214 b: WebDAV', () { late Directory remote; late TestDavServer server; setUp(() async { remote = Directory(p.join(tmp.path, 'remote'))..createSync(); server = TestDavServer(remote); await server.start(); final s = DavServer(id: 'nas', name: 'NAS', url: server.url, user: 'user', password: 'pass'); DavRegistry.configure([s]); }); tearDown(() async { DavRegistry.configure([]); await server.stop(); }); test('214 b: 크기만 같고 내용이 다른 대상 (대상이 더 새것) 이 있어도, 이동은 다시 보내고 지운다 (내용을 잃지 않게)', () async { HttpOverrides.global = null; File(p.join(src, 'same.txt')) ..writeAsStringSync('AAAA') ..setLastModifiedSync(DateTime(2020)); File(p.join(remote.path, 'same.txt')).writeAsStringSync('BBBB'); // 같은 크기 · 더 새것 · 다른 내용 final job = TransferJob(sources: [src], dest: 'dav://nas/', move: true, contents: true); await job.run(); expect(job.error, isNull); expect(File(p.join(remote.path, 'same.txt')).readAsStringSync(), 'AAAA', reason: '원본 내용이 대상에 (예전에는 같다고 보고 원본만 지웠다)'); expect(File(p.join(src, 'same.txt')).existsSync(), isFalse); expect(File(p.join(remote.path, 'a.txt')).readAsStringSync(), 'a'); }); test('214 d (WebDAV 로): 로컬 원본의 링크는 따라가지 않는다', () async { HttpOverrides.global = null; final outside = Directory(p.join(tmp.path, 'outside2'))..createSync(); final precious = File(p.join(outside.path, 'precious.txt'))..writeAsStringSync('keep me'); try { Link(p.join(src, 'jn')).createSync(outside.path); } on FileSystemException { markTestSkipped('이 환경에서는 링크를 만들 수 없음'); return; } final job = TransferJob(sources: [src], dest: 'dav://nas/', move: true, contents: true); await job.run(); expect(job.error, isNull); expect(precious.existsSync(), isTrue); expect(File(p.join(src, 'a.txt')).existsSync(), isFalse); }); }); }