• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23const common = require('../common');
24const hijackstdio = require('../common/hijackstdio');
25const fixtures = require('../common/fixtures');
26const tmpdir = require('../common/tmpdir');
27const assert = require('assert');
28const { execFile } = require('child_process');
29const { writeFileSync, existsSync } = require('fs');
30const { join } = require('path');
31
32// Test for leaked global detection
33{
34  const p = fixtures.path('leakedGlobal.js');
35  execFile(process.execPath, [p], common.mustCall((err, stdout, stderr) => {
36    assert.notStrictEqual(err.code, 0);
37    assert.match(stderr, /\bAssertionError\b.*\bUnexpected global\b.*\bgc\b/);
38  }));
39}
40
41// Test for disabling leaked global detection
42{
43  const p = fixtures.path('leakedGlobal.js');
44  execFile(process.execPath, [p], {
45    env: { ...process.env, NODE_TEST_KNOWN_GLOBALS: 0 }
46  }, common.mustCall((err, stdout, stderr) => {
47    assert.strictEqual(err, null);
48    assert.strictEqual(stderr.trim(), '');
49  }));
50}
51
52// common.mustCall() tests
53assert.throws(function() {
54  // eslint-disable-next-line no-restricted-syntax
55  common.mustCall(function() {}, 'foo');
56}, /^TypeError: Invalid exact value: foo$/);
57
58assert.throws(function() {
59  // eslint-disable-next-line no-restricted-syntax
60  common.mustCall(function() {}, /foo/);
61}, /^TypeError: Invalid exact value: \/foo\/$/);
62
63assert.throws(function() {
64  // eslint-disable-next-line no-restricted-syntax
65  common.mustCallAtLeast(function() {}, /foo/);
66}, /^TypeError: Invalid minimum value: \/foo\/$/);
67
68// assert.fail() tests
69assert.throws(
70  () => { assert.fail('fhqwhgads'); },
71  {
72    code: 'ERR_ASSERTION',
73    message: /^fhqwhgads$/
74  });
75
76const fnOnce = common.mustCall();
77fnOnce();
78const fnTwice = common.mustCall(2);
79fnTwice();
80fnTwice();
81const fnAtLeast1Called1 = common.mustCallAtLeast(1);
82fnAtLeast1Called1();
83const fnAtLeast1Called2 = common.mustCallAtLeast(1);
84fnAtLeast1Called2();
85fnAtLeast1Called2();
86const fnAtLeast2Called2 = common.mustCallAtLeast(2);
87fnAtLeast2Called2();
88fnAtLeast2Called2();
89const fnAtLeast2Called3 = common.mustCallAtLeast(2);
90fnAtLeast2Called3();
91fnAtLeast2Called3();
92fnAtLeast2Called3();
93
94const failFixtures = [
95  [
96    fixtures.path('failmustcall1.js'),
97    'Mismatched <anonymous> function calls. Expected exactly 2, actual 1.',
98  ], [
99    fixtures.path('failmustcall2.js'),
100    'Mismatched <anonymous> function calls. Expected at least 2, actual 1.',
101  ],
102];
103for (const p of failFixtures) {
104  const [file, expected] = p;
105  execFile(process.execPath, [file], common.mustCall((err, stdout, stderr) => {
106    assert.ok(err);
107    assert.strictEqual(stderr, '');
108    const firstLine = stdout.split('\n').shift();
109    assert.strictEqual(firstLine, expected);
110  }));
111}
112
113// hijackStderr and hijackStdout
114const HIJACK_TEST_ARRAY = [ 'foo\n', 'bar\n', 'baz\n' ];
115[ 'err', 'out' ].forEach((txt) => {
116  const stream = process[`std${txt}`];
117  const originalWrite = stream.write;
118
119  hijackstdio[`hijackStd${txt}`](common.mustCall(function(data) {
120    assert.strictEqual(data, HIJACK_TEST_ARRAY[stream.writeTimes]);
121  }, HIJACK_TEST_ARRAY.length));
122  assert.notStrictEqual(originalWrite, stream.write);
123
124  HIJACK_TEST_ARRAY.forEach((val) => {
125    stream.write(val, common.mustCall());
126  });
127
128  assert.strictEqual(HIJACK_TEST_ARRAY.length, stream.writeTimes);
129  hijackstdio[`restoreStd${txt}`]();
130  assert.strictEqual(originalWrite, stream.write);
131});
132
133// Test `tmpdir`.
134{
135  tmpdir.refresh();
136  assert.match(tmpdir.path, /\.tmp\.\d+/);
137  const sentinelPath = join(tmpdir.path, 'gaga');
138  writeFileSync(sentinelPath, 'googoo');
139  tmpdir.refresh();
140  assert.strictEqual(existsSync(tmpdir.path), true);
141  assert.strictEqual(existsSync(sentinelPath), false);
142}
143
144// hijackStderr and hijackStdout again for console
145// Must be last, since it uses `process.on('uncaughtException')`
146{
147  [['err', 'error'], ['out', 'log']].forEach(([type, method]) => {
148    hijackstdio[`hijackStd${type}`](common.mustCall(function(data) {
149      assert.strictEqual(data, 'test\n');
150
151      // throw an error
152      throw new Error(`console ${type} error`);
153    }));
154
155    console[method]('test');
156    hijackstdio[`restoreStd${type}`]();
157  });
158
159  let uncaughtTimes = 0;
160  process.on('uncaughtException', common.mustCallAtLeast(function(e) {
161    assert.strictEqual(uncaughtTimes < 2, true);
162    assert.strictEqual(e instanceof Error, true);
163    assert.strictEqual(
164      e.message,
165      `console ${(['err', 'out'])[uncaughtTimes++]} error`);
166  }, 2));
167}  // End of "Must be last".
168