'success', 'Failed' => 'failed', 'Timeout' => 'timeout', 'BlockedRobots' => 'blocked_robots', 'Blocked4xx' => 'blocked_4xx', 'Blocked5xx' => 'blocked_5xx', 'Rejected' => 'rejected', ]; foreach ($expected as $caseName => $backingValue) { $case = CrawlOutcomeEnum::from($backingValue); $this->assertSame($caseName, $case->name, "Case name for '{$backingValue}' should be '{$caseName}'"); $this->assertSame($backingValue, $case->value, "Backing value for '{$caseName}' should be '{$backingValue}'"); } } public function test_enum_has_exactly_seven_cases(): void { $this->assertCount(7, CrawlOutcomeEnum::cases()); } public function test_to_page_status_maps_each_outcome_correctly(): void { $this->assertSame(PageStatusEnum::Fetched, CrawlOutcomeEnum::Success->toPageStatus()); $this->assertSame(PageStatusEnum::Rejected, CrawlOutcomeEnum::Rejected->toPageStatus()); $this->assertSame(PageStatusEnum::Failed, CrawlOutcomeEnum::Failed->toPageStatus()); $this->assertSame(PageStatusEnum::Failed, CrawlOutcomeEnum::Timeout->toPageStatus()); $this->assertSame(PageStatusEnum::Failed, CrawlOutcomeEnum::Blocked4xx->toPageStatus()); $this->assertSame(PageStatusEnum::Failed, CrawlOutcomeEnum::Blocked5xx->toPageStatus()); $this->assertSame(PageStatusEnum::Failed, CrawlOutcomeEnum::BlockedRobots->toPageStatus()); } public function test_is_retryable_returns_true_only_for_transient_failures(): void { // Retryable: transient network/server problems that may resolve later $this->assertTrue(CrawlOutcomeEnum::Failed->isRetryable()); $this->assertTrue(CrawlOutcomeEnum::Timeout->isRetryable()); $this->assertTrue(CrawlOutcomeEnum::Blocked5xx->isRetryable()); // Not retryable: success (done), permanent failures, or policy decisions $this->assertFalse(CrawlOutcomeEnum::Success->isRetryable()); $this->assertFalse(CrawlOutcomeEnum::Rejected->isRetryable()); $this->assertFalse(CrawlOutcomeEnum::BlockedRobots->isRetryable()); $this->assertFalse(CrawlOutcomeEnum::Blocked4xx->isRetryable()); } public function test_should_register_outbound_links_returns_true_only_for_success(): void { $this->assertTrue(CrawlOutcomeEnum::Success->shouldRegisterOutboundLinks()); // No links to register on any non-Success outcome $this->assertFalse(CrawlOutcomeEnum::Failed->shouldRegisterOutboundLinks()); $this->assertFalse(CrawlOutcomeEnum::Timeout->shouldRegisterOutboundLinks()); $this->assertFalse(CrawlOutcomeEnum::Rejected->shouldRegisterOutboundLinks()); $this->assertFalse(CrawlOutcomeEnum::BlockedRobots->shouldRegisterOutboundLinks()); $this->assertFalse(CrawlOutcomeEnum::Blocked4xx->shouldRegisterOutboundLinks()); $this->assertFalse(CrawlOutcomeEnum::Blocked5xx->shouldRegisterOutboundLinks()); } }