修复测试程序集编译兼容性

This commit is contained in:
JSD\13999
2026-05-18 14:56:10 +08:00
parent 686dec326e
commit 210715d0cd
7 changed files with 109 additions and 23 deletions

View File

@@ -45,35 +45,35 @@ namespace FlowScope.Tests.EditMode.Config
}
[Test]
public void LoadAllAsync_DuplicateId_ThrowsWithId()
public async Task LoadAllAsync_DuplicateId_ThrowsWithId()
{
var provider = new JsonConfigProvider(new[]
{
JsonConfigProvider.Mapping<WeaponConfig>("weapons.json", _ => Task.FromResult("[{\"id\":101,\"name\":\"Axe\"},{\"id\":101,\"name\":\"Sword\"}]"))
});
var exception = Assert.ThrowsAsync<InvalidOperationException>(
var exception = await ThrowsAsync<InvalidOperationException>(
async () => await provider.LoadAllAsync(CancellationToken.None));
Assert.That(exception.Message, Does.Contain("101"));
}
[Test]
public void LoadAllAsync_MalformedJson_ThrowsWithFileName()
public async Task LoadAllAsync_MalformedJson_ThrowsWithFileName()
{
var provider = new JsonConfigProvider(new[]
{
JsonConfigProvider.Mapping<WeaponConfig>("weapons.json", _ => Task.FromResult("[{\"id\":101"))
});
var exception = Assert.ThrowsAsync<InvalidOperationException>(
var exception = await ThrowsAsync<InvalidOperationException>(
async () => await provider.LoadAllAsync(CancellationToken.None));
Assert.That(exception.Message, Does.Contain("weapons.json"));
}
[Test]
public void LoadAllAsync_CanceledToken_ThrowsOperationCanceledException()
public async Task LoadAllAsync_CanceledToken_ThrowsOperationCanceledException()
{
using var cts = new CancellationTokenSource();
cts.Cancel();
@@ -82,10 +82,26 @@ namespace FlowScope.Tests.EditMode.Config
JsonConfigProvider.Mapping<WeaponConfig>("weapons.json", _ => Task.FromResult("[]"))
});
Assert.ThrowsAsync<OperationCanceledException>(
await ThrowsAsync<OperationCanceledException>(
async () => await provider.LoadAllAsync(cts.Token));
}
private static async Task<TException> ThrowsAsync<TException>(Func<Task> action)
where TException : Exception
{
try
{
await action();
}
catch (TException exception)
{
return exception;
}
Assert.Fail($"Expected {typeof(TException).Name}.");
return null;
}
private sealed class WeaponConfig : IConfigRow
{
public int id;

View File

@@ -59,13 +59,13 @@ namespace FlowScope.Tests.EditMode.Flow
}
[Test]
public void StartupAsync_WhenFeatureLoadFails_CleansCreatedFeatureAndReturnsIdle()
public async Task StartupAsync_WhenFeatureLoadFails_CleansCreatedFeatureAndReturnsIdle()
{
var services = new TestServices();
var root = services.CreateRoot();
var flow = new GameFlow();
Assert.ThrowsAsync<InvalidOperationException>(
await ThrowsAsync<InvalidOperationException>(
async () => await flow.StartupAsync<FailingLoadFeature>(root, CancellationToken.None));
Assert.That(flow.State, Is.EqualTo(GameFlowState.Idle));
@@ -81,7 +81,7 @@ namespace FlowScope.Tests.EditMode.Flow
var flow = new GameFlow();
await flow.StartupAsync<FirstFeature>(root, CancellationToken.None);
Assert.ThrowsAsync<InvalidOperationException>(
await ThrowsAsync<InvalidOperationException>(
async () => await flow.SwitchToAsync<FailingEnterFeature>(CancellationToken.None));
Assert.That(flow.State, Is.EqualTo(GameFlowState.NoActiveFeature));
@@ -91,11 +91,11 @@ namespace FlowScope.Tests.EditMode.Flow
}
[Test]
public void SwitchToAsync_WhenIdle_ThrowsWithOperationAndCurrentState()
public async Task SwitchToAsync_WhenIdle_ThrowsWithOperationAndCurrentState()
{
var flow = new GameFlow();
var exception = Assert.ThrowsAsync<InvalidOperationException>(
var exception = await ThrowsAsync<InvalidOperationException>(
async () => await flow.SwitchToAsync<FirstFeature>(CancellationToken.None));
Assert.That(exception.Message, Does.Contain(nameof(GameFlow.SwitchToAsync)));
@@ -126,7 +126,7 @@ namespace FlowScope.Tests.EditMode.Flow
using var cts = new CancellationTokenSource();
cts.Cancel();
Assert.ThrowsAsync<OperationCanceledException>(
await ThrowsAsync<OperationCanceledException>(
async () => await flow.ShutdownAsync(cts.Token));
Assert.That(flow.State, Is.EqualTo(GameFlowState.Disposed));
@@ -134,6 +134,22 @@ namespace FlowScope.Tests.EditMode.Flow
Assert.That(services.Resource.Groups[0].IsDisposed, Is.True);
}
private static async Task<TException> ThrowsAsync<TException>(Func<Task> action)
where TException : Exception
{
try
{
await action();
}
catch (TException exception)
{
return exception;
}
Assert.Fail($"Expected {typeof(TException).Name}.");
return null;
}
private sealed class TestServices
{
public TestConfigProvider Config { get; } = new();

View File

@@ -10,8 +10,11 @@
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"overrideReferences": true,
"precompiledReferences": [
"R3.dll",
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],

View File

@@ -61,27 +61,43 @@ namespace FlowScope.Tests.EditMode.Save
}
[Test]
public void SaveAsync_WriteFailure_ThrowsWithKey()
public async Task SaveAsync_WriteFailure_ThrowsWithKey()
{
var service = new SaveService(new FailingWriteStorage(), new JsonSaveSerializer());
var exception = Assert.ThrowsAsync<InvalidOperationException>(
var exception = await ThrowsAsync<InvalidOperationException>(
async () => await service.SaveAsync("player", new PlayerData(), CancellationToken.None));
Assert.That(exception.Message, Does.Contain("player"));
}
[Test]
public void SaveAsync_CanceledToken_ThrowsOperationCanceledException()
public async Task SaveAsync_CanceledToken_ThrowsOperationCanceledException()
{
using var cts = new CancellationTokenSource();
cts.Cancel();
var service = new SaveService(new MemorySaveStorage(), new JsonSaveSerializer());
Assert.ThrowsAsync<OperationCanceledException>(
await ThrowsAsync<OperationCanceledException>(
async () => await service.SaveAsync("player", new PlayerData(), cts.Token));
}
private static async Task<TException> ThrowsAsync<TException>(Func<Task> action)
where TException : Exception
{
try
{
await action();
}
catch (TException exception)
{
return exception;
}
Assert.Fail($"Expected {typeof(TException).Name}.");
return null;
}
private sealed class PlayerData
{
public ReactiveProperty<int> Gold { get; } = new(0);

View File

@@ -9,8 +9,11 @@
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"overrideReferences": true,
"precompiledReferences": [
"R3.dll",
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],

View File

@@ -39,19 +39,35 @@ namespace FlowScope.Tests.PlayMode.Resources
}
[Test]
public void LoadAsync_WhenBackendFails_IncludesKeyAndBackend()
public async Task LoadAsync_WhenBackendFails_IncludesKeyAndBackend()
{
var service = new AddressablesResourceService(
(_, _, _) => throw new InvalidOperationException("missing"),
(_, _) => { });
var exception = Assert.ThrowsAsync<InvalidOperationException>(
var exception = await ThrowsAsync<InvalidOperationException>(
() => service.LoadAsync<TestAsset>("missing-key", CancellationToken.None));
StringAssert.Contains("missing-key", exception.Message);
StringAssert.Contains("Addressables", exception.Message);
}
private static async Task<TException> ThrowsAsync<TException>(Func<Task> action)
where TException : Exception
{
try
{
await action();
}
catch (TException exception)
{
return exception;
}
Assert.Fail($"Expected {typeof(TException).Name}.");
return null;
}
private sealed class TestAsset
{
}

View File

@@ -154,7 +154,7 @@ namespace FlowScope.Tests.PlayMode.UI
var manager = new UIManager(resources);
manager.RegisterLayer("popup", canvas, 0);
Assert.ThrowsAsync<InvalidOperationException>(
await ThrowsAsync<InvalidOperationException>(
() => manager.OpenAsync<ThrowingBindPanel, TestViewModel>(new TestViewModel("boom"), CancellationToken.None));
Assert.That(resources.Handles[0].IsDisposed, Is.True);
@@ -169,6 +169,22 @@ namespace FlowScope.Tests.PlayMode.UI
return gameObject.AddComponent<Canvas>();
}
private static async Task<TException> ThrowsAsync<TException>(Func<Task> action)
where TException : Exception
{
try
{
await action();
}
catch (TException exception)
{
return exception;
}
Assert.Fail($"Expected {typeof(TException).Name}.");
return null;
}
private GameObject CreatePrefab<TPanel>(string name)
where TPanel : Component
{