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); } }