194 lines
9.4 KiB
C#
194 lines
9.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Paca.Mobile.Core;
|
|
using Xunit;
|
|
|
|
namespace Paca.Tests.Mobile;
|
|
|
|
/// <summary>
|
|
/// 데스크톱 Paca와 1:1 대응하는 모바일 다운로드 관리자, 필터링, 정렬, 정리 게이트 (Gate 153 ~ Gate 160)
|
|
/// </summary>
|
|
public class MobileDesktopParityDownloadGateTests
|
|
{
|
|
private static readonly string MobileProjectDir = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", "src", "Paca.Mobile"));
|
|
|
|
[Fact]
|
|
public void Gate153_StatusAndMediaFilter_Parity_Audit()
|
|
{
|
|
var engine = new MobileDesktopParityFilterEngine();
|
|
var items = new List<MobileParityDownloadItem>
|
|
{
|
|
new("1", "Video Active", "https://ex.com/1.mp4", MobileParityStatus.Active, MobileParityMediaKind.Video, "MP4", 1024 * 1024 * 10, 0.5),
|
|
new("2", "Video Done", "https://ex.com/2.mp4", MobileParityStatus.Done, MobileParityMediaKind.Video, "MP4", 1024 * 1024 * 20, 1.0),
|
|
new("3", "Audio Done", "https://ex.com/3.mp3", MobileParityStatus.Done, MobileParityMediaKind.Audio, "MP3", 1024 * 1024 * 3, 1.0),
|
|
new("4", "Audio Failed", "https://ex.com/4.m4a", MobileParityStatus.Failed, MobileParityMediaKind.Audio, "M4A", 1024 * 500, 0.2)
|
|
};
|
|
|
|
// 1. 상태 필터: Done만
|
|
var doneOnly = engine.Filter(items, status: MobileParityStatusFilter.Done, mediaKind: MobileParityMediaFilter.All, format: "모든 포맷", hideSmall: false, query: "");
|
|
Assert.Equal(2, doneOnly.Count);
|
|
|
|
// 2. 미디어 필터: Audio만
|
|
var audioOnly = engine.Filter(items, status: MobileParityStatusFilter.All, mediaKind: MobileParityMediaFilter.Audio, format: "모든 포맷", hideSmall: false, query: "");
|
|
Assert.Equal(2, audioOnly.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void Gate154_FormatFilter_Parity_Audit()
|
|
{
|
|
var engine = new MobileDesktopParityFilterEngine();
|
|
var items = new List<MobileParityDownloadItem>
|
|
{
|
|
new("1", "HLS Live", "https://ex.com/live.m3u8", MobileParityStatus.Active, MobileParityMediaKind.Video, "HLS", 1024 * 1024 * 5, 0.3),
|
|
new("2", "DASH VoD", "https://ex.com/manifest.mpd", MobileParityStatus.Done, MobileParityMediaKind.Video, "DASH", 1024 * 1024 * 50, 1.0),
|
|
new("3", "WebM Clip", "https://ex.com/clip.webm", MobileParityStatus.Done, MobileParityMediaKind.Video, "WEBM", 1024 * 1024 * 15, 1.0)
|
|
};
|
|
|
|
var hlsItems = engine.Filter(items, MobileParityStatusFilter.All, MobileParityMediaFilter.All, format: "HLS", hideSmall: false, query: "");
|
|
Assert.Single(hlsItems);
|
|
Assert.Equal("HLS Live", hlsItems[0].Title);
|
|
|
|
var webmItems = engine.Filter(items, MobileParityStatusFilter.All, MobileParityMediaFilter.All, format: "WEBM", hideSmall: false, query: "");
|
|
Assert.Single(webmItems);
|
|
Assert.Equal("WebM Clip", webmItems[0].Title);
|
|
}
|
|
|
|
[Fact]
|
|
public void Gate155_SortEngine_Parity_Audit()
|
|
{
|
|
var engine = new MobileDesktopParitySortEngine();
|
|
var items = new List<MobileParityDownloadItem>
|
|
{
|
|
new("1", "Bravo", "url1", MobileParityStatus.Done, MobileParityMediaKind.Video, "MP4", 100, 0.2, DateTime.UtcNow.AddMinutes(-10)),
|
|
new("2", "Alpha", "url2", MobileParityStatus.Done, MobileParityMediaKind.Video, "MP4", 500, 0.9, DateTime.UtcNow.AddMinutes(-5)),
|
|
new("3", "Charlie", "url3", MobileParityStatus.Done, MobileParityMediaKind.Video, "MP4", 300, 0.5, DateTime.UtcNow)
|
|
};
|
|
|
|
// 최신순 (Newest)
|
|
var byNewest = engine.Sort(items, MobileParitySortCriteria.Newest);
|
|
Assert.Equal("Charlie", byNewest[0].Title);
|
|
|
|
// 크기순 (Largest)
|
|
var byLargest = engine.Sort(items, MobileParitySortCriteria.Largest);
|
|
Assert.Equal("Alpha", byLargest[0].Title); // 500
|
|
|
|
// 진행률순 (Progress)
|
|
var byProgress = engine.Sort(items, MobileParitySortCriteria.Progress);
|
|
Assert.Equal("Alpha", byProgress[0].Title); // 0.9
|
|
|
|
// 제목순 (Title)
|
|
var byTitle = engine.Sort(items, MobileParitySortCriteria.Title);
|
|
Assert.Equal("Alpha", byTitle[0].Title);
|
|
Assert.Equal("Charlie", byTitle[2].Title);
|
|
}
|
|
|
|
[Fact]
|
|
public void Gate156_SmallMediaFilter_Parity_Audit()
|
|
{
|
|
var engine = new MobileDesktopParityFilterEngine();
|
|
var items = new List<MobileParityDownloadItem>
|
|
{
|
|
new("1", "Small Preview", "url1", MobileParityStatus.Done, MobileParityMediaKind.Video, "MP4", 500 * 1024, 1.0), // 500KB
|
|
new("2", "Full Movie", "url2", MobileParityStatus.Done, MobileParityMediaKind.Video, "MP4", 10 * 1024 * 1024, 1.0) // 10MB
|
|
};
|
|
|
|
// 1MB 미만 숨김 활성화 시 10MB만 남아야 함
|
|
var filtered = engine.Filter(items, MobileParityStatusFilter.All, MobileParityMediaFilter.All, format: "모든 포맷", hideSmall: true, query: "");
|
|
Assert.Single(filtered);
|
|
Assert.Equal("Full Movie", filtered[0].Title);
|
|
}
|
|
|
|
[Fact]
|
|
public void Gate157_BatchActionManager_Parity_Audit()
|
|
{
|
|
var manager = new MobileParityBatchManager();
|
|
var items = new List<MobileParityDownloadItem>
|
|
{
|
|
new("1", "Active Item", "url1", MobileParityStatus.Active, MobileParityMediaKind.Video, "MP4", 100, 0.5),
|
|
new("2", "Done Item 1", "url2", MobileParityStatus.Done, MobileParityMediaKind.Video, "MP4", 100, 1.0),
|
|
new("3", "Done Item 2", "url3", MobileParityStatus.Done, MobileParityMediaKind.Video, "MP4", 100, 1.0),
|
|
new("4", "Failed Item", "url4", MobileParityStatus.Failed, MobileParityMediaKind.Video, "MP4", 100, 0.1)
|
|
};
|
|
|
|
// 1. 완료 정리 -> Done 항목만 제거
|
|
var afterClearDone = manager.ClearFinishedDownloads(items);
|
|
Assert.Equal(2, afterClearDone.Count);
|
|
Assert.DoesNotContain(afterClearDone, i => i.Status == MobileParityStatus.Done);
|
|
|
|
// 2. 전체 비우기 -> Active 제외하고 모두 제거
|
|
var afterClearAll = manager.ClearAllDownloads(items);
|
|
Assert.Single(afterClearAll);
|
|
Assert.Equal("Active Item", afterClearAll[0].Title);
|
|
}
|
|
|
|
[Fact]
|
|
public void Gate158_MobileDownloadCardActions_Parity_Audit()
|
|
{
|
|
var card = new MobileParityDownloadItem("1", "Test Video", "https://ex.com/video.mp4", MobileParityStatus.Done, MobileParityMediaKind.Video, "MP4", 1024, 1.0);
|
|
Assert.False(card.IsPinned);
|
|
|
|
// 상단 고정 토글
|
|
card.IsPinned = true;
|
|
Assert.True(card.IsPinned);
|
|
|
|
// 우선순위 조절
|
|
Assert.Equal(0, card.Priority);
|
|
card.PriorityUp();
|
|
Assert.Equal(1, card.Priority);
|
|
card.PriorityDown();
|
|
Assert.Equal(0, card.Priority);
|
|
}
|
|
|
|
[Fact]
|
|
public void Gate159_DownloadsPage_DesktopParity_UiElements_Audit()
|
|
{
|
|
var downloadsPageCs = File.ReadAllText(Path.Combine(MobileProjectDir, "DownloadsPage.cs"));
|
|
|
|
// 데스크톱 1:1 대응 UI 요소 검증
|
|
Assert.Contains("DownloadSearchBox", downloadsPageCs);
|
|
Assert.Contains("FilterAll", downloadsPageCs);
|
|
Assert.Contains("FilterActive", downloadsPageCs);
|
|
Assert.Contains("FilterDone", downloadsPageCs);
|
|
Assert.Contains("FilterFailed", downloadsPageCs);
|
|
Assert.Contains("FilterMediaAll", downloadsPageCs);
|
|
Assert.Contains("FilterMediaVideo", downloadsPageCs);
|
|
Assert.Contains("FilterMediaAudio", downloadsPageCs);
|
|
Assert.Contains("FormatFilterPicker", downloadsPageCs);
|
|
Assert.Contains("DownloadSortPicker", downloadsPageCs);
|
|
Assert.Contains("FilterHideSmallMedia", downloadsPageCs);
|
|
Assert.Contains("ClearFinishedDownloadsBtn", downloadsPageCs);
|
|
Assert.Contains("ClearAllDownloadsBtn", downloadsPageCs);
|
|
}
|
|
|
|
[Fact]
|
|
public void Gate160_EndToEndDesktopParityJourney_Audit()
|
|
{
|
|
var filter = new MobileDesktopParityFilterEngine();
|
|
var sorter = new MobileDesktopParitySortEngine();
|
|
var batch = new MobileParityBatchManager();
|
|
|
|
var list = new List<MobileParityDownloadItem>
|
|
{
|
|
new("1", "Nature 4K", "https://ex.com/n.mp4", MobileParityStatus.Done, MobileParityMediaKind.Video, "MP4", 50 * 1024 * 1024, 1.0, DateTime.UtcNow.AddHours(-1)),
|
|
new("2", "Nature 720p", "https://ex.com/n2.mp4", MobileParityStatus.Active, MobileParityMediaKind.Video, "MP4", 10 * 1024 * 1024, 0.4, DateTime.UtcNow),
|
|
new("3", "Background Music", "https://ex.com/bgm.mp3", MobileParityStatus.Done, MobileParityMediaKind.Audio, "MP3", 3 * 1024 * 1024, 1.0, DateTime.UtcNow.AddHours(-2)),
|
|
new("4", "Tiny Icon", "https://ex.com/icon.png", MobileParityStatus.Failed, MobileParityMediaKind.Other, "PNG", 50 * 1024, 0.1, DateTime.UtcNow)
|
|
};
|
|
|
|
// 1. 검색어로 필터링 ("Nature")
|
|
var searched = filter.Filter(list, MobileParityStatusFilter.All, MobileParityMediaFilter.All, "모든 포맷", false, "Nature");
|
|
Assert.Equal(2, searched.Count);
|
|
|
|
// 2. 크기순 정렬
|
|
var sorted = sorter.Sort(searched, MobileParitySortCriteria.Largest);
|
|
Assert.Equal("Nature 4K", sorted[0].Title);
|
|
|
|
// 3. 완료 정리 수행
|
|
var remaining = batch.ClearFinishedDownloads(list);
|
|
Assert.Equal(2, remaining.Count);
|
|
Assert.Contains(remaining, i => i.Title == "Nature 720p");
|
|
Assert.Contains(remaining, i => i.Title == "Tiny Icon");
|
|
}
|
|
}
|