Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal override bool OnTryRead(
scoped ref ReadStack state,
out Memory<T> value)
{
if (reader.TokenType is JsonTokenType.Null)
if (reader.TokenType is JsonTokenType.Null && !state.IsContinuation)
{
value = default;
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal override bool OnTryRead(
scoped ref ReadStack state,
out ReadOnlyMemory<T> value)
{
if (reader.TokenType is JsonTokenType.Null)
if (reader.TokenType is JsonTokenType.Null && !state.IsContinuation)
{
value = default;
return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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;
using System.Threading.Tasks;
using Xunit;

Expand Down Expand Up @@ -137,5 +138,83 @@ public async Task DeserializeMemoryByteClassAsync()
MemoryOfTClass<byte> memoryOfByteClass = await Serializer.DeserializeWrapper<MemoryOfTClass<byte>>(json);
AssertExtensions.SequenceEqual<byte>(s_testData.AsSpan(), memoryOfByteClass.Memory.Span);
}

[Fact]
public async Task DeserializeMemoryFromStreamWithNullElements()
{
// Regression test for https://github.com/dotnet/runtime/issues/118346
// Tests that ReadOnlyMemory/Memory converters handle null elements correctly during streaming deserialization
if (StreamingSerializer is null)
{
return;
}

string json = """[{"Name":"Alice"},null,{"Name":"Bob"}]""";
using var stream = new Utf8MemoryStream(json);

ReadOnlyMemory<SimpleClass?> result = await StreamingSerializer.DeserializeWrapper<ReadOnlyMemory<SimpleClass?>>(stream);

Assert.Equal(3, result.Length);
Assert.NotNull(result.Span[0]);
Assert.Equal("Alice", result.Span[0]!.Name);
Assert.Null(result.Span[1]);
Assert.NotNull(result.Span[2]);
Assert.Equal("Bob", result.Span[2]!.Name);
}

[Fact]
public async Task DeserializeReadOnlyMemoryFromStreamWithNullElements()
{
// Regression test for https://github.com/dotnet/runtime/issues/118346
// Tests that Memory converters handle null elements correctly during streaming deserialization
if (StreamingSerializer is null)
{
return;
}

string json = """[{"Name":"Alice"},null,{"Name":"Bob"}]""";
using var stream = new Utf8MemoryStream(json);

Memory<SimpleClass?> result = await StreamingSerializer.DeserializeWrapper<Memory<SimpleClass?>>(stream);

Assert.Equal(3, result.Length);
Assert.NotNull(result.Span[0]);
Assert.Equal("Alice", result.Span[0]!.Name);
Assert.Null(result.Span[1]);
Assert.NotNull(result.Span[2]);
Assert.Equal("Bob", result.Span[2]!.Name);
}

[Fact]
public async Task DeserializeMemoryFromStreamManyElements()
{
// Regression test for https://github.com/dotnet/runtime/issues/118346
// Tests that ReadOnlyMemory/Memory converters handle streaming deserialization with nulls
if (StreamingSerializer is null)
{
return;
}

// Create a JSON array with nulls that may trigger continuation
string json = """[{"Name":"Alice"},null,{"Name":"Bob"},null,{"Name":"Charlie"}]""";
using var stream = new Utf8MemoryStream(json);

ReadOnlyMemory<SimpleClass?> result = await StreamingSerializer.DeserializeWrapper<ReadOnlyMemory<SimpleClass?>>(stream);

Assert.Equal(5, result.Length);
Assert.NotNull(result.Span[0]);
Assert.Equal("Alice", result.Span[0]!.Name);
Assert.Null(result.Span[1]);
Assert.NotNull(result.Span[2]);
Assert.Equal("Bob", result.Span[2]!.Name);
Assert.Null(result.Span[3]);
Assert.NotNull(result.Span[4]);
Assert.Equal("Charlie", result.Span[4]!.Name);
}

public class SimpleClass
{
public string? Name { get; set; }
}
}
}
Loading