Skip to content

Commit

Permalink
More tests, rename a strategy, update README.md and add tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
IEvangelist committed Feb 1, 2024
1 parent 971c305 commit 9d18a7d
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 22 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,14 @@ Each replacement strategy corresponds to a different way of replacing profane co
| `ReplacementType.FirstLetterThenAsterisk` | `"FirstLetterThenAsterisk"` | Replaces profane content with asterisks after the first letter. For example, a swear word with four letters could look like this `f\*\*\*`. |
| `ReplacementType.VowelAsterisk` | `"VowelAsterisk"` | Replaces profane content with asterisks, but only the vowels. For example, a swear word with four letters could look like this `sh\*t`. |
| `ReplacementType.Bleep` | `"Bleep"` | Replaces profane content with asterisks, but only the vowels. For example, a swear word with four letters could look like this `sh\*t`. |
| `ReplacementType.RedactedBlackRectangle` | `"RedactedBlackRectangle"` | Replaces profane content with black rectangles to redact their content. For example, a swear word with four letters could look like this `████`. |
| `ReplacementType.RedactedRectangle` | `"RedactedRectangle"` | Replaces profane content with rectangles to redact their content. For example, a swear word with four letters could look like this `████`. |
| `ReplacementType.StrikeThrough` | `"StrikeThrough"` | Encloses profane content with `~~` causing strikethrough rendering. For example, a swear word with four letters could look like this ~~`shit`~~. |
| `ReplacementType.Underscores` | `"Underscores"` | Replaces profane content with underscores `_`. For example, a swear word with four letters could look like this `____`. |

The value of the `replacement-strategy` input is case-insensitive, and accepts hyphened alternatives (such as `anger-emoji`) as well.

> [!TIP]
> All asterisk replacement strategies are escaped with a backslash `\` to prevent markdown from rendering the asterisks as bold text. No need for you the escape these values yourself.
> All asterisk replacement strategies are escaped with a backslash `\` to prevent markdown from rendering the asterisks as bold text. No need for you the escape these values yourself. This excludes title updates, as markdown is supported there.

## 🏷️ Label requirements

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal sealed class DefaultProfaneContentFilterService(IMemoryCache cache) : I
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous operation that
/// returns a readonly dictionary of all profane words.</returns>
private async Task<Dictionary<string, ProfaneFilter>> ReadAllProfaneWordsAsync()
private async Task<Dictionary<string, ProfaneSourceFilter>> ReadAllProfaneWordsAsync()
{
return await cache.GetOrCreateAsync(ProfaneListKey, async entry =>
{
Expand Down Expand Up @@ -57,7 +57,7 @@ await Parallel.ForEachAsync(fileNames,
return allWords.ToDictionary(
static kvp => kvp.Key,
static kvp => new ProfaneFilter(kvp.Key, kvp.Value.ToFrozenSet()));
static kvp => new ProfaneSourceFilter(kvp.Key, kvp.Value.ToFrozenSet()));
}) ?? [];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ public static string ToSummaryString(this ReplacementStrategy replacementStrateg
ReplacementStrategy.RandomAsterisk => "random asterisk",
ReplacementStrategy.MiddleAsterisk => "middle asterisk",
ReplacementStrategy.VowelAsterisk => "vowel asterisk",
ReplacementStrategy.FirstLetterThenAsterisk => "first letter then asterisk",
ReplacementStrategy.AngerEmoji => "anger emoji",
ReplacementStrategy.Bleep => "bleep",
ReplacementStrategy.RedactedBlackRectangle => "redacted black rectangle",
ReplacementStrategy.RedactedRectangle => "redacted rectangle",
ReplacementStrategy.StrikeThrough => "string through",
ReplacementStrategy.Underscores => "underscores",

_ => "asterisk",
};
}
Expand All @@ -28,18 +30,19 @@ internal static Func<FilterTarget, MatchEvaluator> GetMatchEvaluator(this Replac
{
return replacementStrategy switch
{
ReplacementStrategy.Asterisk => MatchEvaluators.AsteriskEvaluator,
ReplacementStrategy.Emoji => MatchEvaluators.EmojiEvaluator,
ReplacementStrategy.RandomAsterisk => MatchEvaluators.RandomAsteriskEvaluator,
ReplacementStrategy.MiddleAsterisk => MatchEvaluators.MiddleAsteriskEvaluator,
ReplacementStrategy.MiddleSwearEmoji => MatchEvaluators.MiddleSwearEmojiEvaluator,
ReplacementStrategy.VowelAsterisk => MatchEvaluators.VowelAsteriskEvaluator,
ReplacementStrategy.FirstLetterThenAsterisk => MatchEvaluators.FirstLetterThenAsteriskEvaluator,
ReplacementStrategy.AngerEmoji => MatchEvaluators.AngerEmojiEvaluator,
ReplacementStrategy.Bleep => MatchEvaluators.BleepEvaluator,
ReplacementStrategy.RedactedBlackRectangle => MatchEvaluators.RedactedBlackRectangleEvaluator,
ReplacementStrategy.RedactedRectangle => MatchEvaluators.RedactedRectangleEvaluator,
ReplacementStrategy.StrikeThrough => MatchEvaluators.StrikeThroughEvaluator,
ReplacementStrategy.Underscores => MatchEvaluators.UnderscoresEvaluator,

_ => MatchEvaluators.EmojiEvaluator,
_ => MatchEvaluators.AsteriskEvaluator,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace ProfanityFilter.Services;

internal record class ProfaneFilter(
internal record class ProfaneSourceFilter(
string SourceName,
FrozenSet<string> ProfaneWords)
{
Expand Down
4 changes: 2 additions & 2 deletions src/ProfanityFilter.Services/Filters/ReplacementStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ public enum ReplacementStrategy

/// <summary>
/// Represents a replacement strategy where the profane word has each letter
/// replaced with the black rectangle symbol <c>█</c>.
/// replaced with the rectangle symbol <c>█</c>.
/// </summary>
RedactedBlackRectangle,
RedactedRectangle,

/// <summary>
/// Represents a replacement strategy where the profane word is <c>~~struck through~~</c>.
Expand Down
4 changes: 2 additions & 2 deletions src/ProfanityFilter.Services/Internals/MatchEvaluators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,9 @@ internal static MatchEvaluator BleepEvaluator(FilterTarget target) =>
};

/// <summary>
/// A <see cref="MatchEvaluator"/> that replaces each letter in a string with the black rectangle symbol <c>█</c>.
/// A <see cref="MatchEvaluator"/> that replaces each letter in a string with the rectangle symbol <c>█</c>.
/// </summary>
internal static MatchEvaluator RedactedBlackRectangleEvaluator(FilterTarget target) =>
internal static MatchEvaluator RedactedRectangleEvaluator(FilterTarget target) =>
string (match) =>
{
_ = target;
Expand Down
22 changes: 13 additions & 9 deletions tests/ProfanityFilter.Services.Tests/MatchEvaluatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,29 +48,33 @@ public void EmojiEvaluator_Returns_Expected_Result()
}

[Theory]
[InlineData("Test", @"T\*st")]
[InlineData("swear", @"sw\*\*r")]
public void VowelAsteriskEvaluator_Returns_Expected_Result(string input, string expected)
[InlineData(FilterTarget.Body, "Test", @"T\*st")]
[InlineData(FilterTarget.Body, "swear", @"sw\*\*r")]
[InlineData(FilterTarget.Title, "Test", @"T*st")]
[InlineData(FilterTarget.Title, "swear", @"sw**r")]
public void VowelAsteriskEvaluator_Returns_Expected_Result(FilterTarget target, string input, string expected)
{
var regex = TestRegex();
var match = regex.Match(input);
var sut = MatchEvaluators.VowelAsteriskEvaluator;

var actual = sut(FilterTarget.Body).Invoke(match);
var actual = sut(target).Invoke(match);

Assert.Equal(expected, actual);
}

[Theory]
[InlineData("Test", @"T\*\*t")]
[InlineData("swear", @"s\*\*\*r")]
public void MiddleAsteriskEvaluator_Returns_Expected_Result(string input, string expected)
[InlineData(FilterTarget.Body, "Test", @"T\*\*t")]
[InlineData(FilterTarget.Body, "swear", @"s\*\*\*r")]
[InlineData(FilterTarget.Title, "Test", @"T**t")]
[InlineData(FilterTarget.Title, "swear", @"s***r")]
public void MiddleAsteriskEvaluator_Returns_Expected_Result(FilterTarget target, string input, string expected)
{
var regex = TestRegex();
var match = regex.Match(input);
var sut = MatchEvaluators.MiddleAsteriskEvaluator;

var actual = sut(FilterTarget.Body).Invoke(match);
var actual = sut(target).Invoke(match);

Assert.Equal(expected, actual);
}
Expand All @@ -96,7 +100,7 @@ public void RedactedBlackRectangleEvaluator_Returns_Expected_Result(string input
{
var regex = TestRegex();
var match = regex.Match(input);
var sut = MatchEvaluators.RedactedBlackRectangleEvaluator;
var sut = MatchEvaluators.RedactedRectangleEvaluator;

var actual = sut(FilterTarget.Body).Invoke(match);

Expand Down

0 comments on commit 9d18a7d

Please sign in to comment.