Files
wwdpublic/Content.Tests/Shared/Chat/V2/Moderation/SimpleCensor.cs
SimpleStation14 19568f7a8b Mirror 25908: Chat Censorship Systems (#444)
## Mirror of PR #25908: [SS14-17313 Chatfactor: Chat Censorship
Systems](https://github.com/space-wizards/space-station-14/pull/25908)
from <img src="https://avatars.githubusercontent.com/u/10567778?v=4"
alt="space-wizards" width="22"/>
[space-wizards](https://github.com/space-wizards)/[space-station-14](https://github.com/space-wizards/space-station-14)

###### `bf98a6a8bb2a57fb149459d6b053eaaf6abc8cd7`

PR opened by <img
src="https://avatars.githubusercontent.com/u/732532?v=4" width="16"/><a
href="https://github.com/FairlySadPanda"> FairlySadPanda</a> at
2024-03-07 12:13:16 UTC - merged at 2024-03-25 23:50:20 UTC

---

PR changed 4 files with 576 additions and 0 deletions.

The PR had the following labels:
- Status: Needs Review


---

<details open="true"><summary><h1>Original Body</h1></summary>

> <!-- Please read these guidelines before opening your PR:
https://docs.spacestation14.io/en/getting-started/pr-guideline -->
> <!-- The text between the arrows are comments - they will not be
visible on your PR. -->
> 
> ## About the PR
> Adds some systems to manage chat censorship:
> 
> 1. No-op: does nothing
> 2. SimpleCensor: a regex-free censor with a variety of rules to use
> 3. RegexCensor: a censor that uses regex.
> 
> This exposes a singleton backed by a builder pattern (ChatCensor) that
is set up, probably during the code init phase, and then globally
available for your censorship needs.
> 
> ## Why / Balance
> Partial fulfilment of #17313 
> 
> ## Technical details
> CE wants regex, CE gets regex
> 
> Otherwise SimpleCensor is designed to be usable by people who don't
want to faff with regex.
> 
> This would be setup during server or client init, so would be driven
by Cvars.
> 
> ## Media
> <!-- 
> PRs which make ingame changes (adding clothing, items, new features,
etc) are required to have media attached that showcase the changes.
> Small fixes/refactors are exempt.
> Any media may be used in SS14 progress reports, with clear credit
given.
> 
> If you're unsure whether your PR will require media, ask a maintainer.
> 
> Check the box below to confirm that you have in fact seen this (put an
X in the brackets, like [X]):
> -->
> 
> - [x] I have added screenshots/videos to this PR showcasing its
changes ingame, **or** this PR does not require an ingame showcase
> 
> ## Breaking changes
> nope
> **Changelog**
> nope


</details>

Co-authored-by: SimpleStation14 <Unknown>
2024-07-11 17:54:54 -07:00

163 lines
5.0 KiB
C#

using System.Text.Unicode;
using Content.Shared.Chat.V2.Moderation;
using NUnit.Framework;
namespace Content.Tests.Shared.Chat.V2.Moderation;
public sealed class SimpleCensorTests
{
[Test]
public void CanCensorASingleWord()
{
var sut = new SimpleCensor().WithCustomDictionary(["amogus"]);
var output = sut.Censor("hello amogus");
Assert.That(output, Is.EqualTo("hello ******"));
}
// Basics - use custom dictionary
[Test]
public void CanCensorMultipleWordInstances()
{
var sut= new SimpleCensor().WithCustomDictionary(["amogus"]);
var output = sut.Censor("amogus hello amogus");
Assert.That(output, Is.EqualTo("****** hello ******"));
}
[Test]
public void CanCensorMultipleWords()
{
var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]);
var output = sut.Censor("amogus hello sus");
Assert.That(output, Is.EqualTo("****** hello ***"));
}
[Test]
public void CanUseDifferentCensorSymbols()
{
var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]);
var output = sut.Censor("amogus hello sus", '#');
Assert.That(output, Is.EqualTo("###### hello ###"));
}
[Test]
public void CanCatchCapitalizedWords()
{
var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]);
var output = sut.Censor("AMOGUS hello SUS");
Assert.That(output, Is.EqualTo("****** hello ***"));
}
[Test]
public void CanCatchWordsWithSomeCaptialsInThem()
{
var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]);
var output = sut.Censor("AmoGuS hello SuS");
Assert.That(output, Is.EqualTo("****** hello ***"));
}
[Test]
public void CanCatchWordsHiddenInsideOtherWords()
{
var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]);
var output = sut.Censor("helamoguslo suspicious");
Assert.That(output, Is.EqualTo("hel******lo ***picious"));
}
// Sanitizing Leetspeak
[Test]
public void CanSanitizeLeetspeak()
{
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak();
var output = sut.Censor("am0gu5 hello 5u5");
Assert.That(output, Is.EqualTo("****** hello ***"));
}
[Test]
public void SanitizingLeetspeakOnlyOccursWhenTheWordIsBlocked()
{
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak();
var output = sut.Censor("he110");
Assert.That(output, Is.EqualTo("he110"));
}
[Test]
public void CanCatchLeetspeakReplacementsWithMoreThanOneLetter()
{
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak();
var output = sut.Censor("am()gu5 hello 5u5");
Assert.That(output, Is.EqualTo("******* hello ***"));
}
// Sanitizing special characters
[Test]
public void DoesNotSanitizeOutUncensoredSpecialCharacters()
{
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeSpecialCharacters();
var output = sut.Censor("amogus!hello!sus");
Assert.That(output, Is.EqualTo("******!hello!***"));
}
[Test]
public void DoesSanitizeOutCensoredSpecialCharacters()
{
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeSpecialCharacters();
var output = sut.Censor("amo!gus hello s?us");
Assert.That(output, Is.EqualTo("***!*** hello *?**"));
}
// Unicode ranges
[Test]
public void SanitizesOutNonLatinCharaters()
{
var sut = new SimpleCensor().WithRanges([UnicodeRanges.BasicLatin, UnicodeRanges.Latin1Supplement]);
var output = sut.Censor("amogus Україна sus 日本");
Assert.That(output, Is.EqualTo("amogus sus "));
}
[Test]
public void SanitizesOutNonLatinOrCyrillicCharaters()
{
var sut = new SimpleCensor().WithRanges([UnicodeRanges.BasicLatin, UnicodeRanges.Latin1Supplement, UnicodeRanges.Cyrillic]);
var output = sut.Censor("amogus Україна sus 日本");
Assert.That(output, Is.EqualTo("amogus Україна sus "));
}
// False positives
[Test]
public void CanHandleFalsePositives()
{
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithFalsePositives(["amogusus"]);
var output = sut.Censor("amogusus hello amogus hello sus");
Assert.That(output, Is.EqualTo("amogusus hello ****** hello ***"));
}
// False negatives
[Test]
public void CanHandleFalseNegatives()
{
var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithFalsePositives(["amogusus"]).WithFalseNegatives(["susamogusus"]);
var output = sut.Censor("susamogusus hello amogus hello sus amogusus");
Assert.That(output, Is.EqualTo("*********** hello ****** hello *** ********"));
}
}