diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonEncodedTextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonEncodedTextTests.cs index 0da487f9d42993..8ea5600314b2e7 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonEncodedTextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonEncodedTextTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Text.Encodings.Web; using System.Text.Unicode; +using Microsoft.DotNet.XUnitExtensions; using Xunit; namespace System.Text.Json.Tests @@ -235,7 +236,7 @@ public static void ToStringLargeTest(int stringLength) } { var message = new string('>', stringLength); - var builder = new StringBuilder(); + var builder = new StringBuilder(stringLength); for (int i = 0; i < stringLength; i++) { builder.Append("\\u003E"); @@ -302,7 +303,7 @@ public static void GetUtf8BytesLargeTest(int stringLength) } { var message = new string('>', stringLength); - var builder = new StringBuilder(); + var builder = new StringBuilder(stringLength); for (int i = 0; i < stringLength; i++) { builder.Append("\\u003E"); @@ -362,7 +363,7 @@ public static void GetValueLargeTest(int stringLength) public static void GetValueLargeEscapedTest(int stringLength) { var message = new string('>', stringLength); - var builder = new StringBuilder(); + var builder = new StringBuilder(stringLength); for (int i = 0; i < stringLength; i++) { builder.Append("\\u003E"); @@ -426,7 +427,7 @@ public static void InvalidLargeEncode() } catch (OutOfMemoryException) { - return; + throw new SkipTestException("Out of memory allocating large objects"); } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Object.WriteTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Object.WriteTests.cs index 77e73dd62722a1..23461cab96a250 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Object.WriteTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Object.WriteTests.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text.Encodings.Web; using System.Text.Json.Tests; +using Microsoft.DotNet.XUnitExtensions; using Xunit; namespace System.Text.Json.Serialization.Tests @@ -161,42 +162,49 @@ public static void WriteObjectWithNumberHandling() [OuterLoop] public static void SerializeLargeListOfObjects() { - Dto dto = new() - { - Prop1 = int.MaxValue, - Prop2 = int.MinValue, - Prop3 = "AC", - Prop4 = 500, - Prop5 = int.MaxValue / 2, - Prop6 = 250M, - Prop7 = 250M, - Prop8 = 250M, - Prop9 = 250M, - Prop10 = 250M, - Prop11 = 150M, - Prop12 = 150M, - Prop13 = DateTimeOffset.MaxValue, - Prop14 = DateTimeOffset.MaxValue, - Prop15 = DateTimeOffset.MaxValue, - Prop16 = DateTimeOffset.MaxValue, - Prop17 = 3, - Prop18 = DateTime.MaxValue, - Prop19 = DateTime.MaxValue, - Prop20 = 25000, - Prop21 = DateTime.MaxValue - }; - - // It takes a little over 4,338,000 items to reach a payload size above the Array.MaxLength value. - List items = Enumerable.Repeat(dto, 4_338_000).ToList(); - try { - JsonSerializer.SerializeToUtf8Bytes(items); + Dto dto = new() + { + Prop1 = int.MaxValue, + Prop2 = int.MinValue, + Prop3 = "AC", + Prop4 = 500, + Prop5 = int.MaxValue / 2, + Prop6 = 250M, + Prop7 = 250M, + Prop8 = 250M, + Prop9 = 250M, + Prop10 = 250M, + Prop11 = 150M, + Prop12 = 150M, + Prop13 = DateTimeOffset.MaxValue, + Prop14 = DateTimeOffset.MaxValue, + Prop15 = DateTimeOffset.MaxValue, + Prop16 = DateTimeOffset.MaxValue, + Prop17 = 3, + Prop18 = DateTime.MaxValue, + Prop19 = DateTime.MaxValue, + Prop20 = 25000, + Prop21 = DateTime.MaxValue + }; + + // It takes a little over 4,338,000 items to reach a payload size above the Array.MaxLength value. + List items = Enumerable.Repeat(dto, 4_338_000).ToList(); + + try + { + JsonSerializer.SerializeToUtf8Bytes(items); + } + catch (OutOfMemoryException) { } + + items.AddRange(Enumerable.Repeat(dto, 1000).ToList()); + Assert.Throws(() => JsonSerializer.SerializeToUtf8Bytes(items)); + } + catch (OutOfMemoryException) + { + throw new SkipTestException("Out of memory allocating large objects"); } - catch (OutOfMemoryException) { } - - items.AddRange(Enumerable.Repeat(dto, 1000).ToList()); - Assert.Throws(() => JsonSerializer.SerializeToUtf8Bytes(items)); } class Dto diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs index 8063896b761a18..437acca92b09b2 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Value.ReadTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Globalization; using System.Runtime.CompilerServices; +using Microsoft.DotNet.XUnitExtensions; using Newtonsoft.Json; using Xunit; @@ -453,8 +454,15 @@ public static void LongInputString(int length) [OuterLoop] public static void VeryLongInputString(int length) { - // Verify that deserializer does not do any multiplication or addition on the string length - DeserializeLongJsonString(length); + try + { + // Verify that deserializer does not do any multiplication or addition on the string length + DeserializeLongJsonString(length); + } + catch (OutOfMemoryException) + { + throw new SkipTestException("Out of memory allocating large objects"); + } } private static void DeserializeLongJsonString(int stringLength) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.cs index 0be0fc7dcb1b24..0dd0b296102f31 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonReaderTests.cs @@ -3038,7 +3038,7 @@ public static void JsonContainingOnlyCommentsIsInvalid(string jsonString, int ex [MemberData(nameof(LotsOfCommentsTests))] public static void SkipLotsOfComments(string valueString, bool insideArray, string expectedString) { - var builder = new StringBuilder(); + var builder = new StringBuilder(2_000_000); if (insideArray) { builder.Append("["); @@ -3116,7 +3116,7 @@ public static void SkipLotsOfComments(string valueString, bool insideArray, stri [MemberData(nameof(LotsOfCommentsTests))] public static void ConsumeLotsOfComments(string valueString, bool insideArray, string expectedString) { - var builder = new StringBuilder(); + var builder = new StringBuilder(2_000_000); if (insideArray) { builder.Append("["); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs index 90ce2009d1542e..f24035cf21ca54 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.DotNet.XUnitExtensions; using Xunit; namespace System.Text.Json.Tests @@ -347,46 +348,53 @@ private static string GenerateJsonUsingDepth(int depth) [OuterLoop] public void WriteRawLargeJsonToStreamWithoutFlushing() { - var largeArray = new char[150_000_000]; - largeArray.AsSpan().Fill('a'); - - // Text size chosen so that after several doublings of the underlying buffer we reach ~2 GB (but don't go over) - JsonEncodedText text1 = JsonEncodedText.Encode(largeArray.AsSpan(0, 7_500)); - JsonEncodedText text2 = JsonEncodedText.Encode(largeArray.AsSpan(0, 5_000)); - JsonEncodedText text3 = JsonEncodedText.Encode(largeArray.AsSpan(0, 150_000_000)); - - using (var output = new MemoryStream()) - using (var writer = new Utf8JsonWriter(output)) + try { - writer.WriteStartArray(); - writer.WriteRawValue(WrapInQuotes(text1.EncodedUtf8Bytes)); - Assert.Equal(7_503, writer.BytesPending); + var largeArray = new char[150_000_000]; + largeArray.AsSpan().Fill('a'); - for (int i = 0; i < 30_000; i++) - { - writer.WriteRawValue(WrapInQuotes(text2.EncodedUtf8Bytes)); - } - Assert.Equal(150_097_503, writer.BytesPending); + // Text size chosen so that after several doublings of the underlying buffer we reach ~2 GB (but don't go over) + JsonEncodedText text1 = JsonEncodedText.Encode(largeArray.AsSpan(0, 7_500)); + JsonEncodedText text2 = JsonEncodedText.Encode(largeArray.AsSpan(0, 5_000)); + JsonEncodedText text3 = JsonEncodedText.Encode(largeArray.AsSpan(0, 150_000_000)); - for (int i = 0; i < 13; i++) + using (var output = new MemoryStream()) + using (var writer = new Utf8JsonWriter(output)) { - writer.WriteRawValue(WrapInQuotes(text3.EncodedUtf8Bytes)); - } - Assert.Equal(2_100_097_542, writer.BytesPending); + writer.WriteStartArray(); + writer.WriteRawValue(WrapInQuotes(text1.EncodedUtf8Bytes)); + Assert.Equal(7_503, writer.BytesPending); - // Next write forces a grow beyond max array length + for (int i = 0; i < 30_000; i++) + { + writer.WriteRawValue(WrapInQuotes(text2.EncodedUtf8Bytes)); + } + Assert.Equal(150_097_503, writer.BytesPending); - Assert.Throws(() => writer.WriteRawValue(WrapInQuotes(text3.EncodedUtf8Bytes))); + for (int i = 0; i < 13; i++) + { + writer.WriteRawValue(WrapInQuotes(text3.EncodedUtf8Bytes)); + } + Assert.Equal(2_100_097_542, writer.BytesPending); - Assert.Equal(2_100_097_542, writer.BytesPending); + // Next write forces a grow beyond max array length - var text4 = JsonEncodedText.Encode(largeArray.AsSpan(0, 1)); - for (int i = 0; i < 10_000_000; i++) - { - writer.WriteRawValue(WrapInQuotes(text4.EncodedUtf8Bytes)); - } + Assert.Throws(() => writer.WriteRawValue(WrapInQuotes(text3.EncodedUtf8Bytes))); + + Assert.Equal(2_100_097_542, writer.BytesPending); + + var text4 = JsonEncodedText.Encode(largeArray.AsSpan(0, 1)); + for (int i = 0; i < 10_000_000; i++) + { + writer.WriteRawValue(WrapInQuotes(text4.EncodedUtf8Bytes)); + } - Assert.Equal(2_100_097_542 + (4 * 10_000_000), writer.BytesPending); + Assert.Equal(2_100_097_542 + (4 * 10_000_000), writer.BytesPending); + } + } + catch (OutOfMemoryException) + { + throw new SkipTestException("Out of memory allocating large objects"); } } @@ -398,63 +406,70 @@ public void WriteRawLargeJsonToStreamWithoutFlushing() [InlineData(JsonTokenType.StartObject)] public static void WriteRawMaxUtf16InputLength(JsonTokenType tokenType) { - // Max raw payload length supported by the writer. - int maxLength = int.MaxValue / 3; - - StringBuilder sb = new(); - sb.Append('"'); - - for (int i = 1; i < maxLength - 1; i++) + try { - sb.Append('a'); - } + // Max raw payload length supported by the writer. + int maxLength = int.MaxValue / 3; - sb.Append('"'); + StringBuilder sb = new(maxLength + 2); + sb.Append('"'); - string payload = sb.ToString(); + for (int i = 1; i < maxLength - 1; i++) + { + sb.Append('a'); + } - RunTest(OverloadParamType.ROSChar); - RunTest(OverloadParamType.String); - RunTest(OverloadParamType.ByteArray); - RunTest(OverloadParamType.ROSeqByte); + sb.Append('"'); - void RunTest(OverloadParamType paramType) - { - using MemoryStream ms = new(); - using Utf8JsonWriter writer = new(ms); + string payload = sb.ToString(); + + RunTest(OverloadParamType.ROSChar); + RunTest(OverloadParamType.String); + RunTest(OverloadParamType.ByteArray); + RunTest(OverloadParamType.ROSeqByte); - switch (tokenType) + void RunTest(OverloadParamType paramType) { - case JsonTokenType.String: - WriteRawValueWithSetting(writer, payload, paramType); - writer.Flush(); - Assert.Equal(payload.Length, writer.BytesCommitted); - break; - case JsonTokenType.StartArray: - writer.WriteStartArray(); - WriteRawValueWithSetting(writer, payload, paramType); - WriteRawValueWithSetting(writer, payload, paramType); - writer.WriteEndArray(); - writer.Flush(); - // Start/EndArray + comma, 2 array elements - Assert.Equal(3 + (payload.Length * 2), writer.BytesCommitted); - break; - case JsonTokenType.StartObject: - writer.WriteStartObject(); - writer.WritePropertyName("1"); - WriteRawValueWithSetting(writer, payload, paramType); - writer.WritePropertyName("2"); - WriteRawValueWithSetting(writer, payload, paramType); - writer.WriteEndObject(); - writer.Flush(); - // Start/EndToken + comma, 2 property names, 2 property values - Assert.Equal(3 + (4 * 2) + (payload.Length * 2), writer.BytesCommitted); - break; - default: - Assert.True(false, "Unexpected test configuration"); - break; + using MemoryStream ms = new(); + using Utf8JsonWriter writer = new(ms); + + switch (tokenType) + { + case JsonTokenType.String: + WriteRawValueWithSetting(writer, payload, paramType); + writer.Flush(); + Assert.Equal(payload.Length, writer.BytesCommitted); + break; + case JsonTokenType.StartArray: + writer.WriteStartArray(); + WriteRawValueWithSetting(writer, payload, paramType); + WriteRawValueWithSetting(writer, payload, paramType); + writer.WriteEndArray(); + writer.Flush(); + // Start/EndArray + comma, 2 array elements + Assert.Equal(3 + (payload.Length * 2), writer.BytesCommitted); + break; + case JsonTokenType.StartObject: + writer.WriteStartObject(); + writer.WritePropertyName("1"); + WriteRawValueWithSetting(writer, payload, paramType); + writer.WritePropertyName("2"); + WriteRawValueWithSetting(writer, payload, paramType); + writer.WriteEndObject(); + writer.Flush(); + // Start/EndToken + comma, 2 property names, 2 property values + Assert.Equal(3 + (4 * 2) + (payload.Length * 2), writer.BytesCommitted); + break; + default: + Assert.True(false, "Unexpected test configuration"); + break; + } } } + catch (OutOfMemoryException) + { + throw new SkipTestException("Out of memory allocating large objects"); + } } private enum OverloadParamType @@ -493,35 +508,42 @@ private static void WriteRawValueWithSetting(Utf8JsonWriter writer, string paylo [OuterLoop] public static void WriteRawUtf16LengthGreaterThanMax(int len) { - StringBuilder sb = new(); - sb.Append('"'); - - for (int i = 1; i < len - 1; i++) + try { - sb.Append('a'); - } + StringBuilder sb = new(len + 2); + sb.Append('"'); - sb.Append('"'); + for (int i = 1; i < len - 1; i++) + { + sb.Append('a'); + } - string payload = sb.ToString(); + sb.Append('"'); - using MemoryStream ms = new(); - using Utf8JsonWriter writer = new(ms); + string payload = sb.ToString(); - // UTF-16 overloads not compatible with this length. - Assert.Throws(() => WriteRawValueWithSetting(writer, payload, OverloadParamType.ROSChar)); - Assert.Throws(() => WriteRawValueWithSetting(writer, payload, OverloadParamType.String)); + using MemoryStream ms = new(); + using Utf8JsonWriter writer = new(ms); - // UTF-8 overload is okay. - WriteRawValueWithSetting(writer, payload, OverloadParamType.ByteArray); - writer.Flush(); - Assert.Equal(payload.Length, Encoding.UTF8.GetString(ms.ToArray()).Length); + // UTF-16 overloads not compatible with this length. + Assert.Throws(() => WriteRawValueWithSetting(writer, payload, OverloadParamType.ROSChar)); + Assert.Throws(() => WriteRawValueWithSetting(writer, payload, OverloadParamType.String)); - writer.Reset(); - ms.SetLength(0); - WriteRawValueWithSetting(writer, payload, OverloadParamType.ROSeqByte); - writer.Flush(); - Assert.Equal(payload.Length, Encoding.UTF8.GetString(ms.ToArray()).Length); + // UTF-8 overload is okay. + WriteRawValueWithSetting(writer, payload, OverloadParamType.ByteArray); + writer.Flush(); + Assert.Equal(payload.Length, Encoding.UTF8.GetString(ms.ToArray()).Length); + + writer.Reset(); + ms.SetLength(0); + WriteRawValueWithSetting(writer, payload, OverloadParamType.ROSeqByte); + writer.Flush(); + Assert.Equal(payload.Length, Encoding.UTF8.GetString(ms.ToArray()).Length); + } + catch (OutOfMemoryException) + { + throw new SkipTestException("Out of memory allocating large objects"); + } } [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.OSX)] @@ -538,7 +560,10 @@ public void WriteRawUtf8LengthGreaterThanOrEqualToIntMax(long len) ReadOnlySequence readonlySeq = CreateLargeReadOnlySequence(len); Assert.Throws(() => writer.WriteRawValue(readonlySeq)); } - catch (OutOfMemoryException) { } // Perhaps failed to allocate large arrays + catch (OutOfMemoryException) + { + throw new SkipTestException("Out of memory allocating large objects"); + } } [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.OSX)] @@ -546,41 +571,48 @@ public void WriteRawUtf8LengthGreaterThanOrEqualToIntMax(long len) [OuterLoop] public static void WriteRawTranscodeFromUtf16ToUtf8TooLong() { - // Max raw payload length supported by the writer. - int maxLength = int.MaxValue / 3; - - StringBuilder sb = new(); - sb.Append('"'); - - for (int i = 1; i < maxLength - 1; i++) + try { - sb.Append('\u7684'); // Non-UTF-8 character than will expand during transcoding - } + // Max raw payload length supported by the writer. + int maxLength = int.MaxValue / 3; - sb.Append('"'); + StringBuilder sb = new(maxLength + 2); + sb.Append('"'); - string payload = sb.ToString(); + for (int i = 1; i < maxLength - 1; i++) + { + sb.Append('\u7684'); // Non-UTF-8 character than will expand during transcoding + } - RunTest(OverloadParamType.ROSChar); - RunTest(OverloadParamType.String); - RunTest(OverloadParamType.ByteArray); - RunTest(OverloadParamType.ROSeqByte); + sb.Append('"'); - void RunTest(OverloadParamType paramType) - { - using MemoryStream ms = new(); - using Utf8JsonWriter writer = new(ms); + string payload = sb.ToString(); + + RunTest(OverloadParamType.ROSChar); + RunTest(OverloadParamType.String); + RunTest(OverloadParamType.ByteArray); + RunTest(OverloadParamType.ROSeqByte); - try + void RunTest(OverloadParamType paramType) { - WriteRawValueWithSetting(writer, payload, paramType); - writer.Flush(); + using MemoryStream ms = new(); + using Utf8JsonWriter writer = new(ms); + + try + { + WriteRawValueWithSetting(writer, payload, paramType); + writer.Flush(); - // All characters in the payload will be expanded during transcoding, except for the quotes. - int expectedLength = ((payload.Length - 2) * 3) + 2; - Assert.Equal(expectedLength, writer.BytesCommitted); + // All characters in the payload will be expanded during transcoding, except for the quotes. + int expectedLength = ((payload.Length - 2) * 3) + 2; + Assert.Equal(expectedLength, writer.BytesCommitted); + } + catch (OutOfMemoryException) { } // OutOfMemoryException is okay since the transcoding output is probably too large. } - catch (OutOfMemoryException) { } // OutOfMemoryException is okay since the transcoding output is probably too large. + } + catch (OutOfMemoryException) + { + throw new SkipTestException("Out of memory allocating large objects"); } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs index e625db93ab6742..ea3ee054f628a1 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.cs @@ -785,46 +785,53 @@ private static string GetExpectedLargeArrayOfStrings(int length) [OuterLoop] public void WriteLargeJsonToStreamWithoutFlushing() { - var largeArray = new char[150_000_000]; - largeArray.AsSpan().Fill('a'); - - // Text size chosen so that after several doublings of the underlying buffer we reach ~2 GB (but don't go over) - JsonEncodedText text1 = JsonEncodedText.Encode(largeArray.AsSpan(0, 7_500)); - JsonEncodedText text2 = JsonEncodedText.Encode(largeArray.AsSpan(0, 5_000)); - JsonEncodedText text3 = JsonEncodedText.Encode(largeArray.AsSpan(0, 150_000_000)); - - using (var output = new MemoryStream()) - using (var writer = new Utf8JsonWriter(output)) + try { - writer.WriteStartArray(); - writer.WriteStringValue(text1); - Assert.Equal(7_503, writer.BytesPending); + var largeArray = new char[150_000_000]; + largeArray.AsSpan().Fill('a'); - for (int i = 0; i < 30_000; i++) - { - writer.WriteStringValue(text2); - } - Assert.Equal(150_097_503, writer.BytesPending); + // Text size chosen so that after several doublings of the underlying buffer we reach ~2 GB (but don't go over) + JsonEncodedText text1 = JsonEncodedText.Encode(largeArray.AsSpan(0, 7_500)); + JsonEncodedText text2 = JsonEncodedText.Encode(largeArray.AsSpan(0, 5_000)); + JsonEncodedText text3 = JsonEncodedText.Encode(largeArray.AsSpan(0, 150_000_000)); - for (int i = 0; i < 13; i++) + using (var output = new MemoryStream()) + using (var writer = new Utf8JsonWriter(output)) { - writer.WriteStringValue(text3); - } - Assert.Equal(2_100_097_542, writer.BytesPending); + writer.WriteStartArray(); + writer.WriteStringValue(text1); + Assert.Equal(7_503, writer.BytesPending); - // Next write forces a grow beyond max array length + for (int i = 0; i < 30_000; i++) + { + writer.WriteStringValue(text2); + } + Assert.Equal(150_097_503, writer.BytesPending); - Assert.Throws(() => writer.WriteStringValue(text3)); + for (int i = 0; i < 13; i++) + { + writer.WriteStringValue(text3); + } + Assert.Equal(2_100_097_542, writer.BytesPending); - Assert.Equal(2_100_097_542, writer.BytesPending); + // Next write forces a grow beyond max array length - var text4 = JsonEncodedText.Encode(largeArray.AsSpan(0, 1)); - for (int i = 0; i < 10_000_000; i++) - { - writer.WriteStringValue(text4); - } + Assert.Throws(() => writer.WriteStringValue(text3)); + + Assert.Equal(2_100_097_542, writer.BytesPending); + + var text4 = JsonEncodedText.Encode(largeArray.AsSpan(0, 1)); + for (int i = 0; i < 10_000_000; i++) + { + writer.WriteStringValue(text4); + } - Assert.Equal(2_100_097_542 + (4 * 10_000_000), writer.BytesPending); + Assert.Equal(2_100_097_542 + (4 * 10_000_000), writer.BytesPending); + } + } + catch (OutOfMemoryException) + { + throw new SkipTestException("Out of memory allocating large objects"); } } @@ -3016,35 +3023,35 @@ public static void CustomMaxDepth_DepthExceedingLimit_ShouldFail(int maxDepth) [InlineData(false, false)] public void WritingTooLargeProperty(bool formatted, bool skipValidation) { - byte[] key; - char[] keyChars; - try { + byte[] key; + char[] keyChars; + key = new byte[MaxUnescapedTokenSize + 1]; keyChars = new char[MaxUnescapedTokenSize + 1]; - } - catch (OutOfMemoryException) - { - return; - } - key.AsSpan().Fill((byte)'a'); - keyChars.AsSpan().Fill('a'); + key.AsSpan().Fill((byte)'a'); + keyChars.AsSpan().Fill('a'); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(1024); + var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + var output = new ArrayBufferWriter(1024); - using (var jsonUtf8 = new Utf8JsonWriter(output, options)) - { - jsonUtf8.WriteStartObject(); - Assert.Throws(() => jsonUtf8.WriteStartArray(keyChars)); - } + using (var jsonUtf8 = new Utf8JsonWriter(output, options)) + { + jsonUtf8.WriteStartObject(); + Assert.Throws(() => jsonUtf8.WriteStartArray(keyChars)); + } - using (var jsonUtf8 = new Utf8JsonWriter(output, options)) + using (var jsonUtf8 = new Utf8JsonWriter(output, options)) + { + jsonUtf8.WriteStartObject(); + Assert.Throws(() => jsonUtf8.WriteStartArray(key)); + } + } + catch (OutOfMemoryException) { - jsonUtf8.WriteStartObject(); - Assert.Throws(() => jsonUtf8.WriteStartArray(key)); + throw new SkipTestException("Out of memory allocating large objects"); } } @@ -3061,35 +3068,35 @@ public void WritingTooLargeProperty(bool formatted, bool skipValidation) [InlineData(false, false)] public void WritingTooLargePropertyStandalone(bool formatted, bool skipValidation) { - byte[] key; - char[] keyChars; - try { + byte[] key; + char[] keyChars; + key = new byte[MaxUnescapedTokenSize + 1]; keyChars = new char[MaxUnescapedTokenSize + 1]; - } - catch (OutOfMemoryException) - { - return; - } - key.AsSpan().Fill((byte)'a'); - keyChars.AsSpan().Fill('a'); + key.AsSpan().Fill((byte)'a'); + keyChars.AsSpan().Fill('a'); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - var output = new ArrayBufferWriter(1024); + var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + var output = new ArrayBufferWriter(1024); - using (var jsonUtf8 = new Utf8JsonWriter(output, options)) - { - jsonUtf8.WriteStartObject(); - Assert.Throws(() => jsonUtf8.WritePropertyName(keyChars)); - } + using (var jsonUtf8 = new Utf8JsonWriter(output, options)) + { + jsonUtf8.WriteStartObject(); + Assert.Throws(() => jsonUtf8.WritePropertyName(keyChars)); + } - using (var jsonUtf8 = new Utf8JsonWriter(output, options)) + using (var jsonUtf8 = new Utf8JsonWriter(output, options)) + { + jsonUtf8.WriteStartObject(); + Assert.Throws(() => jsonUtf8.WritePropertyName(key)); + } + } + catch (OutOfMemoryException) { - jsonUtf8.WriteStartObject(); - Assert.Throws(() => jsonUtf8.WritePropertyName(key)); + throw new SkipTestException("Out of memory allocating large objects"); } } @@ -6378,38 +6385,38 @@ public void WriteDateTimeOffsetsValue(bool formatted, bool skipValidation, strin [InlineData(false, false)] public void WriteLargeKeyOrValue(bool formatted, bool skipValidation) { - byte[] key; - byte[] value; - try { + byte[] key; + byte[] value; + key = new byte[MaxUnescapedTokenSize + 1]; value = new byte[MaxUnescapedTokenSize + 1]; - } - catch (OutOfMemoryException) - { - return; - } - key.AsSpan().Fill((byte)'a'); - value.AsSpan().Fill((byte)'b'); + key.AsSpan().Fill((byte)'a'); + value.AsSpan().Fill((byte)'b'); - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - { - var output = new ArrayBufferWriter(1024); - using var jsonUtf8 = new Utf8JsonWriter(output, options); - jsonUtf8.WriteStartObject(); - Assert.Throws(() => jsonUtf8.WriteString(key, DateTimeTestHelpers.FixedDateTimeValue)); - Assert.Equal(0, output.WrittenCount); - } + { + var output = new ArrayBufferWriter(1024); + using var jsonUtf8 = new Utf8JsonWriter(output, options); + jsonUtf8.WriteStartObject(); + Assert.Throws(() => jsonUtf8.WriteString(key, DateTimeTestHelpers.FixedDateTimeValue)); + Assert.Equal(0, output.WrittenCount); + } + { + var output = new ArrayBufferWriter(1024); + using var jsonUtf8 = new Utf8JsonWriter(output, options); + jsonUtf8.WriteStartArray(); + Assert.Throws(() => jsonUtf8.WriteStringValue(value)); + Assert.Equal(0, output.WrittenCount); + } + } + catch (OutOfMemoryException) { - var output = new ArrayBufferWriter(1024); - using var jsonUtf8 = new Utf8JsonWriter(output, options); - jsonUtf8.WriteStartArray(); - Assert.Throws(() => jsonUtf8.WriteStringValue(value)); - Assert.Equal(0, output.WrittenCount); + throw new SkipTestException("Out of memory allocating large objects"); } } @@ -6426,25 +6433,25 @@ public void WriteLargeKeyOrValue(bool formatted, bool skipValidation) [InlineData(false, false)] public void WriteLargeKeyValue(bool formatted, bool skipValidation) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - - Span key; - Span value; - try { + var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + + Span key; + Span value; + key = new byte[MaxUnescapedTokenSize + 1]; value = new byte[MaxUnescapedTokenSize + 1]; + + WriteTooLargeHelper(options, key, value); + WriteTooLargeHelper(options, key.Slice(0, MaxUnescapedTokenSize), value); + WriteTooLargeHelper(options, key, value.Slice(0, MaxUnescapedTokenSize)); + WriteTooLargeHelper(options, key.Slice(0, 10_000_000 / 3), value.Slice(0, 10_000_000 / 3), noThrow: true); } catch (OutOfMemoryException) { - return; + throw new SkipTestException("Out of memory allocating large objects"); } - - WriteTooLargeHelper(options, key, value); - WriteTooLargeHelper(options, key.Slice(0, MaxUnescapedTokenSize), value); - WriteTooLargeHelper(options, key, value.Slice(0, MaxUnescapedTokenSize)); - WriteTooLargeHelper(options, key.Slice(0, 10_000_000 / 3), value.Slice(0, 10_000_000 / 3), noThrow: true); } // NOTE: WriteLargeKeyEscapedValue test is constrained to run on Windows and MacOSX because it causes @@ -6460,23 +6467,23 @@ public void WriteLargeKeyValue(bool formatted, bool skipValidation) [InlineData(false, false)] public void WriteLargeKeyEscapedValue(bool formatted, bool skipValidation) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - - Span key; - Span value; - try { + var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + + Span key; + Span value; + // Since the byte values are 0 they will be escaped and size > MaxUnescapedTokenSize but < MaxEscapedTokenSize. key = new byte[MaxUnescapedTokenSize / 2]; value = new byte[MaxUnescapedTokenSize / 2]; + + WriteTooLargeHelper(options, key, value, noThrow: true); } catch (OutOfMemoryException) { - return; + throw new SkipTestException("Out of memory allocating large objects"); } - - WriteTooLargeHelper(options, key, value, noThrow: true); } [Theory] @@ -6854,74 +6861,74 @@ private static void WriteStringHelper(JsonEncodedText text, string expectedMessa [InlineData(false, false)] public void WriteTooLargeArguments(bool formatted, bool skipValidation) { - var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; - - byte[] bytesTooLarge; - char[] charsTooLarge; - var bytes = new byte[5]; - var chars = new char[5]; - try { + var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation }; + + byte[] bytesTooLarge; + char[] charsTooLarge; + var bytes = new byte[5]; + var chars = new char[5]; + bytesTooLarge = new byte[400_000_000]; charsTooLarge = new char[400_000_000]; - } - catch (OutOfMemoryException) - { - return; - } - bytesTooLarge.AsSpan().Fill((byte)'a'); - charsTooLarge.AsSpan().Fill('a'); - bytes.AsSpan().Fill((byte)'a'); - chars.AsSpan().Fill('a'); + bytesTooLarge.AsSpan().Fill((byte)'a'); + charsTooLarge.AsSpan().Fill('a'); + bytes.AsSpan().Fill((byte)'a'); + chars.AsSpan().Fill('a'); - var pipe = new Pipe(); - PipeWriter output = pipe.Writer; - using var jsonUtf8 = new Utf8JsonWriter(output, options); + var pipe = new Pipe(); + PipeWriter output = pipe.Writer; + using var jsonUtf8 = new Utf8JsonWriter(output, options); - jsonUtf8.WriteStartArray(); + jsonUtf8.WriteStartArray(); - Assert.Throws(() => jsonUtf8.WriteStartObject(bytesTooLarge)); - Assert.Throws(() => jsonUtf8.WriteString(bytesTooLarge, bytes)); - Assert.Throws(() => jsonUtf8.WriteString(bytes, bytesTooLarge)); - Assert.Throws(() => jsonUtf8.WriteString(bytesTooLarge, chars)); - Assert.Throws(() => jsonUtf8.WriteString(chars, bytesTooLarge)); - Assert.Throws(() => jsonUtf8.WriteString(bytesTooLarge, new DateTime(2015, 11, 9))); - Assert.Throws(() => jsonUtf8.WriteString(bytesTooLarge, new DateTimeOffset(new DateTime(2015, 11, 9)))); - Assert.Throws(() => jsonUtf8.WriteString(bytesTooLarge, Guid.NewGuid())); - Assert.Throws(() => jsonUtf8.WriteStringValue(bytesTooLarge)); - Assert.Throws(() => jsonUtf8.WriteCommentValue(bytesTooLarge)); - Assert.Throws(() => jsonUtf8.WriteNumber(bytesTooLarge, 10m)); - Assert.Throws(() => jsonUtf8.WriteNumber(bytesTooLarge, 10.1)); - Assert.Throws(() => jsonUtf8.WriteNumber(bytesTooLarge, 10.1f)); - Assert.Throws(() => jsonUtf8.WriteNumber(bytesTooLarge, 12345678901)); - Assert.Throws(() => jsonUtf8.WriteNumber(bytesTooLarge, (ulong)12345678901)); - Assert.Throws(() => jsonUtf8.WriteBoolean(bytesTooLarge, true)); - Assert.Throws(() => jsonUtf8.WriteNull(bytesTooLarge)); - Assert.Throws(() => jsonUtf8.WritePropertyName(bytesTooLarge)); - - Assert.Throws(() => jsonUtf8.WriteStartObject(charsTooLarge)); - Assert.Throws(() => jsonUtf8.WriteString(charsTooLarge, chars)); - Assert.Throws(() => jsonUtf8.WriteString(chars, charsTooLarge)); - Assert.Throws(() => jsonUtf8.WriteString(charsTooLarge, bytes)); - Assert.Throws(() => jsonUtf8.WriteString(bytes, charsTooLarge)); - Assert.Throws(() => jsonUtf8.WriteString(charsTooLarge, new DateTime(2015, 11, 9))); - Assert.Throws(() => jsonUtf8.WriteString(charsTooLarge, new DateTimeOffset(new DateTime(2015, 11, 9)))); - Assert.Throws(() => jsonUtf8.WriteString(charsTooLarge, Guid.NewGuid())); - Assert.Throws(() => jsonUtf8.WriteStringValue(charsTooLarge)); - Assert.Throws(() => jsonUtf8.WriteCommentValue(charsTooLarge)); - Assert.Throws(() => jsonUtf8.WriteNumber(charsTooLarge, 10m)); - Assert.Throws(() => jsonUtf8.WriteNumber(charsTooLarge, 10.1)); - Assert.Throws(() => jsonUtf8.WriteNumber(charsTooLarge, 10.1f)); - Assert.Throws(() => jsonUtf8.WriteNumber(charsTooLarge, 12345678901)); - Assert.Throws(() => jsonUtf8.WriteNumber(charsTooLarge, (ulong)12345678901)); - Assert.Throws(() => jsonUtf8.WriteBoolean(charsTooLarge, true)); - Assert.Throws(() => jsonUtf8.WriteNull(charsTooLarge)); - Assert.Throws(() => jsonUtf8.WritePropertyName(charsTooLarge)); + Assert.Throws(() => jsonUtf8.WriteStartObject(bytesTooLarge)); + Assert.Throws(() => jsonUtf8.WriteString(bytesTooLarge, bytes)); + Assert.Throws(() => jsonUtf8.WriteString(bytes, bytesTooLarge)); + Assert.Throws(() => jsonUtf8.WriteString(bytesTooLarge, chars)); + Assert.Throws(() => jsonUtf8.WriteString(chars, bytesTooLarge)); + Assert.Throws(() => jsonUtf8.WriteString(bytesTooLarge, new DateTime(2015, 11, 9))); + Assert.Throws(() => jsonUtf8.WriteString(bytesTooLarge, new DateTimeOffset(new DateTime(2015, 11, 9)))); + Assert.Throws(() => jsonUtf8.WriteString(bytesTooLarge, Guid.NewGuid())); + Assert.Throws(() => jsonUtf8.WriteStringValue(bytesTooLarge)); + Assert.Throws(() => jsonUtf8.WriteCommentValue(bytesTooLarge)); + Assert.Throws(() => jsonUtf8.WriteNumber(bytesTooLarge, 10m)); + Assert.Throws(() => jsonUtf8.WriteNumber(bytesTooLarge, 10.1)); + Assert.Throws(() => jsonUtf8.WriteNumber(bytesTooLarge, 10.1f)); + Assert.Throws(() => jsonUtf8.WriteNumber(bytesTooLarge, 12345678901)); + Assert.Throws(() => jsonUtf8.WriteNumber(bytesTooLarge, (ulong)12345678901)); + Assert.Throws(() => jsonUtf8.WriteBoolean(bytesTooLarge, true)); + Assert.Throws(() => jsonUtf8.WriteNull(bytesTooLarge)); + Assert.Throws(() => jsonUtf8.WritePropertyName(bytesTooLarge)); + + Assert.Throws(() => jsonUtf8.WriteStartObject(charsTooLarge)); + Assert.Throws(() => jsonUtf8.WriteString(charsTooLarge, chars)); + Assert.Throws(() => jsonUtf8.WriteString(chars, charsTooLarge)); + Assert.Throws(() => jsonUtf8.WriteString(charsTooLarge, bytes)); + Assert.Throws(() => jsonUtf8.WriteString(bytes, charsTooLarge)); + Assert.Throws(() => jsonUtf8.WriteString(charsTooLarge, new DateTime(2015, 11, 9))); + Assert.Throws(() => jsonUtf8.WriteString(charsTooLarge, new DateTimeOffset(new DateTime(2015, 11, 9)))); + Assert.Throws(() => jsonUtf8.WriteString(charsTooLarge, Guid.NewGuid())); + Assert.Throws(() => jsonUtf8.WriteStringValue(charsTooLarge)); + Assert.Throws(() => jsonUtf8.WriteCommentValue(charsTooLarge)); + Assert.Throws(() => jsonUtf8.WriteNumber(charsTooLarge, 10m)); + Assert.Throws(() => jsonUtf8.WriteNumber(charsTooLarge, 10.1)); + Assert.Throws(() => jsonUtf8.WriteNumber(charsTooLarge, 10.1f)); + Assert.Throws(() => jsonUtf8.WriteNumber(charsTooLarge, 12345678901)); + Assert.Throws(() => jsonUtf8.WriteNumber(charsTooLarge, (ulong)12345678901)); + Assert.Throws(() => jsonUtf8.WriteBoolean(charsTooLarge, true)); + Assert.Throws(() => jsonUtf8.WriteNull(charsTooLarge)); + Assert.Throws(() => jsonUtf8.WritePropertyName(charsTooLarge)); - jsonUtf8.Flush(); - Assert.Equal(1, jsonUtf8.BytesCommitted); + jsonUtf8.Flush(); + Assert.Equal(1, jsonUtf8.BytesCommitted); + } + catch (OutOfMemoryException) + { + throw new SkipTestException("Out of memory allocating large objects"); + } } [Fact]