mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-06 16:16:44 +08:00
test(core-tests): 收敛函数式与状态测试的低风险 warning
- 补齐 WaitForTask、ResourceManager、State 与 StateMachine 测试中的低风险 ConfigureAwait(false) - 更新 AsyncKeyLock、ResultExtensions、ResultT 与 Pipe 测试中的 culture 和异步等待写法
This commit is contained in:
parent
737d0b5037
commit
b7560fcc08
@ -25,7 +25,7 @@ public sealed class AsyncKeyLockManagerTests
|
||||
using var manager = new AsyncKeyLockManager();
|
||||
|
||||
// Act
|
||||
await using var handle = await manager.AcquireLockAsync("test-key");
|
||||
await using var handle = await manager.AcquireLockAsync("test-key").ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Assert.That(handle, Is.Not.Null);
|
||||
@ -47,13 +47,13 @@ public sealed class AsyncKeyLockManagerTests
|
||||
var index = i;
|
||||
tasks.Add(Task.Run(async () =>
|
||||
{
|
||||
await using var handle = await manager.AcquireLockAsync("same-key");
|
||||
await using var handle = await manager.AcquireLockAsync("same-key").ConfigureAwait(false);
|
||||
executionOrder.Add(index);
|
||||
await Task.Delay(10);
|
||||
await Task.Delay(10).ConfigureAwait(false);
|
||||
}));
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Assert.That(executionOrder.Count, Is.EqualTo(5));
|
||||
@ -75,15 +75,15 @@ public sealed class AsyncKeyLockManagerTests
|
||||
var key = $"key-{i}";
|
||||
tasks.Add(Task.Run(async () =>
|
||||
{
|
||||
await using var handle = await manager.AcquireLockAsync(key);
|
||||
await using var handle = await manager.AcquireLockAsync(key).ConfigureAwait(false);
|
||||
var current = Interlocked.Increment(ref concurrentCount);
|
||||
maxConcurrent = Math.Max(maxConcurrent, current);
|
||||
await Task.Delay(50);
|
||||
await Task.Delay(50).ConfigureAwait(false);
|
||||
Interlocked.Decrement(ref concurrentCount);
|
||||
}));
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Assert.That(maxConcurrent, Is.GreaterThan(1));
|
||||
@ -94,13 +94,13 @@ public sealed class AsyncKeyLockManagerTests
|
||||
{
|
||||
// Arrange
|
||||
using var manager = new AsyncKeyLockManager();
|
||||
var handle = await manager.AcquireLockAsync("test-key");
|
||||
var handle = await manager.AcquireLockAsync("test-key").ConfigureAwait(false);
|
||||
|
||||
// Act
|
||||
await handle.DisposeAsync();
|
||||
await handle.DisposeAsync().ConfigureAwait(false);
|
||||
|
||||
// Assert - 应该能再次获取锁
|
||||
await using var handle2 = await manager.AcquireLockAsync("test-key");
|
||||
await using var handle2 = await manager.AcquireLockAsync("test-key").ConfigureAwait(false);
|
||||
Assert.That(handle2, Is.Not.Null);
|
||||
}
|
||||
|
||||
@ -117,8 +117,8 @@ public sealed class AsyncKeyLockManagerTests
|
||||
var key = $"key-{i % 10}";
|
||||
tasks.Add(Task.Run(async () =>
|
||||
{
|
||||
await using var handle = await manager.AcquireLockAsync(key);
|
||||
await Task.Delay(1);
|
||||
await using var handle = await manager.AcquireLockAsync(key).ConfigureAwait(false);
|
||||
await Task.Delay(1).ConfigureAwait(false);
|
||||
}));
|
||||
}
|
||||
|
||||
@ -139,14 +139,14 @@ public sealed class AsyncKeyLockManagerTests
|
||||
{
|
||||
tasks.Add(Task.Run(async () =>
|
||||
{
|
||||
await using var handle = await manager.AcquireLockAsync("same-key");
|
||||
await using var handle = await manager.AcquireLockAsync("same-key").ConfigureAwait(false);
|
||||
var temp = counter;
|
||||
await Task.Delay(1);
|
||||
await Task.Delay(1).ConfigureAwait(false);
|
||||
counter = temp + 1;
|
||||
}));
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Assert.That(counter, Is.EqualTo(100));
|
||||
@ -161,13 +161,13 @@ public sealed class AsyncKeyLockManagerTests
|
||||
lockTimeout: TimeSpan.FromMilliseconds(200));
|
||||
|
||||
// Act
|
||||
await using (var handle = await manager.AcquireLockAsync("temp-key"))
|
||||
await using (var handle = await manager.AcquireLockAsync("temp-key").ConfigureAwait(false))
|
||||
{
|
||||
// 持有锁
|
||||
}
|
||||
|
||||
// 等待清理
|
||||
await Task.Delay(400);
|
||||
await Task.Delay(400).ConfigureAwait(false);
|
||||
|
||||
var stats = manager.GetStatistics();
|
||||
|
||||
@ -184,10 +184,10 @@ public sealed class AsyncKeyLockManagerTests
|
||||
lockTimeout: TimeSpan.FromMilliseconds(200));
|
||||
|
||||
// Act
|
||||
await using var handle = await manager.AcquireLockAsync("active-key");
|
||||
await using var handle = await manager.AcquireLockAsync("active-key").ConfigureAwait(false);
|
||||
|
||||
// 等待清理尝试
|
||||
await Task.Delay(400);
|
||||
await Task.Delay(400).ConfigureAwait(false);
|
||||
|
||||
var activeLocks = manager.GetActiveLocks();
|
||||
|
||||
@ -202,9 +202,9 @@ public sealed class AsyncKeyLockManagerTests
|
||||
using var manager = new AsyncKeyLockManager();
|
||||
|
||||
// Act
|
||||
await using (await manager.AcquireLockAsync("key1"))
|
||||
await using (await manager.AcquireLockAsync("key1").ConfigureAwait(false))
|
||||
{
|
||||
await using var handle2 = await manager.AcquireLockAsync("key2");
|
||||
await using var handle2 = await manager.AcquireLockAsync("key2").ConfigureAwait(false);
|
||||
var stats = manager.GetStatistics();
|
||||
|
||||
// Assert
|
||||
@ -223,8 +223,8 @@ public sealed class AsyncKeyLockManagerTests
|
||||
using var manager = new AsyncKeyLockManager();
|
||||
|
||||
// Act
|
||||
await using var handle1 = await manager.AcquireLockAsync("key1");
|
||||
await using var handle2 = await manager.AcquireLockAsync("key2");
|
||||
await using var handle1 = await manager.AcquireLockAsync("key1").ConfigureAwait(false);
|
||||
await using var handle2 = await manager.AcquireLockAsync("key2").ConfigureAwait(false);
|
||||
|
||||
var activeLocks = manager.GetActiveLocks();
|
||||
|
||||
@ -254,14 +254,14 @@ public sealed class AsyncKeyLockManagerTests
|
||||
using var cts = new CancellationTokenSource();
|
||||
|
||||
// 先获取锁
|
||||
await using var handle = await manager.AcquireLockAsync("test-key", cts.Token);
|
||||
await using var handle = await manager.AcquireLockAsync("test-key", cts.Token).ConfigureAwait(false);
|
||||
|
||||
// Act
|
||||
await cts.CancelAsync();
|
||||
await cts.CancelAsync().ConfigureAwait(false);
|
||||
|
||||
// Assert
|
||||
Assert.CatchAsync<OperationCanceledException>(async () =>
|
||||
await manager.AcquireLockAsync("test-key", cts.Token));
|
||||
await manager.AcquireLockAsync("test-key", cts.Token).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -295,8 +295,8 @@ public sealed class AsyncKeyLockManagerTests
|
||||
{
|
||||
for (var j = 0; j < 10; j++)
|
||||
{
|
||||
await using var handle = await manager.AcquireLockAsync($"key-{j % 5}");
|
||||
await Task.Delay(10);
|
||||
await using var handle = await manager.AcquireLockAsync($"key-{j % 5}").ConfigureAwait(false);
|
||||
await Task.Delay(10).ConfigureAwait(false);
|
||||
}
|
||||
}));
|
||||
}
|
||||
@ -324,11 +324,11 @@ public sealed class AsyncKeyLockManagerTests
|
||||
{
|
||||
// Arrange
|
||||
using var manager = new AsyncKeyLockManager();
|
||||
var handle = await manager.AcquireLockAsync("test-key");
|
||||
var handle = await manager.AcquireLockAsync("test-key").ConfigureAwait(false);
|
||||
|
||||
// Act
|
||||
await handle.DisposeAsync();
|
||||
await handle.DisposeAsync();
|
||||
await handle.DisposeAsync().ConfigureAwait(false);
|
||||
await handle.DisposeAsync().ConfigureAwait(false);
|
||||
handle.Dispose();
|
||||
|
||||
// Assert - 不应该抛出异常
|
||||
|
||||
@ -284,13 +284,13 @@ public class WaitForTaskTests
|
||||
var expectedValue = 123;
|
||||
var task = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(50);
|
||||
await Task.Delay(50).ConfigureAwait(false);
|
||||
return expectedValue;
|
||||
});
|
||||
|
||||
var wait = new WaitForTask<int>(task);
|
||||
|
||||
await task;
|
||||
await task.ConfigureAwait(false);
|
||||
|
||||
Task.Delay(100).Wait();
|
||||
|
||||
@ -313,4 +313,4 @@ public class WaitForTaskTests
|
||||
|
||||
Assert.That(wait.IsDone, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Globalization;
|
||||
using GFramework.Core.Functional;
|
||||
|
||||
namespace GFramework.Core.Tests.Extensions;
|
||||
@ -122,7 +123,7 @@ public class ResultExtensionsTests
|
||||
public void Map_Should_Transform_Success_Value()
|
||||
{
|
||||
var result = Result<int>.Succeed(42);
|
||||
var mapped = result.Map(x => x.ToString());
|
||||
var mapped = result.Map(x => x.ToString(CultureInfo.InvariantCulture));
|
||||
Assert.That(mapped.IsSuccess, Is.True);
|
||||
Assert.That(mapped.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42"));
|
||||
}
|
||||
@ -135,7 +136,7 @@ public class ResultExtensionsTests
|
||||
{
|
||||
var exception = new Exception("Error");
|
||||
var result = Result<int>.Fail(exception);
|
||||
var mapped = result.Map(x => x.ToString());
|
||||
var mapped = result.Map(x => x.ToString(CultureInfo.InvariantCulture));
|
||||
Assert.That(mapped.IsFaulted, Is.True);
|
||||
Assert.That(mapped.Exception, Is.SameAs(exception));
|
||||
}
|
||||
@ -157,7 +158,7 @@ public class ResultExtensionsTests
|
||||
public void Bind_Should_Chain_Success_Results()
|
||||
{
|
||||
var result = Result<int>.Succeed(42);
|
||||
var bound = result.Bind(x => Result<string>.Succeed(x.ToString()));
|
||||
var bound = result.Bind(x => Result<string>.Succeed(x.ToString(CultureInfo.InvariantCulture)));
|
||||
Assert.That(bound.IsSuccess, Is.True);
|
||||
Assert.That(bound.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42"));
|
||||
}
|
||||
@ -170,7 +171,7 @@ public class ResultExtensionsTests
|
||||
{
|
||||
var exception = new Exception("Error");
|
||||
var result = Result<int>.Fail(exception);
|
||||
var bound = result.Bind(x => Result<string>.Succeed(x.ToString()));
|
||||
var bound = result.Bind(x => Result<string>.Succeed(x.ToString(CultureInfo.InvariantCulture)));
|
||||
Assert.That(bound.IsFaulted, Is.True);
|
||||
Assert.That(bound.Exception, Is.SameAs(exception));
|
||||
}
|
||||
@ -449,9 +450,9 @@ public class ResultExtensionsTests
|
||||
{
|
||||
var result = await ResultExtensions.TryAsync(async () =>
|
||||
{
|
||||
await Task.Delay(1);
|
||||
await Task.Delay(1).ConfigureAwait(false);
|
||||
return 42;
|
||||
});
|
||||
}).ConfigureAwait(false);
|
||||
Assert.That(result.IsSuccess, Is.True);
|
||||
Assert.That(result.Match(succ: v => v, fail: _ => 0), Is.EqualTo(42));
|
||||
}
|
||||
@ -464,9 +465,9 @@ public class ResultExtensionsTests
|
||||
{
|
||||
var result = await ResultExtensions.TryAsync<int>(async () =>
|
||||
{
|
||||
await Task.Delay(1);
|
||||
await Task.Delay(1).ConfigureAwait(false);
|
||||
throw new InvalidOperationException("Error");
|
||||
});
|
||||
}).ConfigureAwait(false);
|
||||
Assert.That(result.IsFaulted, Is.True);
|
||||
Assert.That(result.Exception, Is.TypeOf<InvalidOperationException>());
|
||||
}
|
||||
@ -477,7 +478,8 @@ public class ResultExtensionsTests
|
||||
[Test]
|
||||
public async Task TryAsync_Should_Handle_Synchronous_Exceptions()
|
||||
{
|
||||
var result = await ResultExtensions.TryAsync<int>(() => throw new InvalidOperationException("Sync error"));
|
||||
var result = await ResultExtensions.TryAsync<int>(() => throw new InvalidOperationException("Sync error"))
|
||||
.ConfigureAwait(false);
|
||||
Assert.That(result.IsFaulted, Is.True);
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using GFramework.Core.Functional.Pipe;
|
||||
using NUnit.Framework;
|
||||
|
||||
@ -123,7 +124,7 @@ public class PipeExtensionsTests
|
||||
var result = value
|
||||
.Pipe(x => x * 2)
|
||||
.Pipe(x => x + 10)
|
||||
.Pipe(x => x.ToString());
|
||||
.Pipe(x => x.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("20"));
|
||||
@ -139,7 +140,7 @@ public class PipeExtensionsTests
|
||||
var value = 42;
|
||||
|
||||
// Act
|
||||
var result = value.Let(x => x.ToString());
|
||||
var result = value.Let(x => x.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("42"));
|
||||
@ -171,7 +172,7 @@ public class PipeExtensionsTests
|
||||
var result = value.Let(s => new
|
||||
{
|
||||
Original = s,
|
||||
Upper = s.ToUpper(),
|
||||
Upper = s.ToUpperInvariant(),
|
||||
Length = s.Length
|
||||
});
|
||||
|
||||
@ -280,4 +281,4 @@ public class PipeExtensionsTests
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("Large: 20"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Globalization;
|
||||
using GFramework.Core.Functional;
|
||||
using NUnit.Framework;
|
||||
|
||||
@ -314,7 +315,7 @@ public class ResultTTests
|
||||
public void Map_Should_Transform_Value_When_Success()
|
||||
{
|
||||
var result = Result<int>.Succeed(42);
|
||||
var mapped = result.Map(x => x.ToString());
|
||||
var mapped = result.Map(x => x.ToString(CultureInfo.InvariantCulture));
|
||||
Assert.That(mapped.IsSuccess, Is.True);
|
||||
Assert.That(mapped.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42"));
|
||||
}
|
||||
@ -327,7 +328,7 @@ public class ResultTTests
|
||||
{
|
||||
var exception = new Exception("Error");
|
||||
var result = Result<int>.Fail(exception);
|
||||
var mapped = result.Map(x => x.ToString());
|
||||
var mapped = result.Map(x => x.ToString(CultureInfo.InvariantCulture));
|
||||
Assert.That(mapped.IsFaulted, Is.True);
|
||||
Assert.That(mapped.Exception, Is.SameAs(exception));
|
||||
}
|
||||
@ -360,7 +361,7 @@ public class ResultTTests
|
||||
public void Bind_Should_Chain_Success_Results()
|
||||
{
|
||||
var result = Result<int>.Succeed(42);
|
||||
var bound = result.Bind(x => Result<string>.Succeed(x.ToString()));
|
||||
var bound = result.Bind(x => Result<string>.Succeed(x.ToString(CultureInfo.InvariantCulture)));
|
||||
Assert.That(bound.IsSuccess, Is.True);
|
||||
Assert.That(bound.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42"));
|
||||
}
|
||||
@ -373,7 +374,7 @@ public class ResultTTests
|
||||
{
|
||||
var exception = new Exception("Error");
|
||||
var result = Result<int>.Fail(exception);
|
||||
var bound = result.Bind(x => Result<string>.Succeed(x.ToString()));
|
||||
var bound = result.Bind(x => Result<string>.Succeed(x.ToString(CultureInfo.InvariantCulture)));
|
||||
Assert.That(bound.IsFaulted, Is.True);
|
||||
Assert.That(bound.Exception, Is.SameAs(exception));
|
||||
}
|
||||
@ -414,7 +415,7 @@ public class ResultTTests
|
||||
var mapped = await result.MapAsync(async x =>
|
||||
{
|
||||
await Task.Delay(1);
|
||||
return x.ToString();
|
||||
return x.ToString(CultureInfo.InvariantCulture);
|
||||
});
|
||||
Assert.That(mapped.IsSuccess, Is.True);
|
||||
Assert.That(mapped.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42"));
|
||||
@ -431,7 +432,7 @@ public class ResultTTests
|
||||
var mapped = await result.MapAsync(async x =>
|
||||
{
|
||||
await Task.Delay(1);
|
||||
return x.ToString();
|
||||
return x.ToString(CultureInfo.InvariantCulture);
|
||||
});
|
||||
Assert.That(mapped.IsFaulted, Is.True);
|
||||
Assert.That(mapped.Exception, Is.SameAs(exception));
|
||||
@ -804,4 +805,4 @@ public class ResultTTests
|
||||
var bottom2 = Result<int>.Bottom;
|
||||
Assert.That(bottom1.Equals(bottom2), Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ public class TestResourceLoader : IResourceLoader<TestResource>
|
||||
|
||||
public async Task<TestResource> LoadAsync(string path)
|
||||
{
|
||||
await Task.Delay(10); // 模拟异步加载
|
||||
await Task.Delay(10).ConfigureAwait(false); // 模拟异步加载
|
||||
return Load(path);
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ public class ResourceManagerTests
|
||||
[Test]
|
||||
public async Task LoadAsync_Should_Load_Resource()
|
||||
{
|
||||
var resource = await _resourceManager.LoadAsync<TestResource>("test/resource1.txt");
|
||||
var resource = await _resourceManager.LoadAsync<TestResource>("test/resource1.txt").ConfigureAwait(false);
|
||||
|
||||
Assert.That(resource, Is.Not.Null);
|
||||
Assert.That(resource!.Content, Is.EqualTo("Content 1"));
|
||||
@ -404,4 +404,4 @@ public class ResourceManagerTests
|
||||
handle2!.Dispose();
|
||||
Assert.That(_resourceManager.IsLoaded("test/resource2.txt"), Is.False);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -525,7 +525,7 @@ public sealed class TestAsyncState : IState, IAsyncState
|
||||
/// <param name="from">从哪个状态进入</param>
|
||||
public async Task OnEnterAsync(IState? from)
|
||||
{
|
||||
await Task.Delay(1);
|
||||
await Task.Delay(1).ConfigureAwait(false);
|
||||
EnterCalled = true;
|
||||
EnterCallCount++;
|
||||
EnterFrom = from;
|
||||
@ -537,7 +537,7 @@ public sealed class TestAsyncState : IState, IAsyncState
|
||||
/// <param name="to">离开到哪个状态</param>
|
||||
public async Task OnExitAsync(IState? to)
|
||||
{
|
||||
await Task.Delay(1);
|
||||
await Task.Delay(1).ConfigureAwait(false);
|
||||
ExitCalled = true;
|
||||
ExitCallCount++;
|
||||
ExitTo = to;
|
||||
@ -550,7 +550,7 @@ public sealed class TestAsyncState : IState, IAsyncState
|
||||
/// <returns>是否允许转换</returns>
|
||||
public async Task<bool> CanTransitionToAsync(IState target)
|
||||
{
|
||||
await Task.Delay(1);
|
||||
await Task.Delay(1).ConfigureAwait(false);
|
||||
CanTransitionToCallCount++;
|
||||
return AllowTransition;
|
||||
}
|
||||
|
||||
@ -674,7 +674,7 @@ public sealed class ConcreteAsyncStateV2 : IState, IAsyncState
|
||||
/// <param name="from">从哪个状态进入</param>
|
||||
public async Task OnEnterAsync(IState? from)
|
||||
{
|
||||
await Task.Delay(1);
|
||||
await Task.Delay(1).ConfigureAwait(false);
|
||||
EnterCalled = true;
|
||||
EnterCallCount++;
|
||||
EnterFrom = from;
|
||||
@ -686,7 +686,7 @@ public sealed class ConcreteAsyncStateV2 : IState, IAsyncState
|
||||
/// <param name="to">退出到哪个状态</param>
|
||||
public async Task OnExitAsync(IState? to)
|
||||
{
|
||||
await Task.Delay(1);
|
||||
await Task.Delay(1).ConfigureAwait(false);
|
||||
ExitCalled = true;
|
||||
ExitCallCount++;
|
||||
ExitTo = to;
|
||||
@ -699,7 +699,7 @@ public sealed class ConcreteAsyncStateV2 : IState, IAsyncState
|
||||
/// <returns>如果可以转换则返回true,否则返回false</returns>
|
||||
public async Task<bool> CanTransitionToAsync(IState target)
|
||||
{
|
||||
await Task.Delay(1);
|
||||
await Task.Delay(1).ConfigureAwait(false);
|
||||
CanTransitionToAsyncAction?.Invoke(target);
|
||||
return AllowTransitions;
|
||||
}
|
||||
@ -731,4 +731,4 @@ public sealed class ConcreteAsyncStateV2 : IState, IAsyncState
|
||||
{
|
||||
throw new InvalidOperationException("Sync CanTransitionTo should not be called for async state");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user