feat(mobile): advance Paca.Mobile to production excellence with rich design assets and core systems
- Generate high-resolution glassmorphism app icon and splash screen assets - Implement MobileIconSystem with semantic SF Symbols/Material glyph mappings - Add OLEDBlack theme and contrast tokens to MobileThemeSystem - Implement VideoSnifferParser.NegotiateBestQuality for multi-stream quality resolution - Enhance DiscoverPage, FavoritesPage, and SyncSettingsPage with production controls - Add Gate 103-114 test suites with 100% test pass rate
This commit is contained in:
parent
dbc50abb71
commit
f1949024fc
81 changed files with 8611 additions and 0 deletions
135
tests/Paca.Tests/Mobile/MobileAdvancedNativeGateTests.cs
Normal file
135
tests/Paca.Tests/Mobile/MobileAdvancedNativeGateTests.cs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Paca.Mobile.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Paca.Tests.Mobile;
|
||||
|
||||
/// <summary>
|
||||
/// 모바일 네이티브 컨트롤, 햅틱, 타이포 스케일러, 볼트, 오리엔테이션 게이트 (Gate 115 ~ Gate 122)
|
||||
/// </summary>
|
||||
public class MobileAdvancedNativeGateTests
|
||||
{
|
||||
[Fact]
|
||||
public void Gate115_MobileTypographyScaler_Audit()
|
||||
{
|
||||
var scaler = new MobileTypographyScaler();
|
||||
// 기본 1.0x 스케일
|
||||
Assert.Equal(14.0, scaler.GetScaledFontSize(baseFontSize: 14.0, textScaleFactor: 1.0));
|
||||
|
||||
// 1.5x 접근성 큰 글꼴
|
||||
Assert.Equal(21.0, scaler.GetScaledFontSize(baseFontSize: 14.0, textScaleFactor: 1.5));
|
||||
|
||||
// 최대 상한선(2.0x 초과 방지 클램핑)
|
||||
Assert.Equal(28.0, scaler.GetScaledFontSize(baseFontSize: 14.0, textScaleFactor: 2.5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate116_MobileOrientationSensor_Landscape_Audit()
|
||||
{
|
||||
var sensor = new MobileOrientationSensor();
|
||||
Assert.Equal(MobileScreenOrientation.Portrait, sensor.CurrentOrientation);
|
||||
Assert.False(sensor.IsFullscreenVideo);
|
||||
|
||||
// 가로 회전 감지
|
||||
sensor.OnOrientationChanged(MobileScreenOrientation.Landscape);
|
||||
Assert.Equal(MobileScreenOrientation.Landscape, sensor.CurrentOrientation);
|
||||
Assert.True(sensor.IsFullscreenVideo);
|
||||
|
||||
// 컨트롤 자동 숨김 타이머 (3초)
|
||||
Assert.Equal(3000, sensor.ControlsAutoHideTimeoutMs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate117_MobileHapticFeedback_Audit()
|
||||
{
|
||||
var haptic = new MobileHapticFeedback();
|
||||
HapticFeedbackType? triggered = null;
|
||||
haptic.OnHapticTriggered += type => triggered = type;
|
||||
|
||||
haptic.NotifySuccess();
|
||||
Assert.Equal(HapticFeedbackType.Success, triggered);
|
||||
|
||||
haptic.NotifyError();
|
||||
Assert.Equal(HapticFeedbackType.Error, triggered);
|
||||
|
||||
haptic.NotifySelectionChange();
|
||||
Assert.Equal(HapticFeedbackType.LightClick, triggered);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate118_MobileQueueReorderEngine_Audit()
|
||||
{
|
||||
var qm = new MobileQueueManager();
|
||||
var item1 = qm.Enqueue("https://example.com/1.mp4", "Video 1");
|
||||
var item2 = qm.Enqueue("https://example.com/2.mp4", "Video 2");
|
||||
var item3 = qm.Enqueue("https://example.com/3.mp4", "Video 3");
|
||||
|
||||
var reorder = new MobileQueueReorderEngine(qm);
|
||||
// item3을 맨 앞으로 이동 (index 2 -> 0)
|
||||
reorder.MoveItem(fromIndex: 2, toIndex: 0);
|
||||
|
||||
Assert.Equal(item3.Id, qm.Items[0].Id);
|
||||
Assert.Equal(item1.Id, qm.Items[1].Id);
|
||||
Assert.Equal(item2.Id, qm.Items[2].Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate119_MobileBackgroundWorker_Notification_Audit()
|
||||
{
|
||||
var worker = new MobileBackgroundWorker();
|
||||
Assert.False(worker.IsForegroundServiceRunning);
|
||||
|
||||
worker.StartService("Paca 다운로드 진행 중", totalActiveDownloads: 2);
|
||||
Assert.True(worker.IsForegroundServiceRunning);
|
||||
Assert.Equal("Paca 다운로드 진행 중 (2개 활성)", worker.LastNotificationTitle);
|
||||
|
||||
worker.StopService();
|
||||
Assert.False(worker.IsForegroundServiceRunning);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate120_MobileMediaVault_Encryption_Audit()
|
||||
{
|
||||
var vault = new MobileMediaVault();
|
||||
var plainBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
var password = "SafePassword123!";
|
||||
|
||||
// 암호화
|
||||
var encrypted = vault.EncryptMedia(plainBytes, password);
|
||||
Assert.NotEqual(plainBytes, encrypted);
|
||||
|
||||
// 복호화
|
||||
var decrypted = vault.DecryptMedia(encrypted, password);
|
||||
Assert.Equal(plainBytes, decrypted);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate121_MobileAdBlockEngine_EasyList_Audit()
|
||||
{
|
||||
var adBlock = new MobileAdBlockEngine();
|
||||
Assert.True(adBlock.IsAdUrl("https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"));
|
||||
Assert.True(adBlock.IsAdUrl("https://adservice.google.com/adsid/google/ui"));
|
||||
Assert.True(adBlock.IsAdUrl("https://securepubads.g.doubleclick.net/gampad/ads"));
|
||||
|
||||
// 정상 미디어 URL은 허용
|
||||
Assert.False(adBlock.IsAdUrl("https://www.youtube.com/watch?v=dQw4w9WgXcQ"));
|
||||
Assert.False(adBlock.IsAdUrl("https://vimeo.com/12345678"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate122_MobileResolutionPicker_Estimation_Audit()
|
||||
{
|
||||
var picker = new MobileResolutionPicker();
|
||||
// 1080p 60fps 비디오 10분(600초) 예상 용량 계산
|
||||
var estimate1080p = picker.EstimateSizeAndDownloadTime(
|
||||
durationSec: 600,
|
||||
resolution: "1080p",
|
||||
currentNetworkSpeedKbps: 10240 // 10MB/s (80Mbps)
|
||||
);
|
||||
|
||||
Assert.True(estimate1080p.EstimatedSizeBytes > 0);
|
||||
Assert.True(estimate1080p.EstimatedDurationSec > 0);
|
||||
Assert.Equal("1080p Full HD", estimate1080p.ResolutionLabel);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue