import { describe, expect, it } from 'vitest'; import { isSafeProjectName, resolveProjectDir } from '../src/core/project.js'; describe('isSafeProjectName', () => { it('accepte un segment simple', () => { expect(isSafeProjectName('mon-projet')).toBe(true); expect(isSafeProjectName('Projet_42.v2')).toBe(true); expect(isSafeProjectName(' espaces-trim ')).toBe(true); // trim interne }); it('refuse vide / espaces seuls', () => { expect(isSafeProjectName('')).toBe(false); expect(isSafeProjectName(' ')).toBe(false); }); it('refuse `.` et `..`', () => { expect(isSafeProjectName('.')).toBe(false); expect(isSafeProjectName('..')).toBe(false); }); it('refuse les séparateurs et le NUL (anti-traversal)', () => { expect(isSafeProjectName('a/b')).toBe(false); expect(isSafeProjectName('../evil')).toBe(false); expect(isSafeProjectName('a\\b')).toBe(false); expect(isSafeProjectName('a\0b')).toBe(false); }); it('refuse un nom trop long (> 255)', () => { expect(isSafeProjectName('x'.repeat(256))).toBe(false); expect(isSafeProjectName('x'.repeat(255))).toBe(true); }); }); describe('resolveProjectDir', () => { it('joint root + name (trim) en chemin absolu', () => { expect(resolveProjectDir('/home/johan/dev', 'mon-projet')).toBe('/home/johan/dev/mon-projet'); expect(resolveProjectDir('/home/johan/dev', ' mon-projet ')).toBe('/home/johan/dev/mon-projet'); }); it('lève (400) sur un nom invalide', () => { expect(() => resolveProjectDir('/home/johan/dev', '..')).toThrow(); expect(() => resolveProjectDir('/home/johan/dev', 'a/b')).toThrow(); expect(() => resolveProjectDir('/home/johan/dev', '')).toThrow(); }); });