Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 65 additions & 52 deletions tests/history-profile.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function restoreEnv(name, value) {
}
}

test('buildProfile counts descriptive verb forms in the imperative-rate denominator', async () => {
async function withTempHome(callback) {
const originalHome = process.env.HOME;
const originalAppData = process.env.APPDATA;
const originalXdgConfigHome = process.env.XDG_CONFIG_HOME;
Expand All @@ -53,90 +53,57 @@ test('buildProfile counts descriptive verb forms in the imperative-rate denomina
process.env.HOME = tempHome;
process.env.APPDATA = join(tempHome, 'AppData', 'Roaming');
process.env.XDG_CONFIG_HOME = join(tempHome, '.config');
writeHistory(tempHome, ['fix: add retries', 'fix: added retries', 'fix: adding retries']);

const profile = await buildProfile(10);

assert.equal(profile.totalCommits, 3);
assert.equal(profile.imperativeRate, 1 / 3);
return await callback(tempHome);
} finally {
restoreEnv('HOME', originalHome);
restoreEnv('APPDATA', originalAppData);
restoreEnv('XDG_CONFIG_HOME', originalXdgConfigHome);
rmSync(tempHome, { recursive: true, force: true });
}
}

test('buildProfile counts descriptive verb forms in the imperative-rate denominator', async () => {
await withTempHome(async (tempHome) => {
writeHistory(tempHome, ['fix: add retries', 'fix: added retries', 'fix: adding retries']);

const profile = await buildProfile(10);

assert.equal(profile.totalCommits, 3);
assert.equal(profile.imperativeRate, 1 / 3);
});
});

test('buildProfile recognizes base-form verbs that end in descriptive suffixes', async () => {
const originalHome = process.env.HOME;
const originalAppData = process.env.APPDATA;
const originalXdgConfigHome = process.env.XDG_CONFIG_HOME;
const tempHome = mkdtempSync(join(tmpdir(), 'commit-echo-home-'));

try {
process.env.HOME = tempHome;
process.env.APPDATA = join(tempHome, 'AppData', 'Roaming');
process.env.XDG_CONFIG_HOME = join(tempHome, '.config');
await withTempHome(async (tempHome) => {
writeHistory(tempHome, ['fix: add retries', 'fix: Bring retries', 'fix: added retries']);

const profile = await buildProfile(10);

assert.equal(profile.totalCommits, 3);
assert.equal(profile.imperativeRate, 2 / 3);
} finally {
restoreEnv('HOME', originalHome);
restoreEnv('APPDATA', originalAppData);
restoreEnv('XDG_CONFIG_HOME', originalXdgConfigHome);
rmSync(tempHome, { recursive: true, force: true });
}
});
});

test('buildProfile recognizes prefix-derived base-form verbs as imperative', async () => {
const originalHome = process.env.HOME;
const originalAppData = process.env.APPDATA;
const originalXdgConfigHome = process.env.XDG_CONFIG_HOME;
const tempHome = mkdtempSync(join(tmpdir(), 'commit-echo-home-'));

try {
process.env.HOME = tempHome;
process.env.APPDATA = join(tempHome, 'AppData', 'Roaming');
process.env.XDG_CONFIG_HOME = join(tempHome, '.config');
await withTempHome(async (tempHome) => {
writeHistory(tempHome, ['fix: reseed database', 'fix: preseed retries', 'fix: adding retries']);

const profile = await buildProfile(10);

assert.equal(profile.totalCommits, 3);
assert.equal(profile.imperativeRate, 2 / 3);
} finally {
restoreEnv('HOME', originalHome);
restoreEnv('APPDATA', originalAppData);
restoreEnv('XDG_CONFIG_HOME', originalXdgConfigHome);
rmSync(tempHome, { recursive: true, force: true });
}
});
});

test('buildProfile recognizes ed-suffix base-form verbs not in the base allowlist', async () => {
const originalHome = process.env.HOME;
const originalAppData = process.env.APPDATA;
const originalXdgConfigHome = process.env.XDG_CONFIG_HOME;
const tempHome = mkdtempSync(join(tmpdir(), 'commit-echo-home-'));

try {
process.env.HOME = tempHome;
process.env.APPDATA = join(tempHome, 'AppData', 'Roaming');
process.env.XDG_CONFIG_HOME = join(tempHome, '.config');
await withTempHome(async (tempHome) => {
writeHistory(tempHome, ['fix: succeed after retry', 'fix: weed stale entries', 'fix: adding retries']);

const profile = await buildProfile(10);

assert.equal(profile.totalCommits, 3);
assert.equal(profile.imperativeRate, 2 / 3);
} finally {
restoreEnv('HOME', originalHome);
restoreEnv('APPDATA', originalAppData);
restoreEnv('XDG_CONFIG_HOME', originalXdgConfigHome);
rmSync(tempHome, { recursive: true, force: true });
}
});
});

test('formatProfile reports the empty-history fallback', () => {
Expand Down Expand Up @@ -194,3 +161,49 @@ test('formatProfile renders dominant tone, capitalization, scope, body, and pref
assert.match(output, /Body usage: 50%/);
assert.match(output, /Common prefixes: fix: \(75%\), feat: \(25%\)/);
});

test('buildProfile computes scope-usage ratio', async () => {
await withTempHome(async (tempHome) => {
writeHistory(tempHome, [
'feat(auth): add login',
'fix: resolve crash',
'docs(readme): update',
'style: format code',
]);

const profile = await buildProfile(10);

assert.equal(profile.totalCommits, 4);
assert.equal(profile.usesScopeRate, 0.5);
});
});

test('buildProfile computes body-usage ratio', async () => {
await withTempHome(async (tempHome) => {
writeHistory(tempHome, [
'feat: no body',
'fix: with body\n\nThis is a body.',
'docs: no body',
'style: with body\n\nBody line 1\nBody line 2',
]);

const profile = await buildProfile(10);

assert.equal(profile.totalCommits, 4);
assert.equal(profile.usesBodyRate, 0.5);
});
});

test('buildProfile handles empty history', async () => {
await withTempHome(async (tempHome) => {
writeHistory(tempHome, []);

const profile = await buildProfile(10);

assert.equal(profile.totalCommits, 0);
assert.equal(profile.usesScopeRate, 0);
assert.equal(profile.usesBodyRate, 0);
assert.equal(profile.imperativeRate, 0);
assert.equal(profile.sentenceCaseRate, 0);
});
});