fix: Fixes and optimizes NameVerification and ProfanityProtection (#2153)
### Summary Significantly improves the performance of NameVerification & ProfanityProtection: ```cs | Method | Mean | Error | StdDev | |--------------- |----------:|----------:|----------:| | ValidateName | 728.34 ns | 13.244 ns | 11.059 ns | | ValidateNameSV | 26.62 ns | 0.233 ns | 0.207 ns | ```
This commit is contained in:
parent
0ce2a62a76
commit
a94814a7ef
9 changed files with 624 additions and 440 deletions
137
Projects/UOContent.Tests/Tests/Misc/NameVerificationTests.cs
Normal file
137
Projects/UOContent.Tests/Tests/Misc/NameVerificationTests.cs
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
using System.Buffers;
|
||||
using Server.Misc;
|
||||
using Xunit;
|
||||
|
||||
namespace Server.Tests;
|
||||
|
||||
public class NameVerificationTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("John")]
|
||||
[InlineData("Mary Ann")]
|
||||
[InlineData("Bob-Jones")]
|
||||
[InlineData("O'Malley")]
|
||||
public void ValidatePlayerName_ValidNames_ReturnsTrue(string name)
|
||||
{
|
||||
Assert.True(NameVerification.ValidatePlayerName(name));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Rex")]
|
||||
[InlineData("MrWhiskers")]
|
||||
[InlineData("Fido")]
|
||||
public void ValidatePetName_ValidNames_ReturnsTrue(string name)
|
||||
{
|
||||
Assert.True(NameVerification.ValidatePetName(name));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Mrs-Smith")]
|
||||
[InlineData("Mr. Whiskers")]
|
||||
[InlineData("Dog123")]
|
||||
public void ValidatePetName_InvalidNames_ReturnsFalse(string name)
|
||||
{
|
||||
Assert.False(NameVerification.ValidatePetName(name));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Blacksmith12")]
|
||||
[InlineData("Baker")]
|
||||
[InlineData("Innkeeper")]
|
||||
public void ValidateVendorName_ValidNames_ReturnsTrue(string name)
|
||||
{
|
||||
Assert.True(NameVerification.ValidateVendorName(name));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Blacksmith 123")]
|
||||
[InlineData("Baker-Smith")]
|
||||
[InlineData("*Innkeeper*")]
|
||||
public void ValidateVendorName_ValidNames_ReturnsFalse(string name)
|
||||
{
|
||||
Assert.False(NameVerification.ValidateVendorName(name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_MinimumLengthName_ReturnsTrue()
|
||||
{
|
||||
Assert.True(NameVerification.Validate("Ab", 2, 16, true, false));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_MaximumLengthName_ReturnsTrue()
|
||||
{
|
||||
Assert.True(NameVerification.Validate("AbcdefghijklmnopqrsT", 1, 20, true, true));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_MaxExceptions_ReturnsTrue()
|
||||
{
|
||||
var exceptions = SearchValues.Create(' ', '-', '.');
|
||||
Assert.True(NameVerification.Validate("A-B.C D", 2, 16, true, false, false, 3, exceptions));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_BoundaryOfDisallowedWord_ReturnsTrueWhenNotActuallyDisallowed()
|
||||
{
|
||||
// "ass" is in disallowed, but "class" has proper boundaries
|
||||
Assert.True(NameVerification.ValidatePlayerName("Class"));
|
||||
}
|
||||
|
||||
// Negative Tests
|
||||
[Fact]
|
||||
public void Validate_EmptyName_ReturnsFalse()
|
||||
{
|
||||
Assert.False(NameVerification.Validate("", 1, 20, true, true));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_TooShortName_ReturnsFalse()
|
||||
{
|
||||
Assert.False(NameVerification.Validate("A", 2, 16, true, false));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_TooLongName_ReturnsFalse()
|
||||
{
|
||||
Assert.False(NameVerification.Validate("AbcdefghijklmnopqrstuvwxyzABCDEF", 2, 16, true, false));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("ass")]
|
||||
[InlineData("GodDamn Fine")]
|
||||
[InlineData("Fuck")]
|
||||
public void Validate_DisallowedWords_ReturnsFalse(string name)
|
||||
{
|
||||
Assert.False(NameVerification.ValidatePlayerName(name));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("GMJohn")]
|
||||
[InlineData("LordBob")]
|
||||
[InlineData("SeerMagic")]
|
||||
public void Validate_DisallowedPrefixes_ReturnsFalse(string name)
|
||||
{
|
||||
Assert.False(NameVerification.ValidatePlayerName(name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_TooManyExceptions_ReturnsFalse()
|
||||
{
|
||||
var exceptions = SearchValues.Create(' ', '-', '.');
|
||||
Assert.False(NameVerification.Validate("A-B.C D-E", 2, 16, true, false, false, 3, exceptions));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_ExceptionAtStartWhenNotAllowed_ReturnsFalse()
|
||||
{
|
||||
var exceptions = SearchValues.Create(' ', '-', '.');
|
||||
Assert.False(NameVerification.Validate("-John", 2, 16, true, false, true, 1, exceptions));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_DisallowedCharacters_ReturnsFalse()
|
||||
{
|
||||
Assert.False(NameVerification.Validate("John123", 2, 16, true, false));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
using Server.Misc;
|
||||
using Xunit;
|
||||
|
||||
namespace Server.Tests;
|
||||
|
||||
public class ProfanityProtectionTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Hello world")]
|
||||
[InlineData("This is a normal conversation")]
|
||||
[InlineData("I would like to trade with you")]
|
||||
public void Speech_WithoutProfanity_PassesValidation(string speech)
|
||||
{
|
||||
Assert.False(ProfanityProtection.ContainsProfanity(speech));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Speech_Empty_PassesValidation()
|
||||
{
|
||||
Assert.False(ProfanityProtection.ContainsProfanity(""));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("I'm going to class tomorrow")] // contains "ass" but in "class"
|
||||
[InlineData("This assignment is hard")] // contains "ass" but in "assignment"
|
||||
[InlineData("That's a nice cocktail")] // contains "cock" but in "cocktail"
|
||||
public void Speech_WithWordsThatLookLikeProfanity_PassesValidation(string speech)
|
||||
{
|
||||
Assert.False(ProfanityProtection.ContainsProfanity(speech));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("This is ass")]
|
||||
[InlineData("What the fuck")]
|
||||
[InlineData("You're a bitch")]
|
||||
public void Speech_WithProfanity_FailsValidation(string speech)
|
||||
{
|
||||
Assert.True(ProfanityProtection.ContainsProfanity(speech));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("ass")] // standalone profanity
|
||||
[InlineData("an ass joke")] // profanity with word boundaries
|
||||
[InlineData("ass.")] // profanity followed by punctuation
|
||||
public void ContainsDisallowedWord_DetectsProfanityWithBoundaries(string speech)
|
||||
{
|
||||
Assert.True(NameVerification.ContainsDisallowedWord(
|
||||
speech,
|
||||
ProfanityProtection.Disallowed,
|
||||
ProfanityProtection.DisallowedSearchValues
|
||||
));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue