value)->toBe('app_error'); expect((string) $logName)->toBe('app_error'); }); it('validates alphanumeric with underscore and hyphen', function () { $validNames = ['app_error', 'debug-log', 'security_2024', 'LOG-123']; foreach ($validNames as $name) { $logName = LogName::fromString($name); expect($logName->value)->toBe($name); } }); it('throws on empty log name', function () { LogName::fromString(''); })->throws(\InvalidArgumentException::class, 'Log name cannot be empty'); it('throws on invalid characters', function () { LogName::fromString('app/error'); })->throws(\InvalidArgumentException::class, 'contains invalid characters'); it('throws on log name too long', function () { $longName = str_repeat('a', 101); LogName::fromString($longName); })->throws(\InvalidArgumentException::class, 'too long'); it('extracts subdirectory from log name', function () { $logName = LogName::fromString('app_error'); expect($logName->getSubdirectory())->toBe('app'); }); it('returns null subdirectory for simple names', function () { $logName = LogName::fromString('error'); expect($logName->getSubdirectory())->toBeNull(); }); it('extracts filename from log name', function () { $logName = LogName::fromString('app_error'); expect($logName->getFilename())->toBe('error'); }); it('returns full value as filename for simple names', function () { $logName = LogName::fromString('error'); expect($logName->getFilename())->toBe('error'); }); it('compares equality correctly', function () { $logName1 = LogName::fromString('app_error'); $logName2 = LogName::fromString('app_error'); $logName3 = LogName::fromString('debug_log'); expect($logName1->equals($logName2))->toBeTrue(); expect($logName1->equals($logName3))->toBeFalse(); }); });