test(core/browser/platform): 26 extreme RED/GREEN TDD cycles and full regression hardening (3,235 PASS)
This commit is contained in:
parent
bcd242691f
commit
8677853822
100 changed files with 4814 additions and 333 deletions
171
tests/Paca.Tests/Core/AudioEnginesExtremeRedTests.cs
Normal file
171
tests/Paca.Tests/Core/AudioEnginesExtremeRedTests.cs
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Paca.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Paca.Tests.Core;
|
||||
|
||||
public class AudioEnginesExtremeRedTests
|
||||
{
|
||||
[Fact]
|
||||
public void AudioPitchShiftEngine_InPlaceOverwrite_ThrowsArgumentException()
|
||||
{
|
||||
var ex = Assert.Throws<ArgumentException>(() =>
|
||||
AudioPitchShiftEngine.BuildPitchShiftCommandLine("track.mp3", "track.mp3", 2.0));
|
||||
Assert.Contains("identical", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "out.mp3")]
|
||||
[InlineData("", "out.mp3")]
|
||||
[InlineData(" ", "out.mp3")]
|
||||
[InlineData("in.mp3", null)]
|
||||
[InlineData("in.mp3", "")]
|
||||
[InlineData("in.mp3", " ")]
|
||||
public void AudioPitchShiftEngine_NullOrEmptyPaths_ThrowsArgumentException(string? inPath, string? outPath)
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
AudioPitchShiftEngine.BuildPitchShiftCommandLine(inPath!, outPath!, 2.0));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(double.NaN)]
|
||||
[InlineData(double.PositiveInfinity)]
|
||||
[InlineData(double.NegativeInfinity)]
|
||||
public void AudioPitchShiftEngine_NaNOrInfinitySemitones_FallsBackToZeroShift(double invalidSemitones)
|
||||
{
|
||||
var filter = AudioPitchShiftEngine.BuildPitchShiftFilter(invalidSemitones, 44100);
|
||||
Assert.DoesNotContain("NaN", filter, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.DoesNotContain("Infinity", filter, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("asetrate=44100", filter);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(-44100)]
|
||||
public void AudioPitchShiftEngine_InvalidSampleRate_ThrowsArgumentOutOfRangeException(int sampleRate)
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
AudioPitchShiftEngine.BuildPitchShiftFilter(2.0, sampleRate));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudioDynamicRangeCompressor_InPlaceOverwrite_ThrowsArgumentException()
|
||||
{
|
||||
var ex = Assert.Throws<ArgumentException>(() =>
|
||||
AudioDynamicRangeCompressor.BuildFfmpegArgs("podcast.wav", "podcast.wav", CompressorPreset.NightListening));
|
||||
Assert.Contains("identical", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "out.mp3")]
|
||||
[InlineData("", "out.mp3")]
|
||||
[InlineData("in.mp3", null)]
|
||||
[InlineData("in.mp3", "")]
|
||||
public void AudioDynamicRangeCompressor_NullOrEmptyPaths_ThrowsArgumentException(string? inPath, string? outPath)
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
AudioDynamicRangeCompressor.BuildFfmpegArgs(inPath!, outPath!, CompressorPreset.PodcastSpeech));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudioDynamicRangeCompressor_InvalidBitrate_DefaultsTo192k()
|
||||
{
|
||||
var args = AudioDynamicRangeCompressor.BuildFfmpegArgs("in.mp4", "out.mp4", CompressorPreset.NightListening, audioBitrateKbps: 0);
|
||||
Assert.Contains("-b:a 192k", args);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(double.NaN, 4.0, 10.0, 100.0, 4.0, -1.0)]
|
||||
[InlineData(-20.0, double.PositiveInfinity, 10.0, 100.0, 4.0, -1.0)]
|
||||
[InlineData(-20.0, 4.0, double.NaN, 100.0, 4.0, -1.0)]
|
||||
[InlineData(-20.0, -1.0, 10.0, 100.0, 4.0, -1.0)] // Invalid ratio <= 0
|
||||
public void AudioDynamicRangeCompressor_InvalidCustomParameters_ThrowsArgumentOutOfRangeException(
|
||||
double th, double ratio, double attack, double release, double makeup, double limit)
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
AudioDynamicRangeCompressor.BuildCustomFilter(th, ratio, attack, release, makeup, limit));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudioAlbumTrackSplitter_InPlaceOverwrite_ThrowsArgumentException()
|
||||
{
|
||||
var seg = new AlbumTrackSegment(1, 0.0, 60.0, "Track 01");
|
||||
var ex = Assert.Throws<ArgumentException>(() =>
|
||||
AudioAlbumTrackSplitter.BuildSplitCommand("album.flac", seg, "album.flac"));
|
||||
Assert.Contains("identical", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudioAlbumTrackSplitter_NullTrack_ThrowsArgumentNullException()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
AudioAlbumTrackSplitter.BuildSplitCommand("in.mp3", null!, "out.mp3"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(double.NaN)]
|
||||
[InlineData(double.PositiveInfinity)]
|
||||
[InlineData(-10.0)]
|
||||
public void AudioAlbumTrackSplitter_ParseSilenceToTracks_InvalidDuration_ReturnsEmpty(double totalDuration)
|
||||
{
|
||||
var tracks = AudioAlbumTrackSplitter.ParseSilenceToTracks("silence_start: 10.0\nsilence_end: 12.0", totalDuration);
|
||||
Assert.Empty(tracks);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudioAlbumTrackSplitter_GenerateM3uPlaylist_CrlfInjectionSanitized()
|
||||
{
|
||||
var tracks = new List<AlbumTrackSegment>
|
||||
{
|
||||
new(1, 0.0, 180.0, "Song\r\n#EXT-X-MALICIOUS-TAG")
|
||||
};
|
||||
var m3u = AudioAlbumTrackSplitter.GenerateM3uPlaylist("MyAlbum\r\n#FORGED-HEADER", tracks);
|
||||
var lines = m3u.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line.StartsWith("#EXTINF:"))
|
||||
{
|
||||
Assert.DoesNotContain("\r", line);
|
||||
Assert.DoesNotContain("\n", line);
|
||||
Assert.Contains("MyAlbum", line);
|
||||
}
|
||||
Assert.False(line.Equals("#EXT-X-MALICIOUS-TAG", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.False(line.Equals("#FORGED-HEADER", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudioVocalStemExtractor_InPlaceOverwrite_ThrowsArgumentException()
|
||||
{
|
||||
var ex = Assert.Throws<ArgumentException>(() =>
|
||||
AudioVocalStemExtractor.BuildStemCommandLine("audio.wav", "audio.wav", AudioStemMode.VocalRemovalKaraoke));
|
||||
Assert.Contains("identical", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudioChannelDownmixer_InPlaceOverwrite_ThrowsArgumentException()
|
||||
{
|
||||
var ex = Assert.Throws<ArgumentException>(() =>
|
||||
AudioChannelDownmixer.BuildDownmixCommandLine("movie.mkv", "movie.mkv", DownmixMode.StandardItuR775));
|
||||
Assert.Contains("identical", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudioVolumeNormalizer_InPlaceOverwrite_ThrowsArgumentException()
|
||||
{
|
||||
var ex = Assert.Throws<ArgumentException>(() =>
|
||||
AudioVolumeNormalizer.BuildNormalizeCommandLine("stream.aac", "stream.aac", AudioVolumeNormalizer.PodcastStreamingPreset));
|
||||
Assert.Contains("identical", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AudioVolumeNormalizer_NullPreset_ThrowsArgumentNullException()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
AudioVolumeNormalizer.BuildNormalizeCommandLine("in.aac", "out.aac", null!));
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
AudioVolumeNormalizer.BuildLoudnormFilterArgs(null!));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue