Files
MBN_STOCK_WEBVIEW/tests/MBN_STOCK_WEBVIEW.Playout.Tests/InstalledK3dInteropMetadataTests.cs

144 lines
5.4 KiB
C#

using MBN_STOCK_WEBVIEW.Playout.Diagnostics;
using MBN_STOCK_WEBVIEW.Playout.Interop;
using MBN_STOCK_WEBVIEW.Playout.Registration;
using System.Security.Cryptography;
namespace MBN_STOCK_WEBVIEW.Playout.Tests;
public sealed class InstalledK3dInteropMetadataTests
{
[Fact]
public void ApprovedSha256_RequiresAndDecodesExactly64HexCharacters()
{
var parsed = InstalledK3dInteropMetadata.ParseApprovedSha256(
"0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789ABCDEF");
Assert.Equal(32, parsed.Length);
Assert.Equal(0x01, parsed[0]);
Assert.Equal(0xEF, parsed[^1]);
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde")]
[InlineData(" 123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")]
[InlineData("g123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")]
public void ApprovedSha256_RejectsMissingMalformedOrWhitespaceValues(string? value)
{
Assert.Throws<InstalledK3dInteropMetadataUnavailableException>(
() => InstalledK3dInteropMetadata.ParseApprovedSha256(value));
}
[Fact]
public void ApprovedSha256_RequiresExactContentForEitherBinaryPin()
{
byte[] content = [1, 2, 3, 4];
var approved = Convert.ToHexString(SHA256.HashData(content));
using var matching = new MemoryStream(content);
using var different = new MemoryStream([1, 2, 3, 5]);
InstalledK3dInteropMetadata.ValidateApprovedSha256(matching, approved);
Assert.Throws<InstalledK3dInteropMetadataUnavailableException>(
() => InstalledK3dInteropMetadata.ValidateApprovedSha256(different, approved));
Assert.Equal(
"MBN_STOCK_K3D_NATIVE_SHA256",
InstalledK3dInteropMetadata.ApprovedNativeSha256EnvironmentVariable);
Assert.Equal(
"MBN_STOCK_K3D_INTEROP_SHA256",
InstalledK3dInteropMetadata.ApprovedSha256EnvironmentVariable);
}
[Fact]
public void FileLease_KeepsNativeAndInteropFilesWriteLocked()
{
var directory = Path.Combine(Path.GetTempPath(), $"k3d-lease-{Guid.NewGuid():N}");
Directory.CreateDirectory(directory);
var nativePath = Path.Combine(directory, "native.dll");
var interopPath = Path.Combine(directory, "interop.dll");
File.WriteAllBytes(nativePath, [1]);
File.WriteAllBytes(interopPath, [2]);
InstalledK3dInteropFileLease? lease = null;
try
{
lease = new InstalledK3dInteropFileLease(
new FileStream(nativePath, FileMode.Open, FileAccess.Read, FileShare.Read),
new FileStream(interopPath, FileMode.Open, FileAccess.Read, FileShare.Read));
Assert.Throws<IOException>(() => OpenForWrite(nativePath).Dispose());
Assert.Throws<IOException>(() => OpenForWrite(interopPath).Dispose());
}
finally
{
lease?.InteropStream.Dispose();
lease?.NativeStream.Dispose();
Directory.Delete(directory, recursive: true);
}
}
[Fact]
public void RegisteredPaths_MapOnlyExactX64VendorLayout()
{
const string native = @"C:\Vendor\K3DAsyncEngine\DLL\x64\Release\K3DAsyncEngine.dll";
var paths = InstalledK3dInteropMetadata.ResolveRegisteredPaths(ReadySnapshot(native));
Assert.Equal(Path.GetFullPath(native), paths.NativeBinaryPath);
Assert.Equal(
Path.GetFullPath(
@"C:\Vendor\K3DAsyncEngine\Bin\x64\C#\Interop.K3DAsyncEngineLib.dll"),
paths.InteropAssemblyPath);
}
[Fact]
public void RegisteredPaths_RejectDivergentClassBinary()
{
const string native = @"C:\Vendor\K3DAsyncEngine\DLL\x64\Release\K3DAsyncEngine.dll";
var snapshot = ReadySnapshot(native) with
{
EventHandler = ReadySnapshot(native).EventHandler with
{
InprocServerPath =
@"C:\Other\K3DAsyncEngine\DLL\x64\Release\K3DAsyncEngine.dll"
}
};
Assert.Throws<InstalledK3dInteropMetadataUnavailableException>(
() => InstalledK3dInteropMetadata.ResolveRegisteredPaths(snapshot));
}
[Fact]
public void RegisteredPaths_RejectUnexpectedNativeLayout()
{
const string native = @"C:\Vendor\K3DAsyncEngine\bin\K3DAsyncEngine.dll";
Assert.Throws<InstalledK3dInteropMetadataUnavailableException>(
() => InstalledK3dInteropMetadata.ResolveRegisteredPaths(ReadySnapshot(native)));
}
private static K3dRegistrySnapshot ReadySnapshot(string nativePath) => new(
true,
nativePath,
new K3dClassRegistrationSnapshot(
true,
K3dComConstants.KaEngineProgId,
K3dComConstants.KaEngineClassId,
nativePath,
K3dComConstants.ApartmentThreadingModel,
K3dComConstants.TypeLibraryId),
new K3dClassRegistrationSnapshot(
true,
K3dComConstants.KaEventHandlerProgId,
K3dComConstants.KaEventHandlerClassId,
nativePath,
K3dComConstants.ApartmentThreadingModel,
K3dComConstants.TypeLibraryId),
false);
private static FileStream OpenForWrite(string path) => new(
path,
FileMode.Open,
FileAccess.Write,
FileShare.ReadWrite | FileShare.Delete);
}