releases/tests/Paca.Tests/Core/AiMediaAndShaderEnginesExtremeRedTests.cs
Yun Chan 8677853822
Some checks failed
release / test (push) Failing after 14m5s
release / windows (push) Has been cancelled
release / android (push) Has been cancelled
release / linux (push) Has been cancelled
release / macos (push) Has been cancelled
test(core/browser/platform): 26 extreme RED/GREEN TDD cycles and full regression hardening (3,235 PASS)
2026-09-18 23:32:32 +09:00

204 lines
7 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using Paca.Core.Detection;
using Paca.Core.Gateway;
using Paca.Core.Media;
using Xunit;
namespace Paca.Tests.Core;
public class AiMediaAndShaderEnginesExtremeRedTests
{
private const string SampleInput = "C:\\Videos\\source.mp4";
private const string SampleOutput = "C:\\Videos\\shorts.mp4";
// ==========================================
// 1. AiHighlightClipper
// ==========================================
[Theory]
[InlineData(0)]
[InlineData(-100)]
[InlineData(double.NaN)]
public void AiHighlightClipper_DetectHighlights_ZeroOrNegativeDuration_ReturnsEmpty(double duration)
{
var highlights = AiHighlightClipper.DetectHighlights(duration);
Assert.NotNull(highlights);
Assert.Empty(highlights);
}
[Theory]
[InlineData(0)]
[InlineData(-10)]
[InlineData(double.NaN)]
public void AiHighlightClipper_DetectHighlights_ZeroOrNegativeWindowSeconds_DoesNotCrashOrLoopInfinitely(double windowSec)
{
var highlights = AiHighlightClipper.DetectHighlights(120.0, windowSeconds: windowSec);
Assert.NotNull(highlights);
Assert.NotEmpty(highlights);
}
[Fact]
public void AiHighlightClipper_BuildFfmpegShortsCommand_SameInputAndOutput_ThrowsInvalidOperationException()
{
var spec = new ShortsClipSpec();
Assert.Throws<InvalidOperationException>(() =>
AiHighlightClipper.BuildFfmpegShortsCommand(SampleInput, SampleInput, spec));
}
[Theory]
[InlineData(null, SampleOutput)]
[InlineData(SampleInput, null)]
[InlineData("", SampleOutput)]
[InlineData(SampleInput, " ")]
public void AiHighlightClipper_BuildFfmpegShortsCommand_NullOrWhitespacePaths_ThrowsArgumentException(string? inPath, string? outPath)
{
var spec = new ShortsClipSpec();
Assert.Throws<ArgumentException>(() =>
AiHighlightClipper.BuildFfmpegShortsCommand(inPath!, outPath!, spec));
}
[Fact]
public void AiHighlightClipper_BuildFfmpegShortsCommand_NullSpec_ThrowsArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() =>
AiHighlightClipper.BuildFfmpegShortsCommand(SampleInput, SampleOutput, null!));
}
[Fact]
public void AiHighlightClipper_BuildFfmpegShortsCommand_PathsWithQuotes_Stripped()
{
var spec = new ShortsClipSpec();
string maliciousIn = "C:\\Videos\\so\"urce.mp4";
string maliciousOut = "C:\\Videos\\sh\"orts.mp4";
var args = AiHighlightClipper.BuildFfmpegShortsCommand(maliciousIn, maliciousOut, spec);
Assert.NotNull(args);
Assert.DoesNotContain(args, a => a.Contains('"'));
}
// ==========================================
// 2. FftAudioWaveformEngine
// ==========================================
[Fact]
public void FftAudioWaveformEngine_BuildFfmpegEqualizerFilter_NullOrEmptyBands_ReturnsEmptyString()
{
Assert.Equal(string.Empty, FftAudioWaveformEngine.BuildFfmpegEqualizerFilter(null!));
Assert.Equal(string.Empty, FftAudioWaveformEngine.BuildFfmpegEqualizerFilter(new List<EqualizerBand>()));
}
[Fact]
public void FftAudioWaveformEngine_BuildFfmpegEqualizerFilter_ListContainingNullBands_SkipsSafely()
{
var bands = new List<EqualizerBand>
{
null!,
new() { FrequencyHz = 1000, GainDb = 3.5 },
null!
};
var filter = FftAudioWaveformEngine.BuildFfmpegEqualizerFilter(bands);
Assert.NotNull(filter);
Assert.Contains("equalizer=f=1000", filter);
}
[Fact]
public void FftAudioWaveformEngine_BuildFfmpegEqualizerFilter_InCommaDecimalCulture_UsesDotDecimalSeparator()
{
var originalCulture = Thread.CurrentThread.CurrentCulture;
try
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("de-DE"); // German culture uses ',' for decimal
var bands = new List<EqualizerBand>
{
new() { FrequencyHz = 500, GainDb = 4.5 }
};
var filter = FftAudioWaveformEngine.BuildFfmpegEqualizerFilter(bands);
Assert.Contains("g=4.5", filter);
Assert.DoesNotContain("g=4,5", filter);
}
finally
{
Thread.CurrentThread.CurrentCulture = originalCulture;
}
}
// ==========================================
// 3. NeuralShaderUpscaler
// ==========================================
[Fact]
public void NeuralShaderUpscaler_GenerateHlslShaderCode_NullConfig_DoesNotThrow()
{
var shader = NeuralShaderUpscaler.GenerateHlslShaderCode(null!);
Assert.NotNull(shader);
Assert.Contains("float4 PS_NeuralUpscale", shader);
}
[Theory]
[InlineData(0, 0)]
[InlineData(-1920, -1080)]
public void NeuralShaderUpscaler_GenerateHlslShaderCode_ZeroOrNegativeDimensions_FallsBackToDefaultResolution(int w, int h)
{
var config = new ShaderUpscaleConfig { TargetWidth = w, TargetHeight = h };
var shader = NeuralShaderUpscaler.GenerateHlslShaderCode(config);
Assert.NotNull(shader);
Assert.DoesNotContain("1.0 / 0", shader);
Assert.DoesNotContain("1.0 / -", shader);
}
[Fact]
public void NeuralShaderUpscaler_GenerateHlslShaderCode_InCommaDecimalCulture_UsesDotDecimalSeparator()
{
var originalCulture = Thread.CurrentThread.CurrentCulture;
try
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR"); // French culture uses ',' for decimal
var config = new ShaderUpscaleConfig { Sharpness = 2.5 };
var shader = NeuralShaderUpscaler.GenerateHlslShaderCode(config);
Assert.Contains("2.50", shader);
Assert.DoesNotContain("2,50", shader);
}
finally
{
Thread.CurrentThread.CurrentCulture = originalCulture;
}
}
// ==========================================
// 4. PacaConnectCodeGenerator
// ==========================================
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("PACA-12345")] // 5 chars instead of 6
[InlineData("PACA-1234567")] // 7 chars
[InlineData("PACA-000000")] // '0' is disallowed
[InlineData("PACA-111111")] // '1' is disallowed
[InlineData("PACA-IIIIII")] // 'I' is disallowed
[InlineData("PACA-OOOOOO")] // 'O' is disallowed
[InlineData("OTHER-234567")] // wrong prefix
public void PacaConnectCodeGenerator_IsValid_InvalidCodes_ReturnsFalse(string? code)
{
Assert.False(PacaConnectCodeGenerator.IsValid(code));
}
[Fact]
public void PacaConnectCodeGenerator_GenerateCode_AlwaysProducesValidCode()
{
for (int i = 0; i < 50; i++)
{
var code = PacaConnectCodeGenerator.GenerateCode();
Assert.True(PacaConnectCodeGenerator.IsValid(code), $"Generated code '{code}' should be valid.");
}
}
}