Example #1
0
        public void EvaluateInvalidExpression(ITestSettings settings)
        {
            this.TestPurpose("To test invalid expression evaluation return apropriate errors.");
            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 breakpoint so that we can stop at a line.");
                runner.SetBreakpoints(debuggee.Breakpoints(SinkHelper.Expression, 31));

                this.Comment("To start debugging and hit breakpoint.");
                runner.Expects.HitBreakpointEvent().AfterConfigurationDone();

                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    IFrameInspector currentFrame = threadInspector.Stack.First();

                    this.Comment("To evaluate some invalid expression on curren stack frame.");
                    currentFrame.AssertEvaluateAsError("notExistVar", EvaluateContext.Watch);
                }

                this.Comment("Continue to run to exist.");
                runner.Expects.TerminatedEvent().AfterContinue();

                runner.DisconnectAndVerify();
            }
        }
Example #2
0
        public void CallStackBasic(ITestSettings settings)
        {
            this.TestPurpose("To check all frames of callstack on a thead and evaluation on each frame.");
            this.WriteSettings(settings);

            IDebuggee debuggee = SinkHelper.Open(this, settings.CompilerSettings, DebuggeeMonikers.KitchenSink.Expression);

            this.Comment("Here are stack frames in a list we expect the actual to match with this.");
            StackFrame[] expectedstackFrames = ExpressionTests.GenerateFramesList(settings.DebuggerSettings);

            using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
            {
                this.Comment("Configure launch.");
                runner.Launch(settings.DebuggerSettings, debuggee, "-fExpression");

                this.Comment("Set a breakpoint so that we can stop after starting debugging.");
                runner.SetBreakpoints(debuggee.Breakpoints(SinkHelper.Expression, 19));

                this.Comment("To start debugging and break");
                runner.Expects.StoppedEvent(StoppedReason.Breakpoint, SinkHelper.Expression, 19).AfterConfigurationDone();

                this.Comment("To step in several times into the innermost layer of a recursive call.");
                runner.ExpectStepAndStepToTarget(SinkHelper.Expression, 9, 10).AfterStepIn();
                runner.Expects.HitStepEvent(SinkHelper.Expression, 12).AfterStepIn();
                runner.ExpectStepAndStepToTarget(SinkHelper.Expression, 9, 10).AfterStepIn();
                runner.Expects.HitStepEvent(SinkHelper.Expression, 12).AfterStepIn();
                runner.ExpectStepAndStepToTarget(SinkHelper.Expression, 9, 10).AfterStepIn();

                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    IEnumerable <IFrameInspector> stackOfCurrentThread = threadInspector.Stack;
                    this.Comment("To verify the count of stack frames count.");
                    Assert.True(stackOfCurrentThread.Count() >= 13, "Expected the stack frame count to be at least 13 deep");

                    this.Comment("To verify each frame, include frame name, line number and source name.");
                    int index = 0;
                    foreach (IFrameInspector frame in stackOfCurrentThread)
                    {
                        if (index >= 13)
                        {
                            break;
                        }
                        StackFrame expectedstackFrame = expectedstackFrames[index];
                        this.Comment("Comparing Names. Expecected: {0}, Actual: {1}", expectedstackFrame.Name, frame.Name);
                        Assert.Contains(expectedstackFrame.Name, frame.Name, StringComparison.Ordinal);
                        this.Comment("Comparing line number. Expecected: {0}, Actual: {1}", expectedstackFrame.Line, frame.Line);
                        Assert.Equal(expectedstackFrame.Line, frame.Line);
                        this.Comment("Comparing Source Name. Expecected: {0}, Actual: {1}", expectedstackFrame.SourceName, frame.SourceName);
                        Assert.Equal(expectedstackFrame.SourceName, frame.SourceName);
                        index++;
                    }
                }

                this.Comment("Continue to run to exist.");
                runner.Expects.TerminatedEvent().AfterContinue();

                runner.DisconnectAndVerify();
            }
        }
Example #3
0
        public void TestOptimizedBpsAndSource(ITestSettings settings)
        {
            this.TestPurpose("Tests basic operation of bps and source information for optimized app");
            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, 68);
                SourceBreakpoints userDefinedClassBreakpoints = debuggee.Breakpoints(UserDefinedClassName, 8, 15, 54);

                this.Comment("Set initial breakpoints");
                runner.SetBreakpoints(mainBreakpoints);
                runner.SetBreakpoints(userDefinedClassBreakpoints);

                this.Comment("Launch and run until 1st bp");
                runner.Expects.HitBreakpointEvent(UserDefinedClassName, 8)
                .AfterConfigurationDone();

                this.Comment("run until 2nd bp");
                runner.Expects.HitBreakpointEvent(UserDefinedClassName, 54)
                .AfterContinue();

                this.Comment("run until 3rd bp");
                runner.Expects.HitBreakpointEvent(SourceName, 68)
                .AfterContinue();

                //Todo: this has different behavior on Mac(:16), Other Platforms(15) I have logged bug#247891 to track
                this.Comment("run until 4th bp");
                runner.ExpectBreakpointAndStepToTarget(UserDefinedClassName, 15, 16).AfterContinue();

                this.Comment("continue to next bp");
                runner.Expects.HitBreakpointEvent(UserDefinedClassName, 54)
                .AfterContinue();

                this.Comment("Check the current callstack frame");
                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    this.Comment("Get current frame object");
                    IFrameInspector currentFrame = threadInspector.Stack.First();

                    this.Comment("Verify current frame");
                    threadInspector.AssertStackFrameNames(true, "Foo::Sum");
                }

                this.Comment("step out to main entry");
                runner.Expects.HitStepEvent(SourceName, 69)
                .AfterStepOut();

                runner.Expects.ExitedEvent(0).TerminatedEvent().AfterContinue();
                runner.DisconnectAndVerify();
            }
        }
Example #4
0
        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();
            }
        }
Example #5
0
        public void RunModeBreakpoints(ITestSettings settings)
        {
            this.TestPurpose("Tests setting breakpoints while in run mode");
            this.WriteSettings(settings);

            IDebuggee debuggee = SinkHelper.Open(this, settings.CompilerSettings, DebuggeeMonikers.KitchenSink.Breakpoint);

            using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
            {
                this.Comment("Configure launch");
                runner.Launch(settings.DebuggerSettings, debuggee, "-fNonTerminating");
                runner.ConfigurationDone();

                // Wait a second to ensure the debuggee has entered run mode, then try to set a breakpoint
                Thread.Sleep(TimeSpan.FromSeconds(1));
                this.Comment("Set a function breakpoint while in run mode");
                FunctionBreakpoints functionBreakpoints = new FunctionBreakpoints("NonTerminating::DoSleep");
                runner.ExpectBreakpointAndStepToTarget(SinkHelper.NonTerminating, startLine: 37, targetLine: 38)
                .AfterSetFunctionBreakpoints(functionBreakpoints);

                this.Comment("Remove function breakpoint");
                functionBreakpoints.Remove("NonTerminating::DoSleep");
                runner.SetFunctionBreakpoints(functionBreakpoints);

                this.Comment("Continue, set a line breakpoint while in run mode");
                runner.Continue();

                // Wait a second to ensure the debuggee has entered run mode, then try to set a breakpoint
                Thread.Sleep(TimeSpan.FromSeconds(1));
                runner.Expects.HitBreakpointEvent(SinkHelper.NonTerminating, 28)
                .AfterSetBreakpoints(debuggee.Breakpoints(SinkHelper.NonTerminating, 28));

                this.Comment("Escape loop");
                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    IFrameInspector firstFrame = threadInspector.Stack.First();
                    this.WriteLine(firstFrame.ToString());
                    firstFrame.GetVariable("this", "shouldExit").Value = "1";
                }

                this.Comment("Continue until end");
                runner.Expects.ExitedEvent()
                .TerminatedEvent()
                .AfterContinue();

                runner.DisconnectAndVerify();
            }
        }
Example #6
0
        public void TestSharedLibWithoutSymbol(ITestSettings settings)
        {
            this.TestPurpose("Tests basic bps and source information for shared library without symbols");
            this.WriteSettings(settings);

            IDebuggee debuggee = Debuggee.Open(this, settings.CompilerSettings, Name, DebuggeeMonikers.Optimization.OptimizationWithoutSymbols);

            using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
            {
                this.Comment("Configure launch");
                runner.Launch(settings.DebuggerSettings, debuggee);

                SourceBreakpoints mainBreakpoints = debuggee.Breakpoints(SourceName, 87, 91);

                this.Comment("Set initial breakpoints");
                runner.SetBreakpoints(mainBreakpoints);

                this.Comment("Launch and run until 1st bp");
                runner.Expects.HitBreakpointEvent(SourceName, 87)
                .AfterConfigurationDone();

                this.Comment("Step into the library source");
                runner.Expects.HitStepEvent(SourceName, 89)
                .AfterStepIn();

                this.Comment("Check the stack for debugging shared library without symbols");
                using (IThreadInspector inspector = runner.GetThreadInspector())
                {
                    IFrameInspector currentFrame = inspector.Stack.First();
                    inspector.AssertStackFrameNames(true, "main");

                    this.Comment("run to continue to 2nd bp");
                    runner.Expects.HitBreakpointEvent(SourceName, 91)
                    .AfterContinue();

                    this.Comment("Check the stack for debugging shared library without symbols");
                    currentFrame = inspector.Stack.First();
                    inspector.AssertStackFrameNames(true, "main");
                    this.Comment("Check the local variables in main function");
                    IVariableInspector age = currentFrame.Variables["age"];
                    Assert.Matches("31", age.Value);
                }

                runner.DisconnectAndVerify();
            }
        }
        /// <summary>
        /// Verifies the names of the frames in the stack
        /// </summary>
        /// <param name="threadInspector">The thread to verify</param>
        /// <param name="useRegEx">Set to true if the frame names are regular expressions, otherwise expects exact match.</param>
        /// <param name="frameNames">The list of the frame names to verify.</param>
        public static void AssertStackFrameNames(this IThreadInspector threadInspector, bool useRegEx, params string[] frameNames)
        {
            Parameter.ThrowIfOutOfRange(frameNames.Length, 1, int.MaxValue, nameof(frameNames));

            int frameCount = 0;

            foreach (IFrameInspector frameInspector in threadInspector.Stack)
            {
                AssertFrameName(frameInspector, useRegEx, frameNames[frameCount]);

                frameCount++;
                if (frameCount >= frameNames.Length)
                {
                    break;
                }
            }
        }
Example #8
0
        public void AttachAsyncBreak(ITestSettings settings)
        {
            this.TestPurpose("Verifies attach and that breakpoints can be set from break mode.");
            this.WriteSettings(settings);

            IDebuggee debuggee        = SinkHelper.Open(this, settings.CompilerSettings, DebuggeeMonikers.KitchenSink.Attach);
            Process   debuggeeProcess = debuggee.Launch("-fNonTerminating", "-fCalling");

            using (ProcessHelper.ProcessCleanup(this, debuggeeProcess))
                using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
                {
                    this.Comment("Attach to debuggee");
                    runner.Attach(settings.DebuggerSettings, debuggeeProcess);
                    runner.ConfigurationDone();

                    this.Comment("Attempt to break all");
                    StoppedEvent breakAllEvent = new StoppedEvent(StoppedReason.Pause);
                    runner.Expects.Event(breakAllEvent)
                    .AfterAsyncBreak();

                    this.WriteLine("Break all stopped on:");
                    this.WriteLine(breakAllEvent.ActualEvent.ToString());

                    this.Comment("Set breakpoint while breaking code.");
                    runner.SetBreakpoints(debuggee.Breakpoints(SinkHelper.NonTerminating, 28));

                    this.Comment("Start running after the async break (since we have no idea where we are) and then hit the breakpoint");
                    runner.Expects.HitBreakpointEvent(SinkHelper.NonTerminating, 28)
                    .AfterContinue();

                    this.Comment("Evaluate the shouldExit member to true to stop the infinite loop.");
                    using (IThreadInspector threadInspector = runner.GetThreadInspector())
                    {
                        IFrameInspector firstFrame = threadInspector.Stack.First();
                        this.WriteLine(firstFrame.ToString());
                        firstFrame.GetVariable("shouldExitLocal").Value = "true";
                    }

                    this.Comment("Continue until debuggee exists");
                    runner.Expects.ExitedEvent(exitCode: 0).TerminatedEvent().AfterContinue();

                    this.Comment("Verify debugger and debuggee closed");
                    runner.DisconnectAndVerify();
                    Assert.True(debuggeeProcess.HasExited, "Debuggee still running.");
                }
        }
Example #9
0
        private void TestEnvironmentVariable(ITestSettings settings, string variableName, string variableValue, bool newTerminal)
        {
            this.WriteSettings(settings);

            IDebuggee debuggee = SinkHelper.Open(this, settings.CompilerSettings, DebuggeeMonikers.KitchenSink.Environment);

            using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
            {
                this.Comment("Configure launch");
                LaunchCommand launch = new LaunchCommand(settings.DebuggerSettings, debuggee.OutputPath, false, "-fEnvironment")
                {
                    StopAtEntry = false
                };
                if (variableValue != null)
                {
                    launch.Args.environment = new EnvironmentEntry[] {
                        new EnvironmentEntry {
                            Name = variableName, Value = variableValue
                        }
                    };
                }

                launch.Args.externalConsole = newTerminal;
                runner.RunCommand(launch);

                this.Comment("Set breakpoint");
                runner.SetBreakpoints(debuggee.Breakpoints(SinkHelper.Environment, 14));

                runner.Expects.StoppedEvent(StoppedReason.Breakpoint).AfterConfigurationDone();

                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    IFrameInspector currentFrame = threadInspector.Stack.First();
                    this.Comment("Verify locals variables on current frame.");
                    currentFrame.AssertEvaluateAsString("varValue1", EvaluateContext.Watch, variableValue);
                }

                this.Comment("Continue until end");
                runner.Expects.ExitedEvent()
                .TerminatedEvent()
                .AfterContinue();

                runner.DisconnectAndVerify();
            }
        }
Example #10
0
        public void TestOptimizedLocals(ITestSettings settings)
        {
            this.TestPurpose("Tests basic local expression which is not been optimized");
            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 userDefinedClassBreakpoints = debuggee.Breakpoints(UserDefinedClassName, 54);

                this.Comment("Set initial breakpoints");
                runner.SetBreakpoints(userDefinedClassBreakpoints);

                this.Comment("Launch and run until 1st bp");
                runner.Expects.HitBreakpointEvent(UserDefinedClassName, 54)
                .AfterConfigurationDone();

                this.Comment("Check the un-optimized values");
                using (IThreadInspector inspector = runner.GetThreadInspector())
                {
                    IFrameInspector    currentFrame = inspector.Stack.First();
                    IVariableInspector sum          = currentFrame.Variables["sum"];
                    IVariableInspector first        = currentFrame.Variables["first"];

                    this.Comment("Check the local variables in sub function");
                    Assert.Matches("^0", sum.Value);
                    Assert.Matches("^1", first.Value);

                    this.Comment("Step out");
                    runner.Expects.HitStepEvent(SourceName, 66)
                    .AfterStepOut();

                    this.Comment("Evaluate the expression:");
                    currentFrame = inspector.Stack.First();
                    inspector.AssertStackFrameNames(true, "main");
                }

                runner.DisconnectAndVerify();
            }
        }
Example #11
0
        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();
            }
        }
Example #12
0
        public void LocalsBasic(ITestSettings settings)
        {
            this.TestPurpose("Check primitives displying in locals.");
            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 verify locals variables on current frame.");
                    Assert.Subset(new HashSet <string>()
                    {
                        "mybool", "mychar", "myint", "mywchar", "myfloat", "mydouble", "this"
                    }, currentFrame.Variables.ToKeySet());
                    currentFrame.AssertVariables(
                        "mybool", "true",
                        "myint", "100");

                    currentFrame.GetVariable("mychar").AssertValueAsChar('A');
                    currentFrame.GetVariable("mywchar").AssertValueAsWChar('z');
                    currentFrame.GetVariable("myfloat").AssertValueAsFloat(299);
                    currentFrame.GetVariable("mydouble").AssertValueAsDouble(321);
                }

                this.Comment("Run to completion");
                runner.Expects.TerminatedEvent().AfterContinue();

                runner.DisconnectAndVerify();
            }
        }
Example #13
0
        public void AssignInvalidExpressionToVariable(ITestSettings settings)
        {
            this.TestPurpose("Assign an invalid expression to a variable.");
            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 breakpoint so that we can stop at a line.");
                runner.SetBreakpoints(debuggee.Breakpoints(SinkHelper.Expression, 31));

                this.Comment("Start debugging and hit breakpoint.");
                runner.Expects.StoppedEvent(StoppedReason.Breakpoint).AfterConfigurationDone();

                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    IFrameInspector currentFrame = threadInspector.Stack.First();

                    this.Comment("Assign an invalid expression to a variable.");
                    currentFrame.GetVariable("myint").SetVariableValueExpectFailure("39+nonexistingint");
                }

                // Start another inspector to refresh values
                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    IFrameInspector currentFrame = threadInspector.Stack.First();

                    this.Comment("Check the value of the variable hasn't been updated.");
                    Assert.Equal("100", currentFrame.GetVariable("myint").Value);
                }

                this.Comment("Continue to run to exist.");
                runner.Expects.TerminatedEvent().AfterContinue();

                runner.DisconnectAndVerify();
            }
        }
Example #14
0
        public void ExecutionAsyncBreak(ITestSettings settings)
        {
            this.TestPurpose("Verify break all should work run function");
            this.WriteSettings(settings);

            this.Comment("Open the kitchen sink debuggee for execution tests.");
            IDebuggee debuggee = SinkHelper.Open(this, settings.CompilerSettings, DebuggeeMonikers.KitchenSink.Execution);

            using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
            {
                this.Comment("Configure launch");
                runner.Launch(settings.DebuggerSettings, debuggee, "-fNonTerminating", "-fCalling");

                this.Comment("Try to break all");
                StoppedEvent breakAllEvent = new StoppedEvent(StoppedReason.Pause);
                runner.Expects.Event(breakAllEvent).AfterAsyncBreak();

                this.WriteLine("Break all stopped on:");
                this.WriteLine(breakAllEvent.ActualEvent.ToString());

                this.Comment("Set a breakpoint while breaking code");
                runner.SetBreakpoints(debuggee.Breakpoints(SinkHelper.NonTerminating, 28));

                this.Comment("Start running after the async break and then hit the breakpoint");
                runner.Expects.HitBreakpointEvent(SinkHelper.NonTerminating, 28).AfterContinue();

                this.Comment("Evaluate the shouldExit member to true to stop the infinite loop.");
                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    IFrameInspector firstFrame = threadInspector.Stack.First();
                    this.WriteLine(firstFrame.ToString());
                    firstFrame.GetVariable("shouldExit").Value = "true";
                }

                this.Comment("Continue running at the end of application");
                runner.Expects.ExitedEvent().TerminatedEvent().AfterContinue();

                this.Comment("Verify debugger and debuggee closed");
                runner.DisconnectAndVerify();
            }
        }
Example #15
0
        /// <summary>
        /// Run core dump basic debugging scenarios
        /// </summary>
        void RunCoreDumpBasic(ITestSettings settings, int debuggeeMoniker)
        {
            this.Comment("Set initial debuggee for application");
            IDebuggee debuggee = OpenDebuggee(this, settings, debuggeeMoniker);

            this.Comment("Launch the application to hit an exception and generate core dump");
            string coreDumpPath = GenerateCoreDump(settings, debuggeeMoniker, 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 callstack and variables");
                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    this.Comment("Get current frame object");
                    IFrameInspector currentFrame = threadInspector.Stack.First();

                    this.WriteLine("current frame: {0}", currentFrame);

                    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");
                }

                this.Comment("Stop core dump debugging");
                runner.DisconnectAndVerify();
            }
        }
Example #16
0
        public void ConditionalBreakpoints(ITestSettings settings)
        {
            this.TestPurpose("Tests that conditional breakpoints work");
            this.WriteSettings(settings);

            IDebuggee debuggee = SinkHelper.Open(this, settings.CompilerSettings, DebuggeeMonikers.KitchenSink.Breakpoint);

            using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
            {
                this.Comment("Configure launch");
                runner.Launch(settings.DebuggerSettings, debuggee, "-fCalling");

                this.Comment("Set a conditional line breakpoint");
                SourceBreakpoints callingBreakpoints = new SourceBreakpoints(debuggee, SinkHelper.Calling);
                callingBreakpoints.Add(17, "i == 5");
                runner.SetBreakpoints(callingBreakpoints);

                // The schema also supports conditions on function breakpoints, but MIEngine or GDB doesn't seem
                //  to support that.  Plus, there's no way to do it through the VSCode UI anyway.

                this.Comment("Run to breakpoint");
                runner.Expects.HitBreakpointEvent(SinkHelper.Calling, 17)
                .AfterConfigurationDone();

                this.Comment("Verify breakpoint condition is met");
                using (IThreadInspector inspector = runner.GetThreadInspector())
                {
                    IFrameInspector mainFrame = inspector.Stack.First();
                    mainFrame.AssertVariables("i", "5");
                }

                this.Comment("Run to completion");
                runner.Expects.ExitedEvent()
                .TerminatedEvent()
                .AfterContinue();

                runner.DisconnectAndVerify();
            }
        }
Example #17
0
        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();
            }
        }
Example #18
0
        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();
            }
        }
Example #19
0
        public void EvaluateOnFrames(ITestSettings settings)
        {
            this.TestPurpose("To check evalution on different frame with different variable types.");
            this.WriteSettings(settings);

            this.Comment("Open the debugge with a initialization.");
            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 breakpoint so that we can stop at a line.");
                runner.SetBreakpoints(debuggee.Breakpoints(SinkHelper.Expression, 19));

                this.Comment("To start debugging and break");
                runner.Expects.StoppedEvent(StoppedReason.Breakpoint).AfterConfigurationDone();

                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    IFrameInspector currentFrame;

                    this.Comment("To evaluate on the first frame.");
                    currentFrame = threadInspector.Stack.First();
                    currentFrame.AssertVariables("isCalled", "true");
                    Assert.Equal("true", currentFrame.Evaluate("isCalled||false", EvaluateContext.Watch));
                    currentFrame.AssertEvaluateAsDouble("d", EvaluateContext.Watch, 10.1);

                    this.Comment("Switch to next frame then evaluate on that frame.");
                    currentFrame = threadInspector.Stack.ElementAt(1);
                    currentFrame.GetVariable("_f").AssertValueAsFloat(1);
                    currentFrame.AssertEvaluateAsFloat("_f", EvaluateContext.Watch, 1);

                    this.Comment("To evaluate string and vector type on it, the try to enable pretty printing to evaluate again.");
                    currentFrame = threadInspector.Stack.ElementAt(2);
                    currentFrame.GetVariable("vec").AssertValueAsVector(5);
                    currentFrame.AssertEvaluateAsVector("vec", EvaluateContext.Watch, 5);

                    this.Comment("To evaluate some special values on the fourth frame.");
                    currentFrame = threadInspector.Stack.ElementAt(3);
                    currentFrame.AssertEvaluateAsDouble("mydouble=1.0", EvaluateContext.Watch, 1);
                    currentFrame.GetVariable("mynull").AssertValueAsChar('\0');

                    this.Comment("To evaluate class on stack on the fifth frame.");
                    currentFrame = threadInspector.Stack.ElementAt(4);
                    IVariableInspector varInspector;
                    varInspector = currentFrame.GetVariable("student");
                    Assert.Equal("10", varInspector.GetVariable("age").Value);
                    Assert.Equal("19", currentFrame.Evaluate("student.age=19", EvaluateContext.Watch));

                    this.Comment("To evaluate array on the sixth frame.");
                    currentFrame = threadInspector.Stack.ElementAt(5);
                    Assert.Equal("10", currentFrame.Evaluate("*(pArr+1)=10", EvaluateContext.Watch));
                    Assert.Equal("100", currentFrame.Evaluate("arr[0]=100", EvaluateContext.Watch));
                }


                this.Comment("Continue to run to exist.");
                runner.Expects.TerminatedEvent().AfterContinue();

                runner.DisconnectAndVerify();
            }
        }
Example #20
0
        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();
            }
        }
Example #21
0
        public void DataTipBasic(ITestSettings settings)
        {
            this.TestPurpose("To test evaluation in datatip.");
            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("To set a breakpoint so that we can stop at somewhere for evaluation.");
                runner.SetBreakpoints(debuggee.Breakpoints(SinkHelper.Expression, 19));

                this.Comment("To start debugging and break");
                runner.Expects.StoppedEvent(StoppedReason.Breakpoint).AfterConfigurationDone();

                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    IFrameInspector currentFrame;

                    this.Comment("To evaluate in datatip on the first frame.");
                    currentFrame = threadInspector.Stack.First();
                    Assert.Equal("true", currentFrame.Evaluate("isCalled", EvaluateContext.DataTip));
                    currentFrame.AssertEvaluateAsDouble("d", EvaluateContext.DataTip, 10.1);

                    // We only verify the major contents in datatip
                    Assert.Contains(@"accumulate(int)", currentFrame.Evaluate("accumulate", EvaluateContext.DataTip), StringComparison.Ordinal);

                    this.Comment("To evaluate in datatip on the fourth frame.");
                    currentFrame = threadInspector.Stack.ElementAt(3);
                    currentFrame.AssertEvaluateAsDouble("mydouble", EvaluateContext.DataTip, double.PositiveInfinity);
                    currentFrame.AssertEvaluateAsChar("mynull", EvaluateContext.DataTip, '\0');

                    this.Comment("To evaluate in datatip on the fifth frame.");
                    currentFrame = threadInspector.Stack.ElementAt(4);
                    currentFrame.AssertEvaluateAsObject("student", EvaluateContext.DataTip, "name", @"""John""", "age", "10");
                    Assert.Matches(@"0x[0-9A-Fa-f]+", currentFrame.Evaluate("pStu", EvaluateContext.DataTip));

                    this.Comment("To evaluate in datatip on the sixth frame.");
                    currentFrame = threadInspector.Stack.ElementAt(5);
                    currentFrame.AssertEvaluateAsIntArray("arr", EvaluateContext.DataTip, 0, 1, 2, 3, 4);
                    Assert.Matches(@"0x[0-9A-Fa-f]+", currentFrame.Evaluate("pArr", EvaluateContext.DataTip));

                    this.Comment("To evaluate in datatip on the seventh frame.");
                    currentFrame = threadInspector.Stack.ElementAt(6);
                    Assert.Equal("true", currentFrame.Evaluate("mybool", EvaluateContext.DataTip));
                    Assert.Equal("100", currentFrame.Evaluate("myint", EvaluateContext.DataTip));
                    currentFrame.AssertEvaluateAsFloat("myfloat", EvaluateContext.DataTip, 299);
                    currentFrame.AssertEvaluateAsDouble("mydouble", EvaluateContext.DataTip, 321);
                    currentFrame.AssertEvaluateAsChar("mychar", EvaluateContext.DataTip, 'A');
                    currentFrame.AssertEvaluateAsWChar("mywchar", EvaluateContext.DataTip, 'z');
                }

                this.Comment("Continue to run to exist.");
                runner.Expects.TerminatedEvent().AfterContinue();

                runner.DisconnectAndVerify();
            }
        }
Example #22
0
        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();
            }
        }
Example #23
0
        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();
            }
        }
Example #24
0
        public void MapDirectory(ITestSettings settings)
        {
            this.TestPurpose("Validate Source Mapping.");

            this.WriteSettings(settings);

            IDebuggee debuggee = SourceMappingHelper.Open(this, settings.CompilerSettings, DebuggeeMonikers.SourceMapping.Default);

            // VsDbg is case insensitive on Windows so sometimes stackframe file names might all be lowercase
            StringComparison comparison = settings.DebuggerSettings.DebuggerType == SupportedDebugger.VsDbg ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;

            using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
            {
                this.Comment("Configure");
                LaunchCommand launch = new LaunchCommand(settings.DebuggerSettings, debuggee.OutputPath, false, "-fCalling");

                launch.Args.externalConsole = false;

                this.Comment("Setting up Source File Mappings");

                Dictionary <string, string> sourceMappings = new Dictionary <string, string>();
                string pathRoot = Path.GetPathRoot(debuggee.SourceRoot);

                string mgrDirectoryMapping    = Path.Combine(debuggee.SourceRoot, SourceMappingHelper.Manager, Path.GetRandomFileName());
                string writerDirectoryMapping = Path.Combine(pathRoot, Path.GetRandomFileName(), Path.GetRandomFileName());
                string rootDirectoryMapping   = Path.Combine(pathRoot, Path.GetRandomFileName());
                sourceMappings.Add(Path.Combine(debuggee.SourceRoot, SourceMappingHelper.WriterFolder), writerDirectoryMapping);
                sourceMappings.Add(Path.Combine(debuggee.SourceRoot, SourceMappingHelper.ManagerFolder), mgrDirectoryMapping);
                sourceMappings.Add(debuggee.SourceRoot, rootDirectoryMapping);

                launch.Args.sourceFileMap = sourceMappings;

                try
                {
                    if (PlatformUtilities.IsWindows)
                    {
                        // Create all the directories but only some of the files will exist on disk.
                        foreach (var dir in sourceMappings.Values)
                        {
                            Directory.CreateDirectory(dir);
                        }
                        File.Copy(Path.Combine(debuggee.SourceRoot, SourceMappingHelper.WriterFolder, SourceMappingHelper.Writer), Path.Combine(writerDirectoryMapping, SourceMappingHelper.Writer), true);
                        File.Copy(Path.Combine(debuggee.SourceRoot, SourceMappingHelper.Main), Path.Combine(rootDirectoryMapping, SourceMappingHelper.Main), true);
                    }

                    runner.RunCommand(launch);

                    this.Comment("Set Breakpoint");

                    SourceBreakpoints writerBreakpoints  = debuggee.Breakpoints(SourceMappingHelper.Writer, 9);
                    SourceBreakpoints managerBreakpoints = debuggee.Breakpoints(SourceMappingHelper.Manager, 8);
                    runner.SetBreakpoints(writerBreakpoints);
                    runner.SetBreakpoints(managerBreakpoints);
                    runner.Expects.StoppedEvent(StoppedReason.Breakpoint).AfterConfigurationDone();

                    using (IThreadInspector threadInspector = runner.GetThreadInspector())
                    {
                        IEnumerator <IFrameInspector> frameEnumerator = threadInspector.Stack.GetEnumerator();

                        // Move to first stack item
                        Assert.True(frameEnumerator.MoveNext());
                        this.Comment(string.Format(CultureInfo.InvariantCulture, "Verify source path for {0}.", SourceMappingHelper.Writer));
                        // Since file is there, lowercase the drive letter
                        ValidateMappingToFrame(SourceMappingHelper.Writer, EnsureDriveLetterLowercase(Path.Combine(writerDirectoryMapping, SourceMappingHelper.Writer)), frameEnumerator.Current, comparison);


                        // Move to second stack item
                        Assert.True(frameEnumerator.MoveNext());
                        this.Comment(string.Format(CultureInfo.InvariantCulture, "Verify source path for {0}.", SourceMappingHelper.Main));
                        // Since file is there, lowercase the drive letter
                        ValidateMappingToFrame(SourceMappingHelper.Main, EnsureDriveLetterLowercase(Path.Combine(rootDirectoryMapping, SourceMappingHelper.Main)), frameEnumerator.Current, comparison);
                    }
                    runner.Expects.StoppedEvent(StoppedReason.Breakpoint).AfterContinue();

                    using (IThreadInspector threadInspector = runner.GetThreadInspector())
                    {
                        IEnumerator <IFrameInspector> frameEnumerator = threadInspector.Stack.GetEnumerator();

                        // Move to first stack item
                        Assert.True(frameEnumerator.MoveNext());
                        this.Comment(string.Format(CultureInfo.InvariantCulture, "Verify source path for {0}.", SourceMappingHelper.Manager));
                        // Since file is not there, keep what was passed in
                        ValidateMappingToFrame(SourceMappingHelper.Manager, EnsureDriveLetterLowercase(Path.Combine(mgrDirectoryMapping, SourceMappingHelper.Manager)), frameEnumerator.Current, comparison);

                        // Move to second stack item
                        Assert.True(frameEnumerator.MoveNext());
                        this.Comment(string.Format(CultureInfo.InvariantCulture, "Verify source path for {0}.", SourceMappingHelper.Main));
                        // Since file is there, lowercase the drive letter
                        ValidateMappingToFrame(SourceMappingHelper.Main, EnsureDriveLetterLowercase(Path.Combine(rootDirectoryMapping, SourceMappingHelper.Main)), frameEnumerator.Current, comparison);
                    }

                    writerBreakpoints.Remove(9);
                    managerBreakpoints.Remove(8);
                    runner.SetBreakpoints(writerBreakpoints);
                    runner.SetBreakpoints(managerBreakpoints);

                    this.Comment("Continue to end");

                    runner.Expects.TerminatedEvent().AfterContinue();
                    runner.DisconnectAndVerify();
                }
                finally
                {
                    if (PlatformUtilities.IsWindows)
                    {
                        foreach (var dir in sourceMappings.Values)
                        {
                            if (Directory.Exists(dir))
                            {
                                Directory.Delete(dir, recursive: true);
                            }
                        }
                    }
                }
            }
        }
Example #25
0
        public void ExecutionStepRecursiveCall(ITestSettings settings)
        {
            this.TestPurpose("Verify steps should work when debugging recursive call");
            this.WriteSettings(settings);

            this.Comment("Open the kitchen sink debuggee for execution tests.");
            IDebuggee debuggee = SinkHelper.Open(this, settings.CompilerSettings, DebuggeeMonikers.KitchenSink.Execution);

            using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
            {
                this.Comment("Configure launch");
                runner.Launch(settings.DebuggerSettings, debuggee, "-fCalling");

                this.Comment("Set initial function breakpoints");
                FunctionBreakpoints funcBp = new FunctionBreakpoints("Calling::CoreRun()");
                runner.SetFunctionBreakpoints(funcBp);

                this.Comment("Launch and run until hit function breakpoint in the entry of calling");
                runner.ExpectBreakpointAndStepToTarget(SinkHelper.Calling, startLine: 47, targetLine: 48).AfterConfigurationDone();

                this.Comment("Step over to go to the entry of recursive call");
                runner.Expects.HitStepEvent(SinkHelper.Calling, 49).AfterStepOver();

                this.Comment("Step in the recursive call");
                runner.ExpectStepAndStepToTarget(SinkHelper.Calling, startLine: 25, targetLine: 26).AfterStepIn();

                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    this.Comment("Set count = 2");
                    IFrameInspector currentFrame = threadInspector.Stack.First();
                    currentFrame.GetVariable("count").Value = "2";

                    this.Comment("Verify there is only one 'recursiveCall' frames");
                    threadInspector.AssertStackFrameNames(true, "recursiveCall.*", "Calling::CoreRun.*", "Feature::Run.*", "main.*");
                }

                this.Comment("Step over and then step in the recursive call once again");
                runner.Expects.HitStepEvent(SinkHelper.Calling, 29).AfterStepOver();
                runner.ExpectStepAndStepToTarget(SinkHelper.Calling, startLine: 25, targetLine: 26).AfterStepIn();

                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    this.Comment("Verify there are two 'recursiveCall' frames");
                    threadInspector.AssertStackFrameNames(true, "recursiveCall.*", "recursiveCall.*", "Calling::CoreRun.*", "Feature::Run.*", "main.*");

                    this.Comment("Set a source breakpoint in recursive call");
                    SourceBreakpoints srcBp = debuggee.Breakpoints(SinkHelper.Calling, 26);
                    runner.SetBreakpoints(srcBp);
                }

                this.Comment("Step over the recursive call and hit the source breakpoint");
                runner.Expects.HitStepEvent(SinkHelper.Calling, 29).AfterStepOver();
                runner.Expects.HitBreakpointEvent(SinkHelper.Calling, 26).AfterStepOver();

                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    this.Comment("Verify there are three 'recursiveCall' frames");
                    threadInspector.AssertStackFrameNames(true, "recursiveCall.*", "recursiveCall.*", "recursiveCall.*", "Calling::CoreRun.*", "Feature::Run.*", "main.*");
                }

                this.Comment("Try to step out twice from recursive call");
                runner.ExpectStepAndStepToTarget(SinkHelper.Calling, 29, 30).AfterStepOut();
                runner.ExpectStepAndStepToTarget(SinkHelper.Calling, 29, 30).AfterStepOut();

                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    this.Comment("Verify 'recursiveCall' return back only one frame");
                    threadInspector.AssertStackFrameNames(true, "recursiveCall.*", "Calling::CoreRun.*", "Feature::Run.*", "main.*");
                }

                this.Comment("Step over from recursive call");
                runner.ExpectStepAndStepToTarget(SinkHelper.Calling, 49, 50).AfterStepOver();

                using (IThreadInspector threadInspector = runner.GetThreadInspector())
                {
                    this.Comment("Verify there is not 'recursiveCall' frame");
                    threadInspector.AssertStackFrameNames(true, "Calling::CoreRun.*", "Feature::Run.*", "main.*");
                }

                this.Comment("Verify stop debugging");
                runner.DisconnectAndVerify();
            }
        }
Example #26
0
        public void MapSpecificFile(ITestSettings settings)
        {
            this.TestPurpose("Validate Specific File Mapping.");

            this.WriteSettings(settings);

            IDebuggee debuggee = SourceMappingHelper.Open(this, settings.CompilerSettings, DebuggeeMonikers.SourceMapping.Default);

            // VsDbg is case insensitive on Windows so sometimes stackframe file names might all be lowercase
            StringComparison comparison = settings.DebuggerSettings.DebuggerType == SupportedDebugger.VsDbg ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;

            using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
            {
                this.Comment("Configure");
                LaunchCommand launch = new LaunchCommand(settings.DebuggerSettings, debuggee.OutputPath, false);

                launch.Args.externalConsole = false;

                this.Comment("Setting up Source File Mappings");

                Dictionary <string, string> sourceMappings = new Dictionary <string, string>();
                string pathRoot = Path.GetPathRoot(debuggee.SourceRoot);

                string sourceFileMapping  = Path.Combine(pathRoot, Path.GetRandomFileName(), SourceMappingHelper.Writer);
                string compileFileMapping = Path.Combine(debuggee.SourceRoot, SourceMappingHelper.WriterFolder, SourceMappingHelper.Writer);

                if (PlatformUtilities.IsWindows)
                {
                    // Move file to the location
                    Directory.CreateDirectory(Path.GetDirectoryName(sourceFileMapping));
                    File.Copy(compileFileMapping, sourceFileMapping, true);
                }

                // Drive letter should be lowercase
                sourceMappings.Add(compileFileMapping, sourceFileMapping);

                launch.Args.sourceFileMap = sourceMappings;
                try
                {
                    runner.RunCommand(launch);

                    this.Comment("Set Breakpoint");

                    SourceBreakpoints writerBreakpoints = debuggee.Breakpoints(SourceMappingHelper.Writer, 9);
                    runner.SetBreakpoints(writerBreakpoints);
                    runner.Expects.StoppedEvent(StoppedReason.Breakpoint).AfterConfigurationDone();

                    using (IThreadInspector threadInspector = runner.GetThreadInspector())
                    {
                        IEnumerator <IFrameInspector> frameEnumerator = threadInspector.Stack.GetEnumerator();

                        // Move to first stack item
                        Assert.True(frameEnumerator.MoveNext());
                        this.Comment("Verify path is changed for writer.cpp frame");
                        ValidateMappingToFrame(SourceMappingHelper.Writer, EnsureDriveLetterLowercase(sourceFileMapping), frameEnumerator.Current, comparison);

                        // Move to second stack item
                        Assert.True(frameEnumerator.MoveNext());
                        this.Comment("Verify path is not changed for main.cpp frame.");
                        ValidateMappingToFrame(SourceMappingHelper.Main, EnsureDriveLetterLowercase(Path.Combine(debuggee.SourceRoot, SourceMappingHelper.Main)), frameEnumerator.Current, comparison);

                        writerBreakpoints.Remove(9);
                        runner.SetBreakpoints(writerBreakpoints);
                        this.Comment("Continue to end");

                        runner.Expects.TerminatedEvent().AfterContinue();
                        runner.DisconnectAndVerify();
                    }
                }
                finally
                {
                    if (PlatformUtilities.IsWindows)
                    {
                        // Cleanup the directory
                        if (Directory.Exists(Path.GetDirectoryName(sourceFileMapping)))
                        {
                            Directory.Delete(Path.GetDirectoryName(sourceFileMapping), true);
                        }
                    }
                }
            }
        }
Example #27
0
        public void ThreadingBasic(ITestSettings settings)
        {
            this.TestPurpose("Test basic multithreading scenario.");
            this.WriteSettings(settings);

            IDebuggee debuggee = SinkHelper.Open(this, settings.CompilerSettings, DebuggeeMonikers.KitchenSink.Threading);

            using (IDebuggerRunner runner = CreateDebugAdapterRunner(settings))
            {
                this.Comment("Launching debuggee. Run until multiple threads are running.");
                runner.Launch(settings.DebuggerSettings, debuggee, "-fThreading");
                runner.SetBreakpoints(debuggee.Breakpoints(SinkHelper.Threading, 37));

                runner.Expects.HitBreakpointEvent()
                .AfterConfigurationDone();

                IEnumerable <IThreadInfo> threads    = runner.GetThreads();
                List <string>             loopCounts = new List <string>();

                this.Comment("Inspect threads and find 'loopCount' variable on each worker thread.");
                this.WriteLine("Threads:");
                foreach (var threadInfo in threads)
                {
                    IThreadInspector threadInspector = threadInfo.GetThreadInspector();

                    // Don't look at main thread, just workers
                    if (threadInspector.ThreadId == runner.StoppedThreadId)
                    {
                        continue;
                    }

                    this.Comment("Thread '{0}', Id: {1}".FormatInvariantWithArgs(threadInfo.Name, threadInspector.ThreadId));
                    IFrameInspector threadLoopFrame = threadInspector.Stack.FirstOrDefault(s => s.Name.Contains("ThreadLoop"));

                    // Fail the test if the ThreadLoop frame could not be found
                    if (threadLoopFrame == null)
                    {
                        this.WriteLine("This thread's stack did not contain a frame with 'ThreadLoop'");
                        this.WriteLine("Stack Trace:");
                        foreach (var frame in threadInspector.Stack)
                        {
                            this.WriteLine(frame.Name);
                        }
                        continue;
                    }

                    string variables = threadLoopFrame.Variables.ToReadableString();
                    this.WriteLine("Variables in 'ThreadLoop' frame:");
                    this.WriteLine(variables);

                    // Put the different loopCounts in a list, so they can be verified order agnostic
                    string loopCountValue = threadLoopFrame.GetVariable("loopCount").Value;
                    this.WriteLine("loopCount = {0}", loopCountValue);
                    loopCounts.Add(loopCountValue);
                }

                //Verify all the worker threads were observed
                Assert.True(loopCounts.Contains("0"), "Could not find thread with loop count 0");
                Assert.True(loopCounts.Contains("1"), "Could not find thread with loop count 1");
                Assert.True(loopCounts.Contains("2"), "Could not find thread with loop count 2");
                Assert.True(loopCounts.Contains("3"), "Could not find thread with loop count 3");
                Assert.True(4 == loopCounts.Count, "Expected to find 4 threads, but found " + loopCounts.Count.ToString(CultureInfo.InvariantCulture));

                this.Comment("Run to end.");
                runner.Expects.TerminatedEvent().AfterContinue();

                runner.DisconnectAndVerify();
            }
        }