Skip to content

Commit e6ea051

Browse files
committed
test(cli): extend api.mts tests and add glob.mts tests
Add comprehensive test coverage for: - api.mts: queryApi, queryApiSafeText, queryApiSafeJson, sendApiRequest - glob.mts: getSupportedFilePatterns, filterBySupportedScanFiles, createSupportedFilesFilter, isReportSupportedFile, pathsToGlobPatterns Uses @socketsecurity/sdk testing utilities for mock responses.
1 parent 3c9a13e commit e6ea051

File tree

2 files changed

+595
-2
lines changed

2 files changed

+595
-2
lines changed
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/**
2+
* Unit tests for glob utilities.
3+
*
4+
* Purpose:
5+
* Tests the glob pattern utilities for file matching.
6+
*
7+
* Test Coverage:
8+
* - getSupportedFilePatterns function
9+
* - filterBySupportedScanFiles function
10+
* - createSupportedFilesFilter function
11+
* - isReportSupportedFile function
12+
* - pathsToGlobPatterns function
13+
*
14+
* Related Files:
15+
* - utils/fs/glob.mts (implementation)
16+
*/
17+
18+
import path from 'node:path'
19+
20+
import { beforeEach, describe, expect, it, vi } from 'vitest'
21+
22+
// Mock homePath.
23+
vi.mock('../../../../src/constants/paths.mts', async importOriginal => {
24+
const actual = await importOriginal()
25+
return {
26+
...actual,
27+
homePath: '/Users/testuser',
28+
}
29+
})
30+
31+
// Mock isDirSync.
32+
const mockIsDirSync = vi.hoisted(() => vi.fn())
33+
vi.mock('@socketsecurity/lib/fs', () => ({
34+
isDirSync: mockIsDirSync,
35+
safeReadFile: vi.fn(),
36+
}))
37+
38+
import {
39+
createSupportedFilesFilter,
40+
filterBySupportedScanFiles,
41+
getSupportedFilePatterns,
42+
isReportSupportedFile,
43+
pathsToGlobPatterns,
44+
} from '../../../../src/utils/fs/glob.mts'
45+
46+
import type { SocketSdkSuccessResult } from '@socketsecurity/sdk'
47+
48+
// Mock supported files data.
49+
const mockSupportedFiles: SocketSdkSuccessResult<'getReportSupportedFiles'>['data'] =
50+
{
51+
npm: {
52+
'package.json': { pattern: 'package.json' },
53+
'package-lock.json': { pattern: 'package-lock.json' },
54+
},
55+
python: {
56+
'requirements.txt': { pattern: 'requirements.txt' },
57+
'setup.py': { pattern: 'setup.py' },
58+
},
59+
}
60+
61+
describe('utils/fs/glob', () => {
62+
beforeEach(() => {
63+
vi.clearAllMocks()
64+
mockIsDirSync.mockReturnValue(false)
65+
})
66+
67+
describe('getSupportedFilePatterns', () => {
68+
it('returns glob patterns for all supported files', () => {
69+
const patterns = getSupportedFilePatterns(mockSupportedFiles)
70+
71+
expect(patterns).toContain('**/package.json')
72+
expect(patterns).toContain('**/package-lock.json')
73+
expect(patterns).toContain('**/requirements.txt')
74+
expect(patterns).toContain('**/setup.py')
75+
})
76+
77+
it('handles empty supported files', () => {
78+
const patterns = getSupportedFilePatterns({})
79+
80+
expect(patterns).toEqual([])
81+
})
82+
83+
it('handles undefined ecosystem', () => {
84+
const patterns = getSupportedFilePatterns({
85+
npm: undefined as any,
86+
python: {
87+
'requirements.txt': { pattern: 'requirements.txt' },
88+
},
89+
})
90+
91+
expect(patterns).toContain('**/requirements.txt')
92+
expect(patterns).toHaveLength(1)
93+
})
94+
})
95+
96+
describe('filterBySupportedScanFiles', () => {
97+
it('filters files to only supported ones', () => {
98+
const filepaths = [
99+
'/project/package.json',
100+
'/project/src/index.js',
101+
'/project/requirements.txt',
102+
'/project/README.md',
103+
]
104+
105+
const result = filterBySupportedScanFiles(filepaths, mockSupportedFiles)
106+
107+
expect(result).toContain('/project/package.json')
108+
expect(result).toContain('/project/requirements.txt')
109+
expect(result).not.toContain('/project/src/index.js')
110+
expect(result).not.toContain('/project/README.md')
111+
})
112+
113+
it('returns empty array when no files match', () => {
114+
const filepaths = ['/project/index.js', '/project/style.css']
115+
116+
const result = filterBySupportedScanFiles(filepaths, mockSupportedFiles)
117+
118+
expect(result).toEqual([])
119+
})
120+
121+
it('handles empty filepath array', () => {
122+
const result = filterBySupportedScanFiles([], mockSupportedFiles)
123+
124+
expect(result).toEqual([])
125+
})
126+
})
127+
128+
describe('createSupportedFilesFilter', () => {
129+
it('creates a filter function', () => {
130+
const filter = createSupportedFilesFilter(mockSupportedFiles)
131+
132+
expect(typeof filter).toBe('function')
133+
})
134+
135+
it('filter returns true for supported files', () => {
136+
const filter = createSupportedFilesFilter(mockSupportedFiles)
137+
138+
expect(filter('/project/package.json')).toBe(true)
139+
expect(filter('/project/requirements.txt')).toBe(true)
140+
})
141+
142+
it('filter returns false for unsupported files', () => {
143+
const filter = createSupportedFilesFilter(mockSupportedFiles)
144+
145+
expect(filter('/project/index.js')).toBe(false)
146+
expect(filter('/project/README.md')).toBe(false)
147+
})
148+
})
149+
150+
describe('isReportSupportedFile', () => {
151+
it('returns true for supported files', () => {
152+
expect(
153+
isReportSupportedFile('/project/package.json', mockSupportedFiles),
154+
).toBe(true)
155+
expect(
156+
isReportSupportedFile('/project/requirements.txt', mockSupportedFiles),
157+
).toBe(true)
158+
})
159+
160+
it('returns false for unsupported files', () => {
161+
expect(
162+
isReportSupportedFile('/project/index.js', mockSupportedFiles),
163+
).toBe(false)
164+
expect(
165+
isReportSupportedFile('/project/README.md', mockSupportedFiles),
166+
).toBe(false)
167+
})
168+
169+
it('works with nested paths', () => {
170+
expect(
171+
isReportSupportedFile(
172+
'/project/subdir/nested/package.json',
173+
mockSupportedFiles,
174+
),
175+
).toBe(true)
176+
})
177+
})
178+
179+
describe('pathsToGlobPatterns', () => {
180+
it('converts current directory to wildcard pattern', () => {
181+
const result = pathsToGlobPatterns(['.'])
182+
expect(result).toContain('**/*')
183+
})
184+
185+
it('converts ./ to wildcard pattern', () => {
186+
const result = pathsToGlobPatterns(['./'])
187+
expect(result).toContain('**/*')
188+
})
189+
190+
it('expands tilde to home directory', () => {
191+
const result = pathsToGlobPatterns(['~/project'])
192+
expect(result[0]).toContain('/Users/testuser')
193+
})
194+
195+
it('expands lone tilde to home directory', () => {
196+
const result = pathsToGlobPatterns(['~'])
197+
expect(result[0]).toBe('/Users/testuser')
198+
})
199+
200+
it('adds recursive glob for directories', () => {
201+
mockIsDirSync.mockReturnValue(true)
202+
const result = pathsToGlobPatterns(['/some/directory'])
203+
expect(result[0]).toBe('/some/directory/**/*')
204+
})
205+
206+
it('keeps file paths as is', () => {
207+
mockIsDirSync.mockReturnValue(false)
208+
const result = pathsToGlobPatterns(['/some/file.txt'])
209+
expect(result[0]).toBe('/some/file.txt')
210+
})
211+
212+
it('keeps relative paths as is when not directories', () => {
213+
mockIsDirSync.mockReturnValue(false)
214+
const result = pathsToGlobPatterns(['relative/path'], '/cwd')
215+
// Returns resolvedPath (not absolutePath) for non-directory files.
216+
expect(result[0]).toBe('relative/path')
217+
})
218+
219+
it('handles multiple paths', () => {
220+
mockIsDirSync.mockReturnValue(false)
221+
const result = pathsToGlobPatterns(['.', '/absolute/path', '~/home/path'])
222+
expect(result).toHaveLength(3)
223+
})
224+
})
225+
})

0 commit comments

Comments
 (0)