194 lines
6.3 KiB
C#
194 lines
6.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace IdleSpectator;
|
|
|
|
public sealed class CatalogCoverageDiff
|
|
{
|
|
public string Domain = "";
|
|
public int LiveTotal;
|
|
public int AuthoredTotal;
|
|
public int Missing;
|
|
public int Orphan;
|
|
public readonly List<string> MissingIds = new List<string>();
|
|
public readonly List<string> OrphanIds = new List<string>();
|
|
|
|
public bool Passed => Missing == 0 && Orphan == 0;
|
|
|
|
public string Detail =>
|
|
$"{Domain}: live={LiveTotal} authored={AuthoredTotal} missing={Missing} orphan={Orphan}";
|
|
}
|
|
|
|
/// <summary>Shared live-vs-authored coverage audit used by domain event catalogs.</summary>
|
|
public static class CatalogCoverageAudit
|
|
{
|
|
public static CatalogCoverageDiff Diff(
|
|
string domain,
|
|
IEnumerable<string> liveIds,
|
|
IEnumerable<string> authoredIds)
|
|
{
|
|
var live = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
var authored = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
var diff = new CatalogCoverageDiff { Domain = domain ?? "domain" };
|
|
|
|
if (liveIds != null)
|
|
{
|
|
foreach (string id in liveIds)
|
|
{
|
|
if (string.IsNullOrEmpty(id))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
live.Add(id.Trim());
|
|
}
|
|
}
|
|
|
|
if (authoredIds != null)
|
|
{
|
|
foreach (string id in authoredIds)
|
|
{
|
|
if (string.IsNullOrEmpty(id))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
authored.Add(id.Trim());
|
|
}
|
|
}
|
|
|
|
diff.LiveTotal = live.Count;
|
|
diff.AuthoredTotal = authored.Count;
|
|
|
|
foreach (string id in live)
|
|
{
|
|
if (!authored.Contains(id))
|
|
{
|
|
diff.Missing++;
|
|
diff.MissingIds.Add(id);
|
|
}
|
|
}
|
|
|
|
foreach (string id in authored)
|
|
{
|
|
if (!live.Contains(id))
|
|
{
|
|
diff.Orphan++;
|
|
diff.OrphanIds.Add(id);
|
|
}
|
|
}
|
|
|
|
return diff;
|
|
}
|
|
|
|
public static void WriteReport(string outputDirectory, string fileName, string body)
|
|
{
|
|
if (string.IsNullOrEmpty(outputDirectory) || string.IsNullOrEmpty(fileName))
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
Directory.CreateDirectory(outputDirectory);
|
|
File.WriteAllText(Path.Combine(outputDirectory, fileName), body ?? "");
|
|
}
|
|
catch
|
|
{
|
|
// ignore IO
|
|
}
|
|
}
|
|
}
|
|
|
|
public sealed class DomainEventAuditResult
|
|
{
|
|
public bool Passed;
|
|
public string Detail = "";
|
|
}
|
|
|
|
/// <summary>Coverage audits for relationship discrete events + live plot/era/book libraries.</summary>
|
|
public static class DomainEventHarness
|
|
{
|
|
public static DomainEventAuditResult RunAudit(string outputDirectory)
|
|
{
|
|
var tsv = new StringBuilder();
|
|
tsv.AppendLine("domain\tid\tauthored\towns_camera\tevent_strength\tnotes");
|
|
|
|
CatalogCoverageDiff plots = CatalogCoverageAudit.Diff(
|
|
"plots",
|
|
ActivityAssetCatalog.EnumerateLivePlotIds(),
|
|
PlotInterestCatalog.AuthoredIds);
|
|
AppendLibraryDomain(tsv, "plots", ActivityAssetCatalog.EnumerateLivePlotIds(), plots, PlotInterestCatalog.GetOrFallback);
|
|
|
|
CatalogCoverageDiff eras = CatalogCoverageAudit.Diff(
|
|
"eras",
|
|
ActivityAssetCatalog.EnumerateLiveEraIds(),
|
|
EraInterestCatalog.AuthoredIds);
|
|
AppendLibraryDomain(tsv, "eras", ActivityAssetCatalog.EnumerateLiveEraIds(), eras, EraInterestCatalog.GetOrFallback);
|
|
|
|
CatalogCoverageDiff books = CatalogCoverageAudit.Diff(
|
|
"books",
|
|
ActivityAssetCatalog.EnumerateLiveBookTypeIds(),
|
|
BookInterestCatalog.AuthoredIds);
|
|
AppendLibraryDomain(tsv, "books", ActivityAssetCatalog.EnumerateLiveBookTypeIds(), books, BookInterestCatalog.GetOrFallback);
|
|
|
|
CatalogCoverageDiff traits = CatalogCoverageAudit.Diff(
|
|
"traits",
|
|
ActivityAssetCatalog.EnumerateLiveTraitIds(),
|
|
TraitInterestCatalog.AuthoredIds);
|
|
AppendLibraryDomain(tsv, "traits", ActivityAssetCatalog.EnumerateLiveTraitIds(), traits, TraitInterestCatalog.GetOrFallback);
|
|
|
|
int relMissing = 0;
|
|
int relTotal = 0;
|
|
foreach (string id in RelationshipEventCatalog.AuthoredIds)
|
|
{
|
|
relTotal++;
|
|
DiscreteEventEntry entry = RelationshipEventCatalog.GetOrFallback(id);
|
|
bool ok = RelationshipEventCatalog.HasAuthored(id) && !entry.IsFallback;
|
|
if (!ok)
|
|
{
|
|
relMissing++;
|
|
}
|
|
|
|
tsv.Append("relationship\t").Append(id).Append('\t')
|
|
.Append(ok ? "1" : "0").Append('\t')
|
|
.Append(entry.OwnsCamera).Append('\t')
|
|
.Append(entry.EventStrength.ToString("0.#")).Append('\t')
|
|
.Append(ok ? "ok" : "missing_authored").AppendLine();
|
|
}
|
|
|
|
CatalogCoverageAudit.WriteReport(outputDirectory, "domain_event_audit.tsv", tsv.ToString());
|
|
|
|
bool passed = plots.Passed && eras.Passed && books.Passed && traits.Passed
|
|
&& relMissing == 0 && relTotal > 0;
|
|
string detail =
|
|
$"{plots.Detail}; {eras.Detail}; {books.Detail}; {traits.Detail}; relationship: authored={relTotal} missing={relMissing}";
|
|
return new DomainEventAuditResult { Passed = passed, Detail = detail };
|
|
}
|
|
|
|
private static void AppendLibraryDomain(
|
|
StringBuilder tsv,
|
|
string domain,
|
|
IEnumerable<string> liveIds,
|
|
CatalogCoverageDiff diff,
|
|
Func<string, DiscreteEventEntry> lookup)
|
|
{
|
|
foreach (string id in liveIds)
|
|
{
|
|
DiscreteEventEntry entry = lookup(id);
|
|
bool has = !entry.IsFallback;
|
|
tsv.Append(domain).Append('\t').Append(id).Append('\t')
|
|
.Append(has ? "1" : "0").Append('\t')
|
|
.Append(entry.OwnsCamera).Append('\t')
|
|
.Append(entry.EventStrength.ToString("0.#")).Append('\t')
|
|
.Append(has ? "ok" : "missing_authored").AppendLine();
|
|
}
|
|
|
|
foreach (string id in diff.OrphanIds)
|
|
{
|
|
tsv.Append(domain).Append('\t').Append(id).Append("\t1\t\t0\torphan_authored").AppendLine();
|
|
}
|
|
}
|
|
}
|