UNPKG

@aaronshaf/ger

Version:

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

174 lines (147 loc) 5.76 kB
import { describe, expect, test } from 'bun:test' import { incomingCommand } from '@/cli/commands/incoming' import { generateMockChange } from '@/test-utils/mock-generator' import { getStatusIndicators, getStatusString, getLabelValue, getLabelColor, } from '@/utils/status-indicators' import { sanitizeUrlSync, getOpenCommand } from '@/utils/shell-safety' describe('Interactive Incoming Command', () => { test('should create command with interactive option', () => { const command = incomingCommand({ interactive: true }) expect(command).toBeDefined() }) test('should create command with interactive and xml options', () => { const command = incomingCommand({ interactive: true, xml: true }) expect(command).toBeDefined() }) test('should create command without interactive option', () => { const command = incomingCommand({}) expect(command).toBeDefined() }) describe('Status Indicators Utility', () => { test('should generate status indicators for approved change', () => { const change = generateMockChange({ labels: { 'Code-Review': { approved: { _account_id: 1 }, value: 2 }, Verified: { approved: { _account_id: 1 }, value: 1 }, }, }) const indicators = getStatusIndicators(change) expect(indicators).toContain('✓') expect(indicators.length).toBeGreaterThan(0) }) test('should generate status indicators for rejected change', () => { const change = generateMockChange({ labels: { 'Code-Review': { rejected: { _account_id: 1 }, value: -2 }, }, }) const indicators = getStatusIndicators(change) expect(indicators).toContain('✗') }) test('should generate padded status string', () => { const change = generateMockChange({ labels: { 'Code-Review': { recommended: { _account_id: 1 }, value: 1 }, }, }) const statusString = getStatusString(change, undefined, 8) expect(statusString).toContain('↑') expect(statusString.length).toBe(8) }) test('should handle empty labels gracefully', () => { const change = generateMockChange({ labels: {} }) const indicators = getStatusIndicators(change) expect(indicators).toHaveLength(0) }) test('should extract label value safely', () => { expect(getLabelValue({ value: 2 })).toBe(2) expect(getLabelValue({ value: -1 })).toBe(-1) expect(getLabelValue({})).toBe(0) expect(getLabelValue(null)).toBe(0) expect(getLabelValue('invalid')).toBe(0) }) test('should determine label color correctly', () => { expect(getLabelColor(2)).toBe('green') expect(getLabelColor(1)).toBe('green') expect(getLabelColor(0)).toBe('yellow') expect(getLabelColor(-1)).toBe('red') expect(getLabelColor(-2)).toBe('red') }) }) describe('URL Sanitization', () => { test('should sanitize valid HTTPS URLs', () => { const url = 'https://gerrit.example.com/c/project/+/12345' expect(() => sanitizeUrlSync(url)).not.toThrow() expect(sanitizeUrlSync(url)).toBe(url) }) test('should reject HTTP URLs', () => { const url = 'http://gerrit.example.com/c/project/+/12345' expect(() => sanitizeUrlSync(url)).toThrow('Invalid protocol') }) test('should reject URLs with dangerous characters', () => { const url = 'https://gerrit.example.com/c/project/+/12345;rm -rf /' expect(() => sanitizeUrlSync(url)).toThrow('dangerous characters') }) test('should reject malformed URLs', () => { const url = 'not-a-url' expect(() => sanitizeUrlSync(url)).toThrow('Invalid URL format') }) test('should get correct open command for platform', () => { const originalPlatform = process.platform Object.defineProperty(process, 'platform', { value: 'darwin' }) expect(getOpenCommand()).toBe('open') Object.defineProperty(process, 'platform', { value: 'win32' }) expect(getOpenCommand()).toBe('start') Object.defineProperty(process, 'platform', { value: 'linux' }) expect(getOpenCommand()).toBe('xdg-open') // Restore original platform Object.defineProperty(process, 'platform', { value: originalPlatform }) }) }) describe('Change Data Processing', () => { test('should handle changes with various label configurations', () => { const changes = [ generateMockChange({ _number: 1, labels: { 'Code-Review': { value: 2, approved: { _account_id: 1 } } }, }), generateMockChange({ _number: 2, labels: { 'Code-Review': { value: -1, disliked: { _account_id: 1 } } }, }), generateMockChange({ _number: 3, labels: {}, }), ] changes.forEach((change) => { expect(() => getStatusIndicators(change)).not.toThrow() expect(() => getStatusString(change)).not.toThrow() }) }) test('should group changes by project correctly', () => { const changes = [ generateMockChange({ project: 'project-a', _number: 1 }), generateMockChange({ project: 'project-b', _number: 2 }), generateMockChange({ project: 'project-a', _number: 3 }), ] const grouped = changes.reduce( (acc, change) => { if (!acc[change.project]) { acc[change.project] = [] } acc[change.project].push(change) return acc }, {} as Record<string, typeof changes>, ) expect(Object.keys(grouped)).toHaveLength(2) expect(grouped['project-a']).toHaveLength(2) expect(grouped['project-b']).toHaveLength(1) }) }) })