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:
Yun Chan 2026-09-14 00:39:44 +09:00
parent a88aafa1e5
commit 0e568f1f0a
975 changed files with 130593 additions and 16783 deletions

View file

@ -0,0 +1,102 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Paca.Mobile.Core;
using Xunit;
namespace Paca.Tests.Mobile;
/// <summary>
/// Gate 133 ~ 138: PacaDrop 초고속 미디어 전송 및 Send-to-PC 프로덕션 경험 기계적 검증
/// </summary>
public class MobileProductionFeaturesGateTests
{
[Fact]
public void Gate133_PacaDrop_TransferManifest_Integrity()
{
var rawData = Encoding.UTF8.GetBytes("PacaDrop-Binary-Content-Payload-Stream-Test-Data");
var sha256 = Convert.ToHexString(SHA256.HashData(rawData));
var manifest = new PacaDropManifest(
FileId: "media-file-99",
FileName: "BigBuckBunny_4K.mp4",
TotalBytes: rawData.Length,
Sha256Checksum: sha256,
MimeType: "video/mp4",
CreatedAt: DateTimeOffset.UtcNow
);
Assert.Equal("BigBuckBunny_4K.mp4", manifest.FileName);
Assert.Equal(rawData.Length, manifest.TotalBytes);
Assert.True(manifest.VerifyChecksum(rawData));
// 위조되거나 잘린 데이터 검증 실패 확인
var corruptedData = Encoding.UTF8.GetBytes("Corrupted-Data");
Assert.False(manifest.VerifyChecksum(corruptedData));
}
[Fact]
public void Gate134_PacaDropTransfer_Progress_And_Speed_Tracking()
{
var tracker = new PacaDropProgressTracker(totalBytes: 100_000_000L); // 100MB
Assert.Equal(0, tracker.Percent);
Assert.False(tracker.IsCompleted);
// 50MB 수신 보고
tracker.UpdateProgress(transferredBytes: 50_000_000L);
Assert.Equal(50, (int)tracker.Percent);
Assert.False(tracker.IsCompleted);
// 100MB 완료 보고
tracker.UpdateProgress(transferredBytes: 100_000_000L);
Assert.Equal(100, (int)tracker.Percent);
Assert.True(tracker.IsCompleted);
}
[Fact]
public void Gate135_SendToPc_SmartDispatcher_Extracts_And_Enriches()
{
var dispatcher = new SendToPcDispatcher();
var rawShareText = "Check this amazing video out! https://youtu.be/dQw4w9WgXcQ?si=abcdef [Sent from Mobile]";
var request = dispatcher.PrepareRequest(rawShareText, preferredQuality: "4K");
Assert.NotNull(request);
Assert.Equal("https://youtu.be/dQw4w9WgXcQ?si=abcdef", request.NormalizedUrl);
Assert.Equal("YouTube", request.DetectedPlatform);
Assert.Equal("4K", request.PreferredQuality);
Assert.True(request.IsReadyForEnqueue);
}
[Fact]
public void Gate136_SendToPc_Rejects_Empty_Or_Non_Url()
{
var dispatcher = new SendToPcDispatcher();
Assert.Null(dispatcher.PrepareRequest("Just random chat message without any link"));
Assert.Null(dispatcher.PrepareRequest(""));
Assert.Null(dispatcher.PrepareRequest(null!));
}
[Fact]
public void Gate137_PositionSyncStore_Persists_And_Resolves_Accurately()
{
var store = new MobilePlaybackPositionStore();
store.RecordPosition("item-101", 145.5); // 2분 25.5초 지점
Assert.Equal(145.5, store.GetPosition("item-101"));
Assert.Equal(0.0, store.GetPosition("non-existent-item"));
// 유효하지 않은 음수 위치 방어
store.RecordPosition("item-101", -5.0);
Assert.Equal(0.0, store.GetPosition("item-101"));
}
[Fact]
public void Gate138_OfflineStorageQuotaGuard_Evaluates_Available_Space()
{
var guard = new OfflineStorageQuotaGuard(maxQuotaBytes: 1_000_000_000L); // 1GB 한도
Assert.True(guard.CanStoreItem(itemSizeBytes: 200_000_000L, currentUsageBytes: 300_000_000L)); // 500MB < 1GB
Assert.False(guard.CanStoreItem(itemSizeBytes: 800_000_000L, currentUsageBytes: 300_000_000L)); // 1.1GB > 1GB
}
}