From 793861db734ae826b487a1d356d78de5796145df Mon Sep 17 00:00:00 2001 From: Oluwatoyin Date: Sun, 18 Oct 2026 07:41:11 +0100 Subject: [PATCH] test(generator): lock empty vs non-empty destination policy (#139) --- tests/project-validation.test.ts | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/project-validation.test.ts b/tests/project-validation.test.ts index 02c05e8..1aa1665 100644 --- a/tests/project-validation.test.ts +++ b/tests/project-validation.test.ts @@ -99,4 +99,44 @@ describe('project destination planning', () => { ), ).toThrow('is not a directory'); })); + it('treats hidden entries as non-empty (no overwrite)', () => + withTempDirectory((path) => { + const destination = join(path, 'demo'); + mkdirSync(destination); + // Dotfile only — still non-empty for destination policy + writeFileSync(join(destination, '.gitkeep'), ''); + + expect(() => + planProjectDestination( + validateProjectInput({ projectName: 'demo', cwd: path }), + ), + ).toThrow('will not overwrite existing files'); + })); + + it('treats nested subdirectory content as non-empty (no overwrite)', () => + withTempDirectory((path) => { + const destination = join(path, 'demo'); + mkdirSync(join(destination, 'nested'), { recursive: true }); + writeFileSync(join(destination, 'nested', 'file.txt'), 'x'); + + expect(() => + planProjectDestination( + validateProjectInput({ projectName: 'demo', cwd: path }), + ), + ).toThrow('will not overwrite existing files'); + })); + + it('allows empty destination and does not require a force flag', () => + withTempDirectory((path) => { + const destination = join(path, 'demo'); + mkdirSync(destination); + + const plan = planProjectDestination( + validateProjectInput({ projectName: 'demo', cwd: path }), + ); + + // Policy: empty existing dir is OK; no force/overwrite API involved + expect(plan.destination).toBe(destination); + expect(plan.projectName).toBe('demo'); + })); });