Files
GmRelayBot/tests/GmRelay.Bot.Tests/Web/PortfolioServiceSourceTests.cs
T

96 lines
4.0 KiB
C#

namespace GmRelay.Bot.Tests.Web;
public sealed class PortfolioServiceSourceTests
{
[Fact]
public async Task PortfolioService_ShouldExposePortfolioTablesAndPublicationGuards()
{
var source = await ReadRepositoryFileAsync("src/GmRelay.Web/Services/Portfolio/PortfolioService.cs");
Assert.Contains("portfolio_games", source, StringComparison.Ordinal);
Assert.Contains("portfolio_game_sessions", source, StringComparison.Ordinal);
Assert.Contains("portfolio_game_masters", source, StringComparison.Ordinal);
Assert.Contains("portfolio_game_reviews", source, StringComparison.Ordinal);
Assert.Contains("moderation_status = 'Approved'", source, StringComparison.Ordinal);
Assert.Contains("publication_consent_at IS NOT NULL", source, StringComparison.Ordinal);
Assert.Contains("s.scheduled_at < now()", source, StringComparison.Ordinal);
Assert.Contains("FOR UPDATE", source, StringComparison.Ordinal);
Assert.Contains("ON CONFLICT (portfolio_game_id, author_player_id) DO NOTHING", source, StringComparison.Ordinal);
}
[Fact]
public async Task PublicMasterPortfolioQuery_ShouldNotRequirePublicSchedule()
{
var source = await ReadRepositoryFileAsync("src/GmRelay.Web/Services/Portfolio/PortfolioService.cs");
var publicMasterQuery = PublicMasterQuerySection(source);
Assert.Contains("portfolio_game_masters", publicMasterQuery, StringComparison.Ordinal);
Assert.DoesNotContain("public_schedule_enabled = true", publicMasterQuery, StringComparison.Ordinal);
}
[Fact]
public async Task PublicClubPortfolioQuery_ShouldRequirePublicSchedule()
{
var source = await ReadRepositoryFileAsync("src/GmRelay.Web/Services/Portfolio/PortfolioService.cs");
var publicClubQuery = PublicClubQuerySection(source);
Assert.Contains("g.public_schedule_enabled = true", publicClubQuery, StringComparison.Ordinal);
}
[Fact]
public async Task ShowcaseSessionQuery_ShouldKeepFourHourFutureWindow()
{
var source = await ReadRepositoryFileAsync("src/GmRelay.Web/Services/SessionService.cs");
var showcaseQuery = ShowcaseQuerySection(source);
Assert.Contains("s.scheduled_at > now() - interval '4 hours'", showcaseQuery, StringComparison.Ordinal);
}
private static string PublicMasterQuerySection(string source)
{
var start = source.IndexOf("GetPublicPortfolioGamesForMasterAsync", StringComparison.Ordinal);
if (start < 0)
return string.Empty;
var end = source.IndexOf("GetPublicPortfolioGamesForClubAsync", start, StringComparison.Ordinal);
return end < 0 ? source[start..] : source[start..end];
}
private static string PublicClubQuerySection(string source)
{
var start = source.IndexOf("GetPublicPortfolioGamesForClubAsync", StringComparison.Ordinal);
if (start < 0)
return string.Empty;
var end = source.IndexOf("GetPublicPortfolioGameBySlugAsync", start, StringComparison.Ordinal);
return end < 0 ? source[start..] : source[start..end];
}
private static string ShowcaseQuerySection(string source)
{
var start = source.IndexOf("GetShowcaseSessionsAsync", StringComparison.Ordinal);
if (start < 0)
return string.Empty;
var end = source.IndexOf("GetShowcaseSessionAsync", start, StringComparison.Ordinal);
return end < 0 ? source[start..] : source[start..end];
}
private static async Task<string> ReadRepositoryFileAsync(string relativePath)
{
var directory = new DirectoryInfo(AppContext.BaseDirectory);
while (directory is not null)
{
var candidate = Path.Combine(directory.FullName, relativePath);
if (File.Exists(candidate))
{
return await File.ReadAllTextAsync(candidate);
}
directory = directory.Parent;
}
throw new FileNotFoundException($"Could not locate repository file '{relativePath}'.");
}
}