mirror of
https://github.com/Vateron-Media/XC_VM.git
synced 2026-09-25 20:01:56 +02:00
Namespace all of Domain into XcVm\Domain\<Subdir> (33 classes across Bouquet,
Device, Epg, Line, Security, Server, Stream, User, Vod).
- Add namespace to every Domain class; add use to referrers across src/ and
tests/; convert the leading-backslash refs qualified in earlier Core commits
(\UserRepository, \ServerRepository, \BouquetService, \CategoryService,
\ConnectionTracker, \BlocklistService, ...) to their FQCNs.
- Qualify still-global / built-in deps inside Domain with leading backslash
(\RedisManager, \TMDB, \WatchService, \FFprobeRunner, \ProcessChecker,
\Exception, \DateTime, \PDO, ...) — Infrastructure/Streaming/module classes
migrate later.
- BruteforceGuard: string guards class_exists('ServerRepository'/'BlocklistService')
→ ::class FQCN; drop the now-always-true method_exists check.
- phpstan-baseline.neon regenerated (292→291).
Verified: php -l clean; PHPStan no errors; PHPUnit 295/295; leading-backslash
re-sweep across Domain classes is clean.
130 lines
4.3 KiB
PHP
130 lines
4.3 KiB
PHP
<?php
|
|
|
|
use XcVm\Domain\Stream\StreamService;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* Integration tests for StreamService::parseM3U().
|
|
*
|
|
* Validates the parsing behaviour and the import array field extraction
|
|
* logic that the stream import pipeline relies on.
|
|
*/
|
|
final class StreamServiceParseM3UTest extends TestCase {
|
|
// ── helpers ────────────────────────────────────────────────────────────
|
|
|
|
/** Shortcut: parse inline M3U string via StreamService. */
|
|
private function parse(string $m3u): \M3uParser\M3uData {
|
|
return StreamService::parseM3U($m3u, false);
|
|
}
|
|
|
|
/** Build import array from a single parsed entry (mirrors the logic in process()). */
|
|
private function buildImportArray(\M3uParser\M3uData $data): ?array {
|
|
foreach ($data as $result) {
|
|
$tags = $result->getExtTags();
|
|
$tag = $tags[0] ?? null;
|
|
$url = $result->getPath();
|
|
|
|
if (!$url) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'stream_source' => [$url],
|
|
'stream_icon' => $tag ? ($tag->getAttribute('tvg-logo') ?: ($tag->getAttribute('logo') ?: '')) : '',
|
|
'stream_display_name' => $tag
|
|
? ($tag->getTitle() ?: basename(parse_url($url, PHP_URL_PATH) ?: $url))
|
|
: basename(parse_url($url, PHP_URL_PATH) ?: $url),
|
|
];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// ── parseM3U tests ─────────────────────────────────────────────────────
|
|
|
|
public function testParsesBasicExtInfEntry(): void {
|
|
$m3u = "#EXTM3U\n#EXTINF:-1 tvg-id=\"ch1\",Channel One\nhttp://example.com/stream.m3u8\n";
|
|
|
|
$data = $this->parse($m3u);
|
|
|
|
$this->assertCount(1, $data);
|
|
}
|
|
|
|
public function testParsesUrlCorrectly(): void {
|
|
$m3u = "#EXTM3U\n#EXTINF:-1,Test\nhttp://example.com/live.m3u8\n";
|
|
|
|
$data = $this->parse($m3u);
|
|
$entry = iterator_to_array($data)[0];
|
|
|
|
$this->assertSame('http://example.com/live.m3u8', $entry->getPath());
|
|
}
|
|
|
|
public function testEmptyM3UReturnsEmptyResult(): void {
|
|
$data = $this->parse("#EXTM3U\n");
|
|
|
|
$this->assertCount(0, $data);
|
|
}
|
|
|
|
public function testParsesMultipleEntries(): void {
|
|
$m3u = "#EXTM3U\n"
|
|
. "#EXTINF:-1,Ch1\nhttp://example.com/1.m3u8\n"
|
|
. "#EXTINF:-1,Ch2\nhttp://example.com/2.m3u8\n"
|
|
. "#EXTINF:-1,Ch3\nhttp://example.com/3.m3u8\n";
|
|
|
|
$data = $this->parse($m3u);
|
|
|
|
$this->assertCount(3, $data);
|
|
}
|
|
|
|
// ── import array field extraction ──────────────────────────────────────
|
|
|
|
public function testImportArrayContainsTvgLogo(): void {
|
|
$m3u = "#EXTM3U\n#EXTINF:-1 tvg-logo=\"http://example.com/logo.png\",Channel\nhttp://example.com/stream.m3u8\n";
|
|
|
|
$arr = $this->buildImportArray($this->parse($m3u));
|
|
|
|
$this->assertSame('http://example.com/logo.png', $arr['stream_icon']);
|
|
}
|
|
|
|
public function testImportArrayFallsBackToLogoAttribute(): void {
|
|
$m3u = "#EXTM3U\n#EXTINF:-1 logo=\"http://example.com/fallback.png\",Channel\nhttp://example.com/stream.m3u8\n";
|
|
|
|
$arr = $this->buildImportArray($this->parse($m3u));
|
|
|
|
$this->assertSame('http://example.com/fallback.png', $arr['stream_icon']);
|
|
}
|
|
|
|
public function testImportArrayIconEmptyWhenNoLogoAttributes(): void {
|
|
$m3u = "#EXTM3U\n#EXTINF:-1,Channel\nhttp://example.com/stream.m3u8\n";
|
|
|
|
$arr = $this->buildImportArray($this->parse($m3u));
|
|
|
|
$this->assertSame('', $arr['stream_icon']);
|
|
}
|
|
|
|
public function testImportArrayUsesExtInfTitle(): void {
|
|
$m3u = "#EXTM3U\n#EXTINF:-1,My Channel Name\nhttp://example.com/stream.m3u8\n";
|
|
|
|
$arr = $this->buildImportArray($this->parse($m3u));
|
|
|
|
$this->assertSame('My Channel Name', $arr['stream_display_name']);
|
|
}
|
|
|
|
public function testImportArrayFallsBackToUrlBasenameWhenNoTitle(): void {
|
|
// No EXTINF — entry has no tags.
|
|
$m3u = "#EXTM3U\nhttp://example.com/channel-name.m3u8\n";
|
|
|
|
$arr = $this->buildImportArray($this->parse($m3u));
|
|
|
|
$this->assertSame('channel-name.m3u8', $arr['stream_display_name']);
|
|
}
|
|
|
|
public function testImportArrayTvgLogoTakesPrecedenceOverLogo(): void {
|
|
$m3u = "#EXTM3U\n#EXTINF:-1 tvg-logo=\"http://example.com/tvg.png\" logo=\"http://example.com/logo.png\",Channel\nhttp://example.com/stream.m3u8\n";
|
|
|
|
$arr = $this->buildImportArray($this->parse($m3u));
|
|
|
|
$this->assertSame('http://example.com/tvg.png', $arr['stream_icon']);
|
|
}
|
|
}
|