< Summary

Class:DCL.ProfanityFiltering.ThrottledRegexProfanityFilter
Assembly:ProfanityFiltering
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Helpers/ProfanityFiltering/ThrottledRegexProfanityFilter.cs
Covered lines:22
Uncovered lines:14
Coverable lines:36
Total lines:91
Line coverage:61.1% (22 of 36)
Covered branches:0
Total branches:0
Covered methods:5
Total methods:7
Method coverage:71.4% (5 of 7)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
ThrottledRegexProfanityFilter(...)0%110100%
Dispose()0%110100%
Initialize()0%330100%
Filter()0%72800%
CheckTimerAndSkipFrame()0%20400%
ToRegex(...)0%110100%
ToChunks[T](...)0%330100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Helpers/ProfanityFiltering/ThrottledRegexProfanityFilter.cs

#LineLine coverage
 1using Cysharp.Threading.Tasks;
 2using System.Collections.Generic;
 3using System.Diagnostics;
 4using System.Linq;
 5using System.Text;
 6using System.Text.RegularExpressions;
 7using System.Threading;
 8using System.Threading.Tasks;
 9
 10namespace DCL.ProfanityFiltering
 11{
 12    public class ThrottledRegexProfanityFilter : IProfanityFilter
 13    {
 14        private readonly IProfanityWordProvider wordProvider;
 15        private readonly int partitionSize;
 11516        private readonly List<Regex> regexSteps = new ();
 17
 18        /// <param name="wordProvider"></param>
 19        /// <param name="partitionSize">Check https://github.com/decentraland/unity-renderer/issues/2201 for more info a
 11520        public ThrottledRegexProfanityFilter(IProfanityWordProvider wordProvider, int partitionSize = 1)
 21        {
 11522            this.wordProvider = wordProvider;
 11523            this.partitionSize = partitionSize;
 11524        }
 25
 26        public void Dispose()
 27        {
 11528            regexSteps.Clear();
 11529        }
 30
 31        public void Initialize()
 32        {
 11533            List<string> explicitWords = wordProvider.GetExplicitWords().ToList();
 11534            List<string> nonExplicitWords = wordProvider.GetNonExplicitWords().ToList();
 35
 11536            var explicitWordsChunks = ToChunks(explicitWords, partitionSize);
 11537            var nonExplicitWordsChunks = ToChunks(nonExplicitWords, partitionSize);
 38
 69039            for (var i = 0; i < explicitWordsChunks.Count; i++)
 40            {
 23041                var explicitWordsRegex = ToRegex(explicitWordsChunks[i]);
 23042                var regex = new Regex(@$"\b({explicitWordsRegex})\b", RegexOptions.IgnoreCase | RegexOptions.Compiled);
 23043                regexSteps.Add(regex);
 44            }
 45
 460046            for (var i = 0; i < nonExplicitWordsChunks.Count; i++)
 47            {
 218548                var nonExplicitWordsRegex = ToRegex(nonExplicitWordsChunks[i]);
 218549                var regex = new Regex(@$"\\b|({nonExplicitWordsRegex})", RegexOptions.IgnoreCase | RegexOptions.Compiled
 218550                regexSteps.Add(regex);
 51            }
 11552        }
 53
 54        public async UniTask<string> Filter(string message, CancellationToken cancellationToken = default)
 55        {
 056            if (string.IsNullOrEmpty(message))
 057                return message;
 58
 059            var stopwatch = new Stopwatch();
 060            stopwatch.Start();
 61
 062            foreach (Regex regexStep in regexSteps)
 63            {
 064                await CheckTimerAndSkipFrame(stopwatch, cancellationToken);
 065                message = regexStep.Replace(message, match => new StringBuilder().Append('*', match.Value.Length).ToStri
 066            }
 67
 068            return message;
 069        }
 70
 71        private async Task CheckTimerAndSkipFrame(Stopwatch stopwatch, CancellationToken cancellationToken)
 72        {
 073            if (stopwatch.ElapsedMilliseconds > 1)
 74            {
 075                await UniTask.WaitForEndOfFrame(cancellationToken: cancellationToken);
 076                stopwatch.Restart();
 77            }
 078        }
 79
 241580        private string ToRegex(IEnumerable<string> words) => string.Join("|", words);
 81
 82        private List<List<T>> ToChunks<T>(List<T> source, int chunkSize)
 83        {
 23084            return source
 85                  .Select((value, index) => (index, value))
 86                  .GroupBy(x => x.index / chunkSize)
 87                  .Select(x => x.Select(v => v.value).ToList())
 88                  .ToList();
 89        }
 90    }
 91}