• 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.ok(/\bAssertionError\b.*\bUnexpected global\b.*\bgc\b/.test(stderr));
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  common.mustCall(function() {}, 'foo');
55}, /^TypeError: Invalid exact value: foo$/);
56
57assert.throws(function() {
58  common.mustCall(function() {}, /foo/);
59}, /^TypeError: Invalid exact value: \/foo\/$/);
60
61assert.throws(function() {
62  common.mustCallAtLeast(function() {}, /foo/);
63}, /^TypeError: Invalid minimum value: \/foo\/$/);
64
65// assert.fail() tests
66assert.throws(
67  () => { assert.fail('fhqwhgads'); },
68  {
69    code: 'ERR_ASSERTION',
70    message: /^fhqwhgads$/
71  });
72
73const fnOnce = common.mustCall(() => {});
74fnOnce();
75const fnTwice = common.mustCall(() => {}, 2);
76fnTwice();
77fnTwice();
78const fnAtLeast1Called1 = common.mustCallAtLeast(() => {}, 1);
79fnAtLeast1Called1();
80const fnAtLeast1Called2 = common.mustCallAtLeast(() => {}, 1);
81fnAtLeast1Called2();
82fnAtLeast1Called2();
83const fnAtLeast2Called2 = common.mustCallAtLeast(() => {}, 2);
84fnAtLeast2Called2();
85fnAtLeast2Called2();
86const fnAtLeast2Called3 = common.mustCallAtLeast(() => {}, 2);
87fnAtLeast2Called3();
88fnAtLeast2Called3();
89fnAtLeast2Called3();
90
91const failFixtures = [
92  [
93    fixtures.path('failmustcall1.js'),
94    'Mismatched <anonymous> function calls. Expected exactly 2, actual 1.',
95  ], [
96    fixtures.path('failmustcall2.js'),
97    'Mismatched <anonymous> function calls. Expected at least 2, actual 1.',
98  ],
99];
100for (const p of failFixtures) {
101  const [file, expected] = p;
102  execFile(process.execPath, [file], common.mustCall((err, stdout, stderr) => {
103    assert.ok(err);
104    assert.strictEqual(stderr, '');
105    const firstLine = stdout.split('\n').shift();
106    assert.strictEqual(firstLine, expected);
107  }));
108}
109
110// hijackStderr and hijackStdout
111const HIJACK_TEST_ARRAY = [ 'foo\n', 'bar\n', 'baz\n' ];
112[ 'err', 'out' ].forEach((txt) => {
113  const stream = process[`std${txt}`];
114  const originalWrite = stream.write;
115
116  hijackstdio[`hijackStd${txt}`](common.mustCall(function(data) {
117    assert.strictEqual(data, HIJACK_TEST_ARRAY[stream.writeTimes]);
118  }, HIJACK_TEST_ARRAY.length));
119  assert.notStrictEqual(originalWrite, stream.write);
120
121  HIJACK_TEST_ARRAY.forEach((val) => {
122    stream.write(val, common.mustCall());
123  });
124
125  assert.strictEqual(HIJACK_TEST_ARRAY.length, stream.writeTimes);
126  hijackstdio[`restoreStd${txt}`]();
127  assert.strictEqual(originalWrite, stream.write);
128});
129
130// Test `tmpdir`.
131{
132  tmpdir.refresh();
133  assert.ok(/\.tmp\.\d+/.test(tmpdir.path));
134  const sentinelPath = join(tmpdir.path, 'gaga');
135  writeFileSync(sentinelPath, 'googoo');
136  tmpdir.refresh();
137  assert.strictEqual(existsSync(tmpdir.path), true);
138  assert.strictEqual(existsSync(sentinelPath), false);
139}
140
141// hijackStderr and hijackStdout again for console
142// Must be last, since it uses `process.on('uncaughtException')`
143{
144  [['err', 'error'], ['out', 'log']].forEach(([type, method]) => {
145    hijackstdio[`hijackStd${type}`](common.mustCall(function(data) {
146      assert.strictEqual(data, 'test\n');
147
148      // throw an error
149      throw new Error(`console ${type} error`);
150    }));
151
152    console[method]('test');
153    hijackstdio[`restoreStd${type}`]();
154  });
155
156  let uncaughtTimes = 0;
157  process.on('uncaughtException', common.mustCallAtLeast(function(e) {
158    assert.strictEqual(uncaughtTimes < 2, true);
159    assert.strictEqual(e instanceof Error, true);
160    assert.strictEqual(
161      e.message,
162      `console ${(['err', 'out'])[uncaughtTimes++]} error`);
163  }, 2));
164}  // End of "Must be last".
165