diff --git a/src/IntelliTect.Coalesce.Tests/Tests/Utilities/StringExtensionTests.cs b/src/IntelliTect.Coalesce.Tests/Tests/Utilities/StringExtensionTests.cs index 9cb0d0bf0..ecd3c11f4 100644 --- a/src/IntelliTect.Coalesce.Tests/Tests/Utilities/StringExtensionTests.cs +++ b/src/IntelliTect.Coalesce.Tests/Tests/Utilities/StringExtensionTests.cs @@ -1,4 +1,5 @@ using IntelliTect.Coalesce.Utilities; +using System.Collections.Generic; using Xunit; namespace IntelliTect.Coalesce.Tests.Utilities @@ -84,5 +85,51 @@ public void CanGetIndetifierFromVerbatimIdentifier() Assert.Equal("@if", identifier); } + + [Fact] + public void ToProperCase_HandlesTwoCapitalsInARow() + { + const string enumName = "HROnly"; + Assert.Equal("HR Only", enumName.ToProperCase()); + } + [Fact] + public void ToProperCase_HandlesMultipleCapitalsInARow() + { + const string enumName = "FBIOnly"; + Assert.Equal("FBI Only", enumName.ToProperCase()); + } + [Fact] + public void ToProperCase_HandlesOnlyTwoCapitals() + { + const string enumName = "UI"; + Assert.Equal("UI", enumName.ToProperCase()); + } + [Fact] + public void ToProperCase_HandlesANormalWord() + { + const string enumName = "User"; + Assert.Equal("User", enumName.ToProperCase()); + } + + [Fact] + public void ToProperCase_HandlesANormalPhrase() + { + const string enumName = "HelloWorld"; + Assert.Equal("Hello World", enumName.ToProperCase()); + } + + [Fact] + public void ToProperCase_HandlesCamelCase() + { + const string enumName = "helloWorld"; + Assert.Equal("Hello World", enumName.ToProperCase()); + } + + [Fact] + public void ToProperCase_HandlesCamelCaseWithAcronym() + { + const string enumName = "helloWorldUI"; + Assert.Equal("Hello World UI", enumName.ToProperCase()); + } } } diff --git a/src/IntelliTect.Coalesce/Utilities/StringExtensions.cs b/src/IntelliTect.Coalesce/Utilities/StringExtensions.cs index 7a2864474..6b8aac5a1 100644 --- a/src/IntelliTect.Coalesce/Utilities/StringExtensions.cs +++ b/src/IntelliTect.Coalesce/Utilities/StringExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Text; using System.Text.RegularExpressions; using System.Web; using Microsoft.CodeAnalysis.CSharp; @@ -77,21 +78,30 @@ public static string ToCamelCase(this string s) if (theString == null) return null; if (theString.Length < 2) return theString.ToUpper(); - // Two-letter uppercase should be preserved as uppercase. - // https://learn.microsoft.com/en-us/visualstudio/code-quality/ca1709?view=vs-2022 - if (theString.Length == 2 && char.IsUpper(theString[0]) && char.IsUpper(theString[1])) return theString; - - // Start with the first character. - string result = theString.Substring(0, 1).ToUpper(); - - // Add the remaining characters. + StringBuilder returnedString = new(theString.Length); + returnedString.Append(char.ToUpper(theString[0])); for (int i = 1; i < theString.Length; i++) { - if (char.IsUpper(theString[i])) result += " "; - result += theString[i]; + if (char.IsLower(theString[i])) + { + returnedString.Append(theString[i]); + } + else + { + // If the next character is uppercase, don't insert a space. + if (i + 1 < theString.Length && (char.IsLower(theString[i + 1]) || char.IsLower(theString[i - 1]))) + { + returnedString.Append(' '); + returnedString.Append(theString[i]); + } + else + { + returnedString.Append(theString[i]); + } + } } - return result; + return returnedString.ToString(); } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("str")] @@ -105,7 +115,7 @@ public static string ToCamelCase(this string s) .Replace("\"", "\\\""); [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("str")] - public static string? QuotedStringLiteralForCSharp(this string? str) => + public static string? QuotedStringLiteralForCSharp(this string? str) => str is null ? null : ('"' + str.EscapeStringLiteralForCSharp() + '"'); [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("str")]