Ampr: fix path case on Linux (#750)

This commit is contained in:
999sian
2026-08-02 22:36:00 +01:00
committed by GitHub
parent f36ce4084a
commit 8df4039ca4
7 changed files with 144 additions and 33 deletions
@@ -6,6 +6,9 @@ using Xunit;
namespace SharpEmu.Libs.Tests.Ampr;
// AmprFileRegistry is process-global static state, so the classes that index
// or clear it must not run concurrently with each other.
[Collection("AmprFileRegistry")]
public class AmprFileRegistryTests
{
[Fact]
@@ -62,6 +65,79 @@ public class AmprFileRegistryTests
Assert.Equal(host, d);
}
[Fact]
public void App0_index_cache_keeps_files_that_differ_only_by_case()
{
var root = Path.Combine(Path.GetTempPath(), "sharpemu-ampr-case-" + Guid.NewGuid().ToString("N"));
var cacheDir = Path.Combine(root, "..", "sharpemu-ampr-cache-" + Guid.NewGuid().ToString("N"));
var upper = Path.Combine(root, "data", "ASSET.bin");
var lower = Path.Combine(root, "data", "asset.bin");
var previousCacheDir = Environment.GetEnvironmentVariable("SHARPEMU_AMPR_INDEX_CACHE");
try
{
Directory.CreateDirectory(Path.Combine(root, "sce_sys"));
Directory.CreateDirectory(Path.Combine(root, "data"));
File.WriteAllText(Path.Combine(root, "sce_sys", "param.json"), "{}");
File.WriteAllBytes(upper, [1, 2, 3]);
if (File.Exists(lower))
{
// Case-insensitive host: the two names are one file, so there is
// nothing for an ignore-case index to lose.
return;
}
File.WriteAllBytes(lower, [4, 5, 6]);
Environment.SetEnvironmentVariable("SHARPEMU_AMPR_INDEX_CACHE", cacheDir);
var normalizedRoot = Path.GetFullPath(root);
var expectedUpper = Path.Combine(normalizedRoot, "data", "ASSET.bin");
var expectedLower = Path.Combine(normalizedRoot, "data", "asset.bin");
// Fresh tree walk, which also writes the on-disk index cache.
AmprFileRegistry.ClearForTests();
AmprFileRegistry.EnsureApp0Indexed(root);
AssertResolves(expectedUpper, expectedLower);
// Second boot: served from the cache the walk just wrote.
AmprFileRegistry.ClearForTests();
AmprFileRegistry.EnsureApp0Indexed(root);
AssertResolves(expectedUpper, expectedLower);
}
finally
{
Environment.SetEnvironmentVariable("SHARPEMU_AMPR_INDEX_CACHE", previousCacheDir);
AmprFileRegistry.ClearForTests();
TryDeleteDirectory(cacheDir);
TryDeleteDirectory(root);
}
static void AssertResolves(string expectedUpper, string expectedLower)
{
Assert.True(
AmprFileRegistry.TryGetHostPath(
AmprFileRegistry.ComputeFileId("$/data/ASSET.bin"), out var actualUpper),
"data/ASSET.bin is missing from the app0 index.");
Assert.True(
AmprFileRegistry.TryGetHostPath(
AmprFileRegistry.ComputeFileId("$/data/asset.bin"), out var actualLower),
"data/asset.bin is missing from the app0 index.");
Assert.Equal(expectedUpper, actualUpper);
Assert.Equal(expectedLower, actualLower);
}
}
private static void TryDeleteDirectory(string path)
{
try
{
Directory.Delete(path, recursive: true);
}
catch (Exception)
{
// Temp cleanup is best-effort.
}
}
private static uint FnvUtf8(string text)
{
const uint offset = 2166136261;
@@ -8,6 +8,7 @@ using Xunit;
namespace SharpEmu.Libs.Tests.Ampr;
[Collection("AmprFileRegistry")]
public sealed class AmprWriteAddressTests
{
[Fact]
@@ -9,6 +9,7 @@ using Xunit;
namespace SharpEmu.Libs.Tests.Ampr;
[Collection("AmprFileRegistry")]
public sealed class AprStreamingContractTests
{
[Fact]