UNPKG

@aaronshaf/ger

Version:

Gerrit CLI and SDK - A modern CLI tool and TypeScript SDK for Gerrit Code Review, built with Effect-TS

195 lines (164 loc) 7.37 kB
import { test, expect, describe } from 'bun:test' import { buildPushRefspec, validateEmails, PushError } from '@/cli/commands/push' describe('Push Command', () => { describe('buildPushRefspec', () => { test('should build basic refspec without options', () => { const refspec = buildPushRefspec('master', {}) expect(refspec).toBe('refs/for/master') }) test('should build refspec with topic', () => { const refspec = buildPushRefspec('master', { topic: 'my-feature' }) expect(refspec).toBe('refs/for/master%topic=my-feature') }) test('should URL-encode topic with special characters', () => { const refspec = buildPushRefspec('master', { topic: 'feature/auth-fix' }) expect(refspec).toBe('refs/for/master%topic=feature%2Fauth-fix') }) test('should build refspec with wip flag', () => { const refspec = buildPushRefspec('master', { wip: true }) expect(refspec).toBe('refs/for/master%wip') }) test('should build refspec with draft flag (alias for wip)', () => { const refspec = buildPushRefspec('master', { draft: true }) expect(refspec).toBe('refs/for/master%wip') }) test('should build refspec with ready flag', () => { const refspec = buildPushRefspec('master', { ready: true }) expect(refspec).toBe('refs/for/master%ready') }) test('should build refspec with private flag', () => { const refspec = buildPushRefspec('master', { private: true }) expect(refspec).toBe('refs/for/master%private') }) test('should build refspec with single reviewer', () => { const refspec = buildPushRefspec('master', { reviewer: ['alice@example.com'] }) expect(refspec).toBe('refs/for/master%r=alice@example.com') }) test('should build refspec with multiple reviewers', () => { const refspec = buildPushRefspec('master', { reviewer: ['alice@example.com', 'bob@example.com'], }) expect(refspec).toBe('refs/for/master%r=alice@example.com,r=bob@example.com') }) test('should build refspec with single cc', () => { const refspec = buildPushRefspec('master', { cc: ['manager@example.com'] }) expect(refspec).toBe('refs/for/master%cc=manager@example.com') }) test('should build refspec with multiple ccs', () => { const refspec = buildPushRefspec('master', { cc: ['manager@example.com', 'lead@example.com'], }) expect(refspec).toBe('refs/for/master%cc=manager@example.com,cc=lead@example.com') }) test('should build refspec with single hashtag', () => { const refspec = buildPushRefspec('master', { hashtag: ['bugfix'] }) expect(refspec).toBe('refs/for/master%hashtag=bugfix') }) test('should build refspec with multiple hashtags', () => { const refspec = buildPushRefspec('master', { hashtag: ['bugfix', 'urgent'] }) expect(refspec).toBe('refs/for/master%hashtag=bugfix,hashtag=urgent') }) test('should URL-encode hashtags with special characters', () => { const refspec = buildPushRefspec('master', { hashtag: ['release/v1.0'] }) expect(refspec).toBe('refs/for/master%hashtag=release%2Fv1.0') }) test('should build refspec with multiple options combined', () => { const refspec = buildPushRefspec('main', { topic: 'auth-refactor', reviewer: ['alice@example.com'], cc: ['manager@example.com'], wip: true, hashtag: ['security'], }) expect(refspec).toBe( 'refs/for/main%topic=auth-refactor,wip,r=alice@example.com,cc=manager@example.com,hashtag=security', ) }) test('should handle different branch names', () => { expect(buildPushRefspec('main', {})).toBe('refs/for/main') expect(buildPushRefspec('develop', {})).toBe('refs/for/develop') expect(buildPushRefspec('feature/my-branch', {})).toBe('refs/for/feature/my-branch') expect(buildPushRefspec('release/v1.0', {})).toBe('refs/for/release/v1.0') }) test('should preserve order of parameters', () => { // The order should be: topic, wip, ready, private, reviewers, ccs, hashtags const refspec = buildPushRefspec('master', { hashtag: ['tag1'], reviewer: ['r@example.com'], topic: 'topic1', wip: true, cc: ['cc@example.com'], private: true, }) // Order in the code: topic, wip, ready, private, reviewer, cc, hashtag expect(refspec).toBe( 'refs/for/master%topic=topic1,wip,private,r=r@example.com,cc=cc@example.com,hashtag=tag1', ) }) test('should handle empty arrays gracefully', () => { const refspec = buildPushRefspec('master', { reviewer: [], cc: [], hashtag: [], }) expect(refspec).toBe('refs/for/master') }) test('should not add wip twice when both wip and draft are true', () => { const refspec = buildPushRefspec('master', { wip: true, draft: true }) // Both wip and draft set the wip flag, but we check wip first, so only one 'wip' should appear expect(refspec).toBe('refs/for/master%wip') }) }) describe('validateEmails', () => { test('should accept valid email addresses', () => { expect(() => validateEmails(['user@example.com'], 'reviewer')).not.toThrow() expect(() => validateEmails(['alice@company.org'], 'cc')).not.toThrow() expect(() => validateEmails(['test.user@sub.domain.com'], 'reviewer')).not.toThrow() }) test('should accept multiple valid emails', () => { expect(() => validateEmails(['user1@example.com', 'user2@example.com'], 'reviewer'), ).not.toThrow() }) test('should accept undefined', () => { expect(() => validateEmails(undefined, 'reviewer')).not.toThrow() }) test('should accept empty array', () => { expect(() => validateEmails([], 'reviewer')).not.toThrow() }) test('should reject email without @', () => { expect(() => validateEmails(['userexample.com'], 'reviewer')).toThrow(PushError) }) test('should reject email without domain', () => { expect(() => validateEmails(['user@'], 'reviewer')).toThrow(PushError) }) test('should reject email without user', () => { expect(() => validateEmails(['@example.com'], 'reviewer')).toThrow(PushError) }) test('should reject email with spaces', () => { expect(() => validateEmails(['user @example.com'], 'reviewer')).toThrow(PushError) }) test('should reject plain username', () => { expect(() => validateEmails(['username'], 'reviewer')).toThrow(PushError) }) test('should include field name in error message', () => { try { validateEmails(['invalid'], 'reviewer') expect(true).toBe(false) // Should not reach here } catch (e) { expect(e).toBeInstanceOf(PushError) expect((e as PushError).message).toContain('reviewer') expect((e as PushError).message).toContain('invalid') } }) test('should fail on first invalid email in array', () => { try { validateEmails(['valid@example.com', 'invalid', 'another@example.com'], 'cc') expect(true).toBe(false) } catch (e) { expect(e).toBeInstanceOf(PushError) expect((e as PushError).message).toContain('invalid') } }) }) })