fedi-feed-router/backend/tests/Unit/Models/FeedTest.php

332 lines
No EOL
11 KiB
PHP

<?php
namespace Tests\Unit\Models;
use App\Models\Article;
use App\Models\Feed;
use App\Models\Language;
use App\Models\PlatformChannel;
use App\Models\Route;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class FeedTest extends TestCase
{
use RefreshDatabase;
public function test_fillable_fields(): void
{
$fillableFields = ['name', 'url', 'type', 'language_id', 'description', 'settings', 'is_active', 'last_fetched_at'];
$feed = new Feed();
$this->assertEquals($fillableFields, $feed->getFillable());
}
public function test_casts_settings_to_array(): void
{
$settings = ['key1' => 'value1', 'key2' => ['nested' => 'value']];
$feed = Feed::factory()->create(['settings' => $settings]);
$this->assertIsArray($feed->settings);
$this->assertEquals($settings, $feed->settings);
}
public function test_casts_is_active_to_boolean(): void
{
$feed = Feed::factory()->create(['is_active' => '1']);
$this->assertIsBool($feed->is_active);
$this->assertTrue($feed->is_active);
$feed->update(['is_active' => '0']);
$feed->refresh();
$this->assertIsBool($feed->is_active);
$this->assertFalse($feed->is_active);
}
public function test_casts_last_fetched_at_to_datetime(): void
{
$timestamp = now()->subHours(2);
$feed = Feed::factory()->create(['last_fetched_at' => $timestamp]);
$this->assertInstanceOf(\Carbon\Carbon::class, $feed->last_fetched_at);
$this->assertEquals($timestamp->format('Y-m-d H:i:s'), $feed->last_fetched_at->format('Y-m-d H:i:s'));
}
public function test_type_display_attribute(): void
{
$websiteFeed = Feed::factory()->create(['type' => 'website']);
$rssFeed = Feed::factory()->create(['type' => 'rss']);
$this->assertEquals('Website', $websiteFeed->type_display);
$this->assertEquals('RSS Feed', $rssFeed->type_display);
}
public function test_status_attribute_inactive_feed(): void
{
$feed = Feed::factory()->create(['is_active' => false]);
$this->assertEquals('Inactive', $feed->status);
}
public function test_status_attribute_never_fetched(): void
{
$feed = Feed::factory()->create([
'is_active' => true,
'last_fetched_at' => null
]);
$this->assertEquals('Never fetched', $feed->status);
}
public function test_status_attribute_recently_fetched(): void
{
$feed = Feed::factory()->create([
'is_active' => true,
'last_fetched_at' => now()->subHour()
]);
$this->assertEquals('Recently fetched', $feed->status);
}
public function test_status_attribute_fetched_hours_ago(): void
{
$feed = Feed::factory()->create([
'is_active' => true,
'last_fetched_at' => now()->subHours(5)->startOfHour()
]);
$this->assertStringContainsString('Fetched', $feed->status);
$this->assertStringContainsString('ago', $feed->status);
}
public function test_status_attribute_fetched_days_ago(): void
{
$feed = Feed::factory()->create([
'is_active' => true,
'last_fetched_at' => now()->subDays(3)
]);
$this->assertStringStartsWith('Fetched', $feed->status);
$this->assertStringContainsString('ago', $feed->status);
}
public function test_belongs_to_language_relationship(): void
{
$language = Language::factory()->create();
$feed = Feed::factory()->create(['language_id' => $language->id]);
$this->assertInstanceOf(Language::class, $feed->language);
$this->assertEquals($language->id, $feed->language->id);
$this->assertEquals($language->name, $feed->language->name);
}
public function test_has_many_articles_relationship(): void
{
$feed = Feed::factory()->create();
$article1 = Article::factory()->create(['feed_id' => $feed->id]);
$article2 = Article::factory()->create(['feed_id' => $feed->id]);
// Create article for different feed
$otherFeed = Feed::factory()->create();
Article::factory()->create(['feed_id' => $otherFeed->id]);
$articles = $feed->articles;
$this->assertCount(2, $articles);
$this->assertTrue($articles->contains('id', $article1->id));
$this->assertTrue($articles->contains('id', $article2->id));
$this->assertInstanceOf(Article::class, $articles->first());
}
public function test_belongs_to_many_channels_relationship(): void
{
$feed = Feed::factory()->create();
$channel1 = PlatformChannel::factory()->create();
$channel2 = PlatformChannel::factory()->create();
// Create routes (which act as pivot records)
Route::create([
'feed_id' => $feed->id,
'platform_channel_id' => $channel1->id,
'is_active' => true,
'priority' => 100
]);
Route::create([
'feed_id' => $feed->id,
'platform_channel_id' => $channel2->id,
'is_active' => false,
'priority' => 50
]);
$channels = $feed->channels;
$this->assertCount(2, $channels);
$this->assertTrue($channels->contains('id', $channel1->id));
$this->assertTrue($channels->contains('id', $channel2->id));
// Test pivot data
$channel1FromRelation = $channels->find($channel1->id);
$this->assertEquals(1, $channel1FromRelation->pivot->is_active);
$this->assertEquals(100, $channel1FromRelation->pivot->priority);
}
public function test_active_channels_relationship(): void
{
$feed = Feed::factory()->create();
$activeChannel1 = PlatformChannel::factory()->create();
$activeChannel2 = PlatformChannel::factory()->create();
$inactiveChannel = PlatformChannel::factory()->create();
// Create routes
Route::create([
'feed_id' => $feed->id,
'platform_channel_id' => $activeChannel1->id,
'is_active' => true,
'priority' => 100
]);
Route::create([
'feed_id' => $feed->id,
'platform_channel_id' => $activeChannel2->id,
'is_active' => true,
'priority' => 200
]);
Route::create([
'feed_id' => $feed->id,
'platform_channel_id' => $inactiveChannel->id,
'is_active' => false,
'priority' => 150
]);
$activeChannels = $feed->activeChannels;
$this->assertCount(2, $activeChannels);
$this->assertTrue($activeChannels->contains('id', $activeChannel1->id));
$this->assertTrue($activeChannels->contains('id', $activeChannel2->id));
$this->assertFalse($activeChannels->contains('id', $inactiveChannel->id));
// Test ordering by priority descending
$channelIds = $activeChannels->pluck('id')->toArray();
$this->assertEquals($activeChannel2->id, $channelIds[0]); // Priority 200
$this->assertEquals($activeChannel1->id, $channelIds[1]); // Priority 100
}
public function test_feed_creation_with_factory(): void
{
$feed = Feed::factory()->create();
$this->assertInstanceOf(Feed::class, $feed);
$this->assertIsString($feed->name);
$this->assertIsString($feed->url);
$this->assertIsString($feed->type);
// Language ID may be null as it's nullable in the database
$this->assertTrue($feed->language_id === null || is_int($feed->language_id));
$this->assertIsBool($feed->is_active);
$this->assertIsArray($feed->settings);
}
public function test_feed_creation_with_explicit_values(): void
{
$language = Language::factory()->create();
$settings = ['custom' => 'setting', 'nested' => ['key' => 'value']];
$feed = Feed::create([
'name' => 'Test Feed',
'url' => 'https://example.com/feed',
'type' => 'rss',
'language_id' => $language->id,
'description' => 'Test description',
'settings' => $settings,
'is_active' => false
]);
$this->assertEquals('Test Feed', $feed->name);
$this->assertEquals('https://example.com/feed', $feed->url);
$this->assertEquals('rss', $feed->type);
$this->assertEquals($language->id, $feed->language_id);
$this->assertEquals('Test description', $feed->description);
$this->assertEquals($settings, $feed->settings);
$this->assertFalse($feed->is_active);
}
public function test_feed_update(): void
{
$feed = Feed::factory()->create([
'name' => 'Original Name',
'is_active' => true
]);
$feed->update([
'name' => 'Updated Name',
'is_active' => false
]);
$feed->refresh();
$this->assertEquals('Updated Name', $feed->name);
$this->assertFalse($feed->is_active);
}
public function test_feed_deletion(): void
{
$feed = Feed::factory()->create();
$feedId = $feed->id;
$feed->delete();
$this->assertDatabaseMissing('feeds', ['id' => $feedId]);
}
public function test_feed_settings_can_be_empty_array(): void
{
$feed = Feed::factory()->create(['settings' => []]);
$this->assertIsArray($feed->settings);
$this->assertEmpty($feed->settings);
}
public function test_feed_settings_can_be_complex_structure(): void
{
$complexSettings = [
'parsing' => [
'selector' => 'article.post',
'title_selector' => 'h1',
'content_selector' => '.content'
],
'filters' => ['min_length' => 100],
'schedule' => [
'enabled' => true,
'interval' => 3600
]
];
$feed = Feed::factory()->create(['settings' => $complexSettings]);
$this->assertEquals($complexSettings, $feed->settings);
$this->assertEquals('article.post', $feed->settings['parsing']['selector']);
$this->assertTrue($feed->settings['schedule']['enabled']);
}
public function test_feed_can_have_null_last_fetched_at(): void
{
$feed = Feed::factory()->create(['last_fetched_at' => null]);
$this->assertNull($feed->last_fetched_at);
}
public function test_feed_timestamps(): void
{
$feed = Feed::factory()->create();
$this->assertNotNull($feed->created_at);
$this->assertNotNull($feed->updated_at);
$this->assertInstanceOf(\Carbon\Carbon::class, $feed->created_at);
$this->assertInstanceOf(\Carbon\Carbon::class, $feed->updated_at);
}
}