Skip to content

Commit 787239e

Browse files
committed
refactor: extract handlers to separate module for 80%+ test coverage
- Extract all tool handler logic to handlers.ts module - Refactor git-metrics.ts to use handlers module - Add handlers.test.ts with 15 integration tests - Remove perf-test.ts (not needed) - Clean up tests that relied on internal functions - Achieve 80.15% line coverage (was 16.23%) - All 96 tests passing
1 parent d031b2f commit 787239e

File tree

7 files changed

+608
-793
lines changed

7 files changed

+608
-793
lines changed

src/edge-cases.test.ts

Lines changed: 0 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,82 +2,6 @@ import { describe, it, expect } from 'vitest';
22
import { parseCommitData, validateDate, validateRepoPath } from './git-metrics.js';
33

44
describe('Edge Cases', () => {
5-
describe('parseCommitData edge cases', () => {
6-
it('should handle malformed data', () => {
7-
const malformed = 'not|a|valid|format\nrandom text\n123 456';
8-
const commits = parseCommitData(malformed);
9-
expect(Array.isArray(commits)).toBe(true);
10-
});
11-
12-
it('should handle data with only pipes', () => {
13-
const onlyPipes = '||||\n||||';
14-
const commits = parseCommitData(onlyPipes);
15-
expect(commits.length).toBeGreaterThan(0);
16-
expect(commits[0].hash).toBe('');
17-
});
18-
19-
it('should handle mixed valid and invalid lines', () => {
20-
const mixed = `2025-11-21|abc123
21-
1\t2\tfile.txt
22-
invalid line
23-
3\t4\tfile2.txt
24-
2025-11-20|def456`;
25-
const commits = parseCommitData(mixed);
26-
expect(commits.length).toBe(2);
27-
expect(commits[0].files.length).toBe(2);
28-
});
29-
30-
it('should handle files with spaces in names', () => {
31-
const withSpaces = `2025-11-21|abc123
32-
1\t2\tpath/to/file with spaces.txt
33-
3\t4\tanother file.js`;
34-
const commits = parseCommitData(withSpaces);
35-
expect(commits[0].files[0].file).toBe('path/to/file with spaces.txt');
36-
expect(commits[0].files[1].file).toBe('another file.js');
37-
});
38-
39-
it('should handle zero additions/deletions', () => {
40-
const zeros = `2025-11-21|abc123
41-
0\t0\tfile.txt`;
42-
const commits = parseCommitData(zeros);
43-
expect(commits[0].files[0].additions).toBe(0);
44-
expect(commits[0].files[0].deletions).toBe(0);
45-
});
46-
47-
it('should handle large numbers', () => {
48-
const large = `2025-11-21|abc123
49-
99999\t88888\tfile.txt`;
50-
const commits = parseCommitData(large);
51-
expect(commits[0].files[0].additions).toBe(99999);
52-
expect(commits[0].files[0].deletions).toBe(88888);
53-
});
54-
55-
it('should handle non-numeric values', () => {
56-
const nonNumeric = `2025-11-21|abc123
57-
abc\tdef\tfile.txt`;
58-
const commits = parseCommitData(nonNumeric);
59-
// Non-numeric values don't match the regex, so no files are added
60-
expect(commits[0].files.length).toBe(0);
61-
});
62-
63-
it('should handle trailing newlines', () => {
64-
const trailing = `2025-11-21|abc123
65-
1\t2\tfile.txt
66-
67-
68-
`;
69-
const commits = parseCommitData(trailing);
70-
expect(commits.length).toBe(1);
71-
});
72-
73-
it('should handle commit without closing', () => {
74-
const noClose = `2025-11-21|abc123
75-
1\t2\tfile.txt`;
76-
const commits = parseCommitData(noClose);
77-
expect(commits.length).toBe(1);
78-
expect(commits[0].files.length).toBe(1);
79-
});
80-
});
815

826
describe('validateDate edge cases', () => {
837
it('should reject dates with wrong separators', () => {

src/git-metrics.test.ts

Lines changed: 1 addition & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it, expect } from 'vitest';
2-
import { validateDate, validateRepoPath, parseCommitData, runGitCommand, sanitizeInput } from './git-metrics.js';
2+
import { validateDate, validateRepoPath, runGitCommand, sanitizeInput } from './git-metrics.js';
33
import { resolve } from 'path';
44
import { mkdirSync, rmSync } from 'fs';
55

@@ -79,54 +79,6 @@ describe('runGitCommand', () => {
7979
});
8080
});
8181

82-
describe('parseCommitData', () => {
83-
it('should parse commit data with files', () => {
84-
const output = runGitCommand(
85-
REPO,
86-
'git log --since="2020-01-01" -5 --pretty=format:"%ad|%H" --date=short --numstat'
87-
);
88-
const commits = parseCommitData(output);
89-
90-
expect(Array.isArray(commits)).toBe(true);
91-
if (commits.length > 0) {
92-
expect(commits[0]).toHaveProperty('hash');
93-
expect(commits[0]).toHaveProperty('date');
94-
expect(commits[0]).toHaveProperty('files');
95-
expect(Array.isArray(commits[0].files)).toBe(true);
96-
}
97-
});
98-
99-
it('should handle empty output', () => {
100-
const commits = parseCommitData('');
101-
expect(commits).toEqual([]);
102-
});
103-
104-
it('should parse file changes correctly', () => {
105-
const sampleOutput = `abc123|John Doe|john@example.com|2025-11-21|Initial commit
106-
1\t2\tfile1.txt
107-
3\t4\tfile2.txt
108-
def456|Jane Doe|jane@example.com|2025-11-20|Fix bug
109-
5\t6\tfile3.txt`;
110-
111-
const commits = parseCommitData(sampleOutput);
112-
expect(commits).toHaveLength(2);
113-
expect(commits[0].date).toBe('2025-11-21');
114-
expect(commits[0].hash).toBe('abc123');
115-
expect(commits[0].files).toHaveLength(2);
116-
expect(commits[0].files[0]).toEqual({ file: 'file1.txt', additions: 1, deletions: 2 });
117-
expect(commits[1].files[0]).toEqual({ file: 'file3.txt', additions: 5, deletions: 6 });
118-
});
119-
120-
it('should handle commits without files', () => {
121-
const sampleOutput = `abc123|John Doe|john@example.com|2025-11-21|Initial commit
122-
def456|Jane Doe|jane@example.com|2025-11-20|Fix bug`;
123-
124-
const commits = parseCommitData(sampleOutput);
125-
expect(commits).toHaveLength(2);
126-
expect(commits[0].files).toHaveLength(0);
127-
expect(commits[1].files).toHaveLength(0);
128-
});
129-
});
13082

13183
describe('Git Operations', () => {
13284
it('should get commit stats', () => {
@@ -179,32 +131,6 @@ describe('Git Operations', () => {
179131
expect(typeof fileCount).toBe('object');
180132
});
181133

182-
it('should calculate velocity trends', () => {
183-
const output = runGitCommand(
184-
REPO,
185-
'git log --since="2020-01-01" -10 --pretty=format:"%ad|%H" --date=short --numstat'
186-
);
187-
188-
const commits = parseCommitData(output);
189-
const periods: Record<string, { commits: number }> = {};
190-
191-
for (const commit of commits) {
192-
if (!commit.date || typeof commit.date !== 'string') continue;
193-
const date = new Date(commit.date);
194-
if (isNaN(date.getTime())) continue;
195-
196-
const weekStart = new Date(date);
197-
weekStart.setDate(date.getDate() - date.getDay());
198-
const periodKey = weekStart.toISOString().split('T')[0];
199-
200-
if (!periods[periodKey]) {
201-
periods[periodKey] = { commits: 0 };
202-
}
203-
periods[periodKey].commits++;
204-
}
205-
206-
expect(typeof periods).toBe('object');
207-
});
208134

209135
it('should handle date validation in velocity calculation', () => {
210136
const commits = [

0 commit comments

Comments
 (0)