@@ -370,6 +370,293 @@ describe("Shell Detection Tests", () => {
370370 } )
371371 } )
372372
373+ // --------------------------------------------------------------------------
374+ // getTerminalConfig Behavior (tested via getShell)
375+ // --------------------------------------------------------------------------
376+ describe ( "getTerminalConfig" , ( ) => {
377+ it ( "returns defaultProfileName and matching profile for Windows" , ( ) => {
378+ Object . defineProperty ( process , "platform" , { value : "win32" } )
379+ mockVsCodeConfig ( "windows" , "Command Prompt" , {
380+ "Command Prompt" : { path : "C:\\Windows\\System32\\cmd.exe" } ,
381+ } )
382+ expect ( getShell ( ) ) . toBe ( "C:\\Windows\\System32\\cmd.exe" )
383+ } )
384+
385+ it ( "returns defaultProfileName and matching profile for macOS" , ( ) => {
386+ Object . defineProperty ( process , "platform" , { value : "darwin" } )
387+ mockVsCodeConfig ( "osx" , "fish" , {
388+ fish : { path : "/usr/local/bin/fish" } ,
389+ } )
390+ expect ( getShell ( ) ) . toBe ( "/usr/local/bin/fish" )
391+ } )
392+
393+ it ( "returns defaultProfileName and matching profile for Linux" , ( ) => {
394+ Object . defineProperty ( process , "platform" , { value : "linux" } )
395+ mockVsCodeConfig ( "linux" , "zsh" , {
396+ zsh : { path : "/usr/bin/zsh" } ,
397+ } )
398+ expect ( getShell ( ) ) . toBe ( "/usr/bin/zsh" )
399+ } )
400+
401+ it ( "returns null defaultProfileName when config value is undefined" , ( ) => {
402+ Object . defineProperty ( process , "platform" , { value : "linux" } )
403+ const mockConfig = {
404+ get : vi . fn ( ( key : string ) => {
405+ if ( key === "defaultProfile.linux" ) return undefined
406+ if ( key === "profiles.linux" ) return { bash : { path : "/bin/bash" } }
407+ return undefined
408+ } ) ,
409+ }
410+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
411+ expect ( getShell ( ) ) . toBe ( "/bin/bash" )
412+ } )
413+
414+ it ( "returns empty profiles when profiles config is null" , ( ) => {
415+ Object . defineProperty ( process , "platform" , { value : "linux" } )
416+ const mockConfig = {
417+ get : vi . fn ( ( key : string ) => {
418+ if ( key === "defaultProfile.linux" ) return "bash"
419+ if ( key === "profiles.linux" ) return null
420+ return undefined
421+ } ) ,
422+ }
423+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
424+ expect ( getShell ( ) ) . toBe ( "/bin/bash" )
425+ } )
426+
427+ it ( "returns fallback when getConfiguration throws" , ( ) => {
428+ Object . defineProperty ( process , "platform" , { value : "darwin" } )
429+ vi . mocked ( vscode . workspace . getConfiguration ) . mockImplementation ( ( ) => {
430+ throw new Error ( "config error" )
431+ } )
432+ expect ( getShell ( ) ) . toBe ( "/bin/zsh" )
433+ } )
434+
435+ it ( "returns fallback when config.get throws" , ( ) => {
436+ Object . defineProperty ( process , "platform" , { value : "linux" } )
437+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( {
438+ get : ( ) => {
439+ throw new Error ( "get error" )
440+ } ,
441+ } as any )
442+ expect ( getShell ( ) ) . toBe ( "/bin/bash" )
443+ } )
444+ } )
445+
446+ // --------------------------------------------------------------------------
447+ // Non-string defaultProfileName Handling
448+ // --------------------------------------------------------------------------
449+ describe ( "Non-string defaultProfileName handling" , ( ) => {
450+ it ( "Windows: handles numeric defaultProfileName without TypeError" , ( ) => {
451+ Object . defineProperty ( process , "platform" , { value : "win32" } )
452+ const mockConfig = {
453+ get : vi . fn ( ( key : string ) => {
454+ if ( key === "defaultProfile.windows" ) return 1
455+ if ( key === "profiles.windows" ) return { }
456+ return undefined
457+ } ) ,
458+ }
459+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
460+ vi . mocked ( existsSync ) . mockReturnValue ( false )
461+
462+ expect ( getShell ( ) ) . toBe ( "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" )
463+ } )
464+
465+ it ( "Windows: handles boolean defaultProfileName without TypeError" , ( ) => {
466+ Object . defineProperty ( process , "platform" , { value : "win32" } )
467+ const mockConfig = {
468+ get : vi . fn ( ( key : string ) => {
469+ if ( key === "defaultProfile.windows" ) return true
470+ if ( key === "profiles.windows" ) return { }
471+ return undefined
472+ } ) ,
473+ }
474+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
475+ vi . mocked ( existsSync ) . mockReturnValue ( false )
476+
477+ expect ( getShell ( ) ) . toBe ( "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" )
478+ } )
479+
480+ it ( "Windows: handles array defaultProfileName without TypeError" , ( ) => {
481+ Object . defineProperty ( process , "platform" , { value : "win32" } )
482+ const mockConfig = {
483+ get : vi . fn ( ( key : string ) => {
484+ if ( key === "defaultProfile.windows" ) return [ "PowerShell" ]
485+ if ( key === "profiles.windows" ) return { }
486+ return undefined
487+ } ) ,
488+ }
489+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
490+ vi . mocked ( existsSync ) . mockReturnValue ( false )
491+
492+ expect ( getShell ( ) ) . toBe ( "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" )
493+ } )
494+
495+ it ( "Windows: handles object defaultProfileName without TypeError" , ( ) => {
496+ Object . defineProperty ( process , "platform" , { value : "win32" } )
497+ const mockConfig = {
498+ get : vi . fn ( ( key : string ) => {
499+ if ( key === "defaultProfile.windows" ) return { name : "PowerShell" }
500+ if ( key === "profiles.windows" ) return { }
501+ return undefined
502+ } ) ,
503+ }
504+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
505+ vi . mocked ( existsSync ) . mockReturnValue ( false )
506+
507+ expect ( getShell ( ) ) . toBe ( "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" )
508+ } )
509+
510+ it ( "macOS: handles numeric defaultProfileName without TypeError" , ( ) => {
511+ Object . defineProperty ( process , "platform" , { value : "darwin" } )
512+ const mockConfig = {
513+ get : vi . fn ( ( key : string ) => {
514+ if ( key === "defaultProfile.osx" ) return 1
515+ if ( key === "profiles.osx" ) return { }
516+ return undefined
517+ } ) ,
518+ }
519+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
520+
521+ expect ( getShell ( ) ) . toBe ( "/bin/zsh" )
522+ } )
523+
524+ it ( "macOS: handles boolean defaultProfileName without TypeError" , ( ) => {
525+ Object . defineProperty ( process , "platform" , { value : "darwin" } )
526+ const mockConfig = {
527+ get : vi . fn ( ( key : string ) => {
528+ if ( key === "defaultProfile.osx" ) return true
529+ if ( key === "profiles.osx" ) return { }
530+ return undefined
531+ } ) ,
532+ }
533+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
534+
535+ expect ( getShell ( ) ) . toBe ( "/bin/zsh" )
536+ } )
537+
538+ it ( "macOS: handles array defaultProfileName without TypeError" , ( ) => {
539+ Object . defineProperty ( process , "platform" , { value : "darwin" } )
540+ const mockConfig = {
541+ get : vi . fn ( ( key : string ) => {
542+ if ( key === "defaultProfile.osx" ) return [ "zsh" ]
543+ if ( key === "profiles.osx" ) return { }
544+ return undefined
545+ } ) ,
546+ }
547+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
548+
549+ expect ( getShell ( ) ) . toBe ( "/bin/zsh" )
550+ } )
551+
552+ it ( "macOS: handles object defaultProfileName without TypeError" , ( ) => {
553+ Object . defineProperty ( process , "platform" , { value : "darwin" } )
554+ const mockConfig = {
555+ get : vi . fn ( ( key : string ) => {
556+ if ( key === "defaultProfile.osx" ) return { }
557+ if ( key === "profiles.osx" ) return { }
558+ return undefined
559+ } ) ,
560+ }
561+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
562+
563+ expect ( getShell ( ) ) . toBe ( "/bin/zsh" )
564+ } )
565+
566+ // Mutation-resistant: without the typeof guard, profiles[1] === profiles["1"] in JS,
567+ // so a numeric key that matches a real profile would return its path instead of falling back.
568+ it ( "macOS: ignores numeric defaultProfileName even when it matches a profile key" , ( ) => {
569+ Object . defineProperty ( process , "platform" , { value : "darwin" } )
570+ const mockConfig = {
571+ get : vi . fn ( ( key : string ) => {
572+ if ( key === "defaultProfile.osx" ) return 1
573+ // Profile keyed as "1" — would be reached by profiles[1] if the guard were absent
574+ if ( key === "profiles.osx" ) return { "1" : { path : "/usr/local/bin/zsh" } }
575+ return undefined
576+ } ) ,
577+ }
578+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
579+
580+ // Guard treats 1 as null → getMacShellFromVSCode returns null → fallback to /bin/zsh
581+ // Without the guard it would return /usr/local/bin/zsh
582+ expect ( getShell ( ) ) . toBe ( "/bin/zsh" )
583+ } )
584+
585+ it ( "Linux: handles numeric defaultProfileName without TypeError" , ( ) => {
586+ Object . defineProperty ( process , "platform" , { value : "linux" } )
587+ const mockConfig = {
588+ get : vi . fn ( ( key : string ) => {
589+ if ( key === "defaultProfile.linux" ) return 1
590+ if ( key === "profiles.linux" ) return { }
591+ return undefined
592+ } ) ,
593+ }
594+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
595+
596+ expect ( getShell ( ) ) . toBe ( "/bin/bash" )
597+ } )
598+
599+ it ( "Linux: handles boolean defaultProfileName without TypeError" , ( ) => {
600+ Object . defineProperty ( process , "platform" , { value : "linux" } )
601+ const mockConfig = {
602+ get : vi . fn ( ( key : string ) => {
603+ if ( key === "defaultProfile.linux" ) return true
604+ if ( key === "profiles.linux" ) return { }
605+ return undefined
606+ } ) ,
607+ }
608+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
609+
610+ expect ( getShell ( ) ) . toBe ( "/bin/bash" )
611+ } )
612+
613+ it ( "Linux: handles array defaultProfileName without TypeError" , ( ) => {
614+ Object . defineProperty ( process , "platform" , { value : "linux" } )
615+ const mockConfig = {
616+ get : vi . fn ( ( key : string ) => {
617+ if ( key === "defaultProfile.linux" ) return [ "bash" ]
618+ if ( key === "profiles.linux" ) return { }
619+ return undefined
620+ } ) ,
621+ }
622+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
623+
624+ expect ( getShell ( ) ) . toBe ( "/bin/bash" )
625+ } )
626+
627+ it ( "Linux: handles object defaultProfileName without TypeError" , ( ) => {
628+ Object . defineProperty ( process , "platform" , { value : "linux" } )
629+ const mockConfig = {
630+ get : vi . fn ( ( key : string ) => {
631+ if ( key === "defaultProfile.linux" ) return { }
632+ if ( key === "profiles.linux" ) return { }
633+ return undefined
634+ } ) ,
635+ }
636+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
637+
638+ expect ( getShell ( ) ) . toBe ( "/bin/bash" )
639+ } )
640+
641+ // Mutation-resistant: same pattern as macOS — numeric key matches profile "1" only if unguarded.
642+ it ( "Linux: ignores numeric defaultProfileName even when it matches a profile key" , ( ) => {
643+ Object . defineProperty ( process , "platform" , { value : "linux" } )
644+ const mockConfig = {
645+ get : vi . fn ( ( key : string ) => {
646+ if ( key === "defaultProfile.linux" ) return 1
647+ // Profile keyed as "1" — would be reached by profiles[1] if the guard were absent
648+ if ( key === "profiles.linux" ) return { "1" : { path : "/usr/bin/fish" } }
649+ return undefined
650+ } ) ,
651+ }
652+ vi . mocked ( vscode . workspace . getConfiguration ) . mockReturnValue ( mockConfig as any )
653+
654+ // Guard treats 1 as null → getLinuxShellFromVSCode returns null → fallback to /bin/bash
655+ // Without the guard it would return /usr/bin/fish
656+ expect ( getShell ( ) ) . toBe ( "/bin/bash" )
657+ } )
658+ } )
659+
373660 // --------------------------------------------------------------------------
374661 // Shell Validation Tests
375662 // --------------------------------------------------------------------------
0 commit comments