Skip to content

Commit

Permalink
Rewrite System.Text.Json stream tests to be async friendly and enable…
Browse files Browse the repository at this point in the history
… on WASM

The tests dealing are using a (De)SerializationWrapper so the same code can be used both for String and Stream types.
It does that by wrapping the async Stream serialization calls in `Task.Run().GetAwaiter().GetResult()` to turn them into sync calls.
However that doesn't work on WebAssembly since we can't wait on tasks as there's only a single thread.

To fix this inverse the wrapper so the synchronous String calls are turned into async and use normal awaits for the Stream calls.

This allows the test suite to pass on WebAssembly: `Tests run: 8349, Errors: 0, Failures: 0, Skipped: 11. Time: 475.528706s`
  • Loading branch information
akoeplinger committed Jul 3, 2020
1 parent 4aea0a1 commit 99192c0
Show file tree
Hide file tree
Showing 14 changed files with 541 additions and 553 deletions.
87 changes: 42 additions & 45 deletions src/libraries/System.Text.Json/tests/JsonDocumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,77 +232,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 @@ -362,53 +360,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 @@ -487,34 +484,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 @@ -528,7 +525,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
return s_compactJson[testCaseType] = existing;
}

[Fact]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public static void VerifyMultiThreadedDispose()
{
Action<object> disposeAction = (object document) => ((JsonDocument)document).Dispose();
Expand Down
Loading

0 comments on commit 99192c0

Please sign in to comment.