WIP 통합 시험 · 캡처의 임시 폴더: 시험 끝에 (실패해도) 지우기 · test_temp_check 가 통합 시험에도 (검토 대기)

관리자 지시 (10/19, 28 이 찾음): Windows 캡처 · 통합 시험 (integration_test, -d windows) 이 %TEMP%\jj_* 시험 폴더를 남겼다
(시험 본문 끝의 deleteSync 는 실패하면 건너뛰고, 앱 · WebView 가 파일을 잡고 있으면 지우기가 실패했다).
- 새 integration_test/support/temp_dir.dart: testTempDir(prefix, {base}) - 만들면서 addTearDown 으로 지우기를 걸어 실패해도 지운다.
  잠겨 있으면 0.25초씩 20번 다시 (실제 시간 - 가짜 시계 밖), 긴 경로는 \?\, 끝내 못 지우면 알리기만.
  통합 시험 26개 파일의 Directory.systemTemp.createTempSync('jj…') 를 모두 이것으로 (JJ_SHOT_TMP 를 쓰는 캡처 도우미 포함).
- tool/test_temp_check.ps1: integration_test 의 이름 (testTempDir 포함) 도 모은다. 넘겨받은 .dart 파일이 있으면 그 파일과 그것이 import 하는
  support 파일의 이름만 센다 - 같은 때 다른 세션 · worktree 가 돌린 시험의 폴더 (jj_explorer_ · jj_sync_ · jj_fake_recycle_) 를 세던 거짓 실패를 없앰.
  시험 소스에 없는 이름의 새 jj 폴더는 참고로만 보인다. 사용: test_temp_check.ps1 integration_test\windows_b6_shot_test.dart -d windows
- com_guard_test 의 쓰지 않는 dart:io import 정리 (analyze).

시험: windows_b6 · windows_xplore · windows_ftp · windows_wifi 캡처 통과 · 새로 남은 것 0 (test_temp_check), analyze 문제 없음.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
next2
RyuJongJin 2026-10-19 21:51:39 +09:00
parent 58254e42b2
commit 25a0cd3c96
28 changed files with 110 additions and 45 deletions

View File

@ -7,6 +7,7 @@ import 'package:jj_mkvmaker/core/languages.dart';
import 'package:jj_mkvmaker/core/models.dart'; import 'package:jj_mkvmaker/core/models.dart';
import 'package:jj_mkvmaker/core/output_paths.dart'; import 'package:jj_mkvmaker/core/output_paths.dart';
import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/services/platform_services.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 실제 Whisper + NLLB 로 AI 자막 → MKV (모델이 JJ_MKVMAKER_MODELS 에 있어야 함) /// 실제 Whisper + NLLB 로 AI 자막 → MKV (모델이 JJ_MKVMAKER_MODELS 에 있어야 함)
@ -16,7 +17,7 @@ void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('영어 음성 영상 → AI 자막(ko/en/ja) → MKV', (tester) async { testWidgets('영어 음성 영상 → AI 자막(ko/en/ja) → MKV', (tester) async {
final dir = Directory.systemTemp.createTempSync('jj_e2e_'); final dir = testTempDir('jj_e2e_');
final video = p.join(dir.path, '영어 강의.mp4'); final video = p.join(dir.path, '영어 강의.mp4');
final speech = p.join(Directory.current.path, 'test_assets', 'speech_en.wav'); final speech = p.join(Directory.current.path, 'test_assets', 'speech_en.wav');
final r = await Process.run('ffmpeg', [ final r = await Process.run('ffmpeg', [

View File

@ -10,6 +10,7 @@ import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart';
import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart'; import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/browser_page.dart'; import 'package:jj_mkvmaker/ui/browser_page.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 실제 Edge(WebView2): MKV 화면 ↔ 브라우저를 여러 번 오가도 보던 페이지를 다시 읽지 않고 그대로 이어진다 /// 실제 Edge(WebView2): MKV 화면 ↔ 브라우저를 여러 번 오가도 보던 페이지를 다시 읽지 않고 그대로 이어진다
@ -27,7 +28,7 @@ void main() {
await req.response.close(); await req.response.close();
}); });
final url = 'http://127.0.0.1:${server.port}/page'; final url = 'http://127.0.0.1:${server.port}/page';
final dataDir = Directory.systemTemp.createTempSync('jj_keep_').path; final dataDir = testTempDir('jj_keep_').path;
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService())); final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
c.settings c.settings

View File

@ -13,6 +13,7 @@ import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/platform/windows/ytdlp_backend.dart'; import 'package:jj_mkvmaker/platform/windows/ytdlp_backend.dart';
import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/browser_page.dart'; import 'package:jj_mkvmaker/ui/browser_page.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 실제 Edge(WebView2): 페이지 열기 · 동영상 감지 · 쿠키 저장 → yt-dlp 가 같은 쿠키를 읽는지 /// 실제 Edge(WebView2): 페이지 열기 · 동영상 감지 · 쿠키 저장 → yt-dlp 가 같은 쿠키를 읽는지
@ -31,7 +32,7 @@ void main() {
await req.response.close(); await req.response.close();
}); });
final url = 'http://127.0.0.1:${server.port}/'; final url = 'http://127.0.0.1:${server.port}/';
final dataDir = Directory.systemTemp.createTempSync('jj_webview_').path; final dataDir = testTempDir('jj_webview_').path;
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService())); final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
c.settings.webViewDataDir = dataDir; c.settings.webViewDataDir = dataDir;

View File

@ -13,6 +13,7 @@ import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/app_actions.dart'; import 'package:jj_mkvmaker/ui/app_actions.dart';
import 'package:jj_mkvmaker/ui/browser_page.dart'; import 'package:jj_mkvmaker/ui/browser_page.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 실제 망 (Windows): DNS 강제 (8.8.8.8) 상태에서 Chrome 엔진 (CEF) 이 앱 안 프록시의 인증 (비밀값) 에 답해 페이지를 여는지. /// 실제 망 (Windows): DNS 강제 (8.8.8.8) 상태에서 Chrome 엔진 (CEF) 이 앱 안 프록시의 인증 (비밀값) 에 답해 페이지를 여는지.
@ -33,7 +34,7 @@ void main() {
} }
CefRuntime.rememberStartState(); CefRuntime.rememberStartState();
expect(CefRuntime.readyThisRun, isTrue); expect(CefRuntime.readyThisRun, isTrue);
final data = Platform.environment['JJ_MKVMAKER_DATA'] ?? Directory.systemTemp.createTempSync('jj_cef_real_').path; final data = Platform.environment['JJ_MKVMAKER_DATA'] ?? testTempDir('jj_cef_real_').path;
Directory(data).createSync(recursive: true); Directory(data).createSync(recursive: true);
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService())); final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
c.settings c.settings

View File

@ -1,11 +1,10 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:jj_mkvmaker/platform/windows/com_guard.dart'; import 'package:jj_mkvmaker/platform/windows/com_guard.dart';
import 'package:jj_mkvmaker/ui/browser_page.dart'; import 'package:jj_mkvmaker/ui/browser_page.dart';
import 'support/temp_dir.dart';
/// 실제 Edge(WebView2): 다른 구성 요소가 COM 준비 상태를 풀어 버린 상황을 만들고 /// 실제 Edge(WebView2): 다른 구성 요소가 COM 준비 상태를 풀어 버린 상황을 만들고
/// (브라우저가 "CoInitialize 가 호출되지 않았습니다" 로 안 뜨던 문제) 그래도 브라우저 환경이 만들어지는지 /// (브라우저가 "CoInitialize 가 호출되지 않았습니다" 로 안 뜨던 문제) 그래도 브라우저 환경이 만들어지는지
@ -26,7 +25,7 @@ void main() {
for (var i = 0; i < 8; i++) { for (var i = 0; i < 8; i++) {
ComGuard.releaseForTest(); ComGuard.releaseForTest();
} }
final dir = Directory.systemTemp.createTempSync('jj_com_').path; final dir = testTempDir('jj_com_').path;
final raw = await tester.runAsync<Object?>(() async { final raw = await tester.runAsync<Object?>(() async {
try { try {
await WebViewEnvironment.create(settings: WebViewEnvironmentSettings(userDataFolder: '${dir}_raw')); await WebViewEnvironment.create(settings: WebViewEnvironmentSettings(userDataFolder: '${dir}_raw'));

View File

@ -11,6 +11,7 @@ import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/app_actions.dart'; import 'package:jj_mkvmaker/ui/app_actions.dart';
import 'package:jj_mkvmaker/ui/browser_page.dart'; import 'package:jj_mkvmaker/ui/browser_page.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 250 실제 엔진 (Windows Edge WebView2): DNS 강제 서버에 닿지 않으면 (TEST-NET 192.0.2.1) 엔진의 오류 화면 /// 250 실제 엔진 (Windows Edge WebView2): DNS 강제 서버에 닿지 않으면 (TEST-NET 192.0.2.1) 엔진의 오류 화면
@ -20,7 +21,7 @@ void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('250: 닿지 않는 DNS → 브라우저에 앱 덮개 (Edge 실제)', (tester) async { testWidgets('250: 닿지 않는 DNS → 브라우저에 앱 덮개 (Edge 실제)', (tester) async {
final data = Platform.environment['JJ_MKVMAKER_DATA'] ?? Directory.systemTemp.createTempSync('jj_dns_block_').path; final data = Platform.environment['JJ_MKVMAKER_DATA'] ?? testTempDir('jj_dns_block_').path;
Directory(data).createSync(recursive: true); Directory(data).createSync(recursive: true);
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService())); final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
c.settings c.settings

View File

@ -9,6 +9,7 @@ import 'package:jj_mkvmaker/platform/windows/desktop_shell.dart';
import 'package:jj_mkvmaker/services/media_player.dart'; import 'package:jj_mkvmaker/services/media_player.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
import 'support/temp_dir.dart';
/// 실제 mpv 플레이어 + 창 모드 /// 실제 mpv 플레이어 + 창 모드
void main() { void main() {
@ -16,7 +17,7 @@ void main() {
testWidgets('재생 목록 · 자막 트랙 · 음량 · 전체 화면 · 팝업 · 창 크기', (tester) async { testWidgets('재생 목록 · 자막 트랙 · 음량 · 전체 화면 · 팝업 · 창 크기', (tester) async {
MediaKitPreviewPlayer.ensureInitialized(); MediaKitPreviewPlayer.ensureInitialized();
final dir = Directory.systemTemp.createTempSync('jj_fp_'); final dir = testTempDir('jj_fp_');
final srt = p.join(dir.path, 's.srt'); final srt = p.join(dir.path, 's.srt');
File(srt).writeAsStringSync('1\n00:00:00,000 --> 00:00:05,000\n내장 자막\n'); File(srt).writeAsStringSync('1\n00:00:00,000 --> 00:00:05,000\n내장 자막\n');
final ext = p.join(dir.path, 'ep1_ko.srt'); final ext = p.join(dir.path, 'ep1_ko.srt');

View File

@ -13,6 +13,7 @@ import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/monitor_page.dart'; import 'package:jj_mkvmaker/ui/monitor_page.dart';
import 'package:jj_mkvmaker/ui/schedule_editor.dart'; import 'package:jj_mkvmaker/ui/schedule_editor.dart';
import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:jj_mkvmaker/ui/theme.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 모니터링 화면 (복사 진행 중 · lsync · 일정 격자) 을 실제 글꼴로 그려 PNG 로 (JJ_SHOT_DIR). 화면 배치 확인용. /// 모니터링 화면 (복사 진행 중 · lsync · 일정 격자) 을 실제 글꼴로 그려 PNG 로 (JJ_SHOT_DIR). 화면 배치 확인용.
@ -21,7 +22,7 @@ void main() {
testWidgets('모니터링 화면 그림', (tester) async { testWidgets('모니터링 화면 그림', (tester) async {
final out = Platform.environment['JJ_SHOT_DIR'] ?? Directory.systemTemp.path; final out = Platform.environment['JJ_SHOT_DIR'] ?? Directory.systemTemp.path;
final tmp = Directory.systemTemp.createTempSync('jj_monshot_'); final tmp = testTempDir('jj_monshot_');
final src = p.join(tmp.path, '영상 원본'), dst = p.join(tmp.path, '백업'); final src = p.join(tmp.path, '영상 원본'), dst = p.join(tmp.path, '백업');
for (var i = 0; i < 6; i++) { for (var i = 0; i < 6; i++) {
File(p.join(src, i < 3 ? 'A' : 'B', 'clip$i.mkv')) File(p.join(src, i < 3 ? 'A' : 'B', 'clip$i.mkv'))

View File

@ -5,6 +5,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:image/image.dart' as img; import 'package:image/image.dart' as img;
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:jj_mkvmaker/core/reader_sources.dart'; import 'package:jj_mkvmaker/core/reader_sources.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 실제 pdfium: 그림 → PDF, 열기 · 그리기, 페이지 지우기 · 그림 넣기 · 저장 /// 실제 pdfium: 그림 → PDF, 열기 · 그리기, 페이지 지우기 · 그림 넣기 · 저장
@ -12,8 +13,7 @@ void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('PDF: 만들기 · 열기 · 지우기 · 넣기 · 저장', (tester) async { testWidgets('PDF: 만들기 · 열기 · 지우기 · 넣기 · 저장', (tester) async {
final dir = Directory.systemTemp.createTempSync('jj_pdf_'); final dir = testTempDir('jj_pdf_');
addTearDown(() => dir.deleteSync(recursive: true));
String image(String name, int w, int h, {bool jpg = false}) { String image(String name, int w, int h, {bool jpg = false}) {
final im = img.Image(width: w, height: h); final im = img.Image(width: w, height: h);
img.fill(im, color: img.ColorRgb8(200, 50, 50)); img.fill(im, color: img.ColorRgb8(200, 50, 50));

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:jj_mkvmaker/platform/common/media_kit_player.dart'; import 'package:jj_mkvmaker/platform/common/media_kit_player.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 실제 Windows 앱에서 libmpv 재생 확인 /// 실제 Windows 앱에서 libmpv 재생 확인
@ -14,7 +15,7 @@ void main() {
testWidgets('media_kit: 영상 열기 · 재생 · 이동', (tester) async { testWidgets('media_kit: 영상 열기 · 재생 · 이동', (tester) async {
MediaKitPreviewPlayer.ensureInitialized(); MediaKitPreviewPlayer.ensureInitialized();
final dir = Directory.systemTemp.createTempSync('jj_play_'); final dir = testTempDir('jj_play_');
final video = p.join(dir.path, '재생 테스트.mp4'); final video = p.join(dir.path, '재생 테스트.mp4');
final r = await Process.run('ffmpeg', [ final r = await Process.run('ffmpeg', [
'-y', '-f', 'lavfi', '-i', 'testsrc=size=320x240:rate=25', '-y', '-f', 'lavfi', '-i', 'testsrc=size=320x240:rate=25',

View File

@ -12,6 +12,7 @@ import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/explorer_page.dart'; import 'package:jj_mkvmaker/ui/explorer_page.dart';
import 'package:jj_mkvmaker/ui/monitor_page.dart'; import 'package:jj_mkvmaker/ui/monitor_page.dart';
import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:jj_mkvmaker/ui/theme.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// Rsync 화면을 실제 rsync (앱에 들어 있는 것) 로: → 한 방향, ⇄ 양쪽 (-u), 모니터링에 남는지. 화면은 JJ_SHOT_DIR 에 PNG. /// Rsync 화면을 실제 rsync (앱에 들어 있는 것) 로: → 한 방향, ⇄ 양쪽 (-u), 모니터링에 남는지. 화면은 JJ_SHOT_DIR 에 PNG.
@ -20,7 +21,7 @@ void main() {
testWidgets('Rsync 화면: → · ⇄ 실제 실행', (tester) async { testWidgets('Rsync 화면: → · ⇄ 실제 실행', (tester) async {
final out = Platform.environment['JJ_SHOT_DIR'] ?? Directory.systemTemp.path; final out = Platform.environment['JJ_SHOT_DIR'] ?? Directory.systemTemp.path;
final tmp = Directory.systemTemp.createTempSync('jj_rsyncpage_'); final tmp = testTempDir('jj_rsyncpage_');
final a = p.join(tmp.path, '왼쪽 폴더'), b = p.join(tmp.path, 'right'); final a = p.join(tmp.path, '왼쪽 폴더'), b = p.join(tmp.path, 'right');
File(p.join(a, 'sub', '한글 파일.txt')) File(p.join(a, 'sub', '한글 파일.txt'))
..createSync(recursive: true) ..createSync(recursive: true)
@ -108,7 +109,7 @@ void main() {
testWidgets('원본 파일 지우기 (--remove-source-files) · 빈 폴더 정리 · lsync 최종 정리', (tester) async { testWidgets('원본 파일 지우기 (--remove-source-files) · 빈 폴더 정리 · lsync 최종 정리', (tester) async {
final out = Platform.environment['JJ_SHOT_DIR'] ?? Directory.systemTemp.path; final out = Platform.environment['JJ_SHOT_DIR'] ?? Directory.systemTemp.path;
final tmp = Directory.systemTemp.createTempSync('jj_rsyncmove_'); final tmp = testTempDir('jj_rsyncmove_');
final a = p.join(tmp.path, 'srcA'), b = p.join(tmp.path, 'dstB'); final a = p.join(tmp.path, 'srcA'), b = p.join(tmp.path, 'dstB');
final cDir = p.join(tmp.path, 'liveC'), d = p.join(tmp.path, 'liveD'); final cDir = p.join(tmp.path, 'liveC'), d = p.join(tmp.path, 'liveD');
for (final (dir, name) in [(a, 'x'), (cDir, 'y')]) { for (final (dir, name) in [(a, 'x'), (cDir, 'y')]) {

View File

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:jj_mkvmaker/services/secret_store.dart'; import 'package:jj_mkvmaker/services/secret_store.dart';
import 'support/temp_dir.dart';
/// 54: 이 기기의 안전 저장소 (Windows DPAPI · Android Keystore) 에 실제로 쓰고 읽고 지운다. /// 54: 이 기기의 안전 저장소 (Windows DPAPI · Android Keystore) 에 실제로 쓰고 읽고 지운다.
/// 시험용 열쇠 하나만 쓰고 끝에 지운다 (사용자가 저장한 값은 건드리지 않음). /// 시험용 열쇠 하나만 쓰고 끝에 지운다 (사용자가 저장한 값은 건드리지 않음).
@ -13,7 +14,7 @@ void main() {
Directory? tmp; Directory? tmp;
SecretStore store() { SecretStore store() {
if (!Platform.isWindows) return SecretStore.platform(); if (!Platform.isWindows) return SecretStore.platform();
return SecretStore.dpapiAt((tmp ??= Directory.systemTemp.createTempSync('jj_secretit_')).path); return SecretStore.dpapiAt((tmp ??= testTempDir('jj_secretit_')).path);
} }
tearDownAll(() { tearDownAll(() {

View File

@ -0,0 +1,29 @@
import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
/// 관리자 지시 (10/19, 28 이 찾음): 통합 시험 · 캡처가 %TEMP%\jj_* 시험 폴더를 남겼다 - 시험 끝 (실패해도) 에 지운다.
/// [base] 가 있으면 그 아래 (짧은 경로가 필요한 캡처). 반드시 시험 (testWidgets · test) 안에서 부른다 (addTearDown).
Directory testTempDir(String prefix, {String? base}) {
final root = base == null || base.isEmpty ? Directory.systemTemp : (Directory(base)..createSync(recursive: true));
final dir = root.createTempSync(prefix);
addTearDown(() => deleteTestTemp(dir));
return dir;
}
/// 시험 폴더 지우기 - Windows 에서 앱 · WebView · 백신이 파일을 잠깐 잡고 있으면 몇 번 다시 해 본다 (기다림은 실제 시간: 가짜 시계 밖).
/// 긴 경로는 \\?\ 로. 끝내 못 지우면 알리기만 하고 시험은 실패시키지 않는다 (tool/test_temp_check.ps1 이 남은 것을 잡는다)
void deleteTestTemp(Directory dir) {
final path = dir.absolute.path;
final target = Platform.isWindows && !path.startsWith(r'\\?\') ? Directory('\\\\?\\$path') : dir;
for (var i = 0; i < 20; i++) {
try {
if (!target.existsSync()) return;
target.deleteSync(recursive: true);
return;
} on FileSystemException {
sleep(const Duration(milliseconds: 250));
}
}
stderr.writeln('시험 임시 폴더를 지우지 못함: $path');
}

View File

@ -17,6 +17,7 @@ import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/app_actions.dart'; import 'package:jj_mkvmaker/ui/app_actions.dart';
import 'package:jj_mkvmaker/ui/browser_page.dart'; import 'package:jj_mkvmaker/ui/browser_page.dart';
import 'package:jj_mkvmaker/ui/tor_page.dart'; import 'package:jj_mkvmaker/ui/tor_page.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 실제 망 (Windows): DNS 강제 (8.8.8.8) 로 앱의 HTTP · 일반 브라우저 (Edge) 가 이름을 푸는지, 닿지 않는 DNS 는 실패로 알리는지, /// 실제 망 (Windows): DNS 강제 (8.8.8.8) 로 앱의 HTTP · 일반 브라우저 (Edge) 가 이름을 푸는지, 닿지 않는 DNS 는 실패로 알리는지,
@ -26,7 +27,7 @@ void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('DNS 강제 · Tor 화면 실제 연결', (tester) async { testWidgets('DNS 강제 · Tor 화면 실제 연결', (tester) async {
final data = Platform.environment['JJ_MKVMAKER_DATA'] ?? Directory.systemTemp.createTempSync('jj_tor_real_').path; final data = Platform.environment['JJ_MKVMAKER_DATA'] ?? testTempDir('jj_tor_real_').path;
Directory(data).createSync(recursive: true); Directory(data).createSync(recursive: true);
ComponentStore.dataDirectory = data; ComponentStore.dataDirectory = data;
ComponentStore.shared = ComponentStore(data); ComponentStore.shared = ComponentStore(data);

View File

@ -11,6 +11,7 @@ import 'package:jj_mkvmaker/core/models.dart';
import 'package:jj_mkvmaker/core/output_paths.dart'; import 'package:jj_mkvmaker/core/output_paths.dart';
import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/browser_page.dart'; import 'package:jj_mkvmaker/ui/browser_page.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 실제 NLLB + 실제 Edge(WebView2): 브라우저를 보면서 영어 자막 → 한국어 번역 → MKV 를 /// 실제 NLLB + 실제 Edge(WebView2): 브라우저를 보면서 영어 자막 → 한국어 번역 → MKV 를
@ -19,7 +20,7 @@ void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('브라우저 + 작업 현황: 영어 자막 → 한국어 번역 → MKV (대기열)', (tester) async { testWidgets('브라우저 + 작업 현황: 영어 자막 → 한국어 번역 → MKV (대기열)', (tester) async {
final dir = Directory.systemTemp.createTempSync('jj_split_'); final dir = testTempDir('jj_split_');
final video = p.join(dir.path, 'movie.mp4'); final video = p.join(dir.path, 'movie.mp4');
final r = await Process.run('ffmpeg', [ final r = await Process.run('ffmpeg', [
'-y', '-f', 'lavfi', '-i', 'testsrc=size=320x240:rate=10', '-f', 'lavfi', '-i', 'sine', '-y', '-f', 'lavfi', '-i', 'testsrc=size=320x240:rate=10', '-f', 'lavfi', '-i', 'sine',
@ -42,7 +43,7 @@ void main() {
await c.init(); await c.init();
await c.addVideos([video]); await c.addVideos([video]);
}); });
c.settings.webViewDataDir = Directory.systemTemp.createTempSync('jj_webview_').path; c.settings.webViewDataDir = testTempDir('jj_webview_').path;
final v = c.videos.single; final v = c.videos.single;
// 같은 폴더의 movie.en.srt 가 자동으로 잡힘 // 같은 폴더의 movie.en.srt 가 자동으로 잡힘
final s = v.subtitles.firstWhere((x) => x.path != null && p.equals(x.path!, en)); final s = v.subtitles.firstWhere((x) => x.path != null && p.equals(x.path!, en));

View File

@ -12,6 +12,7 @@ import 'package:jj_mkvmaker/core/output_paths.dart';
import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:jj_mkvmaker/ui/theme.dart';
import 'package:jj_mkvmaker/ui/video_adjust_dialog.dart'; import 'package:jj_mkvmaker/ui/video_adjust_dialog.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 실제 FFmpeg: 가로 영상 → 화면 · 색 보정 창 미리보기 → 세로 9:16 + 채도 MKV 만들기 /// 실제 FFmpeg: 가로 영상 → 화면 · 색 보정 창 미리보기 → 세로 9:16 + 채도 MKV 만들기
@ -19,7 +20,7 @@ void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('화면 · 색 보정: 미리보기와 세로 9:16 MKV', (tester) async { testWidgets('화면 · 색 보정: 미리보기와 세로 9:16 MKV', (tester) async {
final dir = Directory.systemTemp.createTempSync('jj_adj_e2e_'); final dir = testTempDir('jj_adj_e2e_');
final video = p.join(dir.path, '가로 영상.mp4'); final video = p.join(dir.path, '가로 영상.mp4');
final ffmpeg = p.join(Directory.current.path, 'third_party', 'ffmpeg', 'windows', 'ffmpeg.exe'); final ffmpeg = p.join(Directory.current.path, 'third_party', 'ffmpeg', 'windows', 'ffmpeg.exe');
final r = await Process.run(ffmpeg, [ final r = await Process.run(ffmpeg, [

View File

@ -10,6 +10,7 @@ import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart';
import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart'; import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/browser_page.dart'; import 'package:jj_mkvmaker/ui/browser_page.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 실제 웹뷰 (Windows: Edge WebView2 · Android: 시스템 WebView) + 실제 Google 번역: /// 실제 웹뷰 (Windows: Edge WebView2 · Android: 시스템 WebView) + 실제 Google 번역:
@ -50,7 +51,7 @@ void main() {
await req.response.close(); await req.response.close();
}); });
final url = 'http://127.0.0.1:${server.port}/'; final url = 'http://127.0.0.1:${server.port}/';
final dataDir = Directory.systemTemp.createTempSync('jj_webview_').path; final dataDir = testTempDir('jj_webview_').path;
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService())); final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
c.settings c.settings

View File

@ -4,6 +4,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:whisper_ggml/whisper_ggml.dart'; import 'package:whisper_ggml/whisper_ggml.dart';
import 'support/temp_dir.dart';
/// whisper.cpp 동작 확인 (스마트 앱 컨트롤·속도) /// whisper.cpp 동작 확인 (스마트 앱 컨트롤·속도)
void main() { void main() {
@ -14,7 +15,7 @@ void main() {
'whisper', 'ggml-base.bin'); 'whisper', 'ggml-base.bin');
final assets = p.join(Directory.current.path, 'test_assets'); final assets = p.join(Directory.current.path, 'test_assets');
for (final name in ['speech_en.wav', 'speech_ko.wav']) { for (final name in ['speech_en.wav', 'speech_ko.wav']) {
final tmp = Directory.systemTemp.createTempSync('jj_w_'); final tmp = testTempDir('jj_w_');
final wav = File(p.join(assets, name)).copySync(p.join(tmp.path, name)).path; final wav = File(p.join(assets, name)).copySync(p.join(tmp.path, name)).path;
final sw = Stopwatch()..start(); final sw = Stopwatch()..start();
final r = await tester.runAsync(() => const Whisper(model: WhisperModel.base).transcribe( final r = await tester.runAsync(() => const Whisper(model: WhisperModel.base).transcribe(

View File

@ -14,6 +14,7 @@ import 'package:jj_mkvmaker/ui/app_actions.dart';
import 'package:jj_mkvmaker/ui/browser_page.dart'; import 'package:jj_mkvmaker/ui/browser_page.dart';
import 'package:jj_mkvmaker/ui/home_page.dart'; import 'package:jj_mkvmaker/ui/home_page.dart';
import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:jj_mkvmaker/ui/theme.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 66-2 기기 감독 확인용 (Windows): 지금 화면 아이콘 (넓은 · 좁은 화면) · 처음으로 알림 · 브라우저 안내 한 줄을 PNG (JJ_SHOT_DIR) 로. /// 66-2 기기 감독 확인용 (Windows): 지금 화면 아이콘 (넓은 · 좁은 화면) · 처음으로 알림 · 브라우저 안내 한 줄을 PNG (JJ_SHOT_DIR) 로.
@ -83,9 +84,7 @@ void main() {
..components = ['mkv', 'browser', 'explorer', 'rsync'] ..components = ['mkv', 'browser', 'explorer', 'rsync']
..navOrder = ['mkv', 'browser', 'explorer', 'rsync']; ..navOrder = ['mkv', 'browser', 'explorer', 'rsync'];
final base = Platform.environment['JJ_SHOT_TMP']; final base = Platform.environment['JJ_SHOT_TMP'];
final dir = (base == null || base.isEmpty ? Directory.systemTemp : (Directory(base)..createSync(recursive: true))) final dir = testTempDir('jj_shot_662_', base: base);
.createTempSync('jj_shot_662_');
addTearDown(() => dir.deleteSync(recursive: true));
final bm = BookmarksController(p.join(dir.path, 'bookmarks.json')); final bm = BookmarksController(p.join(dir.path, 'bookmarks.json'));
t.view.physicalSize = const Size(1280, 800); t.view.physicalSize = const Size(1280, 800);
t.view.devicePixelRatio = 1; t.view.devicePixelRatio = 1;

View File

@ -14,6 +14,7 @@ import 'package:path/path.dart' as p;
import '../test/support/fake_recycle_bin.dart'; import '../test/support/fake_recycle_bin.dart';
import '../test/support/recycle_leftovers.dart'; import '../test/support/recycle_leftovers.dart';
import 'support/temp_dir.dart';
/// 묶음 3 (데이터 쪽) 기기 감독 확인용 (Windows): 실제 앱 화면을 띄워 누르고 단계마다 PNG (JJ_SHOT_DIR) 로 남긴다. /// 묶음 3 (데이터 쪽) 기기 감독 확인용 (Windows): 실제 앱 화면을 띄워 누르고 단계마다 PNG (JJ_SHOT_DIR) 로 남긴다.
/// 165 (드라이브 · 연결 안 됨) · 48 (같은 이름) · 52 (돌아와도 진행 막대) · 148 (휴지통 되돌리기) · 144 (긴 경로). /// 165 (드라이브 · 연결 안 됨) · 48 (같은 이름) · 52 (돌아와도 진행 막대) · 148 (휴지통 되돌리기) · 144 (긴 경로).
@ -23,9 +24,7 @@ void main() {
final out = Platform.environment['JJ_SHOT_DIR'] ?? p.join(Directory.systemTemp.path, 'jj_shots_b3'); final out = Platform.environment['JJ_SHOT_DIR'] ?? p.join(Directory.systemTemp.path, 'jj_shots_b3');
Directory tempDir(String prefix) { Directory tempDir(String prefix) {
final base = Platform.environment['JJ_SHOT_TMP']; final base = Platform.environment['JJ_SHOT_TMP'];
if (base == null || base.isEmpty) return Directory.systemTemp.createTempSync(prefix); return testTempDir(prefix, base: base);
Directory(base).createSync(recursive: true);
return Directory(base).createTempSync(prefix);
} }
final key = GlobalKey(); final key = GlobalKey();

View File

@ -12,6 +12,7 @@ import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/explorer_page.dart'; import 'package:jj_mkvmaker/ui/explorer_page.dart';
import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:jj_mkvmaker/ui/theme.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 관리자 지시 9 (10/17): 82 끌어 놓기 · 75 마우스 4 · 5 번을 Windows 실제 빌드에서 가짜 포인터로 (실제 마우스 · 키보드는 쓰지 않음). /// 관리자 지시 9 (10/17): 82 끌어 놓기 · 75 마우스 4 · 5 번을 Windows 실제 빌드에서 가짜 포인터로 (실제 마우스 · 키보드는 쓰지 않음).
@ -26,7 +27,7 @@ void main() {
setUp(() async { setUp(() async {
await i18n.apply('ko', save: false); await i18n.apply('ko', save: false);
tmp = Directory.systemTemp.createTempSync('jj_b6input_'); tmp = testTempDir('jj_b6input_');
left = p.join(tmp.path, 'left'); left = p.join(tmp.path, 'left');
right = p.join(tmp.path, 'right'); right = p.join(tmp.path, 'right');
File(p.join(left, 'doc.txt')) File(p.join(left, 'doc.txt'))

View File

@ -21,6 +21,7 @@ import 'package:jj_mkvmaker/ui/explorer_search.dart';
import 'package:jj_mkvmaker/ui/quick_look.dart'; import 'package:jj_mkvmaker/ui/quick_look.dart';
import 'package:jj_mkvmaker/ui/storage_page.dart'; import 'package:jj_mkvmaker/ui/storage_page.dart';
import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:jj_mkvmaker/ui/theme.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 관리자 지시 5 (10/17): 기기 없이 15 가 볼 수 있게 묶음6 새 화면을 PNG 로 (JJ_SHOT_DIR, 없으면 임시 폴더). /// 관리자 지시 5 (10/17): 기기 없이 15 가 볼 수 있게 묶음6 새 화면을 PNG 로 (JJ_SHOT_DIR, 없으면 임시 폴더).
@ -38,8 +39,7 @@ void main() {
addTearDown(t.view.reset); addTearDown(t.view.reset);
await t.runAsync(() => i18n.apply(lang, save: false)); await t.runAsync(() => i18n.apply(lang, save: false));
addTearDown(() => i18n.apply('ko', save: false)); addTearDown(() => i18n.apply('ko', save: false));
final tmp = Directory.systemTemp.createTempSync('jj_b6shot_'); final tmp = testTempDir('jj_b6shot_');
addTearDown(() => tmp.deleteSync(recursive: true));
// 시험 파일 // 시험 파일
File(p.join(tmp.path, 'Show', 'ep01.mkv')) File(p.join(tmp.path, 'Show', 'ep01.mkv'))
..createSync(recursive: true) ..createSync(recursive: true)

View File

@ -20,6 +20,7 @@ import 'package:jj_mkvmaker/ui/theme.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import '../test/support/fake_recycle_bin.dart'; import '../test/support/fake_recycle_bin.dart';
import 'support/temp_dir.dart';
/// 기기 감독 (Windows) 확인용: 실제 앱 화면을 띄워 누르고 단계마다 PNG (JJ_SHOT_DIR) 로 남긴다. /// 기기 감독 (Windows) 확인용: 실제 앱 화면을 띄워 누르고 단계마다 PNG (JJ_SHOT_DIR) 로 남긴다.
/// 65 · 94 · 98 (휴지통 · 휴지통 없는 위치 · 오류 문구), 37 (경로 입력), 124 · 130 (마스터 · 최상), 123 (AI 그림). /// 65 · 94 · 98 (휴지통 · 휴지통 없는 위치 · 오류 문구), 37 (경로 입력), 124 · 130 (마스터 · 최상), 123 (AI 그림).
@ -30,9 +31,7 @@ void main() {
// 시험 폴더: 항목이 아주 많은 시스템 임시 폴더 대신 (JJ_SHOT_TMP, 없으면 시스템 임시 폴더) // 시험 폴더: 항목이 아주 많은 시스템 임시 폴더 대신 (JJ_SHOT_TMP, 없으면 시스템 임시 폴더)
Directory tempDir(String prefix) { Directory tempDir(String prefix) {
final base = Platform.environment['JJ_SHOT_TMP']; final base = Platform.environment['JJ_SHOT_TMP'];
if (base == null || base.isEmpty) return Directory.systemTemp.createTempSync(prefix); return testTempDir(prefix, base: base);
Directory(base).createSync(recursive: true);
return Directory(base).createTempSync(prefix);
} }
final key = GlobalKey(); final key = GlobalKey();
const sizes = [('narrow', Size(700, 900)), ('wide', Size(1280, 800))]; const sizes = [('narrow', Size(700, 900)), ('wide', Size(1280, 800))];

View File

@ -8,6 +8,7 @@ import 'package:integration_test/integration_test.dart';
import 'package:jj_mkvmaker/app/i18n_controller.dart'; import 'package:jj_mkvmaker/app/i18n_controller.dart';
import 'package:jj_mkvmaker/ui/file_tools.dart'; import 'package:jj_mkvmaker/ui/file_tools.dart';
import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:jj_mkvmaker/ui/theme.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 관리자 지시 (10/18): X-plore P3 화면을 PNG 로 (JJ_SHOT_DIR, 없으면 임시 폴더) - 해시 창 · 폴더 속성 · 16진 보기. /// 관리자 지시 (10/18): X-plore P3 화면을 PNG 로 (JJ_SHOT_DIR, 없으면 임시 폴더) - 해시 창 · 폴더 속성 · 16진 보기.
@ -23,8 +24,7 @@ void main() {
addTearDown(t.view.reset); addTearDown(t.view.reset);
await t.runAsync(() => i18n.apply(lang, save: false)); await t.runAsync(() => i18n.apply(lang, save: false));
addTearDown(() => i18n.apply('ko', save: false)); addTearDown(() => i18n.apply('ko', save: false));
final tmp = Directory.systemTemp.createTempSync('jj_p3shot_'); final tmp = testTempDir('jj_p3shot_');
addTearDown(() => tmp.deleteSync(recursive: true));
final file = File(p.join(tmp.path, '영상 폴더', 'ep01 긴 이름의 동영상 파일.mkv')) final file = File(p.join(tmp.path, '영상 폴더', 'ep01 긴 이름의 동영상 파일.mkv'))
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsBytesSync(List.generate(5000, (i) => i % 256)); ..writeAsBytesSync(List.generate(5000, (i) => i % 256));

View File

@ -13,6 +13,7 @@ import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:jj_mkvmaker/ui/theme.dart';
import 'package:jj_mkvmaker/ui/wifi_share_page.dart'; import 'package:jj_mkvmaker/ui/wifi_share_page.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// 관리자 지시 (10/18): 89 Wi-Fi 공유 화면을 PNG 로 (JJ_SHOT_DIR) - 켜기 전 · 켠 뒤 (코드 · 주소 · QR · 남은 시간 · 접속 기록). /// 관리자 지시 (10/18): 89 Wi-Fi 공유 화면을 PNG 로 (JJ_SHOT_DIR) - 켜기 전 · 켠 뒤 (코드 · 주소 · QR · 남은 시간 · 접속 기록).
@ -37,8 +38,7 @@ void main() {
WifiShare.debugLoopbackOnly = false; WifiShare.debugLoopbackOnly = false;
WifiShare.debugAddresses = null; WifiShare.debugAddresses = null;
}); });
final tmp = Directory.systemTemp.createTempSync('jj_wifishot_'); final tmp = testTempDir('jj_wifishot_');
addTearDown(() => tmp.deleteSync(recursive: true));
final dir = Directory(p.join(tmp.path, '여행 사진'))..createSync(); final dir = Directory(p.join(tmp.path, '여행 사진'))..createSync();
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService())); final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
final shotKey = GlobalKey(); final shotKey = GlobalKey();

View File

@ -14,6 +14,7 @@ import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/services/platform_services.dart'; import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/explorer_page.dart'; import 'package:jj_mkvmaker/ui/explorer_page.dart';
import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:jj_mkvmaker/ui/theme.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// X-plore 비교 P1 (관리자 지시 10/18): X-plore 스타일 탐색기를 PNG 로 (JJ_SHOT_DIR, 없으면 임시 폴더). /// X-plore 비교 P1 (관리자 지시 10/18): X-plore 스타일 탐색기를 PNG 로 (JJ_SHOT_DIR, 없으면 임시 폴더).
@ -31,8 +32,7 @@ void main() {
addTearDown(t.view.reset); addTearDown(t.view.reset);
await t.runAsync(() => i18n.apply(lang, save: false)); await t.runAsync(() => i18n.apply(lang, save: false));
addTearDown(() => i18n.apply('ko', save: false)); addTearDown(() => i18n.apply('ko', save: false));
final tmp = Directory.systemTemp.createTempSync('jj_xpshot_'); final tmp = testTempDir('jj_xpshot_');
addTearDown(() => tmp.deleteSync(recursive: true));
final a = Directory(p.join(tmp.path, 'Videos'))..createSync(); final a = Directory(p.join(tmp.path, 'Videos'))..createSync();
final b = Directory(p.join(tmp.path, 'Backup'))..createSync(); final b = Directory(p.join(tmp.path, 'Backup'))..createSync();
for (final n in ['Show S01', 'Movies']) { for (final n in ['Show S01', 'Movies']) {

View File

@ -15,6 +15,7 @@ import 'package:jj_mkvmaker/ui/explorer_grid.dart';
import 'package:jj_mkvmaker/ui/storage_page.dart'; import 'package:jj_mkvmaker/ui/storage_page.dart';
import 'package:jj_mkvmaker/ui/text_viewer.dart'; import 'package:jj_mkvmaker/ui/text_viewer.dart';
import 'package:jj_mkvmaker/ui/theme.dart'; import 'package:jj_mkvmaker/ui/theme.dart';
import 'support/temp_dir.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
/// X-plore 비교 g · h · i · P3 (관리자 지시 10/18): 격자 보기 · 글 뷰어 · 일괄 이름 (날짜) · 저장 공간 그림을 PNG 로 /// X-plore 비교 g · h · i · P3 (관리자 지시 10/18): 격자 보기 · 글 뷰어 · 일괄 이름 (날짜) · 저장 공간 그림을 PNG 로
@ -31,8 +32,7 @@ void main() {
addTearDown(t.view.reset); addTearDown(t.view.reset);
await t.runAsync(() => i18n.apply(lang, save: false)); await t.runAsync(() => i18n.apply(lang, save: false));
addTearDown(() => i18n.apply('ko', save: false)); addTearDown(() => i18n.apply('ko', save: false));
final tmp = Directory.systemTemp.createTempSync('jj_xptshot_'); final tmp = testTempDir('jj_xptshot_');
addTearDown(() => tmp.deleteSync(recursive: true));
// 그림 (색이 다른 작은 그림) · 동영상 이름 · 글 (CP949) // 그림 (색이 다른 작은 그림) · 동영상 이름 · 글 (CP949)
final pics = <String>[]; final pics = <String>[];
for (var i = 0; i < 7; i++) { for (var i = 0; i < 7; i++) {

View File

@ -5,15 +5,33 @@
# - 다른 worktree · 세션이 같은 시험을 동시에 돌리면 그쪽 폴더가 섞일 수 있다 (이름으로 확인). # - 다른 worktree · 세션이 같은 시험을 동시에 돌리면 그쪽 폴더가 섞일 수 있다 (이름으로 확인).
# - 이미 있던 폴더는 건드리지 않는다 (지우지 않음). # - 이미 있던 폴더는 건드리지 않는다 (지우지 않음).
# 사용 (app 폴더에서): powershell -ExecutionPolicy Bypass -File tool\test_temp_check.ps1 [flutter test 인자…] # 사용 (app 폴더에서): powershell -ExecutionPolicy Bypass -File tool\test_temp_check.ps1 [flutter test 인자…]
# 통합 시험 · 캡처도 (관리자 지시 10/19, 28 이 찾음): … test_temp_check.ps1 integration_test\windows_b6_shot_test.dart -d windows
# - 폴더 이름 앞부분은 test 와 integration_test 두 곳의 시험 소스에서 모은다
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
$app = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path $app = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
$temp = [System.IO.Path]::GetTempPath() $temp = [System.IO.Path]::GetTempPath()
# 시험 소스가 쓰는 임시 폴더 이름 앞부분 (createTemp('jj_x_') · createTempSync('jj_x_')) # 시험 소스가 쓰는 임시 폴더 이름 앞부분 (createTemp('jj_x_') · createTempSync('jj_x_'))
$prefixes = @(Get-ChildItem (Join-Path $app 'test') -Recurse -Filter *.dart | # 넘겨받은 시험 파일 (.dart) 이 있으면 그 파일들과 support 폴더만 본다 - 다른 세션 · worktree 가 같은 때 돌린 시험의 폴더를 세지 않게
ForEach-Object { [regex]::Matches((Get-Content $_.FullName -Raw -Encoding utf8), 'createTemp(?:Sync)?\(''(jj[^''$]*)''') } | # (10/19: b6 캡처 앞뒤에 다른 세션의 단위 시험 폴더 jj_explorer_ · jj_sync_ 가 섞여 거짓 실패)
$named = @($args | Where-Object { "$_" -like '*.dart' } | ForEach-Object { Join-Path $app "$_" } | Where-Object { Test-Path $_ })
$sources = if ($named.Count -gt 0) {
# 그 파일들이 가져다 쓰는 support 파일만 함께 (import 'support/…') - 다른 세션의 시험과 이름이 겹치지 않게 (10/19: jj_fake_recycle_)
$support = @($named | ForEach-Object {
$dir = Split-Path $_
[regex]::Matches((Get-Content $_ -Raw -Encoding utf8), "import '(support/[^']+\.dart)'") |
ForEach-Object { Join-Path $dir $_.Groups[1].Value } })
@($named) + @($support | Where-Object { Test-Path $_ })
} else {
@(@('test', 'integration_test') | ForEach-Object { Join-Path $app $_ } | Where-Object { Test-Path $_ } |
ForEach-Object { Get-ChildItem $_ -Recurse -Filter *.dart | ForEach-Object { $_.FullName } })
}
# 이름이 하나도 없으면 (임시 폴더를 만들지 않는 시험) 새 jj 폴더는 참고로만 보인다
# 이름 앞부분: createTemp('jj_x_') · createTempSync('jj_x_') · testTempDir('jj_x_') (integration_test/support/temp_dir.dart)
$prefixes = @($sources |
ForEach-Object { [regex]::Matches((Get-Content $_ -Raw -Encoding utf8), '(?:createTemp(?:Sync)?|testTempDir)\(''(jj[^''$]*)''') } |
ForEach-Object { $_.Groups[1].Value } | Sort-Object -Unique) ForEach-Object { $_.Groups[1].Value } | Sort-Object -Unique)
if ($prefixes.Count -eq 0) { throw '시험 소스에서 임시 폴더 이름을 찾지 못했습니다' } if ($prefixes.Count -eq 0 -and $named.Count -eq 0) { throw '시험 소스에서 임시 폴더 이름을 찾지 못했습니다' }
function Get-TestTemp { function Get-TestTemp {
@(Get-ChildItem $temp -Directory -Filter 'jj*' -ErrorAction SilentlyContinue | ForEach-Object { $_.Name }) @(Get-ChildItem $temp -Directory -Filter 'jj*' -ErrorAction SilentlyContinue | ForEach-Object { $_.Name })
@ -34,6 +52,12 @@ $left = @(Get-TestTemp | Where-Object { -not $before.ContainsKey($_) } | Where-O
$n = $_ $n = $_
@($prefixes | Where-Object { $n.StartsWith($_) }).Count -gt 0 @($prefixes | Where-Object { $n.StartsWith($_) }).Count -gt 0
}) })
# 참고: 시험 소스의 이름이 아닌 새 jj 폴더 (앱 코드가 만든 것일 수 있음 - 실패로 세지 않고 보이기만)
$other = @(Get-TestTemp | Where-Object { -not $before.ContainsKey($_) -and $left -notcontains $_ })
if ($other.Count -gt 0) {
Write-Host ("참고 - 시험 소스에 없는 이름의 새 jj 폴더 {0}개:" -f $other.Count)
$other | Sort-Object | ForEach-Object { Write-Host " $_" }
}
if ($left.Count -gt 0) { if ($left.Count -gt 0) {
Write-Host ("시험이 남긴 임시 폴더 {0}개 (%TEMP%):" -f $left.Count) Write-Host ("시험이 남긴 임시 폴더 {0}개 (%TEMP%):" -f $left.Count)
$left | Sort-Object | ForEach-Object { Write-Host " $_" } $left | Sort-Object | ForEach-Object { Write-Host " $_" }