releases/tests/Paca.Tests/Browser/ChromeParityLastTabCloseHomeTabGateTests.cs

360 lines
13 KiB
C#

using System;
using System.IO;
using System.Linq;
using System.Windows;
using Paca.App;
using Paca.App.Browser.Features;
using Paca.Browser.Tabs;
using Paca.Tests.Browser;
using Xunit;
namespace Paca.Tests.Browser;
/// <summary>
/// 크롬 파리티: 창 내 모든 탭이 완전히 닫혔을 때(남은 탭 0개) 빈 화면이나 빈 탭이 아닌
/// 올바른 Home Tab(일반: Home/NTP, 시크릿: InPrivate NTP)이 자동으로 나타나는지 검증하는 테스트 게이트.
/// </summary>
public sealed class ChromeParityLastTabCloseHomeTabGateTests
{
[Fact]
public void TabManager_일반탭_마지막탭_닫으면_HomeUrl과_제목을_가진_홈탭이_생성된다()
{
// Arrange
var mgr = new TabManager(() => new TabItem())
{
HomeUrl = "paca://newtab"
};
var solo = mgr.NewTab("https://www.google.com");
solo.Title = "구글 검색";
Assert.Single(mgr.Tabs);
Assert.Same(solo, mgr.ActiveTab);
// Act: 유일한 탭 닫기
var closed = mgr.CloseTab(solo);
// Assert: 탭이 완전히 닫혔지만 탭이 0개가 되지 않고 홈 탭이 생성됨
Assert.True(closed);
Assert.Single(mgr.Tabs);
var homeTab = mgr.ActiveTab;
Assert.NotNull(homeTab);
Assert.NotSame(solo, homeTab);
Assert.Equal("paca://newtab", homeTab!.Url);
Assert.Equal("새 탭", homeTab.Title);
Assert.False(homeTab.IsPrivate);
Assert.True(homeTab.IsActive);
}
[Fact]
public void TabManager_시크릿탭_마지막탭_닫으면_InPrivate_HomeUrl과_제목을_가진_홈탭이_생성된다()
{
// Arrange
var mgr = new TabManager(() => new TabItem())
{
DefaultIsPrivate = true,
HomeUrl = "paca://newtab",
HomeUrlProvider = isPriv => isPriv ? "paca://inprivate" : "paca://newtab"
};
var privTab = mgr.NewTab("https://secret.example.org", isPrivate: true);
privTab.Title = "비밀 페이지";
Assert.Single(mgr.Tabs);
// Act
var closed = mgr.CloseTab(privTab);
// Assert
Assert.True(closed);
Assert.Single(mgr.Tabs);
var homeTab = mgr.ActiveTab;
Assert.NotNull(homeTab);
Assert.NotSame(privTab, homeTab);
Assert.Equal("paca://inprivate", homeTab!.Url);
Assert.Equal("InPrivate 새 탭", homeTab.Title);
Assert.True(homeTab.IsPrivate);
Assert.True(homeTab.IsActive);
}
[Fact]
public void TabManager_CloseAllTabs_호출시_모든탭이_닫히고_홈탭_1개로_초기화된다()
{
// Arrange
var mgr = new TabManager(() => new TabItem())
{
HomeUrl = "paca://newtab"
};
mgr.NewTab("https://site1.com");
mgr.NewTab("https://site2.com");
mgr.NewTab("https://site3.com");
Assert.Equal(3, mgr.Tabs.Count);
// Act
var homeTab = mgr.CloseAllTabs();
// Assert
Assert.Single(mgr.Tabs);
Assert.Same(homeTab, mgr.Tabs[0]);
Assert.Same(homeTab, mgr.ActiveTab);
Assert.Equal("paca://newtab", homeTab.Url);
Assert.Equal("새 탭", homeTab.Title);
}
[Fact]
public void MainWindow_단일탭_닫기시_홈탭이_자동생성되고_IsNewTabUrl_조건을_충족한다()
{
using var sta = StaDispatcher.Start();
WpfTestApp.Ensure(sta.Dispatcher);
sta.Invoke(() =>
{
var dataDir = Path.Combine(Path.GetTempPath(), $"vd_home_tab_close_{Guid.NewGuid():N}");
Environment.SetEnvironmentVariable("VD_DATA_DIR", dataDir);
try
{
var win = new MainWindow(isPrivateWindow: false);
win.TabsManager.Tabs.Clear();
var solo = win.TabsManager.NewTab("https://example.com");
solo.Title = "예제 사이트";
win.TabsManager.Activate(solo);
Assert.Single(win.TabsManager.Tabs);
// Act: 닫기
win.TabsManager.CloseTab(solo);
// Assert: 닫힌 후 새 홈 탭이 생성되어 있으며 NewTabUrl 규격을 만족함
Assert.Single(win.TabsManager.Tabs);
var active = win.TabsManager.ActiveTab;
Assert.NotNull(active);
Assert.True(NewTabPageBuilder.IsNewTabUrl(active!.Url), $"Expected NewTabUrl but was '{active.Url}'");
Assert.Equal("새 탭", active.Title);
Assert.False(active.IsPrivate);
}
finally
{
try { if (Directory.Exists(dataDir)) Directory.Delete(dataDir, true); } catch { }
}
});
}
[Fact]
public void MainWindow_시크릿창_단일탭_닫기시_InPrivate홈탭이_생성된다()
{
using var sta = StaDispatcher.Start();
WpfTestApp.Ensure(sta.Dispatcher);
sta.Invoke(() =>
{
var dataDir = Path.Combine(Path.GetTempPath(), $"vd_priv_home_close_{Guid.NewGuid():N}");
Environment.SetEnvironmentVariable("VD_DATA_DIR", dataDir);
try
{
var win = new MainWindow(isPrivateWindow: true);
win.TabsManager.Tabs.Clear();
var privTab = win.TabsManager.NewTab("https://secret.com", isPrivate: true);
privTab.Title = "보안 세션";
win.TabsManager.Activate(privTab);
Assert.Single(win.TabsManager.Tabs);
// Act
win.TabsManager.CloseTab(privTab);
// Assert
Assert.Single(win.TabsManager.Tabs);
var active = win.TabsManager.ActiveTab;
Assert.NotNull(active);
Assert.Equal(NewTabPageBuilder.InPrivateNtpUrl, active!.Url);
Assert.Equal("InPrivate 새 탭", active.Title);
Assert.True(active.IsPrivate);
}
finally
{
try { if (Directory.Exists(dataDir)) Directory.Delete(dataDir, true); } catch { }
}
});
}
[Fact]
public void MainWindow_다중창에서_각각_마지막탭_닫을때_독립적으로_홈탭이_생성된다()
{
using var sta = StaDispatcher.Start();
WpfTestApp.Ensure(sta.Dispatcher);
sta.Invoke(() =>
{
var dataDir = Path.Combine(Path.GetTempPath(), $"vd_multi_win_close_{Guid.NewGuid():N}");
Environment.SetEnvironmentVariable("VD_DATA_DIR", dataDir);
try
{
// Window 1: 일반 창
var win1 = new MainWindow(isPrivateWindow: false);
win1.TabsManager.Tabs.Clear();
var tab1 = win1.TabsManager.NewTab("https://site-window-1.com");
win1.TabsManager.Activate(tab1);
// Window 2: 시크릿 창
var win2 = new MainWindow(isPrivateWindow: true);
win2.TabsManager.Tabs.Clear();
var tab2 = win2.TabsManager.NewTab("https://site-window-2.com", isPrivate: true);
win2.TabsManager.Activate(tab2);
// Act: 두 창의 마지막 탭을 각각 닫음
win1.TabsManager.CloseTab(tab1);
win2.TabsManager.CloseTab(tab2);
// Assert: Window 1은 일반 홈 탭
Assert.Single(win1.TabsManager.Tabs);
Assert.True(NewTabPageBuilder.IsNewTabUrl(win1.TabsManager.ActiveTab?.Url));
Assert.False(win1.TabsManager.ActiveTab?.IsPrivate);
Assert.Equal("새 탭", win1.TabsManager.ActiveTab?.Title);
// Assert: Window 2는 시크릿 홈 탭
Assert.Single(win2.TabsManager.Tabs);
Assert.Equal(NewTabPageBuilder.InPrivateNtpUrl, win2.TabsManager.ActiveTab?.Url);
Assert.True(win2.TabsManager.ActiveTab?.IsPrivate);
Assert.Equal("InPrivate 새 탭", win2.TabsManager.ActiveTab?.Title);
}
finally
{
try { if (Directory.Exists(dataDir)) Directory.Delete(dataDir, true); } catch { }
}
});
}
[Fact]
public void TabManager_마지막_탭이_홈탭이면_CloseTab이_거부되고_탭이_유지된다()
{
// Arrange: 홈 탭 1개만 존재하는 상태
var mgr = new TabManager(() => new TabItem())
{
HomeUrl = "paca://newtab"
};
var homeTab = mgr.NewHomeTab();
Assert.Single(mgr.Tabs);
Assert.Same(homeTab, mgr.ActiveTab);
// Act: 마지막 탭이자 홈 탭인 탭 닫기 시도
var canClose = mgr.CanCloseTab(homeTab);
var closed = mgr.CloseTab(homeTab);
// Assert: 닫기가 거부되고 탭이 그대로 유지됨
Assert.False(canClose);
Assert.False(closed);
Assert.Single(mgr.Tabs);
Assert.Same(homeTab, mgr.Tabs[0]);
Assert.Same(homeTab, mgr.ActiveTab);
}
[Fact]
public void TabManager_마지막_탭이_InPrivate_홈탭이면_CloseTab이_거부된다()
{
// Arrange
var mgr = new TabManager(() => new TabItem())
{
DefaultIsPrivate = true,
HomeUrlProvider = p => p ? "paca://inprivate" : "paca://newtab"
};
var privHome = mgr.NewHomeTab(isPrivate: true);
Assert.Single(mgr.Tabs);
Assert.Same(privHome, mgr.ActiveTab);
// Act
var canClose = mgr.CanCloseTab(privHome);
var closed = mgr.CloseTab(privHome);
// Assert
Assert.False(canClose);
Assert.False(closed);
Assert.Single(mgr.Tabs);
Assert.Same(privHome, mgr.Tabs[0]);
Assert.Same(privHome, mgr.ActiveTab);
}
[Fact]
public void TabManager_다중탭일때_홈탭은_정상적으로_닫힌다()
{
// Arrange: 홈 탭과 일반 웹페이지 탭이 모두 존재하는 다중 탭 상태
var mgr = new TabManager(() => new TabItem())
{
HomeUrl = "paca://newtab"
};
var home = mgr.NewHomeTab();
var web = mgr.NewTab("https://example.com");
Assert.Equal(2, mgr.Tabs.Count);
// Act: 홈 탭 닫기
var canClose = mgr.CanCloseTab(home);
var closed = mgr.CloseTab(home);
// Assert: 다중 탭 상태이므로 홈 탭이라도 정상적으로 닫힘
Assert.True(canClose);
Assert.True(closed);
Assert.Single(mgr.Tabs);
Assert.Same(web, mgr.ActiveTab);
}
[Fact]
public void TabManager_일반사이트_마지막탭_닫기후_생성된_홈탭은_연속닫기_시도시_닫히지_않는다()
{
// Arrange: 일반 웹페이지 단일 탭
var mgr = new TabManager(() => new TabItem())
{
HomeUrl = "paca://newtab"
};
var solo = mgr.NewTab("https://news.com");
Assert.Single(mgr.Tabs);
// Act 1: 일반 웹페이지 단일 탭 닫기 -> 홈 탭으로 자동 대체되어 창 유지
var canClose1 = mgr.CanCloseTab(solo);
var closed1 = mgr.CloseTab(solo);
Assert.True(canClose1);
Assert.True(closed1);
Assert.Single(mgr.Tabs);
var autoHome = mgr.ActiveTab;
Assert.NotNull(autoHome);
Assert.NotSame(solo, autoHome);
// Act 2: 이제 마지막 탭이 홈 탭이 된 상태에서 다시 닫기 시도 -> 거부되어야 함
var canClose2 = mgr.CanCloseTab(autoHome);
var closed2 = mgr.CloseTab(autoHome);
// Assert 2
Assert.False(canClose2);
Assert.False(closed2);
Assert.Single(mgr.Tabs);
Assert.Same(autoHome, mgr.ActiveTab);
}
[Fact]
public void MainWindow_마지막_홈탭_닫기_시도시_거부되고_탭이_유지된다()
{
using var sta = StaDispatcher.Start();
WpfTestApp.Ensure(sta.Dispatcher);
sta.Invoke(() =>
{
var dataDir = Path.Combine(Path.GetTempPath(), $"vd_last_home_close_guard_{Guid.NewGuid():N}");
Environment.SetEnvironmentVariable("VD_DATA_DIR", dataDir);
try
{
var win = new MainWindow(isPrivateWindow: false);
win.TabsManager.Tabs.Clear();
var home = win.TabsManager.NewHomeTab();
win.TabsManager.Activate(home);
Assert.Single(win.TabsManager.Tabs);
// Act: 마지막 홈 탭 닫기 시도
var canClose = win.TabsManager.CanCloseTab(home);
var closed = win.TabsManager.CloseTab(home);
// Assert: 닫기가 거부되고 탭이 유지됨
Assert.False(canClose);
Assert.False(closed);
Assert.Single(win.TabsManager.Tabs);
Assert.Same(home, win.TabsManager.ActiveTab);
}
finally
{
try { if (Directory.Exists(dataDir)) Directory.Delete(dataDir, true); } catch { }
}
});
}
}