diff --git a/src/libraries/System.Text.Json/Common/JsonConstants.cs b/src/libraries/System.Text.Json/Common/JsonConstants.cs
index 63bf065d126872..4a7209f9a4aba2 100644
--- a/src/libraries/System.Text.Json/Common/JsonConstants.cs
+++ b/src/libraries/System.Text.Json/Common/JsonConstants.cs
@@ -8,5 +8,8 @@ internal static partial class JsonConstants
// Standard format for double and single on non-inbox frameworks.
public const string DoubleFormatString = "G17";
public const string SingleFormatString = "G9";
+
+ public const int StackallocByteThreshold = 256;
+ public const int StackallocCharThreshold = StackallocByteThreshold / 2;
}
}
diff --git a/src/libraries/System.Text.Json/Common/JsonKebabCaseLowerNamingPolicy.cs b/src/libraries/System.Text.Json/Common/JsonKebabCaseLowerNamingPolicy.cs
new file mode 100644
index 00000000000000..ebb380d34dd63d
--- /dev/null
+++ b/src/libraries/System.Text.Json/Common/JsonKebabCaseLowerNamingPolicy.cs
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Text.Json
+{
+ internal sealed class JsonKebabCaseLowerNamingPolicy : JsonSeparatorNamingPolicy
+ {
+ public JsonKebabCaseLowerNamingPolicy()
+ : base(lowercase: true, separator: '-')
+ {
+ }
+ }
+}
diff --git a/src/libraries/System.Text.Json/Common/JsonKebabCaseUpperNamingPolicy.cs b/src/libraries/System.Text.Json/Common/JsonKebabCaseUpperNamingPolicy.cs
new file mode 100644
index 00000000000000..1bd58a6e0b07fb
--- /dev/null
+++ b/src/libraries/System.Text.Json/Common/JsonKebabCaseUpperNamingPolicy.cs
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Text.Json
+{
+ internal sealed class JsonKebabCaseUpperNamingPolicy : JsonSeparatorNamingPolicy
+ {
+ public JsonKebabCaseUpperNamingPolicy()
+ : base(lowercase: false, separator: '-')
+ {
+ }
+ }
+}
diff --git a/src/libraries/System.Text.Json/Common/JsonKnownNamingPolicy.cs b/src/libraries/System.Text.Json/Common/JsonKnownNamingPolicy.cs
index 73868fcd7c9357..4c414544759c4e 100644
--- a/src/libraries/System.Text.Json/Common/JsonKnownNamingPolicy.cs
+++ b/src/libraries/System.Text.Json/Common/JsonKnownNamingPolicy.cs
@@ -21,6 +21,26 @@ enum JsonKnownNamingPolicy
///
/// Specifies that the built-in be used to convert JSON property names.
///
- CamelCase = 1
+ CamelCase = 1,
+
+ ///
+ /// Specifies that the built-in be used to convert JSON property names.
+ ///
+ SnakeCaseLower = 2,
+
+ ///
+ /// Specifies that the built-in be used to convert JSON property names.
+ ///
+ SnakeCaseUpper = 3,
+
+ ///
+ /// Specifies that the built-in be used to convert JSON property names.
+ ///
+ KebabCaseLower = 4,
+
+ ///
+ /// Specifies that the built-in be used to convert JSON property names.
+ ///
+ KebabCaseUpper = 5
}
}
diff --git a/src/libraries/System.Text.Json/Common/JsonNamingPolicy.cs b/src/libraries/System.Text.Json/Common/JsonNamingPolicy.cs
index ee0a86c2321bc8..5abfa4621eb173 100644
--- a/src/libraries/System.Text.Json/Common/JsonNamingPolicy.cs
+++ b/src/libraries/System.Text.Json/Common/JsonNamingPolicy.cs
@@ -23,6 +23,26 @@ protected JsonNamingPolicy() { }
///
public static JsonNamingPolicy CamelCase { get; } = new JsonCamelCaseNamingPolicy();
+ ///
+ /// Returns the naming policy for lower snake-casing.
+ ///
+ public static JsonNamingPolicy SnakeCaseLower { get; } = new JsonSnakeCaseLowerNamingPolicy();
+
+ ///
+ /// Returns the naming policy for upper snake-casing.
+ ///
+ public static JsonNamingPolicy SnakeCaseUpper { get; } = new JsonSnakeCaseUpperNamingPolicy();
+
+ ///
+ /// Returns the naming policy for lower kebab-casing.
+ ///
+ public static JsonNamingPolicy KebabCaseLower { get; } = new JsonKebabCaseLowerNamingPolicy();
+
+ ///
+ /// Returns the naming policy for upper kebab-casing.
+ ///
+ public static JsonNamingPolicy KebabCaseUpper { get; } = new JsonKebabCaseUpperNamingPolicy();
+
///
/// When overridden in a derived class, converts the specified name according to the policy.
///
diff --git a/src/libraries/System.Text.Json/Common/JsonSeparatorNamingPolicy.cs b/src/libraries/System.Text.Json/Common/JsonSeparatorNamingPolicy.cs
new file mode 100644
index 00000000000000..9e54127c65ad95
--- /dev/null
+++ b/src/libraries/System.Text.Json/Common/JsonSeparatorNamingPolicy.cs
@@ -0,0 +1,164 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Buffers;
+using System.Globalization;
+
+namespace System.Text.Json
+{
+ internal abstract class JsonSeparatorNamingPolicy : JsonNamingPolicy
+ {
+ private readonly bool _lowercase;
+ private readonly char _separator;
+
+ internal JsonSeparatorNamingPolicy(bool lowercase, char separator) =>
+ (_lowercase, _separator) = (lowercase, separator);
+
+ public sealed override string ConvertName(string name)
+ {
+ // Rented buffer 20% longer that the input.
+ int rentedBufferLength = (12 * name.Length) / 10;
+ char[]? rentedBuffer = rentedBufferLength > JsonConstants.StackallocCharThreshold
+ ? ArrayPool.Shared.Rent(rentedBufferLength)
+ : null;
+
+ int resultUsedLength = 0;
+ Span result = rentedBuffer is null
+ ? stackalloc char[JsonConstants.StackallocCharThreshold]
+ : rentedBuffer;
+
+ void ExpandBuffer(ref Span result)
+ {
+ char[] newBuffer = ArrayPool.Shared.Rent(result.Length * 2);
+
+ result.CopyTo(newBuffer);
+
+ if (rentedBuffer is not null)
+ {
+ result.Slice(0, resultUsedLength).Clear();
+ ArrayPool.Shared.Return(rentedBuffer);
+ }
+
+ rentedBuffer = newBuffer;
+ result = rentedBuffer;
+ }
+
+ void WriteWord(ReadOnlySpan word, ref Span result)
+ {
+ if (word.IsEmpty)
+ {
+ return;
+ }
+
+ int written;
+ while (true)
+ {
+ var destinationOffset = resultUsedLength != 0
+ ? resultUsedLength + 1
+ : resultUsedLength;
+
+ if (destinationOffset < result.Length)
+ {
+ Span destination = result.Slice(destinationOffset);
+
+ written = _lowercase
+ ? word.ToLowerInvariant(destination)
+ : word.ToUpperInvariant(destination);
+
+ if (written > 0)
+ {
+ break;
+ }
+ }
+
+ ExpandBuffer(ref result);
+ }
+
+ if (resultUsedLength != 0)
+ {
+ result[resultUsedLength] = _separator;
+ resultUsedLength += 1;
+ }
+
+ resultUsedLength += written;
+ }
+
+ int first = 0;
+ ReadOnlySpan chars = name.AsSpan();
+ CharCategory previousCategory = CharCategory.Boundary;
+
+ for (int index = 0; index < chars.Length; index++)
+ {
+ char current = chars[index];
+ UnicodeCategory currentCategoryUnicode = char.GetUnicodeCategory(current);
+
+ if (currentCategoryUnicode == UnicodeCategory.SpaceSeparator ||
+ currentCategoryUnicode >= UnicodeCategory.ConnectorPunctuation &&
+ currentCategoryUnicode <= UnicodeCategory.OtherPunctuation)
+ {
+ WriteWord(chars.Slice(first, index - first), ref result);
+
+ previousCategory = CharCategory.Boundary;
+ first = index + 1;
+
+ continue;
+ }
+
+ if (index + 1 < chars.Length)
+ {
+ char next = chars[index + 1];
+ CharCategory currentCategory = currentCategoryUnicode switch
+ {
+ UnicodeCategory.LowercaseLetter => CharCategory.Lowercase,
+ UnicodeCategory.UppercaseLetter => CharCategory.Uppercase,
+ _ => previousCategory
+ };
+
+ if (currentCategory == CharCategory.Lowercase && char.IsUpper(next) ||
+ next == '_')
+ {
+ WriteWord(chars.Slice(first, index - first + 1), ref result);
+
+ previousCategory = CharCategory.Boundary;
+ first = index + 1;
+
+ continue;
+ }
+
+ if (previousCategory == CharCategory.Uppercase &&
+ currentCategoryUnicode == UnicodeCategory.UppercaseLetter &&
+ char.IsLower(next))
+ {
+ WriteWord(chars.Slice(first, index - first), ref result);
+
+ previousCategory = CharCategory.Boundary;
+ first = index;
+
+ continue;
+ }
+
+ previousCategory = currentCategory;
+ }
+ }
+
+ WriteWord(chars.Slice(first), ref result);
+
+ name = result.Slice(0, resultUsedLength).ToString();
+
+ if (rentedBuffer is not null)
+ {
+ result.Slice(0, resultUsedLength).Clear();
+ ArrayPool.Shared.Return(rentedBuffer);
+ }
+
+ return name;
+ }
+
+ private enum CharCategory
+ {
+ Boundary,
+ Lowercase,
+ Uppercase,
+ }
+ }
+}
diff --git a/src/libraries/System.Text.Json/Common/JsonSnakeCaseLowerNamingPolicy.cs b/src/libraries/System.Text.Json/Common/JsonSnakeCaseLowerNamingPolicy.cs
new file mode 100644
index 00000000000000..f46488143dae3e
--- /dev/null
+++ b/src/libraries/System.Text.Json/Common/JsonSnakeCaseLowerNamingPolicy.cs
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Text.Json
+{
+ internal sealed class JsonSnakeCaseLowerNamingPolicy : JsonSeparatorNamingPolicy
+ {
+ public JsonSnakeCaseLowerNamingPolicy()
+ : base(lowercase: true, separator: '_')
+ {
+ }
+ }
+}
diff --git a/src/libraries/System.Text.Json/Common/JsonSnakeCaseUpperNamingPolicy.cs b/src/libraries/System.Text.Json/Common/JsonSnakeCaseUpperNamingPolicy.cs
new file mode 100644
index 00000000000000..3f49d873f8960c
--- /dev/null
+++ b/src/libraries/System.Text.Json/Common/JsonSnakeCaseUpperNamingPolicy.cs
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Text.Json
+{
+ internal sealed class JsonSnakeCaseUpperNamingPolicy : JsonSeparatorNamingPolicy
+ {
+ public JsonSnakeCaseUpperNamingPolicy()
+ : base(lowercase: false, separator: '_')
+ {
+ }
+ }
+}
diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
index db7b990e095d92..4c3f4e897fea57 100644
--- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
+++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
@@ -1167,9 +1167,19 @@ private string GetLogicForDefaultSerializerOptionsInit()
{
JsonSourceGenerationOptionsAttribute options = _currentContext.GenerationOptions;
- string? namingPolicyInit = options.PropertyNamingPolicy == JsonKnownNamingPolicy.CamelCase
+ string? namingPolicyName = options.PropertyNamingPolicy switch
+ {
+ JsonKnownNamingPolicy.CamelCase => nameof(JsonNamingPolicy.CamelCase),
+ JsonKnownNamingPolicy.SnakeCaseLower => nameof(JsonNamingPolicy.SnakeCaseLower),
+ JsonKnownNamingPolicy.SnakeCaseUpper => nameof(JsonNamingPolicy.SnakeCaseUpper),
+ JsonKnownNamingPolicy.KebabCaseLower => nameof(JsonNamingPolicy.KebabCaseLower),
+ JsonKnownNamingPolicy.KebabCaseUpper => nameof(JsonNamingPolicy.KebabCaseUpper),
+ _ => null,
+ };
+
+ string? namingPolicyInit = namingPolicyName != null
? $@"
- PropertyNamingPolicy = {JsonNamingPolicyTypeRef}.CamelCase"
+ PropertyNamingPolicy = {JsonNamingPolicyTypeRef}.{namingPolicyName}"
: null;
return $@"
diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
index 60a0be1265182a..0230408f89adec 100644
--- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
+++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
@@ -1514,13 +1514,19 @@ private static string DetermineRuntimePropName(string clrPropName, string? jsonP
{
runtimePropName = jsonPropName;
}
- else if (namingPolicy == JsonKnownNamingPolicy.CamelCase)
- {
- runtimePropName = JsonNamingPolicy.CamelCase.ConvertName(clrPropName);
- }
else
{
- runtimePropName = clrPropName;
+ JsonNamingPolicy? instance = namingPolicy switch
+ {
+ JsonKnownNamingPolicy.CamelCase => JsonNamingPolicy.CamelCase,
+ JsonKnownNamingPolicy.SnakeCaseLower => JsonNamingPolicy.SnakeCaseLower,
+ JsonKnownNamingPolicy.SnakeCaseUpper => JsonNamingPolicy.SnakeCaseUpper,
+ JsonKnownNamingPolicy.KebabCaseLower => JsonNamingPolicy.KebabCaseLower,
+ JsonKnownNamingPolicy.KebabCaseUpper => JsonNamingPolicy.KebabCaseUpper,
+ _ => null,
+ };
+
+ runtimePropName = instance?.ConvertName(clrPropName) ?? clrPropName;
}
return runtimePropName;
diff --git a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets
index 596ce0c49163cb..0b45537c27dfed 100644
--- a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets
+++ b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets
@@ -30,9 +30,14 @@
+
+
+
+
+
diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs
index 3afd4bfe4cec9c..b3426cdf8c4425 100644
--- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs
+++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs
@@ -157,6 +157,10 @@ public abstract partial class JsonNamingPolicy
{
protected JsonNamingPolicy() { }
public static System.Text.Json.JsonNamingPolicy CamelCase { get { throw null; } }
+ public static System.Text.Json.JsonNamingPolicy SnakeCaseLower { get { throw null; } }
+ public static System.Text.Json.JsonNamingPolicy SnakeCaseUpper { get { throw null; } }
+ public static System.Text.Json.JsonNamingPolicy KebabCaseLower { get { throw null; } }
+ public static System.Text.Json.JsonNamingPolicy KebabCaseUpper { get { throw null; } }
public abstract string ConvertName(string name);
}
public readonly partial struct JsonProperty
@@ -914,6 +918,10 @@ public enum JsonKnownNamingPolicy
{
Unspecified = 0,
CamelCase = 1,
+ SnakeCaseLower = 2,
+ SnakeCaseUpper = 3,
+ KebabCaseLower = 4,
+ KebabCaseUpper = 5,
}
[System.FlagsAttribute]
public enum JsonNumberHandling
diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj
index f0341a109304e8..635be981ff62ca 100644
--- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj
+++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj
@@ -30,9 +30,14 @@ The System.Text.Json library is built-in as part of the shared framework in .NET
+
+
+
+
+
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs
index 421b71e80f0494..97746bc0ad6b00 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs
@@ -50,9 +50,6 @@ internal static partial class JsonConstants
public const int SpacesPerIndent = 2;
public const int RemoveFlagsBitMask = 0x7FFFFFFF;
- public const int StackallocByteThreshold = 256;
- public const int StackallocCharThreshold = StackallocByteThreshold / 2;
-
// In the worst case, an ASCII character represented as a single utf-8 byte could expand 6x when escaped.
// For example: '+' becomes '\u0043'
// Escaping surrogate pairs (represented by 3 or 4 utf-8 bytes) would expand to 12 bytes (which is still <= 6x).
diff --git a/src/libraries/System.Text.Json/tests/Common/PropertyNameTests.cs b/src/libraries/System.Text.Json/tests/Common/PropertyNameTests.cs
index 568357a5088b1d..e20233a678f6c0 100644
--- a/src/libraries/System.Text.Json/tests/Common/PropertyNameTests.cs
+++ b/src/libraries/System.Text.Json/tests/Common/PropertyNameTests.cs
@@ -15,40 +15,54 @@ public abstract partial class PropertyNameTests : SerializerTests
public PropertyNameTests(JsonSerializerWrapper serializerWrapper) : base(serializerWrapper) { }
[Fact]
- public async Task CamelCaseDeserializeNoMatch()
+ public async Task BuiltInPolicyDeserializeNoMatch()
{
- var options = new JsonSerializerOptions();
- options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
-
- SimpleTestClass obj = await Serializer.DeserializeWrapper(@"{""MyInt16"":1}", options);
-
- // This is 0 (default value) because the data does not match the property "MyInt16" that is assuming camel-casing of "myInt16".
- Assert.Equal(0, obj.MyInt16);
+ // This is 0 (default value) because the data does not match the property "MyInt16" using the specified policy.
+ await DeserializeAndAssert(JsonNamingPolicy.CamelCase, @"{""MyInt16"":1}", 0);
+ await DeserializeAndAssert(JsonNamingPolicy.SnakeCaseLower, @"{""MyInt16"":1}", 0);
+ await DeserializeAndAssert(JsonNamingPolicy.SnakeCaseUpper, @"{""MyInt16"":1}", 0);
+ await DeserializeAndAssert(JsonNamingPolicy.KebabCaseLower, @"{""MyInt16"":1}", 0);
+ await DeserializeAndAssert(JsonNamingPolicy.KebabCaseUpper, @"{""MyInt16"":1}", 0);
}
[Fact]
- public async Task CamelCaseDeserializeMatch()
+ public async Task BuiltInPolicyDeserializeMatch()
{
- var options = new JsonSerializerOptions();
- options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
+ // This is 1 because the data matches the property "MyInt16" using the specified policy.
+ await DeserializeAndAssert(JsonNamingPolicy.CamelCase, @"{""myInt16"":1}", 1);
+ await DeserializeAndAssert(JsonNamingPolicy.SnakeCaseLower, @"{""my_int16"":1}", 1);
+ await DeserializeAndAssert(JsonNamingPolicy.SnakeCaseUpper, @"{""MY_INT16"":1}", 1);
+ await DeserializeAndAssert(JsonNamingPolicy.KebabCaseLower, @"{""my-int16"":1}", 1);
+ await DeserializeAndAssert(JsonNamingPolicy.KebabCaseUpper, @"{""MY-INT16"":1}", 1);
+ }
- SimpleTestClass obj = await Serializer.DeserializeWrapper(@"{""myInt16"":1}", options);
+ private async Task DeserializeAndAssert(JsonNamingPolicy policy, string json, short expected)
+ {
+ var options = new JsonSerializerOptions { PropertyNamingPolicy = policy };
+ var obj = await Serializer.DeserializeWrapper(json, options);
- // This is 1 because the data matches the property "MyInt16" that is assuming camel-casing of "myInt16".
- Assert.Equal(1, obj.MyInt16);
+ Assert.Equal(expected, obj.MyInt16);
}
[Fact]
- public async Task CamelCaseSerialize()
+ public async Task BuiltInPolicySerialize()
{
- var options = new JsonSerializerOptions();
- options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
+ await SerializeAndAssert(JsonNamingPolicy.CamelCase, @"""myInt16"":0", @"""myInt32"":0");
+ await SerializeAndAssert(JsonNamingPolicy.SnakeCaseLower, @"""my_int16"":0", @"""my_int32"":0");
+ await SerializeAndAssert(JsonNamingPolicy.SnakeCaseUpper, @"""MY_INT16"":0", @"""MY_INT32"":0");
+ await SerializeAndAssert(JsonNamingPolicy.KebabCaseLower, @"""my-int16"":0", @"""my-int32"":0");
+ await SerializeAndAssert(JsonNamingPolicy.KebabCaseUpper, @"""MY-INT16"":0", @"""MY-INT32"":0");
- SimpleTestClass obj = await Serializer.DeserializeWrapper(@"{}", options);
+ async Task SerializeAndAssert(JsonNamingPolicy policy, string myInt16, string myInt32)
+ {
+ var options = new JsonSerializerOptions { PropertyNamingPolicy = policy };
+ var obj = await Serializer.DeserializeWrapper(@"{}", options);
- string json = await Serializer.SerializeWrapper(obj, options);
- Assert.Contains(@"""myInt16"":0", json);
- Assert.Contains(@"""myInt32"":0", json);
+ string json = await Serializer.SerializeWrapper(obj, options);
+
+ Assert.Contains(myInt16, json);
+ Assert.Contains(myInt32, json);
+ }
}
[Fact]
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CamelCaseUnitTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CamelCaseUnitTests.cs
deleted file mode 100644
index aebce3dcce17ab..00000000000000
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CamelCaseUnitTests.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using Xunit;
-
-namespace System.Text.Json.Serialization.Tests
-{
- public static class CamelCaseUnitTests
- {
- [Fact]
- public static void ToCamelCaseTest()
- {
- // These test cases were copied from Json.NET.
- Assert.Equal("urlValue", ConvertToCamelCase("URLValue"));
- Assert.Equal("url", ConvertToCamelCase("URL"));
- Assert.Equal("id", ConvertToCamelCase("ID"));
- Assert.Equal("i", ConvertToCamelCase("I"));
- Assert.Equal("", ConvertToCamelCase(""));
- Assert.Null(ConvertToCamelCase(null));
- Assert.Equal("person", ConvertToCamelCase("Person"));
- Assert.Equal("iPhone", ConvertToCamelCase("iPhone"));
- Assert.Equal("iPhone", ConvertToCamelCase("IPhone"));
- Assert.Equal("i Phone", ConvertToCamelCase("I Phone"));
- Assert.Equal("i Phone", ConvertToCamelCase("I Phone"));
- Assert.Equal(" IPhone", ConvertToCamelCase(" IPhone"));
- Assert.Equal(" IPhone ", ConvertToCamelCase(" IPhone "));
- Assert.Equal("isCIA", ConvertToCamelCase("IsCIA"));
- Assert.Equal("vmQ", ConvertToCamelCase("VmQ"));
- Assert.Equal("xml2Json", ConvertToCamelCase("Xml2Json"));
- Assert.Equal("snAkEcAsE", ConvertToCamelCase("SnAkEcAsE"));
- Assert.Equal("snA__kEcAsE", ConvertToCamelCase("SnA__kEcAsE"));
- Assert.Equal("snA__ kEcAsE", ConvertToCamelCase("SnA__ kEcAsE"));
- Assert.Equal("already_snake_case_ ", ConvertToCamelCase("already_snake_case_ "));
- Assert.Equal("isJSONProperty", ConvertToCamelCase("IsJSONProperty"));
- Assert.Equal("shoutinG_CASE", ConvertToCamelCase("SHOUTING_CASE"));
- Assert.Equal("9999-12-31T23:59:59.9999999Z", ConvertToCamelCase("9999-12-31T23:59:59.9999999Z"));
- Assert.Equal("hi!! This is text. Time to test.", ConvertToCamelCase("Hi!! This is text. Time to test."));
- Assert.Equal("building", ConvertToCamelCase("BUILDING"));
- Assert.Equal("building Property", ConvertToCamelCase("BUILDING Property"));
- Assert.Equal("building Property", ConvertToCamelCase("Building Property"));
- Assert.Equal("building PROPERTY", ConvertToCamelCase("BUILDING PROPERTY"));
- }
-
- // Use a helper method since the method is not public.
- private static string ConvertToCamelCase(string name)
- {
- JsonNamingPolicy policy = JsonNamingPolicy.CamelCase;
- string value = policy.ConvertName(name);
- return value;
- }
- }
-}
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
new file mode 100644
index 00000000000000..6a62c2acdd1f9f
--- /dev/null
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NamingPolicyUnitTests.cs
@@ -0,0 +1,235 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Xunit;
+
+namespace System.Text.Json.Serialization.Tests
+{
+ public static class NamingPolicyUnitTests
+ {
+ [Fact]
+ public static void ToCamelCaseTest()
+ {
+ // These test cases were copied from Json.NET.
+ Assert.Equal("urlValue", Convert("URLValue"));
+ Assert.Equal("url", Convert("URL"));
+ Assert.Equal("id", Convert("ID"));
+ Assert.Equal("i", Convert("I"));
+ Assert.Equal("", Convert(""));
+ Assert.Null(Convert(null));
+ Assert.Equal("person", Convert("Person"));
+ Assert.Equal("iPhone", Convert("iPhone"));
+ Assert.Equal("iPhone", Convert("IPhone"));
+ Assert.Equal("i Phone", Convert("I Phone"));
+ Assert.Equal("i Phone", Convert("I Phone"));
+ Assert.Equal(" IPhone", Convert(" IPhone"));
+ Assert.Equal(" IPhone ", Convert(" IPhone "));
+ Assert.Equal("isCIA", Convert("IsCIA"));
+ Assert.Equal("vmQ", Convert("VmQ"));
+ Assert.Equal("xml2Json", Convert("Xml2Json"));
+ Assert.Equal("snAkEcAsE", Convert("SnAkEcAsE"));
+ Assert.Equal("snA__kEcAsE", Convert("SnA__kEcAsE"));
+ Assert.Equal("snA__ kEcAsE", Convert("SnA__ kEcAsE"));
+ Assert.Equal("already_snake_case_ ", Convert("already_snake_case_ "));
+ Assert.Equal("isJSONProperty", Convert("IsJSONProperty"));
+ Assert.Equal("shoutinG_CASE", Convert("SHOUTING_CASE"));
+ Assert.Equal("9999-12-31T23:59:59.9999999Z", Convert("9999-12-31T23:59:59.9999999Z"));
+ Assert.Equal("hi!! This is text. Time to test.", Convert("Hi!! This is text. Time to test."));
+ Assert.Equal("building", Convert("BUILDING"));
+ Assert.Equal("building Property", Convert("BUILDING Property"));
+ Assert.Equal("building Property", Convert("Building Property"));
+ Assert.Equal("building PROPERTY", Convert("BUILDING PROPERTY"));
+
+ static string Convert(string name)
+ {
+ JsonNamingPolicy policy = JsonNamingPolicy.CamelCase;
+ string value = policy.ConvertName(name);
+ return value;
+ }
+ }
+
+ [Fact]
+ public static void ToSnakeLowerCase()
+ {
+ Assert.Equal("xml_http_request", Convert("XMLHttpRequest"));
+ Assert.Equal("camel_case", Convert("camelCase"));
+ Assert.Equal("camel_case", Convert("CamelCase"));
+ Assert.Equal("snake_case", Convert("snake_case"));
+ Assert.Equal("snake_case", Convert("SNAKE_CASE"));
+ Assert.Equal("kebab_case", Convert("kebab-case"));
+ Assert.Equal("kebab_case", Convert("KEBAB-CASE"));
+ Assert.Equal("double_space", Convert("double space"));
+ Assert.Equal("double_underscore", Convert("double__underscore"));
+ Assert.Equal("abc", Convert("abc"));
+ Assert.Equal("ab_c", Convert("abC"));
+ Assert.Equal("a_bc", Convert("aBc"));
+ Assert.Equal("a_bc", Convert("aBC"));
+ Assert.Equal("a_bc", Convert("ABc"));
+ Assert.Equal("abc", Convert("ABC"));
+ Assert.Equal("abc123def456", Convert("abc123def456"));
+ Assert.Equal("abc123_def456", Convert("abc123Def456"));
+ Assert.Equal("abc123_def456", Convert("abc123DEF456"));
+ Assert.Equal("abc123def456", Convert("ABC123DEF456"));
+ Assert.Equal("abc123def456", Convert("ABC123def456"));
+ Assert.Equal("abc123def456", Convert("Abc123def456"));
+ Assert.Equal("abc", Convert(" abc"));
+ Assert.Equal("abc", Convert("abc "));
+ Assert.Equal("abc", Convert(" abc "));
+ Assert.Equal("abc_def", Convert(" abc def "));
+ Assert.Equal(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ Convert("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ Assert.Equal(
+ "a_haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ Convert("aHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ Assert.Equal(
+ "a_towel_it_says_is_about_the_most_massively_useful_thing_an_interstellar_hitchhiker_can_have_partly_it_has_great_practical_value_you_can_wrap_it_around_you_for_warmth_as_you_bound_across_the_cold_moons_of_jaglan_beta_you_can_lie_on_it_on_the_brilliant_marble_sanded_beaches_of_santraginus_v_inhaling_the_heady_sea_vapors_you_can_sleep_under_it_beneath_the_stars_which_shine_so_redly_on_the_desert_world_of_kakrafoon_use_it_to_sail_a_miniraft_down_the_slow_heavy_river_moth_wet_it_for_use_in_hand_to_hand_combat_wrap_it_round_your_head_to_ward_off_noxious_fumes_or_avoid_the_gaze_of_the_ravenous_bugblatter_beast_of_traal_a_mind_bogglingly_stupid_animal_it_assumes_that_if_you_cant_see_it_it_cant_see_you_daft_as_a_brush_but_very_very_ravenous_you_can_wave_your_towel_in_emergencies_as_a_distress_signal_and_of_course_dry_yourself_of_with_it_if_it_still_seems_to_be_clean_enough",
+ Convert("ATowelItSaysIsAboutTheMostMassivelyUsefulThingAnInterstellarHitchhikerCanHave_PartlyItHasGreatPracticalValue_YouCanWrapItAroundYouForWarmthAsYouBoundAcrossTheColdMoonsOfJaglanBeta_YouCanLieOnItOnTheBrilliantMarbleSandedBeachesOfSantraginusVInhalingTheHeadySeaVapors_YouCanSleepUnderItBeneathTheStarsWhichShineSoRedlyOnTheDesertWorldOfKakrafoon_UseItToSailAMiniraftDownTheSlowHeavyRiverMoth_WetItForUseInHandToHandCombat_WrapItRoundYourHeadToWardOffNoxiousFumesOrAvoidTheGazeOfTheRavenousBugblatterBeastOfTraalAMindBogglinglyStupidAnimal_ItAssumesThatIfYouCantSeeItItCantSeeYouDaftAsABrushButVeryVeryRavenous_YouCanWaveYourTowelInEmergenciesAsADistressSignalAndOfCourseDryYourselfOfWithItIfItStillSeemsToBeCleanEnough"));
+
+ static string Convert(string name)
+ {
+ JsonNamingPolicy policy = JsonNamingPolicy.SnakeCaseLower;
+ string value = policy.ConvertName(name);
+ return value;
+ }
+ }
+
+ [Fact]
+ public static void ToSnakeUpperCase()
+ {
+ Assert.Equal("XML_HTTP_REQUEST", Convert("XMLHttpRequest"));
+ Assert.Equal("CAMEL_CASE", Convert("camelCase"));
+ Assert.Equal("CAMEL_CASE", Convert("CamelCase"));
+ Assert.Equal("SNAKE_CASE", Convert("snake_case"));
+ Assert.Equal("SNAKE_CASE", Convert("SNAKE_CASE"));
+ Assert.Equal("KEBAB_CASE", Convert("kebab-case"));
+ Assert.Equal("KEBAB_CASE", Convert("KEBAB-CASE"));
+ Assert.Equal("DOUBLE_SPACE", Convert("double space"));
+ Assert.Equal("DOUBLE_UNDERSCORE", Convert("double__underscore"));
+ Assert.Equal("ABC", Convert("abc"));
+ Assert.Equal("AB_C", Convert("abC"));
+ Assert.Equal("A_BC", Convert("aBc"));
+ Assert.Equal("A_BC", Convert("aBC"));
+ Assert.Equal("A_BC", Convert("ABc"));
+ Assert.Equal("ABC", Convert("ABC"));
+ Assert.Equal("ABC123DEF456", Convert("abc123def456"));
+ Assert.Equal("ABC123_DEF456", Convert("abc123Def456"));
+ Assert.Equal("ABC123_DEF456", Convert("abc123DEF456"));
+ Assert.Equal("ABC123DEF456", Convert("ABC123DEF456"));
+ Assert.Equal("ABC123DEF456", Convert("ABC123def456"));
+ Assert.Equal("ABC123DEF456", Convert("Abc123def456"));
+ Assert.Equal("ABC", Convert(" ABC"));
+ Assert.Equal("ABC", Convert("ABC "));
+ Assert.Equal("ABC", Convert(" ABC "));
+ Assert.Equal("ABC_DEF", Convert(" ABC def "));
+ Assert.Equal(
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ Convert("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ Assert.Equal(
+ "A_HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ Convert("aHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ Assert.Equal(
+ "A_TOWEL_IT_SAYS_IS_ABOUT_THE_MOST_MASSIVELY_USEFUL_THING_AN_INTERSTELLAR_HITCHHIKER_CAN_HAVE_PARTLY_IT_HAS_GREAT_PRACTICAL_VALUE_YOU_CAN_WRAP_IT_AROUND_YOU_FOR_WARMTH_AS_YOU_BOUND_ACROSS_THE_COLD_MOONS_OF_JAGLAN_BETA_YOU_CAN_LIE_ON_IT_ON_THE_BRILLIANT_MARBLE_SANDED_BEACHES_OF_SANTRAGINUS_V_INHALING_THE_HEADY_SEA_VAPORS_YOU_CAN_SLEEP_UNDER_IT_BENEATH_THE_STARS_WHICH_SHINE_SO_REDLY_ON_THE_DESERT_WORLD_OF_KAKRAFOON_USE_IT_TO_SAIL_A_MINIRAFT_DOWN_THE_SLOW_HEAVY_RIVER_MOTH_WET_IT_FOR_USE_IN_HAND_TO_HAND_COMBAT_WRAP_IT_ROUND_YOUR_HEAD_TO_WARD_OFF_NOXIOUS_FUMES_OR_AVOID_THE_GAZE_OF_THE_RAVENOUS_BUGBLATTER_BEAST_OF_TRAAL_A_MIND_BOGGLINGLY_STUPID_ANIMAL_IT_ASSUMES_THAT_IF_YOU_CANT_SEE_IT_IT_CANT_SEE_YOU_DAFT_AS_A_BRUSH_BUT_VERY_VERY_RAVENOUS_YOU_CAN_WAVE_YOUR_TOWEL_IN_EMERGENCIES_AS_A_DISTRESS_SIGNAL_AND_OF_COURSE_DRY_YOURSELF_OF_WITH_IT_IF_IT_STILL_SEEMS_TO_BE_CLEAN_ENOUGH",
+ Convert("ATowelItSaysIsAboutTheMostMassivelyUsefulThingAnInterstellarHitchhikerCanHave_PartlyItHasGreatPracticalValue_YouCanWrapItAroundYouForWarmthAsYouBoundAcrossTheColdMoonsOfJaglanBeta_YouCanLieOnItOnTheBrilliantMarbleSandedBeachesOfSantraginusVInhalingTheHeadySeaVapors_YouCanSleepUnderItBeneathTheStarsWhichShineSoRedlyOnTheDesertWorldOfKakrafoon_UseItToSailAMiniraftDownTheSlowHeavyRiverMoth_WetItForUseInHandToHandCombat_WrapItRoundYourHeadToWardOffNoxiousFumesOrAvoidTheGazeOfTheRavenousBugblatterBeastOfTraalAMindBogglinglyStupidAnimal_ItAssumesThatIfYouCantSeeItItCantSeeYouDaftAsABrushButVeryVeryRavenous_YouCanWaveYourTowelInEmergenciesAsADistressSignalAndOfCourseDryYourselfOfWithItIfItStillSeemsToBeCleanEnough"));
+
+ static string Convert(string name)
+ {
+ JsonNamingPolicy policy = JsonNamingPolicy.SnakeCaseUpper;
+ string value = policy.ConvertName(name);
+ return value;
+ }
+ }
+
+ [Fact]
+ public static void ToKebabLowerCase()
+ {
+ Assert.Equal("xml-http-request", Convert("XMLHttpRequest"));
+ Assert.Equal("camel-case", Convert("camelCase"));
+ Assert.Equal("camel-case", Convert("CamelCase"));
+ Assert.Equal("snake-case", Convert("snake_case"));
+ Assert.Equal("snake-case", Convert("SNAKE_CASE"));
+ Assert.Equal("kebab-case", Convert("kebab-case"));
+ Assert.Equal("kebab-case", Convert("KEBAB-CASE"));
+ Assert.Equal("double-space", Convert("double space"));
+ Assert.Equal("double-underscore", Convert("double__underscore"));
+ Assert.Equal("abc", Convert("abc"));
+ Assert.Equal("ab-c", Convert("abC"));
+ Assert.Equal("a-bc", Convert("aBc"));
+ Assert.Equal("a-bc", Convert("aBC"));
+ Assert.Equal("a-bc", Convert("ABc"));
+ Assert.Equal("abc", Convert("ABC"));
+ Assert.Equal("abc123def456", Convert("abc123def456"));
+ Assert.Equal("abc123-def456", Convert("abc123Def456"));
+ Assert.Equal("abc123-def456", Convert("abc123DEF456"));
+ Assert.Equal("abc123def456", Convert("ABC123DEF456"));
+ Assert.Equal("abc123def456", Convert("ABC123def456"));
+ Assert.Equal("abc123def456", Convert("Abc123def456"));
+ Assert.Equal("abc", Convert(" abc"));
+ Assert.Equal("abc", Convert("abc "));
+ Assert.Equal("abc", Convert(" abc "));
+ Assert.Equal("abc-def", Convert(" abc def "));
+ Assert.Equal(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ Convert("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ Assert.Equal(
+ "a-haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ Convert("aHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ Assert.Equal(
+ "a-towel-it-says-is-about-the-most-massively-useful-thing-an-interstellar-hitchhiker-can-have-partly-it-has-great-practical-value-you-can-wrap-it-around-you-for-warmth-as-you-bound-across-the-cold-moons-of-jaglan-beta-you-can-lie-on-it-on-the-brilliant-marble-sanded-beaches-of-santraginus-v-inhaling-the-heady-sea-vapors-you-can-sleep-under-it-beneath-the-stars-which-shine-so-redly-on-the-desert-world-of-kakrafoon-use-it-to-sail-a-miniraft-down-the-slow-heavy-river-moth-wet-it-for-use-in-hand-to-hand-combat-wrap-it-round-your-head-to-ward-off-noxious-fumes-or-avoid-the-gaze-of-the-ravenous-bugblatter-beast-of-traal-a-mind-bogglingly-stupid-animal-it-assumes-that-if-you-cant-see-it-it-cant-see-you-daft-as-a-brush-but-very-very-ravenous-you-can-wave-your-towel-in-emergencies-as-a-distress-signal-and-of-course-dry-yourself-of-with-it-if-it-still-seems-to-be-clean-enough",
+ Convert("ATowelItSaysIsAboutTheMostMassivelyUsefulThingAnInterstellarHitchhikerCanHave_PartlyItHasGreatPracticalValue_YouCanWrapItAroundYouForWarmthAsYouBoundAcrossTheColdMoonsOfJaglanBeta_YouCanLieOnItOnTheBrilliantMarbleSandedBeachesOfSantraginusVInhalingTheHeadySeaVapors_YouCanSleepUnderItBeneathTheStarsWhichShineSoRedlyOnTheDesertWorldOfKakrafoon_UseItToSailAMiniraftDownTheSlowHeavyRiverMoth_WetItForUseInHandToHandCombat_WrapItRoundYourHeadToWardOffNoxiousFumesOrAvoidTheGazeOfTheRavenousBugblatterBeastOfTraalAMindBogglinglyStupidAnimal_ItAssumesThatIfYouCantSeeItItCantSeeYouDaftAsABrushButVeryVeryRavenous_YouCanWaveYourTowelInEmergenciesAsADistressSignalAndOfCourseDryYourselfOfWithItIfItStillSeemsToBeCleanEnough"));
+
+ static string Convert(string name)
+ {
+ JsonNamingPolicy policy = JsonNamingPolicy.KebabCaseLower;
+ string value = policy.ConvertName(name);
+ return value;
+ }
+ }
+
+ [Fact]
+ public static void ToKebabUpperCase()
+ {
+ Assert.Equal("XML-HTTP-REQUEST", Convert("XMLHttpRequest"));
+ Assert.Equal("CAMEL-CASE", Convert("camelCase"));
+ Assert.Equal("CAMEL-CASE", Convert("CamelCase"));
+ Assert.Equal("SNAKE-CASE", Convert("snake_case"));
+ Assert.Equal("SNAKE-CASE", Convert("SNAKE_CASE"));
+ Assert.Equal("KEBAB-CASE", Convert("kebab-case"));
+ Assert.Equal("KEBAB-CASE", Convert("KEBAB-CASE"));
+ Assert.Equal("DOUBLE-SPACE", Convert("double space"));
+ Assert.Equal("DOUBLE-UNDERSCORE", Convert("double__underscore"));
+ Assert.Equal("ABC", Convert("abc"));
+ Assert.Equal("AB-C", Convert("abC"));
+ Assert.Equal("A-BC", Convert("aBc"));
+ Assert.Equal("A-BC", Convert("aBC"));
+ Assert.Equal("A-BC", Convert("ABc"));
+ Assert.Equal("ABC", Convert("ABC"));
+ Assert.Equal("ABC123DEF456", Convert("abc123def456"));
+ Assert.Equal("ABC123-DEF456", Convert("abc123Def456"));
+ Assert.Equal("ABC123-DEF456", Convert("abc123DEF456"));
+ Assert.Equal("ABC123DEF456", Convert("ABC123DEF456"));
+ Assert.Equal("ABC123DEF456", Convert("ABC123def456"));
+ Assert.Equal("ABC123DEF456", Convert("Abc123def456"));
+ Assert.Equal("ABC", Convert(" ABC"));
+ Assert.Equal("ABC", Convert("ABC "));
+ Assert.Equal("ABC", Convert(" ABC "));
+ Assert.Equal("ABC-DEF", Convert(" ABC def "));
+ Assert.Equal(
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ Convert("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ Assert.Equal(
+ "A-HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ Convert("aHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ Assert.Equal(
+ "A-TOWEL-IT-SAYS-IS-ABOUT-THE-MOST-MASSIVELY-USEFUL-THING-AN-INTERSTELLAR-HITCHHIKER-CAN-HAVE-PARTLY-IT-HAS-GREAT-PRACTICAL-VALUE-YOU-CAN-WRAP-IT-AROUND-YOU-FOR-WARMTH-AS-YOU-BOUND-ACROSS-THE-COLD-MOONS-OF-JAGLAN-BETA-YOU-CAN-LIE-ON-IT-ON-THE-BRILLIANT-MARBLE-SANDED-BEACHES-OF-SANTRAGINUS-V-INHALING-THE-HEADY-SEA-VAPORS-YOU-CAN-SLEEP-UNDER-IT-BENEATH-THE-STARS-WHICH-SHINE-SO-REDLY-ON-THE-DESERT-WORLD-OF-KAKRAFOON-USE-IT-TO-SAIL-A-MINIRAFT-DOWN-THE-SLOW-HEAVY-RIVER-MOTH-WET-IT-FOR-USE-IN-HAND-TO-HAND-COMBAT-WRAP-IT-ROUND-YOUR-HEAD-TO-WARD-OFF-NOXIOUS-FUMES-OR-AVOID-THE-GAZE-OF-THE-RAVENOUS-BUGBLATTER-BEAST-OF-TRAAL-A-MIND-BOGGLINGLY-STUPID-ANIMAL-IT-ASSUMES-THAT-IF-YOU-CANT-SEE-IT-IT-CANT-SEE-YOU-DAFT-AS-A-BRUSH-BUT-VERY-VERY-RAVENOUS-YOU-CAN-WAVE-YOUR-TOWEL-IN-EMERGENCIES-AS-A-DISTRESS-SIGNAL-AND-OF-COURSE-DRY-YOURSELF-OF-WITH-IT-IF-IT-STILL-SEEMS-TO-BE-CLEAN-ENOUGH",
+ Convert("ATowelItSaysIsAboutTheMostMassivelyUsefulThingAnInterstellarHitchhikerCanHave_PartlyItHasGreatPracticalValue_YouCanWrapItAroundYouForWarmthAsYouBoundAcrossTheColdMoonsOfJaglanBeta_YouCanLieOnItOnTheBrilliantMarbleSandedBeachesOfSantraginusVInhalingTheHeadySeaVapors_YouCanSleepUnderItBeneathTheStarsWhichShineSoRedlyOnTheDesertWorldOfKakrafoon_UseItToSailAMiniraftDownTheSlowHeavyRiverMoth_WetItForUseInHandToHandCombat_WrapItRoundYourHeadToWardOffNoxiousFumesOrAvoidTheGazeOfTheRavenousBugblatterBeastOfTraalAMindBogglinglyStupidAnimal_ItAssumesThatIfYouCantSeeItItCantSeeYouDaftAsABrushButVeryVeryRavenous_YouCanWaveYourTowelInEmergenciesAsADistressSignalAndOfCourseDryYourselfOfWithItIfItStillSeemsToBeCleanEnough"));
+
+ static string Convert(string name)
+ {
+ JsonNamingPolicy policy = JsonNamingPolicy.KebabCaseUpper;
+ string value = policy.ConvertName(name);
+ return value;
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj
index 749f6364889bac..9c95305a2ea693 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj
@@ -116,7 +116,6 @@
-
@@ -175,6 +174,7 @@
+