using System; using System.Text; using System.Threading.Tasks; using Paca.Core.QuickActions; using Xunit; namespace Paca.Tests.Core; public class QuickActionsExtremeRedTests { // ========================================== // 1. QuickActionFuzzyMatcher Memory & DoS // ========================================== [Fact] public void QuickActionFuzzyMatcher_LevenshteinDistance_LargeStrings_DoesNotThrowOutOfMemory() { // 5000 character strings would allocate ~100MB in 2D array if unbounded string large1 = new string('A', 3000); string large2 = new string('B', 3000); var ex = Record.Exception(() => QuickActionFuzzyMatcher.LevenshteinDistance(large1, large2)); Assert.Null(ex); } [Theory] [InlineData(null, null)] [InlineData(null, "abc")] [InlineData("xyz", null)] public void QuickActionFuzzyMatcher_LevenshteinDistance_Nulls_HandledGracefully(string? s, string? t) { var ex = Record.Exception(() => QuickActionFuzzyMatcher.LevenshteinDistance(s, t)); Assert.Null(ex); } // ========================================== // 2. QuickActionInlineEvaluator Hardening // ========================================== [Theory] [InlineData("-5 + 10", "5")] [InlineData("10 * -2", "-20")] [InlineData("-4 * -3", "12")] public void QuickActionInlineEvaluator_TryEvaluateMath_NegativeNumbers_CalculatesCorrectly(string expr, string expected) { var eval = new QuickActionInlineEvaluator(); bool success = eval.TryEvaluate(expr, out var res); Assert.True(success, $"Expression '{expr}' should be successfully evaluated"); Assert.NotNull(res); Assert.Equal(expected, res.Value); } [Theory] [InlineData("#fff", "rgb(255, 255, 255)")] [InlineData("#F00", "rgb(255, 0, 0)")] [InlineData("hex 000", "rgb(0, 0, 0)")] public void QuickActionInlineEvaluator_TryEvaluateDev_Hex3DigitShorthand_ExpandsCorrectly(string hexInput, string expectedRgb) { var eval = new QuickActionInlineEvaluator(); bool success = eval.TryEvaluate(hexInput, out var res); Assert.True(success, $"Shorthand hex '{hexInput}' should be parsed"); Assert.NotNull(res); Assert.Equal(expectedRgb, res.Value); } [Fact] public void QuickActionInlineEvaluator_TryEvaluateDev_Base64WithNullBytes_DoesNotReturnRawNullChars() { var eval = new QuickActionInlineEvaluator(); // Base64 containing null bytes: "\0\0\0" -> "AAAA" bool success = eval.TryEvaluate("b64d AAAA", out var res); Assert.True(success); Assert.NotNull(res); Assert.DoesNotContain('\0', res.Value); } // ========================================== // 3. QuickActionClipboardDetector Security & Resilience // ========================================== [Fact] public void QuickActionClipboardDetector_DetectIntent_EnormousClipboard_DoesNotSpikeOrHang() { var detector = new QuickActionClipboardDetector(); string hugeText = new string('x', 500_000); // 500KB var intent = detector.DetectIntent(hugeText); Assert.NotNull(intent); Assert.Equal(ClipboardIntentType.None, intent.IntentType); } [Theory] [InlineData("youtube.com/watch?v=dQw4w9WgXcQ")] [InlineData("www.youtube.com/watch?v=dQw4w9WgXcQ")] [InlineData("youtu.be/dQw4w9WgXcQ")] public void QuickActionClipboardDetector_DetectIntent_MediaUrlWithoutScheme_DetectedAsMediaDownload(string rawUrl) { var detector = new QuickActionClipboardDetector(); var intent = detector.DetectIntent(rawUrl); Assert.NotNull(intent); Assert.Equal(ClipboardIntentType.MediaDownload, intent.IntentType); } // ========================================== // 4. QuickActionParameterRouter Null Context Defenses // ========================================== [Theory] [InlineData("b64 hello")] [InlineData("b64d aGVsbG8=")] [InlineData("hash password123")] [InlineData("note sample note")] public async Task QuickActionParameterRouter_Handlers_NullContext_DoesNotThrowNullReferenceException(string command) { var router = new QuickActionParameterRouter(); bool parsed = router.TryParseCommand(command, out var action); Assert.True(parsed); Assert.NotNull(action); var ex = await Record.ExceptionAsync(async () => await action!.Handler!(null!)); Assert.Null(ex); } }