- Merges #1427 from @eahciMic
- Fixes #1426
This commit is contained in:
Steve Gravrock
2018-01-02 08:15:30 -08:00
4 changed files with 66 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (c) 2008-2017 Pivotal Labs Copyright (c) 2008-2018 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the
@@ -2066,6 +2066,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
var scheduledFunctions = {}; var scheduledFunctions = {};
var currentTime = 0; var currentTime = 0;
var delayedFnCount = 0; var delayedFnCount = 0;
var deletedKeys = [];
self.tick = function(millis, tickDate) { self.tick = function(millis, tickDate) {
millis = millis || 0; millis = millis || 0;
@@ -2112,6 +2113,8 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
}; };
self.removeFunctionWithId = function(timeoutKey) { self.removeFunctionWithId = function(timeoutKey) {
deletedKeys.push(timeoutKey);
for (var runAtMillis in scheduledFunctions) { for (var runAtMillis in scheduledFunctions) {
var funcs = scheduledFunctions[runAtMillis]; var funcs = scheduledFunctions[runAtMillis];
var i = indexOfFirstToPass(funcs, function (func) { var i = indexOfFirstToPass(funcs, function (func) {
@@ -2188,6 +2191,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
currentTime = newCurrentTime; currentTime = newCurrentTime;
var funcsToRun = scheduledFunctions[currentTime]; var funcsToRun = scheduledFunctions[currentTime];
delete scheduledFunctions[currentTime]; delete scheduledFunctions[currentTime];
forEachFunction(funcsToRun, function(funcToRun) { forEachFunction(funcsToRun, function(funcToRun) {
@@ -2197,8 +2201,13 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
}); });
forEachFunction(funcsToRun, function(funcToRun) { forEachFunction(funcsToRun, function(funcToRun) {
if (deletedKeys.indexOf(funcToRun.timeoutKey) !== -1) {
// skip a timeoutKey deleted whilst we were running
return;
}
funcToRun.funcToCall.apply(null, funcToRun.params || []); funcToRun.funcToCall.apply(null, funcToRun.params || []);
}); });
deletedKeys = [];
} while (scheduledLookup.length > 0 && } while (scheduledLookup.length > 0 &&
// checking first if we're out of time prevents setTimeout(0) // checking first if we're out of time prevents setTimeout(0)
// scheduled in a funcToRun from forcing an extra iteration // scheduled in a funcToRun from forcing an extra iteration

View File

@@ -714,4 +714,41 @@ describe("Clock (acceptance)", function() {
expect(actualTimes).toEqual([baseTime.getTime(), baseTime.getTime() + 1, baseTime.getTime() + 3]); expect(actualTimes).toEqual([baseTime.getTime(), baseTime.getTime() + 1, baseTime.getTime() + 3]);
}) })
it('correctly clears a scheduled timeout while the Clock is advancing', function () {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = {Date: Date, setTimeout: undefined},
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(global, function () { return delayedFunctionScheduler; }, mockDate);
clock.install();
var timerId2;
global.setTimeout(function () {
global.clearTimeout(timerId2);
}, 100);
timerId2 = global.setTimeout(fail, 100);
clock.tick(100);
});
it('correctly clears a scheduled interval while the Clock is advancing', function () {
var delayedFunctionScheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
global = {Date: Date, setTimeout: undefined},
mockDate = new jasmineUnderTest.MockDate(global),
clock = new jasmineUnderTest.Clock(global, function () { return delayedFunctionScheduler; }, mockDate);
clock.install();
var timerId2;
var timerId1 = global.setInterval(function () {
global.clearInterval(timerId2);
}, 100);
timerId2 = global.setInterval(fail, 100);
clock.tick(400);
});
}); });

View File

@@ -216,21 +216,23 @@ describe("DelayedFunctionScheduler", function() {
it("removes functions during a tick that runs the function", function() { it("removes functions during a tick that runs the function", function() {
var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(), var scheduler = new jasmineUnderTest.DelayedFunctionScheduler(),
fn = jasmine.createSpy('fn'), spy = jasmine.createSpy('fn'),
spyAndRemove = jasmine.createSpy('fn'),
fnDelay = 10, fnDelay = 10,
timeoutKey; timeoutKey;
timeoutKey = scheduler.scheduleFunction(fn, fnDelay, [], true); spyAndRemove.and.callFake(function() {
scheduler.scheduleFunction(function () {
scheduler.removeFunctionWithId(timeoutKey); scheduler.removeFunctionWithId(timeoutKey);
}, 2 * fnDelay); });
expect(fn).not.toHaveBeenCalled(); scheduler.scheduleFunction(spyAndRemove, fnDelay);
scheduler.tick(3 * fnDelay); timeoutKey = scheduler.scheduleFunction(spy, fnDelay, [], true);
expect(fn).toHaveBeenCalled(); scheduler.tick(2 * fnDelay);
expect(fn.calls.count()).toBe(2);
expect(spy).not.toHaveBeenCalled();
expect(spyAndRemove).toHaveBeenCalled();
}); });
it("removes functions during the first tick that runs the function", function() { it("removes functions during the first tick that runs the function", function() {

View File

@@ -5,6 +5,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
var scheduledFunctions = {}; var scheduledFunctions = {};
var currentTime = 0; var currentTime = 0;
var delayedFnCount = 0; var delayedFnCount = 0;
var deletedKeys = [];
self.tick = function(millis, tickDate) { self.tick = function(millis, tickDate) {
millis = millis || 0; millis = millis || 0;
@@ -51,6 +52,8 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
}; };
self.removeFunctionWithId = function(timeoutKey) { self.removeFunctionWithId = function(timeoutKey) {
deletedKeys.push(timeoutKey);
for (var runAtMillis in scheduledFunctions) { for (var runAtMillis in scheduledFunctions) {
var funcs = scheduledFunctions[runAtMillis]; var funcs = scheduledFunctions[runAtMillis];
var i = indexOfFirstToPass(funcs, function (func) { var i = indexOfFirstToPass(funcs, function (func) {
@@ -127,6 +130,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
currentTime = newCurrentTime; currentTime = newCurrentTime;
var funcsToRun = scheduledFunctions[currentTime]; var funcsToRun = scheduledFunctions[currentTime];
delete scheduledFunctions[currentTime]; delete scheduledFunctions[currentTime];
forEachFunction(funcsToRun, function(funcToRun) { forEachFunction(funcsToRun, function(funcToRun) {
@@ -136,8 +140,13 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
}); });
forEachFunction(funcsToRun, function(funcToRun) { forEachFunction(funcsToRun, function(funcToRun) {
if (deletedKeys.indexOf(funcToRun.timeoutKey) !== -1) {
// skip a timeoutKey deleted whilst we were running
return;
}
funcToRun.funcToCall.apply(null, funcToRun.params || []); funcToRun.funcToCall.apply(null, funcToRun.params || []);
}); });
deletedKeys = [];
} while (scheduledLookup.length > 0 && } while (scheduledLookup.length > 0 &&
// checking first if we're out of time prevents setTimeout(0) // checking first if we're out of time prevents setTimeout(0)
// scheduled in a funcToRun from forcing an extra iteration // scheduled in a funcToRun from forcing an extra iteration