Skip to content

Commit

Permalink
Enable nullable ref types
Browse files Browse the repository at this point in the history
  • Loading branch information
AArnott committed Nov 5, 2019
1 parent e441369 commit 233fc95
Show file tree
Hide file tree
Showing 64 changed files with 525 additions and 387 deletions.
4 changes: 3 additions & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<BaseOutputPath Condition=" '$(BaseOutputPath)' == '' ">$(RepoRootPath)bin\$(MSBuildProjectName)\</BaseOutputPath>
<PackageOutputPath>$(RepoRootPath)bin\Packages\$(Configuration)\NuGet\</PackageOutputPath>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<UpdateXlfOnBuild Condition=" '$(UpdateXlfOnBuild)' == '' ">true</UpdateXlfOnBuild>

Expand All @@ -27,10 +28,11 @@

<ItemGroup>
<PackageReference Include="MicroBuild.VisualStudio" Version="$(MicroBuildPackageVersion)" PrivateAssets="all" />
<PackageReference Include="Microsoft.Net.Compilers.Toolset" Version="3.4.0-beta2-final" PrivateAssets="all" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0-preview.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" PrivateAssets="All" />
<PackageReference Include="Nerdbank.GitVersioning" Version="3.0.25" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)PackageIcon.png" Pack="true" PackagePath="" />
Expand Down
2 changes: 1 addition & 1 deletion src/StreamJsonRpc.Tests/CommonErrorDataTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public CommonErrorDataTests(ITestOutputHelper logger)
[Fact]
public void Ctor_CopyFrom_Null()
{
Assert.Throws<ArgumentNullException>(() => new CommonErrorData(null));
Assert.Throws<ArgumentNullException>(() => new CommonErrorData(null!));
}

[Fact]
Expand Down
4 changes: 2 additions & 2 deletions src/StreamJsonRpc.Tests/CommonMethodNameTransformsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public void CamelCase()
Assert.Equal("fireOne", CommonMethodNameTransforms.CamelCase("fireOne"));
Assert.Equal("fireOneAndTwo", CommonMethodNameTransforms.CamelCase("FIREOneAndTwo"));
Assert.Equal("fire", CommonMethodNameTransforms.CamelCase("FIRE"));
Assert.Throws<ArgumentNullException>(() => CommonMethodNameTransforms.CamelCase(null));
Assert.Throws<ArgumentNullException>(() => CommonMethodNameTransforms.CamelCase(null!));
Assert.Equal(string.Empty, CommonMethodNameTransforms.CamelCase(string.Empty));
}

Expand All @@ -25,7 +25,7 @@ public void Prefix()
Assert.Equal("Foo.Do", CommonMethodNameTransforms.Prepend("Foo.")("Do"));
Assert.Equal("Foo.Bar/Do", CommonMethodNameTransforms.Prepend("Foo.Bar/")("Do"));
Assert.Equal("Foo.Bar.Do", CommonMethodNameTransforms.Prepend("Foo.Bar.")("Do"));
Assert.Throws<ArgumentNullException>(() => CommonMethodNameTransforms.Prepend(null));
Assert.Throws<ArgumentNullException>(() => CommonMethodNameTransforms.Prepend(null!));
Assert.Equal("Do", CommonMethodNameTransforms.Prepend(string.Empty)("Do"));
}
}
2 changes: 1 addition & 1 deletion src/StreamJsonRpc.Tests/DirectMessageHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public DirectMessageHandler()

internal AsyncQueue<JToken> WrittenMessages { get; } = new AsyncQueue<JToken>();

protected override async ValueTask<JsonRpcMessage> ReadCoreAsync(CancellationToken cancellationToken)
protected override async ValueTask<JsonRpcMessage?> ReadCoreAsync(CancellationToken cancellationToken)
{
return this.Formatter.Deserialize(await this.MessagesToRead.DequeueAsync(cancellationToken));
}
Expand Down
12 changes: 7 additions & 5 deletions src/StreamJsonRpc.Tests/DuplexPipeMarshalingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ public class DuplexPipeMarshalingTests : TestBase, IAsyncLifetime
private JsonRpc clientRpc;
private MultiplexingStream clientMx;

#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
public DuplexPipeMarshalingTests(ITestOutputHelper logger)
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
: base(logger)
{
}
Expand Down Expand Up @@ -375,7 +377,7 @@ public async Task PipeRemainsOpenAfterSuccessfulServerResult()
(IDuplexPipe, IDuplexPipe) pipePair = FullDuplexStream.CreatePipePair();
await this.clientRpc.InvokeWithCancellationAsync(nameof(Server.AcceptPipeAndChatLater), new object[] { false, pipePair.Item2 }, this.TimeoutToken);

await WhenAllSucceedOrAnyFault(TwoWayTalkAsync(pipePair.Item1, writeOnOdd: true, this.TimeoutToken), this.server.ChatLaterTask);
await WhenAllSucceedOrAnyFault(TwoWayTalkAsync(pipePair.Item1, writeOnOdd: true, this.TimeoutToken), this.server.ChatLaterTask!);
pipePair.Item1.Output.Complete();

// Verify that the pipe closes when the server completes writing.
Expand Down Expand Up @@ -432,7 +434,7 @@ public async Task ClientSendsMultiplePipes()
[Fact]
public async Task ClientSendsNullPipe()
{
await this.clientRpc.InvokeWithCancellationAsync(nameof(Server.AcceptNullPipe), new object[] { null }, this.TimeoutToken);
await this.clientRpc.InvokeWithCancellationAsync(nameof(Server.AcceptNullPipe), new object?[] { null }, this.TimeoutToken);
}

/// <summary>
Expand Down Expand Up @@ -471,7 +473,7 @@ public async Task InvokeWithPipe_ServerMethodDoesNotExist_ChannelOfferCanceled()
// It may or may not have already occurred so for test stability, we code our assertion to handle both cases.
try
{
MultiplexingStream.Channel serverChannel = this.serverMx.AcceptChannel(channelIdOffered.Value);
MultiplexingStream.Channel serverChannel = this.serverMx.AcceptChannel(channelIdOffered!.Value);

// The client had not yet canceled the offer. So wait for the client to close the channel now that we've accepted it.
await serverChannel.Completion.WithCancellation(this.TimeoutToken);
Expand Down Expand Up @@ -575,7 +577,7 @@ public async Task OverloadedMethod(bool writeOnOdd, IDuplexPipe pipe, string mes

private class Server
{
internal Task ChatLaterTask { get; private set; }
internal Task? ChatLaterTask { get; private set; }

public async Task<long> AcceptReadablePipe(string fileName, IDuplexPipe content, CancellationToken cancellationToken)
{
Expand Down Expand Up @@ -702,7 +704,7 @@ public Task AcceptPipeAndChatLater(bool writeOnOdd, IDuplexPipe pipe, Cancellati

private class ServerWithIDuplexPipeReturningMethod
{
public IDuplexPipe MethodThatReturnsIDuplexPipe() => null;
public IDuplexPipe? MethodThatReturnsIDuplexPipe() => null;
}

private class OneWayStreamWrapper : Stream
Expand Down
22 changes: 11 additions & 11 deletions src/StreamJsonRpc.Tests/FullDuplexStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ public class FullDuplexStream : Stream
/// The options to use when creating the value for <see cref="enqueuedSource"/>.
/// </summary>
private const TaskCreationOptions EnqueuedSourceOptions = TaskCreationOptions.RunContinuationsAsynchronously;
private static readonly byte[] EmptyByteArray = new byte[0];
private static readonly Task CompletedTask = Task.FromResult<object>(null);

/// <summary>
/// The messages posted by the <see cref="other"/> party,
Expand All @@ -32,13 +30,15 @@ public class FullDuplexStream : Stream
/// <summary>
/// The stream to write to.
/// </summary>
#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
private FullDuplexStream other;
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.

/// <summary>
/// The completion source for a Task that completes whenever a message
/// is enqueued to <see cref="readQueue"/>.
/// </summary>
private TaskCompletionSource<object> enqueuedSource = new TaskCompletionSource<object>(EnqueuedSourceOptions);
private TaskCompletionSource<object?> enqueuedSource = new TaskCompletionSource<object?>(EnqueuedSourceOptions);

/// <summary>
/// Gets or sets a value indicating whether the stream is disposed.
Expand Down Expand Up @@ -71,7 +71,7 @@ public override long Position
/// Gets or sets a delegate that is called just before writing to the stream,
/// but after the caller's cancellation token has been checked.
/// </summary>
public BeforeWriteToFullDuplexStreamDelegate BeforeWrite { get; set; }
public BeforeWriteToFullDuplexStreamDelegate? BeforeWrite { get; set; }

/// <summary>
/// Creates a pair of streams that can be passed to two parties
Expand Down Expand Up @@ -101,10 +101,10 @@ public override async Task<int> ReadAsync(byte[] buffer, int offset, int count,
Requires.Range(offset + count <= buffer.Length, nameof(count));

cancellationToken.ThrowIfCancellationRequested();
Message message = null;
Message? message = null;
while (message == null)
{
Task waitTask = null;
Task? waitTask = null;
lock (this.readQueue)
{
if (this.readQueue.Count > 0)
Expand All @@ -123,7 +123,7 @@ public override async Task<int> ReadAsync(byte[] buffer, int offset, int count,
{
// Arrange to wake up when a new message is posted, or when the caller's CancellationToken is canceled.
var wakeUpEarly = new TaskCompletionSource<object>();
using (cancellationToken.Register(state => ((TaskCompletionSource<object>)state).SetResult(null), wakeUpEarly, false))
using (cancellationToken.Register(state => ((TaskCompletionSource<object?>)state).SetResult(null), wakeUpEarly, false))
{
await Task.WhenAny(waitTask, wakeUpEarly.Task).ConfigureAwait(false);
}
Expand Down Expand Up @@ -206,7 +206,7 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati
{
cancellationToken.ThrowIfCancellationRequested();
this.Write(buffer, offset, count);
return CompletedTask;
return Task.CompletedTask;
}

/// <inheritdoc />
Expand Down Expand Up @@ -242,7 +242,7 @@ protected override void Dispose(bool disposing)

// Sending an empty buffer is the traditional way to signal
// that the transmitting stream has closed.
this.other.PostMessage(new Message(EmptyByteArray));
this.other.PostMessage(new Message(Array.Empty<byte>()));
base.Dispose(disposing);
}

Expand All @@ -254,12 +254,12 @@ private void PostMessage(Message message)
{
Requires.NotNull(message, nameof(message));

TaskCompletionSource<object> enqueuedSource;
TaskCompletionSource<object?> enqueuedSource;
lock (this.readQueue)
{
this.readQueue.Add(message);
Monitor.PulseAll(this.readQueue);
enqueuedSource = Interlocked.Exchange(ref this.enqueuedSource, new TaskCompletionSource<object>(EnqueuedSourceOptions));
enqueuedSource = Interlocked.Exchange(ref this.enqueuedSource, new TaskCompletionSource<object?>(EnqueuedSourceOptions));
}

enqueuedSource.TrySetResult(null);
Expand Down
16 changes: 8 additions & 8 deletions src/StreamJsonRpc.Tests/HeaderDelimitedMessageHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ public async Task ReadCoreAsync_HandlesSpacingCorrectly()
this.receivingStream.Flush();
this.receivingStream.Position = 0;

var readContent = (JsonRpcRequest)await this.handler.ReadAsync(CancellationToken.None);
Assert.Equal("test", readContent.Method);
var readContent = (JsonRpcRequest?)await this.handler.ReadAsync(CancellationToken.None);
Assert.Equal("test", readContent!.Method);

this.receivingStream.Position = 0;
this.receivingStream.SetLength(0);
Expand All @@ -77,8 +77,8 @@ public async Task ReadCoreAsync_HandlesSpacingCorrectly()
this.receivingStream.Flush();
this.receivingStream.Position = 0;

readContent = (JsonRpcRequest)await this.handler.ReadAsync(CancellationToken.None);
Assert.Equal("test", readContent.Method);
readContent = (JsonRpcRequest?)await this.handler.ReadAsync(CancellationToken.None);
Assert.Equal("test", readContent!.Method);
}

[Fact]
Expand All @@ -95,8 +95,8 @@ public async Task ReadCoreAsync_HandlesUtf8CharsetCorrectly()
this.receivingStream.Flush();
this.receivingStream.Position = 0;

var readContent = (JsonRpcRequest)await this.handler.ReadAsync(CancellationToken.None);
Assert.Equal("test", readContent.Method);
var readContent = (JsonRpcRequest?)await this.handler.ReadAsync(CancellationToken.None);
Assert.Equal("test", readContent!.Method);

this.receivingStream.Position = 0;
this.receivingStream.SetLength(0);
Expand All @@ -112,8 +112,8 @@ public async Task ReadCoreAsync_HandlesUtf8CharsetCorrectly()
this.receivingStream.Flush();
this.receivingStream.Position = 0;

readContent = (JsonRpcRequest)await this.handler.ReadAsync(CancellationToken.None);
Assert.Equal("test", readContent.Method);
readContent = (JsonRpcRequest?)await this.handler.ReadAsync(CancellationToken.None);
Assert.Equal("test", readContent!.Method);
}

[Fact]
Expand Down
1 change: 0 additions & 1 deletion src/StreamJsonRpc.Tests/InteropTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
public class InteropTestBase : TestBase
{
protected readonly DirectMessageHandler messageHandler;
protected readonly JsonRpc rpc;

public InteropTestBase(ITestOutputHelper logger, bool serverTest)
: base(logger)
Expand Down
4 changes: 2 additions & 2 deletions src/StreamJsonRpc.Tests/JsonMessageFormatterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void ProtocolVersion_AcceptedVersions(int major, int minor)
public void ProtocolVersion_RejectsOtherVersions()
{
var formatter = new JsonMessageFormatter();
Assert.Throws<ArgumentNullException>(() => formatter.ProtocolVersion = null);
Assert.Throws<ArgumentNullException>(() => formatter.ProtocolVersion = null!);
Assert.Throws<NotSupportedException>(() => formatter.ProtocolVersion = new Version(0, 0));
Assert.Throws<NotSupportedException>(() => formatter.ProtocolVersion = new Version(1, 1));
Assert.Throws<NotSupportedException>(() => formatter.ProtocolVersion = new Version(2, 1));
Expand Down Expand Up @@ -108,7 +108,7 @@ public void JTokenParserHonorsSettingsOnSerializer()
string jsonRequest = @"{""jsonrpc"":""2.0"",""method"":""asdf"",""params"":[""2019-01-29T03:37:28.4433841Z""]}";
ReadOnlySequence<byte> jsonSequence = new ReadOnlySequence<byte>(formatter.Encoding.GetBytes(jsonRequest));
var jsonMessage = (JsonRpcRequest)formatter.Deserialize(jsonSequence);
Assert.True(jsonMessage.TryGetArgumentByNameOrIndex(null, 0, typeof(string), out object value));
Assert.True(jsonMessage.TryGetArgumentByNameOrIndex(null, 0, typeof(string), out object? value));
Assert.IsType<string>(value);
Assert.Equal("2019-01-29T03:37:28.4433841Z", value);
}
Expand Down
4 changes: 2 additions & 2 deletions src/StreamJsonRpc.Tests/JsonRpcClient10InteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task ClientRecognizesResultWithNullError()
{
id = request["id"],
result = expectedResult,
error = (object)null, // JSON-RPC 1.0 requires that the error property be specified as null in successful responses.
error = (object?)null, // JSON-RPC 1.0 requires that the error property be specified as null in successful responses.
});
string actualResult = await invokeTask;
Assert.Equal(expectedResult, actualResult);
Expand All @@ -57,7 +57,7 @@ public async Task ClientRecognizesErrorWithNullResult()
this.Send(new
{
id = request.id,
result = (object)null, // JSON-RPC 1.0 requires that result be specified and null if there is an error.
result = (object?)null, // JSON-RPC 1.0 requires that result be specified and null if there is an error.
error = new { message = expectedErrorMessage },
});
var error = await Assert.ThrowsAsync<RemoteInvocationException>(() => invokeTask);
Expand Down
8 changes: 4 additions & 4 deletions src/StreamJsonRpc.Tests/JsonRpcClient20InteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ public async Task ErrorResponseIncludesCallstack()
};
this.Send(errorObject);
var ex = await Assert.ThrowsAsync<RemoteInvocationException>(() => requestTask);
var commonErrorData = ((JToken)ex.ErrorData).ToObject<CommonErrorData>();
var commonErrorData = ((JToken)ex.ErrorData!).ToObject<CommonErrorData>();
Assert.Equal(errorObject.error.data.stack, commonErrorData.StackTrace);
}

Expand All @@ -327,7 +327,7 @@ public async Task ErrorResponseIncludesCallstackAndNumericErrorCode()
};
this.Send(errorObject);
var ex = await Assert.ThrowsAsync<RemoteInvocationException>(() => requestTask);
var commonErrorData = ((JToken)ex.ErrorData).ToObject<CommonErrorData>();
var commonErrorData = ((JToken?)ex.ErrorData)!.ToObject<CommonErrorData>();
Assert.Equal(errorObject.error.data.stack, commonErrorData.StackTrace);
Assert.Equal(-2147467261, commonErrorData.HResult);
}
Expand Down Expand Up @@ -355,7 +355,7 @@ public async Task ErrorResponseUsesUnexpectedDataTypes()
};
this.Send(errorObject);
var ex = await Assert.ThrowsAsync<RemoteInvocationException>(() => requestTask);
JToken errorDataToken = (JToken)ex.ErrorData;
JToken errorDataToken = (JToken)ex.ErrorData!;
Assert.Throws<JsonReaderException>(() => errorDataToken.ToObject<CommonErrorData>());
Assert.Equal(errorData.stack.foo, errorDataToken["stack"].Value<int>("foo"));
}
Expand Down Expand Up @@ -406,7 +406,7 @@ public async Task ErrorResponseDataFieldIsPrimitive()
});
var ex = await Assert.ThrowsAsync<RemoteInvocationException>(() => requestTask);
Assert.Equal(expectedMessage, ex.Message);
Assert.Equal(expectedData, ((JToken)ex.ErrorData)?.Value<string>());
Assert.Equal(expectedData, ((JToken?)ex.ErrorData)?.Value<string>());
}

[Fact]
Expand Down
2 changes: 1 addition & 1 deletion src/StreamJsonRpc.Tests/JsonRpcCustomRequestIdTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public JsonRpcWithStringIds(IJsonRpcMessageHandler handler)

protected override RequestId CreateNewRequestId()
{
return new RequestId("prefix-" + base.CreateNewRequestId().Number.Value.ToString());
return new RequestId("prefix-" + base.CreateNewRequestId().Number);
}
}
}
8 changes: 4 additions & 4 deletions src/StreamJsonRpc.Tests/JsonRpcJsonHeadersTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ public async Task ExceptionControllingErrorData()

// C# dynamic is infamously unstable. If this test ends up being unstable, yet the dump clearly shows the fields are there even though the exception claims it isn't,
// that's consistent with the instability I've seen before. Switching to using JToken APIs will fix the instability, but it relies on using the JsonMessageFormatter.
dynamic data = exception.ErrorData;
dynamic myCustomData = data.myCustomData;
dynamic? data = exception.ErrorData;
dynamic myCustomData = data!.myCustomData;
string actual = myCustomData;
Assert.Equal("hi", actual);
}
Expand All @@ -189,7 +189,7 @@ public async Task CanPassExceptionFromServer()
#pragma warning restore SA1139 // Use literal suffix notation instead of casting
RemoteInvocationException exception = await Assert.ThrowsAnyAsync<RemoteInvocationException>(() => this.clientRpc.InvokeAsync(nameof(Server.MethodThatThrowsUnauthorizedAccessException)));
Assert.Equal((int)JsonRpcErrorCode.InvocationError, exception.ErrorCode);
var errorData = ((JToken)exception.ErrorData).ToObject<CommonErrorData>();
var errorData = ((JToken?)exception.ErrorData)!.ToObject<CommonErrorData>();
Assert.NotNull(errorData.StackTrace);
Assert.StrictEqual(COR_E_UNAUTHORIZEDACCESS, errorData.HResult);
}
Expand All @@ -207,7 +207,7 @@ protected override void InitializeFormattersAndHandlers()
public class ParamsObjectWithCustomNames
{
[DataMember(Name = "argument")]
public string TheArgument { get; set; }
public string? TheArgument { get; set; }
}

private class StringBase64Converter : JsonConverter
Expand Down
Loading

0 comments on commit 233fc95

Please sign in to comment.