195 lines
12 KiB
Dart
195 lines
12 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:flutter/foundation.dart' show LicenseRegistry;
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:jj_mkvmaker/core/ai_catalog.dart';
|
|
import 'package:jj_mkvmaker/ui/license_texts.dart';
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
test('62 · 63 · 64: GPL · LGPL 원문 · 고지 문서 · PDFium · yt-dlp 가 라이선스 화면에', () async {
|
|
registerAppLicenses();
|
|
final entries = await LicenseRegistry.licenses.toList();
|
|
String find(String name) {
|
|
final e = entries.firstWhere((e) => e.packages.any((p) => p.startsWith(name)));
|
|
return e.paragraphs.map((p) => p.text).join('\n');
|
|
}
|
|
|
|
expect(find('aria2'), contains('GNU GENERAL PUBLIC LICENSE'));
|
|
expect(find('aria2'), contains('Version 2'));
|
|
expect(find('H2Orestart'), contains('Version 3, 29 June 2007'));
|
|
expect(find('libmpv'), contains('LESSER GENERAL PUBLIC LICENSE'));
|
|
expect(entries.any((e) => e.packages.any((p) => p.contains('LibreOffice'))), false, reason: 'LGPL 은 libmpv 이름으로');
|
|
expect(find('PDFium'), contains('The PDFium Authors'));
|
|
expect(find('yt-dlp (실행 파일에 묶인'), contains('THIRD-PARTY LICENSES'));
|
|
final notices = find('JJ_MKVMaker');
|
|
for (final s in ['GPL-3.0-or-later', 'yt-dlp 2026', 'chromium/7811', 'H2Orestart/tree/v0.7.14', 'rsync-3.5.1.tar.gz',
|
|
'ffmpeg-9.0.2', 'Android 판은 위의 GPLv3']) {
|
|
expect(notices, contains(s));
|
|
}
|
|
});
|
|
|
|
test('175: MIT · BSD 항목은 저작권 줄과 허가 문구 원문을 함께 (이름 · 주소 한 줄이 아니라)', () async {
|
|
registerAppLicenses();
|
|
final entries = await LicenseRegistry.licenses.toList();
|
|
String find(String name) {
|
|
final e = entries.firstWhere((e) => e.packages.any((p) => p.startsWith(name)), orElse: () => throw 'no entry: $name');
|
|
return e.paragraphs.map((p) => p.text).join('\n');
|
|
}
|
|
|
|
const mit = 'Permission is hereby granted';
|
|
const bsd = 'Redistribution and use';
|
|
// (라이선스 화면 이름, 꼭 있어야 할 저작권 줄, 허가 문구)
|
|
final want = [
|
|
('stable-diffusion.cpp', 'Copyright (c) 2023 leejet', mit),
|
|
('stable-diffusion.cpp', 'The ggml authors', mit), // 함께 묶인 ggml
|
|
('stable-diffusion.cpp', 'Copyright (c) 2010, Google Inc.', bsd), // libwebp · libwebm
|
|
('stable-diffusion.cpp', 'K.Kosako', bsd), // Oniguruma
|
|
('stable-diffusion.cpp', 'Niels Lohmann', mit), // nlohmann/json
|
|
('stable-diffusion.cpp', 'Rich Geldreich', mit), // miniz
|
|
('stable-diffusion.cpp', 'Sean Barrett', mit), // stb
|
|
('whisper.cpp', 'The ggml authors', mit),
|
|
('ONNX Runtime', 'Copyright (c) Microsoft Corporation', mit),
|
|
('Whisper 모델', 'Copyright (c) 2022 OpenAI', mit),
|
|
('TAESD', 'Ollin Boer Bohan', mit),
|
|
('Real-ESRGAN x4plus (사진)', 'Copyright (c) 2021, Xintao Wang', bsd),
|
|
('Real-ESRGAN x4plus anime', 'Copyright (c) 2021, Xintao Wang', bsd),
|
|
];
|
|
for (final (name, copyright, grant) in want) {
|
|
final t = find(name);
|
|
expect(t, contains(copyright), reason: name);
|
|
expect(t, contains(grant), reason: name);
|
|
}
|
|
// OpenRAIL 계열은 원문 (부속서 A 의 용도 제한까지)
|
|
expect(find('Stable Diffusion v1.5'), contains('Attachment A'));
|
|
expect(find('Stable Diffusion v1.5'), contains('Copyright (c) 2022 Robin Rombach'));
|
|
expect(find('LCM-LoRA'), contains('CreativeML Open RAIL++-M'));
|
|
expect(find('LCM-LoRA'), contains('Attachment A'));
|
|
// NLLB: CC BY-NC 4.0 원문 (비상업적 이용만)
|
|
expect(find('NLLB-200'), contains('Attribution-NonCommercial 4.0 International'));
|
|
expect(find('NLLB-200'), contains('NonCommercial means not primarily intended for or directed towards'));
|
|
});
|
|
|
|
test('175: AI 받기 목록의 MIT · BSD · OpenRAIL 파일은 원문 asset 이 있고, 그 파일이 실제로 있다', () {
|
|
for (final f in aiCatalog) {
|
|
if (f.license.contains('NVIDIA')) continue; // CUDA 런타임: NVIDIA EULA (주소)
|
|
expect(f.licenseAsset, isNotNull, reason: f.id);
|
|
expect(File(f.licenseAsset!).existsSync(), isTrue, reason: f.licenseAsset);
|
|
}
|
|
});
|
|
|
|
test('86: 7-Zip - 라이선스 화면에 원문 (LGPL · BSD · unRAR 제한) · 고지 문서에 판 · 소스 · RAR 은 풀기만 · 설치 폴더에 원문', () async {
|
|
registerAppLicenses();
|
|
final entries = await LicenseRegistry.licenses.toList();
|
|
final t = entries.firstWhere((e) => e.packages.any((p) => p.startsWith('7-Zip 25.01 (7z.exe'))).paragraphs.map((p) => p.text).join('\n');
|
|
for (final s in ['Igor Pavlov', 'GNU LGPL', 'unRAR license restriction', 'BSD 3-clause License']) {
|
|
expect(t, contains(s), reason: s);
|
|
}
|
|
final lgpl = entries.firstWhere((e) => e.packages.any((p) => p.startsWith('7-Zip 25.01 (GNU LGPL'))).paragraphs.map((p) => p.text).join('\n');
|
|
expect(lgpl, contains('LESSER GENERAL PUBLIC LICENSE'));
|
|
final notices = File('assets/licenses/THIRD_PARTY_NOTICES.txt').readAsStringSync();
|
|
for (final s in ['7-Zip 25.01', '7z2501-src.7z', 'RAR 을 만들지 않습니다', '7ZIP_LICENSE.txt']) {
|
|
expect(notices, contains(s), reason: s);
|
|
}
|
|
final cmake = File('windows/CMakeLists.txt').readAsStringSync();
|
|
expect(cmake, contains('third_party/7zip/windows'));
|
|
expect(cmake, contains('License.txt'));
|
|
expect(File('tool/fetch_7zip.ps1').readAsStringSync(), contains('e7eb0b7ed5efa4e087b7b17f191797f7af5b7f442d1290c66f3a21777005ef57'));
|
|
// Android 판 (lib7zz.so - 공식 소스를 NDK 로 빌드): 고지 · 빌드 스크립트의 소스 해시 · APK 목록
|
|
final android = File('assets/licenses/THIRD_PARTY_NOTICES_ANDROID.txt').readAsStringSync();
|
|
for (final s in ['7-Zip 25.01 (lib7zz.so', '7z2501-src.7z', 'build_7zz_android.sh', 'RAR 을 만들지 않습니다']) {
|
|
expect(android, contains(s), reason: s);
|
|
}
|
|
expect(File('tool/build_7zz_android.sh').readAsStringSync(), contains('2aed39b8f1238464475e9de7dda169a5e873a1dc8bbf4f664b943eaba5620181'));
|
|
expect(File('android/app/third_party_libs.txt').readAsLinesSync(), contains('lib7zz.so'));
|
|
// ZIP 풀기 · 묶기는 archive 패키지 (MIT) - 두 고지에 이름으로
|
|
for (final t in [notices, android]) {
|
|
expect(t, contains('archive 4.3.0'));
|
|
// 88: SFTP (dartssh2, MIT)
|
|
expect(t, contains('dartssh2 4.1.0'));
|
|
}
|
|
// 88: Android SMB (smbj Apache-2.0 + 함께 쓰는 것) - Android 고지 · 원문 (Apache 전문)
|
|
expect(android, contains('smbj 0.15.0'));
|
|
final smbj = File('assets/licenses/SMBJ_LICENSES.txt').readAsStringSync();
|
|
for (final s in ['SMBJ Contributors', 'Legion of the Bouncy Castle', 'QOS.ch', 'Benjamin Diedrichsen', 'Apache License', 'TERMS AND CONDITIONS FOR USE']) {
|
|
expect(smbj, contains(s), reason: s);
|
|
}
|
|
expect(File('android/app/build.gradle.kts').readAsStringSync(), contains('com.hierynomus:smbj:0.15.0'),
|
|
reason: 'smbj 판이 바뀌면 고지 · 원문도 고친다');
|
|
expect(File('pubspec.lock').readAsStringSync(), matches(RegExp(r'\n dartssh2:\r?\n(?: .*\r?\n){1,8}? version: "4\.1\.0"')),
|
|
reason: 'dartssh2 판이 바뀌면 고지의 판 번호도 고친다');
|
|
expect(File('pubspec.lock').readAsStringSync(), matches(RegExp(r'\n archive:\r?\n(?: .*\r?\n){1,8}? version: "4\.3\.0"')),
|
|
reason: 'archive 판이 바뀌면 고지의 판 번호도 고친다');
|
|
// 89: Wi-Fi 공유 QR 은 qr 패키지 (BSD-3-Clause) - 두 고지에 이름으로
|
|
for (final t in [notices, android]) {
|
|
expect(t, contains('qr 3.0.2'));
|
|
}
|
|
expect(File('pubspec.lock').readAsStringSync(), matches(RegExp(r'\n qr:\r?\n(?: .*\r?\n){1,8}? version: "3\.0\.2"')),
|
|
reason: 'qr 판이 바뀌면 고지의 판 번호도 고친다');
|
|
});
|
|
|
|
test('Windows 설치: 실행 파일 옆 · tools · rsync 에 원문을 둔다 (CMake)', () {
|
|
final cmake = File('windows/CMakeLists.txt').readAsStringSync();
|
|
expect(cmake, contains('assets/licenses'));
|
|
expect(cmake, contains('YT-DLP_THIRD_PARTY_LICENSES.txt'));
|
|
expect(cmake, contains('RSYNC_COPYING.txt'));
|
|
for (final f in ['THIRD_PARTY_NOTICES.txt', 'GPL-2.0.txt', 'GPL-3.0.txt', 'LGPL-2.1.txt', 'PDFIUM_LICENSES.txt']) {
|
|
expect(File('assets/licenses/$f').existsSync(), true, reason: f);
|
|
}
|
|
});
|
|
|
|
test('Tor 브라우저: tor (BSD-3 · GPL 빌드) 와 함께 묶인 Libevent · OpenSSL · zlib · zstd 원문, 고지 문서 · 소스 주소', () async {
|
|
registerAppLicenses();
|
|
final entries = await LicenseRegistry.licenses.toList();
|
|
final tor = entries.firstWhere((e) => e.packages.any((p) => p.startsWith('Tor 0.4.9.13'))).paragraphs.map((p) => p.text).join('\n');
|
|
for (final s in ['Roger Dingledine', 'Redistribution and use', 'Niels Provos', 'Apache License', 'Jean-loup Gailly', 'Zstandard',
|
|
'This build of Tor is covered by the GNU General Public License', 'tor-0.4.9.13.tar.gz']) {
|
|
expect(tor, contains(s), reason: s);
|
|
}
|
|
final gpl = entries.firstWhere((e) => e.packages.any((p) => p.startsWith('Tor (tor 실행 파일')));
|
|
expect(gpl.paragraphs.map((p) => p.text).join('\n'), contains('Version 3, 29 June 2007'));
|
|
for (final f in ['THIRD_PARTY_NOTICES.txt', 'THIRD_PARTY_NOTICES_ANDROID.txt']) {
|
|
final t = File('assets/licenses/$f').readAsStringSync();
|
|
expect(t, contains('Tor 0.4.9.13'), reason: f);
|
|
expect(t, contains('tor-0.4.9.13.tar.gz'), reason: f);
|
|
expect(t, contains('공식 Tor Browser 가 아닙니다'), reason: f);
|
|
}
|
|
});
|
|
|
|
test('64: Android 고지 문서에는 Windows 파일 · 경로가 없고 [패키지 라이선스] 로 안내', () {
|
|
final a = File('assets/licenses/THIRD_PARTY_NOTICES_ANDROID.txt').readAsStringSync();
|
|
for (final w in ['libmpv-2.dll', 'flutter_assets', '.exe', r'tools\', r'ffmpeg\']) {
|
|
expect(a, isNot(contains(w)), reason: w);
|
|
}
|
|
expect(a, contains('[패키지 라이선스]'));
|
|
expect(a, contains('GPLv3'));
|
|
});
|
|
|
|
// 관리자 지시 (10/20, 28 지적): Android HWP 보기 (libjj_rhwp.so) - 실제로 링크되는 Rust crate 마다 라이선스 · 원문
|
|
// (tool/licenses/rhwp_crates.py 를 tool/build_rhwp_android.sh 가 부름). Cargo.lock 이 바뀌었는데 다시 만들지 않으면 여기서 잡힌다
|
|
test('rhwp: Cargo.lock 의 모든 crate 가 "linked" 나 "not linked" 에 있고, 링크되는 crate 마다 원문 절', () {
|
|
final t = File('assets/licenses/RHWP_LICENSES.txt').readAsStringSync().replaceAll('\r\n', '\n');
|
|
final lock = File('tool/rhwp_ffi/Cargo.lock').readAsStringSync().replaceAll('\r\n', '\n');
|
|
final locked = {
|
|
for (final m in RegExp(r'\[\[package\]\]\s*\nname = "([^"]+)"\s*\nversion = "([^"]+)"').allMatches(lock)) '${m[1]} ${m[2]}'
|
|
};
|
|
final linked = {for (final m in RegExp(r'^linked: (\S+) (\S+) ', multiLine: true).allMatches(t)) '${m[1]} ${m[2]}'};
|
|
final notLinked = {for (final m in RegExp(r'^not linked: (\S+) (\S+)$', multiLine: true).allMatches(t)) '${m[1]} ${m[2]}'};
|
|
expect(linked, isNotEmpty);
|
|
expect(linked.intersection(notLinked), isEmpty);
|
|
expect({...linked, ...notLinked, 'jj_rhwp 0.1.0'}, locked, reason: 'Cargo.lock 이 바뀌면 sh tool/build_rhwp_android.sh 로 다시 만든다');
|
|
for (final c in linked) {
|
|
expect(t, contains('=== $c ('), reason: '$c 의 라이선스 원문 절');
|
|
}
|
|
// 28 이 짚은 것들 (Cargo.lock 에 있으면 어느 한쪽 목록에 - 링크되는지는 cargo tree 가 정함)
|
|
for (final n in ['tiny-skia', 'zlib-rs', 'curve25519-dalek', 'unicode-ident', 'rustybuzz', 'skrifa', 'miniz_oxide', 'fontdb']) {
|
|
for (final c in locked.where((c) => c.startsWith('$n '))) {
|
|
expect(linked.contains(c) || notLinked.contains(c), isTrue, reason: c);
|
|
}
|
|
}
|
|
expect(t, contains('rhwp v0.8.7'));
|
|
expect(t, contains('1a76570e833917d15817415a53c09ad61ab3203f'));
|
|
});
|
|
}
|