From 5659a1e79eab776dceae58a54d71884b10b17e8d Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Mon, 12 Oct 2009 23:09:51 -0500 Subject: [PATCH] jasmine.Queue iterates by looping rather than recursing, so stack overflows should be less likely. --- spec/runner.html | 1 + spec/suites/QueueSpec.js | 23 +++++++++++++ src/Queue.js | 73 +++++++++++++++++++++++----------------- 3 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 spec/suites/QueueSpec.js diff --git a/spec/runner.html b/spec/runner.html index 6c02a62..f963bb4 100644 --- a/spec/runner.html +++ b/spec/runner.html @@ -39,6 +39,7 @@ 'suites/ExceptionsSpec.js', 'suites/TrivialReporterSpec.js', 'suites/MatchersSpec.js', + 'suites/QueueSpec.js', 'suites/ReporterSpec.js', 'suites/MultiReporterSpec.js', 'suites/PrettyPrintSpec.js', diff --git a/spec/suites/QueueSpec.js b/spec/suites/QueueSpec.js new file mode 100644 index 0000000..59a70f3 --- /dev/null +++ b/spec/suites/QueueSpec.js @@ -0,0 +1,23 @@ +describe("jasmine.Queue", function() { + it("should not call itself recursively, so we don't get stack overflow errors", function() { + var queue = new jasmine.Queue(new jasmine.Env()); + queue.add(new jasmine.Block(null, function() {})); + queue.add(new jasmine.Block(null, function() {})); + queue.add(new jasmine.Block(null, function() {})); + queue.add(new jasmine.Block(null, function() {})); + + var nestCount = 0; + var maxNestCount = 0; + var nextCallCount = 0; + queue.next_ = function() { + nestCount++; + if (nestCount > maxNestCount) maxNestCount = nestCount; + + jasmine.Queue.prototype.next_.apply(queue, arguments); + nestCount--; + }; + + queue.start(); + expect(maxNestCount).toEqual(1); + }); +}); \ No newline at end of file diff --git a/src/Queue.js b/src/Queue.js index 18300d3..c3e064a 100644 --- a/src/Queue.js +++ b/src/Queue.js @@ -29,43 +29,54 @@ jasmine.Queue.prototype.isRunning = function() { return this.running; }; -jasmine.Queue.UNROLL = true; +jasmine.Queue.LOOP_DONT_RECURSE = true; jasmine.Queue.prototype.next_ = function() { var self = this; - if (self.index < self.blocks.length) { - var calledSynchronously = true; - var completedSynchronously = false; + var goAgain = true; - var onComplete = function () { - if (jasmine.Queue.UNROLL && calledSynchronously) { - completedSynchronously = true; - return; + while (goAgain) { + goAgain = false; + + if (self.index < self.blocks.length) { + var calledSynchronously = true; + var completedSynchronously = false; + + var onComplete = function () { + if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) { + completedSynchronously = true; + return; + } + + self.offset = 0; + self.index++; + + var now = new Date().getTime(); + if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) { + self.env.lastUpdate = now; + self.env.setTimeout(function() { + self.next_(); + }, 0); + } else { + if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) { + goAgain = true; + } else { + self.next_(); + } + } + }; + self.blocks[self.index].execute(onComplete); + + calledSynchronously = false; + if (completedSynchronously) { + onComplete(); } - - self.offset = 0; - self.index++; - - var now = new Date().getTime(); - if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) { - self.env.lastUpdate = now; - self.env.setTimeout(function() { - self.next_(); - }, 0); - } else { - self.next_(); + + } else { + self.running = false; + if (self.onComplete) { + self.onComplete(); } - }; - self.blocks[self.index].execute(onComplete); - - calledSynchronously = false; - if (completedSynchronously) { - onComplete(); - } - } else { - self.running = false; - if (self.onComplete) { - self.onComplete(); } } };