Phase B (T1-5/T1-6/T2-2/T2-8/T2-12): download manager flyout w/ speed+pause/resume/cancel, bookmark bar, tab sleeping, tab search (open+closed), context menu w/ 'download video from this link' (79 tests GREEN)

This commit is contained in:
Yun Chan 2026-08-15 15:09:59 +09:00
parent af19dba8f4
commit 0caa1111e7
9 changed files with 763 additions and 3 deletions

View file

@ -0,0 +1,103 @@
using VideoDownloader.App.Browser.Features;
namespace VideoDownloader.Tests.Browser;
/// <summary>페이지 다운로드 추상화(다운로드 매니저 UI 의 로직 코어) — fake op 로 검증.</summary>
public interface IFakeOpHost { }
public class PageDownloadTrackerTests
{
private sealed class FakeOp : IDownloadOperation
{
public string Uri { get; set; } = "https://x.test/file.zip";
public string FileName { get; set; } = "file.zip";
public long BytesReceived { get; set; }
public long TotalBytesToReceive { get; set; } = 1000;
public string State { get; set; } = "InProgress";
public bool Paused, Resumed, Cancelled;
public event Action? Changed;
public void Raise() => Changed?.Invoke();
public void Pause() { Paused = true; State = "Paused"; Raise(); }
public void Resume() { Resumed = true; State = "InProgress"; Raise(); }
public void Cancel() { Cancelled = true; State = "Cancelled"; Raise(); }
}
[Fact]
public void Add는_항목을_등록하고_최근순_정렬한다()
{
var t = new PageDownloadTracker();
var a = new FakeOp { FileName = "a.zip" };
var b = new FakeOp { FileName = "b.zip" };
t.Add(a, a.FileName);
t.Add(b, b.FileName);
Assert.Equal(2, t.Items.Count);
Assert.Equal("b.zip", t.Items[0].FileName); // 최신 우선
}
[Fact]
public void 진행률과_속도를_계산한다()
{
var t = new PageDownloadTracker();
var op = new FakeOp { TotalBytesToReceive = 1000 };
var item = t.Add(op, "f.zip");
item.UpdateSpeed(500, TimeSpan.FromSeconds(2)); // 500B/2s = 250 B/s
Assert.Equal(50.0, item.Percent, 2);
Assert.Equal(250, item.BytesPerSecond);
Assert.Equal("250.0 B/s", item.SpeedText);
}
[Fact]
public void 속도_단위는_KB_MB로_표시된다()
{
var t = new PageDownloadTracker();
var item = t.Add(new FakeOp { TotalBytesToReceive = 10_000_000 }, "f");
item.UpdateSpeed(0, TimeSpan.FromSeconds(1)); // 초기
Assert.Equal("—", item.SpeedText);
item = t.Add(new FakeOp { TotalBytesToReceive = 10_000_000 }, "g");
item.UpdateSpeed(2048 * 100, TimeSpan.FromSeconds(1)); // 200 KB/s
Assert.Equal("200.0 KB/s", item.SpeedText);
item = t.Add(new FakeOp { TotalBytesToReceive = 10_000_000 }, "h");
item.UpdateSpeed(3 * 1024 * 1024L, TimeSpan.FromSeconds(1)); // 3 MB/s
Assert.Equal("3.0 MB/s", item.SpeedText);
}
[Fact]
public void Pause_Resume_Cancel_위임()
{
var t = new PageDownloadTracker();
var op = new FakeOp();
var item = t.Add(op, "f");
t.Pause(item); t.Resume(item); t.Cancel(item);
Assert.True(op.Paused && op.Resumed && op.Cancelled);
}
[Fact]
public void 완료_항목은_ClearCompleted로_일괄_제거()
{
var t = new PageDownloadTracker();
var done = new FakeOp { State = "Completed" };
var running = new FakeOp { State = "InProgress" };
t.Add(done, "d"); t.Add(running, "r");
t.ClearCompleted();
Assert.Single(t.Items);
Assert.Equal("r", t.Items[0].FileName);
}
[Fact]
public void 취소된_항목도_ClearCompleted로_제거된다()
{
var t = new PageDownloadTracker();
var c = new FakeOp { State = "Interrupted" };
t.Add(c, "c");
t.ClearCompleted();
Assert.Empty(t.Items);
}
}