feat(ads/seo/release): v1.2.0 with live Google Ads, isolated ad profile, ads.txt, and SEO/AEO/GEO optimization
This commit is contained in:
parent
a88aafa1e5
commit
0e568f1f0a
975 changed files with 130593 additions and 16783 deletions
203
tests/Paca.Tests/Browser/PrivateBrowsingSessionGateTests.cs
Normal file
203
tests/Paca.Tests/Browser/PrivateBrowsingSessionGateTests.cs
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Paca.App;
|
||||
using Paca.App.Browser.Features;
|
||||
using Paca.Browser;
|
||||
using Paca.Browser.Tabs;
|
||||
using Xunit;
|
||||
|
||||
namespace Paca.Tests.Browser;
|
||||
|
||||
/// <summary>
|
||||
/// 사생활 보호(InPrivate/Private Browsing) 무결성 검증 게이트:
|
||||
/// 세션 스냅샷, 닫힌 탭 복원, 방문 기록 영속화, 원시 네트워크 로그, NTP 대시보드 무누수 검증.
|
||||
/// </summary>
|
||||
public class PrivateBrowsingSessionGateTests
|
||||
{
|
||||
private static TabManager NewManager() => new(() => new TabItem());
|
||||
|
||||
[Fact]
|
||||
public void CaptureSession_사생활보호_InPrivate_탭은_세션스냅샷에_포함되지_않는다()
|
||||
{
|
||||
var m = NewManager();
|
||||
var normalTab = m.NewTab("https://public-site.com");
|
||||
var privateTab = m.NewTab("https://secret-bank.com", isPrivate: true);
|
||||
m.Activate(privateTab);
|
||||
|
||||
var snap = m.CaptureSession();
|
||||
|
||||
Assert.Contains("https://public-site.com", snap.Urls);
|
||||
Assert.DoesNotContain("https://secret-bank.com", snap.Urls);
|
||||
Assert.Single(snap.Urls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CaptureSession_모든_탭이_InPrivate일때_비공개URL이_누출되지_않는다()
|
||||
{
|
||||
var m = NewManager();
|
||||
m.NewTab("https://confidential-1.com", isPrivate: true);
|
||||
m.NewTab("https://confidential-2.com", isPrivate: true);
|
||||
|
||||
var snap = m.CaptureSession();
|
||||
|
||||
Assert.DoesNotContain("https://confidential-1.com", snap.Urls);
|
||||
Assert.DoesNotContain("https://confidential-2.com", snap.Urls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReopenClosedTab_InPrivate_탭_복원_시_IsPrivate_속성이_그대로_보존된다()
|
||||
{
|
||||
var m = NewManager();
|
||||
var privateTab = m.NewTab("https://secret-passwords.com", isPrivate: true);
|
||||
|
||||
// InPrivate 탭 닫기
|
||||
m.CloseTab(privateTab);
|
||||
|
||||
// Ctrl+Shift+T 복원 시 InPrivate 상태가 유지되어야 함 (일반 탭으로 격하 누수 방지)
|
||||
var reopened = m.ReopenClosedTab();
|
||||
Assert.NotNull(reopened);
|
||||
Assert.True(reopened!.IsPrivate, "복원된 탭도 IsPrivate 상태가 엄격히 유지되어야 합니다.");
|
||||
Assert.Equal("https://secret-passwords.com", reopened.Url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewTabPageBuilder_InPrivate_NTP는_안내문구와_검색창을_제공하고_일반기록은_배제한다()
|
||||
{
|
||||
var html = NewTabPageBuilder.BuildInPrivateNtp(isDark: true, accentColor: "#8B5CF6");
|
||||
|
||||
Assert.NotNull(html);
|
||||
Assert.Contains("InPrivate", html, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("방문 기록", html);
|
||||
Assert.Contains("쿠키", html);
|
||||
Assert.Contains("저장되지 않습니다", html);
|
||||
|
||||
// 일반 NTP의 컴포넌트(shortcuts, recentHistory, recentDownloads) JSON 데이터가 없어야 함
|
||||
Assert.DoesNotContain("\"recentHistory\":[", html);
|
||||
Assert.DoesNotContain("\"recentDownloads\":[", html);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewTabPageBuilder_IsNewTabUrl_paca_inprivate_인식_검증()
|
||||
{
|
||||
Assert.True(NewTabPageBuilder.IsNewTabUrl("paca://inprivate"));
|
||||
Assert.True(NewTabPageBuilder.IsNewTabUrl("about:inprivate"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MainWindow_InPrivate_창_생성_시_기본_IsPrivate_및_비공개_식별자_유지()
|
||||
{
|
||||
var dataDir = Path.Combine(Path.GetTempPath(), $"paca_inprivate_test_{Guid.NewGuid():N}");
|
||||
Environment.SetEnvironmentVariable("VD_DATA_DIR", dataDir);
|
||||
try
|
||||
{
|
||||
using var sta = StaDispatcher.Start();
|
||||
WpfTestApp.Ensure(sta.Dispatcher);
|
||||
|
||||
await sta.InvokeAsync(async () =>
|
||||
{
|
||||
var privateWindow = new MainWindow(isPrivateWindow: true);
|
||||
privateWindow.Show();
|
||||
|
||||
Assert.True(privateWindow.IsPrivateWindow, "isPrivateWindow: true로 생성된 창의 IsPrivateWindow는 true여야 합니다.");
|
||||
Assert.Contains("InPrivate", privateWindow.Title, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// 새 탭 생성 시 기본으로 InPrivate인지 확인
|
||||
var newTab = privateWindow.Tabs.NewTab("https://test.org");
|
||||
Assert.True(newTab.IsPrivate, "InPrivate 창에서 생성된 탭은 기본적으로 IsPrivate이어야 합니다.");
|
||||
|
||||
privateWindow.Close();
|
||||
await Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
try { if (Directory.Exists(dataDir)) Directory.Delete(dataDir, true); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InPrivate_탭_종료_시_아카이브_파일_archive_json에_저장되지_않는다()
|
||||
{
|
||||
var dataDir = Path.Combine(Path.GetTempPath(), $"paca_archive_leak_test_{Guid.NewGuid():N}");
|
||||
Environment.SetEnvironmentVariable("VD_DATA_DIR", dataDir);
|
||||
try
|
||||
{
|
||||
using var sta = StaDispatcher.Start();
|
||||
WpfTestApp.Ensure(sta.Dispatcher);
|
||||
|
||||
await sta.InvokeAsync(async () =>
|
||||
{
|
||||
var window = new MainWindow();
|
||||
window.Show();
|
||||
|
||||
// 1. InPrivate 탭 생성 및 닫기
|
||||
var secretTab = window.Tabs.NewTab("https://classified-credentials.com", isPrivate: true);
|
||||
secretTab.Title = "기밀 페이지";
|
||||
window.Tabs.CloseTab(secretTab);
|
||||
|
||||
// 2. archive.json 확인: InPrivate 탭이 저장되지 않았어야 함
|
||||
var archivePath = Path.Combine(dataDir, "archive.json");
|
||||
if (File.Exists(archivePath))
|
||||
{
|
||||
var archiveContent = File.ReadAllText(archivePath);
|
||||
Assert.DoesNotContain("classified-credentials.com", archiveContent);
|
||||
}
|
||||
|
||||
// 3. 일반 탭 생성 및 닫기 -> 일반 탭은 정상 저장되어야 함
|
||||
var normalTab = window.Tabs.NewTab("https://public-news.com");
|
||||
normalTab.Title = "공개 뉴스";
|
||||
window.Tabs.CloseTab(normalTab);
|
||||
|
||||
if (File.Exists(archivePath))
|
||||
{
|
||||
var archiveContent = File.ReadAllText(archivePath);
|
||||
Assert.Contains("public-news.com", archiveContent);
|
||||
}
|
||||
|
||||
window.Close();
|
||||
await Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
try { if (Directory.Exists(dataDir)) Directory.Delete(dataDir, true); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InPrivate_탭_활성화_시_주소창_InPrivate_배지가_동기화된다()
|
||||
{
|
||||
var dataDir = Path.Combine(Path.GetTempPath(), $"paca_badge_test_{Guid.NewGuid():N}");
|
||||
Environment.SetEnvironmentVariable("VD_DATA_DIR", dataDir);
|
||||
try
|
||||
{
|
||||
using var sta = StaDispatcher.Start();
|
||||
WpfTestApp.Ensure(sta.Dispatcher);
|
||||
|
||||
await sta.InvokeAsync(async () =>
|
||||
{
|
||||
var window = new MainWindow();
|
||||
window.Show();
|
||||
|
||||
var normalTab = window.Tabs.NewTab("https://normal.com", activate: true);
|
||||
Assert.Equal(Visibility.Collapsed, window.InPrivateAddressBadge.Visibility);
|
||||
|
||||
var privateTab = window.Tabs.NewTab("https://secret.com", activate: true, isPrivate: true);
|
||||
Assert.Equal(Visibility.Visible, window.InPrivateAddressBadge.Visibility);
|
||||
|
||||
window.Tabs.Activate(normalTab);
|
||||
Assert.Equal(Visibility.Collapsed, window.InPrivateAddressBadge.Visibility);
|
||||
|
||||
window.Close();
|
||||
await Task.CompletedTask;
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
try { if (Directory.Exists(dataDir)) Directory.Delete(dataDir, true); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue