Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

Commit

Permalink
Merge a236b9c into b715bd0
Browse files Browse the repository at this point in the history
  • Loading branch information
imurchie authored Dec 18, 2019
2 parents b715bd0 + a236b9c commit da3d229
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 4 deletions.
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"extends": "appium"
"extends": "appium",
"globals": {
"BigInt": true
}
}
5 changes: 3 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as zip from './lib/zip';
import * as imageUtil from './lib/image-util';
import * as mjpeg from './lib/mjpeg';
import * as node from './lib/node';
import * as timing from './lib/timing';


const { fs } = fsIndex;
Expand All @@ -19,9 +20,9 @@ const { mkdirp } = mkdirpIndex;

export {
tempDir, system, util, fs, cancellableDelay, plist, mkdirp, logger, process,
zip, imageUtil, net, mjpeg, node,
zip, imageUtil, net, mjpeg, node, timing,
};
export default {
tempDir, system, util, fs, cancellableDelay, plist, mkdirp, logger, process,
zip, imageUtil, net, mjpeg, node,
zip, imageUtil, net, mjpeg, node, timing,
};
119 changes: 119 additions & 0 deletions lib/timing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import _ from 'lodash';


const NS_PER_S = 1e9;
const NS_PER_MS = 1e6;


/**
* Class representing a duration, encapsulating the number and units.
*/
class Duration {
constructor (nanos) {
this._nanos = nanos;
}

get nanos () {
return this._nanos;
}

/**
* Get the duration as nanoseconds
*
* @returns {number} The duration as nanoseconds
*/
get asNanoSeconds () {
return this.nanos;
}

/**
* Get the duration converted into milliseconds
*
* @returns {number} The duration as milliseconds
*/
get asMilliSeconds () {
return this.nanos / NS_PER_MS;
}

/**
* Get the duration converted into seconds
*
* @returns {number} The duration fas seconds
*/
get asSeconds () {
return this.nanos / NS_PER_S;
}

toString () {
// default to milliseconds, rounded
return this.asMilliSeconds.toFixed(0);
}
}

class Timer {
/**
* Creates a timer
*/
constructor () {
this._startTime = null;
}

get startTime () {
return this._startTime;
}

/**
* Start the timer
*
* @return {Timer} The current instance, for chaining
*/
start () {
if (!_.isNull(this.startTime)) {
throw new Error('Timer has already been started.');
}
// once Node 10 is no longer supported, this check can be removed
this._startTime = _.isFunction(process.hrtime.bigint)
? process.hrtime.bigint()
: process.hrtime();
return this;
}

/**
* Get the duration since the timer was started
*
* @return {Duration} the duration, in the specified units
*/
getDuration () {
if (_.isNull(this.startTime)) {
throw new Error(`Unable to get duration. Timer was not started`);
}

let nanoDuration;
if (_.isArray(this.startTime)) {
// startTime was created using process.hrtime()
const [seconds, nanos] = process.hrtime(this.startTime);
nanoDuration = seconds * NS_PER_S + nanos;
} else if (typeof this.startTime === 'bigint' && _.isFunction(process.hrtime.bigint)) {
// startTime was created using process.hrtime.bigint()
const endTime = process.hrtime.bigint();
// get the difference, and convert to number
nanoDuration = Number(endTime - this.startTime);
} else {
throw new Error(`Unable to get duration. Start time '${this.startTime}' cannot be parsed`);
}

return new Duration(nanoDuration);
}

toString () {
try {
return this.getDuration().toString();
} catch (err) {
return `<err: ${err.message}>`;
}
}
}


export { Timer, Duration };
export default Timer;
2 changes: 1 addition & 1 deletion test/fs-specs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import B from 'bluebird';

const should = chai.should();

const MOCHA_TIMEOUT = 10000;
const MOCHA_TIMEOUT = 20000;

describe('fs', function () {
this.timeout(MOCHA_TIMEOUT);
Expand Down
143 changes: 143 additions & 0 deletions test/timing-specs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import _ from 'lodash';
import chai from 'chai';
import sinon from 'sinon';
import { timing } from '..';


chai.should();
const expect = chai.expect;

describe('timing', function () {
let processMock;
afterEach(function () {
processMock.verify();
});

describe('no bigint', function () {
const bigintFn = process.hrtime.bigint;
before(function () {
// if the system has BigInt support, remove it
if (_.isFunction(bigintFn)) {
delete process.hrtime.bigint;
}
});
beforeEach(function () {
processMock = sinon.mock(process);
});
after(function () {
if (_.isFunction(bigintFn)) {
process.hrtime.bigint = bigintFn;
}
});
it('should get a start time as array', function () {
const timer = new timing.Timer().start();
_.isArray(timer.startTime).should.be.true;
});
it('should get a duration', function () {
const timer = new timing.Timer().start();
const duration = timer.getDuration();
_.isNumber(duration.nanos).should.be.true;
});
it('should get correct seconds', function () {
processMock.expects('hrtime').twice()
.onFirstCall().returns([12, 12345])
.onSecondCall().returns([13, 54321]);

const timer = new timing.Timer().start();
const duration = timer.getDuration();
duration.asSeconds.should.eql(13.000054321);
});
it('should get correct milliseconds', function () {
processMock.expects('hrtime').twice()
.onFirstCall().returns([12, 12345])
.onSecondCall().returns([13, 54321]);

const timer = new timing.Timer().start();
const duration = timer.getDuration();
duration.asMilliSeconds.should.eql(13000.054321);
});
it('should get correct nanoseconds', function () {
processMock.expects('hrtime').twice()
.onFirstCall().returns([12, 12345])
.onSecondCall().returns([13, 54321]);

const timer = new timing.Timer().start();
const duration = timer.getDuration();
duration.asNanoSeconds.should.eql(13000054321);
});
it('should error if the timer was not started', function () {
const timer = new timing.Timer();
expect(() => timer.getDuration())
.to.throw('Unable to get duration');
});
it('should error if start time is a number', function () {
const timer = new timing.Timer();
timer._startTime = 12345;
expect(() => timer.getDuration())
.to.throw('Unable to get duration');
});
});
describe('bigint', function () {
beforeEach(function () {
// the non-mocked test cannot run if BigInt does not exist,
// and it cannot be mocked. Luckily support was added in Node 10.4.0,
// so it should not be a case where we are testing without this,
// though it still can be a test that Appium is _used_ without it.
if (!_.isFunction(process.hrtime.bigint)) {
return this.skip();
}
processMock = sinon.mock(process.hrtime);
});

function setupMocks (once = false) {
if (once) {
processMock.expects('bigint').once()
.onFirstCall().returns(BigInt(1172941153404030));
} else {
processMock.expects('bigint').twice()
.onFirstCall().returns(BigInt(1172941153404030))
.onSecondCall().returns(BigInt(1172951164887132));
}
}

it('should get a duration', function () {
setupMocks();

const timer = new timing.Timer().start();
const duration = timer.getDuration();
_.isNumber(duration.nanos).should.be.true;
});
it('should get correct seconds', function () {
setupMocks();

const timer = new timing.Timer().start();
const duration = timer.getDuration();
duration.asSeconds.should.be.eql(10.011483102);
});
it('should get correct milliseconds', function () {
setupMocks();

const timer = new timing.Timer().start();
const duration = timer.getDuration();
duration.asMilliSeconds.should.be.eql(10011.483102);
});
it('should get correct nanoseconds', function () {
setupMocks();

const timer = new timing.Timer().start();
const duration = timer.getDuration();
duration.asNanoSeconds.should.be.eql(10011483102);
});
it('should error if the timer was not started', function () {
const timer = new timing.Timer();
expect(() => timer.getDuration())
.to.throw('Unable to get duration');
});
it('should error if passing in a non-bigint', function () {
const timer = new timing.Timer();
timer._startTime = 12345;
expect(() => timer.getDuration())
.to.throw('Unable to get duration');
});
});
});

0 comments on commit da3d229

Please sign in to comment.