public void RaisedUnhandledException(ITestSettings settings) { this.TestPurpose("This test checks to see if unhandled exception can work during debugging"); this.WriteSettings(settings); this.Comment("Set initial debuggee for application"); IDebuggee debuggee = OpenDebuggee(this, settings, DebuggeeMonikers.Exception.Default); using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings)) { this.Comment("Launch the application"); runner.Launch(settings.DebuggerSettings, debuggee, "-CallRaisedUnhandledException"); this.Comment("Start debugging to hit the exception and verify it should stop at correct source file and line"); runner.Expects.StoppedEvent(StoppedReason.Exception, srcClassName, 8).AfterConfigurationDone(); this.Comment("Verify the callstack, variables and evaluation "); using (IThreadInspector threadInspector = runner.GetThreadInspector()) { this.Comment("Get current frame object"); IFrameInspector currentFrame = threadInspector.Stack.First(); this.Comment("Verify current frame when stop at the exception"); threadInspector.AssertStackFrameNames(true, "myException::RaisedUnhandledException.*"); this.Comment("Verify the variables after stop at the exception"); Assert.Subset(new HashSet <string>() { "result", "temp", "this", "myvar" }, currentFrame.Variables.ToKeySet()); currentFrame.AssertVariables("result", "10", "temp", "0", "myvar", "200"); // TODO: LLDB was affected by bug #240441, I wil update this once this bug get fixed if (settings.DebuggerSettings.DebuggerType != SupportedDebugger.Lldb) { this.Comment("Evaluate an expression and verify the results after stop at the exception"); string varEvalResult = currentFrame.Evaluate("result = result + 1"); this.WriteLine("Expected: 11, Actual: {0}", varEvalResult); Assert.Equal("11", varEvalResult); } // TODO: Mingw32 was affected by bug #242924, I wil update this once this bug get fixed if (!(settings.DebuggerSettings.DebuggerType == SupportedDebugger.Gdb_MinGW && settings.DebuggerSettings.DebuggeeArchitecture == SupportedArchitecture.x86)) { this.Comment("Evaluate a function and verify the the results after stop at exception"); string funEvalResult = currentFrame.Evaluate("EvalFunc(100,100)"); this.WriteLine("Expected: 200, Actual: {0}", funEvalResult); Assert.Equal("200", funEvalResult); } } this.Comment("Stop debugging"); runner.DisconnectAndVerify(); } }
/// <summary> /// This method has only been used for const char* so far. /// If required to work with other string-like types, please test it and /// expand this method to support those types. /// </summary> /// <param name="frameInspector"></param> /// <param name="expression"></param> /// <param name="context"></param> /// <param name="expectedValue"></param> public static void AssertEvaluateAsString( this IFrameInspector frameInspector, string expression, EvaluateContext context, string expectedValue) { if (expectedValue == null) { AssertEvaluateAsNull(frameInspector, expression, context); return; } for (int i = 0; i <= expectedValue.Length; i++) { string actualValue = frameInspector.Evaluate( string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", expression, i), context); char expectedChar;; if (i == expectedValue.Length) { expectedChar = '\0'; } else { expectedChar = expectedValue[i]; } AssertCharValue(frameInspector.DebuggerRunner.DebuggerSettings, actualValue, expectedChar); } }
public static void AssertEvaluateAsError(this IFrameInspector frameInspector, string variableName, EvaluateContext context) { string actualErrorMessage = frameInspector.Evaluate(variableName, context); string expectedErrorMessage = GetUndefinedError(frameInspector.DebuggerRunner.DebuggerSettings, variableName); Assert.Contains(expectedErrorMessage, actualErrorMessage, StringComparison.OrdinalIgnoreCase); }
/// <summary> /// Checks whether a pointer value is null. /// This function will return incorrect results if not called with an expression of type pointer. /// </summary> /// <param name="frameInspector"></param> /// <param name="expression"></param> /// <param name="context"></param> public static void AssertEvaluateAsNull( this IFrameInspector frameInspector, string expression, EvaluateContext context) { string actualValue = frameInspector.Evaluate( string.Format(CultureInfo.InvariantCulture, "{0}==0", expression), context); Assert.Equal("true", actualValue); }
public void WatchBasic(ITestSettings settings) { this.TestPurpose("Evaluate some expressions in watch."); this.WriteSettings(settings); IDebuggee debuggee = SinkHelper.Open(this, settings.CompilerSettings, DebuggeeMonikers.KitchenSink.Expression); using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings)) { this.Comment("Configure launch"); runner.Launch(settings.DebuggerSettings, debuggee, "-fExpression"); this.Comment("Set a line breakpoints so that we can stop."); runner.SetBreakpoints(debuggee.Breakpoints(SinkHelper.Expression, 31)); this.Comment("To start debugging and break"); runner.Expects.StoppedEvent(StoppedReason.Breakpoint).AfterConfigurationDone(); using (IThreadInspector threadInspector = runner.GetThreadInspector()) { IFrameInspector currentFrame = threadInspector.Stack.First(); this.Comment("To evaluate variables and functions in watch."); string evalMyInt = currentFrame.Evaluate("myint-=100", EvaluateContext.Watch); currentFrame.AssertEvaluateAsChar("mychar", EvaluateContext.Watch, 'A'); string evalMyBool = currentFrame.Evaluate("mybool", EvaluateContext.Watch); currentFrame.AssertEvaluateAsWChar("mywchar", EvaluateContext.Watch, 'z'); currentFrame.AssertEvaluateAsDouble("mydouble", EvaluateContext.Watch, 321); currentFrame.AssertEvaluateAsFloat("myfloat", EvaluateContext.Watch, 299); string evalFuncMaxInt = currentFrame.Evaluate("Test::max(myint,1)", EvaluateContext.Watch); currentFrame.AssertEvaluateAsDouble("Test::max(mydouble,0.0)-321.0", EvaluateContext.Watch, 0); Assert.Equal("0", evalMyInt); Assert.Equal("true", evalMyBool); Assert.Equal("1", evalFuncMaxInt); } this.Comment("Run to completion"); runner.Expects.TerminatedEvent().AfterContinue(); runner.DisconnectAndVerify(); } }
public static void AssertEvaluateAsFloat(this IFrameInspector frameInspector, string expression, EvaluateContext context, float expectedValue) { string actualValue = frameInspector.Evaluate(expression, context); AssertFloatValue(frameInspector.DebuggerRunner.DebuggerSettings, actualValue, expectedValue); }
public static void AssertEvaluateAsIntArray(this IFrameInspector frameInspector, string expression, EvaluateContext context, params int[] expectedValue) { string actualValue = frameInspector.Evaluate(expression, context); AssertIntArrayValue(frameInspector.DebuggerRunner.DebuggerSettings, actualValue, expectedValue); }
public static void AssertEvaluateAsObject(this IFrameInspector frameInspector, string expression, EvaluateContext context, params string[] expectedObjectProperties) { string actualValue = frameInspector.Evaluate(expression, context); AssertObjectValue(frameInspector.DebuggerRunner.DebuggerSettings, actualValue, expectedObjectProperties); }
public static void AssertEvaluateAsVector(this IFrameInspector frameInspector, string expression, EvaluateContext context, int vectorCount) { string actualValue = frameInspector.Evaluate(expression, context); AssertVectorValue(frameInspector.DebuggerRunner.DebuggerSettings, actualValue, vectorCount); }
public void CoreDumpVerifyActions(ITestSettings settings) { this.TestPurpose("This test checks to see the behavior when do actions during core dump debugging."); this.WriteSettings(settings); this.Comment("Compile the application"); CompileApp(this, settings, DebuggeeMonikers.CoreDump.Action); this.Comment("Set initial debuggee for application"); IDebuggee debuggee = OpenDebuggee(this, settings, DebuggeeMonikers.CoreDump.Action); this.Comment("Launch the application to hit an exception and generate core dump"); string coreDumpPath = GenerateCoreDump(settings, DebuggeeMonikers.CoreDump.Action, debuggee); using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings)) { this.Comment("Configure the core dump before start debugging"); runner.LaunchCoreDump(settings.DebuggerSettings, debuggee, coreDumpPath); this.Comment("Start debugging to hit the exception and verify it should stop at correct source file and line"); runner.Expects.StoppedEvent(StoppedReason.Exception, srcClassName, 8).AfterConfigurationDone(); this.Comment("Verify the error message for relevant actions during core dump debugging"); using (IThreadInspector threadInspector = runner.GetThreadInspector()) { this.Comment("Get current frame object"); IFrameInspector currentFrame = threadInspector.Stack.First(); this.Comment("Verify current frame when stop at the exception"); threadInspector.AssertStackFrameNames(true, "myException::RaisedUnhandledException.*"); this.Comment("Try to evaluate a expression and verify the results"); string varEvalResult = currentFrame.Evaluate("result + 1"); Assert.Equal("11", varEvalResult); this.Comment("Try to evaluate a function and verify the error message"); EvaluateResponseValue evalResponse = runner.RunCommand(new EvaluateCommand("EvalFunc(100, 100)", currentFrame.Id)); // TODO: From VSCode IDE with the latest cpptools, the error message after evaluate function is "not availabe", but evalResponse.message is null, is it expected ? // Currently just simply verify the result is empty as a workaround, need to revisit this once get more information from logged bug #242418 this.Comment(string.Format(CultureInfo.InvariantCulture, "Actual evaluated result: {0}", evalResponse.body.result)); Assert.True(evalResponse.body.result.Equals(string.Empty)); this.Comment(string.Format(CultureInfo.InvariantCulture, "Actual evaluated respone message: {0}", evalResponse.message)); //Assert.True(evalResponse.message.Contains(evalError)); } this.Comment("Try to step in and verify the error message"); StepInCommand stepInCommand = new StepInCommand(runner.DarRunner.CurrentThreadId); runner.RunCommandExpectFailure(stepInCommand); this.WriteLine(string.Format(CultureInfo.InvariantCulture, "Actual respone message: {0}", stepInCommand.Message)); Assert.Contains(stepInCommand.Message, string.Format(CultureInfo.InvariantCulture, stepError, "step in")); this.Comment("Try to step over and verify the error message"); StepOverCommand stepOverCommand = new StepOverCommand(runner.DarRunner.CurrentThreadId); runner.RunCommandExpectFailure(stepOverCommand); this.WriteLine(string.Format(CultureInfo.InvariantCulture, "Actual respone message: {0}", stepOverCommand.Message)); Assert.Contains(stepOverCommand.Message, string.Format(CultureInfo.InvariantCulture, stepError, "step next")); this.Comment("Try to step out and verify the error message"); StepOutCommand stepOutCommand = new StepOutCommand(runner.DarRunner.CurrentThreadId); runner.RunCommandExpectFailure(stepOutCommand); this.WriteLine(string.Format(CultureInfo.InvariantCulture, "Actual respone message: {0}", stepOutCommand.Message)); Assert.Contains(stepOutCommand.Message, string.Format(CultureInfo.InvariantCulture, stepError, "step out")); this.Comment("Try to continue and verify the error message"); ContinueCommand continueCommand = new ContinueCommand(runner.DarRunner.CurrentThreadId); runner.RunCommandExpectFailure(continueCommand); this.WriteLine(string.Format(CultureInfo.InvariantCulture, "Actual respone message: {0}", continueCommand.Message)); Assert.Contains(continueCommand.Message, string.Format(CultureInfo.InvariantCulture, stepError, "continue")); this.Comment("Try to set a breakpoint and verify the error message"); SourceBreakpoints bp = debuggee.Breakpoints(srcAppName, 16); SetBreakpointsResponseValue setBpResponse = runner.SetBreakpoints(bp); Assert.False(setBpResponse.body.breakpoints[0].verified); this.WriteLine(string.Format(CultureInfo.InvariantCulture, "Actual respone message: {0}", setBpResponse.body.breakpoints[0].message)); Assert.Contains(setBpResponse.body.breakpoints[0].message, bpError); this.Comment("Stop core dump debugging"); runner.DisconnectAndVerify(); } }
public void TestOptimizedSharedLib(ITestSettings settings) { this.TestPurpose("Tests basic bps and source information for shared library"); this.WriteSettings(settings); IDebuggee debuggee = Debuggee.Open(this, settings.CompilerSettings, Name, DebuggeeMonikers.Optimization.OptimizationWithSymbols); using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings)) { this.Comment("Configure launch"); runner.Launch(settings.DebuggerSettings, debuggee); SourceBreakpoints mainBreakpoints = debuggee.Breakpoints(SourceName, 87, 89); SourceBreakpoints libBreakpoints = debuggee.Breakpoints(SrcLibName, 9, 12); this.Comment("Set initial breakpoints"); runner.SetBreakpoints(mainBreakpoints); runner.SetBreakpoints(libBreakpoints); this.Comment("Launch and run until 1st bp"); runner.Expects.HitBreakpointEvent(SourceName, 87) .AfterConfigurationDone(); //Todo: this has different behavior on Mac, I have logged bug#247895 to track //Del said that Different compilers generate symbols differently. //Our tests have to be resilient to this fact. The location of the step is reasonable, //so this is by design. this.Comment("enter into the library source"); runner.ExpectBreakpointAndStepToTarget(SrcLibName, 8, 9).AfterContinue(); this.Comment("Step over"); runner.Expects.HitStepEvent(SrcLibName, 10).AfterStepOver(); this.Comment("Check the un-optimized values in shared library"); using (IThreadInspector inspector = runner.GetThreadInspector()) { IFrameInspector currentFrame = inspector.Stack.First(); IVariableInspector age = currentFrame.Variables["age"]; this.Comment("Check the local variable in sub function"); Assert.Matches("31", age.Value); this.Comment("run to continue"); if (settings.DebuggerSettings.DebuggerType == SupportedDebugger.Lldb) { runner.Expects.HitBreakpointEvent(SourceName, 89) .AfterContinue(); this.Comment("Verify current frame for main func"); inspector.AssertStackFrameNames(true, "main"); } else { runner.Expects.HitBreakpointEvent(SrcLibName, 12) .AfterContinue(); this.Comment("Verify current frame for library func"); inspector.AssertStackFrameNames(true, "myClass::DisplayAge"); this.Comment("Step out to main entry"); runner.Expects.HitBreakpointEvent(SourceName, 89).AfterContinue(); this.Comment("Verify current frame for main entry"); inspector.AssertStackFrameNames(true, "main"); } this.Comment("Evaluate the expression:"); //skip the Mac's verification as bug#247893 currentFrame = inspector.Stack.First(); string strAge = currentFrame.Evaluate("myclass->DisplayAge(30)"); if (settings.DebuggerSettings.DebuggerType == SupportedDebugger.Gdb_MinGW || settings.DebuggerSettings.DebuggerType == SupportedDebugger.Gdb_Cygwin) { Assert.Equal("Cannot evaluate function -- may be inlined", strAge); } } runner.DisconnectAndVerify(); } }
public void RaisedReThrowException(ITestSettings settings) { this.TestPurpose("This test checks to see if re-throw exception can work during debugging."); this.WriteSettings(settings); this.Comment("Set initial debuggee for application"); IDebuggee debuggee = OpenDebuggee(this, settings, DebuggeeMonikers.Exception.Default); using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings)) { this.Comment("Launch the application"); runner.Launch(settings.DebuggerSettings, debuggee, "-CallRaisedReThrowException"); this.Comment("Set line breakpoints to the lines with entry of try block and catch block"); SourceBreakpoints bps = debuggee.Breakpoints(srcClassName, 73, 79, 86); runner.SetBreakpoints(bps); this.Comment("Start debugging and hit the breakpoint in the try block"); runner.Expects.HitBreakpointEvent(srcClassName, 73).AfterConfigurationDone(); this.Comment("Continue executing and hit the breakpoint in the frist catch block"); runner.Expects.HitBreakpointEvent(srcClassName, 79).AfterContinue(); using (IThreadInspector threadInspector = runner.GetThreadInspector()) { this.Comment("Get current frame object"); IFrameInspector currentFrame = threadInspector.Stack.First(); this.Comment("Verify current frame when stop at the first catch block"); threadInspector.AssertStackFrameNames(true, "myException::RaisedReThrowException.*"); this.Comment("Verify the variables of 'errorCode' in the first catch block"); currentFrame.AssertVariables("errorCode", "200"); this.Comment("Verify step in can work in the first catch block"); runner.ExpectStepAndStepToTarget(srcClassName, startLine: 41, targetLine: 42).AfterStepIn(); this.Comment("Verify current frame after step in another function"); threadInspector.AssertStackFrameNames(true, "myException::EvalFunc.*"); this.Comment("Verify step out can work in the first catch block"); runner.Expects.HitStepEvent(srcClassName, 79).AfterStepOut(); } this.Comment("Continue to hit the re-throw exception in the first catch block"); runner.Expects.HitBreakpointEvent(srcClassName, 86).AfterContinue(); using (IThreadInspector threadInspector = runner.GetThreadInspector()) { this.Comment("Get current frame object"); IFrameInspector currentFrame = threadInspector.Stack.First(); this.Comment("Verify current frame when stop at the second catch block"); threadInspector.AssertStackFrameNames(true, "myException::RaisedReThrowException.*"); this.Comment("Verify the variables in the second catch block"); Assert.Subset(new HashSet <string>() { "var", "this", "errorCode", "ex2" }, currentFrame.Variables.ToKeySet()); currentFrame.AssertVariables("var", "400", "errorCode", "400"); this.Comment("Verify the exception information in the second catch block"); IVariableInspector ex2Var = currentFrame.Variables["ex2"]; Assert.Contains("code", ex2Var.Variables.Keys); this.WriteLine("Expected: 400, Actual: {0}", ex2Var.Variables["code"].Value); Assert.Equal("400", ex2Var.Variables["code"].Value); this.Comment("Evaluate a function and verify the the results at the second catch block "); // TODO: Mingw32 was affected by bug #242924, I wil update this once this bug get fixed bool evalNotSupportedInCatch = (settings.DebuggerSettings.DebuggerType == SupportedDebugger.Gdb_MinGW && settings.DebuggerSettings.DebuggeeArchitecture == SupportedArchitecture.x86) || (settings.DebuggerSettings.DebuggerType == SupportedDebugger.VsDbg && settings.DebuggerSettings.DebuggeeArchitecture == SupportedArchitecture.x64); if (!evalNotSupportedInCatch) { string funEvalResult = currentFrame.Evaluate("EvalFunc(20,20)"); this.WriteLine("Expected: 40, Actual: {0}", funEvalResult); Assert.Equal("40", funEvalResult); } } this.Comment("Verify can step out from a catch block"); runner.ExpectStopAndStepToTarget(StoppedReason.Step, srcAppName, startLine: 61, targetLine: 64).AfterStepOut(); this.Comment("Continue to run at the end of the application"); runner.Expects.TerminatedEvent().AfterContinue(); runner.DisconnectAndVerify(); } }
public void RaisedHandledException(ITestSettings settings) { this.TestPurpose("This test checks to see if user handled exception can work during debugging"); this.WriteSettings(settings); this.Comment("Set initial debuggee for application"); IDebuggee debuggee = OpenDebuggee(this, settings, DebuggeeMonikers.Exception.Default); using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings)) { this.Comment("Launch the application"); runner.Launch(settings.DebuggerSettings, debuggee, "-CallRaisedHandledException"); this.Comment("Set line breakpoints to the lines with entry of try block and catch block"); SourceBreakpoints bps = debuggee.Breakpoints(srcClassName, 20, 33); runner.SetBreakpoints(bps); this.Comment("Start debugging and hit the breakpoint in the try block"); runner.Expects.HitBreakpointEvent(srcClassName, 20).AfterConfigurationDone(); this.Comment("Step over in the try block"); runner.Expects.HitStepEvent(srcClassName, 21).AfterStepOver(); this.Comment("Continue to raise the exception and hit the breakpoint set in the catch block"); runner.Expects.HitBreakpointEvent(srcClassName, 33).AfterContinue(); this.Comment("Verify can step over in the catch block"); runner.Expects.HitStepEvent(srcClassName, 34).AfterStepOver(); this.Comment("Verify the callstack, variables and evaluation "); using (IThreadInspector threadInspector = runner.GetThreadInspector()) { this.Comment("Get current frame object"); IFrameInspector currentFrame = threadInspector.Stack.First(); this.Comment("Verify current frame when stop at the catch block"); threadInspector.AssertStackFrameNames(true, "myException::RaisedHandledException.*"); this.Comment("Verify the variables in the catch block"); Assert.Subset(new HashSet <string>() { "result", "global", "this", "a", "errorCode", "ex" }, currentFrame.Variables.ToKeySet()); currentFrame.AssertVariables("result", "201", "global", "101", "a", "100"); this.Comment("Verify the exception information in the catch block"); IVariableInspector exVar = currentFrame.Variables["ex"]; Assert.Contains("code", exVar.Variables.Keys); this.WriteLine("Expected: 101, Actual: {0}", exVar.Variables["code"].Value); Assert.Equal("101", exVar.Variables["code"].Value); // TODO: LLDB was affected by bug #240441, I wil update this once this bug get fixed if (settings.DebuggerSettings.DebuggerType != SupportedDebugger.Lldb) { this.Comment("Evaluate an expression and verify the results"); string varEvalResult = currentFrame.Evaluate("result=result + 1"); this.WriteLine("Expected: 202, Actual: {0}", varEvalResult); Assert.Equal("202", varEvalResult); } this.Comment("Evaluate a function and verify the the results"); // TODO: Mingw32 was affected by bug #242924, I wil update this once this bug get fixed bool evalNotSupportedInCatch = (settings.DebuggerSettings.DebuggerType == SupportedDebugger.Gdb_MinGW && settings.DebuggerSettings.DebuggeeArchitecture == SupportedArchitecture.x86) || (settings.DebuggerSettings.DebuggerType == SupportedDebugger.VsDbg && settings.DebuggerSettings.DebuggeeArchitecture == SupportedArchitecture.x64); if (!evalNotSupportedInCatch) { string funEvalResult = currentFrame.Evaluate("RecursiveFunc(50)"); this.WriteLine("Expected: 1, Actual: {0}", funEvalResult); Assert.Equal("1", funEvalResult); } } this.Comment("Verify can step over after evaluation in the catch block"); runner.Expects.HitStepEvent(srcClassName, 35).AfterStepOver(); this.Comment("Continue to run at the end of the application"); runner.Expects.TerminatedEvent().AfterContinue(); runner.DisconnectAndVerify(); } }
public void TestFolderol(ITestSettings settings) { this.TestPurpose("This test checks a bunch of commands and events."); this.WriteSettings(settings); IDebuggee debuggee = Debuggee.Open(this, settings.CompilerSettings, HelloName, DebuggeeMonikers.HelloWorld.Sample); using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings)) { this.Comment("Launch the debuggee"); runner.Launch(settings.DebuggerSettings, debuggee); StoppedEvent stopAtBreak = new StoppedEvent(StoppedReason.Breakpoint); // VsDbg does not fire Breakpoint Change events when breakpoints are set. // Instead it sends a new breakpoint event when it is bound (after configuration done). bool bindsLate = (settings.DebuggerSettings.DebuggerType == SupportedDebugger.VsDbg); this.Comment("Set a breakpoint on line 8, but expect it to resolve to line 9."); runner.Expects.ConditionalEvent(!bindsLate, x => x.BreakpointChangedEvent(BreakpointReason.Changed, 9)) .AfterSetBreakpoints(debuggee.Breakpoints(HelloSourceName, 8)); this.Comment("Start debuggging until breakpoint is hit."); runner.Expects.ConditionalEvent(bindsLate, x => x.BreakpointChangedEvent(BreakpointReason.Changed, 9)) .Event(stopAtBreak) .AfterConfigurationDone(); Assert.Equal(HelloSourceName, stopAtBreak.ActualEventInfo.Filename); Assert.Equal(9, stopAtBreak.ActualEventInfo.Line); Assert.Equal(StoppedReason.Breakpoint, stopAtBreak.ActualEventInfo.Reason); this.Comment("Step forward twice until we have initialized variables"); runner.Expects.StoppedEvent(StoppedReason.Step, HelloSourceName, 10) .AfterStepOver(); runner.Expects.StoppedEvent(StoppedReason.Step, HelloSourceName, 11) .AfterStepIn(); this.Comment("Inspect the stack and try evaluation."); using (IThreadInspector inspector = runner.GetThreadInspector()) { this.Comment("Get the stack trace"); IFrameInspector mainFrame = inspector.Stack.First(); inspector.AssertStackFrameNames(true, "main.*"); this.WriteLine("Main frame: {0}", mainFrame); this.Comment("Get variables"); Assert.Subset(new HashSet <string>() { "x", "y", "argc", "argv" }, mainFrame.Variables.ToKeySet()); mainFrame.AssertVariables( "x", "6", "argc", "1"); IVariableInspector argv = mainFrame.Variables["argv"]; Assert.Matches(HexNumberPattern, argv.Value); this.Comment("Expand a variable (argv has *argv under it)"); string variableName = "*argv"; if (settings.DebuggerSettings.DebuggerType == SupportedDebugger.VsDbg) { variableName = String.Empty; } Assert.Contains(variableName, argv.Variables.Keys); Assert.Matches(HexNumberPattern, argv.Variables[variableName].Value); this.Comment("Evaluate with side effect"); string result = mainFrame.Evaluate("x = x + 1"); Assert.Equal("7", result); } this.Comment("Step to force stack info to refresh"); runner.Expects.StoppedEvent(StoppedReason.Step).AfterStepOver(); using (IThreadInspector inspector = runner.GetThreadInspector()) { this.Comment("Evaluation has side effect, make sure it propagates"); Assert.Equal("7", inspector.Stack.First().Variables["x"].Value); } runner.Expects.ExitedEvent(0).TerminatedEvent().AfterContinue(); runner.DisconnectAndVerify(); } }