public static void TestTextEqualsLargeMatch() { var jsonChars = new char[320]; // Some value larger than 256 (stack threshold) jsonChars.AsSpan().Fill('a'); byte[] lookup = Encoding.UTF8.GetBytes(jsonChars); ReadOnlySpan <char> escapedA = new char[6] { '\\', 'u', '0', '0', '6', '1' }; ReadOnlySpan <byte> lookupSpan = lookup.AsSpan(0, lookup.Length - escapedA.Length + 1); // remove extra characters that were replaced by escaped bytes Span <char> lookupChars = new char[jsonChars.Length]; jsonChars.CopyTo(lookupChars); lookupChars = lookupChars.Slice(0, lookupChars.Length - escapedA.Length + 1); // Replacing 'a' with '\u0061', so a net change of 5. // escapedA.Length - 1 = 6 - 1 = 5 for (int i = 0; i < jsonChars.Length - escapedA.Length + 1; i++) { jsonChars.AsSpan().Fill('a'); escapedA.CopyTo(jsonChars.AsSpan(i)); string jsonString = "\"" + new string(jsonChars) + "\""; byte[] utf8Data = Encoding.UTF8.GetBytes(jsonString); bool found = false; var json = new Utf8JsonReader(utf8Data, isFinalBlock: true, state: default); while (json.Read()) { if (json.TokenType == JsonTokenType.String) { if (json.ValueTextEquals(lookupSpan) && json.ValueTextEquals(lookupChars) && json.ValueTextEquals(new string(lookupChars.ToArray()))) { found = true; break; } } } Assert.True(found, $"Json String: {jsonString}"); ReadOnlySequence <byte> sequence = JsonTestHelper.GetSequence(utf8Data, 1); found = false; json = new Utf8JsonReader(sequence, isFinalBlock: true, state: default); while (json.Read()) { if (json.TokenType == JsonTokenType.String) { if (json.ValueTextEquals(lookupSpan) && json.ValueTextEquals(lookupChars) && json.ValueTextEquals(new string(lookupChars.ToArray()))) { found = true; break; } } } Assert.True(found, $"Json String: {jsonString} | Look up: {Encoding.UTF8.GetString(lookupSpan.ToArray())}"); } }
public static void CheckOnlyOneOfValueSpanOrSequenceIsSet(int testCase, string jsonString) { byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString); bool[] expectedHasValueSequence = null; bool[] expectedHasValueSequenceSkip = null; bool[] expectedHasValueSequenceAllow = null; ReadOnlySequence <byte> sequence; switch (testCase) { case 0: Debug.Assert(dataUtf8.Length == 95); byte[][] buffers = new byte[6][]; buffers[0] = dataUtf8.AsSpan(0, 10).ToArray(); buffers[1] = dataUtf8.AsSpan(10, 28).ToArray(); buffers[2] = dataUtf8.AsSpan(38, 32).ToArray(); buffers[3] = dataUtf8.AsSpan(70, 23).ToArray(); buffers[4] = dataUtf8.AsSpan(93, 1).ToArray(); buffers[5] = dataUtf8.AsSpan(94, 1).ToArray(); sequence = BufferFactory.Create(buffers); expectedHasValueSequence = new bool [] { false, true, false, false, true, false, true, false, false, false, false, false }; break; case 1: Debug.Assert(dataUtf8.Length == 97); buffers = new byte[7][]; buffers[0] = dataUtf8.AsSpan(0, 39).ToArray(); buffers[1] = dataUtf8.AsSpan(39, 22).ToArray(); buffers[2] = dataUtf8.AsSpan(61, 18).ToArray(); buffers[3] = dataUtf8.AsSpan(79, 7).ToArray(); buffers[4] = dataUtf8.AsSpan(86, 7).ToArray(); buffers[5] = dataUtf8.AsSpan(93, 3).ToArray(); buffers[6] = dataUtf8.AsSpan(96, 1).ToArray(); sequence = BufferFactory.Create(buffers); expectedHasValueSequence = new bool[] { false, false, false, false, false, true, true, false, true, true, true, false, false, false }; break; case 2: Debug.Assert(dataUtf8.Length == 90); buffers = new byte[5][]; buffers[0] = dataUtf8.AsSpan(0, 36).ToArray(); buffers[1] = dataUtf8.AsSpan(36, 13).ToArray(); buffers[2] = dataUtf8.AsSpan(49, 30).ToArray(); buffers[3] = dataUtf8.AsSpan(79, 9).ToArray(); buffers[4] = dataUtf8.AsSpan(88, 2).ToArray(); sequence = BufferFactory.Create(buffers); expectedHasValueSequenceSkip = new bool[] { false, false, false, true, false, false }; expectedHasValueSequenceAllow = new bool[] { false, false, false, true, true, true, false, false }; break; default: return; } foreach (JsonCommentHandling commentHandling in Enum.GetValues(typeof(JsonCommentHandling))) { if (commentHandling == JsonCommentHandling.Disallow && testCase == 2) { continue; } var state = new JsonReaderState(options: new JsonReaderOptions { CommentHandling = commentHandling }); var json = new Utf8JsonReader(sequence, isFinalBlock: true, state); int index = 0; while (json.Read()) { if (testCase == 0 || testCase == 1) { Assert.True(expectedHasValueSequence[index] == json.HasValueSequence, $"{commentHandling}, {testCase}, {index}, {json.HasValueSequence}"); } else { if (commentHandling == JsonCommentHandling.Skip) { Assert.True(expectedHasValueSequenceSkip[index] == json.HasValueSequence, $"{commentHandling}, {testCase}, {index}, {json.HasValueSequence}"); } else { Assert.True(expectedHasValueSequenceAllow[index] == json.HasValueSequence, $"{commentHandling}, {testCase}, {index}, {json.HasValueSequence}"); } } if (json.HasValueSequence) { Assert.True(json.ValueSpan == default, $"Escaped ValueSpan to be empty when HasValueSequence is true. Test case: {testCase}"); Assert.False(json.ValueSequence.IsEmpty, $"Escaped ValueSequence to not be empty when HasValueSequence is true. Test case: {testCase}"); } else { Assert.True(json.ValueSequence.IsEmpty, $"Escaped ValueSequence to be empty when HasValueSequence is false. Test case: {testCase}"); Assert.False(json.ValueSpan == default, $"Escaped ValueSpan to not be empty when HasValueSequence is false. Test case: {testCase}"); } index++; } } }
public Span <byte> GetSpan(int minimumLength = 0) => _buffer.AsSpan(_count);