JJ_MKVMaker/test/start_menu_test.dart

89 lines
5.3 KiB
Dart

import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:jj_mkvmaker/core/playlist.dart';
import 'package:jj_mkvmaker/platform/windows/start_menu.dart';
import 'package:path/path.dart' as p;
import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart';
/// 99: 시작 메뉴 바로 가기 (앱 ID 포함) · 알림을 누르면 jjmkvmaker://lsync 로 실시간 동기화 화면
/// (시험은 임시 폴더에 만든다 - 사용자의 시작 메뉴 · 레지스트리는 건드리지 않음)
void main() {
test('바로 가기를 앱 ID (AUMID) 와 함께 만들고, 실행 파일이 바뀌면 고친다', () async {
final tmp = Directory.systemTemp.createTempSync('jj_lnk_');
addTearDown(() => tmp.deleteSync(recursive: true));
final lnk = p.join(tmp.path, 'JJ_MKVMaker.lnk');
final exe1 = Platform.resolvedExecutable;
expect(await StartMenu.user.ensure(exe: exe1, lnk: lnk, registerProtocol: false), isTrue);
expect(File(lnk).existsSync(), isTrue);
Future<String> read(String what) async => '${(await Process.run('powershell.exe', [
'-NoProfile',
'-Command',
what == 'id'
? "(New-Object -ComObject Shell.Application).Namespace('${tmp.path}').ParseName('JJ_MKVMaker.lnk').ExtendedProperty('System.AppUserModel.ID')"
: "(New-Object -ComObject WScript.Shell).CreateShortcut('$lnk').TargetPath",
])).stdout}'
.trim();
expect(await read('id'), StartMenu.aumid);
expect((await read('target')).toLowerCase(), exe1.toLowerCase());
// 앱 폴더를 옮긴 경우: 다음 실행 때 새 위치로
final exe2 = p.join(Platform.environment['SystemRoot'] ?? r'C:\Windows', 'notepad.exe');
expect(await StartMenu.user.ensure(exe: exe2, lnk: lnk, registerProtocol: false), isTrue);
expect((await read('target')).toLowerCase(), exe2.toLowerCase());
expect(await read('id'), StartMenu.aumid);
}, skip: !Platform.isWindows, timeout: const Timeout(Duration(minutes: 2)));
test('관리자 지시 (10/20): 시험판 · 시험 (따로 데이터) 이면 사용자 시작 메뉴 · jjmkvmaker:// 를 바꾸거나 지우지 않는다', () async {
// 명령은 가짜로만 (사용자 영역을 건드리지 않음) - 무엇을 부르는지만 본다
final calls = <String>[];
final tmp = Directory.systemTemp.createTempSync('jj_lnk_');
addTearDown(() => tmp.deleteSync(recursive: true));
// 바로 가기 파일도 시험 폴더로 (시험이 잘못돼도 사용자 시작 메뉴의 것을 지우지 않게) - 설계 M4: 가짜를 넘긴 인스턴스
final lnk = p.join(tmp.path, 'JJ_MKVMaker.lnk');
File(lnk).writeAsStringSync('x');
var locked = true;
final menu = StartMenu(
shortcutPath: lnk,
userAreaLocked: () => locked,
run: (exe, args) async {
calls.add(exe);
return ProcessResult(0, 0, 'JJ_OK', '');
},
);
expect(await menu.ensure(), isFalse, reason: '사용자 바로 가기 · 주소 연결');
expect(await menu.ensure(lnk: lnk), isFalse, reason: '주소 연결 (HKCU) 은 사용자 영역');
await menu.remove();
expect(calls, isEmpty, reason: '막힌 동안은 아무 명령도 부르지 않음');
expect(File(lnk).existsSync(), isTrue, reason: '바로 가기를 지우지 않음');
// 시험이 따로 준 바로 가기 파일만 쓰는 것은 그대로
expect(await menu.ensure(exe: Platform.resolvedExecutable, lnk: lnk, registerProtocol: false), isTrue);
expect(calls, ['powershell.exe']);
// 막지 않으면 (사용자 판) 예전처럼 부른다
locked = false;
calls.clear();
expect(await menu.ensure(), isTrue);
await menu.remove();
expect(calls, ['powershell.exe', 'reg.exe']);
expect(File(lnk).existsSync(), isFalse, reason: '사용자 판에서 끄면 지움 (여기서는 시험 폴더의 것)');
}, skip: !Platform.isWindows);
test('알림을 누르면 오는 주소 (jjmkvmaker://lsync) 는 실시간 동기화 화면 요청', () {
expect(LaunchRequest.parse(['jjmkvmaker://lsync/']).action, LaunchAction.lsync);
expect(LaunchRequest.parse(['jjmkvmaker://lsync/']).files, isEmpty);
expect(LaunchRequest.parse(['--lsync']).action, LaunchAction.lsync);
expect(LaunchRequest.parse(LaunchRequest(LaunchAction.lsync, const []).toArgs()).action, LaunchAction.lsync);
expect(LaunchRequest.parse(['jjmkvmaker://other']).files, isEmpty); // 모르는 주소를 파일로 열지 않음
});
test('설계 M4: PlatformServices 를 손으로 조립하면 시작 메뉴는 사용자 영역을 건드리지 않는 것 (늘 막힘 · 바로 가기 자리는 임시 폴더)', () async {
final s = PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService());
final userLnk = p.join(Platform.environment['APPDATA'] ?? '', 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'JJ_MKVMaker.lnk');
expect(s.startMenu.userAreaLocked(), isTrue);
expect(p.equals(s.startMenu.shortcutPath, userLnk), isFalse, reason: '사용자 시작 메뉴가 아님');
expect(p.isWithin(Directory.systemTemp.path, s.startMenu.shortcutPath), isTrue);
expect(await s.startMenu.ensure(), isFalse, reason: '막힘 - 아무것도 만들지 않음');
});
}