releases/VideoDownloader.Tests/Platform/UpdateCheckerTests.cs
Yun Chan 02995f4153 MEDIABROWSER 개명·업데이트 채널 전환·아이콘 tofu 근본 수정 (BACKLOG 13차) — ①개명: installer.iss AppName/출력 MediaBrowser-Setup-*(AppId·exe·데이터 경로 유지로 업그레이드 호환), 워크플로 산출물명(mediabrowser-*.tar.gz, MediaBrowser-<ver>-arm64.apk), 창 타이틀·모바일 표시명·obtainium.json·README. ②UpdateChecker: apiBase 주입(기본=자체 Forgejo /api/v1, GitHub 는 apiBase 로 호환), osx 자산 tar.gz 허용(기존 dmg 만 → mac 영원히 자산 없음 결함 수정), AppConfig 기본 UpdateRepo=Video-Downloader/releases+UpdateApiBase — 테스트 4건. ③아이콘 tofu(사용자 보고 "절대 안고쳐지네") 근본 원인: Shared.xaml 암시적 TextBlock 스타일의 FontFamily=UiFont 강제가 버튼 ContentPresenter 자동 TextBlock 의 IconFont 상속을 덮어 모든 PUA 글리프가 notdef — 폰트 설치/글리프 존재/HW·SW 렌더/RTB/DPI/런타임 8·10/자체포함·공유 전부 배제 후 실창 픽셀 비교로 격리, 콘텐츠 TextBlock 의 실폰트가 Pretendard 체인임을 테스트로 실증. 수정: 암시 스타일 FontFamily 제거(창 루트 상속으로 통일, PairingWindow/PlayerWindow 는 SetResourceReference), PUA+텍스트 혼합 콘텐츠 7곳+코드 1곳 정리, 순수 글리프 2곳 IconFont 명시. 회귀 방어: IconGlyphXamlTests(정적 스캔)·IconContentFontTests(실창 폰트 단정)·IconGlyphRenderTests(픽셀 비교) — 462/462 GREEN, 수정 전후 실창 캡처로 글리프 렌더 확인
2026-08-18 07:13:18 +09:00

154 lines
6.4 KiB
C#

using System.Net;
using System.Net.Http;
using VideoDownloader.Core.Update;
namespace VideoDownloader.Tests.Platform;
/// <summary>
/// DEPLOYMENT_PLAN §6 자동 업데이트 v1 — GitHub Releases latest 태그 비교 + 아키텍처별 설치 자산 선택.
/// 네트워크는 가짜 핸들러로 격리.
/// </summary>
public class UpdateCheckerTests
{
private sealed class FakeHandler : HttpMessageHandler
{
private readonly HttpStatusCode _status;
private readonly string _json;
public HttpRequestMessage? LastRequest { get; private set; }
public FakeHandler(HttpStatusCode status, string json)
{
_status = status;
_json = json;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken ct)
{
LastRequest = request;
return Task.FromResult(new HttpResponseMessage(_status)
{
Content = new StringContent(_json, System.Text.Encoding.UTF8, "application/json"),
});
}
}
private const string ReleaseJson = """
{
"tag_name": "v1.2.0",
"html_url": "https://github.com/user/videodownloader/releases/tag/v1.2.0",
"assets": [
{ "name": "VideoDownloader-Setup-x64.exe", "browser_download_url": "https://github.com/user/videodownloader/releases/download/v1.2.0/VideoDownloader-Setup-x64.exe" },
{ "name": "VideoDownloader-Setup-arm64.exe", "browser_download_url": "https://github.com/user/videodownloader/releases/download/v1.2.0/VideoDownloader-Setup-arm64.exe" }
]
}
""";
[Theory]
[InlineData("1.0.0", "v1.2.0", true)] // 최신이 더 높음
[InlineData("1.2.0", "v1.2.0", false)] // 동일
[InlineData("2.0.0", "v1.9.9", false)] // 현재가 더 높음
[InlineData("1.0.0.0", "v1.0.1", true)] // 어셈블리 4자리 버전 허용
[InlineData("1.0.0", "garbage", false)] // 파싱 불가면 갱신 아님
public void 버전비교(string current, string latest, bool expected) =>
Assert.Equal(expected, UpdateChecker.IsNewer(current, latest));
[Fact]
public void 자산선택_x64와_arm64_구분()
{
var assets = new[]
{
new UpdateAsset("VideoDownloader-Setup-x64.exe", "https://dl/x64"),
new UpdateAsset("VideoDownloader-Setup-arm64.exe", "https://dl/arm64"),
};
Assert.Equal("https://dl/x64", UpdateChecker.SelectAsset(assets, "win-x64")!.DownloadUrl);
Assert.Equal("https://dl/arm64", UpdateChecker.SelectAsset(assets, "win-arm64")!.DownloadUrl);
Assert.Null(UpdateChecker.SelectAsset(assets, "linux-x64")); // 일치 없음
}
[Fact]
public async Task 최신확인_새버전이면_자산과_릴리스URL()
{
var handler = new FakeHandler(HttpStatusCode.OK, ReleaseJson);
var checker = new UpdateChecker(handler);
var result = await checker.CheckAsync("user/videodownloader", "1.0.0", "win-x64");
Assert.NotNull(result);
Assert.True(result!.IsNewer);
Assert.Equal("1.2.0", result.LatestVersion);
Assert.Equal("https://github.com/user/videodownloader/releases/tag/v1.2.0", result.ReleaseUrl);
Assert.Equal("VideoDownloader-Setup-x64.exe", result.Asset!.Name);
// 기본 채널(자체 Forgejo) 엔드포인트 + User-Agent(GitHub 채널 호환 규약 유지)
Assert.Equal("https://git.chanpaca.net/api/v1/repos/user/videodownloader/releases/latest", handler.LastRequest!.RequestUri!.ToString());
Assert.NotEmpty(handler.LastRequest.Headers.UserAgent);
}
[Fact]
public async Task 최신확인_이미_최신이면_IsNewer_false()
{
var checker = new UpdateChecker(new FakeHandler(HttpStatusCode.OK, ReleaseJson));
var result = await checker.CheckAsync("user/videodownloader", "1.2.0", "win-x64");
Assert.False(result!.IsNewer);
}
[Fact]
public async Task 최신확인_API_실패는_예외로_드러남()
{
var checker = new UpdateChecker(new FakeHandler(HttpStatusCode.NotFound, """{"message":"Not Found"}"""));
await Assert.ThrowsAsync<HttpRequestException>(() => checker.CheckAsync("user/none", "1.0.0", "win-x64"));
}
// ── 배포 채널 전환 (DEPLOYMENT_PLAN §5-bis/§5-ter): 기본 = 자체 Forgejo 공개 릴리스 저장소 ──
[Fact]
public async Task 최신확인_기본은_Forgejo_공개저장소_API()
{
var handler = new FakeHandler(HttpStatusCode.OK, ReleaseJson);
var checker = new UpdateChecker(handler);
await checker.CheckAsync("Video-Downloader/releases", "1.0.0", "win-x64");
// Forgejo 는 /api/v1 접두가 필요 — GitHub 형태(api.github.com/repos/...)와 경로 규칙만 다르다
Assert.Equal(
"https://git.chanpaca.net/api/v1/repos/Video-Downloader/releases/releases/latest",
handler.LastRequest!.RequestUri!.ToString());
}
[Fact]
public async Task 최신확인_apiBase_지정으로_GitHub_채널도_호환()
{
var handler = new FakeHandler(HttpStatusCode.OK, ReleaseJson);
var checker = new UpdateChecker(handler);
var result = await checker.CheckAsync("user/videodownloader", "1.0.0", "win-x64",
apiBase: "https://api.github.com");
Assert.True(result!.IsNewer);
Assert.Equal("https://api.github.com/repos/user/videodownloader/releases/latest",
handler.LastRequest!.RequestUri!.ToString());
}
[Fact]
public void 자산선택_osx는_tar_gz_도_허용()
{
// macOS 프리뷰는 dmg 가 아니라 tar.gz 로 배포 중 — dmg 만 허용하면 mac 은 영원히 자산 없음
var assets = new[]
{
new UpdateAsset("mediabrowser-osx-arm64.tar.gz", "https://dl/osx-arm64"),
new UpdateAsset("mediabrowser-osx-x64.tar.gz", "https://dl/osx-x64"),
};
Assert.Equal("https://dl/osx-arm64", UpdateChecker.SelectAsset(assets, "osx-arm64")!.DownloadUrl);
Assert.Equal("https://dl/osx-x64", UpdateChecker.SelectAsset(assets, "osx-x64")!.DownloadUrl);
}
[Fact]
public void 업데이트_기본채널은_공개릴리스저장소()
{
var config = new VideoDownloader.Core.Config.AppConfig();
Assert.Equal("Video-Downloader/releases", config.UpdateRepo);
Assert.Equal("https://git.chanpaca.net/api/v1", config.UpdateApiBase);
}
}