164 lines
5.8 KiB
C#
164 lines
5.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Paca.Core;
|
|
using Xunit;
|
|
|
|
namespace Paca.Tests.Core;
|
|
|
|
public class MediaMuxerAndMetadataExtremeRedTests
|
|
{
|
|
private const string SampleIn1 = "C:\\Media\\video.mp4";
|
|
private const string SampleAudio = "C:\\Media\\audio.m4a";
|
|
private const string SampleOut = "C:\\Media\\output.mp4";
|
|
|
|
// ==========================================
|
|
// 1. MediaMetadataTagWriter
|
|
// ==========================================
|
|
|
|
[Fact]
|
|
public void MediaMetadataTagWriter_BuildFfmpegArgs_NullTag_ThrowsArgumentNullException()
|
|
{
|
|
Assert.Throws<ArgumentNullException>(() =>
|
|
MediaMetadataTagWriter.BuildFfmpegArgs(null!, SampleIn1, SampleOut));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null, SampleOut)]
|
|
[InlineData(SampleIn1, null)]
|
|
[InlineData("", SampleOut)]
|
|
[InlineData(SampleIn1, " ")]
|
|
public void MediaMetadataTagWriter_BuildFfmpegArgs_NullOrWhitespacePaths_ThrowsArgumentException(string? inPath, string? outPath)
|
|
{
|
|
var tag = new MediaMetadataTag { Title = "Song" };
|
|
Assert.Throws<ArgumentException>(() =>
|
|
MediaMetadataTagWriter.BuildFfmpegArgs(tag, inPath!, outPath!));
|
|
}
|
|
|
|
[Fact]
|
|
public void MediaMetadataTagWriter_BuildFfmpegArgs_SameInputAndOutput_ThrowsInvalidOperationException()
|
|
{
|
|
var tag = new MediaMetadataTag { Title = "Song" };
|
|
Assert.Throws<InvalidOperationException>(() =>
|
|
MediaMetadataTagWriter.BuildFfmpegArgs(tag, SampleIn1, SampleIn1));
|
|
}
|
|
|
|
[Fact]
|
|
public void MediaMetadataTagWriter_BuildFfmpegArgs_PathsWithQuotes_EscapedOrStripped()
|
|
{
|
|
var tag = new MediaMetadataTag { Title = "Song" };
|
|
string maliciousIn = "C:\\Media\\in\"put.mp4";
|
|
string maliciousOut = "C:\\Media\\out\"put.mp4";
|
|
|
|
var cmd = MediaMetadataTagWriter.BuildFfmpegArgs(tag, maliciousIn, maliciousOut);
|
|
Assert.NotNull(cmd);
|
|
Assert.DoesNotContain("in\"put", cmd);
|
|
Assert.DoesNotContain("out\"put", cmd);
|
|
}
|
|
|
|
// ==========================================
|
|
// 2. MultiTrackMediaMuxer
|
|
// ==========================================
|
|
|
|
[Fact]
|
|
public void MultiTrackMediaMuxer_BuildMuxCommandLine_NullJob_ThrowsArgumentNullException()
|
|
{
|
|
Assert.Throws<ArgumentNullException>(() =>
|
|
MultiTrackMediaMuxer.BuildMuxCommandLine(null!));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void MultiTrackMediaMuxer_BuildMuxCommandLine_NullOrWhitespaceOutputPath_ThrowsArgumentException(string? badOut)
|
|
{
|
|
var job = new MuxJobSpecification
|
|
{
|
|
VideoTrack = new TrackSpec(SampleIn1),
|
|
OutputPath = badOut!
|
|
};
|
|
Assert.Throws<ArgumentException>(() =>
|
|
MultiTrackMediaMuxer.BuildMuxCommandLine(job));
|
|
}
|
|
|
|
[Fact]
|
|
public void MultiTrackMediaMuxer_BuildMuxCommandLine_NoTracks_ThrowsInvalidOperationException()
|
|
{
|
|
var job = new MuxJobSpecification
|
|
{
|
|
OutputPath = SampleOut
|
|
};
|
|
Assert.Throws<InvalidOperationException>(() =>
|
|
MultiTrackMediaMuxer.BuildMuxCommandLine(job));
|
|
}
|
|
|
|
[Fact]
|
|
public void MultiTrackMediaMuxer_BuildMuxCommandLine_OutputPathMatchesAnyInput_ThrowsInvalidOperationException()
|
|
{
|
|
var job = new MuxJobSpecification
|
|
{
|
|
VideoTrack = new TrackSpec(SampleIn1),
|
|
AudioTracks = new List<TrackSpec> { new(SampleAudio) },
|
|
OutputPath = SampleAudio // Overwriting audio source!
|
|
};
|
|
Assert.Throws<InvalidOperationException>(() =>
|
|
MultiTrackMediaMuxer.BuildMuxCommandLine(job));
|
|
}
|
|
|
|
[Fact]
|
|
public void MultiTrackMediaMuxer_BuildMuxCommandLine_TrackTitleWithQuotes_EscapedSafely()
|
|
{
|
|
var job = new MuxJobSpecification
|
|
{
|
|
VideoTrack = new TrackSpec(SampleIn1),
|
|
AudioTracks = new List<TrackSpec> { new(SampleAudio, Title: "Director's \"Commentary\"") },
|
|
OutputPath = SampleOut
|
|
};
|
|
var cmd = MultiTrackMediaMuxer.BuildMuxCommandLine(job);
|
|
Assert.NotNull(cmd);
|
|
Assert.DoesNotContain("title=\"Director's \"Commentary\"\"", cmd);
|
|
}
|
|
|
|
// ==========================================
|
|
// 3. VideoTonemapEnhancer
|
|
// ==========================================
|
|
|
|
[Theory]
|
|
[InlineData(null, SampleOut)]
|
|
[InlineData(SampleIn1, null)]
|
|
public void VideoTonemapEnhancer_BuildFfmpegArgs_NullOrWhitespacePaths_ThrowsArgumentException(string? inPath, string? outPath)
|
|
{
|
|
Assert.Throws<ArgumentException>(() =>
|
|
VideoTonemapEnhancer.BuildFfmpegArgs(inPath!, outPath!, TonemapAlgorithm.Hable, ColorGradePreset.None));
|
|
}
|
|
|
|
[Fact]
|
|
public void VideoTonemapEnhancer_BuildFfmpegArgs_SameInputAndOutput_ThrowsInvalidOperationException()
|
|
{
|
|
Assert.Throws<InvalidOperationException>(() =>
|
|
VideoTonemapEnhancer.BuildFfmpegArgs(SampleIn1, SampleIn1, TonemapAlgorithm.Hable, ColorGradePreset.None));
|
|
}
|
|
|
|
[Fact]
|
|
public void VideoTonemapEnhancer_BuildFfmpegArgs_PathsWithQuotes_EscapedOrStripped()
|
|
{
|
|
string maliciousIn = "C:\\Media\\in\"put.mp4";
|
|
string maliciousOut = "C:\\Media\\out\"put.mp4";
|
|
|
|
var cmd = VideoTonemapEnhancer.BuildFfmpegArgs(maliciousIn, maliciousOut, TonemapAlgorithm.Hable, ColorGradePreset.None);
|
|
Assert.NotNull(cmd);
|
|
Assert.DoesNotContain("in\"put", cmd);
|
|
Assert.DoesNotContain("out\"put", cmd);
|
|
}
|
|
|
|
[Fact]
|
|
public void VideoTonemapEnhancer_BuildFfmpegArgs_InvalidEncoderOrCrf_ClampedSafely()
|
|
{
|
|
var cmd = VideoTonemapEnhancer.BuildFfmpegArgs(
|
|
SampleIn1, SampleOut, TonemapAlgorithm.Hable, ColorGradePreset.None,
|
|
crf: 999, videoEncoder: "libx264; echo pwned");
|
|
Assert.NotNull(cmd);
|
|
Assert.Contains("-crf 51", cmd);
|
|
Assert.DoesNotContain(";", cmd);
|
|
}
|
|
}
|