fedi-feed-router/backend/tests/Unit/Services/Factories/ArticleParserFactoryTest.php

225 lines
No EOL
7.7 KiB
PHP

<?php
namespace Tests\Unit\Services\Factories;
use App\Contracts\ArticleParserInterface;
use App\Services\Factories\ArticleParserFactory;
use App\Services\Parsers\BelgaArticleParser;
use App\Services\Parsers\VrtArticleParser;
use Exception;
use Tests\TestCase;
class ArticleParserFactoryTest extends TestCase
{
public function test_get_parser_returns_vrt_parser_for_vrt_urls(): void
{
$vrtUrl = 'https://www.vrt.be/vrtnws/nl/2024/01/01/test-article/';
$parser = ArticleParserFactory::getParser($vrtUrl);
$this->assertInstanceOf(VrtArticleParser::class, $parser);
$this->assertInstanceOf(ArticleParserInterface::class, $parser);
}
public function test_get_parser_returns_belga_parser_for_belga_urls(): void
{
$belgaUrl = 'https://www.belganewsagency.eu/nl/nieuws/binnenland/test-article';
$parser = ArticleParserFactory::getParser($belgaUrl);
$this->assertInstanceOf(BelgaArticleParser::class, $parser);
$this->assertInstanceOf(ArticleParserInterface::class, $parser);
}
public function test_get_parser_throws_exception_for_unsupported_url(): void
{
$unsupportedUrl = 'https://www.example.com/article';
$this->expectException(Exception::class);
$this->expectExceptionMessage("No parser found for URL: {$unsupportedUrl}");
ArticleParserFactory::getParser($unsupportedUrl);
}
public function test_get_supported_sources_returns_array_of_source_names(): void
{
$sources = ArticleParserFactory::getSupportedSources();
$this->assertIsArray($sources);
$this->assertCount(2, $sources);
$this->assertContains('VRT News', $sources);
$this->assertContains('Belga News Agency', $sources);
}
public function test_get_supported_sources_returns_sources_in_correct_order(): void
{
$sources = ArticleParserFactory::getSupportedSources();
// Based on the factory's parser registration order
$this->assertEquals('VRT News', $sources[0]);
$this->assertEquals('Belga News Agency', $sources[1]);
}
public function test_register_parser_adds_new_parser_to_list(): void
{
// Create a mock parser class
$mockParserClass = new class implements ArticleParserInterface {
public function canParse(string $url): bool
{
return str_contains($url, 'test-parser.com');
}
public function extractData(string $html): array
{
return ['title' => 'Test Title'];
}
public function getSourceName(): string
{
return 'TestParser';
}
};
$mockParserClassName = get_class($mockParserClass);
// Register the mock parser
ArticleParserFactory::registerParser($mockParserClassName);
// Verify it's now included in supported sources
$sources = ArticleParserFactory::getSupportedSources();
$this->assertContains('TestParser', $sources);
$this->assertCount(3, $sources); // Original 2 + 1 new
// Verify it can be used to parse URLs
$testUrl = 'https://test-parser.com/article';
$parser = ArticleParserFactory::getParser($testUrl);
$this->assertInstanceOf($mockParserClassName, $parser);
}
public function test_register_parser_prevents_duplicate_registration(): void
{
// Get initial source count
$initialSources = ArticleParserFactory::getSupportedSources();
$initialCount = count($initialSources);
// Try to register an existing parser
ArticleParserFactory::registerParser(VrtArticleParser::class);
// Verify count hasn't changed
$newSources = ArticleParserFactory::getSupportedSources();
$this->assertCount($initialCount, $newSources);
$this->assertEquals($initialSources, $newSources);
}
public function test_get_parser_uses_first_matching_parser(): void
{
// Create two mock parsers that can parse the same URL
$mockParser1 = new class implements ArticleParserInterface {
public function canParse(string $url): bool
{
return str_contains($url, 'shared-domain.com');
}
public function extractData(string $html): array
{
return ['parser' => 'first'];
}
public function getSourceName(): string
{
return 'FirstParser';
}
};
$mockParser2 = new class implements ArticleParserInterface {
public function canParse(string $url): bool
{
return str_contains($url, 'shared-domain.com');
}
public function extractData(string $html): array
{
return ['parser' => 'second'];
}
public function getSourceName(): string
{
return 'SecondParser';
}
};
$mockParser1Class = get_class($mockParser1);
$mockParser2Class = get_class($mockParser2);
// Register both parsers
ArticleParserFactory::registerParser($mockParser1Class);
ArticleParserFactory::registerParser($mockParser2Class);
// The first registered parser should be returned
$testUrl = 'https://shared-domain.com/article';
$parser = ArticleParserFactory::getParser($testUrl);
// Should return the first parser since it was registered first
$this->assertInstanceOf($mockParser1Class, $parser);
}
public function test_factory_maintains_parser_registration_across_calls(): void
{
// Create a mock parser
$mockParser = new class implements ArticleParserInterface {
public function canParse(string $url): bool
{
return str_contains($url, 'persistent-test.com');
}
public function extractData(string $html): array
{
return ['title' => 'Persistent Test'];
}
public function getSourceName(): string
{
return 'PersistentTestParser';
}
};
$mockParserClass = get_class($mockParser);
// Register the parser
ArticleParserFactory::registerParser($mockParserClass);
// Make multiple calls to verify persistence
$parser1 = ArticleParserFactory::getParser('https://persistent-test.com/article1');
$parser2 = ArticleParserFactory::getParser('https://persistent-test.com/article2');
$this->assertInstanceOf($mockParserClass, $parser1);
$this->assertInstanceOf($mockParserClass, $parser2);
// Verify both instances are of the same class but different objects
$this->assertEquals(get_class($parser1), get_class($parser2));
}
public function test_get_parser_creates_new_instance_each_time(): void
{
$vrtUrl = 'https://www.vrt.be/vrtnws/nl/test/';
$parser1 = ArticleParserFactory::getParser($vrtUrl);
$parser2 = ArticleParserFactory::getParser($vrtUrl);
// Should be same class but different instances
$this->assertEquals(get_class($parser1), get_class($parser2));
$this->assertNotSame($parser1, $parser2);
}
public function test_get_supported_sources_creates_new_instances_for_each_call(): void
{
// This test ensures that getSupportedSources doesn't cause issues
// by creating new instances each time it's called
$sources1 = ArticleParserFactory::getSupportedSources();
$sources2 = ArticleParserFactory::getSupportedSources();
$this->assertEquals($sources1, $sources2);
$this->assertCount(count($sources1), $sources2);
}
}