Skip to content

Commit

Permalink
fix: #469 handle sequences of digits when converting PascalCase to Ti…
Browse files Browse the repository at this point in the history
…tle Case ("Is24h" => "Is 24h")
  • Loading branch information
ascott18 committed Oct 8, 2024
1 parent ac0c6ba commit bf84c1e
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 29 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# 5.1.0

- feat: Automatically produce user-friendly response messages in behaviors for Save and Delete operations that fail due to a violation of a SQL Server foreign key or unique constraint. This behavior can be controlled with the `DetailedEfConstraintExceptionMessages` setting in `.AddCoalesce(c => c.Configure(o => { ... }))`, or by overriding `StandardBehaviors.GetExceptionResult`. This is not a substitute for adding proper validation or other handling of related entities - it only exists to provide a better user experience in cases where the developer has forgotten to handle these situations. This behavior does respect Coalesce's security model and won't produce descriptions of types or values that the user is not allowed to see.
- feat: Error responses now include inner exception messages when `DetailedExceptionMessages` is enabled.
- feat: Automatically produce user-friendly response messages in behaviors for Save and Delete operations that fail due to a violation of a SQL Server foreign key or unique constraint. This behavior can be controlled with the `DetailedEfConstraintExceptionMessages` setting in `.AddCoalesce(c => c.Configure(o => { ... }))`, or by overriding `StandardBehaviors.GetExceptionResult`. This is not a substitute for adding proper validation or other handling of related entities - it only exists to provide a better user experience in cases where the developer has forgotten to handle these situations. This behavior does respect Coalesce's security model and won't produce descriptions of types or values that the user is not allowed to see. (#468)
- feat: Error responses now include inner exception messages when `DetailedExceptionMessages` is enabled. (#468)

- refactor: `CoalesceOptions.DetailedEntityFrameworkExceptionMessages` has been renamed to `CoalesceOptions.DetailedEFMigrationExceptionMessages`
- fix: The "Max _N_ items retrieved" message in c-select now accounts for list calls that don't provide a count, e.g. by passing `noCount=true`.
- fix: handle sequences of digits when converting PascalCase to Title Case ("Is24h" => "Is 24h") (#469)

# 5.0.3

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,47 +89,78 @@ public void CanGetIndetifierFromVerbatimIdentifier()
[Fact]
public void ToProperCase_HandlesTwoCapitalsInARow()
{
const string enumName = "HROnly";
Assert.Equal("HR Only", enumName.ToProperCase());
const string input = "HROnly";
Assert.Equal("HR Only", input.ToProperCase());
}

[Fact]
public void ToProperCase_HandlesMultipleCapitalsInARow()
{
const string enumName = "FBIOnly";
Assert.Equal("FBI Only", enumName.ToProperCase());
const string input = "FBIOnly";
Assert.Equal("FBI Only", input.ToProperCase());
}

[Fact]
public void ToProperCase_HandlesOnlyTwoCapitals()
{
const string enumName = "UI";
Assert.Equal("UI", enumName.ToProperCase());
const string input = "UI";
Assert.Equal("UI", input.ToProperCase());
}

[Fact]
public void ToProperCase_HandlesANormalWord()
{
const string enumName = "User";
Assert.Equal("User", enumName.ToProperCase());
const string input = "User";
Assert.Equal("User", input.ToProperCase());
}

[Fact]
public void ToProperCase_HandlesANormalPhrase()
{
const string enumName = "HelloWorld";
Assert.Equal("Hello World", enumName.ToProperCase());
const string input = "HelloWorld";
Assert.Equal("Hello World", input.ToProperCase());
}

[Fact]
public void ToProperCase_HandlesCamelCase()
{
const string enumName = "helloWorld";
Assert.Equal("Hello World", enumName.ToProperCase());
const string input = "helloWorld";
Assert.Equal("Hello World", input.ToProperCase());
}

[Fact]
public void ToProperCase_HandlesCamelCaseWithAcronym()
{
const string enumName = "helloWorldUI";
Assert.Equal("Hello World UI", enumName.ToProperCase());
const string input = "helloWorldUI";
Assert.Equal("Hello World UI", input.ToProperCase());
}

[Fact]
public void ToProperCase_HandlesNumberBeforeLowercase()
{
const string input = "Is1h";
Assert.Equal("Is 1h", input.ToProperCase());
}

[Fact]
public void ToProperCase_HandlesNumbersBeforeLowercase()
{
const string input = "Is24h";
Assert.Equal("Is 24h", input.ToProperCase());
}

[Fact]
public void ToProperCase_HandlesNumberBeforeUppercase()
{
const string input = "Is3D";
Assert.Equal("Is 3D", input.ToProperCase());
}

[Fact]
public void ToProperCase_HandlesNumbersBeforeUppercase()
{
const string input = "Is365Days";
Assert.Equal("Is 365 Days", input.ToProperCase());
}
}
}
36 changes: 23 additions & 13 deletions src/IntelliTect.Coalesce/Utilities/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,31 +72,41 @@ public static string ToCamelCase(this string s)
// Capitalize the first character and add a space before
// each capitalized letter (except the first character).
[return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("theString")]
public static string? ToProperCase(this string? theString)
public static string? ToProperCase(this string? input)
{
// If there are 0 or 1 characters, just return the string.
if (theString == null) return null;
if (theString.Length < 2) return theString.ToUpper();
if (input == null) return null;
if (input.Length < 2) return input.ToUpper();

StringBuilder returnedString = new(input.Length);

StringBuilder returnedString = new(theString.Length);
returnedString.Append(char.ToUpper(theString[0]));
for (int i = 1; i < theString.Length; i++)
returnedString.Append(char.ToUpper(input[0]));

for (int i = 1; i < input.Length; i++)
{
if (char.IsLower(theString[i]))
if (char.IsLower(input[i]))
{
returnedString.Append(theString[i]);
returnedString.Append(input[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])))
if (
// If there is no next character,
i + 1 >= input.Length ||
// Or we're in the middle of a string of capital letters
// (e.g. "R" in "HROnly" or "B" in "FBI"),
(!char.IsLower(input[i - 1]) && !char.IsLower(input[i + 1])) ||
// Or we're in the middle of a multi-digit number,
(char.IsDigit(input[i - 1]) && char.IsDigit(input[i]))
)
{
returnedString.Append(' ');
returnedString.Append(theString[i]);
// ...don't insert a space.
returnedString.Append(input[i]);
}
else
{
returnedString.Append(theString[i]);
returnedString.Append(' ');
returnedString.Append(input[i]);
}
}
}
Expand Down

0 comments on commit bf84c1e

Please sign in to comment.