Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -504,6 +504,7 @@ public bool Equals(JsonSerializerOptions? left, JsonSerializerOptions? right)
left._unmappedMemberHandling == right._unmappedMemberHandling &&
left._defaultBufferSize == right._defaultBufferSize &&
left._maxDepth == right._maxDepth &&
left._newLine == right._newLine &&
left._allowOutOfOrderMetadataProperties == right._allowOutOfOrderMetadataProperties &&
left._allowTrailingCommas == right._allowTrailingCommas &&
left._ignoreNullValues == right._ignoreNullValues &&
Expand Down Expand Up @@ -561,6 +562,7 @@ public int GetHashCode(JsonSerializerOptions options)
AddHashCode(ref hc, options._unmappedMemberHandling);
AddHashCode(ref hc, options._defaultBufferSize);
AddHashCode(ref hc, options._maxDepth);
AddHashCode(ref hc, options._newLine ?? Environment.NewLine); // Null is equivalent to the default
AddHashCode(ref hc, options._allowOutOfOrderMetadataProperties);
AddHashCode(ref hc, options._allowTrailingCommas);
AddHashCode(ref hc, options._ignoreNullValues);
Expand Down Expand Up @@ -591,7 +593,7 @@ static void AddListHashCode<TValue>(ref HashCode hc, ConfigurationList<TValue>?

static void AddHashCode<TValue>(ref HashCode hc, TValue? value)
{
if (typeof(TValue).IsValueType)
if (typeof(TValue).IsValueType || typeof(TValue) == typeof(string))
{
hc.Add(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public static JsonSerializerOptions Web
private bool _ignoreReadOnlyProperties;
private bool _ignoreReadonlyFields;
private bool _includeFields;
private string _newLine = Environment.NewLine;
private string? _newLine;
private bool _propertyNameCaseInsensitive;
private bool _writeIndented;
private char _indentCharacter = JsonConstants.DefaultIndentCharacter;
Expand Down Expand Up @@ -766,7 +766,7 @@ public string NewLine
{
get
{
return _newLine;
return _newLine ??= Environment.NewLine;
}
set
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static void WriteIndentation(Span<byte> buffer, int indent, byte indentBy
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidateNewLine(string value)
{
if (value is not JsonConstants.NewLineLineFeed and not JsonConstants.NewLineCarriageReturnLineFeed)
if (value is not null && value is not JsonConstants.NewLineLineFeed and not JsonConstants.NewLineCarriageReturnLineFeed)
ThrowHelper.ThrowArgumentOutOfRangeException_NewLine(nameof(value));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public string NewLine
set
{
JsonWriterHelper.ValidateNewLine(value);
if (value != Environment.NewLine)
if (value is not null && value != Environment.NewLine)
_optionsMask |= NewLineBit;
else
_optionsMask &= ~NewLineBit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ namespace System.Text.Json
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable
{
// Depending on OS, either '\r\n' OR '\n'
private static readonly int s_defaultNewLineLength = Environment.NewLine.Length;

private const int DefaultGrowthSize = 4096;
private const int InitialGrowthSize = 256;

Expand All @@ -61,7 +58,9 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable
// Cache indentation settings from JsonWriterOptions to avoid recomputing them in the hot path.
private byte _indentByte;
private int _indentLength;
private int _newLineLength = s_defaultNewLineLength;

// A length of 1 will emit LF for indented writes, a length of 2 will emit CRLF. Other values are invalid.
private int _newLineLength;

/// <summary>
/// Returns the amount of bytes written by the <see cref="Utf8JsonWriter"/> so far
Expand Down Expand Up @@ -151,6 +150,8 @@ private void SetOptions(JsonWriterOptions options)
_options = options;
_indentByte = (byte)_options.IndentCharacter;
_indentLength = options.IndentSize;

Debug.Assert(options.NewLine is "\n" or "\r\n", "Invalid NewLine string.");
_newLineLength = options.NewLine.Length;

if (_options.MaxDepth == 0)
Expand Down Expand Up @@ -1025,7 +1026,8 @@ private void WriteEndIndented(byte token)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void WriteNewLine(Span<byte> output)
{
// Write '\r\n' OR '\n', depending on OS
// Write '\r\n' OR '\n', depending on the configured new line string
Debug.Assert(_newLineLength is 1 or 2, "Invalid new line length.");
if (_newLineLength == 2)
{
output[BytesPending++] = JsonConstants.CarriageReturn;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,27 @@ public static void JsonWriterOptions_IndentSize_OutOfRange(int size)
[InlineData("\r")]
[InlineData("\n\n")]
[InlineData("\r\n\r\n")]
[InlineData("0")]
[InlineData("a")]
[InlineData("foo")]
[InlineData("$")]
[InlineData(".")]
[InlineData("\u03b1")]
public static void JsonWriterOptions_NewLine_InvalidNewLine(string value)
{
var options = new JsonWriterOptions();
Assert.Throws<ArgumentOutOfRangeException>(() => options.NewLine = value);
}

[Fact]
public static void JsonWriterOptions_NewLine_Null_Resets_To_Default()
{
var options = new JsonWriterOptions();

options.NewLine = "\n";
options.NewLine = null!;

Assert.Equal(Environment.NewLine, options.NewLine);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ public static void JsonSerializerOptions_EqualityComparer_ChangingAnySettingShou
yield return (GetProp(nameof(JsonSerializerOptions.IgnoreReadOnlyFields)), true);
yield return (GetProp(nameof(JsonSerializerOptions.IncludeFields)), true);
yield return (GetProp(nameof(JsonSerializerOptions.MaxDepth)), 11);
yield return (GetProp(nameof(JsonSerializerOptions.NewLine)), Environment.NewLine);
yield return (GetProp(nameof(JsonSerializerOptions.NewLine)), Environment.NewLine.Length is 1 ? "\r\n" : "\n");
yield return (GetProp(nameof(JsonSerializerOptions.PropertyNamingPolicy)), JsonNamingPolicy.CamelCase);
yield return (GetProp(nameof(JsonSerializerOptions.PropertyNameCaseInsensitive)), true);
yield return (GetProp(nameof(JsonSerializerOptions.ReadCommentHandling)), JsonCommentHandling.Skip);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,60 @@ public static void MaxDepthRead()
Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<BasicCompany>(BasicCompany.s_data, options));
}

[Theory]
[InlineData(new char[] { '\n' }, '\r')]
[InlineData(new char[] { '\r', '\n' }, null)]
public static void NewLine(char[] newLineChars, char? notExpectedNewLineChars)
{
var obj = new BasicCompany();
obj.Initialize();

var newLine = new string(newLineChars);
var options = new JsonSerializerOptions();
var json = JsonSerializer.Serialize(obj, options);
Assert.DoesNotContain(newLine, json);

// Set custom newLine with indentation enabled
options = new JsonSerializerOptions();
options.WriteIndented = true;
options.NewLine = newLine;
json = JsonSerializer.Serialize(obj, options);
Assert.Contains(newLine, json);

if (notExpectedNewLineChars is { } notExpected)
{
Assert.DoesNotContain(notExpected, json);
}
}

[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData("\r")]
[InlineData("\n\n")]
[InlineData("\r\n\r\n")]
[InlineData("0")]
[InlineData("a")]
[InlineData("foo")]
[InlineData("$")]
[InlineData(".")]
[InlineData("\u03b1")]
public static void TestNewLineInvalid(string value)
{
var options = new JsonSerializerOptions();
Assert.Throws<ArgumentOutOfRangeException>("value", () => options.NewLine = value);
}

[Fact]
public static void TestNewLineNullResetsToDefault()
{
var options = new JsonSerializerOptions();
options.NewLine = "\n";
options.NewLine = null!;

Assert.Equal(Environment.NewLine, options.NewLine);
}

private class TestClassForEncoding
{
public string MyString { get; set; }
Expand Down Expand Up @@ -1416,7 +1470,7 @@ and not nameof(JsonSerializerOptions.IsReadOnly)) // Property is not structural
}
else if (propertyType == typeof(string))
{
if (property.Name is "NewLine")
if (property.Name is nameof(JsonSerializerOptions.NewLine))
{
property.SetValue(options, "\n");
}
Expand Down