toString())->toBe('abc123'); }); it('creates short code with valid length 6', function () { $code = ShortCode::fromString('abcdef'); expect($code->toString())->toBe('abcdef'); }); it('creates short code with valid length 7', function () { $code = ShortCode::fromString('abc1234'); expect($code->toString())->toBe('abc1234'); }); it('creates short code with valid length 8', function () { $code = ShortCode::fromString('abc12345'); expect($code->toString())->toBe('abc12345'); }); it('throws exception for too short code', function () { expect(fn() => ShortCode::fromString('abc12')) ->toThrow(\InvalidArgumentException::class, 'ShortCode must be between 6 and 8 characters'); }); it('throws exception for too long code', function () { expect(fn() => ShortCode::fromString('abc123456')) ->toThrow(\InvalidArgumentException::class, 'ShortCode must be between 6 and 8 characters'); }); it('accepts lowercase alphanumeric characters', function () { $code = ShortCode::fromString('abc123'); expect($code->toString())->toBe('abc123'); }); it('accepts uppercase alphanumeric characters', function () { $code = ShortCode::fromString('ABC123'); expect($code->toString())->toBe('ABC123'); }); it('accepts mixed case alphanumeric characters', function () { $code = ShortCode::fromString('aBcDeF'); expect($code->toString())->toBe('aBcDeF'); }); it('rejects dash characters', function () { expect(fn() => ShortCode::fromString('abc-12')) ->toThrow(\InvalidArgumentException::class, 'ShortCode can only contain alphanumeric characters'); }); it('rejects underscore characters', function () { expect(fn() => ShortCode::fromString('abc_12')) ->toThrow(\InvalidArgumentException::class, 'ShortCode can only contain alphanumeric characters'); }); it('rejects space characters', function () { expect(fn() => ShortCode::fromString('abc 12')) ->toThrow(\InvalidArgumentException::class, 'ShortCode can only contain alphanumeric characters'); }); it('rejects special characters', function () { expect(fn() => ShortCode::fromString('abc@12')) ->toThrow(\InvalidArgumentException::class, 'ShortCode can only contain alphanumeric characters'); }); it('rejects dot characters', function () { expect(fn() => ShortCode::fromString('abc.12')) ->toThrow(\InvalidArgumentException::class, 'ShortCode can only contain alphanumeric characters'); }); it('rejects too short code', function () { // Empty string triggers length validation, not empty check expect(fn() => ShortCode::fromString('')) ->toThrow(\InvalidArgumentException::class, 'ShortCode must be between 6 and 8 characters'); }); it('compares short codes correctly', function () { $code1 = ShortCode::fromString('abc123'); $code2 = ShortCode::fromString('abc123'); $code3 = ShortCode::fromString('xyz789'); expect($code1->equals($code2))->toBeTrue(); expect($code1->equals($code3))->toBeFalse(); }); it('converts to string', function () { $code = ShortCode::fromString('test12'); expect($code->toString())->toBe('test12'); expect((string) $code)->toBe('test12'); }); it('generates random short codes of length 6', function () { $code = ShortCode::generate(6); expect($code->toString())->toHaveLength(6); expect($code->toString())->toMatch('/^[a-zA-Z0-9]{6}$/'); }); it('generates unique codes on multiple calls', function () { $codes = []; for ($i = 0; $i < 10; $i++) { $codes[] = ShortCode::generate(6)->toString(); } $uniqueCodes = array_unique($codes); // With 62 possible characters and 6 positions, duplicates are extremely unlikely expect(count($uniqueCodes))->toBeGreaterThan(8); }); });