|
// UUT.test.js |
|
import { timerUtils } from './timerUtils.js'; |
|
import { UUT } from './UUT.js'; |
|
import sinon from 'sinon'; |
|
import { expect } from 'chai'; |
|
|
|
const promiseResolvers = []; |
|
const useGlobalClock = false; |
|
let clock; |
|
const callCount = 3; |
|
|
|
const HIL_SIM_TIME = 1000; |
|
|
|
async function realTimeOut(ms) { |
|
if (useGlobalClock) { |
|
clock.restore() |
|
} else { |
|
timerUtils.pauseFakeTimer(); |
|
} |
|
|
|
await new Promise(resolve => setTimeout(resolve, ms)); |
|
|
|
if (useGlobalClock) { |
|
clock = sinon.useFakeTimers(); |
|
} else { |
|
timerUtils.resumeFakeTimer(); |
|
} |
|
} |
|
|
|
describe('Main Function Test', function () { |
|
beforeEach(function () { |
|
if (useGlobalClock) { |
|
clock = sinon.useFakeTimers(); |
|
} else { |
|
timerUtils.useFakeTimer(); |
|
} |
|
|
|
sinon.stub(UUT, 'subFunction').callsFake(async (index) => { |
|
console.log(`Stub: subFunction ${index} called, ${new Date().toISOString()}`); |
|
return new Promise((resolve) => { |
|
promiseResolvers.push(() => { |
|
// HIL Simulation calls are stubbed here |
|
timerUtils.pauseFakeTimer(); // Pause the fake timer |
|
console.log(`Stub: [HIL-SIM] call #${index} starting on ${new Date().toISOString()}`) |
|
setTimeout(() => { |
|
resolve(); |
|
console.log(`Stub: [HIL-SIM] call #${index} ended on ${new Date().toISOString()}`) |
|
timerUtils.resumeFakeTimer(); // Resume the fake timer |
|
}, HIL_SIM_TIME); // Real-time timeout |
|
}); |
|
}); |
|
}); |
|
|
|
}); |
|
|
|
afterEach(function () { |
|
if (useGlobalClock) { |
|
clock.restore(); |
|
} else { |
|
timerUtils.restoreRealTimer(); |
|
} |
|
promiseResolvers.length = 0; |
|
UUT.subFunction.restore(); |
|
}); |
|
|
|
it('should complete mainFunction with controlled promise resolution', async function () { |
|
this.timeout((callCount + 2) * HIL_SIM_TIME); |
|
const mainFunctionPromise = UUT.mainFunction(); |
|
// Ensure we advance time and resolve promises only after they are pushed |
|
for (let i = 1; i <= callCount; i++) { |
|
|
|
// Wait for real time based stub, at least HIL_SIM_TIME |
|
console.log(`Test: Start waiting in real time (for the stub) [subfunction ${i}]`); |
|
await realTimeOut(1000); |
|
console.log(`Test: Finish waiting in real time (for the stub) [subfunction ${i}]`); |
|
|
|
console.log(`Test: Start waiting in fake time (for the UUT) [subfunction ${i}]`); |
|
if (useGlobalClock) { |
|
await clock.tickAsync(1000) |
|
} else { |
|
await timerUtils.currentClock.tickAsync(1000); |
|
} |
|
console.log(`Test: Finish waiting in fake time (for the UUT) [subfunction ${i}]`); |
|
|
|
let rCount = promiseResolvers.length; |
|
expect(rCount, `Expected ${i} resolvers but received ${rCount}`).to.equal(i); |
|
|
|
console.log(`Test: Resolving subfunction ${i}`); |
|
if (typeof promiseResolvers[i - 1] === 'function') { |
|
promiseResolvers[i - 1](); // Resolve the i-th subfunction's promise |
|
console.log(`Test: Resolved subfunction ${i}`) |
|
} else { |
|
// This should not be reached as the previous expectation should fire |
|
throw new Error(`Test: Resolver for subfunction ${i} is not a function`); |
|
} |
|
} |
|
|
|
console.log(`Test: All ${promiseResolvers.length} subfunction promises are resolved`); |
|
console.log('Test: Advancing time for the final wait'); |
|
if (useGlobalClock) { |
|
await clock.tickAsync(4000) |
|
} else { |
|
await timerUtils.currentClock.tickAsync(4000); |
|
} |
|
|
|
console.log('Test: awaiting mainFunction promise'); |
|
await mainFunctionPromise; |
|
console.log('Test: mainFunction should be completed now'); |
|
expect(UUT.subFunction.callCount).to.equal(callCount); |
|
}); |
|
}); |