toString())->toBe('valid_refresh_token_1234567890'); }); it('rejects empty token', function () { RefreshToken::create(''); })->throws(\InvalidArgumentException::class, 'Refresh token cannot be empty'); it('rejects too short token', function () { RefreshToken::create('short'); })->throws(\InvalidArgumentException::class, 'Refresh token appears invalid (too short)'); it('masks token for logging', function () { $token = RefreshToken::create('1234567890abcdefghijklmnop'); $masked = $token->getMasked(); expect($masked)->toStartWith('1234'); expect($masked)->toEndWith('mnop'); expect($masked)->toContain('*'); expect(strlen($masked))->toBe(strlen('1234567890abcdefghijklmnop')); }); it('fully masks very short tokens', function () { $token = RefreshToken::create('short_token_'); $masked = $token->getMasked(); expect($masked)->toBe('************'); expect(str_contains($masked, 's'))->toBeFalse(); expect(str_contains($masked, '_'))->toBeFalse(); }); it('converts to string as masked', function () { $token = RefreshToken::create('1234567890abcdefghijklmnop'); expect((string) $token)->toBe($token->getMasked()); }); });