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
165
tests/Paca.Tests/Mobile/MobilePrivateBrowsingGateTests.cs
Normal file
165
tests/Paca.Tests/Mobile/MobilePrivateBrowsingGateTests.cs
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Paca.Mobile;
|
||||
using Paca.Mobile.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Paca.Tests.Mobile;
|
||||
|
||||
/// <summary>
|
||||
/// PACA Mobile 사생활 보호(InPrivate / Incognito) 세션 격리 및 수명주기 무결성 검증 게이트
|
||||
/// </summary>
|
||||
public class MobilePrivateBrowsingGateTests : IDisposable
|
||||
{
|
||||
private readonly string _testTempDir;
|
||||
|
||||
public MobilePrivateBrowsingGateTests()
|
||||
{
|
||||
_testTempDir = Path.Combine(Path.GetTempPath(), "paca_mobile_priv_tests_" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(_testTempDir);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(_testTempDir))
|
||||
Directory.Delete(_testTempDir, recursive: true);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate1_MobilePrivateBrowsingPolicy_사생활보호_정책_단정_검증()
|
||||
{
|
||||
var privTab = new BrowserTab
|
||||
{
|
||||
Id = "priv-1",
|
||||
Url = "https://confidential-portal.org",
|
||||
IsPrivate = true
|
||||
};
|
||||
|
||||
var normTab = new BrowserTab
|
||||
{
|
||||
Id = "norm-1",
|
||||
Url = "https://public-news.org",
|
||||
IsPrivate = false
|
||||
};
|
||||
|
||||
// 1. 방문 기록 저장 차단 여부
|
||||
Assert.False(MobilePrivateBrowsingPolicy.ShouldPersistHistory(privTab));
|
||||
Assert.True(MobilePrivateBrowsingPolicy.ShouldPersistHistory(normTab));
|
||||
Assert.False(MobilePrivateBrowsingPolicy.ShouldPersistHistory(null));
|
||||
|
||||
// 2. 디스크 쿠키 Flush 차단 여부 (RAM에만 유지)
|
||||
Assert.False(MobilePrivateBrowsingPolicy.ShouldFlushCookies(privTab));
|
||||
Assert.True(MobilePrivateBrowsingPolicy.ShouldFlushCookies(normTab));
|
||||
Assert.False(MobilePrivateBrowsingPolicy.ShouldFlushCookies(null));
|
||||
|
||||
// 3. 디스크 캐시 및 양식 자동저장 차단 여부
|
||||
Assert.False(MobilePrivateBrowsingPolicy.ShouldEnableDiskCache(privTab));
|
||||
Assert.True(MobilePrivateBrowsingPolicy.ShouldEnableDiskCache(normTab));
|
||||
Assert.False(MobilePrivateBrowsingPolicy.ShouldSaveFormData(privTab));
|
||||
Assert.True(MobilePrivateBrowsingPolicy.ShouldSaveFormData(normTab));
|
||||
|
||||
// 4. 최근 앱 섬네일 스크린샷 방어(FLAG_SECURE) 활성화 여부
|
||||
Assert.True(MobilePrivateBrowsingPolicy.ShouldEnableSecureWindow(privTab));
|
||||
Assert.False(MobilePrivateBrowsingPolicy.ShouldEnableSecureWindow(normTab));
|
||||
Assert.False(MobilePrivateBrowsingPolicy.ShouldEnableSecureWindow(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate2_MobileTabManager_시크릿탭_카운트_및_CloseAllPrivateTabs_검증()
|
||||
{
|
||||
var manager = new MobileTabManager();
|
||||
// manager starts with 1 normal tab
|
||||
Assert.Equal(1, manager.NormalTabCount);
|
||||
Assert.Equal(0, manager.PrivateTabCount);
|
||||
Assert.False(manager.HasPrivateTabs);
|
||||
|
||||
var priv1 = manager.AddTab("https://secret1.com", isPrivate: true);
|
||||
var priv2 = manager.AddTab("https://secret2.com", isPrivate: true);
|
||||
var norm2 = manager.AddTab("https://public2.com", isPrivate: false);
|
||||
|
||||
Assert.Equal(4, manager.Count);
|
||||
Assert.Equal(2, manager.NormalTabCount);
|
||||
Assert.Equal(2, manager.PrivateTabCount);
|
||||
Assert.True(manager.HasPrivateTabs);
|
||||
|
||||
bool allPrivateClosedFired = false;
|
||||
manager.AllPrivateTabsClosed += () => allPrivateClosedFired = true;
|
||||
|
||||
// 모든 시크릿 탭 일괄 닫기
|
||||
manager.CloseAllPrivateTabs();
|
||||
|
||||
Assert.True(allPrivateClosedFired, "AllPrivateTabsClosed 이벤트가 발생해야 합니다.");
|
||||
Assert.Equal(2, manager.Count);
|
||||
Assert.Equal(2, manager.NormalTabCount);
|
||||
Assert.Equal(0, manager.PrivateTabCount);
|
||||
Assert.False(manager.HasPrivateTabs);
|
||||
Assert.All(manager.Tabs, t => Assert.False(t.IsPrivate));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate3_마지막_시크릿탭_개별_종료_시_AllPrivateTabsClosed_이벤트_발생_검증()
|
||||
{
|
||||
var manager = new MobileTabManager();
|
||||
var priv1 = manager.AddTab("https://secret-only.com", isPrivate: true);
|
||||
|
||||
BrowserTab? closedTab = null;
|
||||
manager.TabClosed += t => closedTab = t;
|
||||
|
||||
bool allPrivateClosedFired = false;
|
||||
manager.AllPrivateTabsClosed += () => allPrivateClosedFired = true;
|
||||
|
||||
manager.CloseTab(priv1.Id);
|
||||
|
||||
Assert.NotNull(closedTab);
|
||||
Assert.Equal(priv1.Id, closedTab!.Id);
|
||||
Assert.True(allPrivateClosedFired, "마지막 시크릿 탭이 닫히면 AllPrivateTabsClosed가 발행되어야 합니다.");
|
||||
Assert.False(manager.HasPrivateTabs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Gate4_MobilePrivateSessionManager_세션_종료_시_플랫폼_정화_훅_연동_검증()
|
||||
{
|
||||
bool cacheCleared = false;
|
||||
bool cookiesCleared = false;
|
||||
bool formDataCleared = false;
|
||||
bool webStorageCleared = false;
|
||||
|
||||
var sessionManager = new MobilePrivateSessionManager(
|
||||
clearCache: () => cacheCleared = true,
|
||||
clearCookies: () => cookiesCleared = true,
|
||||
clearFormData: () => formDataCleared = true,
|
||||
clearWebStorage: () => webStorageCleared = true
|
||||
);
|
||||
|
||||
sessionManager.PurgePrivateSessionData();
|
||||
|
||||
Assert.True(cacheCleared, "캐시 정화 훅이 실행되어야 합니다.");
|
||||
Assert.True(cookiesCleared, "쿠키 정화 훅이 실행되어야 합니다.");
|
||||
Assert.True(formDataCleared, "폼 데이터 정화 훅이 실행되어야 합니다.");
|
||||
Assert.True(webStorageCleared, "웹 스토리지 정화 훅이 실행되어야 합니다.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Gate5_MobileTabManager_세션_영속화_시_시크릿탭_누출_원천_차단()
|
||||
{
|
||||
var manager = new MobileTabManager();
|
||||
manager.AddTab("https://public-portal.com", isPrivate: false);
|
||||
manager.AddTab("https://confidential-bank-account.org/dashboard", isPrivate: true);
|
||||
|
||||
var sessionFile = Path.Combine(_testTempDir, "session_test.json");
|
||||
await manager.SaveSessionAsync(sessionFile);
|
||||
|
||||
Assert.True(File.Exists(sessionFile));
|
||||
var rawJson = await File.ReadAllTextAsync(sessionFile);
|
||||
|
||||
// 시크릿 URL이 디스크 파일에 일체 기록되지 않아야 함
|
||||
Assert.DoesNotContain("confidential-bank-account", rawJson);
|
||||
Assert.Contains("public-portal.com", rawJson);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue