Files
LlamaCasty/ytLive.Tests/AssemblyIdentityTests.cs
T
gramps abfab25685 build: the exe is LlamaCasty.exe, and the publish script proves the artifact
Renames AssemblyName to LlamaCasty before the first Steam depot — Steamworks is explicit
that renaming a live exe is painful, so this had to land first, not later.

Four assembly-qualified pack URIs carried the old name, not three: MainWindow (window
icon), OverlayHost (logo), RenameRecordingDialog and KeepBroadcastDialog. Pack URIs
resolve by assembly name at runtime, so a stale one compiles, passes every test and then
silently renders nothing the first time that view opens. AssemblyIdentityTests guards
both halves — the assembly name, and no source XAML still naming the legacy assembly.
Packaging/Package.appxmanifest and package-msix.sh carry the exe name too.

scripts/publish.sh replaces the by-hand publish: single-file win-x64, ReadyToRun,
ffmpeg beside the exe, and it refuses to finish if ffmpeg, LICENSE, PRIVACY.md or
THIRD-PARTY-NOTICES.txt are missing, or if a test assembly leaked in.

That last guard exists because the first publish was wrong in a way no test could see:
PublishSingleFile + IncludeNativeLibrariesForSelfExtract bundled the libav*.dll family
into the exe — a 9-file output with no ffmpeg folder and a 182 MB binary, so the locator
would have found nothing at runtime. ExcludeFromSingleFile="true" on the content keeps
the folder a folder. Diffing against a control publish without the single-file flags
found it; guessing at item globs wasted two attempts first (recorded in MyMistakes.md).

Measured: 127 MB exe + 129 MB ffmpeg = 257 MB depot. Tests: AssemblyIdentity,
StorePackaging, BuildStamp, BundledFonts all pass; app builds with 0 warnings.
2026-11-01 07:01:50 -08:00

72 lines
3.2 KiB
C#

using System;
using System.IO;
using System.Linq;
using Xunit;
namespace ytLive.Tests;
/// <summary>
/// The shipped binary is <c>LlamaCasty.exe</c> (renamed 2026-11-01, before the first Steam
/// depot). Two things have to agree for that to be true, and neither fails the build when it
/// doesn't:
///
/// <list type="number">
/// <item>The assembly name comes from <c>ytLive.csproj</c> and silently reverting it produces
/// <c>ytLive.exe</c> again — which is why the rename lands before a depot upload rather than
/// after (Steamworks: renaming a live exe is painful).</item>
/// <item>Assembly-qualified WPF pack URIs (<c>/Assembly;component/path</c>) resolve by that
/// same name. A stale <c>/ytLive;component/…</c> compiles, runs, and then fails <b>silently</b>
/// the moment that particular view opens — a blank window icon, a missing logo in the overlay
/// host. Nobody notices until a dialog is opened at the wrong time, so the rename is exactly the
/// kind of change that needs a source-level guard.</item>
/// </list>
///
/// <para>The C# namespaces stay <c>ytLive</c>: they are not user-visible, and the file churn
/// would buy nothing. Only the assembly name and the URIs that quote it move.</para>
/// </summary>
public class AssemblyIdentityTests
{
private const string ShipName = "LlamaCasty";
private const string LegacyName = "ytLive";
[Fact]
public void The_assembly_is_LlamaCasty_and_no_pack_uri_still_names_the_legacy_assembly()
{
Assert.Equal(ShipName, typeof(MainWindow).Assembly.GetName().Name);
var root = RepoRoot();
var stale = Directory.EnumerateFiles(root, "*.xaml", SearchOption.AllDirectories)
.Where(path => !IsBuildOutput(path))
.Where(path => File.ReadAllText(path).Contains("/" + LegacyName + ";component/", StringComparison.Ordinal))
.Select(path => Path.GetRelativePath(root, path))
.ToArray();
Assert.True(stale.Length == 0,
"These XAML files still point at the legacy assembly name in a pack URI, which " +
"fails silently at runtime: " + string.Join(", ", stale));
}
/// <summary>Walks up from the test output directory to the repo root (the folder holding
/// <c>ytLive.csproj</c>).</summary>
private static string RepoRoot()
{
var dir = new DirectoryInfo(AppContext.BaseDirectory);
while (dir != null)
{
if (File.Exists(Path.Combine(dir.FullName, "ytLive.csproj"))) return dir.FullName;
dir = dir.Parent;
}
throw new InvalidOperationException("Could not locate the repo root from " + AppContext.BaseDirectory);
}
/// <summary>Publish and compile output carry copies of the XAML (and old generated XAML);
/// only the source tree is the thing under test.</summary>
private static bool IsBuildOutput(string path)
{
var parts = path.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
return parts.Any(part => part.Equals("bin", StringComparison.OrdinalIgnoreCase)
|| part.Equals("obj", StringComparison.OrdinalIgnoreCase)
|| part.Equals("artifacts", StringComparison.OrdinalIgnoreCase));
}
}