124 lines
4.5 KiB
C#
124 lines
4.5 KiB
C#
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);
|
|
}
|
|
}
|
|
|