Skip to content

Commit

Permalink
Merge pull request #466 from Cysharp/hotfix/DefaultUnaryResult
Browse files Browse the repository at this point in the history
Make default(UnaryResult<T>) awaitable
  • Loading branch information
mayuki authored Oct 26, 2021
2 parents 8d73bfa + 565a82b commit 17e0e94
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 4 deletions.
11 changes: 9 additions & 2 deletions src/MagicOnion.Abstractions/UnaryResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public UnaryResult(Task<TResponse> rawTaskValue)
{
this.hasRawValue = true;
this.rawValue = default(TResponse);
this.rawTaskValue = rawTaskValue;
this.rawTaskValue = rawTaskValue ?? throw new ArgumentNullException(nameof(rawTaskValue));
this.response = null;
}

Expand All @@ -67,7 +67,7 @@ public UnaryResult(Task<IResponseContext<TResponse>> response)
this.hasRawValue = false;
this.rawValue = default(TResponse);
this.rawTaskValue = null;
this.response = response;
this.response = response ?? throw new ArgumentNullException(nameof(response));
}

/// <summary>
Expand All @@ -79,6 +79,13 @@ public Task<TResponse> ResponseAsync
{
if (!hasRawValue)
{
// If the UnaryResult has no raw-value and no response, it is the default value of UnaryResult<TResponse>.
// 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public UnaryResult(Task<TResponse> rawTaskValue)
{
this.hasRawValue = true;
this.rawValue = default(TResponse);
this.rawTaskValue = rawTaskValue;
this.rawTaskValue = rawTaskValue ?? throw new ArgumentNullException(nameof(rawTaskValue));
this.response = null;
}

Expand All @@ -67,7 +67,7 @@ public UnaryResult(Task<IResponseContext<TResponse>> response)
this.hasRawValue = false;
this.rawValue = default(TResponse);
this.rawTaskValue = null;
this.response = response;
this.response = response ?? throw new ArgumentNullException(nameof(response));
}

/// <summary>
Expand All @@ -79,6 +79,13 @@ public Task<TResponse> ResponseAsync
{
if (!hasRawValue)
{
// If the UnaryResult has no raw-value and no response, it is the default value of UnaryResult<TResponse>.
// 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)
Expand Down
96 changes: 96 additions & 0 deletions tests/MagicOnion.Server.Tests/UnaryResultTest.cs
Original file line number Diff line number Diff line change
@@ -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<string>(default(string))).Should().BeNull();

Assert.Throws<ArgumentNullException>(() => UnaryResult.FromResult(default(Task<string>)));
}

[Fact]
public async Task Ctor_RawValue()
{
var result = new UnaryResult<int>(123);
(await result).Should().Be(123);

var result2 = new UnaryResult<string>("foo");
(await result2).Should().Be("foo");

var result3 = new UnaryResult<string>(default(string));
(await result3).Should().BeNull();
}

[Fact]
public async Task Ctor_RawTask()
{
var result = new UnaryResult<int>(Task.FromResult(456));
(await result).Should().Be(456);

var result2 = new UnaryResult<string>(Task.FromResult("foo"));
(await result2).Should().Be("foo");

Assert.Throws<ArgumentNullException>(() => new UnaryResult<string>(default(Task<string>)));
}

[Fact]
public async Task Ctor_TaskOfResponseContext()
{
var result = new UnaryResult<int>(Task.FromResult(DummyResponseContext.Create(456)));
(await result).Should().Be(456);

var result2 = new UnaryResult<string>(Task.FromResult(DummyResponseContext.Create("foo")));
(await result2).Should().Be("foo");

Assert.Throws<ArgumentNullException>(() => new UnaryResult<string>(default(Task<IResponseContext<string>>)));
}

static class DummyResponseContext
{
public static IResponseContext<T> Create<T>(T value)
=> new DummyResponseContext<T>(value);
}
class DummyResponseContext<T> : IResponseContext<T>
{
readonly T value;

public DummyResponseContext(T value)
{
this.value = value;
}

public Task<Metadata> ResponseHeadersAsync => Task.FromResult(Metadata.Empty);
public Status GetStatus() => Status.DefaultSuccess;
public Metadata GetTrailers() => Metadata.Empty;

public Type ResponseType => typeof(T);
public Task<T> ResponseAsync => Task.FromResult(value);

public void Dispose() { }

}

[Fact]
public async Task Ctor_Default()
{
var result = default(UnaryResult<int>);
(await result).Should().Be(0);

var result2 = default(UnaryResult<string>);
(await result2).Should().Be(null);
}
}
}

0 comments on commit 17e0e94

Please sign in to comment.