Skip to content

Commit f6e791f

Browse files
committed
test: add comprehensive tests for dlx and effects modules
Add 82 new tests improving code coverage: - test/dlx.test.ts: 42 tests for DLX package management utilities - Cache key generation, directory operations - Package installation/removal, sync/async variants - Edge cases and error handling - test/effects/pulse-frames.test.ts: 19 tests for spinner frame generation - Frame generation, intervals, ANSI codes - Unicode characters, animation patterns - test/effects/ultra.test.ts: 21 tests for rainbow gradient generation - Color cycling, RGB validation - Gradient distribution and consistency Coverage improvements: - dlx.ts: 12.5% → ~95% - pulse-frames.ts: 9.09% → ~100% - ultra.ts: 20% → ~100% - Overall code coverage: 70.76% → 71.99% - Test count: 4,483 → 4,565 (+82)
1 parent 0273417 commit f6e791f

3 files changed

Lines changed: 690 additions & 0 deletions

File tree

test/dlx.test.ts

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
/**
2+
* @fileoverview Tests for DLX utilities.
3+
*/
4+
5+
import fs from 'node:fs'
6+
import path from 'node:path'
7+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
8+
9+
import {
10+
clearDlx,
11+
clearDlxSync,
12+
dlxDirExists,
13+
dlxDirExistsAsync,
14+
ensureDlxDir,
15+
ensureDlxDirSync,
16+
generateCacheKey,
17+
getDlxInstalledPackageDir,
18+
getDlxPackageDir,
19+
getDlxPackageJsonPath,
20+
getDlxPackageNodeModulesDir,
21+
isDlxPackageInstalled,
22+
isDlxPackageInstalledAsync,
23+
isInSocketDlx,
24+
listDlxPackages,
25+
listDlxPackagesAsync,
26+
removeDlxPackage,
27+
removeDlxPackageSync,
28+
} from '@socketsecurity/lib/dlx'
29+
import { getSocketDlxDir } from '@socketsecurity/lib/paths'
30+
31+
describe('dlx', () => {
32+
const testPackageName = 'test-package'
33+
const dlxDir = getSocketDlxDir()
34+
35+
beforeEach(async () => {
36+
// Clean up any existing test artifacts
37+
await clearDlx().catch(() => {})
38+
})
39+
40+
afterEach(async () => {
41+
// Clean up after tests
42+
await clearDlx().catch(() => {})
43+
})
44+
45+
describe('generateCacheKey', () => {
46+
it('should generate a 16-character hex string', () => {
47+
const key = generateCacheKey('test-spec')
48+
expect(key).toHaveLength(16)
49+
expect(key).toMatch(/^[0-9a-f]{16}$/)
50+
})
51+
52+
it('should generate consistent keys for same input', () => {
53+
const key1 = generateCacheKey('test-spec')
54+
const key2 = generateCacheKey('test-spec')
55+
expect(key1).toBe(key2)
56+
})
57+
58+
it('should generate different keys for different inputs', () => {
59+
const key1 = generateCacheKey('test-spec-1')
60+
const key2 = generateCacheKey('test-spec-2')
61+
expect(key1).not.toBe(key2)
62+
})
63+
64+
it('should handle package specs with versions', () => {
65+
const key = generateCacheKey('npm:prettier@3.0.0')
66+
expect(key).toHaveLength(16)
67+
expect(key).toMatch(/^[0-9a-f]{16}$/)
68+
})
69+
})
70+
71+
describe('dlxDirExists / dlxDirExistsAsync', () => {
72+
it('should return false when DLX directory does not exist', () => {
73+
// Ensure it doesn't exist
74+
if (fs.existsSync(dlxDir)) {
75+
fs.rmSync(dlxDir, { recursive: true, force: true })
76+
}
77+
expect(dlxDirExists()).toBe(false)
78+
})
79+
80+
it('should return true when DLX directory exists', async () => {
81+
await ensureDlxDir()
82+
expect(dlxDirExists()).toBe(true)
83+
})
84+
85+
it('async version should return false when directory does not exist', async () => {
86+
// Ensure it doesn't exist
87+
if (fs.existsSync(dlxDir)) {
88+
fs.rmSync(dlxDir, { recursive: true, force: true })
89+
}
90+
expect(await dlxDirExistsAsync()).toBe(false)
91+
})
92+
93+
it('async version should return true when directory exists', async () => {
94+
await ensureDlxDir()
95+
expect(await dlxDirExistsAsync()).toBe(true)
96+
})
97+
})
98+
99+
describe('ensureDlxDir / ensureDlxDirSync', () => {
100+
it('should create DLX directory if it does not exist', async () => {
101+
// Ensure it doesn't exist
102+
if (fs.existsSync(dlxDir)) {
103+
fs.rmSync(dlxDir, { recursive: true, force: true })
104+
}
105+
await ensureDlxDir()
106+
expect(fs.existsSync(dlxDir)).toBe(true)
107+
})
108+
109+
it('should not throw if DLX directory already exists', async () => {
110+
await ensureDlxDir()
111+
await expect(ensureDlxDir()).resolves.not.toThrow()
112+
})
113+
114+
it('sync version should create DLX directory if it does not exist', () => {
115+
// Ensure it doesn't exist
116+
if (fs.existsSync(dlxDir)) {
117+
fs.rmSync(dlxDir, { recursive: true, force: true })
118+
}
119+
ensureDlxDirSync()
120+
expect(fs.existsSync(dlxDir)).toBe(true)
121+
})
122+
123+
it('sync version should not throw if DLX directory already exists', () => {
124+
ensureDlxDirSync()
125+
expect(() => ensureDlxDirSync()).not.toThrow()
126+
})
127+
})
128+
129+
describe('getDlxPackageDir', () => {
130+
it('should return path to package directory', () => {
131+
const packageDir = getDlxPackageDir(testPackageName)
132+
expect(packageDir).toContain(dlxDir)
133+
expect(packageDir).toContain(testPackageName)
134+
})
135+
136+
it('should normalize path separators', () => {
137+
const packageDir = getDlxPackageDir(testPackageName)
138+
// Path should not contain backslashes on any platform after normalization
139+
expect(packageDir).not.toContain('\\')
140+
})
141+
})
142+
143+
describe('getDlxPackageNodeModulesDir', () => {
144+
it('should return path to node_modules directory', () => {
145+
const nodeModulesDir = getDlxPackageNodeModulesDir(testPackageName)
146+
expect(nodeModulesDir).toContain(dlxDir)
147+
expect(nodeModulesDir).toContain(testPackageName)
148+
expect(nodeModulesDir).toContain('node_modules')
149+
})
150+
})
151+
152+
describe('getDlxInstalledPackageDir', () => {
153+
it('should return path to installed package directory', () => {
154+
const installedDir = getDlxInstalledPackageDir(testPackageName)
155+
expect(installedDir).toContain(dlxDir)
156+
expect(installedDir).toContain(testPackageName)
157+
expect(installedDir).toContain('node_modules')
158+
})
159+
160+
it('should handle scoped packages', () => {
161+
const scopedPackage = '@socket/test'
162+
const installedDir = getDlxInstalledPackageDir(scopedPackage)
163+
expect(installedDir).toContain(dlxDir)
164+
expect(installedDir).toContain('@socket/test')
165+
})
166+
})
167+
168+
describe('getDlxPackageJsonPath', () => {
169+
it('should return path to package.json', () => {
170+
const packageJsonPath = getDlxPackageJsonPath(testPackageName)
171+
expect(packageJsonPath).toContain(dlxDir)
172+
expect(packageJsonPath).toContain(testPackageName)
173+
expect(packageJsonPath).toContain('package.json')
174+
})
175+
})
176+
177+
describe('isInSocketDlx', () => {
178+
it('should return true for paths within DLX directory', () => {
179+
const dlxPath = path.join(dlxDir, 'some-package', 'bin', 'binary')
180+
expect(isInSocketDlx(dlxPath)).toBe(true)
181+
})
182+
183+
it('should return false for paths outside DLX directory', () => {
184+
expect(isInSocketDlx('/usr/local/bin/binary')).toBe(false)
185+
})
186+
187+
it('should return false for empty string', () => {
188+
expect(isInSocketDlx('')).toBe(false)
189+
})
190+
191+
it('should handle relative paths', () => {
192+
const relativePath = 'some/relative/path'
193+
const result = isInSocketDlx(relativePath)
194+
expect(typeof result).toBe('boolean')
195+
})
196+
197+
it('should handle paths with trailing separators', () => {
198+
const dlxPath = path.join(dlxDir, 'package', '')
199+
expect(isInSocketDlx(dlxPath)).toBe(true)
200+
})
201+
})
202+
203+
describe('isDlxPackageInstalled / isDlxPackageInstalledAsync', () => {
204+
it('should return false when package is not installed', () => {
205+
expect(isDlxPackageInstalled(testPackageName)).toBe(false)
206+
})
207+
208+
it('should return true when package is installed', async () => {
209+
// Create a mock installation
210+
const installedDir = getDlxInstalledPackageDir(testPackageName)
211+
await fs.promises.mkdir(installedDir, { recursive: true })
212+
expect(isDlxPackageInstalled(testPackageName)).toBe(true)
213+
})
214+
215+
it('async version should return false when package is not installed', async () => {
216+
expect(await isDlxPackageInstalledAsync(testPackageName)).toBe(false)
217+
})
218+
219+
it('async version should return true when package is installed', async () => {
220+
// Create a mock installation
221+
const installedDir = getDlxInstalledPackageDir(testPackageName)
222+
await fs.promises.mkdir(installedDir, { recursive: true })
223+
expect(await isDlxPackageInstalledAsync(testPackageName)).toBe(true)
224+
})
225+
})
226+
227+
describe('listDlxPackages / listDlxPackagesAsync', () => {
228+
it('should return empty array when no packages are installed', () => {
229+
const packages = listDlxPackages()
230+
expect(packages).toEqual([])
231+
})
232+
233+
it('should list installed packages', async () => {
234+
// Create mock installations
235+
await ensureDlxDir()
236+
const pkg1Dir = getDlxPackageDir('package-1')
237+
const pkg2Dir = getDlxPackageDir('package-2')
238+
await fs.promises.mkdir(pkg1Dir, { recursive: true })
239+
await fs.promises.mkdir(pkg2Dir, { recursive: true })
240+
241+
const packages = listDlxPackages()
242+
expect(packages).toContain('package-1')
243+
expect(packages).toContain('package-2')
244+
expect(packages).toHaveLength(2)
245+
})
246+
247+
it('should return sorted list of packages', async () => {
248+
// Create mock installations in reverse order
249+
await ensureDlxDir()
250+
const pkgZDir = getDlxPackageDir('z-package')
251+
const pkgADir = getDlxPackageDir('a-package')
252+
await fs.promises.mkdir(pkgZDir, { recursive: true })
253+
await fs.promises.mkdir(pkgADir, { recursive: true })
254+
255+
const packages = listDlxPackages()
256+
expect(packages).toEqual(['a-package', 'z-package'])
257+
})
258+
259+
it('async version should return empty array when no packages are installed', async () => {
260+
const packages = await listDlxPackagesAsync()
261+
expect(packages).toEqual([])
262+
})
263+
264+
it('async version should list installed packages', async () => {
265+
// Create mock installations
266+
await ensureDlxDir()
267+
const pkg1Dir = getDlxPackageDir('package-1')
268+
const pkg2Dir = getDlxPackageDir('package-2')
269+
await fs.promises.mkdir(pkg1Dir, { recursive: true })
270+
await fs.promises.mkdir(pkg2Dir, { recursive: true })
271+
272+
const packages = await listDlxPackagesAsync()
273+
expect(packages).toContain('package-1')
274+
expect(packages).toContain('package-2')
275+
expect(packages).toHaveLength(2)
276+
})
277+
})
278+
279+
describe('removeDlxPackage / removeDlxPackageSync', () => {
280+
it('should remove installed package', async () => {
281+
// Create a mock installation
282+
const packageDir = getDlxPackageDir(testPackageName)
283+
await fs.promises.mkdir(packageDir, { recursive: true })
284+
expect(fs.existsSync(packageDir)).toBe(true)
285+
286+
await removeDlxPackage(testPackageName)
287+
expect(fs.existsSync(packageDir)).toBe(false)
288+
})
289+
290+
it('should not throw when removing non-existent package', async () => {
291+
// safeDelete handles non-existent files gracefully (force: true)
292+
await expect(
293+
removeDlxPackage('non-existent-package'),
294+
).resolves.not.toThrow()
295+
})
296+
297+
it('sync version should remove installed package', () => {
298+
// Create a mock installation
299+
const packageDir = getDlxPackageDir(testPackageName)
300+
fs.mkdirSync(packageDir, { recursive: true })
301+
expect(fs.existsSync(packageDir)).toBe(true)
302+
303+
removeDlxPackageSync(testPackageName)
304+
expect(fs.existsSync(packageDir)).toBe(false)
305+
})
306+
307+
it('sync version should not throw when removing non-existent package', () => {
308+
// Removing a non-existent package should not throw (force: true)
309+
expect(() => removeDlxPackageSync('non-existent-package')).not.toThrow()
310+
})
311+
})
312+
313+
describe('clearDlx / clearDlxSync', () => {
314+
it('should remove all DLX packages', async () => {
315+
// Create multiple mock installations
316+
await ensureDlxDir()
317+
const pkg1Dir = getDlxPackageDir('package-1')
318+
const pkg2Dir = getDlxPackageDir('package-2')
319+
await fs.promises.mkdir(pkg1Dir, { recursive: true })
320+
await fs.promises.mkdir(pkg2Dir, { recursive: true })
321+
322+
expect(listDlxPackages()).toHaveLength(2)
323+
await clearDlx()
324+
expect(listDlxPackages()).toHaveLength(0)
325+
})
326+
327+
it('should not throw when DLX directory is empty', async () => {
328+
await ensureDlxDir()
329+
await expect(clearDlx()).resolves.not.toThrow()
330+
})
331+
332+
it('should not throw when DLX directory does not exist', async () => {
333+
// Ensure directory doesn't exist
334+
if (fs.existsSync(dlxDir)) {
335+
fs.rmSync(dlxDir, { recursive: true, force: true })
336+
}
337+
await expect(clearDlx()).resolves.not.toThrow()
338+
})
339+
340+
it('sync version should remove all DLX packages', () => {
341+
// Create multiple mock installations
342+
ensureDlxDirSync()
343+
const pkg1Dir = getDlxPackageDir('package-1')
344+
const pkg2Dir = getDlxPackageDir('package-2')
345+
fs.mkdirSync(pkg1Dir, { recursive: true })
346+
fs.mkdirSync(pkg2Dir, { recursive: true })
347+
348+
expect(listDlxPackages()).toHaveLength(2)
349+
clearDlxSync()
350+
expect(listDlxPackages()).toHaveLength(0)
351+
})
352+
353+
it('sync version should not throw when DLX directory is empty', () => {
354+
ensureDlxDirSync()
355+
expect(() => clearDlxSync()).not.toThrow()
356+
})
357+
358+
it('sync version should not throw when DLX directory does not exist', () => {
359+
// Ensure directory doesn't exist
360+
if (fs.existsSync(dlxDir)) {
361+
fs.rmSync(dlxDir, { recursive: true, force: true })
362+
}
363+
expect(() => clearDlxSync()).not.toThrow()
364+
})
365+
})
366+
})

0 commit comments

Comments
 (0)