Repository: sinonjs/lolex (js)

Issue:
Support hrtime.bigint()
> We understand you have a problem and are in a hurry, but please provide us with some info to make it much more likely for your issue to be understood, worked on and resolved quickly.


* Lolex version : 3.1.0
* Environment   : Node.js 10.15.3
* Example URL   : N/A
* Other libraries you are using:

**What did you expect to happen?**

My code uses [`process.hrtime.bigint()`](https://nodejs.org/api/process.html#process_process_hrtime_bigint). When stubbing `process.hrtime` using Lolex, this method is no longer available.

On platforms that don't provide this function, I'd expect it not be made available by Lolex either.

**What actually happens**

It returns the stubbed time, as a BigInt.

**How to reproduce**
> Describe *with code* how to reproduce the faulty behaviour
> or link to code on JSBin or similar

```console
$ node                                                                                                                                            > process.hrtime.bigint()
39069092115824n
> require('lolex').install({toFake: ['hrtime']})
{ now: 0, … }
> process.hrtime.bigint()
TypeError: process.hrtime.bigint is not a function
```

Pull request:
Support hrtime.bigint()
Fixes #235.

I didn't think it was relevant to mention this in the documentation.

Patch:
diff --git a/src/lolex-src.js b/src/lolex-src.js
index b43e304..8a0b74c 100644
--- a/src/lolex-src.js
+++ b/src/lolex-src.js
@@ -31,6 +31,7 @@ function withGlobal(_global) {
     var timeoutResult = _global.setTimeout(NOOP, 0);
     var addTimerReturnsObject = typeof timeoutResult === "object";
     var hrtimePresent = (_global.process && typeof _global.process.hrtime === "function");
+    var hrtimeBigintPresent = (hrtimePresent && typeof _global.process.hrtime.bigint === "function");
     var nextTickPresent = (_global.process && typeof _global.process.nextTick === "function");
     var performancePresent = (_global.performance && typeof _global.performance.now === "function");
     var hasPerformancePrototype = (_global.Performance && (typeof _global.Performance).match(/^(function|object)$/));
@@ -576,6 +577,13 @@ function withGlobal(_global) {
             return [secsSinceStart, remainderInNanos];
         }
 
+        if (hrtimeBigintPresent) {
+            hrtime.bigint = function () {
+                var parts = hrtime();
+                return BigInt(parts[0]) * BigInt(1e9) + BigInt(parts[1]); // eslint-disable-line
+            };
+        }
+
         clock.requestIdleCallback = function requestIdleCallback(func, timeout) {
             var timeToNextIdlePeriod = 0;
 


Test patch:
diff --git a/test/lolex-test.js b/test/lolex-test.js
index 10ab5d3..3aca095 100644
--- a/test/lolex-test.js
+++ b/test/lolex-test.js
@@ -21,6 +21,7 @@ var NOOP = function NOOP() { return undefined; };
 var nextTickPresent = (global.process && typeof global.process.nextTick === "function");
 var queueMicrotaskPresent = (typeof global.queueMicrotask === "function");
 var hrtimePresent = (global.process && typeof global.process.hrtime === "function");
+var hrtimeBigintPresent = (hrtimePresent && typeof global.process.hrtime.bigint === "function");
 var performanceNowPresent = (global.performance && typeof global.performance.now === "function");
 var performanceMarkPresent = (global.performance && typeof global.performance.mark === "function");
 
@@ -2546,6 +2547,58 @@ describe("lolex", function () {
         });
     });
 
+    describe("process.hrtime.bigint()", function () {
+
+        before(function () {
+            if (!hrtimeBigintPresent) { this.skip(); }
+        });
+
+        afterEach(function () {
+            if (this.clock) {
+                this.clock.uninstall();
+            }
+        });
+
+        it("should start at 0n", function () {
+            var clock = lolex.createClock(1001);
+            var result = clock.hrtime.bigint();
+            assert.same(result, BigInt(0)); // eslint-disable-line
+        });
+
+        it("should run along with clock.tick", function () {
+            var clock = lolex.createClock(0);
+            clock.tick(5001);
+            var result = clock.hrtime.bigint();
+            assert.same(result, BigInt(5.001e9)); // eslint-disable-line
+        });
+
+        it("should run along with clock.tick when timers set", function () {
+            var clock = lolex.createClock(0);
+            clock.setTimeout(function () {
+                var result = clock.hrtime.bigint();
+                assert.same(result, BigInt(2.5e9)); // eslint-disable-line
+            }, 2500);
+            clock.tick(5000);
+        });
+
+        it("should not move with setSystemTime", function () {
+            var clock = lolex.createClock(0);
+            clock.setSystemTime(50000);
+            var result = clock.hrtime.bigint();
+            assert.same(result, BigInt(0)); // eslint-disable-line
+        });
+
+        it("should move with timeouts", function () {
+            var clock = lolex.createClock();
+            var result = clock.hrtime.bigint();
+            assert.same(result, BigInt(0)); // eslint-disable-line
+            clock.setTimeout(function () {}, 1000);
+            clock.runAll();
+            result = clock.hrtime.bigint();
+            assert.same(result, BigInt(1e9)); // eslint-disable-line
+        });
+    });
+
     describe("queueMicrotask semantics", function () {
         // adapted from Node's tests
         var clock, called;