Files
MBN_STOCK_WEBVIEW/tests/MBN_STOCK_WEBVIEW.LegacyWeb.Tests/LegacyFirstRunSetupNativeContractTests.cs

288 lines
11 KiB
C#

using System.Xml.Linq;
namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;
public sealed class LegacyFirstRunSetupNativeContractTests
{
private static readonly string RepositoryRoot = FindRepositoryRoot();
private static readonly string AppRoot = Path.Combine(
RepositoryRoot,
"src",
"MBN_STOCK_WEBVIEW.LegacyParityApp");
[Fact]
public void SourceOnlyLaunchShowsOnlyTheNativeFirstRunWindow()
{
var app = File.ReadAllText(Path.Combine(AppRoot, "App.xaml.cs"))
.ReplaceLineEndings("\n");
var sourceOnlyStart = app.IndexOf("#if SOURCE_ONLY_RUNTIME",
StringComparison.Ordinal);
var fullRuntimeStart = app.IndexOf("#else", sourceOnlyStart,
StringComparison.Ordinal);
var runtimeEnd = app.IndexOf("#endif", fullRuntimeStart,
StringComparison.Ordinal);
Assert.True(sourceOnlyStart >= 0);
Assert.True(fullRuntimeStart > sourceOnlyStart);
Assert.True(runtimeEnd > fullRuntimeStart);
var sourceOnly = app[sourceOnlyStart..fullRuntimeStart];
var fullRuntime = app[fullRuntimeStart..runtimeEnd];
Assert.Contains("new FirstRunSetupWindow()", sourceOnly, StringComparison.Ordinal);
Assert.DoesNotContain("new MainWindow()", sourceOnly, StringComparison.Ordinal);
Assert.DoesNotContain(
"DevelopmentLiveLaunchBootstrap.TryApply(",
sourceOnly,
StringComparison.Ordinal);
Assert.Contains("DevelopmentLiveLaunchBootstrap.TryApply(", fullRuntime,
StringComparison.Ordinal);
Assert.Contains("new MainWindow()", fullRuntime, StringComparison.Ordinal);
Assert.DoesNotContain("new FirstRunSetupWindow()", fullRuntime,
StringComparison.Ordinal);
Assert.DoesNotContain(
"new FirstRunSetupWindow(App.IsDevelopmentLiveLaunch",
app,
StringComparison.Ordinal);
}
[Fact]
public void FirstRunUiRequestsOnlyCutsAndTheWholeResFolder()
{
var xaml = XDocument.Load(Path.Combine(
AppRoot,
"FirstRunSetupWindow.xaml"));
XNamespace presentation =
"http://schemas.microsoft.com/winfx/2006/xaml/presentation";
var buttons = xaml.Descendants(presentation + "Button")
.Select(element => element.Attribute("Content")?.Value)
.Where(value => value is not null)
.ToArray();
var source = File.ReadAllText(Path.Combine(
AppRoot,
"FirstRunSetupWindow.xaml"));
Assert.Contains("Cuts 폴더 선택", buttons);
Assert.Contains("Res 폴더 선택", buttons);
Assert.DoesNotContain("INI 파일 선택", source, StringComparison.Ordinal);
Assert.DoesNotContain("비밀번호", source, StringComparison.Ordinal);
Assert.DoesNotContain("포트 입력", source, StringComparison.Ordinal);
Assert.DoesNotContain("해시 입력", source, StringComparison.Ordinal);
}
[Fact]
public void BothFolderSelectionsValidateOnlyCanonicalPaths()
{
var setup = File.ReadAllText(Path.Combine(
AppRoot,
"FirstRunSetupWindow.xaml.cs"));
Assert.Contains(
"LegacyOperatorSettingsFolderKind.Scene",
setup,
StringComparison.Ordinal);
Assert.Contains(
"LegacyOperatorSettingsFolderKind.Resource",
setup,
StringComparison.Ordinal);
Assert.DoesNotContain("MmoneyCoder.ini", setup, StringComparison.Ordinal);
Assert.DoesNotContain("LegacyIniDatabaseOptionsLoader", setup,
StringComparison.Ordinal);
var clearCuts = setup.IndexOf(
"_cutsDirectory = null;",
StringComparison.Ordinal);
var validateCuts = setup.IndexOf(
"LegacyOperatorSettingsFolderKind.Scene",
StringComparison.Ordinal);
var clearResource = setup.IndexOf(
"_resourceDirectory = null;",
StringComparison.Ordinal);
var validateResource = setup.IndexOf(
"LegacyOperatorSettingsFolderKind.Resource",
StringComparison.Ordinal);
Assert.True(clearCuts >= 0);
Assert.True(validateCuts > clearCuts);
Assert.True(clearResource > validateCuts);
Assert.True(validateResource > clearResource);
Assert.Contains(
"Path.GetFileName(cuts),\n" +
" \"Cuts\"",
setup.ReplaceLineEndings("\n"),
StringComparison.Ordinal);
Assert.Contains(
"Path.GetFileName(resource),\n" +
" \"Res\"",
setup.ReplaceLineEndings("\n"),
StringComparison.Ordinal);
}
[Fact]
public void SetupPersistsOnlyTheSelectedPathsWithoutStartingAChildProcess()
{
var setup = File.ReadAllText(Path.Combine(
AppRoot,
"FirstRunSetupWindow.xaml.cs"));
var saveSettings = RequiredIndex(
setup,
"var saved = store.Save(current with");
var saveBinding = RequiredIndex(
setup,
"SaveRuntimeBinding(repositoryRoot, runtimeRoot);");
Assert.True(saveSettings < saveBinding);
Assert.Contains(
"var store = new LegacyOperatorSettingsStore();",
setup,
StringComparison.Ordinal);
Assert.Contains(
"SceneDirectory = cutsDirectory",
setup,
StringComparison.Ordinal);
Assert.Contains(
"ResourceDirectory = resourceDirectory",
setup,
StringComparison.Ordinal);
Assert.Contains(
"Directory.Build.local.props",
setup,
StringComparison.Ordinal);
Assert.Contains(
"File.Move(temporary, destination, overwrite: true);",
setup,
StringComparison.Ordinal);
Assert.DoesNotContain("ProcessStartInfo", setup, StringComparison.Ordinal);
Assert.DoesNotContain("Process.Start", setup, StringComparison.Ordinal);
Assert.DoesNotContain("RunSetupAsync", setup, StringComparison.Ordinal);
Assert.DoesNotContain("powershell.exe", setup, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("dotnet", setup, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("ConfigureDevelopmentLive", setup,
StringComparison.Ordinal);
Assert.DoesNotContain("PinRegisteredK3D", setup, StringComparison.Ordinal);
Assert.DoesNotContain("DatabaseIniPath", setup, StringComparison.Ordinal);
}
[Fact]
public void SourceOnlyBuildEmbedsOnlyItsOwnClonePathForTheLocalBinding()
{
var project = XDocument.Load(Path.Combine(
AppRoot,
"MBN_STOCK_WEBVIEW.LegacyParityApp.csproj"));
var metadata = Assert.Single(project.Descendants("AssemblyMetadata"));
Assert.Equal("SourceRepositoryRoot", metadata.Attribute("Include")?.Value);
Assert.Equal("$(SourceRepositoryRoot)", metadata.Attribute("Value")?.Value);
Assert.Contains(
"'$(LegacyRuntimeAssetsEnabled)' != 'true'",
metadata.Attribute("Condition")?.Value,
StringComparison.Ordinal);
Assert.Contains(
"'$(Configuration)' == 'Debug'",
metadata.Attribute("Condition")?.Value,
StringComparison.Ordinal);
}
[Fact]
public void AutomaticK3dPinningIsPersistentAndCannotApproveAChangedDll()
{
var initializer = File.ReadAllText(Path.Combine(
RepositoryRoot,
"scripts",
"Initialize-ExistingDevelopmentPc.ps1"));
Assert.Contains("[switch] $PinRegisteredK3D", initializer,
StringComparison.Ordinal);
Assert.Contains("[switch] $ReplaceK3DPin", initializer,
StringComparison.Ordinal);
Assert.Contains(
"Join-Path $ConfigurationRoot 'k3d-pins.local.json'",
initializer,
StringComparison.Ordinal);
Assert.Contains(
"$approvedNativeSha256 = $actualNativeHash",
initializer,
StringComparison.Ordinal);
Assert.Contains(
"$approvedInteropSha256 = $actualInteropHash",
initializer,
StringComparison.Ordinal);
Assert.Contains(
"-PinRegisteredK3D cannot be combined with independently",
initializer,
StringComparison.Ordinal);
Assert.Contains(
"Automatic pinning cannot approve a changed DLL.",
initializer,
StringComparison.Ordinal);
Assert.Contains(
"-ReplaceK3DPin cannot be combined with -PinRegisteredK3D.",
initializer,
StringComparison.Ordinal);
Assert.Contains(
"A replacement requires independently supplied native and interop hashes.",
initializer,
StringComparison.Ordinal);
Assert.Contains(
"Write-ProtectedUtf8TextAtomically",
initializer,
StringComparison.Ordinal);
Assert.Contains(
"This is a durable trust anchor, not transactional runtime state.",
initializer,
StringComparison.Ordinal);
Assert.DoesNotContain(
"K3D persistent pin rollback failed:",
initializer,
StringComparison.Ordinal);
var pinPreflight = initializer.LastIndexOf(
"$k3dPinPreflight = Get-K3DPinPreflight",
StringComparison.Ordinal);
var pinWrite = initializer.IndexOf(
"Write-ProtectedUtf8TextAtomically",
pinPreflight,
StringComparison.Ordinal);
var livePreflight = initializer.IndexOf(
"$livePreflight = Get-DevelopmentLivePreflight",
pinWrite,
StringComparison.Ordinal);
Assert.True(pinPreflight >= 0);
Assert.True(pinWrite > pinPreflight);
Assert.True(livePreflight > pinWrite);
Assert.Contains(
"nativeSha256 = $ApprovedNativeHash.ToUpperInvariant()",
initializer,
StringComparison.Ordinal);
Assert.Contains(
"interopSha256 = $ApprovedInteropHash.ToUpperInvariant()",
initializer,
StringComparison.Ordinal);
Assert.Contains(
"Get-VerifiedK3DRegistration -Reports $registrationReports",
initializer,
StringComparison.Ordinal);
Assert.DoesNotContain("Activator.CreateInstance", initializer,
StringComparison.Ordinal);
}
private static string FindRepositoryRoot()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current is not null)
{
if (File.Exists(Path.Combine(current.FullName, "MBN_STOCK_WEBVIEW.sln")))
{
return current.FullName;
}
current = current.Parent;
}
throw new DirectoryNotFoundException("Repository root was not found.");
}
private static int RequiredIndex(string value, string marker)
{
var index = value.IndexOf(marker, StringComparison.Ordinal);
Assert.True(index >= 0, $"Required marker was not found: {marker}");
return index;
}
}