diff --git a/src/MagicOnion.Abstractions/UnaryResult.cs b/src/MagicOnion.Abstractions/UnaryResult.cs index 49dd68792..58b1b574c 100644 --- a/src/MagicOnion.Abstractions/UnaryResult.cs +++ b/src/MagicOnion.Abstractions/UnaryResult.cs @@ -58,7 +58,7 @@ public UnaryResult(Task rawTaskValue) { this.hasRawValue = true; this.rawValue = default(TResponse); - this.rawTaskValue = rawTaskValue; + this.rawTaskValue = rawTaskValue ?? throw new ArgumentNullException(nameof(rawTaskValue)); this.response = null; } @@ -67,7 +67,7 @@ public UnaryResult(Task> response) this.hasRawValue = false; this.rawValue = default(TResponse); this.rawTaskValue = null; - this.response = response; + this.response = response ?? throw new ArgumentNullException(nameof(response)); } /// @@ -79,6 +79,13 @@ public Task ResponseAsync { if (!hasRawValue) { + // If the UnaryResult has no raw-value and no response, it is the default value of UnaryResult. + // So, we will return the default value of TResponse as Task. + if (response is null) + { + return Task.FromResult(default(TResponse)); + } + return UnwrapResponse(); } else if (rawTaskValue != null) diff --git a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Abstractions/UnaryResult.cs b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Abstractions/UnaryResult.cs index 49dd68792..58b1b574c 100644 --- a/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Abstractions/UnaryResult.cs +++ b/src/MagicOnion.Client.Unity/Assets/Scripts/MagicOnion/MagicOnion.Abstractions/UnaryResult.cs @@ -58,7 +58,7 @@ public UnaryResult(Task rawTaskValue) { this.hasRawValue = true; this.rawValue = default(TResponse); - this.rawTaskValue = rawTaskValue; + this.rawTaskValue = rawTaskValue ?? throw new ArgumentNullException(nameof(rawTaskValue)); this.response = null; } @@ -67,7 +67,7 @@ public UnaryResult(Task> response) this.hasRawValue = false; this.rawValue = default(TResponse); this.rawTaskValue = null; - this.response = response; + this.response = response ?? throw new ArgumentNullException(nameof(response)); } /// @@ -79,6 +79,13 @@ public Task ResponseAsync { if (!hasRawValue) { + // If the UnaryResult has no raw-value and no response, it is the default value of UnaryResult. + // So, we will return the default value of TResponse as Task. + if (response is null) + { + return Task.FromResult(default(TResponse)); + } + return UnwrapResponse(); } else if (rawTaskValue != null) diff --git a/tests/MagicOnion.Server.Tests/UnaryResultTest.cs b/tests/MagicOnion.Server.Tests/UnaryResultTest.cs new file mode 100644 index 000000000..a8d8ede09 --- /dev/null +++ b/tests/MagicOnion.Server.Tests/UnaryResultTest.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using FluentAssertions; +using Grpc.Core; +using MagicOnion.Client; +using Xunit; + +namespace MagicOnion.Server.Tests +{ + public class UnaryResultTest + { + [Fact] + public async Task FromResult() + { + (await UnaryResult.FromResult(123)).Should().Be(123); + (await UnaryResult.FromResult("foo")).Should().Be("foo"); + (await UnaryResult.FromResult(default(string))).Should().BeNull(); + + Assert.Throws(() => UnaryResult.FromResult(default(Task))); + } + + [Fact] + public async Task Ctor_RawValue() + { + var result = new UnaryResult(123); + (await result).Should().Be(123); + + var result2 = new UnaryResult("foo"); + (await result2).Should().Be("foo"); + + var result3 = new UnaryResult(default(string)); + (await result3).Should().BeNull(); + } + + [Fact] + public async Task Ctor_RawTask() + { + var result = new UnaryResult(Task.FromResult(456)); + (await result).Should().Be(456); + + var result2 = new UnaryResult(Task.FromResult("foo")); + (await result2).Should().Be("foo"); + + Assert.Throws(() => new UnaryResult(default(Task))); + } + + [Fact] + public async Task Ctor_TaskOfResponseContext() + { + var result = new UnaryResult(Task.FromResult(DummyResponseContext.Create(456))); + (await result).Should().Be(456); + + var result2 = new UnaryResult(Task.FromResult(DummyResponseContext.Create("foo"))); + (await result2).Should().Be("foo"); + + Assert.Throws(() => new UnaryResult(default(Task>))); + } + + static class DummyResponseContext + { + public static IResponseContext Create(T value) + => new DummyResponseContext(value); + } + class DummyResponseContext : IResponseContext + { + readonly T value; + + public DummyResponseContext(T value) + { + this.value = value; + } + + public Task ResponseHeadersAsync => Task.FromResult(Metadata.Empty); + public Status GetStatus() => Status.DefaultSuccess; + public Metadata GetTrailers() => Metadata.Empty; + + public Type ResponseType => typeof(T); + public Task ResponseAsync => Task.FromResult(value); + + public void Dispose() { } + + } + + [Fact] + public async Task Ctor_Default() + { + var result = default(UnaryResult); + (await result).Should().Be(0); + + var result2 = default(UnaryResult); + (await result2).Should().Be(null); + } + } +}