import { expect, test, describe, beforeEach, afterEach } from 'bun:test'; import * as path from 'path'; import * as os from 'os'; import { expandPath } from '../../../src/utils/helpers'; describe('expandPath', () => { const originalEnv = { ...process.env }; const HOME = os.homedir(); beforeEach(() => { process.env.TEST_HOME = '/custom/home'; process.env.TEST_VAR = 'foo'; }); afterEach(() => { process.env = { ...originalEnv }; }); test('1. Tilde expansion: ~/path -> /home/user/path', () => { expect(expandPath('~/test/file.txt')).toBe(path.join(HOME, 'test/file.txt')); }); test('2. Windows tilde with backslash: ~\\path', () => { // expandPath handles both ~/ and ~\ regardless of platform expect(expandPath('~\\test\\file.txt')).toBe(path.join(HOME, 'test/file.txt')); }); test('3. Environment variable expansion: ${VAR}/path', () => { expect(expandPath('${TEST_HOME}/file.txt')).toBe(path.normalize('/custom/home/file.txt')); }); test('4. Dollar sign env vars: $VAR/path', () => { expect(expandPath('$TEST_HOME/file.txt')).toBe(path.normalize('/custom/home/file.txt')); }); test('5. Windows %VAR% expansion: %VAR%\\path (simulated)', () => { // We can't easily mock process.platform if it's not win32, // but the function check process.platform === 'win32' if (process.platform === 'win32') { expect(expandPath('%TEST_HOME%\\file.txt')).toBe(path.normalize('/custom/home/file.txt')); } else { // Should remain unchanged on non-windows (but separators normalized) expect(expandPath('%TEST_HOME%\\file.txt')).toBe(path.normalize('%TEST_HOME%/file.txt')); } }); test('6. Mixed path separators normalization', () => { const result = expandPath('path/to\\some/file'); expect(result).toBe(path.normalize('path/to/some/file')); }); test('7. Nested env vars: ${HOME}/${VAR}/path', () => { expect(expandPath('${TEST_HOME}/${TEST_VAR}/file.txt')).toBe( path.normalize('/custom/home/foo/file.txt') ); }); test('8. Empty/null path handling', () => { expect(expandPath('')).toBe('.'); }); test('9. Already absolute paths stay unchanged', () => { const absPath = '/absolute/path'; expect(expandPath(absPath)).toBe(path.normalize(absPath)); }); test('10. Undefined env vars -> empty string', () => { expect(expandPath('${UNDEFINED_VAR}/file.txt')).toBe(path.normalize('/file.txt')); expect(expandPath('$UNDEFINED_VAR/file.txt')).toBe(path.normalize('/file.txt')); }); test('11. Windows drive letters stay intact', () => { // Windows drive letter paths should be preserved const result = expandPath('C:\\Users\\test\\file.txt'); expect(result).toContain('Users'); expect(result).toContain('test'); }); test('12. Windows UNC paths handled', () => { // UNC paths start with \\ const uncPath = '\\\\server\\share\\folder'; const result = expandPath(uncPath); // Should normalize but preserve the structure expect(result).toContain('server'); expect(result).toContain('share'); }); test('13. Null-like input throws TypeError', () => { // Function requires string input - documents current behavior // @ts-ignore - testing runtime edge case expect(() => expandPath(undefined as unknown as string)).toThrow(TypeError); // @ts-ignore - testing runtime edge case expect(() => expandPath(null as unknown as string)).toThrow(TypeError); }); test('14. Path with spaces preserved', () => { const pathWithSpaces = '~/My Documents/file.txt'; const result = expandPath(pathWithSpaces); expect(result).toContain('My Documents'); }); test('15. Multiple consecutive slashes normalized', () => { const result = expandPath('path//to///file.txt'); expect(result).toBe(path.normalize('path/to/file.txt')); }); });