332 lines
No EOL
11 KiB
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);
|
|
}
|
|
} |