private void TestExitCode(PythonDebugger debugger, string filename, int expectedExitCode) { var process = DebugProcess(debugger, filename); bool created = false, exited = false; process.ThreadCreated += (sender, args) => { created = true; }; process.ThreadExited += (sender, args) => { exited = true; }; process.ProcessExited += (sender, args) => { Assert.AreEqual(args.ExitCode, expectedExitCode); }; process.ExceptionRaised += (sender, args) => { process.Resume(); }; process.Start(); process.WaitForExit(); Assert.IsTrue(created); Assert.IsTrue(exited); }
private void TestModuleLoad(PythonDebugger debugger, string filename, params string[] expectedModulesLoaded) { var process = DebugProcess(debugger, filename); List <string> receivedFilenames = new List <string>(); process.ModuleLoaded += (sender, args) => { receivedFilenames.Add(args.Module.Filename); }; process.ExceptionRaised += (sender, args) => { args.Thread.Resume(); }; process.Start(); process.WaitForExit(); Assert.IsTrue(receivedFilenames.Count >= expectedModulesLoaded.Length); var set = new HashSet <string>(); foreach (var received in receivedFilenames) { set.Add(Path.GetFileName(received)); } foreach (var file in expectedModulesLoaded) { Assert.IsTrue(set.Contains(file)); } }
public void TestBreakpointFailed() { var debugger = new PythonDebugger(); PythonThread thread = null; PythonBreakpoint breakPoint = null; var process = DebugProcess(debugger, DebuggerTestPath + "BreakpointTest.py", (newproc, newthread) => { breakPoint = newproc.AddBreakPoint("doesnotexist.py", 1); breakPoint.Add(); thread = newthread; }); bool bindFailed = false; process.BreakpointBindFailed += (sender, args) => { bindFailed = true; Assert.AreEqual(args.Breakpoint, breakPoint); }; process.ExceptionRaised += (sender, args) => { args.Thread.Resume(); }; process.Start(); process.WaitForExit(); Assert.AreEqual(bindFailed, true); }
internal static PythonProcess DebugProcess(this PythonDebugger debugger, PythonVersion version, string filename, Func <PythonProcess, PythonThread, Task> onLoaded = null, bool resumeOnProcessLoaded = true, string interpreterOptions = null, PythonDebugOptions debugOptions = PythonDebugOptions.RedirectOutput, string cwd = null, string arguments = "") { string fullPath = Path.GetFullPath(filename); string dir = cwd ?? Path.GetFullPath(Path.GetDirectoryName(filename)); if (!String.IsNullOrEmpty(arguments)) { arguments = "\"" + fullPath + "\" " + arguments; } else { arguments = "\"" + fullPath + "\""; } var process = debugger.CreateProcess(version.Version, version.InterpreterPath, arguments, dir, "", interpreterOptions, debugOptions); process.DebuggerOutput += (sender, args) => { Console.WriteLine("{0}: {1}", args.Thread?.Id, args.Output); }; process.ProcessLoaded += async(sender, args) => { if (onLoaded != null) { await onLoaded(process, args.Thread); } if (resumeOnProcessLoaded) { await process.ResumeAsync(default(CancellationToken)); } }; return(process); }
private async Task AttachAsync(string filename, int lineNo) { var debugger = new PythonDebugger(); PythonProcess process = debugger.DebugProcess(Version, DebuggerTestPath + filename, null, async(newproc, newthread) => { var breakPoint = newproc.AddBreakpointByFileExtension(lineNo, filename); await breakPoint.AddAsync(TimeoutToken()); }); _processes.Add(process); long?threadAtBreakpoint = null; using (var brkHit = new AutoResetEvent(false)) using (var procExited = new AutoResetEvent(false)) { EventHandler <BreakpointHitEventArgs> breakpointHitHandler = (s, e) => { threadAtBreakpoint = e.Thread.Id; SafeSetEvent(brkHit); }; EventHandler <ProcessExitedEventArgs> processExitedHandler = (s, e) => SafeSetEvent(procExited); process.BreakpointHit += breakpointHitHandler; process.ProcessExited += processExitedHandler; try { await process.StartAsync(); } catch (Win32Exception ex) { _processes.Remove(process); if (ex.HResult == -2147467259 /*0x80004005*/) { Assert.Inconclusive("Required Python interpreter is not installed"); } else { Assert.Fail("Process start failed:\r\n" + ex.ToString()); } } var handles = new[] { brkHit, procExited }; if (WaitHandle.WaitAny(handles, 25000) != 0) { Assert.Fail("Failed to wait on event"); } process.BreakpointHit -= breakpointHitHandler; process.ProcessExited -= processExitedHandler; } await _evaluator.AttachProcessAsync(process, new MockThreadIdMapper()); // AttachProcessAsync calls InitializeAsync which sets the active // thread by using the DTE (which is null in these tests), so we // adjust it to the correct thread where breakpoint was hit. if (threadAtBreakpoint != null) { _evaluator.ChangeActiveThread(threadAtBreakpoint.Value, false); } }
public void TestModuleLoad() { var debugger = new PythonDebugger(); // main file is reported TestModuleLoad(debugger, @"Python.VS.TestData\HelloWorld\Program.py", "Program.py"); // imports are reported TestModuleLoad(debugger, DebuggerTestPath + @"imports_other.py", "imports_other.py", "is_imported.py"); }
private void EvalTest(string filename, int lineNo, string frameName, int frameIndex, EvalResult eval) { var debugger = new PythonDebugger(); PythonThread thread = null; var process = DebugProcess(debugger, DebuggerTestPath + filename, (newproc, newthread) => { var breakPoint = newproc.AddBreakPoint(filename, lineNo); breakPoint.Add(); thread = newthread; }); AutoResetEvent brkHit = new AutoResetEvent(false); process.BreakpointHit += (sender, args) => { brkHit.Set(); }; process.ExceptionRaised += (sender, args) => { args.Thread.Resume(); }; process.Start(); brkHit.WaitOne(); var frames = thread.GetFrames(); PythonEvaluationResult obj = null; string errorMsg; if (eval.IsError) { Assert.IsTrue(!frames[frameIndex].TryParseText(eval.Expression, out errorMsg)); Assert.AreEqual(errorMsg, eval.ExceptionText); } else { Assert.IsTrue(frames[frameIndex].TryParseText(eval.Expression, out errorMsg)); Assert.AreEqual(errorMsg, null); AutoResetEvent textExecuted = new AutoResetEvent(false); Assert.AreEqual(frameName, frames[frameIndex].FunctionName); frames[frameIndex].ExecuteText(eval.Expression, (completion) => { obj = completion; textExecuted.Set(); } ); textExecuted.WaitOne(); eval.Validate(obj); } process.Continue(); process.WaitForExit(); }
public void TestStartup() { var debugger = new PythonDebugger(); // hello world TestExitCode(debugger, @"Python.VS.TestData\HelloWorld\Program.py", 0); // test which calls sys.exit(23) TestExitCode(debugger, DebuggerTestPath + @"SysExit.py", 23); // test which calls raise Exception() TestExitCode(debugger, DebuggerTestPath + @"ExceptionalExit.py", 1); }
private PythonProcess DebugProcess(PythonDebugger debugger, string filename, Action <PythonProcess, PythonThread> onLoaded = null) { string fullPath = Path.GetFullPath(filename); string dir = Path.GetFullPath(Path.GetDirectoryName(filename)); var process = debugger.CreateProcess(Version.Version, Version.Path, "\"" + fullPath + "\"", dir, ""); process.ProcessLoaded += (sender, args) => { if (onLoaded != null) { onLoaded(process, args.Thread); } process.Resume(); }; return(process); }
private void Attach(string filename, int lineNo) { var debugger = new PythonDebugger(); PythonProcess process = debugger.DebugProcess(Version, DebuggerTestPath + filename, (newproc, newthread) => { var breakPoint = newproc.AddBreakPointByFileExtension(lineNo, filename); breakPoint.Add(); _evaluator.AttachProcess(newproc, new MockThreadIdMapper()); }, debugOptions: PythonDebugOptions.CreateNoWindow); _processes.Add(process); using (var brkHit = new AutoResetEvent(false)) using (var procExited = new AutoResetEvent(false)) { EventHandler <BreakpointHitEventArgs> breakpointHitHandler = (s, e) => brkHit.Set(); EventHandler <ProcessExitedEventArgs> processExitedHandler = (s, e) => procExited.Set(); process.BreakpointHit += breakpointHitHandler; process.ProcessExited += processExitedHandler; try { process.Start(); } catch (Win32Exception ex) { _processes.Remove(process); #if DEV11_OR_LATER if (ex.HResult == -2147467259 /*0x80004005*/) { Assert.Inconclusive("Required Python interpreter is not installed"); } else #endif { Assert.Fail("Process start failed:\r\n" + ex.ToString()); } } var handles = new[] { brkHit, procExited }; if (WaitHandle.WaitAny(handles, 25000) != 0) { Assert.Fail("Failed to wait on event"); } process.BreakpointHit -= breakpointHitHandler; process.ProcessExited -= processExitedHandler; } _evaluator.AttachProcess(process, new MockThreadIdMapper()); }
public void TestBreakAllThreads() { var debugger = new PythonDebugger(); PythonThread thread = null; AutoResetEvent loaded = new AutoResetEvent(false); var process = DebugProcess(debugger, DebuggerTestPath + "InfiniteThreads.py", (newproc, newthread) => { loaded.Set(); thread = newthread; }); process.ExceptionRaised += (sender, args) => { args.Thread.Resume(); }; process.Start(); if (!loaded.WaitOne(10000)) { Assert.Fail("Failed to load"); } AutoResetEvent breakComplete = new AutoResetEvent(false); process.AsyncBreakComplete += (sender, args) => { breakComplete.Set(); }; // let loop run for (int i = 0; i < 100; i++) { Thread.Sleep(50); Debug.WriteLine(String.Format("Breaking {0}", i)); process.Break(); if (!breakComplete.WaitOne(10000)) { Console.WriteLine("Failed to break"); } process.Resume(); Debug.WriteLine(String.Format("Resumed {0}", i)); } process.Terminate(); }
internal async Task <PythonThread> RunAndBreakAsync(string filename, int lineNo, string breakFilename = null, string arguments = "", Action processLoaded = null, PythonDebugOptions debugOptions = PythonDebugOptions.RedirectOutput) { PythonThread thread; var debugger = new PythonDebugger(); thread = null; PythonProcess process = DebugProcess(debugger, DebuggerTestPath + filename, async(newproc, newthread) => { var breakPoint = newproc.AddBreakpointByFileExtension(lineNo, breakFilename ?? filename); await breakPoint.AddAsync(TimeoutToken()); thread = newthread; processLoaded?.Invoke(); }, arguments: arguments, debugOptions: debugOptions); AutoResetEvent brkHit = new AutoResetEvent(false); process.BreakpointHit += (sender, args) => { thread = args.Thread; brkHit.Set(); }; bool ready = false; try { await process.StartAsync(); AssertWaited(brkHit); ready = true; } finally { if (!ready) { process.Terminate(); } } return(thread); }
private void TestException(PythonDebugger debugger, string filename, bool resumeProcess, params ExceptionInfo[] exceptions) { var process = DebugProcess(debugger, filename); bool loaded = false; process.ProcessLoaded += (sender, args) => { loaded = true; }; int curException = 0; process.ExceptionRaised += (sender, args) => { // V30 raises an exception as the process shuts down. if (loaded && ((Version.Version == PythonLanguageVersion.V30 && curException < exceptions.Length) || Version.Version != PythonLanguageVersion.V30)) { Assert.AreEqual(args.Exception.TypeName, exceptions[curException].TypeName); // http://ironpython.codeplex.com/workitem/30130 if (GetType() != typeof(DebuggerTestsIpy)) { Assert.IsTrue(args.Exception.Description.IndexOf("line " + exceptions[curException].LineNumber) != -1); } Assert.IsTrue(args.Exception.Description.IndexOf(filename) != -1); curException++; if (resumeProcess) { process.Resume(); } else { args.Thread.Resume(); } } else { args.Thread.Resume(); } }; process.Start(); process.WaitForExit(); Assert.AreEqual(exceptions.Length, curException); }
public void TestBreakAll() { var debugger = new PythonDebugger(); PythonThread thread = null; AutoResetEvent loaded = new AutoResetEvent(false); var process = DebugProcess(debugger, DebuggerTestPath + "BreakAllTest.py", (newproc, newthread) => { loaded.Set(); thread = newthread; }); process.ExceptionRaised += (sender, args) => { args.Thread.Resume(); }; process.Start(); if (!loaded.WaitOne(10000)) { Assert.Fail("Failed to load"); } // let loop run Thread.Sleep(500); AutoResetEvent breakComplete = new AutoResetEvent(false); PythonThread breakThread = null; process.AsyncBreakComplete += (sender, args) => { breakThread = args.Thread; breakComplete.Set(); }; process.Break(); if (!breakComplete.WaitOne(10000)) { Assert.Fail("failed to break"); } Assert.AreEqual(breakThread, thread); process.Resume(); process.Terminate(); }
private void LocalsTest(string filename, int lineNo, string[] paramNames, string[] localsNames) { var debugger = new PythonDebugger(); PythonThread thread = null; var process = DebugProcess(debugger, DebuggerTestPath + filename, (newproc, newthread) => { var breakPoint = newproc.AddBreakPoint(filename, lineNo); breakPoint.Add(); thread = newthread; }); AutoResetEvent brkHit = new AutoResetEvent(false); process.BreakpointHit += (sender, args) => { brkHit.Set(); }; process.ExceptionRaised += (sender, args) => { // some versions of Python raise exceptions args.Thread.Resume(); }; process.Start(); brkHit.WaitOne(); var frames = thread.GetFrames(); var localsExpected = new HashSet <string>(localsNames); var paramsExpected = new HashSet <string>(paramNames); Assert.IsTrue(localsExpected.ContainsExactly(frames[0].Locals.Select(x => x.Expression))); Assert.IsTrue(paramsExpected.ContainsExactly(frames[0].Parameters.Select(x => x.Expression))); Assert.AreEqual(frames[0].FileName, Path.GetFullPath(DebuggerTestPath + filename)); process.Continue(); process.WaitForExit(); }
public void TestExceptions() { var debugger = new PythonDebugger(); for (int i = 0; i < 2; i++) { TestException(debugger, DebuggerTestPath + @"SimpleException.py", i == 0, new ExceptionInfo(ExceptionModule + ".Exception", 3)); TestException(debugger, DebuggerTestPath + ComplexExceptions, i == 0, new ExceptionInfo(PickleModule + ".PickleError", 6), new ExceptionInfo(ExceptionModule + ".StopIteration", 13), new ExceptionInfo(ExceptionModule + ".NameError", 15), new ExceptionInfo(ExceptionModule + ".StopIteration", 21), new ExceptionInfo(ExceptionModule + ".NameError", 23), new ExceptionInfo(ExceptionModule + ".Exception", 29), new ExceptionInfo(ExceptionModule + ".Exception", 32) ); if (Version.Version.Is2x()) { TestException(debugger, DebuggerTestPath + @"UnicodeException.py", i == 0, new ExceptionInfo(ExceptionModule + ".Exception", 3)); } } }
/// <summary> /// Runs the given file name setting break points at linenos. Expects to hit the lines /// in lineHits as break points in the order provided in lineHits. If lineHits is negative /// expects to hit the positive number and then removes the break point. /// </summary> private void BreakpointTest(string filename, int[] linenos, int[] lineHits, string[] conditions = null, bool[] breakWhenChanged = null) { var debugger = new PythonDebugger(); PythonThread thread = null; var process = DebugProcess(debugger, DebuggerTestPath + filename, (newproc, newthread) => { for (int i = 0; i < linenos.Length; i++) { var line = linenos[i]; int finalLine = line; if (finalLine < 0) { finalLine = -finalLine; } PythonBreakpoint breakPoint; if (conditions != null) { if (breakWhenChanged != null) { breakPoint = newproc.AddBreakPoint(filename, line, conditions[i], breakWhenChanged[i]); } else { breakPoint = newproc.AddBreakPoint(filename, line, conditions[i]); } } else { breakPoint = newproc.AddBreakPoint(filename, line); } breakPoint.Add(); } thread = newthread; }); process.BreakpointBindFailed += (sender, args) => { Assert.Fail("unexpected bind failure"); }; var lineList = new List <int>(linenos); int breakpointBound = 0; int breakpointHit = 0; process.BreakpointBindSucceeded += (sender, args) => { Assert.AreEqual(args.Breakpoint.Filename, filename); int index = lineList.IndexOf(args.Breakpoint.LineNo); Assert.IsTrue(index != -1); lineList[index] = -1; breakpointBound++; }; process.BreakpointHit += (sender, args) => { if (lineHits[breakpointHit] < 0) { Assert.AreEqual(args.Breakpoint.LineNo, -lineHits[breakpointHit++]); try { args.Breakpoint.Remove(); } catch { Debug.Assert(false); } } else { Assert.AreEqual(args.Breakpoint.LineNo, lineHits[breakpointHit++]); } Assert.AreEqual(args.Thread, thread); process.Continue(); }; process.ExceptionRaised += (sender, args) => { args.Thread.Resume(); }; process.Start(); process.WaitForExit(); Assert.AreEqual(breakpointHit, lineHits.Length); Assert.AreEqual(breakpointBound, linenos.Length); }
public void SetNextLineTest() { if (GetType() == typeof(DebuggerTestsIpy)) { //http://ironpython.codeplex.com/workitem/30129 return; } var debugger = new PythonDebugger(); PythonThread thread = null; var process = DebugProcess(debugger, DebuggerTestPath + @"SetNextLine.py", (newproc, newthread) => { var breakPoint = newproc.AddBreakPoint("SetNextLine.py", 1); breakPoint.Add(); thread = newthread; }); AutoResetEvent brkHit = new AutoResetEvent(false); AutoResetEvent stepDone = new AutoResetEvent(false); process.BreakpointHit += (sender, args) => { brkHit.Set(); }; process.StepComplete += (sender, args) => { stepDone.Set(); }; process.ExceptionRaised += (sender, args) => { args.Thread.Resume(); }; process.Start(); brkHit.WaitOne(); var moduleFrame = thread.GetFrames()[0]; Assert.AreEqual(moduleFrame.StartLine, 1); if (GetType() != typeof(DebuggerTestsIpy)) { Assert.AreEqual(moduleFrame.EndLine, 13); } // skip over def f() Assert.IsTrue(moduleFrame.SetLineNumber(6)); // set break point in g, run until we hit it. var newBp = process.AddBreakPoint("SetNextLine.py", 7); newBp.Add(); process.Resume(); brkHit.WaitOne(); thread.StepOver(); // step over x = 42 stepDone.WaitOne(); // skip y = 100 Assert.IsTrue(moduleFrame.SetLineNumber(9)); thread.StepOver(); // step over z = 200 stepDone.WaitOne(); // z shouldn't be defined var frames = thread.GetFrames(); new HashSet <string>(new[] { "x", "z" }).ContainsExactly(frames[0].Locals.Select(x => x.Expression)); // set break point in module, run until we hit it. newBp = process.AddBreakPoint("SetNextLine.py", 13); newBp.Add(); thread.Resume(); brkHit.WaitOne(); // f shouldn't be defined. frames = thread.GetFrames(); new HashSet <string>(new[] { "sys", "g" }).ContainsExactly(frames[0].Locals.Select(x => x.Expression)); process.Continue(); process.WaitForExit(); }
internal async Task StepTestAsync(string filename, string breakFile, string arguments, int[] breakLines, Action <PythonProcess>[] breakAction, Action processLoaded, PythonDebugOptions options = PythonDebugOptions.RedirectOutput, bool waitForExit = true, params ExpectedStep[] kinds) { Console.WriteLine("--- Begin Step Test ---"); var debugger = new PythonDebugger(); if (breakFile == null) { breakFile = filename; } string fullPath = Path.GetFullPath(filename); string dir = Path.GetDirectoryName(filename); var process = debugger.CreateProcess(Version.Version, Version.InterpreterPath, "\"" + fullPath + "\" " + (arguments ?? ""), dir, "", null, options, DebugLog); try { PythonThread thread = null; process.ThreadCreated += (sender, args) => { thread = args.Thread; }; AutoResetEvent processEvent = new AutoResetEvent(false); bool processLoad = false, stepComplete = false; process.ProcessLoaded += async(sender, args) => { foreach (var breakLine in breakLines) { var bp = process.AddBreakpointByFileExtension(breakLine, breakFile); await bp.AddAsync(TimeoutToken()); } processLoad = true; processEvent.Set(); processLoaded?.Invoke(); }; process.StepComplete += (sender, args) => { stepComplete = true; processEvent.Set(); }; int breakHits = 0; ExceptionDispatchInfo edi = null; process.BreakpointHit += (sender, args) => { try { Console.WriteLine("Breakpoint hit"); if (breakAction != null) { if (breakHits >= breakAction.Length) { Assert.Fail("Unexpected breakpoint hit at {0}:{1}", args.Breakpoint.Filename, args.Breakpoint.LineNo); } breakAction[breakHits++](process); } stepComplete = true; processEvent.Set(); } catch (Exception ex) { edi = ExceptionDispatchInfo.Capture(ex); try { processEvent.Set(); } catch { } } }; await process.StartAsync(); for (int curStep = 0; curStep < kinds.Length; curStep++) { Console.WriteLine("Step {0} {1}", curStep, kinds[curStep].Kind); // process the stepping events as they occur, we cannot callback during the // event because the notificaiton happens on the debugger thread and we // need to callback to get the frames. AssertWaited(processEvent); edi?.Throw(); // first time through we hit process load, each additional time we should hit step complete. Debug.Assert((processLoad == true && stepComplete == false && curStep == 0) || (stepComplete == true && processLoad == false && curStep != 0)); processLoad = stepComplete = false; var frames = thread.Frames; var stepInfo = kinds[curStep]; Assert.AreEqual(stepInfo.StartLine, frames[0].LineNo, String.Format("{0} != {1} on {2} step", stepInfo.StartLine, frames[0].LineNo, curStep)); switch (stepInfo.Kind) { case StepKind.Into: await thread.StepIntoAsync(TimeoutToken()); break; case StepKind.Out: await thread.StepOutAsync(TimeoutToken()); break; case StepKind.Over: await thread.StepOverAsync(TimeoutToken()); break; case StepKind.Resume: await process.ResumeAsync(TimeoutToken()); break; } } if (waitForExit) { WaitForExit(process); } } finally { process.Terminate(); } }
public async Task RunAsync() { string runFileName = RunFileName; if (!Path.IsPathRooted(runFileName)) { runFileName = _tests.DebuggerTestPath + runFileName; } string breakFileName = BreakFileName; if (breakFileName != null && !Path.IsPathRooted(breakFileName)) { breakFileName = _tests.DebuggerTestPath + breakFileName; } foreach (var bp in Breakpoints) { var fileName = bp.FileName ?? breakFileName ?? runFileName; if (fileName.EndsWith(".py")) { Assert.IsTrue(bp is Breakpoint); } else { Assert.IsTrue(bp is DjangoBreakpoint); } } var bps = new Dictionary <PythonBreakpoint, BreakpointBase>(); var unboundBps = new HashSet <Breakpoint>(); var breakpointsToBeBound = Breakpoints.Count; var debugger = new PythonDebugger(); PythonThread thread = null; // Used to signal exceptions from debugger event handlers that run on a background thread. var backgroundException = new TaskCompletionSource <bool>(); var processLoaded = new TaskCompletionSource <bool>(); var process = _tests.DebugProcess( debugger, runFileName, cwd: WorkingDirectory, arguments: Arguments, resumeOnProcessLoaded: false, onLoaded: async(newproc, newthread) => { try { foreach (var bp in Breakpoints) { var fileName = bp.FileName ?? breakFileName ?? runFileName; PythonBreakpoint breakpoint; var pyBP = bp as Breakpoint; if (pyBP != null) { breakpoint = newproc.AddBreakpoint(fileName, pyBP.LineNumber, pyBP.ConditionKind, pyBP.Condition, pyBP.PassCountKind, pyBP.PassCount); unboundBps.Add(pyBP); } else { var djangoBP = bp as DjangoBreakpoint; if (djangoBP != null) { breakpoint = newproc.AddDjangoBreakpoint(fileName, djangoBP.LineNumber); // Django breakpoints are never bound. --breakpointsToBeBound; } else { Assert.Fail("Unknown breakpoint type."); return; } } // Bind failed and succeeded events expect to find the breakpoint // in the dictionary, so update it before sending the add request. bps.Add(breakpoint, bp); await breakpoint.AddAsync(TimeoutToken()); } OnProcessLoaded?.Invoke(newproc); thread = newthread; processLoaded.SetResult(true); } catch (Exception ex) { backgroundException.TrySetException(ex); } }, interpreterOptions: InterpreterOptions ); int breakpointsBound = 0; int breakpointsNotBound = 0; int nextExpectedHit = 0; var allBreakpointsHit = new TaskCompletionSource <bool>(); var allBreakpointBindResults = new TaskCompletionSource <bool>(); if (breakpointsToBeBound == 0) { allBreakpointBindResults.SetResult(true); } try { process.BreakpointBindFailed += (sender, args) => { try { var bp = (Breakpoint)bps[args.Breakpoint]; if (bp != null && !(bp.IsBindFailureExpected ?? IsBindFailureExpected)) { Assert.Fail("Breakpoint at {0}:{1} failed to bind.", bp.FileName ?? breakFileName ?? runFileName, bp.LineNumber); } ++breakpointsNotBound; if (breakpointsBound + breakpointsNotBound == breakpointsToBeBound) { allBreakpointBindResults.SetResult(true); } } catch (Exception ex) { backgroundException.TrySetException(ex); } }; process.BreakpointBindSucceeded += (sender, args) => { try { var bp = (Breakpoint)bps[args.Breakpoint]; Assert.AreEqual(bp.FileName ?? breakFileName ?? runFileName, args.Breakpoint.Filename); Assert.IsTrue(unboundBps.Remove(bp)); ++breakpointsBound; if (breakpointsBound + breakpointsNotBound == breakpointsToBeBound) { allBreakpointBindResults.SetResult(true); } } catch (Exception ex) { backgroundException.TrySetException(ex); } }; process.BreakpointHit += async(sender, args) => { try { if (nextExpectedHit < ExpectedHits.Count) { var bp = Breakpoints[ExpectedHits[nextExpectedHit]]; Trace.TraceInformation("Hit {0}:{1}", args.Breakpoint.Filename, args.Breakpoint.LineNo); Assert.AreSame(bp, bps[args.Breakpoint]); if (bp.RemoveWhenHit) { await args.Breakpoint.RemoveAsync(TimeoutToken()); } if (bp.ExpectHitOnMainThread ?? ExpectHitOnMainThread) { Assert.AreSame(thread, args.Thread); } bp.OnHit?.Invoke(args); if (++nextExpectedHit == ExpectedHits.Count) { allBreakpointsHit.SetResult(true); } } try { await process.ResumeAsync(TimeoutToken()); } catch (TaskCanceledException) { // If we don't wait for exit, the Terminate() call // will cause ResumeAsync to be canceled. if (WaitForExit) { throw; } } } catch (Exception ex) { backgroundException.TrySetException(ex); } }; await process.StartAsync(); Assert.IsTrue(WaitForAny(10000, processLoaded.Task, backgroundException.Task), "Timed out waiting for process load"); await process.AutoResumeThread(thread.Id, TimeoutToken()); if (breakpointsToBeBound > 0) { Assert.IsTrue(WaitForAny(10000, allBreakpointBindResults.Task, backgroundException.Task), "Timed out waiting for breakpoints to bind"); } } finally { if (WaitForExit) { _tests.WaitForExit(process); } else { Assert.IsTrue(WaitForAny(20000, allBreakpointsHit.Task, backgroundException.Task), "Timed out waiting for breakpoints to hit"); process.Terminate(); } } if (backgroundException.Task.IsFaulted) { backgroundException.Task.GetAwaiter().GetResult(); } Assert.AreEqual(ExpectedHits.Count, nextExpectedHit); Assert.IsTrue(unboundBps.All(bp => bp.IsBindFailureExpected ?? IsBindFailureExpected)); }
internal PythonProcess DebugProcess(PythonDebugger debugger, string filename, Func <PythonProcess, PythonThread, Task> onLoaded = null, bool resumeOnProcessLoaded = true, string interpreterOptions = null, PythonDebugOptions debugOptions = PythonDebugOptions.RedirectOutput, string cwd = null, string arguments = "") { return(debugger.DebugProcess(Version, filename, DebugLog, onLoaded, resumeOnProcessLoaded, interpreterOptions, debugOptions, cwd, arguments)); }
internal object DebugProcess(PythonDebugger debugger, string runFileName, string cwd, string arguments, bool resumeOnProcessLoaded, object onLoaded, string interpreterOptions) { throw new NotImplementedException(); }
public void Run() { string runFileName = RunFileName; if (!Path.IsPathRooted(runFileName)) { runFileName = _tests.DebuggerTestPath + runFileName; } string breakFileName = BreakFileName; if (breakFileName != null && !Path.IsPathRooted(breakFileName)) { breakFileName = _tests.DebuggerTestPath + breakFileName; } foreach (var bp in Breakpoints) { var fileName = bp.FileName ?? breakFileName ?? runFileName; if (fileName.EndsWith(".py")) { Assert.IsTrue(bp is Breakpoint); } else { Assert.IsTrue(bp is DjangoBreakpoint); } } var bps = new Dictionary <PythonBreakpoint, BreakpointBase>(); var unboundBps = new HashSet <Breakpoint>(); var breakpointsToBeBound = Breakpoints.Count; var debugger = new PythonDebugger(); PythonThread thread = null; // Used to signal exceptions from debugger event handlers that run on a background thread. var backgroundException = new TaskCompletionSource <bool>(); var processLoaded = new TaskCompletionSource <bool>(); var process = _tests.DebugProcess( debugger, runFileName, cwd: WorkingDirectory, arguments: Arguments, resumeOnProcessLoaded: false, onLoaded: (newproc, newthread) => { try { foreach (var bp in Breakpoints) { var fileName = bp.FileName ?? breakFileName ?? runFileName; PythonBreakpoint breakpoint; var pyBP = bp as Breakpoint; if (pyBP != null) { breakpoint = newproc.AddBreakPoint(fileName, pyBP.LineNumber, pyBP.ConditionKind, pyBP.Condition, pyBP.PassCountKind, pyBP.PassCount); unboundBps.Add(pyBP); } else { var djangoBP = bp as DjangoBreakpoint; if (djangoBP != null) { breakpoint = newproc.AddDjangoBreakPoint(fileName, djangoBP.LineNumber); // Django breakpoints are never bound. --breakpointsToBeBound; } else { Assert.Fail("Unknown breakpoint type."); return; } } breakpoint.Add(); bps.Add(breakpoint, bp); } if (OnProcessLoaded != null) { OnProcessLoaded(newproc); } thread = newthread; processLoaded.SetResult(true); } catch (Exception ex) { backgroundException.SetException(ex); } }, interpreterOptions: InterpreterOptions ); int breakpointsBound = 0; int breakpointsNotBound = 0; int nextExpectedHit = 0; var allBreakpointsHit = new TaskCompletionSource <bool>(); var allBreakpointBindResults = new TaskCompletionSource <bool>(); if (breakpointsToBeBound == 0) { allBreakpointBindResults.SetResult(true); } try { process.BreakpointBindFailed += (sender, args) => { try { var bp = (Breakpoint)bps[args.Breakpoint]; if (bp != null && !(bp.IsBindFailureExpected ?? IsBindFailureExpected)) { Assert.Fail("Breakpoint at {0}:{1} failed to bind.", bp.FileName ?? breakFileName ?? runFileName, bp.LineNumber); } ++breakpointsNotBound; if (breakpointsBound + breakpointsNotBound == breakpointsToBeBound) { allBreakpointBindResults.SetResult(true); } } catch (Exception ex) { backgroundException.SetException(ex); } }; process.BreakpointBindSucceeded += (sender, args) => { try { var bp = (Breakpoint)bps[args.Breakpoint]; Assert.AreEqual(bp.FileName ?? breakFileName ?? runFileName, args.Breakpoint.Filename); Assert.IsTrue(unboundBps.Remove(bp)); ++breakpointsBound; if (breakpointsBound + breakpointsNotBound == breakpointsToBeBound) { allBreakpointBindResults.SetResult(true); } } catch (Exception ex) { backgroundException.SetException(ex); } }; process.BreakpointHit += (sender, args) => { try { if (nextExpectedHit < ExpectedHits.Count) { var bp = Breakpoints[ExpectedHits[nextExpectedHit]]; Assert.AreSame(bp, bps[args.Breakpoint]); if (bp.RemoveWhenHit) { args.Breakpoint.Remove(); } if (bp.ExpectHitOnMainThread ?? ExpectHitOnMainThread) { Assert.AreSame(thread, args.Thread); } if (bp.OnHit != null) { bp.OnHit(args); } if (++nextExpectedHit == ExpectedHits.Count) { allBreakpointsHit.SetResult(true); } } process.Continue(); } catch (Exception ex) { backgroundException.SetException(ex); } }; process.Start(); WaitForAny(10000, processLoaded.Task, backgroundException.Task); process.AutoResumeThread(thread.Id); if (breakpointsToBeBound > 0) { WaitForAny(10000, allBreakpointBindResults.Task, backgroundException.Task); } } finally { if (WaitForExit) { _tests.WaitForExit(process); } else { WaitForAny(10000, allBreakpointsHit.Task, backgroundException.Task); process.Terminate(); } } if (backgroundException.Task.IsFaulted) { backgroundException.Task.GetAwaiter().GetResult(); } Assert.AreEqual(ExpectedHits.Count, nextExpectedHit); Assert.IsTrue(unboundBps.All(bp => bp.IsBindFailureExpected ?? IsBindFailureExpected)); }
private void ChildTest(string filename, int lineNo, string text, params ChildInfo[] children) { var debugger = new PythonDebugger(); PythonThread thread = null; var process = DebugProcess(debugger, DebuggerTestPath + filename, (newproc, newthread) => { var breakPoint = newproc.AddBreakPoint(filename, lineNo); breakPoint.Add(); thread = newthread; }); AutoResetEvent brkHit = new AutoResetEvent(false); process.BreakpointHit += (sender, args) => { brkHit.Set(); }; process.ExceptionRaised += (sender, args) => { // some versions of Python raise exceptions during startup args.Thread.Resume(); }; process.Start(); brkHit.WaitOne(); var frames = thread.GetFrames(); AutoResetEvent evalComplete = new AutoResetEvent(false); PythonEvaluationResult evalRes = null; frames[0].ExecuteText(text, (completion) => { evalRes = completion; evalComplete.Set(); }); evalComplete.WaitOne(); Assert.IsTrue(evalRes != null); if (children == null) { Assert.IsTrue(!evalRes.IsExpandable); Assert.IsTrue(evalRes.GetChildren(Int32.MaxValue) == null); } else { Assert.IsTrue(evalRes.IsExpandable); var childrenReceived = new List <PythonEvaluationResult>(evalRes.GetChildren(Int32.MaxValue)); Assert.IsTrue(children.Length == childrenReceived.Count); for (int i = 0; i < children.Length; i++) { bool foundChild = false; for (int j = 0; j < childrenReceived.Count; j++) { if (childrenReceived[j].ChildText == children[i].ChildText && childrenReceived[j].StringRepr == children[i].Repr) { foundChild = true; if (children[i].ChildText.StartsWith("[")) { Assert.AreEqual(childrenReceived[j].Expression, text + children[i].ChildText); } else { Assert.AreEqual(childrenReceived[j].Expression, text + "." + children[i].ChildText); } Assert.AreEqual(childrenReceived[j].Frame, frames[0]); childrenReceived.RemoveAt(j); break; } } Assert.IsTrue(foundChild); } Assert.IsTrue(childrenReceived.Count == 0); } process.Continue(); process.WaitForExit(); }
private void StepTest(string filename, params ExpectedStep[] kinds) { var debugger = new PythonDebugger(); string fullPath = Path.GetFullPath(filename); string dir = Path.GetDirectoryName(filename); var process = debugger.CreateProcess(Version.Version, Version.Path, "\"" + fullPath + "\"", dir, ""); PythonThread thread = null; process.ThreadCreated += (sender, args) => { thread = args.Thread; }; AutoResetEvent processEvent = new AutoResetEvent(false); bool processLoad = false, stepComplete = false; process.ProcessLoaded += (sender, args) => { processLoad = true; processEvent.Set(); }; process.StepComplete += (sender, args) => { stepComplete = true; processEvent.Set(); }; process.ExceptionRaised += (sender, args) => { args.Thread.Resume(); }; process.Start(); for (int curStep = 0; curStep < kinds.Length; curStep++) { // process the stepping events as they occur, we cannot callback during the // event because the notificaiton happens on the debugger thread and we // need to callback to get the frames. processEvent.WaitOne(); // first time through we hit process load, each additional time we should hit step complete. Debug.Assert((processLoad == true && stepComplete == false && curStep == 0) || (stepComplete == true && processLoad == false && curStep != 0)); processLoad = stepComplete = false; var frames = thread.GetFrames(); var stepInfo = kinds[curStep]; Assert.AreEqual(stepInfo.StartLine, frames[0].LineNo, String.Format("{0} != {1} on {2} step", stepInfo.StartLine, frames[0].LineNo, curStep)); switch (stepInfo.Kind) { case StepKind.Into: thread.StepInto(); break; case StepKind.Out: thread.StepOut(); break; case StepKind.Over: thread.StepOver(); break; case StepKind.Resume: process.Resume(); break; } } process.WaitForExit(); }