AyCode.Core/AyCode.Services.Server.Tests/InvokeMethodExtensionTests.cs

122 lines
4.8 KiB
C#

using AyCode.Core.Tests.TestModels;
using AyCode.Services.Server.SignalRs;
using AyCode.Services.Server.Tests.SignalRs;
namespace AyCode.Services.Server.Tests;
[TestClass]
public class InvokeMethodExtensionTests
{
#region InvokeMethod Unit Tests
[TestMethod]
public void InvokeMethod_SyncMethod_ReturnsValue()
{
var service = new TestSignalRService2();
var methodInfo = typeof(TestSignalRService2).GetMethod("HandleSingleInt")!;
var result = methodInfo.InvokeMethod(service, 42);
Assert.AreEqual("42", result);
}
[TestMethod]
public void InvokeMethod_AsyncTaskTMethod_ReturnsUnwrappedValue()
{
var service = new TestSignalRService2();
var methodInfo = typeof(TestSignalRService2).GetMethod("HandleAsyncString")!;
var result = methodInfo.InvokeMethod(service, "Test");
Assert.IsNotNull(result, "InvokeMethod should unwrap Task<T> and return the result");
Assert.AreEqual("Async: Test", result);
}
[TestMethod]
public void InvokeMethod_AsyncTaskTMethod_WithComplexObject_ReturnsUnwrappedValue()
{
var service = new TestSignalRService2();
var methodInfo = typeof(TestSignalRService2).GetMethod("HandleAsyncTestOrderItem")!;
var input = new TestOrderItem { Id = 1, ProductName = "Widget", Quantity = 5, UnitPrice = 10m };
var result = methodInfo.InvokeMethod(service, input);
Assert.IsNotNull(result, "InvokeMethod should unwrap Task<TestOrderItem> and return the result");
Assert.IsInstanceOfType(result, typeof(TestOrderItem));
var item = (TestOrderItem)result;
Assert.AreEqual("Async: Widget", item.ProductName);
Assert.AreEqual(15, item.Quantity);
}
[TestMethod]
public void InvokeMethod_AsyncTaskTMethod_WithInt_ReturnsUnwrappedValue()
{
var service = new TestSignalRService2();
var methodInfo = typeof(TestSignalRService2).GetMethod("HandleAsyncInt")!;
var result = methodInfo.InvokeMethod(service, 42);
Assert.IsNotNull(result, "InvokeMethod should unwrap Task<int> and return the result");
Assert.AreEqual(84, result);
}
/// <summary>
/// CRITICAL: Tests Task.FromResult() - methods returning Task without async keyword.
/// This was the root cause of the production bug where Task wrapper was serialized.
/// </summary>
[TestMethod]
public void InvokeMethod_TaskFromResult_ReturnsUnwrappedValue()
{
var service = new TestSignalRService2();
var methodInfo = typeof(TestSignalRService2).GetMethod("HandleTaskFromResultString")!;
var result = methodInfo.InvokeMethod(service, "Test");
Assert.IsNotNull(result, "InvokeMethod should unwrap Task.FromResult<T> and return the result");
Assert.AreEqual("FromResult: Test", result);
}
[TestMethod]
public void InvokeMethod_TaskFromResult_WithComplexObject_ReturnsUnwrappedValue()
{
var service = new TestSignalRService2();
var methodInfo = typeof(TestSignalRService2).GetMethod("HandleTaskFromResultTestOrderItem")!;
var input = new TestOrderItem { Id = 1, ProductName = "Widget", Quantity = 5, UnitPrice = 10m };
var result = methodInfo.InvokeMethod(service, input);
Assert.IsNotNull(result, "InvokeMethod should unwrap Task.FromResult<TestOrderItem> and return the result");
Assert.IsInstanceOfType(result, typeof(TestOrderItem));
var item = (TestOrderItem)result;
Assert.AreEqual("FromResult: Widget", item.ProductName);
Assert.AreEqual(10, item.Quantity); // Doubled
}
[TestMethod]
public void InvokeMethod_TaskFromResult_WithInt_ReturnsUnwrappedValue()
{
var service = new TestSignalRService2();
var methodInfo = typeof(TestSignalRService2).GetMethod("HandleTaskFromResultInt")!;
var result = methodInfo.InvokeMethod(service, 42);
Assert.IsNotNull(result, "InvokeMethod should unwrap Task.FromResult<int> and return the result");
Assert.AreEqual(84, result);
}
[TestMethod]
public void InvokeMethod_NonGenericTask_ReturnsNull()
{
var service = new TestSignalRService2();
var methodInfo = typeof(TestSignalRService2).GetMethod("HandleTaskFromResultNoParams")!;
var result = methodInfo.InvokeMethod(service);
// Task.CompletedTask returns a completed Task, InvokeMethod waits for it
// The result should be null since it's a non-generic Task (no return value)
// Note: Task.CompletedTask internally may be Task<VoidTaskResult> but we don't expose it
// The important thing is the method completes without exception
}
#endregion
}