@@ -98,6 +98,43 @@ describe.sequential('dlx', () => {
9898 expect ( key ) . toHaveLength ( 16 )
9999 expect ( key ) . toMatch ( / ^ [ 0 - 9 a - f ] { 16 } $ / )
100100 } )
101+
102+ it ( 'should handle empty strings' , ( ) => {
103+ const key = generateCacheKey ( '' )
104+ expect ( key ) . toHaveLength ( 16 )
105+ expect ( key ) . toMatch ( / ^ [ 0 - 9 a - f ] { 16 } $ / )
106+ } )
107+
108+ it ( 'should handle special characters' , ( ) => {
109+ const key = generateCacheKey ( 'test@#$%^&*()_+-=[]{}|;:,.<>?' )
110+ expect ( key ) . toHaveLength ( 16 )
111+ expect ( key ) . toMatch ( / ^ [ 0 - 9 a - f ] { 16 } $ / )
112+ } )
113+
114+ it ( 'should handle unicode characters' , ( ) => {
115+ const key = generateCacheKey ( '测试-тест-テスト' )
116+ expect ( key ) . toHaveLength ( 16 )
117+ expect ( key ) . toMatch ( / ^ [ 0 - 9 a - f ] { 16 } $ / )
118+ } )
119+
120+ it ( 'should handle very long inputs' , ( ) => {
121+ const longSpec = 'a' . repeat ( 10_000 )
122+ const key = generateCacheKey ( longSpec )
123+ expect ( key ) . toHaveLength ( 16 )
124+ expect ( key ) . toMatch ( / ^ [ 0 - 9 a - f ] { 16 } $ / )
125+ } )
126+
127+ it ( 'should handle URLs as specs' , ( ) => {
128+ const key = generateCacheKey ( 'https://example.com/binary.tar.gz:binary' )
129+ expect ( key ) . toHaveLength ( 16 )
130+ expect ( key ) . toMatch ( / ^ [ 0 - 9 a - f ] { 16 } $ / )
131+ } )
132+
133+ it ( 'should produce different hashes for similar strings' , ( ) => {
134+ const key1 = generateCacheKey ( 'npm:test@1.0.0' )
135+ const key2 = generateCacheKey ( 'npm:test@1.0.1' )
136+ expect ( key1 ) . not . toBe ( key2 )
137+ } )
101138 } )
102139
103140 describe ( 'dlxDirExists / dlxDirExistsAsync' , ( ) => {
@@ -175,6 +212,25 @@ describe.sequential('dlx', () => {
175212 // Path should not contain backslashes on any platform after normalization
176213 expect ( packageDir ) . not . toContain ( '\\' )
177214 } )
215+
216+ it ( 'should handle scoped package names' , ( ) => {
217+ const scopedPackage = '@socket/cli'
218+ const packageDir = getDlxPackageDir ( scopedPackage )
219+ expect ( packageDir ) . toContain ( getSocketDlxDir ( ) )
220+ expect ( packageDir ) . toContain ( '@socket/cli' )
221+ } )
222+
223+ it ( 'should handle package names with special characters' , ( ) => {
224+ const specialPackage = 'package-name_with.chars'
225+ const packageDir = getDlxPackageDir ( specialPackage )
226+ expect ( packageDir ) . toContain ( getSocketDlxDir ( ) )
227+ expect ( packageDir ) . toContain ( specialPackage )
228+ } )
229+
230+ it ( 'should handle empty package name' , ( ) => {
231+ const packageDir = getDlxPackageDir ( '' )
232+ expect ( packageDir ) . toContain ( getSocketDlxDir ( ) )
233+ } )
178234 } )
179235
180236 describe ( 'getDlxPackageNodeModulesDir' , ( ) => {
@@ -184,6 +240,19 @@ describe.sequential('dlx', () => {
184240 expect ( nodeModulesDir ) . toContain ( testPackageName )
185241 expect ( nodeModulesDir ) . toContain ( 'node_modules' )
186242 } )
243+
244+ it ( 'should handle scoped packages' , ( ) => {
245+ const scopedPackage = '@socket/test'
246+ const nodeModulesDir = getDlxPackageNodeModulesDir ( scopedPackage )
247+ expect ( nodeModulesDir ) . toContain ( getSocketDlxDir ( ) )
248+ expect ( nodeModulesDir ) . toContain ( 'node_modules' )
249+ } )
250+
251+ it ( 'should handle empty package name' , ( ) => {
252+ const nodeModulesDir = getDlxPackageNodeModulesDir ( '' )
253+ expect ( nodeModulesDir ) . toContain ( getSocketDlxDir ( ) )
254+ expect ( nodeModulesDir ) . toContain ( 'node_modules' )
255+ } )
187256 } )
188257
189258 describe ( 'getDlxInstalledPackageDir' , ( ) => {
@@ -209,6 +278,19 @@ describe.sequential('dlx', () => {
209278 expect ( packageJsonPath ) . toContain ( testPackageName )
210279 expect ( packageJsonPath ) . toContain ( 'package.json' )
211280 } )
281+
282+ it ( 'should handle scoped packages' , ( ) => {
283+ const scopedPackage = '@socket/test'
284+ const packageJsonPath = getDlxPackageJsonPath ( scopedPackage )
285+ expect ( packageJsonPath ) . toContain ( getSocketDlxDir ( ) )
286+ expect ( packageJsonPath ) . toContain ( 'package.json' )
287+ } )
288+
289+ it ( 'should handle empty package name' , ( ) => {
290+ const packageJsonPath = getDlxPackageJsonPath ( '' )
291+ expect ( packageJsonPath ) . toContain ( getSocketDlxDir ( ) )
292+ expect ( packageJsonPath ) . toContain ( 'package.json' )
293+ } )
212294 } )
213295
214296 describe ( 'isInSocketDlx' , ( ) => {
@@ -240,6 +322,39 @@ describe.sequential('dlx', () => {
240322 const dlxPath = path . join ( getSocketDlxDir ( ) , 'package' , '' )
241323 expect ( isInSocketDlx ( dlxPath ) ) . toBe ( true )
242324 } )
325+
326+ it ( 'should return false for exact DLX directory path' , ( ) => {
327+ // The DLX directory itself is not "inside" the DLX directory
328+ expect ( isInSocketDlx ( getSocketDlxDir ( ) ) ) . toBe ( false )
329+ } )
330+
331+ it ( 'should return true for paths inside DLX with trailing slash' , ( ) => {
332+ // A path with trailing slash after DLX dir is considered inside
333+ const insidePath = path . join ( getSocketDlxDir ( ) , 'anything' )
334+ expect ( isInSocketDlx ( insidePath ) ) . toBe ( true )
335+ } )
336+
337+ it ( 'should handle nested paths' , ( ) => {
338+ const nestedPath = path . join (
339+ getSocketDlxDir ( ) ,
340+ 'pkg' ,
341+ 'node_modules' ,
342+ 'dep' ,
343+ 'lib' ,
344+ 'file.js' ,
345+ )
346+ expect ( isInSocketDlx ( nestedPath ) ) . toBe ( true )
347+ } )
348+
349+ it ( 'should handle similar but different paths' , ( ) => {
350+ const similarPath = `${ getSocketDlxDir ( ) } -other/package`
351+ expect ( isInSocketDlx ( similarPath ) ) . toBe ( false )
352+ } )
353+
354+ it ( 'should handle paths with special characters' , ( ) => {
355+ const specialPath = path . join ( getSocketDlxDir ( ) , '@scope/package' , 'bin' )
356+ expect ( isInSocketDlx ( specialPath ) ) . toBe ( true )
357+ } )
243358 } )
244359
245360 describe ( 'isDlxPackageInstalled / isDlxPackageInstalledAsync' , ( ) => {
@@ -264,6 +379,18 @@ describe.sequential('dlx', () => {
264379 await fs . promises . mkdir ( installedDir , { recursive : true } )
265380 expect ( await isDlxPackageInstalledAsync ( testPackageName ) ) . toBe ( true )
266381 } )
382+
383+ it ( 'should handle scoped packages' , async ( ) => {
384+ const scopedPackage = '@socket/test'
385+ expect ( isDlxPackageInstalled ( scopedPackage ) ) . toBe ( false )
386+ const installedDir = getDlxInstalledPackageDir ( scopedPackage )
387+ await fs . promises . mkdir ( installedDir , { recursive : true } )
388+ expect ( isDlxPackageInstalled ( scopedPackage ) ) . toBe ( true )
389+ } )
390+
391+ it ( 'should handle empty package name' , ( ) => {
392+ expect ( isDlxPackageInstalled ( '' ) ) . toBe ( false )
393+ } )
267394 } )
268395
269396 describe ( 'listDlxPackages / listDlxPackagesAsync' , ( ) => {
@@ -298,6 +425,44 @@ describe.sequential('dlx', () => {
298425 expect ( packages ) . toEqual ( [ 'a-package' , 'z-package' ] )
299426 } )
300427
428+ it ( 'should handle packages with special characters' , async ( ) => {
429+ await ensureDlxDir ( )
430+ const pkg1Dir = getDlxPackageDir ( 'package-name_with.chars' )
431+ const pkg2Dir = getDlxPackageDir ( 'other-package_123' )
432+ await fs . promises . mkdir ( pkg1Dir , { recursive : true } )
433+ await fs . promises . mkdir ( pkg2Dir , { recursive : true } )
434+
435+ const packages = listDlxPackages ( )
436+ expect ( packages ) . toContain ( 'other-package_123' )
437+ expect ( packages ) . toContain ( 'package-name_with.chars' )
438+ expect ( packages ) . toHaveLength ( 2 )
439+ } )
440+
441+ it ( 'should list scoped packages by scope directory' , async ( ) => {
442+ // When creating @scope /package, filesystem creates @scope dir and @scope/package subdir
443+ // listDlxPackages returns only top-level dirs, so it returns '@scope' not '@scope/package'
444+ await ensureDlxDir ( )
445+ const scopedPkgDir = getDlxPackageDir ( '@scope/package' )
446+ await fs . promises . mkdir ( scopedPkgDir , { recursive : true } )
447+
448+ const packages = listDlxPackages ( )
449+ expect ( packages ) . toContain ( '@scope' )
450+ expect ( packages ) . toHaveLength ( 1 )
451+ } )
452+
453+ it ( 'should filter out non-directory entries' , async ( ) => {
454+ await ensureDlxDir ( )
455+ const pkgDir = getDlxPackageDir ( 'real-package' )
456+ await fs . promises . mkdir ( pkgDir , { recursive : true } )
457+ // Create a file in the DLX directory (should be ignored)
458+ const filePath = path . join ( getSocketDlxDir ( ) , 'some-file.txt' )
459+ await fs . promises . writeFile ( filePath , 'content' )
460+
461+ const packages = listDlxPackages ( )
462+ expect ( packages ) . toEqual ( [ 'real-package' ] )
463+ expect ( packages ) . toHaveLength ( 1 )
464+ } )
465+
301466 it ( 'async version should return empty array when no packages are installed' , async ( ) => {
302467 const packages = await listDlxPackagesAsync ( )
303468 expect ( packages ) . toEqual ( [ ] )
@@ -316,6 +481,19 @@ describe.sequential('dlx', () => {
316481 expect ( packages ) . toContain ( 'package-2' )
317482 expect ( packages ) . toHaveLength ( 2 )
318483 } )
484+
485+ it ( 'async version should return sorted list' , async ( ) => {
486+ await ensureDlxDir ( )
487+ const pkgZDir = getDlxPackageDir ( 'z-package' )
488+ const pkgADir = getDlxPackageDir ( 'a-package' )
489+ const pkgMDir = getDlxPackageDir ( 'm-package' )
490+ await fs . promises . mkdir ( pkgZDir , { recursive : true } )
491+ await fs . promises . mkdir ( pkgADir , { recursive : true } )
492+ await fs . promises . mkdir ( pkgMDir , { recursive : true } )
493+
494+ const packages = await listDlxPackagesAsync ( )
495+ expect ( packages ) . toEqual ( [ 'a-package' , 'm-package' , 'z-package' ] )
496+ } )
319497 } )
320498
321499 describe ( 'removeDlxPackage / removeDlxPackageSync' , ( ) => {
0 commit comments