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
100
tests/Paca.Tests/Core/HlsAndDashResilienceExtremeRedTests.cs
Normal file
100
tests/Paca.Tests/Core/HlsAndDashResilienceExtremeRedTests.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using Paca.Core.Config;
|
||||
using Paca.Core.Dash;
|
||||
using Paca.Core.Hls;
|
||||
using Paca.Core.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace Paca.Tests.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Cycle 2: 극한 RED 시나리오 - HLS AES-128 암호화 IV/키 경계값 패딩, 블록 크기 손상 예외 정밀화, DASH 매니페스트 퍼징 검증
|
||||
/// </summary>
|
||||
public class HlsAndDashResilienceExtremeRedTests
|
||||
{
|
||||
[Fact]
|
||||
public void Cycle2_Gate1_ResolveIv_ShortHex_PadsTo16BytesBigEndian()
|
||||
{
|
||||
// RFC 8216: IV 속성은 128비트(16바이트) 빅엔디언 정수 16진수 표현
|
||||
// 0x1 과 같이 축약된 hex 가 주어졌을 때 1바이트가 아닌 16바이트로 좌측 0 패딩되어야 함
|
||||
var keyInfo = new KeyInfo(new Uri("https://example.com/key.bin"), "0x1");
|
||||
var iv = HlsDownloader.ResolveIv(keyInfo, 100);
|
||||
|
||||
Assert.Equal(16, iv.Length);
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
Assert.Equal(0, iv[i]);
|
||||
}
|
||||
Assert.Equal(1, iv[15]);
|
||||
|
||||
// 3바이트 hex (6글자)
|
||||
var keyHex6 = new KeyInfo(new Uri("https://example.com/key.bin"), "0xABCDEF");
|
||||
var iv6 = HlsDownloader.ResolveIv(keyHex6, 100);
|
||||
Assert.Equal(16, iv6.Length);
|
||||
Assert.Equal(0xAB, iv6[13]);
|
||||
Assert.Equal(0xCD, iv6[14]);
|
||||
Assert.Equal(0xEF, iv6[15]);
|
||||
|
||||
// 잘못된 비-16진수("0xZZZZ") 주입 시 크래시 없이 시퀀스 번호(100)로 안전 폴백
|
||||
var malformedKey = new KeyInfo(new Uri("https://example.com/key.bin"), "0xZZZZ");
|
||||
var ivFallback = HlsDownloader.ResolveIv(malformedKey, 100);
|
||||
Assert.Equal(16, ivFallback.Length);
|
||||
Assert.Equal(100, ivFallback[15]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cycle2_Gate2_DecryptSegment_InvalidKeyOrCorruptedBlock_ThrowsInvalidDataException()
|
||||
{
|
||||
var config = new AppConfig();
|
||||
var downloader = new HlsDownloader(new System.Net.Http.HttpClient(), config);
|
||||
var keyUri = new Uri("https://example.com/aes.key");
|
||||
var seg = new Segment(new Uri("https://example.com/seg1.ts"), 0, 1, new KeyInfo(keyUri, "0x1"));
|
||||
|
||||
// 1. 비정상 키 길이 (16바이트가 아닌 10바이트 등) -> InvalidDataException 발생 확인
|
||||
downloader.SetPreloadedKeyForTesting(keyUri, new byte[10]);
|
||||
var exKey = Assert.Throws<InvalidDataException>(() => downloader.DecryptSegmentForTesting(new byte[16], seg));
|
||||
Assert.Contains("16바이트", exKey.Message);
|
||||
|
||||
// 2. 비정상 데이터 블록 크기 (AES CBC는 16의 배수여야 함, 15바이트 주입) -> InvalidDataException 발생 확인
|
||||
downloader.SetPreloadedKeyForTesting(keyUri, new byte[16]);
|
||||
var exData = Assert.Throws<InvalidDataException>(() => downloader.DecryptSegmentForTesting(new byte[15], seg));
|
||||
Assert.Contains("블록 크기", exData.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cycle2_Gate3_DashParser_TimescaleZeroOrNegative_DefaultsToOne()
|
||||
{
|
||||
var mpdXml = """
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" mediaPresentationDuration="PT10S">
|
||||
<Period>
|
||||
<AdaptationSet contentType="video">
|
||||
<Representation id="1" bandwidth="2000000">
|
||||
<SegmentTemplate timescale="0" duration="2" media="chunk_$Number$.m4s" startNumber="1" />
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
</MPD>
|
||||
""";
|
||||
|
||||
var manifest = DashParser.Parse(mpdXml, new Uri("https://cdn.example.com/manifest.mpd"));
|
||||
Assert.NotNull(manifest);
|
||||
Assert.NotNull(manifest.Video);
|
||||
// timescale="0"이어도 0으로 나누기 예외 없이 1로 폴백되어 5개 세그먼트 생성
|
||||
Assert.NotEmpty(manifest.Video.Segments);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("P1D", 86400.0)]
|
||||
[InlineData("P1DT2H", 93600.0)]
|
||||
[InlineData("PT1H30M", 5400.0)]
|
||||
[InlineData("PT1.5S", 1.5)]
|
||||
[InlineData("", 0.0)]
|
||||
[InlineData("INVALID_DURATION", 0.0)]
|
||||
public void Cycle2_Gate4_DashParser_Iso8601Duration_SupportsDaysAndFractions(string isoDuration, double expectedSec)
|
||||
{
|
||||
double actual = DashParser.ParseDuration(isoDuration);
|
||||
Assert.Equal(expectedSec, actual, precision: 2);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue