Owner direction 2026-09-06: the owner visually accepted all three connected
gates from the plugin-shelf/DAT-icon work — the movable plugin shelf
(Slice A), the DAT icon markup (Slice B), and the retained-UI outline-order
fix (761a7519f). With that gate passed, the Smoke plugin's job as the gate
artifact is done, so it is deleted outright rather than merely hidden:
src/AcDream.Plugins.Smoke/ (SmokePlugin.cs, SmokeIconPanel.cs, csproj, lock
files).
Reference sites cleaned:
- AcDream.slnx: removed the project entry.
- src/AcDream.App/AcDream.App.csproj: removed the Smoke ProjectReference and
the CopySmokePluginToBuildOutput/CopySmokePluginToPublishOutput targets;
the MossTank equivalents are untouched.
- .github/workflows/headless-portability.yml: the Linux package-contract
step no longer asserts a Smoke plugin.dll/plugin.json pair — repointed at
MossTank's, since the step's job was to prove the plugin-copy packaging
mechanism works end to end, not specifically to prove Smoke.
- tests/AcDream.Core.Tests/Plugins/PluginManifestTests.cs: the inline JSON
fixture used Smoke's manifest values as arbitrary test data; swapped for
MossTank's so the parser test still proves the same thing.
- tests/AcDream.App.Tests/Rendering/LinuxPlatformBoundaryTests.cs: the
shipped-plugin-copy shape test counted 4 GetTargetPath targets (Smoke +
MossTank, build + publish); now 2 (MossTank only).
- tests/AcDream.App.Tests/Plugins/AppAutomationSurfaceIconInstalledDatTests.cs:
reworded a doc comment that named the now-deleted SmokeIconPanel.
- README.md, docs/plugin-ui-markup.md: dropped Smoke-specific mentions,
kept the icon markup example/grammar (now citing MossTank's own real
IconSurfaceId).
- docs/plans/2026-09-06-plugin-shelf-and-dat-icons.md: recorded the owner's
2026-09-06 acceptance and the Smoke removal in the review ledger; deleted
the now-moot "before shipment" Smoke-in-release-zip warning.
- docs/reviews/coverage-ledger.md, docs/reviews/findings-ledger.md: left
untouched — both are frozen audit snapshots ("complete for baseline
<hash>"), so their Smoke rows are historical record, not live claims.
- docs/ISSUES.md: left untouched — its Smoke mentions are inside closed
issue #193's historical write-up of a past investigation.
MossTank plugin shelf icon: MossTankPlugin.cs's PluginPanelDescriptor now
sets IconSurfaceId = 0x06002C41 (IconText = "MT" remains the fallback).
Verified against the installed retail DAT with a new InstalledDat-lane test,
tests/AcDream.App.Tests/UI/MossTankIconInstalledDatTests.cs, mirroring
RetailMarkupIconResolverInstalledDatTests's convention: confirms the id is a
real Portal/HighRes RenderSurface and that RetailMarkupIconResolver.ResolveDid
returns a non-zero texture for it.
Verified: dotnet build AcDream.slnx -c Release green; a stale
plugins/AcDream.Plugins.Smoke output folder from a prior build was deleted
and a fresh build does not recreate it. Full App suite: 7,363 passed / 97
skipped / 36 failed (was 7,362/97/36) — the failing set is unchanged and
none are plugin-related; the one new pass is the MossTank DAT-icon test.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
152 lines
5.3 KiB
C#
152 lines
5.3 KiB
C#
namespace AcDream.App.Tests.Rendering;
|
|
|
|
public sealed class LinuxPlatformBoundaryTests
|
|
{
|
|
[Fact]
|
|
public void FramePacingSelectsPlatformWaiterOnlyAtFactoryBoundary()
|
|
{
|
|
string app = AppSourceRoot();
|
|
string controller = File.ReadAllText(Path.Combine(
|
|
app,
|
|
"Rendering",
|
|
"FramePacingController.cs"));
|
|
Assert.Contains(
|
|
"PlatformFramePacingWaiterFactory.ForCurrentProcess()",
|
|
controller,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain(
|
|
"WindowsHighResolutionFramePacingWaiter.Create()",
|
|
controller,
|
|
StringComparison.Ordinal);
|
|
|
|
string[] windowsImports = Directory
|
|
.EnumerateFiles(app, "*.cs", SearchOption.AllDirectories)
|
|
.Where(path => File.ReadAllText(path).Contains(
|
|
"LibraryImport(\"kernel32.dll\"",
|
|
StringComparison.Ordinal))
|
|
.Select(path => Path.GetFileName(path)!)
|
|
.ToArray();
|
|
|
|
Assert.Equal(
|
|
["WindowsHighResolutionFramePacingWaiter.cs"],
|
|
windowsImports);
|
|
}
|
|
|
|
[Fact]
|
|
public void GraphicalFeatureCodeDoesNotResolveWindowsLocalAppData()
|
|
{
|
|
string root = RepositoryRoot();
|
|
string[] productionFiles =
|
|
[
|
|
.. Directory.EnumerateFiles(
|
|
Path.Combine(root, "src", "AcDream.App"),
|
|
"*.cs",
|
|
SearchOption.AllDirectories),
|
|
.. Directory.EnumerateFiles(
|
|
Path.Combine(root, "src", "AcDream.UI.Abstractions"),
|
|
"*.cs",
|
|
SearchOption.AllDirectories),
|
|
];
|
|
|
|
string[] offenders = productionFiles
|
|
.Where(path => File.ReadAllText(path).Contains(
|
|
"LocalApplicationData",
|
|
StringComparison.Ordinal))
|
|
.Select(path => Path.GetRelativePath(root, path))
|
|
.ToArray();
|
|
|
|
Assert.Empty(offenders);
|
|
}
|
|
|
|
[Fact]
|
|
public void OperatingSystemChecksRemainInsidePlatformOwners()
|
|
{
|
|
string app = AppSourceRoot();
|
|
string[] offenders = Directory
|
|
.EnumerateFiles(app, "*.cs", SearchOption.AllDirectories)
|
|
.Where(path => File.ReadAllText(path).Contains(
|
|
"OperatingSystem.Is",
|
|
StringComparison.Ordinal))
|
|
.Where(path =>
|
|
{
|
|
string relative = Path.GetRelativePath(app, path)
|
|
.Replace('\\', '/');
|
|
return !relative.StartsWith(
|
|
"Platform/",
|
|
StringComparison.Ordinal)
|
|
&& relative is not
|
|
"Rendering/FramePacingWaiterFactory.cs"
|
|
&& relative is not
|
|
"Rendering/LinuxMonotonicFramePacingWaiter.cs"
|
|
&& relative is not
|
|
"Rendering/WindowsHighResolutionFramePacingWaiter.cs";
|
|
})
|
|
.Select(path => Path.GetRelativePath(app, path))
|
|
.ToArray();
|
|
|
|
Assert.Empty(offenders);
|
|
}
|
|
|
|
[Fact]
|
|
public void RuntimePlatformGuardHasOneDefinitionAndOneApprovedConsumer()
|
|
{
|
|
string app = AppSourceRoot();
|
|
string[] files = Directory
|
|
.EnumerateFiles(app, "*.cs", SearchOption.AllDirectories)
|
|
.Where(path => File.ReadAllText(path).Contains(
|
|
"RuntimePlatformGuard",
|
|
StringComparison.Ordinal))
|
|
.Select(path => Path.GetRelativePath(app, path).Replace('\\', '/'))
|
|
.OrderBy(static path => path, StringComparer.Ordinal)
|
|
.ToArray();
|
|
|
|
Assert.Equal(
|
|
[
|
|
"Credentials/AppCredentialResolver.cs",
|
|
"Platform/GraphicalHostPlatformServices.cs",
|
|
],
|
|
files);
|
|
}
|
|
|
|
[Fact]
|
|
public void ShippedPluginCopiesUseResolvedTargetPathsForBuildAndPublish()
|
|
{
|
|
string project = File.ReadAllText(Path.Combine(
|
|
AppSourceRoot(),
|
|
"AcDream.App.csproj"));
|
|
|
|
Assert.Contains("$(TargetFramework)", project, StringComparison.Ordinal);
|
|
Assert.Contains("$(RuntimeIdentifier)", project, StringComparison.Ordinal);
|
|
Assert.Contains("$(OutputPath)plugins/", project, StringComparison.Ordinal);
|
|
Assert.Contains("$(PublishDir)plugins/", project, StringComparison.Ordinal);
|
|
Assert.Equal(
|
|
2,
|
|
project.Split("Targets=\"GetTargetPath\"", StringSplitOptions.None)
|
|
.Length - 1);
|
|
Assert.Contains(
|
|
"../AcDream.Plugins.MossTank/mosstank.xml",
|
|
project,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain(
|
|
"/bin/$(Configuration)",
|
|
project,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
private static string AppSourceRoot() =>
|
|
Path.Combine(RepositoryRoot(), "src", "AcDream.App");
|
|
|
|
private static string RepositoryRoot()
|
|
{
|
|
DirectoryInfo? directory = new(AppContext.BaseDirectory);
|
|
while (directory is not null)
|
|
{
|
|
if (File.Exists(Path.Combine(directory.FullName, "AcDream.slnx")))
|
|
return directory.FullName;
|
|
directory = directory.Parent;
|
|
}
|
|
|
|
throw new DirectoryNotFoundException(
|
|
"Could not locate repository root from test output.");
|
|
}
|
|
}
|