Skip to content
File

Blob: src/workerd/api/node/tests/process-nodejs-test.js

javascript1175 lines
1// Copyright (c) 2024 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4import assert from 'node:assert';
5import { readdirSync, readFileSync, writeFileSync } from 'node:fs';
6import * as processMod from 'node:process';
7 
8const processBuiltin = processMod.getBuiltinModule('process');
9const processBuiltinScheme = processMod.getBuiltinModule('node:process');
10 
11// -------------------------------------------------------
12// Ensures the globalThis process and Buffer properties are handled correctly.
13// Placement of these at the top level scope before any thing else runs is
14// intentional. Do not move these elsewhere in the test.
15queueMicrotask(() => process);
16queueMicrotask(() => Buffer);
17process.env.QUX = 1;
18// eslint-disable-next-line @typescript-eslint/no-unused-expressions
19Buffer;
20 
21const originalProcess = process;
22globalThis.process = 123;
23assert.strictEqual(globalThis.process, 123);
24globalThis.process = originalProcess;
25assert.strictEqual(globalThis.process, process);
26// -------------------------------------------------------
27 
28const pEnv = { ...process.env };
29 
30export const processPlatform = {
31 test() {
32 assert.ok(['darwin', 'win32', 'linux'].includes(process.platform));
33 },
34};
35 
36// undefined process properties
37const processUndefinedKeys = [
38 '_channel',
39 '_disconnect',
40 '_handleQueue',
41 '_maxListeners',
42 '_pendingMessage',
43 '_send',
44 'exitCode',
45];
46 
47// functions which just return
48const processNoopKeys = [
49 '_debugEnd',
50 '_debugProcess',
51 '_startProfilerIdleNotifier',
52 '_stopProfilerIdleNotifier',
53 '_tickCallback',
54 'ref',
55 'setSourceMapsEnabled',
56 'unref',
57];
58 
59// functions which throw unsupported
60const processUnimplementedKeys = [
61 '_kill',
62 '_linkedBinding',
63 'binding',
64 'cpuUsage',
65 'dlopen',
66 'execve',
67 'getActiveResourcesInfo',
68 'hasUncaughtExceptionCaptureCallback',
69 'kill',
70 'setUncaughtExceptionCaptureCallback',
71 'threadCpuUsage',
72];
73 
74// remaining keys
75const processImplementedOrStubbedKeys = [
76 '_events',
77 '_eventsCount',
78 '_exiting',
79 '_fatalException',
80 '_getActiveHandles',
81 '_getActiveRequests',
82 '_preload_modules',
83 '_rawDebug',
84 'abort',
85 'allowedNodeEnvironmentFlags',
86 'arch',
87 'argv',
88 'argv0',
89 'assert',
90 'availableMemory',
91 'channel',
92 'chdir',
93 'config',
94 'connected',
95 'constrainedMemory',
96 'cwd',
97 'debugPort',
98 'default',
99 'domain',
100 'emitWarning',
101 'env',
102 'execArgv',
103 'execPath',
104 'exit',
105 'features',
106 'finalization',
107 'getBuiltinModule',
108 'getSourceMapsSupport',
109 'getegid',
110 'geteuid',
111 'getgid',
112 'getgroups',
113 'getuid',
114 'hrtime',
115 'initgroups',
116 'loadEnvFile',
117 'memoryUsage',
118 'moduleLoadList',
119 'nextTick',
120 'noDeprecation',
121 'openStdin',
122 'permission',
123 'pid',
124 'platform',
125 'ppid',
126 'reallyExit',
127 'release',
128 'report',
129 'resourceUsage',
130 'send',
131 'setegid',
132 'seteuid',
133 'setgid',
134 'setgroups',
135 'setuid',
136 'sourceMapsEnabled',
137 'stderr',
138 'stdin',
139 'stdout',
140 'throwDeprecation',
141 'title',
142 'traceDeprecation',
143 'umask',
144 'uptime',
145 'version',
146 'versions',
147];
148 
149const allProcessKeys = [
150 ...processUndefinedKeys,
151 ...processUnimplementedKeys,
152 ...processNoopKeys,
153 ...processImplementedOrStubbedKeys,
154].sort();
155 
156export const processKeys = {
157 test() {
158 assert.deepStrictEqual(Object.keys(processMod), allProcessKeys);
159 allProcessKeys.splice(allProcessKeys.indexOf('default'), 1);
160 assert.deepStrictEqual(Object.keys(process).sort(), allProcessKeys);
161 assert.deepStrictEqual(
162 Object.keys(processMod.default).sort(),
163 allProcessKeys
164 );
165 assert.deepStrictEqual(Object.keys(processBuiltin).sort(), allProcessKeys);
166 assert.deepStrictEqual(
167 Object.keys(processBuiltinScheme).sort(),
168 allProcessKeys
169 );
170 },
171};
172 
173export const processUndefined = {
174 test() {
175 for (const key of processUndefinedKeys) {
176 const msg = `process.${key}`;
177 assert.strictEqual(processMod[key], undefined, msg);
178 assert.strictEqual(process[key], undefined, msg);
179 assert.strictEqual(processBuiltin[key], undefined, msg);
180 assert.strictEqual(processBuiltinScheme[key], undefined, msg);
181 }
182 },
183};
184 
185export const processNoop = {
186 test() {
187 for (const key of processNoopKeys) {
188 const msg = `process.${key}`;
189 
190 assert.strictEqual(typeof processMod[key], 'function', msg);
191 assert.strictEqual(typeof process[key], 'function', msg);
192 assert.strictEqual(typeof processBuiltin[key], 'function', msg);
193 assert.strictEqual(typeof processBuiltinScheme[key], 'function', msg);
194 
195 assert.strictEqual(processMod[key](), undefined, msg);
196 assert.strictEqual(process[key](), undefined, msg);
197 assert.strictEqual(processBuiltin[key](), undefined, msg);
198 assert.strictEqual(processBuiltinScheme[key](), undefined, msg);
199 }
200 },
201};
202 
203export const processUnimplemented = {
204 test() {
205 for (const key of processUnimplementedKeys) {
206 const msg = `process.${key}`;
207 
208 assert.strictEqual(typeof processMod[key], 'function', msg);
209 assert.strictEqual(typeof process[key], 'function', msg);
210 assert.strictEqual(typeof processBuiltin[key], 'function', msg);
211 assert.strictEqual(typeof processBuiltinScheme[key], 'function', msg);
212 
213 try {
214 processMod[key]();
215 assert.fail(msg);
216 } catch (e) {
217 assert.strictEqual(e.code, 'ERR_METHOD_NOT_IMPLEMENTED', msg);
218 assert.ok(e.message.includes(key), msg);
219 }
220 try {
221 process[key]();
222 assert.fail(msg);
223 } catch (e) {
224 assert.strictEqual(e.code, 'ERR_METHOD_NOT_IMPLEMENTED', msg);
225 }
226 try {
227 processBuiltin[key]();
228 assert.fail(msg);
229 } catch (e) {
230 assert.strictEqual(e.code, 'ERR_METHOD_NOT_IMPLEMENTED', msg);
231 }
232 try {
233 processBuiltinScheme[key]();
234 assert.fail(msg);
235 } catch (e) {
236 assert.strictEqual(e.code, 'ERR_METHOD_NOT_IMPLEMENTED', msg);
237 }
238 }
239 },
240};
241 
242export const processEnv = {
243 async test(ctrl, env) {
244 assert.notDeepStrictEqual(env, process.env);
245 
246 assert.strictEqual(pEnv.FOO, 'BAR');
247 
248 // It should be possible to mutate the process.env at runtime.
249 // All values manually set are coerced to strings.
250 assert.strictEqual(pEnv.QUX, '1');
251 
252 // JSON bindings that do not parse to strings come through as
253 // raw unparsed JSON strings....
254 assert.strictEqual(pEnv.BAR, '{}');
255 JSON.parse(pEnv.BAR);
256 
257 // JSON bindings that parse as strings come through as the
258 // parsed string value.
259 assert.strictEqual(pEnv.BAZ, 'abc');
260 
261 // Throws because althought defined as a JSON binding, the value
262 // that comes through to process.env in this case is not a JSON
263 // parseable string because it will already have been parsed.
264 // This assertion is only true when the JSON bindings value
265 // happens to parse as a string.
266 assert.throws(() => JSON.parse(pEnv.BAZ));
267 
268 // JSON bindings that parse as strings that happen to be double
269 // escaped might be JSON parseable.
270 assert.strictEqual(JSON.parse(pEnv.DUB), 'abc');
271 
272 // Test that imports can see the process.env at the top level
273 const { FOO } = await import('mod');
274 assert.strictEqual(FOO, 'BAR');
275 
276 // Mutating the env argument does not change process.env, and
277 // vis versa. The reason for this is that just mutations may
278 // be entirely surprising and unexpected for users.
279 assert.strictEqual(env.QUX, undefined);
280 env.ZZZ = 'a';
281 assert.strictEqual(process.env.ZZZ, undefined);
282 
283 env.FOO = ['just some other value'];
284 assert.strictEqual(process.env.FOO, 'BAR');
285 
286 // Other kinds of bindings will be on env but not process.env
287 assert.strictEqual(pEnv.NON, undefined);
288 assert.deepStrictEqual(
289 new Uint8Array(env.NON),
290 new Uint8Array([97, 98, 99, 100, 101, 102])
291 );
292 
293 // Test process bindings delete https://github.com/nodejs/node/blob/5f7dbf45a3d3e3070d5f58f9a9c2c43dbecc8672/test/parallel/test-process-env-delete.js
294 {
295 process.env.foo = 'foo';
296 assert.strictEqual(process.env.foo, 'foo');
297 process.env.foo = undefined;
298 assert.strictEqual(process.env.foo, 'undefined');
299 
300 process.env.foo = 'foo';
301 assert.strictEqual(process.env.foo, 'foo');
302 delete process.env.foo;
303 assert.strictEqual(process.env.foo, undefined);
304 }
305 
306 // Test process env ignore getter setter https://github.com/nodejs/node/blob/5f7dbf45a3d3e3070d5f58f9a9c2c43dbecc8672/test/parallel/test-process-env-ignore-getter-setter.js
307 {
308 assert.throws(
309 () => {
310 Object.defineProperty(process.env, 'foo', {
311 value: 'foo1',
312 });
313 },
314 {
315 code: 'ERR_INVALID_ARG_VALUE',
316 name: 'TypeError',
317 }
318 );
319 
320 assert.strictEqual(process.env.foo, undefined);
321 process.env.foo = 'foo2';
322 assert.strictEqual(process.env.foo, 'foo2');
323 
324 assert.throws(
325 () => {
326 Object.defineProperty(process.env, 'goo', {
327 get() {
328 return 'goo';
329 },
330 set() {},
331 });
332 },
333 {
334 code: 'ERR_INVALID_ARG_VALUE',
335 name: 'TypeError',
336 }
337 );
338 
339 const attributes = ['configurable', 'writable', 'enumerable'];
340 
341 for (const attribute of attributes) {
342 assert.throws(
343 () => {
344 Object.defineProperty(process.env, 'goo', {
345 [attribute]: false,
346 });
347 },
348 {
349 code: 'ERR_INVALID_ARG_VALUE',
350 name: 'TypeError',
351 }
352 );
353 }
354 
355 assert.strictEqual(process.env.goo, undefined);
356 Object.defineProperty(process.env, 'goo', {
357 value: 'goo',
358 configurable: true,
359 writable: true,
360 enumerable: true,
361 });
362 assert.strictEqual(process.env.goo, 'goo');
363 }
364 
365 // Process env symbols (https://github.com/nodejs/node/blob/5f7dbf45a3d3e3070d5f58f9a9c2c43dbecc8672/test/parallel/test-process-env-symbols.js)
366 {
367 const symbol = Symbol('sym');
368 
369 // Verify that getting via a symbol key returns undefined.
370 assert.strictEqual(process.env[symbol], undefined);
371 
372 // Verify that assigning via a symbol key throws.
373 // The message depends on the JavaScript engine and so will be different between
374 // different JavaScript engines. Confirm that the `Error` is a `TypeError` only.
375 assert.throws(() => {
376 process.env[symbol] = 42;
377 }, TypeError);
378 
379 // Verify that assigning a symbol value throws.
380 // The message depends on the JavaScript engine and so will be different between
381 // different JavaScript engines. Confirm that the `Error` is a `TypeError` only.
382 assert.throws(() => {
383 process.env.foo = symbol;
384 }, TypeError);
385 
386 // Verify that using a symbol with the in operator returns false.
387 assert.strictEqual(symbol in process.env, false);
388 
389 // Verify that deleting a symbol key returns true.
390 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
391 assert.strictEqual(delete process.env[symbol], true);
392 
393 // Checks that well-known symbols like `Symbol.toStringTag` won’t throw.
394 Object.prototype.toString.call(process.env);
395 }
396 },
397};
398 
399export const processProperties = {
400 test() {
401 // Test basic process properties
402 assert.strictEqual(typeof process.title, 'string');
403 assert.ok(process.title.length > 0);
404 
405 assert.ok(Array.isArray(process.argv));
406 assert.ok(process.argv.length >= 1);
407 
408 assert.strictEqual(typeof process.arch, 'string');
409 assert.strictEqual(process.arch, 'x64');
410 
411 assert.strictEqual(typeof process.version, 'string');
412 assert.ok(process.version.startsWith('v'));
413 
414 // Test additional properties
415 assert.strictEqual(process.argv0, 'workerd');
416 assert.ok(Array.isArray(process.execArgv));
417 assert.strictEqual(process.execArgv.length, 0);
418 
419 assert.strictEqual(process.pid, 1);
420 assert.strictEqual(process.ppid, 0);
421 
422 // Test config object
423 assert.strictEqual(typeof process.config, 'object');
424 assert.strictEqual(typeof process.config.target_defaults, 'object');
425 assert.strictEqual(typeof process.config.variables, 'object');
426 
427 // Test uid/gid functions
428 assert.strictEqual(process.getegid(), 0);
429 assert.strictEqual(process.geteuid(), 0);
430 assert.throws(
431 () => {
432 process.setegid(1000);
433 },
434 { code: 'EPERM' }
435 );
436 assert.throws(
437 () => {
438 process.seteuid(1000);
439 },
440 { code: 'EPERM' }
441 );
442 process.setegid(0);
443 assert.strictEqual(process.getegid(), 0);
444 assert.strictEqual(process.geteuid(), 0);
445 
446 // Test other functions
447 process.setSourceMapsEnabled(false); // Should be no-op
448 
449 // Test allowedNodeEnvironmentFlags
450 assert.ok(process.allowedNodeEnvironmentFlags instanceof Set);
451 assert.strictEqual(process.allowedNodeEnvironmentFlags.size, 0);
452 },
453};
454 
455// Test implemented process APIs - no longer undefined
456export const processImplemented = {
457 test() {
458 // No-op functions
459 assert.strictEqual(typeof process.ref, 'function');
460 assert.strictEqual(typeof process.unref, 'function');
461 
462 // Error-throwing functions
463 assert.strictEqual(typeof process.kill, 'function');
464 assert.strictEqual(typeof process.binding, 'function');
465 assert.strictEqual(typeof process.dlopen, 'function');
466 
467 // Mock implementations
468 assert.strictEqual(typeof process.memoryUsage, 'function');
469 assert.strictEqual(typeof process.resourceUsage, 'function');
470 assert.strictEqual(typeof process.threadCpuUsage, 'function');
471 assert.strictEqual(typeof process.cpuUsage, 'function');
472 
473 // Properties with default values
474 assert.strictEqual(process.exitCode, undefined);
475 assert.strictEqual(process.channel, null);
476 assert.strictEqual(process.connected, false);
477 assert.strictEqual(typeof process.debugPort, 'number');
478 assert.strictEqual(process.noDeprecation, false);
479 assert.strictEqual(process.traceDeprecation, false);
480 assert.strictEqual(process.throwDeprecation, false);
481 assert.strictEqual(process.sourceMapsEnabled, false);
482 assert.strictEqual(typeof process.execPath, 'string');
483 
484 // Objects
485 assert.strictEqual(typeof process.permission, 'object');
486 assert.strictEqual(typeof process.release, 'object');
487 assert.strictEqual(typeof process.report, 'object');
488 assert.strictEqual(typeof process.finalization, 'object');
489 
490 // Additional APIs
491 assert.strictEqual(typeof process.constrainedMemory, 'function');
492 assert.strictEqual(typeof process.availableMemory, 'function');
493 assert.strictEqual(typeof process.send, 'function');
494 assert.strictEqual(process.send('test'), false);
495 
496 // Test that error-throwing functions actually throw
497 assert.throws(() => process.getActiveResourcesInfo(), {
498 message: /process\.getActiveResourcesInfo/,
499 });
500 assert.throws(() => process.setUncaughtExceptionCaptureCallback(), {
501 message: /process\.setUncaughtExceptionCaptureCallback/,
502 });
503 assert.throws(() => process.hasUncaughtExceptionCaptureCallback(), {
504 message: /process\.hasUncaughtExceptionCaptureCallback/,
505 });
506 assert.throws(() => process.kill(1), { message: /process\.kill/ });
507 assert.throws(() => process.binding('test'), {
508 message: /process\.binding/,
509 });
510 assert.throws(() => process.dlopen({}, 'test'), {
511 message: /process\.dlopen/,
512 });
513 },
514};
515 
516export const processVersions = {
517 test() {
518 assert.strictEqual(typeof process.versions, 'object');
519 assert.ok(process.versions !== null);
520 
521 const expectedVersions = ['node'];
522 
523 // Check that all expected versions are included and are strings
524 for (const versionKey of expectedVersions) {
525 assert.strictEqual(
526 typeof process.versions[versionKey],
527 'string',
528 `process.versions.${versionKey} should be a string`
529 );
530 }
531 },
532};
533 
534export const processFeatures = {
535 test() {
536 assert.strictEqual(typeof process.features, 'object');
537 assert.ok(process.features != null);
538 
539 // Process features should be an object that can be inspected
540 const features = Object.keys(process.features);
541 assert.ok(Array.isArray(features));
542 },
543};
544 
545export const processNextTick = {
546 async test() {
547 let called = false;
548 let order = [];
549 
550 // Test basic nextTick functionality
551 process.nextTick(() => {
552 called = true;
553 order.push('nextTick1');
554 });
555 
556 // Test multiple nextTick calls
557 process.nextTick(() => {
558 order.push('nextTick2');
559 });
560 
561 // Test nextTick with arguments
562 process.nextTick(
563 (arg1, arg2) => {
564 assert.strictEqual(arg1, 'hello');
565 assert.strictEqual(arg2, 'world');
566 order.push('nextTick3');
567 },
568 'hello',
569 'world'
570 );
571 
572 order.push('sync');
573 
574 // Wait for microtasks to complete
575 await scheduler.wait(0);
576 
577 assert.ok(called);
578 assert.deepStrictEqual(order, [
579 'sync',
580 'nextTick1',
581 'nextTick2',
582 'nextTick3',
583 ]);
584 },
585};
586 
587export const processGetBuiltinModule = {
588 test() {
589 // Should be able to get built-in modules
590 const processBuiltin = process.getBuiltinModule('node:process');
591 assert.strictEqual(typeof processBuiltin, 'object');
592 
593 // Should return null/undefined for non-existent modules
594 const nonExistent = process.getBuiltinModule('node:nonexistent');
595 assert.ok(nonExistent == null);
596 
597 // Internal modules must not be accessible via getBuiltinModule.
598 // These are BUILTIN_ONLY modules that should only be importable
599 // by other built-in modules, never by user code.
600 assert.strictEqual(
601 process.getBuiltinModule('node-internal:process'),
602 undefined
603 );
604 assert.strictEqual(
605 process.getBuiltinModule('node-internal:public_process'),
606 undefined
607 );
608 assert.strictEqual(
609 process.getBuiltinModule('node-internal:legacy_process'),
610 undefined
611 );
612 assert.strictEqual(
613 process.getBuiltinModule('node-internal:internal_timers_global_override'),
614 undefined
615 );
616 assert.strictEqual(
617 process.getBuiltinModule('cloudflare-internal:env'),
618 undefined
619 );
620 assert.strictEqual(
621 process.getBuiltinModule('cloudflare-internal:filesystem'),
622 undefined
623 );
624 },
625};
626 
627export const processEmitWarning = {
628 async test() {
629 const testMsg = 'A Warning';
630 const testCode = 'CODE001';
631 const testDetail = 'Some detail';
632 const testType = 'CustomWarning';
633 
634 let calledWarningHandler = false;
635 process.on(
636 'warning',
637 (warning) => {
638 calledWarningHandler = true;
639 assert(warning);
640 assert.match(warning.name, /^(?:Warning|CustomWarning)/);
641 assert.strictEqual(warning.message, testMsg);
642 if (warning.code) assert.strictEqual(warning.code, testCode);
643 if (warning.detail) assert.strictEqual(warning.detail, testDetail);
644 },
645 15
646 );
647 
648 class CustomWarning extends Error {
649 constructor() {
650 super();
651 this.name = testType;
652 this.message = testMsg;
653 this.code = testCode;
654 Error.captureStackTrace(this, CustomWarning);
655 }
656 }
657 
658 [
659 [testMsg],
660 [testMsg, testType],
661 [testMsg, CustomWarning],
662 [testMsg, testType, CustomWarning],
663 [testMsg, testType, testCode],
664 [testMsg, { type: testType }],
665 [testMsg, { type: testType, code: testCode }],
666 [testMsg, { type: testType, code: testCode, detail: testDetail }],
667 [new CustomWarning()],
668 // Detail will be ignored for the following. No errors thrown
669 [testMsg, { type: testType, code: testCode, detail: true }],
670 [testMsg, { type: testType, code: testCode, detail: [] }],
671 [testMsg, { type: testType, code: testCode, detail: null }],
672 [testMsg, { type: testType, code: testCode, detail: 1 }],
673 ].forEach((args) => {
674 process.emitWarning(...args);
675 });
676 
677 const warningNoToString = new CustomWarning();
678 warningNoToString.toString = null;
679 process.emitWarning(warningNoToString);
680 
681 const warningThrowToString = new CustomWarning();
682 warningThrowToString.toString = function () {
683 throw new Error('invalid toString');
684 };
685 process.emitWarning(warningThrowToString);
686 
687 // TypeError is thrown on invalid input
688 [
689 [1],
690 [{}],
691 [true],
692 [[]],
693 ['', '', {}],
694 ['', 1],
695 ['', '', 1],
696 ['', true],
697 ['', '', true],
698 ['', []],
699 ['', '', []],
700 [],
701 [undefined, 'foo', 'bar'],
702 [undefined],
703 ].forEach((args) => {
704 assert.throws(() => process.emitWarning(...args), {
705 code: 'ERR_INVALID_ARG_TYPE',
706 name: 'TypeError',
707 });
708 });
709 
710 await new Promise(process.nextTick);
711 assert(calledWarningHandler);
712 },
713};
714 
715export const processHrtime = {
716 async test() {
717 // process.hrtime
718 // https://github.com/nodejs/node/blob/5f7dbf45a3d3e3070d5f58f9a9c2c43dbecc8672/test/parallel/test-process-hrtime.js
719 {
720 // The default behavior, return an Array "tuple" of numbers
721 const tuple = process.hrtime();
722 
723 // Validate the default behavior
724 validateTuple(tuple);
725 
726 // Validate that passing an existing tuple returns another valid tuple
727 validateTuple(process.hrtime(tuple));
728 
729 // Test that only an Array may be passed to process.hrtime()
730 assert.throws(
731 () => {
732 process.hrtime(1);
733 },
734 {
735 code: 'ERR_INVALID_ARG_TYPE',
736 name: 'TypeError',
737 }
738 );
739 assert.throws(
740 () => {
741 process.hrtime([]);
742 },
743 {
744 code: 'ERR_OUT_OF_RANGE',
745 name: 'RangeError',
746 }
747 );
748 assert.throws(
749 () => {
750 process.hrtime([1]);
751 },
752 {
753 code: 'ERR_OUT_OF_RANGE',
754 name: 'RangeError',
755 }
756 );
757 assert.throws(
758 () => {
759 process.hrtime([1, 2, 3]);
760 },
761 {
762 code: 'ERR_OUT_OF_RANGE',
763 name: 'RangeError',
764 }
765 );
766 
767 function validateTuple(tuple) {
768 assert(Array.isArray(tuple));
769 assert.strictEqual(tuple.length, 2);
770 assert(Number.isInteger(tuple[0]));
771 assert(Number.isInteger(tuple[1]));
772 }
773 
774 const diff = process.hrtime([0, 1e9 - 1]);
775 assert(diff[1] >= 0); // https://github.com/nodejs/node/issues/4751
776 }
777 
778 // process.hrtime.bigint
779 // https://github.com/nodejs/node/blob/5f7dbf45a3d3e3070d5f58f9a9c2c43dbecc8672/test/parallel/test-process-hrtime-bigint.js
780 {
781 const start = process.hrtime.bigint();
782 
783 await scheduler.wait(1000);
784 
785 const end = process.hrtime.bigint();
786 assert.strictEqual(typeof end, 'bigint');
787 
788 assert(end - start >= 0n);
789 
790 // Ideally, this should be closer to 1000, or we could test
791 // a smaller interval, but this is to work around the
792 // test runner time accuracy.
793 assert(end - start >= 1_000_000n);
794 }
795 },
796};
797 
798const basicValidEnv = `BASIC=overriden
799`;
800 
801const validEnv = `BASIC=basic
802
803# COMMENTS=work
804#BASIC=basic2
805#BASIC=basic3
806
807# previous line intentionally left blank
808AFTER_LINE=after_line
809A="B=C"
810B=C=D
811EMPTY=
812EMPTY_SINGLE_QUOTES=''
813EMPTY_DOUBLE_QUOTES=""
814EMPTY_BACKTICKS=\`\`
815SINGLE_QUOTES='single_quotes'
816SINGLE_QUOTES_SPACED=' single quotes '
817DOUBLE_QUOTES="double_quotes"
818DOUBLE_QUOTES_SPACED=" double quotes "
819DOUBLE_QUOTES_INSIDE_SINGLE='double "quotes" work inside single quotes'
820DOUBLE_QUOTES_WITH_NO_SPACE_BRACKET="{ port: $MONGOLAB_PORT}"
821SINGLE_QUOTES_INSIDE_DOUBLE="single 'quotes' work inside double quotes"
822BACKTICKS_INSIDE_SINGLE='\`backticks\` work inside single quotes'
823BACKTICKS_INSIDE_DOUBLE="\`backticks\` work inside double quotes"
824BACKTICKS=\`backticks\`
825BACKTICKS_SPACED=\` backticks \`
826DOUBLE_QUOTES_INSIDE_BACKTICKS=\`double "quotes" work inside backticks\`
827SINGLE_QUOTES_INSIDE_BACKTICKS=\`single 'quotes' work inside backticks\`
828DOUBLE_AND_SINGLE_QUOTES_INSIDE_BACKTICKS=\`double "quotes" and single 'quotes' work inside backticks\`
829EXPAND_NEWLINES="expand\\nnew\\nlines"
830DONT_EXPAND_UNQUOTED=dontexpand\\nnewlines
831DONT_EXPAND_SQUOTED='dontexpand\\nnewlines'
832# COMMENTS=work
833INLINE_COMMENTS=inline comments # work #very #well
834INLINE_COMMENTS_SINGLE_QUOTES='inline comments outside of #singlequotes' # work
835INLINE_COMMENTS_DOUBLE_QUOTES="inline comments outside of #doublequotes" # work
836INLINE_COMMENTS_BACKTICKS=\`inline comments outside of #backticks\` # work
837INLINE_COMMENTS_SPACE=inline comments start with a#number sign. no space required.
838EQUAL_SIGNS=equals==
839RETAIN_INNER_QUOTES={"foo": "bar"}
840RETAIN_INNER_QUOTES_AS_STRING='{"foo": "bar"}'
841RETAIN_INNER_QUOTES_AS_BACKTICKS=\`{"foo": "bar's"}\`
842TRIM_SPACE_FROM_UNQUOTED= some spaced out string
843SPACE_BEFORE_DOUBLE_QUOTES= "space before double quotes"
844EMAIL=therealnerdybeast@example.tld
845 SPACED_KEY = parsed
846EDGE_CASE_INLINE_COMMENTS="VALUE1" # or "VALUE2" or "VALUE3"
847
848MULTI_DOUBLE_QUOTED="THIS
849IS
850A
851MULTILINE
852STRING"
853
854MULTI_SINGLE_QUOTED='THIS
855IS
856A
857MULTILINE
858STRING'
859
860MULTI_BACKTICKED=\`THIS
861IS
862A
863"MULTILINE'S"
864STRING\`
865export EXPORT_EXAMPLE = ignore export
866
867MULTI_NOT_VALID_QUOTE="
868MULTI_NOT_VALID=THIS
869IS NOT MULTILINE`;
870 
871// process.loadEnvFile
872// https://github.com/nodejs/node/blob/5f7dbf45a3d3e3070d5f58f9a9c2c43dbecc8672/test/parallel/test-process-load-env-file.js
873export const processLoadEnvFile = {
874 async test() {
875 const basicValidEnvFilePath = '/tmp/basic-valid.env';
876 const validEnvFilePath = '/tmp/valid.env';
877 const missingEnvFilePath =
878 '/tmp/dir%20with unusual"chars \'åß∂ƒ©∆¬…`/non-existent-file.env';
879 
880 // Test prep: write the basic env file and valid env file
881 writeFileSync(basicValidEnvFilePath, basicValidEnv);
882 writeFileSync(validEnvFilePath, validEnv);
883 
884 // supports passing path
885 {
886 process.loadEnvFile(validEnvFilePath);
887 assert.strictEqual(process.env.BASIC, 'basic');
888 }
889 
890 // supports not-passing a path
891 {
892 // Uses `/tmp/.env` file.
893 try {
894 process.loadEnvFile();
895 assert.fail();
896 } catch (e) {
897 assert.strictEqual(e.code, 'ENOENT');
898 // TODO(soon): Enable once `path` is supported on ENOENT
899 // assert.strictEqual(e.path, '/bundle/.env');
900 }
901 }
902 
903 // fails on missing paths
904 {
905 try {
906 process.loadEnvFile(missingEnvFilePath);
907 } catch (e) {
908 assert.strictEqual(e.code, 'ENOENT');
909 // TODO(soon): Enable once `path` is supported on ENOENT errors
910 // assert.strictEqual(e.path, missingEnvFile);
911 }
912 }
913 
914 // should override
915 {
916 process.loadEnvFile(basicValidEnvFilePath);
917 assert.strictEqual(process.env.BASIC, 'overriden');
918 }
919 
920 // supports cwd
921 {
922 const originalCwd = process.cwd();
923 process.chdir('/tmp');
924 writeFileSync('.env', validEnv);
925 try {
926 process.loadEnvFile();
927 } finally {
928 process.chdir(originalCwd);
929 }
930 }
931 },
932};
933 
934export const processRejectionListeners = {
935 async test() {
936 const e = new Error();
937 
938 const { promise: unhandledPromise, resolve } = Promise.withResolvers();
939 process.on('unhandledRejection', (reason, promise) => {
940 resolve({ reason, promise });
941 });
942 Promise.reject(e);
943 const { reason, promise } = await unhandledPromise;
944 assert.strictEqual(reason, e);
945 
946 {
947 const { promise: handledPromise, resolve } = Promise.withResolvers();
948 process.on('rejectionHandled', (promise) => {
949 resolve({ promise });
950 });
951 await new Promise((resolve) => promise.catch(resolve));
952 const { promise: promise2 } = await handledPromise;
953 assert.strictEqual(promise, promise2);
954 }
955 },
956};
957 
958// init time process.cwd checks
959assert.strictEqual(process.cwd(), '/bundle');
960process.chdir('/');
961assert.deepStrictEqual(readdirSync('.'), ['bundle', 'tmp', 'dev']);
962 
963export const processCwd = {
964 test() {
965 assert.strictEqual(process.cwd(), '/bundle');
966 
967 const originalCwd = process.cwd();
968 
969 process.chdir('/tmp');
970 assert.strictEqual(process.cwd(), '/tmp');
971 writeFileSync('foo', 'foo');
972 
973 process.chdir(originalCwd);
974 assert.strictEqual(process.cwd(), originalCwd);
975 
976 assert.throws(
977 () => {
978 readFileSync('foo');
979 },
980 { code: 'ENOENT' }
981 );
982 
983 assert.strictEqual(readFileSync('/tmp/foo', 'utf8'), 'foo');
984 
985 assert.throws(
986 () => {
987 process.chdir('/nonexistent/directory');
988 },
989 { code: 'ENOENT' }
990 );
991 },
992};
993 
994export const processCwdRelative = {
995 test() {
996 const originalCwd = process.cwd();
997 
998 // Test relative path navigation
999 process.chdir('/tmp');
1000 assert.strictEqual(process.cwd(), '/tmp');
1001 
1002 // Test going up from /tmp (should work if parent exists)
1003 try {
1004 process.chdir('..');
1005 const newCwd = process.cwd();
1006 assert.strictEqual(newCwd, '/');
1007 } catch (e) {
1008 // If parent doesn't exist, that's fine for this test
1009 if (e.code !== 'ENOENT') {
1010 throw e;
1011 }
1012 }
1013 
1014 // Test relative path from root
1015 process.chdir('/');
1016 process.chdir('tmp');
1017 assert.strictEqual(process.cwd(), '/tmp');
1018 
1019 // Test current directory "."
1020 process.chdir('.');
1021 assert.strictEqual(process.cwd(), '/tmp');
1022 
1023 // Restore original directory
1024 process.chdir(originalCwd);
1025 assert.strictEqual(process.cwd(), originalCwd);
1026 },
1027};
1028 
1029export const processCwdBadInput = {
1030 test() {
1031 const longPath = 'a'.repeat(4097); // Just over the path length limit
1032 assert.throws(
1033 () => {
1034 process.chdir(longPath);
1035 },
1036 { code: 'ENAMETOOLONG' }
1037 );
1038 
1039 try {
1040 process.chdir('/tmp/basic-valid.env');
1041 assert.fail('Expected chdir to throw an error');
1042 } catch (err) {
1043 assert.strictEqual(err.code, 'ENOENT');
1044 }
1045 
1046 assert.throws(
1047 () => {
1048 process.chdir('');
1049 },
1050 { code: 'ENOENT' }
1051 );
1052 },
1053};
1054 
1055export const processUmask = {
1056 test() {
1057 assert.strictEqual(typeof process.umask, 'function');
1058 
1059 assert.strictEqual(process.umask(), 18);
1060 
1061 assert.strictEqual(process.umask(0), 18);
1062 assert.strictEqual(process.umask(0o022), 18);
1063 assert.strictEqual(process.umask(0o755), 18);
1064 assert.strictEqual(process.umask(0xffffffff), 18);
1065 
1066 assert.strictEqual(process.umask('0'), 18);
1067 assert.strictEqual(process.umask('022'), 18);
1068 assert.strictEqual(process.umask('755'), 18);
1069 assert.strictEqual(process.umask('37777777777'), 18); // max 32-bit octal
1070 
1071 assert.throws(() => process.umask('8'), { code: 'ERR_INVALID_ARG_VALUE' });
1072 assert.throws(() => process.umask('9'), { code: 'ERR_INVALID_ARG_VALUE' });
1073 assert.throws(() => process.umask('abc'), {
1074 code: 'ERR_INVALID_ARG_VALUE',
1075 });
1076 assert.throws(() => process.umask('0x123'), {
1077 code: 'ERR_INVALID_ARG_VALUE',
1078 });
1079 assert.throws(() => process.umask(''), { code: 'ERR_INVALID_ARG_VALUE' });
1080 
1081 assert.throws(() => process.umask(-1), { code: 'ERR_INVALID_ARG_VALUE' });
1082 assert.throws(() => process.umask(1.5), { code: 'ERR_INVALID_ARG_VALUE' });
1083 assert.throws(
1084 () => process.umask(0x100000000), // 2^32
1085 { code: 'ERR_INVALID_ARG_VALUE' }
1086 );
1087 assert.throws(() => process.umask(NaN), { code: 'ERR_INVALID_ARG_VALUE' });
1088 assert.throws(() => process.umask(Infinity), {
1089 code: 'ERR_INVALID_ARG_VALUE',
1090 });
1091 
1092 assert.throws(() => process.umask({}), { code: 'ERR_INVALID_ARG_TYPE' });
1093 assert.throws(() => process.umask([]), { code: 'ERR_INVALID_ARG_TYPE' });
1094 assert.throws(() => process.umask(null), { code: 'ERR_INVALID_ARG_TYPE' });
1095 assert.throws(() => process.umask(true), { code: 'ERR_INVALID_ARG_TYPE' });
1096 
1097 assert.throws(
1098 () => process.umask('40000000000'), // > 32-bit max octal
1099 { code: 'ERR_INVALID_ARG_VALUE' }
1100 );
1101 },
1102};
1103 
1104export const processStdio = {
1105 test() {
1106 assert.ok(process.stdout, 'process.stdout should exist');
1107 assert.ok(process.stderr, 'process.stderr should exist');
1108 
1109 assert.ok(process.stdout.writable, 'process.stdout should be writable');
1110 assert.ok(process.stderr.writable, 'process.stderr should be writable');
1111 
1112 assert.strictEqual(
1113 typeof process.stdout.write,
1114 'function',
1115 'process.stdout.write should be a function'
1116 );
1117 assert.strictEqual(
1118 typeof process.stderr.write,
1119 'function',
1120 'process.stderr.write should be a function'
1121 );
1122 
1123 assert.notStrictEqual(
1124 process.stdout,
1125 process.stderr,
1126 'stdout and stderr should be different objects'
1127 );
1128 
1129 assert.doesNotThrow(() => {
1130 process.stdout.write('test stdout');
1131 process.stderr.write('test stderr');
1132 }, 'Writing to stdio streams should not throw');
1133 
1134 assert.ok(process.stdin, 'process.stdin should exist');
1135 assert.ok(process.stdin.readable, 'process.stdin should be readable');
1136 assert.strictEqual(process.stdin.read(), null);
1137 
1138 assert.strictEqual(
1139 process.stdout.isTTY,
1140 undefined,
1141 'process.stdout.isTTY should be undefined'
1142 );
1143 assert(!('isTTY' in process.stdin));
1144 assert(!('isTTY' in process.stdout));
1145 assert(!('isTTY' in process.stderr));
1146 
1147 assert.strictEqual(process.stdin.fd, 0, 'process.stdin.fd should be 0');
1148 assert.strictEqual(process.stdout.fd, 1, 'process.stdout.fd should be 1');
1149 assert.strictEqual(process.stderr.fd, 2, 'process.stderr.fd should be 2');
1150 },
1151};
1152 
1153export const processAssert = {
1154 test() {
1155 assert.ok('assert' in process);
1156 assert.notStrictEqual(process.assert, undefined);
1157 assert.strictEqual(typeof process.assert, 'function');
1158 },
1159};
1160 
1161export const processToStringTag = {
1162 test() {
1163 assert.strictEqual(
1164 Object.prototype.toString.call(process),
1165 '[object process]'
1166 );
1167 },
1168};
1169 
1170export const processGetReport = {
1171 test() {
1172 assert.deepStrictEqual(process.report.getReport(), {});
1173 },
1174};