internal NodeThread(NodeDebugger process, int identity, bool isWorkerThread) { _process = process; _identity = identity; _isWorkerThread = isWorkerThread; Name = "main thread"; }
private void StartAndAttachDebugger(string file, string nodePath, bool startBrowser) { // start the node process var workingDir = _project.GetWorkingDirectory(); var url = GetFullUrl(); var env = GetEnvironmentVariablesString(url); var interpreterOptions = _project.GetProjectProperty(NodeProjectProperty.NodeExeArguments); var debugOptions = this.GetDebugOptions(); var script = GetFullArguments(file, includeNodeArgs: false); var process = NodeDebugger.StartNodeProcessWithInspect(exe: nodePath, script: script, dir: workingDir, env: env, interpreterOptions: interpreterOptions, debugOptions: debugOptions); process.Start(); // setup debug info and attach var debugUri = $"http://127.0.0.1:{process.DebuggerPort}"; var dbgInfo = new VsDebugTargetInfo4(); dbgInfo.dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_AlreadyRunning; dbgInfo.LaunchFlags = (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd; dbgInfo.guidLaunchDebugEngine = WebkitDebuggerGuid; dbgInfo.dwDebugEngineCount = 1; var enginesPtr = MarshalDebugEngines(new[] { WebkitDebuggerGuid }); dbgInfo.pDebugEngines = enginesPtr; dbgInfo.guidPortSupplier = WebkitPortSupplierGuid; dbgInfo.bstrPortName = debugUri; dbgInfo.fSendToOutputWindow = 0; // we connect through a URI, so no need to set the process, // we need to set the process id to '1' so the debugger is able to attach dbgInfo.bstrExe = $"\01"; AttachDebugger(dbgInfo); if (startBrowser) { Uri uri = null; if (!String.IsNullOrWhiteSpace(url)) { uri = new Uri(url); } if (uri != null) { OnPortOpenedHandler.CreateHandler( uri.Port, shortCircuitPredicate: () => process.HasExited, action: () => { VsShellUtilities.OpenBrowser(url, (uint)__VSOSPFLAGS.OSP_LaunchNewBrowser); } ); } } }
public NodeBreakpoint(NodeDebugger process, FilePosition target, bool enabled, BreakOn breakOn, string condition) { this._process = process; this._target = target; this._enabled = enabled; this._breakOn = breakOn; this._condition = condition; }
private static Dictionary <int, NodeModule> GetScripts(NodeDebugger debugger, JsonArray references) { var scripts = new Dictionary <int, NodeModule>(references.Count); for (int i = 0; i < references.Count; i++) { JsonValue reference = references[i]; var scriptId = reference.GetValue <int>("id"); var filename = reference.GetValue <string>("name"); scripts.Add(scriptId, new NodeModule(debugger, scriptId, filename)); } return(scripts); }
internal static NodeBreakpoint AddBreakPoint( NodeDebugger newproc, string fileName, int line, int column, bool enabled = true, BreakOn breakOn = new BreakOn(), string condition = "" ) { NodeBreakpoint breakPoint = newproc.AddBreakpoint(fileName, line, column, enabled, breakOn, condition); breakPoint.BindAsync().WaitAndUnwrapExceptions(); return(breakPoint); }
void DrawLayer(NeuralLayer neuralLayer, List <NodeRenderer> debuggerLayer, ref float leftMargin, float topMargin) { float verticalShift = 0; if (neuralLayer.nodes.Count % 2 == 0) { topMargin += 25; } for (int i = 0; i < neuralLayer.nodes.Count; i++) { GameObject node = new GameObject("node" + i.ToString()); NodeRenderer nodeRenderer = new NodeRenderer(node.AddComponent <Image>() as Image); nodeRenderer.parent = new GameObject("node" + i.ToString()); NodeDebugger nodeDebugger = nodeRenderer.parent.AddComponent <NodeDebugger>(); nodeDebugger.Init(neuralLayer.nodes[i]); nodeRenderer.parent.transform.SetParent(targetCanvas.transform); node.transform.SetParent(nodeRenderer.parent.transform); nodeRenderer.nodeImage.sprite = nodeTexture; nodeRenderer.nodeImage.rectTransform.sizeDelta = new Vector2(nodeSize, nodeSize); float targetCanvasHeight = targetCanvas.gameObject.GetComponent <RectTransform>().rect.height; float v = i % 2 == 0 ? -verticalShift : verticalShift; nodeRenderer.nodeImage.rectTransform.position = new Vector2(leftMargin, targetCanvasHeight - topMargin + v); nodeRenderer.nodeImage.color = new Color32(48, 112, 181, 255); debuggerLayer.Add(nodeRenderer); if (i % 2 == 0) { verticalShift += 60; } SetupTextLabel(node, nodeRenderer); } leftMargin += 100; }
private void StartAndAttachDebugger(string file, string nodePath) { // start the node process var workingDir = _project.GetWorkingDirectory(); var url = GetFullUrl(); var env = GetEnvironmentVariablesString(url); var interpreterOptions = _project.GetProjectProperty(NodeProjectProperty.NodeExeArguments); var debugOptions = this.GetDebugOptions(); var script = GetFullArguments(file, includeNodeArgs: false); var process = NodeDebugger.StartNodeProcessWithInspect(exe: nodePath, script: script, dir: workingDir, env: env, interpreterOptions: interpreterOptions, debugOptions: debugOptions); process.Start(); // setup debug info and attach var debugUri = $"http://127.0.0.1:{process.DebuggerPort}"; var dbgInfo = new VsDebugTargetInfo4(); dbgInfo.dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_AlreadyRunning; dbgInfo.LaunchFlags = (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd; dbgInfo.guidLaunchDebugEngine = WebkitDebuggerGuid; dbgInfo.dwDebugEngineCount = 1; var enginesPtr = MarshalDebugEngines(new[] { WebkitDebuggerGuid }); dbgInfo.pDebugEngines = enginesPtr; dbgInfo.guidPortSupplier = WebkitPortSupplierGuid; dbgInfo.bstrPortName = debugUri; dbgInfo.fSendToOutputWindow = 0; // we connect through a URI, so no need to set the process, // we need to set the process id to '1' so the debugger is able to attach dbgInfo.bstrExe = $"\01"; AttachDebugger(dbgInfo); }
internal NodeDebugger AttachToNodeProcess( Action <NodeDebugger> onProcessCreated = null, Action <NodeDebugger, NodeThread> onLoadComplete = null, string hostName = "localhost", ushort portNumber = 5858, int id = 0, bool resumeOnProcessLoad = false) { // Load process AutoResetEvent processLoaded = new AutoResetEvent(false); var process = new NodeDebugger(new UriBuilder { Scheme = "tcp", Host = hostName, Port = portNumber }.Uri, id); if (onProcessCreated != null) { onProcessCreated(process); } process.ProcessLoaded += (sender, args) => { // Invoke onLoadComplete delegate, if requested if (onLoadComplete != null) { onLoadComplete(process, args.Thread); } processLoaded.Set(); }; process.StartListening(); AssertWaited(processLoaded); // Resume, if requested if (resumeOnProcessLoad) { process.Resume(); } return(process); }
private void AttachEvents(NodeDebugger process) { process.ProcessLoaded += OnProcessLoaded; process.ModuleLoaded += OnModuleLoaded; process.ThreadCreated += OnThreadCreated; process.BreakpointBound += OnBreakpointBound; process.BreakpointUnbound += OnBreakpointUnbound; process.BreakpointBindFailure += OnBreakpointBindFailure; process.BreakpointHit += OnBreakpointHit; process.AsyncBreakComplete += OnAsyncBreakComplete; process.ExceptionRaised += OnExceptionRaised; process.ProcessExited += OnProcessExited; process.EntryPointHit += OnEntryPointHit; process.StepComplete += OnStepComplete; process.ThreadExited += OnThreadExited; process.DebuggerOutput += OnDebuggerOutput; // Subscribe to document changes if Edit and Continue is enabled. var shell = (IVsShell)Package.GetGlobalService(typeof(SVsShell)); if (shell != null) { // The debug engine is loaded by VS separately from the main NTVS package, so we // need to make sure that the package is also loaded before querying its options. var packageGuid = new Guid(Guids.NodejsPackageString); IVsPackage package; shell.LoadPackage(ref packageGuid, out package); var nodejsPackage = package as NodejsPackage; if (nodejsPackage != null) { _trackFileChanges = nodejsPackage.GeneralOptionsPage.EditAndContinue; if (_trackFileChanges) { _documentEvents = nodejsPackage.DTE.Events.DocumentEvents; _documentEvents.DocumentSaved += OnDocumentSaved; } } } process.StartListening(); }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { LiveLogger.WriteLine("AD7Engine LaunchSuspended Called with flags '{0}' ({1})", launchFlags, GetHashCode()); AssertMainThread(); Debug.Assert(_events == null); Debug.Assert(_process == null); Debug.Assert(_ad7ProgramId == Guid.Empty); _events = ad7Callback; var debugOptions = NodeDebugOptions.None; List<string[]> dirMapping = null; string interpreterOptions = null; ushort? debugPort = null; if (options != null) { var splitOptions = SplitOptions(options); foreach (var optionSetting in splitOptions) { var setting = optionSetting.Split(new[] { '=' }, 2); if (setting.Length == 2) { setting[1] = HttpUtility.UrlDecode(setting[1]); switch (setting[0]) { case WaitOnAbnormalExitSetting: bool value; if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= NodeDebugOptions.WaitOnAbnormalExit; } break; case WaitOnNormalExitSetting: if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= NodeDebugOptions.WaitOnNormalExit; } break; case RedirectOutputSetting: if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= NodeDebugOptions.RedirectOutput; } break; case DirMappingSetting: string[] dirs = setting[1].Split('|'); if (dirs.Length == 2) { if (dirMapping == null) { dirMapping = new List<string[]>(); } LiveLogger.WriteLine(String.Format("Mapping dir {0} to {1}", dirs[0], dirs[1])); dirMapping.Add(dirs); } break; case InterpreterOptions: interpreterOptions = setting[1]; break; case WebBrowserUrl: _webBrowserUrl = setting[1]; break; case DebuggerPort: ushort dbgPortTmp; if (ushort.TryParse(setting[1], out dbgPortTmp)) { debugPort = dbgPortTmp; } break; } } } } _process = new NodeDebugger( exe, args, dir, env, interpreterOptions, debugOptions, debugPort ); _process.Start(false); AttachEvents(_process); var adProcessId = new AD_PROCESS_ID(); adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = (uint)_process.Id; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); LiveLogger.WriteLine("AD7Engine LaunchSuspended returning S_OK"); Debug.Assert(process != null); Debug.Assert(!_process.HasExited); return VSConstants.S_OK; }
// Called by the SDM to indicate that a synchronous debug event, previously sent by the DE to the SDM, // was received and processed. The only event we send in this fashion is Program Destroy. // It responds to that event by shutting down the engine. int IDebugEngine2.ContinueFromSynchronousEvent(IDebugEvent2 eventObject) { DebugWriteCommand("ContinueFromSynchronousEvent"); AssertMainThread(); if (eventObject is AD7ProgramDestroyEvent) { var debuggedProcess = _process; _events = null; _process = null; _ad7ProgramId = Guid.Empty; _threads.Clear(); _modules.Clear(); if (_trackFileChanges) { _documentEvents.DocumentSaved -= OnDocumentSaved; _documentEvents = null; } debuggedProcess.Close(); } else { Debug.Fail("Unknown synchronous event"); } return VSConstants.S_OK; }
// Attach the debug engine to a program. int IDebugEngine2.Attach(IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason) { DebugWriteCommand("Attach"); AssertMainThread(); Debug.Assert(_ad7ProgramId == Guid.Empty); if (celtPrograms != 1) { Debug.Fail("Node debugging only supports one program in a process"); throw new ArgumentException(); } int processId = EngineUtils.GetProcessId(rgpPrograms[0]); if (processId == 0) { // engine only supports system processes LiveLogger.WriteLine("AD7Engine failed to get process id during attach"); return VSConstants.E_NOTIMPL; } EngineUtils.RequireOk(rgpPrograms[0].GetProgramId(out _ad7ProgramId)); // Attach can either be called to attach to a new process, or to complete an attach // to a launched process if (_process == null) { _events = ad7Callback; var program = (NodeRemoteDebugProgram)rgpPrograms[0]; var process = program.DebugProcess; var uri = process.DebugPort.Uri; _process = new NodeDebugger(uri, process.Id); // We only need to do fuzzy comparisons when debugging remotely if (!uri.IsLoopback) { _process.IsRemote = true; _process.FileNameMapper = new FuzzyLogicFileNameMapper(EnumerateSolutionFiles()); } AttachEvents(_process); _attached = true; } else { if (processId != _process.Id) { Debug.Fail("Asked to attach to a process while we are debugging"); return VSConstants.E_FAIL; } } lock (_syncLock) { _sdmAttached = true; HandleLoadComplete(); } LiveLogger.WriteLine("AD7Engine Attach returning S_OK"); return VSConstants.S_OK; }
private void DetachEvents(NodeDebugger process) { process.ProcessLoaded -= OnProcessLoaded; process.ModuleLoaded -= OnModuleLoaded; process.ThreadCreated -= OnThreadCreated; process.BreakpointBound -= OnBreakpointBound; process.BreakpointUnbound -= OnBreakpointUnbound; process.BreakpointBindFailure -= OnBreakpointBindFailure; process.BreakpointHit -= OnBreakpointHit; process.AsyncBreakComplete -= OnAsyncBreakComplete; process.ExceptionRaised -= OnExceptionRaised; process.ProcessExited -= OnProcessExited; process.EntryPointHit -= OnEntryPointHit; process.StepComplete -= OnStepComplete; process.ThreadExited -= OnThreadExited; process.DebuggerOutput -= OnDebuggerOutput; if (_documentEvents != null) { _documentEvents.DocumentSaved -= OnDocumentSaved; } }
private static Dictionary<int, NodeModule> GetScripts(NodeDebugger debugger, JsonArray references) { var scripts = new Dictionary<int, NodeModule>(references.Count); for (int i = 0; i < references.Count; i++) { JsonValue reference = references[i]; var scriptId = reference.GetValue<int>("id"); var filename = reference.GetValue<string>("name"); scripts.Add(scriptId, new NodeModule(debugger, scriptId, filename)); } return scripts; }
internal NodeDebugger DebugProcess( string filename, Action <NodeDebugger> onProcessCreated = null, Action <NodeDebugger, NodeThread> onLoadComplete = null, string interpreterOptions = null, NodeDebugOptions debugOptions = NodeDebugOptions.None, string cwd = null, string arguments = "", bool resumeOnProcessLoad = true ) { if (!Path.IsPathRooted(filename)) { filename = DebuggerTestPath + filename; } string fullPath = Path.GetFullPath(filename); string dir = cwd ?? Path.GetFullPath(Path.GetDirectoryName(filename)); if (!String.IsNullOrEmpty(arguments)) { arguments = "\"" + fullPath + "\" " + arguments; } else { arguments = "\"" + fullPath + "\""; } // Load process AutoResetEvent processLoaded = new AutoResetEvent(false); Assert.IsNotNull(Nodejs.NodeExePath, "Node isn't installed"); NodeDebugger process = new NodeDebugger( Nodejs.NodeExePath, arguments, dir, null, interpreterOptions, debugOptions, null, createNodeWindow: false); if (onProcessCreated != null) { onProcessCreated(process); } process.ProcessLoaded += (sender, args) => { // Invoke onLoadComplete delegate, if requested if (onLoadComplete != null) { onLoadComplete(process, args.Thread); } processLoaded.Set(); }; process.Start(); AssertWaited(processLoaded); // Resume, if requested if (resumeOnProcessLoad) { process.Resume(); } return(process); }
internal void TestDebuggerSteps( NodeDebugger process, NodeThread thread, string filename, IEnumerable <TestStep> steps, ExceptionHitTreatment?defaultExceptionTreatment = null, ICollection <KeyValuePair <string, ExceptionHitTreatment> > exceptionTreatments = null, bool waitForExit = false ) { if (!Path.IsPathRooted(filename)) { filename = DebuggerTestPath + filename; } // Since Alpha does not support break on unhandled, and the commonly used Express module has handled SyntaxError exceptions, // for alpha we have SyntaxErrors set to BreakNever by default. Here we set it to BreakAlways so unit tests can run // assuming BreakAlways is the default. // TODO: Remove once exception treatment is updated for just my code support when it is added after Alpha process.SetExceptionTreatment(null, CollectExceptionTreatments(ExceptionHitTreatment.BreakAlways, "SyntaxError")); if (defaultExceptionTreatment != null || exceptionTreatments != null) { process.SetExceptionTreatment(defaultExceptionTreatment, exceptionTreatments); } Dictionary <Breakpoint, NodeBreakpoint> breakpoints = new Dictionary <Breakpoint, NodeBreakpoint>(); AutoResetEvent entryPointHit = new AutoResetEvent(false); process.EntryPointHit += (sender, e) => { Console.WriteLine("EntryPointHit"); Assert.AreEqual(e.Thread, thread); entryPointHit.Set(); }; AutoResetEvent breakpointBound = new AutoResetEvent(false); process.BreakpointBound += (sender, e) => { Console.WriteLine("BreakpointBound {0} {1}", e.BreakpointBinding.Position.FileName, e.BreakpointBinding.Position.Line); breakpointBound.Set(); }; AutoResetEvent breakpointUnbound = new AutoResetEvent(false); process.BreakpointUnbound += (sender, e) => { Console.WriteLine("BreakpointUnbound"); breakpointUnbound.Set(); }; AutoResetEvent breakpointBindFailure = new AutoResetEvent(false); process.BreakpointBindFailure += (sender, e) => { Console.WriteLine("BreakpointBindFailure"); breakpointBindFailure.Set(); }; AutoResetEvent breakpointHit = new AutoResetEvent(false); process.BreakpointHit += (sender, e) => { Console.WriteLine("BreakpointHit {0}", e.BreakpointBinding.Target.Line); Assert.AreEqual(e.Thread, thread); Assert.AreEqual(e.BreakpointBinding.Target.Line, thread.Frames.First().Line); breakpointHit.Set(); }; AutoResetEvent stepComplete = new AutoResetEvent(false); process.StepComplete += (sender, e) => { Console.WriteLine("StepComplete"); Assert.AreEqual(e.Thread, thread); stepComplete.Set(); }; AutoResetEvent exceptionRaised = new AutoResetEvent(false); NodeException exception = null; process.ExceptionRaised += (sender, e) => { Console.WriteLine("ExceptionRaised"); Assert.AreEqual(e.Thread, thread); exception = e.Exception; exceptionRaised.Set(); }; AutoResetEvent processExited = new AutoResetEvent(false); int exitCode = 0; process.ProcessExited += (sender, e) => { Console.WriteLine("ProcessExited {0}", e.ExitCode); exitCode = e.ExitCode; processExited.Set(); }; Console.WriteLine("-----------------------------------------"); Console.WriteLine("Begin debugger step test"); foreach (var step in steps) { Console.WriteLine("Step: {0}", step._action); Assert.IsFalse( ((step._expectedEntryPointHit != null ? 1 : 0) + (step._expectedBreakpointHit != null ? 1 : 0) + (step._expectedStepComplete != null ? 1 : 0) + (step._expectedExceptionRaised != null ? 1 : 0)) > 1); bool wait = false; NodeBreakpoint nodeBreakpoint; switch (step._action) { case TestAction.None: break; case TestAction.Wait: wait = true; break; case TestAction.ResumeThread: thread.Resume(); wait = true; break; case TestAction.ResumeProcess: process.Resume(); wait = true; break; case TestAction.StepOver: thread.StepOver(); wait = true; break; case TestAction.StepInto: thread.StepInto(); wait = true; break; case TestAction.StepOut: thread.StepOut(); wait = true; break; case TestAction.AddBreakpoint: string breakpointFileName = step._targetBreakpointFile; if (breakpointFileName != null) { if (!step._builtin && !Path.IsPathRooted(breakpointFileName)) { breakpointFileName = DebuggerTestPath + breakpointFileName; } } else { breakpointFileName = filename; } int breakpointLine = step._targetBreakpoint.Value; int breakpointColumn = step._targetBreakpointColumn.HasValue ? step._targetBreakpointColumn.Value : 0; Breakpoint breakpoint = new Breakpoint(breakpointFileName, breakpointLine, breakpointColumn); Assert.IsFalse(breakpoints.TryGetValue(breakpoint, out nodeBreakpoint)); breakpoints[breakpoint] = AddBreakPoint( process, breakpointFileName, breakpointLine, breakpointColumn, step._enabled ?? true, step._breakOn ?? new BreakOn(), step._condition ); if (step._expectFailure) { AssertWaited(breakpointBindFailure); AssertNotSet(breakpointBound); breakpointBindFailure.Reset(); } else { AssertWaited(breakpointBound); AssertNotSet(breakpointBindFailure); breakpointBound.Reset(); } break; case TestAction.RemoveBreakpoint: breakpointFileName = step._targetBreakpointFile ?? filename; breakpointLine = step._targetBreakpoint.Value; breakpointColumn = step._targetBreakpointColumn.HasValue ? step._targetBreakpointColumn.Value : 0; breakpoint = new Breakpoint(breakpointFileName, breakpointLine, breakpointColumn); breakpoints[breakpoint].Remove().WaitAndUnwrapExceptions(); breakpoints.Remove(breakpoint); AssertWaited(breakpointUnbound); breakpointUnbound.Reset(); break; case TestAction.UpdateBreakpoint: breakpointFileName = step._targetBreakpointFile ?? filename; breakpointLine = step._targetBreakpoint.Value; breakpointColumn = step._targetBreakpointColumn.HasValue ? step._targetBreakpointColumn.Value : 0; breakpoint = new Breakpoint(breakpointFileName, breakpointLine, breakpointColumn); nodeBreakpoint = breakpoints[breakpoint]; foreach (var breakpointBinding in nodeBreakpoint.GetBindings()) { if (step._hitCount != null) { Assert.IsTrue(breakpointBinding.SetHitCountAsync(step._hitCount.Value).WaitAndUnwrapExceptions()); } if (step._enabled != null) { Assert.IsTrue(breakpointBinding.SetEnabledAsync(step._enabled.Value).WaitAndUnwrapExceptions()); } if (step._breakOn != null) { Assert.IsTrue(breakpointBinding.SetBreakOnAsync(step._breakOn.Value).WaitAndUnwrapExceptions()); } if (step._condition != null) { Assert.IsTrue(breakpointBinding.SetConditionAsync(step._condition).WaitAndUnwrapExceptions()); } } break; case TestAction.KillProcess: process.Terminate(); break; case TestAction.Detach: process.Detach(); break; } if (wait) { if (step._expectedEntryPointHit != null) { AssertWaited(entryPointHit); AssertNotSet(breakpointHit); AssertNotSet(stepComplete); AssertNotSet(exceptionRaised); Assert.IsNull(exception); entryPointHit.Reset(); } else if (step._expectedBreakpointHit != null) { if (step._expectReBind) { AssertWaited(breakpointUnbound); AssertWaited(breakpointBound); breakpointUnbound.Reset(); breakpointBound.Reset(); } AssertWaited(breakpointHit); AssertNotSet(entryPointHit); AssertNotSet(stepComplete); AssertNotSet(exceptionRaised); Assert.IsNull(exception); breakpointHit.Reset(); } else if (step._expectedStepComplete != null) { AssertWaited(stepComplete); AssertNotSet(entryPointHit); AssertNotSet(breakpointHit); AssertNotSet(exceptionRaised); Assert.IsNull(exception); stepComplete.Reset(); } else if (step._expectedExceptionRaised != null) { AssertWaited(exceptionRaised); AssertNotSet(entryPointHit); AssertNotSet(breakpointHit); AssertNotSet(stepComplete); exceptionRaised.Reset(); } else { AssertNotSet(entryPointHit); AssertNotSet(breakpointHit); AssertNotSet(stepComplete); AssertNotSet(exceptionRaised); Assert.IsNull(exception); } } if (step._expectedEntryPointHit != null) { Assert.AreEqual(step._expectedEntryPointHit.Value, thread.Frames.First().Line); } else if (step._expectedBreakpointHit != null) { Assert.AreEqual(step._expectedBreakpointHit.Value, thread.Frames.First().Line); } else if (step._expectedStepComplete != null) { Assert.AreEqual(step._expectedStepComplete.Value, thread.Frames.First().Line); } else if (step._expectedExceptionRaised != null) { Assert.AreEqual(step._expectedExceptionRaised.TypeName, exception.TypeName); Assert.AreEqual(step._expectedExceptionRaised.Description, exception.Description); if (step._expectedExceptionRaised.LineNo != null) { Assert.AreEqual(step._expectedExceptionRaised.LineNo.Value, thread.Frames[0].Line); } exception = null; } var expectedBreakFile = step._expectedBreakFile; if (expectedBreakFile != null) { if (!step._builtin && !Path.IsPathRooted(expectedBreakFile)) { expectedBreakFile = DebuggerTestPath + expectedBreakFile; } Assert.AreEqual(expectedBreakFile, thread.Frames.First().FileName); } var expectedBreakFunction = step._expectedBreakFunction; if (expectedBreakFunction != null) { Assert.AreEqual(expectedBreakFunction, thread.Frames.First().FunctionName); } if (step._expectedHitCount != null) { string breakpointFileName = step._targetBreakpointFile ?? filename; if (!step._builtin && !Path.IsPathRooted(breakpointFileName)) { breakpointFileName = DebuggerTestPath + breakpointFileName; } int breakpointLine = step._targetBreakpoint.Value; int breakpointColumn = step._targetBreakpointColumn.HasValue ? step._targetBreakpointColumn.Value : 0; var breakpoint = new Breakpoint(breakpointFileName, breakpointLine, breakpointColumn); nodeBreakpoint = breakpoints[breakpoint]; foreach (var breakpointBinding in nodeBreakpoint.GetBindings()) { Assert.AreEqual(step._expectedHitCount.Value, breakpointBinding.GetHitCount()); } } if (step._validation != null) { step._validation(process, thread); } if (step._expectedExitCode != null) { AssertWaited(processExited); Assert.AreEqual(step._expectedExitCode.Value, exitCode); } } if (waitForExit) { process.WaitForExit(10000); } AssertNotSet(entryPointHit); AssertNotSet(breakpointHit); AssertNotSet(stepComplete); AssertNotSet(exceptionRaised); Assert.IsNull(exception); }