Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite System.Text.Json stream tests to be async friendly and enable on WASM #38663

Merged
merged 8 commits into from
Jul 10, 2020
89 changes: 43 additions & 46 deletions src/libraries/System.Text.Json/tests/JsonDocumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,77 +231,75 @@ private static string ReadJson400KB(JsonElement obj)
// If the internals change such that one of these is exercising substantially different
// code, then it should switch to the full variation set.
[MemberData(nameof(TestCases))]
public static void ParseJson_MemoryBytes(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_MemoryBytes(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
null,
bytes => JsonDocument.Parse(bytes.AsMemory()));
bytes => Task.FromResult(JsonDocument.Parse(bytes.AsMemory())));
}

[Theory]
[MemberData(nameof(ReducedTestCases))]
public static void ParseJson_String(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_String(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
str => JsonDocument.Parse(str),
str => Task.FromResult(JsonDocument.Parse(str)),
null);
}

[Theory]
[MemberData(nameof(ReducedTestCases))]
public static void ParseJson_SeekableStream(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_SeekableStream(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
null,
bytes => JsonDocument.Parse(new MemoryStream(bytes)));
bytes => Task.FromResult(JsonDocument.Parse(new MemoryStream(bytes))));
}

[Theory]
[MemberData(nameof(ReducedTestCases))]
public static void ParseJson_SeekableStream_Async(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_SeekableStream_Async(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
null,
bytes => JsonDocument.ParseAsync(new MemoryStream(bytes)).GetAwaiter().GetResult());
bytes => JsonDocument.ParseAsync(new MemoryStream(bytes)));
}

[Theory]
[MemberData(nameof(ReducedTestCases))]
public static void ParseJson_UnseekableStream(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_UnseekableStream(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
null,
bytes => JsonDocument.Parse(
bytes => JsonDocument.ParseAsync(
new WrappedMemoryStream(canRead: true, canWrite: false, canSeek: false, bytes)));
}

[Theory]
[MemberData(nameof(ReducedTestCases))]
public static void ParseJson_UnseekableStream_Async(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_UnseekableStream_Async(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
null,
bytes => JsonDocument.ParseAsync(
new WrappedMemoryStream(canRead: true, canWrite: false, canSeek: false, bytes)).
GetAwaiter().GetResult());
bytes => JsonDocument.ParseAsync(new WrappedMemoryStream(canRead: true, canWrite: false, canSeek: false, bytes)));
}


Expand Down Expand Up @@ -361,53 +359,52 @@ public static async Task ParseJson_UnseekableStream_Small_Async()

[Theory]
[MemberData(nameof(ReducedTestCases))]
public static void ParseJson_SeekableStream_WithBOM(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_SeekableStream_WithBOM(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
null,
bytes => JsonDocument.Parse(new MemoryStream(Utf8Bom.Concat(bytes).ToArray())));
bytes => Task.FromResult(JsonDocument.Parse(new MemoryStream(Utf8Bom.Concat(bytes).ToArray()))));
}

[Theory]
[MemberData(nameof(ReducedTestCases))]
public static void ParseJson_SeekableStream_Async_WithBOM(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_SeekableStream_Async_WithBOM(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
null,
bytes => JsonDocument.ParseAsync(new MemoryStream(Utf8Bom.Concat(bytes).ToArray())).GetAwaiter().GetResult());
bytes => JsonDocument.ParseAsync(new MemoryStream(Utf8Bom.Concat(bytes).ToArray())));
}

[Theory]
[MemberData(nameof(ReducedTestCases))]
public static void ParseJson_UnseekableStream_WithBOM(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_UnseekableStream_WithBOM(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
null,
bytes => JsonDocument.Parse(
new WrappedMemoryStream(canRead: true, canWrite: false, canSeek: false, Utf8Bom.Concat(bytes).ToArray())));
bytes => Task.FromResult(JsonDocument.Parse(
new WrappedMemoryStream(canRead: true, canWrite: false, canSeek: false, Utf8Bom.Concat(bytes).ToArray()))));
}

[Theory]
[MemberData(nameof(ReducedTestCases))]
public static void ParseJson_UnseekableStream_Async_WithBOM(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_UnseekableStream_Async_WithBOM(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
null,
bytes => JsonDocument.ParseAsync(
new WrappedMemoryStream(canRead: true, canWrite: false, canSeek: false, Utf8Bom.Concat(bytes).ToArray())).
GetAwaiter().GetResult());
new WrappedMemoryStream(canRead: true, canWrite: false, canSeek: false, Utf8Bom.Concat(bytes).ToArray())));
}

[Fact]
Expand Down Expand Up @@ -486,34 +483,34 @@ public static Task ParseJson_UnseekableStream_Async_BadBOM(string json)

[Theory]
[MemberData(nameof(ReducedTestCases))]
public static void ParseJson_SequenceBytes_Single(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_SequenceBytes_Single(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
null,
bytes => JsonDocument.Parse(new ReadOnlySequence<byte>(bytes)));
bytes => Task.FromResult(JsonDocument.Parse(new ReadOnlySequence<byte>(bytes))));
}

[Theory]
[MemberData(nameof(ReducedTestCases))]
public static void ParseJson_SequenceBytes_Multi(bool compactData, TestCaseType type, string jsonString)
public static async Task ParseJson_SequenceBytes_Multi(bool compactData, TestCaseType type, string jsonString)
{
ParseJson(
await ParseJsonAsync(
compactData,
type,
jsonString,
null,
bytes => JsonDocument.Parse(JsonTestHelper.SegmentInto(bytes, 31)));
bytes => Task.FromResult(JsonDocument.Parse(JsonTestHelper.SegmentInto(bytes, 31))));
}

private static void ParseJson(
private static async Task ParseJsonAsync(
bool compactData,
TestCaseType type,
string jsonString,
Func<string, JsonDocument> stringDocBuilder,
Func<byte[], JsonDocument> bytesDocBuilder)
Func<string, Task<JsonDocument>> stringDocBuilder,
Func<byte[], Task<JsonDocument>> bytesDocBuilder)
{
// One, but not both, must be null.
if ((stringDocBuilder == null) == (bytesDocBuilder == null))
Expand All @@ -527,7 +524,7 @@ private static void ParseJson(

byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString);

using (JsonDocument doc = stringDocBuilder?.Invoke(jsonString) ?? bytesDocBuilder?.Invoke(dataUtf8))
using (JsonDocument doc = await (stringDocBuilder?.Invoke(jsonString) ?? bytesDocBuilder?.Invoke(dataUtf8)))
{
Assert.NotNull(doc);

Expand Down Expand Up @@ -3650,7 +3647,7 @@ private static string GetCompactJson(TestCaseType testCaseType, string jsonStrin
}

[Fact]
public static void VerifyMultiThreadedDispose()
public static async Task VerifyMultiThreadedDispose()
{
Action<object> disposeAction = (object document) => ((JsonDocument)document).Dispose();

Expand All @@ -3669,7 +3666,7 @@ public static void VerifyMultiThreadedDispose()
}
}

Task.WaitAll(tasks);
await Task.WhenAll(tasks);

// When ArrayPool gets corrupted, the Rent method might return an already rented array, which is incorrect.
// So we will rent as many arrays as calls to JsonElement.Dispose and check they are unique.
Expand Down
28 changes: 14 additions & 14 deletions src/libraries/System.Text.Json/tests/Serialization/CacheTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
Expand All @@ -11,18 +11,18 @@ namespace System.Text.Json.Serialization.Tests
public static class CacheTests
{
[Fact, OuterLoop]
public static void MultipleThreads_SameType_DifferentJson_Looping()
public static async Task MultipleThreads_SameType_DifferentJson_Looping()
{
const int Iterations = 100;

for (int i = 0; i < Iterations; i++)
{
MultipleThreads_SameType_DifferentJson();
await MultipleThreads_SameType_DifferentJson();
}
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public static void MultipleThreads_SameType_DifferentJson()
[Fact]
public static async Task MultipleThreads_SameType_DifferentJson()
{
// Use local options to avoid obtaining already cached metadata from the default options.
var options = new JsonSerializerOptions();
Expand Down Expand Up @@ -69,22 +69,22 @@ void SerializeObject()
tasks[i + 3] = Task.Run(() => SerializeObject());
};

Task.WaitAll(tasks);
await Task.WhenAll(tasks);
}

[Fact, OuterLoop]
public static void MultipleThreads_DifferentTypes_Looping()
public static async Task MultipleThreads_DifferentTypes_Looping()
{
const int Iterations = 100;

for (int i = 0; i < Iterations; i++)
{
MultipleThreads_DifferentTypes();
await MultipleThreads_DifferentTypes();
}
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public static void MultipleThreads_DifferentTypes()
[Fact]
public static async Task MultipleThreads_DifferentTypes()
{
// Use local options to avoid obtaining already cached metadata from the default options.
var options = new JsonSerializerOptions();
Expand Down Expand Up @@ -121,7 +121,7 @@ void Test(int i)
tasks[i + 1] = Task.Run(() => Test(TestClassCount - 2));
}

Task.WaitAll(tasks);
await Task.WhenAll(tasks);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI this area of code really does care about threading, and the changes shouldn't affect the multi-threading aspects.

}

[Fact]
Expand Down Expand Up @@ -164,9 +164,9 @@ public static void PropertyCacheWithMinInputsLast()
// this options is not the default options instance the tests will not use previously cached metadata.
private static JsonSerializerOptions s_options = new JsonSerializerOptions();

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[Theory]
[MemberData(nameof(WriteSuccessCases))]
public static void MultipleTypes(ITestClass testObj)
public static async Task MultipleTypes(ITestClass testObj)
{
Type type = testObj.GetType();

Expand Down Expand Up @@ -199,7 +199,7 @@ void Deserialize()
tasks[i + 1] = Task.Run(() => Serialize());
};

Task.WaitAll(tasks);
await Task.WhenAll(tasks);
}

public static IEnumerable<object[]> WriteSuccessCases
Expand Down
Loading