From 25566251dcad6f9d464e1778917c92894c6cda41 Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Tue, 26 Oct 2021 16:14:55 +0900 Subject: [PATCH 1/2] Make default(UnaryResult) awaitable --- src/MagicOnion.Abstractions/UnaryResult.cs | 11 +++- .../MagicOnion.Abstractions/UnaryResult.cs | 11 +++- .../UnaryResultTest.cs | 57 +++++++++++++++++++ 3 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 tests/MagicOnion.Server.Tests/UnaryResultTest.cs 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..b0169ca7f --- /dev/null +++ b/tests/MagicOnion.Server.Tests/UnaryResultTest.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using FluentAssertions; +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_Default() + { + var result = default(UnaryResult); + (await result).Should().Be(0); + + var result2 = default(UnaryResult); + (await result2).Should().Be(null); + } + } +} From 565a82b820c5e4c8e7e0a3c4bc78016480f6a526 Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Tue, 26 Oct 2021 16:20:27 +0900 Subject: [PATCH 2/2] Add test case --- .../UnaryResultTest.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/MagicOnion.Server.Tests/UnaryResultTest.cs b/tests/MagicOnion.Server.Tests/UnaryResultTest.cs index b0169ca7f..a8d8ede09 100644 --- a/tests/MagicOnion.Server.Tests/UnaryResultTest.cs +++ b/tests/MagicOnion.Server.Tests/UnaryResultTest.cs @@ -3,6 +3,8 @@ using System.Text; using System.Threading.Tasks; using FluentAssertions; +using Grpc.Core; +using MagicOnion.Client; using Xunit; namespace MagicOnion.Server.Tests @@ -44,6 +46,43 @@ public async Task Ctor_RawTask() 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() {