JJ_MKVMaker/test/ai_quality_test.dart

75 lines
3.8 KiB
Dart

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:image/image.dart' as img;
import 'package:jj_mkvmaker/app/ai_local.dart';
import 'package:jj_mkvmaker/app/ai_upscale.dart';
import 'package:jj_mkvmaker/app/app_controller.dart';
import 'package:jj_mkvmaker/app/settings.dart';
import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart';
import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/ai_upscale_ui.dart';
import 'package:path/path.dart' as p;
/// 관리자 판단 (10/17, 사용자 질문에 답이 없어 둘 다 넣고 기본 꺼짐):
/// (a) 해상도 올리기 배율 "1배 (선명하게)" - 크기 그대로 · 처음 값은 2배 그대로
/// (b) [품질 올리기] - 그림 → 그림 약하게 + 해상도 올리기, 단추는 설정으로 (처음 끔), 새 파일 "이름_q", 모델이 없으면 안내
void main() {
late Directory tmp;
setUp(() => tmp = Directory.systemTemp.createTempSync('jj_quality_t_'));
tearDown(() => tmp.deleteSync(recursive: true));
test('설정: 배율 1 을 받아들이고 처음 값은 2 · 품질 올리기 단추는 처음 끔 · 저장', () {
expect(AppSettings().aiUpScale, 2);
expect(AppSettings.fromJson({'aiUpScale': 1}).aiUpScale, 1);
expect(AppSettings.fromJson({'aiUpScale': 7}).aiUpScale, 2);
expect(AppSettings().aiQualityButton, isFalse);
expect(AppSettings.fromJson((AppSettings()..aiQualityButton = true).toJson()).aiQualityButton, isTrue);
});
test('1배: 4배 결과를 원본 크기로 줄인다 (선명하게만)', () async {
final four = img.encodePng(img.Image(width: 40, height: 24));
final out = img.decodePng(await finishUpscale(four, origW: 10, origH: 6, scale: 1, ext: 'png'))!;
expect((out.width, out.height), (10, 6));
expect(p.basename(upscaledPath(p.join(tmp.path, 'a.jpg'), scale: 1, ext: 'jpg')), 'a_x1.jpg');
});
test('품질 올리기: 저장 이름 "이름_q" (덮어쓰지 않음) · 그림 → 그림 크기 (64 배수 · 긴 쪽 1024 까지)', () {
final src = p.join(tmp.path, 'b.png');
expect(p.basename(upscaledPath(src, scale: 2, ext: 'png', suffix: '_q')), 'b_q.png');
File(p.join(tmp.path, 'b_q.png')).writeAsStringSync('x');
expect(p.basename(upscaledPath(src, scale: 2, ext: 'png', suffix: '_q')), 'b_q (2).png');
expect(qualitySize(800, 600), (832, 576));
expect(qualitySize(4000, 3000), (1024, 768));
expect(qualitySize(100, 50), (256, 256));
expect(qualitySize(0, 0), (512, 512));
});
testWidgets('품질 올리기: AI 그림 모델이 없으면 받으라는 안내 (원본은 그대로)', (tester) async {
final input = p.join(tmp.path, 'page.png');
File(input).writeAsBytesSync(img.encodePng(img.Image(width: 8, height: 6)));
final before = AiStore.instance;
AiStore.instance = AiStore(p.join(tmp.path, 'ai')); // 받은 모델이 없는 곳
addTearDown(() => AiStore.instance = before);
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Builder(
builder: (ctx) => TextButton(
onPressed: () => qualityUp(ctx, c, input: input, nameFrom: input, outDir: tmp.path),
child: const Text('품질'),
),
),
),
));
await tester.tap(find.text('품질'));
await tester.pumpAndSettle();
expect(find.textContaining('AI 그림 모델이 필요합니다'), findsOneWidget);
await tester.tap(find.text('닫기'));
await tester.pumpAndSettle();
expect(tmp.listSync().map((e) => p.basename(e.path)).where((n) => n.contains('_q')), isEmpty);
});
}