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,64 @@
using System;
using System.Collections.Generic;
using Paca.Mobile.Core;
using Xunit;
namespace Paca.Tests.Core;
public class BookmarkChapterExporterGateTests
{
[Fact]
public void Gate405_BookmarkChapterExporter_FormatsYoutubeTimestamps_Correctly()
{
// 45 seconds -> 00:45
Assert.Equal("00:45", BookmarkChapterExporter.FormatYoutubeTimestamp(45.0));
// 12 minutes 30 seconds -> 12:30
Assert.Equal("12:30", BookmarkChapterExporter.FormatYoutubeTimestamp(750.0));
// 1 hour 15 minutes 4 seconds -> 01:15:04
Assert.Equal("01:15:04", BookmarkChapterExporter.FormatYoutubeTimestamp(4504.0));
}
[Fact]
public void Gate406_BookmarkChapterExporter_ExportsYoutubeTimecodes_WithZeroStart()
{
var doc = new MediaBookmarkDocument("vid-1", "lecture.mp4");
doc.Bookmarks.Add(new MediaBookmark("1", 150.0, "Introduction", null, "#FFF", DateTime.UtcNow));
doc.Bookmarks.Add(new MediaBookmark("2", 600.0, "Main Content", null, "#FFF", DateTime.UtcNow));
var text = BookmarkChapterExporter.ExportYoutubeTimecodes(doc);
Assert.Contains("00:00 - 시작", text);
Assert.Contains("02:30 - Introduction", text);
Assert.Contains("10:00 - Main Content", text);
}
[Fact]
public void Gate407_BookmarkChapterExporter_ExportsWebVttChapters_Accurately()
{
var doc = new MediaBookmarkDocument("vid-1", "podcast.mp4");
doc.Bookmarks.Add(new MediaBookmark("1", 0.0, "Intro", null, "#FFF", DateTime.UtcNow));
doc.Bookmarks.Add(new MediaBookmark("2", 120.0, "Discussion", null, "#FFF", DateTime.UtcNow));
var vtt = BookmarkChapterExporter.ExportWebVttChapters(doc, totalDurationSec: 300.0);
Assert.StartsWith("WEBVTT - Chapters", vtt.TrimStart());
Assert.Contains("00:00:00.000 --> 00:02:00.000", vtt);
Assert.Contains("Intro", vtt);
Assert.Contains("00:02:00.000 --> 00:05:00.000", vtt);
Assert.Contains("Discussion", vtt);
}
[Fact]
public void Gate408_BookmarkChapterExporter_HandlesEmptyDocumentGracefully()
{
var emptyDoc = new MediaBookmarkDocument("vid-0", "empty.mp4");
var yt = BookmarkChapterExporter.ExportYoutubeTimecodes(emptyDoc);
Assert.Equal("00:00 - 시작", yt.Trim());
var vtt = BookmarkChapterExporter.ExportWebVttChapters(emptyDoc, totalDurationSec: 60.0);
Assert.Contains("00:00:00.000 --> 00:01:00.000", vtt);
}
}