596 lines
20 KiB
C#
596 lines
20 KiB
C#
using System.IO;
|
|
using System.Text;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using Paca.App;
|
|
using Paca.App.Browser.Features;
|
|
using Paca.Browser;
|
|
using Paca.Browser.Tabs;
|
|
using Paca.Tests.Infrastructure;
|
|
using Xunit;
|
|
|
|
namespace Paca.Tests.Browser;
|
|
|
|
/// <summary>
|
|
/// 다운로드창 리사이즈 시 브라우저 탭 및 탭 스트립 동적 리사이즈 단위/E2E 테스트.
|
|
/// </summary>
|
|
[Collection("E2E")]
|
|
public class TabDynamicResizeTests
|
|
{
|
|
[Fact]
|
|
public void TabStripRow_위치가_브라우저_열에_배치되어_우측패널과_분리된다()
|
|
{
|
|
using var sta = StaDispatcher.Start();
|
|
WpfTestApp.Ensure(sta.Dispatcher);
|
|
sta.Invoke(() =>
|
|
{
|
|
var dataDir = Path.Combine(Path.GetTempPath(), $"vd_tabresize_{Guid.NewGuid():N}");
|
|
Environment.SetEnvironmentVariable("VD_DATA_DIR", dataDir);
|
|
try
|
|
{
|
|
var window = new MainWindow();
|
|
|
|
// MainGrid 열 분할 검증: Col 0 = 브라우저(*), Col 1 = 스플리터(Auto), Col 2 = 다운로드 패널(RightCol)
|
|
Assert.Equal(3, window.MainGrid.ColumnDefinitions.Count);
|
|
Assert.Equal(GridUnitType.Star, window.MainGrid.ColumnDefinitions[0].Width.GridUnitType);
|
|
Assert.Same(window.RightCol, window.MainGrid.ColumnDefinitions[2]);
|
|
|
|
// TabStripRow가 Col 0에 위치하는지 검증
|
|
Assert.Equal(0, Grid.GetColumn(window.TabStripRow));
|
|
Assert.Equal(2, Grid.GetRow(window.TabStripRow));
|
|
|
|
// ContentRoot(브라우저 본체)가 Col 0에 위치하는지 검증
|
|
Assert.Equal(0, Grid.GetColumn(window.ContentRoot));
|
|
Assert.Equal(3, Grid.GetRow(window.ContentRoot));
|
|
|
|
// RightSplitter가 Col 1에 위치하는지 검증
|
|
Assert.Equal(1, Grid.GetColumn(window.RightSplitter));
|
|
}
|
|
finally
|
|
{
|
|
try { if (Directory.Exists(dataDir)) Directory.Delete(dataDir, true); } catch { }
|
|
}
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void 탭_개수_및_가용너비에_따라_TabItemWidth가_동적으로_조절된다()
|
|
{
|
|
using var sta = StaDispatcher.Start();
|
|
WpfTestApp.Ensure(sta.Dispatcher);
|
|
sta.Invoke(() =>
|
|
{
|
|
var dataDir = Path.Combine(Path.GetTempPath(), $"vd_tabresize_{Guid.NewGuid():N}");
|
|
Environment.SetEnvironmentVariable("VD_DATA_DIR", dataDir);
|
|
try
|
|
{
|
|
var window = new MainWindow();
|
|
Assert.True(window.TabItemWidth >= 48.0 && window.TabItemWidth <= 220.0);
|
|
|
|
// 탭이 추가되면 UpdateDynamicTabWidth를 통해 너비가 다시 계산됨
|
|
window.UpdateDynamicTabWidth();
|
|
Assert.True(window.TabItemWidth <= 220.0);
|
|
}
|
|
finally
|
|
{
|
|
try { if (Directory.Exists(dataDir)) Directory.Delete(dataDir, true); } catch { }
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// ── T2-2 탭 절전: 유휴 비활성 탭 자동 서스펜드 ──
|
|
public class TabSuspendServiceTests
|
|
{
|
|
[Fact]
|
|
public void 활성_탭은_절전하지_않는다()
|
|
{
|
|
var m = new TabManager(() => new TabItem());
|
|
var active = m.NewTab("https://a.com");
|
|
var svc = new TabSuspendService(TimeSpan.FromMinutes(10),
|
|
t => throw new InvalidOperationException("suspend should not be called"),
|
|
t => t == active);
|
|
|
|
svc.SuspendIdleTabs(m.Tabs, active, now: active.LastActivated.AddMinutes(30));
|
|
Assert.False(active.IsSuspended);
|
|
}
|
|
|
|
[Fact]
|
|
public void 유휴_비활성_탭은_절전한다()
|
|
{
|
|
var m = new TabManager(() => new TabItem());
|
|
var old = m.NewTab("https://a.com");
|
|
var active = m.NewTab("https://b.com");
|
|
var suspended = new List<TabItem>();
|
|
var svc = new TabSuspendService(TimeSpan.FromMinutes(10),
|
|
t => { suspended.Add(t); return true; },
|
|
t => t != active);
|
|
|
|
var now = old.LastActivated.AddMinutes(11);
|
|
svc.SuspendIdleTabs(m.Tabs, active, now);
|
|
Assert.Contains(old, suspended);
|
|
Assert.DoesNotContain(active, suspended);
|
|
}
|
|
|
|
[Fact]
|
|
public void 이미_절전된_탭은_중복_서스펜드_하지_않는다()
|
|
{
|
|
var m = new TabManager(() => new TabItem());
|
|
var old = m.NewTab("https://a.com");
|
|
var active = m.NewTab("https://b.com");
|
|
old.IsSuspended = true;
|
|
var calls = 0;
|
|
var svc = new TabSuspendService(TimeSpan.FromMinutes(10), t => { calls++; return true; }, t => t != active);
|
|
|
|
svc.SuspendIdleTabs(m.Tabs, active, old.LastActivated.AddHours(1));
|
|
Assert.Equal(0, calls);
|
|
}
|
|
|
|
[Fact]
|
|
public void 최근에_활성화된_탭은_절전하지_않는다()
|
|
{
|
|
var m = new TabManager(() => new TabItem());
|
|
var recent = m.NewTab("https://a.com");
|
|
var active = m.NewTab("https://b.com");
|
|
m.Activate(recent); // 방금 사용
|
|
var calls = 0;
|
|
var svc = new TabSuspendService(TimeSpan.FromMinutes(10), t => { calls++; return true; }, t => t != active);
|
|
|
|
svc.SuspendIdleTabs(m.Tabs, active, recent.LastActivated.AddMinutes(1));
|
|
Assert.Equal(0, calls);
|
|
}
|
|
}
|
|
|
|
// ── T2-8 탭 검색(Ctrl+Shift+A): 열린+닫힌 탭 필터 ──
|
|
public class TabSearchFilterTests
|
|
{
|
|
[Fact]
|
|
public void 제목과_URL_부분일치로_필터링한다()
|
|
{
|
|
var m = new TabManager(() => new TabItem());
|
|
m.NewTab("https://youtube.com/watch?v=1");
|
|
m.Tabs[0].Title = "My Favorite Video";
|
|
m.NewTab("https://news.example.com");
|
|
m.Tabs[1].Title = "News";
|
|
|
|
var hits = TabSearchFilter.Search(m.Tabs, "favorite");
|
|
Assert.Single(hits);
|
|
Assert.Equal("My Favorite Video", hits[0].Title);
|
|
|
|
hits = TabSearchFilter.Search(m.Tabs, "youtube");
|
|
Assert.Single(hits);
|
|
|
|
hits = TabSearchFilter.Search(m.Tabs, "EXAMPLE"); // 대소문자 무시
|
|
Assert.Single(hits);
|
|
}
|
|
|
|
[Fact]
|
|
public void 닫힌_탭도_검색_대상에_포함된다()
|
|
{
|
|
var m = new TabManager(() => new TabItem());
|
|
var t = m.NewTab("https://github.com/x");
|
|
m.Tabs[0].Title = "GitHub Repo";
|
|
m.CloseTab(t);
|
|
|
|
var hits = TabSearchFilter.Search(m.Tabs, m.ClosedStack, "github");
|
|
Assert.Single(hits);
|
|
Assert.Equal("GitHub Repo", hits[0].Title);
|
|
Assert.True(hits[0].IsClosed);
|
|
}
|
|
|
|
[Fact]
|
|
public void 빈_질의는_빈_결과()
|
|
{
|
|
var m = new TabManager(() => new TabItem());
|
|
m.NewTab("https://a.com");
|
|
Assert.Empty(TabSearchFilter.Search(m.Tabs, ""));
|
|
Assert.Empty(TabSearchFilter.Search(m.Tabs, " "));
|
|
}
|
|
}
|
|
|
|
// ── T2-11 탭 그룹: 색상 라벨 + 그룹 단위 이동/닫기 ──
|
|
public class TabGroupsTests
|
|
{
|
|
private static TabManager NewManager() => new(() => new TabItem());
|
|
|
|
[Fact]
|
|
public void 그룹_지정과_해제()
|
|
{
|
|
var m = NewManager();
|
|
var t = m.NewTab("https://a.com");
|
|
m.SetGroup(t, "Work", "#e11");
|
|
Assert.Equal("Work", t.GroupName);
|
|
Assert.Equal("#e11", t.GroupColor);
|
|
m.SetGroup(t, null, null);
|
|
Assert.Null(t.GroupName);
|
|
}
|
|
|
|
[Fact]
|
|
public void 같은_그룹_탭은_서로_인접한다()
|
|
{
|
|
var m = NewManager();
|
|
var a = m.NewTab("a"); m.SetGroup(a, "G", "#111");
|
|
m.NewTab("b"); // 비그룹
|
|
var c = m.NewTab("c"); m.SetGroup(c, "G", "#111"); // 그룹으로 → a 옆으로 이동
|
|
Assert.Equal(1, m.Tabs.IndexOf(c));
|
|
Assert.Equal(0, m.Tabs.IndexOf(a));
|
|
}
|
|
|
|
[Fact]
|
|
public void 그룹_탭_전체_닫기()
|
|
{
|
|
var m = NewManager();
|
|
var a = m.NewTab("a"); m.SetGroup(a, "G", "#111");
|
|
var b = m.NewTab("b"); m.SetGroup(b, "G", "#111");
|
|
m.NewTab("solo");
|
|
var closed = m.CloseGroup("G");
|
|
Assert.Equal(2, closed);
|
|
Assert.Single(m.Tabs);
|
|
}
|
|
}
|
|
|
|
// ── T3-1 워크스페이스: 탭 세트 저장/전환 ──
|
|
public class WorkspaceTests
|
|
{
|
|
private static TabManager NewManager() => new(() => new TabItem());
|
|
|
|
[Fact]
|
|
public void 워크스페이스_저장후_스왑하면_탭_세트가_교체된다()
|
|
{
|
|
var m = NewManager();
|
|
m.NewTab("https://work1.com");
|
|
m.NewTab("https://work2.com");
|
|
var ws = m.CaptureWorkspace("Work");
|
|
|
|
m.NewTab("https://personal.com");
|
|
Assert.Equal(3, m.Tabs.Count);
|
|
|
|
m.SwitchWorkspace(ws);
|
|
Assert.Equal(2, m.Tabs.Count);
|
|
Assert.Equal("https://work1.com", m.Tabs[0].Url);
|
|
Assert.Equal("https://work2.com", m.Tabs[1].Url);
|
|
Assert.Equal("Work", ws.Name);
|
|
}
|
|
|
|
[Fact]
|
|
public void 워크스페이스_캡처는_현재_탭을_그대로_유지한다()
|
|
{
|
|
var m = NewManager();
|
|
m.NewTab("https://a.com");
|
|
var ws = m.CaptureWorkspace("X");
|
|
Assert.Single(m.Tabs); // 캡처 자체는 현재 상태 유지(스냅샷)
|
|
Assert.Single(ws.Urls);
|
|
}
|
|
}
|
|
|
|
// Phase A 탭 아키텍처: TabManager 순수 로직(뷰 팩토리 주입 — WebView2 없이 검증).
|
|
public class TabManagerTests
|
|
{
|
|
private static TabManager NewManager() => new(() => new TabItem());
|
|
|
|
[Fact]
|
|
public void NewTab은_탭을_추가하고_활성화한다()
|
|
{
|
|
var m = NewManager();
|
|
var t = m.NewTab("https://a.com");
|
|
Assert.Single(m.Tabs);
|
|
Assert.Same(t, m.ActiveTab);
|
|
Assert.Equal("https://a.com", t.Url);
|
|
}
|
|
|
|
[Fact]
|
|
public void 두_번째_탭은_이전_탭을_비활성화하고_활성화된다()
|
|
{
|
|
var m = NewManager();
|
|
var t1 = m.NewTab("https://a.com");
|
|
var t2 = m.NewTab("https://b.com");
|
|
Assert.Same(t2, m.ActiveTab);
|
|
Assert.False(t1.IsActive);
|
|
Assert.True(t2.IsActive);
|
|
}
|
|
|
|
[Fact]
|
|
public void Activate는_활성_탭을_바꾸고_이벤트를_발생시킨다()
|
|
{
|
|
var m = NewManager();
|
|
var t1 = m.NewTab();
|
|
var t2 = m.NewTab();
|
|
var fired = 0;
|
|
m.ActiveChanged += _ => fired++;
|
|
m.Activate(t1);
|
|
Assert.Same(t1, m.ActiveTab);
|
|
Assert.True(t1.IsActive);
|
|
Assert.False(t2.IsActive);
|
|
Assert.Equal(1, fired);
|
|
}
|
|
|
|
[Fact]
|
|
public void CloseTab은_제거하고_이웃_탭을_활성화한다()
|
|
{
|
|
var m = NewManager();
|
|
m.NewTab("https://a.com"); // index 0
|
|
var t2 = m.NewTab("https://b.com"); // index 1 (active)
|
|
var t3 = m.NewTab("https://c.com"); // index 2
|
|
m.Activate(t2);
|
|
|
|
m.CloseTab(t2);
|
|
Assert.Equal(2, m.Tabs.Count);
|
|
Assert.DoesNotContain(t2, m.Tabs);
|
|
// 닫힌 탭 오른쪽이 있으면 그 탭(t3) 활성화 (Chrome 동작)
|
|
Assert.Same(t3, m.ActiveTab);
|
|
}
|
|
|
|
[Fact]
|
|
public void 마지막_탭을_닫으면_새_빈_탭으로_대체된다()
|
|
{
|
|
var m = NewManager();
|
|
var only = m.NewTab("https://solo.com");
|
|
m.CloseTab(only);
|
|
Assert.Single(m.Tabs);
|
|
Assert.NotSame(only, m.ActiveTab);
|
|
Assert.Same(m.ActiveTab, m.Tabs[0]);
|
|
}
|
|
|
|
[Fact]
|
|
public void 닫힌_탭은_스택에_쌓이고_ReopenClosedTab으로_원래_위치에_복원된다()
|
|
{
|
|
var m = NewManager();
|
|
var t1 = m.NewTab("https://a.com");
|
|
m.NewTab("https://b.com");
|
|
m.NewTab("https://c.com"); // index 2, active
|
|
m.CloseTab(m.Tabs[2]); // 마지막 인덱스 탭 닫기
|
|
|
|
var reopened = m.ReopenClosedTab();
|
|
Assert.NotNull(reopened);
|
|
Assert.Equal("https://c.com", reopened!.Url);
|
|
Assert.Equal(3, m.Tabs.Count);
|
|
Assert.Equal(2, m.Tabs.IndexOf(reopened)); // 원래 인덱스 복원
|
|
Assert.Same(reopened, m.ActiveTab);
|
|
Assert.Empty(m.ClosedStack);
|
|
}
|
|
|
|
[Fact]
|
|
public void 닫힌_탭_스택은_최대_25개다()
|
|
{
|
|
var m = NewManager();
|
|
for (int i = 0; i < 30; i++)
|
|
{
|
|
var t = m.NewTab($"https://x{i}.com");
|
|
m.CloseTab(t);
|
|
}
|
|
Assert.Equal(25, m.ClosedStack.Count);
|
|
Assert.Equal("https://x29.com", m.ClosedStack.First().Url); // LIFO 최신 우선
|
|
}
|
|
|
|
[Fact]
|
|
public void ActivateNext_Previous는_순환한다()
|
|
{
|
|
var m = NewManager();
|
|
var t1 = m.NewTab("https://a.com");
|
|
var t2 = m.NewTab("https://b.com");
|
|
m.Activate(t1);
|
|
|
|
m.ActivateNext();
|
|
Assert.Same(t2, m.ActiveTab);
|
|
m.ActivateNext(); // 순환
|
|
Assert.Same(t1, m.ActiveTab);
|
|
m.ActivatePrevious();
|
|
Assert.Same(t2, m.ActiveTab);
|
|
}
|
|
|
|
[Fact]
|
|
public void ActivateAt와_ActivateLast가_동작한다()
|
|
{
|
|
var m = NewManager();
|
|
m.NewTab("a"); m.NewTab("b"); var last = m.NewTab("c");
|
|
m.ActivateAt(0);
|
|
Assert.Same(m.Tabs[0], m.ActiveTab);
|
|
m.ActivateLast();
|
|
Assert.Same(last, m.ActiveTab);
|
|
}
|
|
|
|
[Fact]
|
|
public void Move는_탭_순서를_바꾼다()
|
|
{
|
|
var m = NewManager();
|
|
var t1 = m.NewTab("a"); var t2 = m.NewTab("b"); var t3 = m.NewTab("c");
|
|
m.Move(t1, 2); // a 를 끝으로
|
|
Assert.Equal(2, m.Tabs.IndexOf(t1));
|
|
Assert.Equal(0, m.Tabs.IndexOf(t2));
|
|
Assert.Equal(1, m.Tabs.IndexOf(t3));
|
|
}
|
|
|
|
[Fact]
|
|
public void Pin은_탭을_좌측_끝으로_이동시키고_핀_표시한다()
|
|
{
|
|
var m = NewManager();
|
|
m.NewTab("a"); m.NewTab("b");
|
|
var t3 = m.NewTab("c");
|
|
m.SetPinned(t3, true);
|
|
Assert.True(t3.IsPinned);
|
|
Assert.Equal(0, m.Tabs.IndexOf(t3)); // 핀 탭은 좌측 정렬
|
|
m.SetPinned(t3, false);
|
|
Assert.False(t3.IsPinned);
|
|
}
|
|
|
|
[Fact]
|
|
public void CaptureSession은_URL과_활성_인덱스와_핀을_담는다()
|
|
{
|
|
var m = NewManager();
|
|
m.NewTab("https://a.com");
|
|
var t2 = m.NewTab("https://b.com");
|
|
m.NewTab("https://c.com");
|
|
m.SetPinned(t2, true); // b 가 좌측으로 이동 → 순서: b,a,c
|
|
m.Activate(t2);
|
|
|
|
var s = m.CaptureSession();
|
|
Assert.Equal(new[] { "https://b.com", "https://a.com", "https://c.com" }, s.Urls);
|
|
Assert.Equal(0, s.ActiveIndex);
|
|
Assert.Equal(new[] { true, false, false }, s.Pinned);
|
|
}
|
|
|
|
[Fact]
|
|
public void RestoreSession은_저장된_탭들을_재생성한다()
|
|
{
|
|
var m = NewManager();
|
|
// CaptureSession 불변식: 핀 탭이 먼저 오는 순서로 저장됨
|
|
var snap = new SessionSnapshot(
|
|
new() { "https://b.com", "https://a.com" }, 0, new() { true, false });
|
|
m.RestoreSession(snap);
|
|
Assert.Equal(2, m.Tabs.Count);
|
|
Assert.Equal("https://b.com", m.ActiveTab!.Url);
|
|
Assert.True(m.Tabs[0].IsPinned); // 핀 탭이 좌측
|
|
Assert.False(m.Tabs[1].IsPinned);
|
|
}
|
|
|
|
[Fact]
|
|
public void RestoreSession은_기존_탭을_치환한다()
|
|
{
|
|
var m = NewManager();
|
|
m.NewTab("https://old.com");
|
|
m.RestoreSession(new SessionSnapshot(new() { "https://new.com" }, 0, new() { false }));
|
|
Assert.Single(m.Tabs);
|
|
Assert.Equal("https://new.com", m.Tabs[0].Url);
|
|
}
|
|
|
|
[Fact]
|
|
public void CaptureSession_유효한탭이있을때_비활성빈탭은_제외된다()
|
|
{
|
|
var m = NewManager();
|
|
var t1 = m.NewTab("https://a.com");
|
|
var t2 = m.NewTab(""); // 비활성 빈 탭
|
|
m.Activate(t1);
|
|
|
|
var snap = m.CaptureSession();
|
|
Assert.Single(snap.Urls);
|
|
Assert.Equal("https://a.com", snap.Urls[0]);
|
|
}
|
|
|
|
[Fact]
|
|
public void CaptureSession_모든탭이_빈탭일때_단일빈탭만_저장된다()
|
|
{
|
|
var m = NewManager();
|
|
m.NewTab("");
|
|
m.NewTab("");
|
|
|
|
var snap = m.CaptureSession();
|
|
Assert.Single(snap.Urls);
|
|
Assert.Equal("", snap.Urls[0]);
|
|
}
|
|
}
|
|
|
|
// 세션 JSON 저장소(T1-10) 분리 테스트
|
|
public class TabSessionStoreTests : IDisposable
|
|
{
|
|
private readonly string _path = Path.Combine(Path.GetTempPath(), $"session_{Guid.NewGuid():N}.json");
|
|
|
|
[Fact]
|
|
public void 저장_후_로드_라운드트립()
|
|
{
|
|
var snap = new SessionSnapshot(
|
|
new() { "https://a.com", "https://b.com", "https://c.com" }, 2, new() { true, false, false });
|
|
TabSessionStore.Save(_path, snap);
|
|
var loaded = TabSessionStore.Load(_path);
|
|
Assert.NotNull(loaded);
|
|
Assert.Equal(snap.Urls, loaded!.Urls);
|
|
Assert.Equal(2, loaded.ActiveIndex);
|
|
Assert.Equal(snap.Pinned, loaded.Pinned);
|
|
}
|
|
|
|
[Fact]
|
|
public void 파일_없으면_null()
|
|
{
|
|
Assert.Null(TabSessionStore.Load(_path));
|
|
}
|
|
|
|
[Fact]
|
|
public void 손상된_JSON이면_null()
|
|
{
|
|
File.WriteAllText(_path, "{ broken");
|
|
Assert.Null(TabSessionStore.Load(_path));
|
|
}
|
|
|
|
[Fact]
|
|
public void TabSessionStore_Load는_중복빈탭을_정제한다()
|
|
{
|
|
var snap = new SessionSnapshot(new() { "https://a.com", "", "" }, 0, new() { false, false, false });
|
|
TabSessionStore.Save(_path, snap);
|
|
var loaded = TabSessionStore.Load(_path);
|
|
Assert.NotNull(loaded);
|
|
Assert.Single(loaded!.Urls);
|
|
Assert.Equal("https://a.com", loaded.Urls[0]);
|
|
}
|
|
|
|
[Fact]
|
|
public void TabSessionStore_Load는_모두빈탭일때_단일탭만_반환한다()
|
|
{
|
|
var snap = new SessionSnapshot(new() { "", "" }, 0, new() { false, false });
|
|
TabSessionStore.Save(_path, snap);
|
|
var loaded = TabSessionStore.Load(_path);
|
|
Assert.NotNull(loaded);
|
|
Assert.Single(loaded!.Urls);
|
|
Assert.Equal("", loaded.Urls[0]);
|
|
}
|
|
|
|
public void Dispose() { try { File.Delete(_path); } catch { } }
|
|
}
|
|
|
|
public class ModernVerticalTabsFeatureTests
|
|
{
|
|
[Fact]
|
|
public void AppConfig_VerticalTabs_기본값_및_직렬화_검증()
|
|
{
|
|
var config = new Paca.Core.Config.AppConfig();
|
|
Assert.Equal("Left", config.VerticalTabsPosition);
|
|
Assert.False(config.VerticalTabsCollapsed);
|
|
Assert.Equal(220.0, config.VerticalTabsWidth);
|
|
Assert.True(config.VerticalTabsAutoExpand);
|
|
|
|
config.VerticalTabsPosition = "Right";
|
|
config.VerticalTabsCollapsed = true;
|
|
config.VerticalTabsWidth = 260.0;
|
|
config.VerticalTabsAutoExpand = false;
|
|
|
|
string json = System.Text.Json.JsonSerializer.Serialize(config);
|
|
var restored = System.Text.Json.JsonSerializer.Deserialize<Paca.Core.Config.AppConfig>(json);
|
|
|
|
Assert.NotNull(restored);
|
|
Assert.Equal("Right", restored!.VerticalTabsPosition);
|
|
Assert.True(restored.VerticalTabsCollapsed);
|
|
Assert.Equal(260.0, restored.VerticalTabsWidth);
|
|
Assert.False(restored.VerticalTabsAutoExpand);
|
|
}
|
|
|
|
[Fact]
|
|
public void SettingsViewModel_VerticalTabs_바인딩_및_커밋_검증()
|
|
{
|
|
var vm = new Paca.App.ViewModels.SettingsViewModel(new Paca.Core.Config.AppConfig());
|
|
var cfg = new Paca.Core.Config.AppConfig
|
|
{
|
|
VerticalTabsPosition = "Right",
|
|
VerticalTabsCollapsed = true,
|
|
VerticalTabsWidth = 280,
|
|
VerticalTabsAutoExpand = false
|
|
};
|
|
|
|
vm.LoadFromConfig(cfg);
|
|
|
|
Assert.Equal("Right", vm.VerticalTabsPosition);
|
|
Assert.True(vm.VerticalTabsCollapsed);
|
|
Assert.Equal(280, vm.VerticalTabsWidth);
|
|
Assert.False(vm.VerticalTabsAutoExpand);
|
|
|
|
vm.VerticalTabsPosition = "Left";
|
|
vm.VerticalTabsCollapsed = false;
|
|
vm.VerticalTabsWidth = 240;
|
|
vm.VerticalTabsAutoExpand = true;
|
|
|
|
var targetCfg = new Paca.Core.Config.AppConfig();
|
|
vm.CommitToConfig(targetCfg);
|
|
|
|
Assert.Equal("Left", targetCfg.VerticalTabsPosition);
|
|
Assert.False(targetCfg.VerticalTabsCollapsed);
|
|
Assert.Equal(240, targetCfg.VerticalTabsWidth);
|
|
Assert.True(targetCfg.VerticalTabsAutoExpand);
|
|
}
|
|
}
|