77using System . IO ;
88using System . Linq ;
99using System . Management . Automation ;
10+ using System . Management . Automation . Runspaces ;
1011using System . Threading ;
1112using System . Threading . Tasks ;
1213using Microsoft . Extensions . Logging . Abstractions ;
1314using Microsoft . PowerShell . EditorServices . Handlers ;
1415using Microsoft . PowerShell . EditorServices . Services ;
1516using Microsoft . PowerShell . EditorServices . Services . DebugAdapter ;
17+ using Microsoft . PowerShell . EditorServices . Services . PowerShell . Context ;
18+ using Microsoft . PowerShell . EditorServices . Services . PowerShell . Execution ;
1619using Microsoft . PowerShell . EditorServices . Services . PowerShell . Console ;
1720using Microsoft . PowerShell . EditorServices . Services . PowerShell . Host ;
21+ using Microsoft . PowerShell . EditorServices . Services . PowerShell ;
22+ using Microsoft . PowerShell . EditorServices . Services . PowerShell . Runspace ;
1823using Microsoft . PowerShell . EditorServices . Services . TextDocument ;
1924using Microsoft . PowerShell . EditorServices . Test ;
2025using Microsoft . PowerShell . EditorServices . Test . Shared ;
2126using Microsoft . PowerShell . EditorServices . Utility ;
27+ using SMA = System . Management . Automation ;
2228using Xunit ;
2329
2430namespace PowerShellEditorServices . Test . Debugging
@@ -32,6 +38,69 @@ internal class TestReadLine : IReadLine
3238 public void AddToHistory ( string historyEntry ) => history . Add ( historyEntry ) ;
3339 }
3440
41+ internal sealed class TestRunspaceInfo ( Runspace runspace ) : IRunspaceInfo
42+ {
43+ public RunspaceOrigin RunspaceOrigin => global ::Microsoft . PowerShell . EditorServices . Services . PowerShell . Runspace . RunspaceOrigin . Local ;
44+
45+ public bool IsOnRemoteMachine => false ;
46+
47+ public PowerShellVersionDetails PowerShellVersionDetails => throw new NotImplementedException ( ) ;
48+
49+ public SessionDetails SessionDetails => throw new NotImplementedException ( ) ;
50+
51+ public Runspace Runspace { get ; } = runspace ;
52+ }
53+
54+ internal sealed class TestRunspaceContext ( Runspace runspace ) : IRunspaceContext
55+ {
56+ public IRunspaceInfo CurrentRunspace { get ; } = new TestRunspaceInfo ( runspace ) ;
57+ }
58+
59+ internal sealed class ThrowingExecutionService : IInternalPowerShellExecutionService
60+ {
61+ public event Action < object , RunspaceChangedEventArgs > RunspaceChanged
62+ {
63+ add { }
64+ remove { }
65+ }
66+
67+ public Task < TResult > ExecuteDelegateAsync < TResult > (
68+ string representation ,
69+ ExecutionOptions executionOptions ,
70+ Func < SMA . PowerShell , CancellationToken , TResult > func ,
71+ CancellationToken cancellationToken ) => throw new NotImplementedException ( ) ;
72+
73+ public Task ExecuteDelegateAsync (
74+ string representation ,
75+ ExecutionOptions executionOptions ,
76+ Action < SMA . PowerShell , CancellationToken > action ,
77+ CancellationToken cancellationToken ) => throw new NotImplementedException ( ) ;
78+
79+ public Task < TResult > ExecuteDelegateAsync < TResult > (
80+ string representation ,
81+ ExecutionOptions executionOptions ,
82+ Func < CancellationToken , TResult > func ,
83+ CancellationToken cancellationToken ) => throw new NotImplementedException ( ) ;
84+
85+ public Task ExecuteDelegateAsync (
86+ string representation ,
87+ ExecutionOptions executionOptions ,
88+ Action < CancellationToken > action ,
89+ CancellationToken cancellationToken ) => throw new NotImplementedException ( ) ;
90+
91+ public Task < IReadOnlyList < TResult > > ExecutePSCommandAsync < TResult > (
92+ PSCommand psCommand ,
93+ CancellationToken cancellationToken ,
94+ PowerShellExecutionOptions executionOptions = null ) => throw new NotImplementedException ( ) ;
95+
96+ public Task ExecutePSCommandAsync (
97+ PSCommand psCommand ,
98+ CancellationToken cancellationToken ,
99+ PowerShellExecutionOptions executionOptions = null ) => throw new NotImplementedException ( ) ;
100+
101+ public void CancelCurrentTask ( ) => throw new NotImplementedException ( ) ;
102+ }
103+
35104 [ Trait ( "Category" , "DebugService" ) ]
36105 public class DebugServiceTests : IAsyncLifetime
37106 {
@@ -589,6 +658,44 @@ public async Task RecordsF5CommandInPowerShellHistory()
589658 Assert . Equal ( ". '" + debugScriptFile . FilePath + "'" , Assert . Single ( testReadLine . history ) ) ;
590659 }
591660
661+ [ Fact ]
662+ public async Task LaunchFailsInConstrainedLanguageWhenDebugCommandsAreUnavailable ( )
663+ {
664+ InitialSessionState initialSessionState = InitialSessionState . CreateDefault2 ( ) ;
665+ initialSessionState . LanguageMode = PSLanguageMode . ConstrainedLanguage ;
666+ using Runspace constrainedRunspace = RunspaceFactory . CreateRunspace ( initialSessionState ) ;
667+ constrainedRunspace . Open ( ) ;
668+
669+ Assert . Equal ( PSLanguageMode . ConstrainedLanguage , constrainedRunspace . SessionStateProxy . LanguageMode ) ;
670+ Assert . Null ( constrainedRunspace . SessionStateProxy . InvokeCommand . GetCommand ( "Wait-Debugger" , CommandTypes . Cmdlet ) ) ;
671+
672+ LaunchAndAttachHandler launchHandler = new (
673+ NullLoggerFactory . Instance ,
674+ debugAdapterServer : null ,
675+ breakpointService : null ,
676+ debugEventHandlerService : null ,
677+ debugService ,
678+ new TestRunspaceContext ( constrainedRunspace ) ,
679+ new ThrowingExecutionService ( ) ,
680+ new DebugStateService ( ) ,
681+ remoteFileManagerService : null ) ;
682+
683+ HandlerErrorException exception = await Assert . ThrowsAsync < HandlerErrorException > ( ( ) =>
684+ launchHandler . Handle (
685+ new PsesLaunchRequestArguments
686+ {
687+ Script = debugScriptFile . FilePath ,
688+ Cwd = "" ,
689+ CreateTemporaryIntegratedConsole = false ,
690+ ExecuteMode = "DotSource" ,
691+ } ,
692+ CancellationToken . None ) ) ;
693+
694+ Assert . Equal (
695+ "Cannot start debugging because you are running PowerShell in a constrained language mode that does not have the required debug commands available. Please contact your administrator to add the debug commands to your constrained runspace." ,
696+ exception . Message ) ;
697+ }
698+
592699 [ Fact ]
593700 public async Task RecordsF8CommandInHistory ( )
594701 {
0 commit comments