+ class ReusableBreakpoint {
+ DebuggerTests owner;
+ public string method_name;
+ public BreakpointEventRequest req;
+ public BreakpointEvent lastEvent = null;
+ public ReusableBreakpoint (DebuggerTests owner, string method_name)
+ {
+ this.owner = owner;
+ this.method_name = method_name;
+ MethodMirror m = owner.entry_point.DeclaringType.GetMethod (method_name);
+ Assert.IsNotNull (m);
+ req = owner.vm.SetBreakpoint (m, m.ILOffsets [0]);
+ }
+
+ public void Continue ()
+ {
+ bool survived = false;
+
+ try {
+ Event e = null;
+
+ while (true) {
+ owner.vm.Resume ();
+ e = owner.GetNextEvent ();
+ if (e is BreakpointEvent)
+ break;
+ }
+
+ Assert.IsInstanceOfType (typeof (BreakpointEvent), e);
+ Assert.AreEqual (method_name, (e as BreakpointEvent).Method.Name);
+
+ lastEvent = e as BreakpointEvent;
+
+ survived = true;
+ } finally {
+ if (!survived) { // Ensure cleanup if we triggered an assert
+ Disable ();
+ }
+ }
+ }
+
+ public void Disable ()
+ {
+ req.Disable ();
+ }
+ }
+
+ /* One of the tests executes a complex tree of recursive functions.
+ The only good way to specify how its behavior should appear from this side
+ is to just run the function tree once over here and record what it does. */
+ public struct RecursiveChaoticPoint
+ {
+ public bool breakpoint;
+ public string name;
+ public int depth;
+
+ public RecursiveChaoticPoint (bool breakpoint, string name, int depth)
+ {
+ this.breakpoint = breakpoint;
+ this.name = name;
+ this.depth = depth;
+ }
+ }
+
+ // The breakpoint is placed here in dtest-app.cs
+ public static void ss_recursive_chaotic_trap (int n, List<RecursiveChaoticPoint> trace, ref bool didLast, ref bool didAny)
+ {
+ // Depth is calculated as:
+ // Main + single_stepping + ss_recursive_chaotic + (n is 5 at outermost frame and 0 at innermost frame) + ss_recursive_chaotic_trap
+ trace.Add (new RecursiveChaoticPoint (true, "ss_recursive_chaotic_trap", 5 - n + 5));
+ didLast = true;
+ }
+
+ public static void ss_recursive_chaotic_at (string at, int n, List<RecursiveChaoticPoint> trace, ref bool didLast, ref bool didAny)
+ {
+ // This will be called after every return from a function. The other function will return whether "step out" is currently active, and it will be passed in here as didLast.
+ if (didLast) {
+ // Depth is calculated as:
+ // Main + single_stepping + ss_recursive_chaotic + (n is 5 at outermost frame and 0 at innermost frame)
+ trace.Add (new RecursiveChaoticPoint (false, "ss_recursive_chaotic_" + at, 5 - n + 4));
+ didAny = true;
+ didLast = false;
+ }
+ }
+
+ public static bool ss_recursive_chaotic_fizz (int n, List<RecursiveChaoticPoint> trace)
+ {
+ bool didLast = false, didAny = false;
+ if (n > 0) {
+ int next = n - 1;
+ didLast = ss_recursive_chaotic_buzz (next, trace);
+ ss_recursive_chaotic_at ("fizz", n, trace, ref didLast, ref didAny);
+ didLast = ss_recursive_chaotic_fizzbuzz (next, trace);
+ ss_recursive_chaotic_at ("fizz", n, trace, ref didLast, ref didAny);
+ } else {
+ ss_recursive_chaotic_trap (n, trace, ref didLast, ref didAny);
+ ss_recursive_chaotic_at ("fizz", n, trace, ref didLast, ref didAny);
+ }
+ return didAny;
+ }
+
+ public static bool ss_recursive_chaotic_buzz (int n, List<RecursiveChaoticPoint> trace)
+ {
+ bool didLast = false, didAny = false;
+ if (n > 0) {
+ int next = n - 1;
+ didLast = ss_recursive_chaotic_fizz (next, trace);
+ ss_recursive_chaotic_at ("buzz", n, trace, ref didLast, ref didAny);
+ didLast = ss_recursive_chaotic_fizzbuzz (next, trace);
+ ss_recursive_chaotic_at ("buzz", n, trace, ref didLast, ref didAny);
+ }
+ return didAny;
+ }
+
+ public static bool ss_recursive_chaotic_fizzbuzz (int n, List<RecursiveChaoticPoint> trace)
+ {
+ bool didLast = false, didAny = false;
+ if (n > 0) {
+ int next = n - 1;
+ didLast = ss_recursive_chaotic_fizz (next, trace);
+ ss_recursive_chaotic_at ("fizzbuzz", n, trace, ref didLast, ref didAny);
+ didLast = ss_recursive_chaotic_buzz (next, trace);
+ ss_recursive_chaotic_at ("fizzbuzz", n, trace, ref didLast, ref didAny);
+ didLast = ss_recursive_chaotic_fizzbuzz (next, trace);
+ ss_recursive_chaotic_at ("fizzbuzz", n, trace, ref didLast, ref didAny);
+ }
+ return didAny;
+ }
+
+ public static void trace_ss_recursive_chaotic (List<RecursiveChaoticPoint> trace)
+ {
+ ss_recursive_chaotic_fizz (5, trace);
+ }
+