360 lines
13 KiB
C#
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 { }
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|