121 lines
5.2 KiB
Dart
121 lines
5.2 KiB
Dart
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:jj_mkvmaker/core/app_manager.dart';
|
|
import 'package:jj_mkvmaker/ui/app_manager_page.dart';
|
|
import 'package:jj_mkvmaker/ui/explorer_page.dart' show ExplorerButton;
|
|
import 'package:path/path.dart' as p;
|
|
|
|
/// X-plore 비교 5-2 앱 관리자 (사용자 결정 10/21, Android): 보이는 앱만 · APK 백업 · 앱 정보 · 지우기 (시스템 창)
|
|
class _Fake implements AppManagerBackend {
|
|
final List<InstalledApp> apps;
|
|
final String dir;
|
|
final calls = <String>[];
|
|
_Fake(this.apps, this.dir);
|
|
@override
|
|
Future<List<InstalledApp>> list() async => apps;
|
|
@override
|
|
Future<Uint8List?> icon(String package) async => null;
|
|
@override
|
|
Future<bool> details(String package) async {
|
|
calls.add('details:$package');
|
|
return true;
|
|
}
|
|
|
|
@override
|
|
Future<bool> uninstall(String package) async {
|
|
calls.add('uninstall:$package');
|
|
return true;
|
|
}
|
|
|
|
@override
|
|
Future<String> backupDir() async => dir;
|
|
}
|
|
|
|
void main() {
|
|
late Directory tmp;
|
|
setUp(() => tmp = Directory.systemTemp.createTempSync('jj_apps_'));
|
|
tearDown(() => tmp.deleteSync(recursive: true));
|
|
|
|
InstalledApp app(String label, {int size = 1000, int day = 1, bool system = false, int splits = 0, String? apk}) => InstalledApp(
|
|
package: 'com.x.${label.toLowerCase()}',
|
|
label: label,
|
|
version: '1.2',
|
|
apk: apk ?? '',
|
|
installed: DateTime(2026, 1, day),
|
|
updated: DateTime(2026, 1, day),
|
|
size: size,
|
|
system: system,
|
|
splits: splits,
|
|
);
|
|
|
|
test('기기 답 (지도) 읽기 · APK 백업 이름 (못 쓰는 글자 _ · 이미 있으면 (2))', () async {
|
|
final a = InstalledApp.fromMap({'package': 'p', 'label': 'A/B', 'version': '3', 'apk': '/x', 'installed': 0, 'updated': 0, 'size': 5, 'splits': 2, 'system': true});
|
|
expect((a.label, a.size, a.splits, a.system), ('A/B', 5, 2, true));
|
|
final src = File(p.join(tmp.path, 'base.apk'))..writeAsStringSync('apk');
|
|
final b = app('A/B', apk: src.path);
|
|
final out = p.join(tmp.path, 'out');
|
|
final first = await backupApk(b, out);
|
|
final second = await backupApk(b, out);
|
|
expect(p.basename(first), 'A_B_1.2.apk');
|
|
expect(p.basename(second), 'A_B_1.2 (2).apk');
|
|
expect(File(second).readAsStringSync(), 'apk');
|
|
});
|
|
|
|
testWidgets('화면: 안내 · 이름 / 크기 / 설치일 정렬 · 찾기 · [APK 백업] · [앱 정보] · 시스템 앱은 [지우기] 없음', (tester) async {
|
|
tester.view.physicalSize = const Size(900, 1400);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.reset);
|
|
final src = File(p.join(tmp.path, 'b.apk'))..writeAsStringSync('apk');
|
|
final fake = _Fake([
|
|
app('Banana', size: 300, day: 5, apk: src.path, splits: 3),
|
|
app('Apple', size: 900, day: 1),
|
|
app('Settings', size: 100, day: 2, system: true),
|
|
], p.join(tmp.path, 'Download', 'JJ_MKVMaker', 'apk'));
|
|
await tester.pumpWidget(MaterialApp(home: AppManagerPage(backend: fake)));
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('보이는 앱만 나옵니다 (모든 앱 목록 권한은 쓰지 않음)'), findsOneWidget);
|
|
double y(String t) => tester.getTopLeft(find.text(t)).dy;
|
|
expect(y('Apple') < y('Banana') && y('Banana') < y('Settings'), isTrue, reason: '처음은 이름 순');
|
|
await tester.tap(find.text('이름'));
|
|
await tester.pumpAndSettle();
|
|
await tester.tap(find.text('크기').last);
|
|
await tester.pumpAndSettle();
|
|
expect(y('Apple') < y('Banana'), isTrue, reason: '큰 것부터');
|
|
await tester.enterText(find.byType(TextField), 'ban');
|
|
await tester.pump();
|
|
expect(find.text('Apple'), findsNothing);
|
|
// APK 백업 (나눠진 앱이면 알림)
|
|
await tester.tap(find.text('Banana'));
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('지우기 (시스템 창에서 확인)'), findsOneWidget);
|
|
await tester.tap(find.text('APK 백업'));
|
|
for (var i = 0; i < 20; i++) {
|
|
await tester.runAsync(() => Future<void>.delayed(const Duration(milliseconds: 20)));
|
|
await tester.pump();
|
|
}
|
|
expect(File(p.join(fake.dir, 'Banana_1.2.apk')).existsSync(), isTrue);
|
|
expect(find.textContaining('나눠진 앱 (조각 3개)'), findsOneWidget);
|
|
// 시스템 앱: 지우기 없음 · 앱 정보는 시스템 화면
|
|
await tester.enterText(find.byType(TextField), 'set');
|
|
await tester.pump();
|
|
await tester.tap(find.text('Settings'));
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('지우기 (시스템 창에서 확인)'), findsNothing);
|
|
await tester.tap(find.text('앱 정보 (시스템 화면)'));
|
|
await tester.pumpAndSettle();
|
|
expect(fake.calls, ['details:com.x.settings']);
|
|
});
|
|
|
|
test('가운데 버튼 [앱 관리자] 는 Android 에서만 고를 수 있음', () {
|
|
final was = ExplorerButton.appsButtonSupported;
|
|
addTearDown(() => ExplorerButton.appsButtonSupported = was);
|
|
ExplorerButton.appsButtonSupported = () => false;
|
|
expect(ExplorerButton.explorerValues, isNot(contains(ExplorerButton.apps)));
|
|
ExplorerButton.appsButtonSupported = () => true;
|
|
expect(ExplorerButton.explorerValues, contains(ExplorerButton.apps));
|
|
});
|
|
}
|