131 lines
3.7 KiB
C#
131 lines
3.7 KiB
C#
using System;
|
|
using Paca.Core.Hls;
|
|
using Paca.Core.Models;
|
|
using Xunit;
|
|
|
|
namespace Paca.Tests.Core;
|
|
|
|
public class M3u8ParserByteRangeAndfMp4ExtremeRedTests
|
|
{
|
|
private static readonly Uri Base = new("https://cdn.example.com/stream/playlist.m3u8");
|
|
|
|
[Fact]
|
|
public void M3u8Parser_ByteRange_ExplicitLengthAndOffset_ParsedCorrectly()
|
|
{
|
|
var text = @"#EXTM3U
|
|
#EXT-X-TARGETDURATION:10
|
|
#EXT-X-BYTERANGE:1000@500
|
|
segment.ts";
|
|
|
|
var playlist = M3u8Parser.Parse(text, Base);
|
|
Assert.Single(playlist.Segments);
|
|
var seg = playlist.Segments[0];
|
|
Assert.Equal(1000, seg.ByteRangeLength);
|
|
Assert.Equal(500, seg.ByteRangeOffset);
|
|
}
|
|
|
|
[Fact]
|
|
public void M3u8Parser_ByteRange_SequentialImplicitOffset_AccumulatesCorrectly()
|
|
{
|
|
var text = @"#EXTM3U
|
|
#EXT-X-TARGETDURATION:10
|
|
#EXT-X-BYTERANGE:1000@0
|
|
segment.ts
|
|
#EXT-X-BYTERANGE:2000
|
|
segment.ts
|
|
#EXT-X-BYTERANGE:1500
|
|
segment.ts";
|
|
|
|
var playlist = M3u8Parser.Parse(text, Base);
|
|
Assert.Equal(3, playlist.Segments.Count);
|
|
|
|
Assert.Equal(1000, playlist.Segments[0].ByteRangeLength);
|
|
Assert.Equal(0, playlist.Segments[0].ByteRangeOffset);
|
|
|
|
Assert.Equal(2000, playlist.Segments[1].ByteRangeLength);
|
|
Assert.Equal(1000, playlist.Segments[1].ByteRangeOffset);
|
|
|
|
Assert.Equal(1500, playlist.Segments[2].ByteRangeLength);
|
|
Assert.Equal(3000, playlist.Segments[2].ByteRangeOffset);
|
|
}
|
|
|
|
[Fact]
|
|
public void M3u8Parser_ByteRange_InvalidNegativeOrNonNumeric_IgnoredGracefully()
|
|
{
|
|
var text = @"#EXTM3U
|
|
#EXT-X-TARGETDURATION:10
|
|
#EXT-X-BYTERANGE:-500@-100
|
|
segment1.ts
|
|
#EXT-X-BYTERANGE:invalid@nan
|
|
segment2.ts";
|
|
|
|
var playlist = M3u8Parser.Parse(text, Base);
|
|
Assert.Equal(2, playlist.Segments.Count);
|
|
|
|
Assert.Null(playlist.Segments[0].ByteRangeLength);
|
|
Assert.Null(playlist.Segments[0].ByteRangeOffset);
|
|
|
|
Assert.Null(playlist.Segments[1].ByteRangeLength);
|
|
Assert.Null(playlist.Segments[1].ByteRangeOffset);
|
|
}
|
|
|
|
[Fact]
|
|
public void M3u8Parser_InitSegment_WithByteRange_ParsedCorrectly()
|
|
{
|
|
var text = @"#EXTM3U
|
|
#EXT-X-TARGETDURATION:10
|
|
#EXT-X-MAP:URI=""init.mp4"",BYTERANGE=""800@0""
|
|
#EXTINF:6.0,
|
|
segment1.m4s";
|
|
|
|
var playlist = M3u8Parser.Parse(text, Base);
|
|
Assert.NotNull(playlist.InitSegment);
|
|
Assert.Equal("https://cdn.example.com/stream/init.mp4", playlist.InitSegment.AbsoluteUri);
|
|
Assert.Equal(800, playlist.InitByteRangeLength);
|
|
Assert.Equal(0, playlist.InitByteRangeOffset);
|
|
}
|
|
|
|
[Fact]
|
|
public void M3u8Parser_NullBaseUrl_ReturnsEmptyPlaylistWithoutCrashing()
|
|
{
|
|
var text = @"#EXTM3U
|
|
#EXT-X-TARGETDURATION:10
|
|
segment.ts";
|
|
|
|
var playlist = M3u8Parser.Parse(text, null!);
|
|
Assert.NotNull(playlist);
|
|
Assert.Empty(playlist.Segments);
|
|
}
|
|
|
|
[Fact]
|
|
public void Variant_NegativeOrMalformedResolution_ClampsToZero()
|
|
{
|
|
var v = new Variant(new Uri("https://example.com/v.m3u8"), 1000, "-1920x-1080", "avc1");
|
|
Assert.Equal(0, v.Width);
|
|
Assert.Equal(0, v.Height);
|
|
}
|
|
|
|
[Fact]
|
|
public void Variant_ComplexResolution_ParsesWidthAndHeight()
|
|
{
|
|
var v = new Variant(new Uri("https://example.com/v.m3u8"), 1000, "1920x1080@60fps", "avc1");
|
|
Assert.Equal(1920, v.Width);
|
|
Assert.Equal(1080, v.Height);
|
|
}
|
|
|
|
[Fact]
|
|
public void M3u8Parser_MediaSequence_Int64Overflow_DoesNotGoNegative()
|
|
{
|
|
var text = @"#EXTM3U
|
|
#EXT-X-MEDIA-SEQUENCE:9223372036854775807
|
|
#EXTINF:6.0,
|
|
seg1.ts
|
|
#EXTINF:6.0,
|
|
seg2.ts";
|
|
|
|
var playlist = M3u8Parser.Parse(text, Base);
|
|
Assert.Equal(2, playlist.Segments.Count);
|
|
Assert.True(playlist.Segments[0].Sequence >= 0);
|
|
Assert.True(playlist.Segments[1].Sequence >= 0);
|
|
}
|
|
}
|