Copy some node tests (#13458)

This commit is contained in:
Jarred Sumner
2024-08-21 23:09:09 -07:00
committed by GitHub
parent 83a256013f
commit 1bac09488d
77 changed files with 3778 additions and 0 deletions

View File

@@ -441,6 +441,8 @@ async function spawnBun(execPath, { args, cwd, timeout, env, stdout, stderr }) {
BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0",
BUN_INSTALL_CACHE_DIR: tmpdirPath,
SHELLOPTS: isWindows ? "igncr" : undefined, // ignore "\r" on Windows
// Used in Node.js tests.
TEST_TMPDIR: tmpdirPath,
};
if (env) {
Object.assign(bunEnv, env);

2
test/bunfig.toml Normal file
View File

@@ -0,0 +1,2 @@
[test]
preload = "./preload.ts"

View File

@@ -1264,3 +1264,11 @@ https://buildkite.com/docs/pipelines/security/secrets/buildkite-secrets`;
return value;
}
// Make it easier to run some node tests.
Object.defineProperty(globalThis, "gc", {
value: Bun.gc,
writable: true,
enumerable: false,
configurable: true,
});

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,42 @@
//#FILE: test-fs-readdir-recursive.js
//#SHA1: daa6ac8e46cd3d530e4546354a11f87f1b1c092d
//-----------------
'use strict';
const fs = require('fs');
const net = require('net');
const path = require('path');
const os = require('os');
const tmpdir = path.join(os.tmpdir(), 'node-test-fs-readdir-recursive');
beforeAll(() => {
// Refresh tmpdir
if (fs.existsSync(tmpdir)) {
fs.rmSync(tmpdir, { recursive: true, force: true });
}
fs.mkdirSync(tmpdir, { recursive: true });
});
afterAll(() => {
// Clean up tmpdir
fs.rmSync(tmpdir, { recursive: true, force: true });
});
test('fs.readdirSync with recursive option should not crash', (done) => {
const server = net.createServer().listen(
path.join(tmpdir, 'test.sock'),
() => {
// The process should not crash
// See https://github.com/nodejs/node/issues/52159
expect(() => {
fs.readdirSync(tmpdir, { recursive: true });
}).not.toThrow();
server.close();
done();
}
);
});
//<#END_FILE: test-fs-readdir-recursive.js

View File

@@ -0,0 +1,82 @@
//#FILE: test-fs-readdir.js
//#SHA1: ce2c5a12cb271c5023f965afe712e78b1a484ad5
//-----------------
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
const readdirDir = path.join(os.tmpdir(), 'test-fs-readdir');
const files = ['empty', 'files', 'for', 'just', 'testing'];
beforeAll(() => {
// Make sure tmp directory is clean
if (fs.existsSync(readdirDir)) {
fs.rmSync(readdirDir, { recursive: true, force: true });
}
fs.mkdirSync(readdirDir, { recursive: true });
// Create the necessary files
files.forEach((currentFile) => {
fs.closeSync(fs.openSync(path.join(readdirDir, currentFile), 'w'));
});
});
afterAll(() => {
// Clean up
fs.rmSync(readdirDir, { recursive: true, force: true });
});
test('fs.readdirSync returns correct files', () => {
expect(fs.readdirSync(readdirDir).sort()).toEqual(files);
});
test('fs.readdir returns correct files', async () => {
await new Promise((resolve) => {
fs.readdir(readdirDir, (err, f) => {
expect(err).toBeNull();
expect(f.sort()).toEqual(files);
resolve();
});
});
});
test('fs.readdirSync throws ENOTDIR on file', () => {
expect(() => {
fs.readdirSync(__filename);
}).toThrow(expect.objectContaining({
code: 'ENOTDIR',
message: expect.any(String)
}));
});
test('fs.readdir throws ENOTDIR on file', async () => {
await new Promise((resolve) => {
fs.readdir(__filename, (e) => {
expect(e).toEqual(expect.objectContaining({
code: 'ENOTDIR',
message: expect.any(String)
}));
resolve();
});
});
});
test('fs.readdir and fs.readdirSync throw on invalid input', () => {
[false, 1, [], {}, null, undefined].forEach((i) => {
expect(() => fs.readdir(i, () => {})).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
expect(() => fs.readdirSync(i)).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
});
});
//<#END_FILE: test-fs-readdir.js

View File

@@ -0,0 +1,52 @@
//#FILE: test-fs-readfile-unlink.js
//#SHA1: a7107747d7901dfcc1ffd0e7adbf548412a1016a
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
// Test that unlink succeeds immediately after readFile completes.
test('unlink succeeds immediately after readFile completes', async () => {
const tmpdir = path.join(os.tmpdir(), 'node-test-fs-readfile-unlink');
await fs.promises.mkdir(tmpdir, { recursive: true });
const fileName = path.join(tmpdir, 'test.bin');
const buf = Buffer.alloc(512 * 1024, 42);
await fs.promises.writeFile(fileName, buf);
const data = await fs.promises.readFile(fileName);
expect(data.length).toBe(buf.length);
expect(data[0]).toBe(42);
// Unlink should not throw. This is part of the test. It used to throw on
// Windows due to a bug.
await expect(fs.promises.unlink(fileName)).resolves.toBeUndefined();
});
//<#END_FILE: test-fs-readfile-unlink.js

View File

@@ -0,0 +1,61 @@
//#FILE: test-fs-readfile-zero-byte-liar.js
//#SHA1: ddca2f114cf32b03f36405a21c81058e7a1f0c18
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const fs = require('fs');
// Test that readFile works even when stat returns size 0.
const dataExpected = fs.readFileSync(__filename, 'utf8');
// Sometimes stat returns size=0, but it's a lie.
fs._fstat = fs.fstat;
fs._fstatSync = fs.fstatSync;
fs.fstat = (fd, cb) => {
fs._fstat(fd, (er, st) => {
if (er) return cb(er);
st.size = 0;
return cb(er, st);
});
};
fs.fstatSync = (fd) => {
const st = fs._fstatSync(fd);
st.size = 0;
return st;
};
test('readFileSync works with zero byte liar', () => {
const d = fs.readFileSync(__filename, 'utf8');
expect(d).toBe(dataExpected);
});
test('readFile works with zero byte liar', async () => {
const d = await fs.promises.readFile(__filename, 'utf8');
expect(d).toBe(dataExpected);
});
//<#END_FILE: test-fs-readfile-zero-byte-liar.js

View File

@@ -0,0 +1,26 @@
//#FILE: test-fs-readlink-type-check.js
//#SHA1: dd36bda8e12e6c22c342325345dd8d1de2097d9c
//-----------------
'use strict';
const fs = require('fs');
[false, 1, {}, [], null, undefined].forEach((i) => {
test(`fs.readlink throws for invalid input: ${JSON.stringify(i)}`, () => {
expect(() => fs.readlink(i, jest.fn())).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
});
test(`fs.readlinkSync throws for invalid input: ${JSON.stringify(i)}`, () => {
expect(() => fs.readlinkSync(i)).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
});
});
//<#END_FILE: test-fs-readlink-type-check.js

View File

@@ -0,0 +1,69 @@
//#FILE: test-fs-readv-promises.js
//#SHA1: 43d801fa8a2eabf438e98f5aa713eb9680fe798b
//-----------------
'use strict';
const fs = require('fs').promises;
const path = require('path');
const os = require('os');
const expected = 'ümlaut. Лорем 運務ホソモ指及 आपको करने विकास 紙読決多密所 أضف';
const expectedBuff = Buffer.from(expected);
let cnt = 0;
function getFileName() {
return path.join(os.tmpdir(), `readv_promises_${++cnt}.txt`);
}
const allocateEmptyBuffers = (combinedLength) => {
const bufferArr = [];
// Allocate two buffers, each half the size of expectedBuff
bufferArr[0] = Buffer.alloc(Math.floor(combinedLength / 2));
bufferArr[1] = Buffer.alloc(combinedLength - bufferArr[0].length);
return bufferArr;
};
describe('fs.promises.readv', () => {
beforeEach(() => {
cnt = 0;
});
test('readv with position', async () => {
const filename = getFileName();
await fs.writeFile(filename, expectedBuff);
const handle = await fs.open(filename, 'r');
const bufferArr = allocateEmptyBuffers(expectedBuff.length);
const expectedLength = expectedBuff.length;
let { bytesRead, buffers } = await handle.readv([Buffer.from('')], null);
expect(bytesRead).toBe(0);
expect(buffers).toEqual([Buffer.from('')]);
({ bytesRead, buffers } = await handle.readv(bufferArr, null));
expect(bytesRead).toBe(expectedLength);
expect(buffers).toEqual(bufferArr);
expect(Buffer.concat(bufferArr)).toEqual(await fs.readFile(filename));
await handle.close();
});
test('readv without position', async () => {
const filename = getFileName();
await fs.writeFile(filename, expectedBuff);
const handle = await fs.open(filename, 'r');
const bufferArr = allocateEmptyBuffers(expectedBuff.length);
const expectedLength = expectedBuff.length;
let { bytesRead, buffers } = await handle.readv([Buffer.from('')]);
expect(bytesRead).toBe(0);
expect(buffers).toEqual([Buffer.from('')]);
({ bytesRead, buffers } = await handle.readv(bufferArr));
expect(bytesRead).toBe(expectedLength);
expect(buffers).toEqual(bufferArr);
expect(Buffer.concat(bufferArr)).toEqual(await fs.readFile(filename));
await handle.close();
});
});
//<#END_FILE: test-fs-readv-promises.js

View File

@@ -0,0 +1,100 @@
//#FILE: test-fs-readv-sync.js
//#SHA1: e9a4527b118e4a814a04c976eaafb5127f7c7c9d
//-----------------
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
const expected = 'ümlaut. Лорем 運務ホソモ指及 आपको करने विकास 紙読決多密所 أضف';
const exptectedBuff = Buffer.from(expected);
const expectedLength = exptectedBuff.length;
let filename;
let tmpdir;
beforeAll(() => {
tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-fs-readv-sync-'));
filename = path.join(tmpdir, 'readv_sync.txt');
fs.writeFileSync(filename, exptectedBuff);
});
afterAll(() => {
fs.rmSync(tmpdir, { recursive: true, force: true });
});
const allocateEmptyBuffers = (combinedLength) => {
const bufferArr = [];
// Allocate two buffers, each half the size of exptectedBuff
bufferArr[0] = Buffer.alloc(Math.floor(combinedLength / 2));
bufferArr[1] = Buffer.alloc(combinedLength - bufferArr[0].length);
return bufferArr;
};
// fs.readvSync with array of buffers with all parameters
test('fs.readvSync with array of buffers with all parameters', () => {
const fd = fs.openSync(filename, 'r');
const bufferArr = allocateEmptyBuffers(exptectedBuff.length);
let read = fs.readvSync(fd, [Buffer.from('')], 0);
expect(read).toBe(0);
read = fs.readvSync(fd, bufferArr, 0);
expect(read).toBe(expectedLength);
fs.closeSync(fd);
expect(Buffer.concat(bufferArr)).toEqual(fs.readFileSync(filename));
});
// fs.readvSync with array of buffers without position
test('fs.readvSync with array of buffers without position', () => {
const fd = fs.openSync(filename, 'r');
const bufferArr = allocateEmptyBuffers(exptectedBuff.length);
let read = fs.readvSync(fd, [Buffer.from('')]);
expect(read).toBe(0);
read = fs.readvSync(fd, bufferArr);
expect(read).toBe(expectedLength);
fs.closeSync(fd);
expect(Buffer.concat(bufferArr)).toEqual(fs.readFileSync(filename));
});
/**
* Testing with incorrect arguments
*/
const wrongInputs = [false, 'test', {}, [{}], ['sdf'], null, undefined];
test('fs.readvSync with incorrect arguments', () => {
const fd = fs.openSync(filename, 'r');
for (const wrongInput of wrongInputs) {
expect(() => fs.readvSync(fd, wrongInput, null)).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
}
fs.closeSync(fd);
});
test('fs.readvSync with wrong fd argument', () => {
for (const wrongInput of wrongInputs) {
expect(() => fs.readvSync(wrongInput)).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
}
});
//<#END_FILE: test-fs-readv-sync.js

View File

@@ -0,0 +1,106 @@
//#FILE: test-fs-readv.js
//#SHA1: 07d6fe434017163aea491c98db8127bc2c942b96
//-----------------
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
const expected = 'ümlaut. Лорем 運務ホソモ指及 आपको करने विकास 紙読決多密所 أضف';
let cnt = 0;
const getFileName = () => path.join(os.tmpdir(), `readv_${++cnt}.txt`);
const expectedBuff = Buffer.from(expected);
const allocateEmptyBuffers = (combinedLength) => {
const bufferArr = [];
// Allocate two buffers, each half the size of expectedBuff
bufferArr[0] = Buffer.alloc(Math.floor(combinedLength / 2));
bufferArr[1] = Buffer.alloc(combinedLength - bufferArr[0].length);
return bufferArr;
};
const getCallback = (fd, bufferArr) => {
return (err, bytesRead, buffers) => {
expect(err).toBeNull();
expect(bufferArr).toEqual(buffers);
const expectedLength = expectedBuff.length;
expect(bytesRead).toBe(expectedLength);
fs.closeSync(fd);
expect(Buffer.concat(bufferArr).equals(expectedBuff)).toBe(true);
};
};
beforeEach(() => {
jest.spyOn(fs, 'writeSync');
jest.spyOn(fs, 'writeFileSync');
jest.spyOn(fs, 'openSync');
jest.spyOn(fs, 'closeSync');
});
afterEach(() => {
jest.restoreAllMocks();
});
test('fs.readv with array of buffers with all parameters', (done) => {
const filename = getFileName();
const fd = fs.openSync(filename, 'w+');
fs.writeSync(fd, expectedBuff);
const bufferArr = allocateEmptyBuffers(expectedBuff.length);
const callback = getCallback(fd, bufferArr);
fs.readv(fd, bufferArr, 0, (err, bytesRead, buffers) => {
callback(err, bytesRead, buffers);
done();
});
});
test('fs.readv with array of buffers without position', (done) => {
const filename = getFileName();
fs.writeFileSync(filename, expectedBuff);
const fd = fs.openSync(filename, 'r');
const bufferArr = allocateEmptyBuffers(expectedBuff.length);
const callback = getCallback(fd, bufferArr);
fs.readv(fd, bufferArr, (err, bytesRead, buffers) => {
callback(err, bytesRead, buffers);
done();
});
});
describe('Testing with incorrect arguments', () => {
const wrongInputs = [false, 'test', {}, [{}], ['sdf'], null, undefined];
test('fs.readv with wrong buffers argument', () => {
const filename = getFileName();
fs.writeFileSync(filename, expectedBuff);
const fd = fs.openSync(filename, 'r');
for (const wrongInput of wrongInputs) {
expect(() => fs.readv(fd, wrongInput, null, jest.fn())).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
}
fs.closeSync(fd);
});
test('fs.readv with wrong fd argument', () => {
for (const wrongInput of wrongInputs) {
expect(() => fs.readv(wrongInput, jest.fn())).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
}
});
});
//<#END_FILE: test-fs-readv.js

View File

@@ -0,0 +1,47 @@
//#FILE: test-fs-realpath-pipe.js
//#SHA1: 2a876967f5134cd77e2214f2abcbf753d46983cf
//-----------------
'use strict';
const { spawnSync } = require('child_process');
// Skip test for Windows, AIX, and IBMi
const isSkippedPlatform = ['win32', 'aix', 'os400'].includes(process.platform);
const testName = `No /dev/stdin on ${process.platform}.`;
(isSkippedPlatform ? test.skip : test)(testName, () => {
const testCases = [
`require('fs').realpath('/dev/stdin', (err, resolvedPath) => {
if (err) {
console.error(err);
process.exit(1);
}
if (resolvedPath) {
process.exit(2);
}
});`,
`try {
if (require('fs').realpathSync('/dev/stdin')) {
process.exit(2);
}
} catch (e) {
console.error(e);
process.exit(1);
}`
];
for (const code of testCases) {
const child = spawnSync(process.execPath, ['-e', code], {
stdio: 'pipe'
});
if (child.status !== 2) {
console.log(code);
console.log(child.stderr.toString());
}
expect(child.status).toBe(2);
}
});
//<#END_FILE: test-fs-realpath-pipe.js

View File

@@ -0,0 +1,24 @@
//#FILE: test-fs-rmdir-type-check.js
//#SHA1: 2a00191160af6f0f76a82dcaef31d13c9b223d3b
//-----------------
'use strict';
const fs = require('fs');
test('fs.rmdir and fs.rmdirSync with invalid arguments', () => {
[false, 1, [], {}, null, undefined].forEach((i) => {
expect(() => fs.rmdir(i, jest.fn())).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
expect(() => fs.rmdirSync(i)).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
});
});
//<#END_FILE: test-fs-rmdir-type-check.js

View File

@@ -0,0 +1,84 @@
//#FILE: test-fs-stream-double-close.js
//#SHA1: 25fa219f7ee462e67611751f996393afc1869490
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
const tmpdir = path.join(os.tmpdir(), 'node-test-fs-stream-double-close');
beforeAll(() => {
if (!fs.existsSync(tmpdir)) {
fs.mkdirSync(tmpdir, { recursive: true });
}
});
afterAll(() => {
fs.rmSync(tmpdir, { recursive: true, force: true });
});
test('test1 with ReadStream', () => {
test1(fs.createReadStream(__filename));
});
test('test2 with ReadStream', () => {
test2(fs.createReadStream(__filename));
});
test('test3 with ReadStream', () => {
test3(fs.createReadStream(__filename));
});
test('test1 with WriteStream', () => {
test1(fs.createWriteStream(path.join(tmpdir, 'dummy1')));
});
test('test2 with WriteStream', () => {
test2(fs.createWriteStream(path.join(tmpdir, 'dummy2')));
});
test('test3 with WriteStream', () => {
test3(fs.createWriteStream(path.join(tmpdir, 'dummy3')));
});
function test1(stream) {
stream.destroy();
stream.destroy();
}
function test2(stream) {
stream.destroy();
stream.on('open', jest.fn());
}
function test3(stream) {
const openHandler = jest.fn();
stream.on('open', openHandler);
stream.emit('open');
expect(openHandler).toHaveBeenCalledTimes(1);
stream.destroy();
stream.destroy();
}
//<#END_FILE: test-fs-stream-double-close.js

View File

@@ -0,0 +1,148 @@
//#FILE: test-fs-symlink.js
//#SHA1: 4861a453e314d789a1b933d7179da96b7a35378c
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
const canCreateSymLink = () => {
try {
fs.symlinkSync('', '');
fs.unlinkSync('');
return true;
} catch (e) {
return false;
}
};
if (!canCreateSymLink()) {
it.skip('insufficient privileges', () => {});
} else {
let linkTime;
let fileTime;
const tmpdir = os.tmpdir();
beforeEach(() => {
jest.spyOn(fs, 'symlink');
jest.spyOn(fs, 'lstat');
jest.spyOn(fs, 'stat');
jest.spyOn(fs, 'readlink');
});
afterEach(() => {
jest.restoreAllMocks();
});
test('Test creating and reading symbolic link', async () => {
const linkData = path.resolve(__dirname, '../fixtures/cycles/root.js');
const linkPath = path.resolve(tmpdir, 'symlink1.js');
await new Promise((resolve) => {
fs.symlink(linkData, linkPath, resolve);
});
expect(fs.symlink).toHaveBeenCalled();
await new Promise((resolve) => {
fs.lstat(linkPath, (err, stats) => {
expect(err).toBeNull();
linkTime = stats.mtime.getTime();
resolve();
});
});
await new Promise((resolve) => {
fs.stat(linkPath, (err, stats) => {
expect(err).toBeNull();
fileTime = stats.mtime.getTime();
resolve();
});
});
await new Promise((resolve) => {
fs.readlink(linkPath, (err, destination) => {
expect(err).toBeNull();
expect(destination).toBe(linkData);
resolve();
});
});
});
test('Test invalid symlink', async () => {
const linkData = path.resolve(__dirname, '../fixtures/not/exists/file');
const linkPath = path.resolve(tmpdir, 'symlink2.js');
await new Promise((resolve) => {
fs.symlink(linkData, linkPath, resolve);
});
expect(fs.existsSync(linkPath)).toBe(false);
});
test('Test invalid inputs', () => {
const invalidInputs = [false, 1, {}, [], null, undefined];
const errObj = expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.stringMatching(/target|path/)
});
invalidInputs.forEach((input) => {
expect(() => fs.symlink(input, '', () => {})).toThrow(errObj);
expect(() => fs.symlinkSync(input, '')).toThrow(errObj);
expect(() => fs.symlink('', input, () => {})).toThrow(errObj);
expect(() => fs.symlinkSync('', input)).toThrow(errObj);
});
});
test('Test invalid type inputs', () => {
const errObj = expect.objectContaining({
code: 'ERR_INVALID_ARG_VALUE',
name: 'TypeError',
});
expect(() => fs.symlink('', '', '🍏', () => {})).toThrow(errObj);
expect(() => fs.symlinkSync('', '', '🍏')).toThrow(errObj);
expect(() => fs.symlink('', '', 'nonExistentType', () => {})).toThrow(errObj);
expect(() => fs.symlinkSync('', '', 'nonExistentType')).toThrow(errObj);
expect(fs.promises.symlink('', '', 'nonExistentType')).rejects.toMatchObject(errObj);
expect(() => fs.symlink('', '', false, () => {})).toThrow(errObj);
expect(() => fs.symlinkSync('', '', false)).toThrow(errObj);
expect(fs.promises.symlink('', '', false)).rejects.toMatchObject(errObj);
expect(() => fs.symlink('', '', {}, () => {})).toThrow(errObj);
expect(() => fs.symlinkSync('', '', {})).toThrow(errObj);
expect(fs.promises.symlink('', '', {})).rejects.toMatchObject(errObj);
});
test('Link time should not be equal to file time', () => {
expect(linkTime).not.toBe(fileTime);
});
}
//<#END_FILE: test-fs-symlink.js

View File

@@ -0,0 +1,67 @@
//#FILE: test-fs-truncate-clear-file-zero.js
//#SHA1: 28aa057c9903ea2436c340ccecfec093c647714c
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
// This test ensures that `fs.truncate` opens the file with `r+` and not `w`,
// which had earlier resulted in the target file's content getting zeroed out.
// https://github.com/nodejs/node-v0.x-archive/issues/6233
const filename = path.join(os.tmpdir(), 'truncate-file.txt');
beforeEach(() => {
// Clean up any existing test file
try {
fs.unlinkSync(filename);
} catch (err) {
if (err.code !== 'ENOENT') throw err;
}
});
test('fs.truncateSync', () => {
fs.writeFileSync(filename, '0123456789');
expect(fs.readFileSync(filename, 'utf8')).toBe('0123456789');
fs.truncateSync(filename, 5);
expect(fs.readFileSync(filename, 'utf8')).toBe('01234');
});
test('fs.truncate', async () => {
fs.writeFileSync(filename, '0123456789');
expect(fs.readFileSync(filename, 'utf8')).toBe('0123456789');
await new Promise((resolve, reject) => {
fs.truncate(filename, 5, (err) => {
if (err) reject(err);
else resolve();
});
});
expect(fs.readFileSync(filename, 'utf8')).toBe('01234');
});
//<#END_FILE: test-fs-truncate-clear-file-zero.js

View File

@@ -0,0 +1,26 @@
//#FILE: test-fs-unlink-type-check.js
//#SHA1: 337e42f3b15589a7652c32c0a1c92292abf098d0
//-----------------
'use strict';
const fs = require('fs');
test('fs.unlink and fs.unlinkSync with invalid types', () => {
const invalidTypes = [false, 1, {}, [], null, undefined];
invalidTypes.forEach((invalidType) => {
expect(() => fs.unlink(invalidType, jest.fn())).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
expect(() => fs.unlinkSync(invalidType)).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
});
});
//<#END_FILE: test-fs-unlink-type-check.js

View File

@@ -0,0 +1,62 @@
//#FILE: test-fs-watch-close-when-destroyed.js
//#SHA1: f062b7243d0c42722a289a6228d4c2c1a503be1b
//-----------------
'use strict';
// This tests that closing a watcher when the underlying handle is
// already destroyed will result in a noop instead of a crash.
const fs = require('fs');
const path = require('path');
const os = require('os');
// fs-watch on folders have limited capability in AIX.
// The testcase makes use of folder watching, and causes
// hang. This behavior is documented. Skip this for AIX.
if (process.platform === 'aix') {
it.skip('folder watch capability is limited in AIX.');
} else if (process.platform === 'os400') {
it.skip('IBMi does not support `fs.watch()`');
} else {
let root;
beforeEach(() => {
root = path.join(os.tmpdir(), 'watched-directory-' + Math.random().toString(36).slice(2));
fs.mkdirSync(root);
});
afterEach(() => {
try {
fs.rmdirSync(root);
} catch (error) {
// Ignore errors, directory might already be removed
}
});
it('should not crash when closing watcher after handle is destroyed', (done) => {
const watcher = fs.watch(root, { persistent: false, recursive: false });
// The following listeners may or may not be invoked.
watcher.addListener('error', () => {
setTimeout(
() => { watcher.close(); }, // Should not crash if it's invoked
10
);
});
watcher.addListener('change', () => {
setTimeout(
() => { watcher.close(); },
10
);
});
fs.rmdirSync(root);
// Wait for the listener to hit
setTimeout(done, 100);
});
}
//<#END_FILE: test-fs-watch-close-when-destroyed.js

View File

@@ -0,0 +1,65 @@
//#FILE: test-fs-watch-file-enoent-after-deletion.js
//#SHA1: d6c93db608d119bd35fcab0e1e9307bfd6558b68
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
// Make sure the deletion event gets reported in the following scenario:
// 1. Watch a file.
// 2. The initial stat() goes okay.
// 3. Something deletes the watched file.
// 4. The second stat() fails with ENOENT.
// The second stat() translates into the first 'change' event but a logic error
// stopped it from getting emitted.
// https://github.com/nodejs/node-v0.x-archive/issues/4027
test('fs.watchFile reports deletion', (done) => {
const tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-'));
const filename = path.join(tmpdir, 'watched');
fs.writeFileSync(filename, 'quis custodiet ipsos custodes');
const watcher = jest.fn();
fs.watchFile(filename, { interval: 50 }, watcher);
setTimeout(() => {
fs.unlinkSync(filename);
setTimeout(() => {
expect(watcher).toHaveBeenCalledTimes(1);
const [curr, prev] = watcher.mock.calls[0];
expect(curr.nlink).toBe(0);
expect(prev.nlink).toBe(1);
fs.unwatchFile(filename);
fs.rmdirSync(tmpdir);
done();
}, 100);
}, 100);
});
//<#END_FILE: test-fs-watch-file-enoent-after-deletion.js

View File

@@ -0,0 +1,55 @@
//#FILE: test-fs-watch-recursive-add-file-with-url.js
//#SHA1: e6498ea80abdf69cb66d888bbd7d631931970c0a
//-----------------
'use strict';
const { setTimeout } = require('timers/promises');
const path = require('path');
const fs = require('fs');
const { pathToFileURL } = require('url');
const os = require('os');
const isIBMi = process.platform === 'os400';
const isAIX = process.platform === 'aix';
if (isIBMi) {
it.skip('IBMi does not support `fs.watch()`', () => {});
} else if (isAIX) {
it.skip('folder watch capability is limited in AIX.', () => {});
} else {
it('should watch for file changes using URL as path', async () => {
const testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-'));
// Add a file to already watching folder, and use URL as the path
const rootDirectory = fs.mkdtempSync(path.join(testDir, path.sep));
const testDirectory = path.join(rootDirectory, 'test-5');
fs.mkdirSync(testDirectory);
const filePath = path.join(testDirectory, 'file-8.txt');
const url = pathToFileURL(testDirectory);
const watcher = fs.watch(url, { recursive: true });
let watcherClosed = false;
const watchPromise = new Promise((resolve) => {
watcher.on('change', function(event, filename) {
expect(event).toBe('rename');
if (filename === path.basename(filePath)) {
watcher.close();
watcherClosed = true;
resolve();
}
});
});
await setTimeout(100);
fs.writeFileSync(filePath, 'world');
await watchPromise;
expect(watcherClosed).toBe(true);
}, 10000); // Increase timeout to 10 seconds
}
//<#END_FILE: test-fs-watch-recursive-add-file-with-url.js

View File

@@ -0,0 +1,60 @@
//#FILE: test-fs-watch-recursive-add-file.js
//#SHA1: e87d2c9f4789a6e6a83fbdca56e39683625bd0af
//-----------------
'use strict';
const path = require('path');
const fs = require('fs');
const os = require('os');
const isIBMi = os.platform() === 'os400';
const isAIX = os.platform() === 'aix';
if (isIBMi) {
it.skip('IBMi does not support `fs.watch()`', () => {});
} else if (isAIX) {
it.skip('folder watch capability is limited in AIX.', () => {});
} else {
const tmpdir = {
path: path.join(os.tmpdir(), 'jest-test-fs-watch-recursive-add-file'),
refresh: () => {
if (fs.existsSync(tmpdir.path)) {
fs.rmSync(tmpdir.path, { recursive: true, force: true });
}
fs.mkdirSync(tmpdir.path, { recursive: true });
}
};
beforeEach(() => {
tmpdir.refresh();
});
it('should detect file added to already watching folder', (done) => {
const rootDirectory = fs.mkdtempSync(tmpdir.path + path.sep);
const testDirectory = path.join(rootDirectory, 'test-1');
fs.mkdirSync(testDirectory);
const testFile = path.join(testDirectory, 'file-1.txt');
const watcher = fs.watch(testDirectory, { recursive: true });
let watcherClosed = false;
watcher.on('change', function(event, filename) {
expect(event).toBe('rename');
if (filename === path.basename(testFile)) {
watcher.close();
watcherClosed = true;
expect(watcherClosed).toBe(true);
done();
}
});
// Do the write with a delay to ensure that the OS is ready to notify us.
setTimeout(() => {
fs.writeFileSync(testFile, 'world');
}, process.platform === 'win32' ? 200 : 100);
});
}
//<#END_FILE: test-fs-watch-recursive-add-file.js

View File

@@ -0,0 +1,59 @@
//#FILE: test-fs-watch-recursive-add-folder.js
//#SHA1: 4c2908ccc8502f5f760963a9b9a6db6ddadd4c1c
//-----------------
'use strict';
const { setTimeout } = require('timers/promises');
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const os = require('os');
const isIBMi = os.platform() === 'os400';
const isAIX = os.platform() === 'aix';
if (isIBMi) {
it.skip('IBMi does not support `fs.watch()`', () => {});
} else if (isAIX) {
it.skip('folder watch capability is limited in AIX.', () => {});
} else {
const testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-'));
afterAll(() => {
fs.rmSync(testDir, { recursive: true, force: true });
});
test('Add a folder to already watching folder', async () => {
// Add a folder to already watching folder
const rootDirectory = fs.mkdtempSync(path.join(testDir, 'root-'));
const testDirectory = path.join(rootDirectory, 'test-2');
fs.mkdirSync(testDirectory);
const testFile = path.join(testDirectory, 'folder-2');
const watcher = fs.watch(testDirectory, { recursive: true });
let watcherClosed = false;
const watchPromise = new Promise((resolve) => {
watcher.on('change', function(event, filename) {
expect(event).toBe('rename');
if (filename === path.basename(testFile)) {
watcher.close();
watcherClosed = true;
resolve();
}
});
});
await setTimeout(100);
fs.mkdirSync(testFile);
await watchPromise;
expect(watcherClosed).toBe(true);
});
}
//<#END_FILE: test-fs-watch-recursive-add-folder.js

View File

@@ -0,0 +1,52 @@
//#FILE: test-fs-watch-recursive-linux-parallel-remove.js
//#SHA1: ed10536d8d54febe24a3dcf494a26eab06bc4f66
//-----------------
'use strict';
const path = require('node:path');
const fs = require('node:fs');
const { spawn } = require('node:child_process');
const os = require('node:os');
// Skip test if not running on Linux
if (os.platform() !== 'linux') {
test.skip('This test can run only on Linux', () => {});
} else {
// Test that the watcher do not crash if the file "disappears" while
// watch is being set up.
let testDir;
let watcher;
beforeEach(() => {
testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-'));
});
afterEach(() => {
if (watcher) {
watcher.close();
}
fs.rmSync(testDir, { recursive: true, force: true });
});
test('fs.watch does not crash on parallel file removal', (done) => {
watcher = fs.watch(testDir, { recursive: true });
watcher.on('change', function(event, filename) {
// This console.log makes the error happen
// do not remove
console.log(filename, event);
});
const testFile = path.join(testDir, 'a');
const child = spawn(process.argv[0], ['-e', `const fs = require('node:fs'); for (let i = 0; i < 10000; i++) { const fd = fs.openSync('${testFile}', 'w'); fs.writeSync(fd, Buffer.from('hello')); fs.rmSync('${testFile}') }`], {
stdio: 'inherit'
});
child.on('exit', function() {
watcher.close();
done();
});
});
}
//<#END_FILE: test-fs-watch-recursive-linux-parallel-remove.js

View File

@@ -0,0 +1,47 @@
//#FILE: test-fs-watch-recursive-validate.js
//#SHA1: eb5d9ff1caac7f9d4acf694c43e4f634f538befb
//-----------------
'use strict';
const path = require('path');
const fs = require('fs');
const os = require('os');
const isIBMi = process.platform === 'os400';
const isAIX = process.platform === 'aix';
const isWindows = process.platform === 'win32';
const isOSX = process.platform === 'darwin';
if (isIBMi) {
test.skip('IBMi does not support `fs.watch()`', () => {});
} else if (isAIX) {
test.skip('folder watch capability is limited in AIX.', () => {});
} else {
const tmpdir = {
path: path.join(os.tmpdir(), 'jest-fs-watch-recursive-validate'),
refresh: () => {
if (fs.existsSync(tmpdir.path)) {
fs.rmSync(tmpdir.path, { recursive: true, force: true });
}
fs.mkdirSync(tmpdir.path, { recursive: true });
},
};
beforeEach(() => {
tmpdir.refresh();
});
test('Handle non-boolean values for options.recursive', async () => {
if (!isWindows && !isOSX) {
expect(() => {
const testsubdir = fs.mkdtempSync(tmpdir.path + path.sep);
fs.watch(testsubdir, { recursive: '1' });
}).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
message: expect.any(String)
}));
}
});
}
//<#END_FILE: test-fs-watch-recursive-validate.js

View File

@@ -0,0 +1,66 @@
//#FILE: test-fs-watch-recursive-watch-file.js
//#SHA1: 1f06958f6f645cb5c80b424a24b046f107ab83ae
//-----------------
'use strict';
const path = require('path');
const fs = require('fs');
const os = require('os');
const isIBMi = os.platform() === 'os400';
const isAIX = os.platform() === 'aix';
if (isIBMi) {
test.skip('IBMi does not support `fs.watch()`');
}
// fs-watch on folders have limited capability in AIX.
// The testcase makes use of folder watching, and causes
// hang. This behavior is documented. Skip this for AIX.
if (isAIX) {
test.skip('folder watch capability is limited in AIX.');
}
const platformTimeout = (ms) => ms * (process.platform === 'win32' ? 2 : 1);
test('Watch a file (not a folder) using fs.watch', async () => {
// Create a temporary directory for testing
const testDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'test-'));
const rootDirectory = await fs.promises.mkdtemp(path.join(testDir, path.sep));
const testDirectory = path.join(rootDirectory, 'test-6');
await fs.promises.mkdir(testDirectory);
const filePath = path.join(testDirectory, 'only-file.txt');
await fs.promises.writeFile(filePath, 'hello');
let watcherClosed = false;
let interval;
const watcher = fs.watch(filePath, { recursive: true });
const watchPromise = new Promise((resolve) => {
watcher.on('change', function(event, filename) {
expect(event).toBe('change');
if (filename === path.basename(filePath)) {
clearInterval(interval);
interval = null;
watcher.close();
watcherClosed = true;
resolve();
}
});
});
interval = setInterval(() => {
fs.writeFileSync(filePath, 'world');
}, platformTimeout(10));
await watchPromise;
expect(watcherClosed).toBe(true);
expect(interval).toBeNull();
});
//<#END_FILE: test-fs-watch-recursive-watch-file.js

View File

@@ -0,0 +1,29 @@
//#FILE: test-fs-watch-ref-unref.js
//#SHA1: ffceabfd7f8fef655b05735b8bba7fb059609980
//-----------------
'use strict';
const fs = require('fs');
if (process.platform === 'os400') {
test.skip('IBMi does not support `fs.watch()`');
}
test('fs.watch() can be unref()ed and ref()ed', () => {
const watcher = fs.watch(__filename, () => {
// This callback should not be called
expect(true).toBe(false);
});
watcher.unref();
return new Promise((resolve) => {
setTimeout(() => {
watcher.ref();
watcher.unref();
resolve();
}, process.platform === 'win32' ? 100 : 50);
});
});
//<#END_FILE: test-fs-watch-ref-unref.js

View File

@@ -0,0 +1,27 @@
//#FILE: test-fs-watch-stop-sync.js
//#SHA1: 8285d2bd43d2f9be7be525417cf51f9336b2f379
//-----------------
'use strict';
// This test checks that the `stop` event is emitted asynchronously.
//
// If it isn't asynchronous, then the listener will be called during the
// execution of `watch.stop()`. That would be a bug.
//
// If it is asynchronous, then the listener will be removed before the event is
// emitted.
const fs = require('fs');
test('stop event is emitted asynchronously', () => {
const listener = jest.fn();
const watch = fs.watchFile(__filename, jest.fn());
watch.once('stop', listener);
watch.stop();
watch.removeListener('stop', listener);
expect(listener).not.toHaveBeenCalled();
});
//<#END_FILE: test-fs-watch-stop-sync.js

View File

@@ -0,0 +1,70 @@
//#FILE: test-fs-write-file-buffer.js
//#SHA1: f721ad0f6969d6cf1ba78f96ccf9600a7f93458d
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const fs = require('fs');
const path = require('path');
let data = [
'/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcH',
'Bw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/',
'2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e',
'Hh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAQABADASIAAhEBAxEB/8QA',
'HwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUF',
'BAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK',
'FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1',
'dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG',
'x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEB',
'AQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAEC',
'AxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRom',
'JygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOE',
'hYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU',
'1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDhfBUFl/wk',
'OmPqKJJZw3aiZFBw4z93jnkkc9u9dj8XLfSI/EBt7DTo7ea2Ox5YXVo5FC7g',
'Tjq24nJPXNVtO0KATRvNHCIg3zoWJWQHqp+o4pun+EtJ0zxBq8mnLJa2d1L5',
'0NvnKRjJBUE5PAx3NYxxUY0pRtvYHSc5Ka2X9d7H/9k='];
data = data.join('\n');
let tmpdir;
beforeEach(() => {
tmpdir = fs.mkdtempSync(path.join(process.env.TEST_TMPDIR || '/tmp', 'test-fs-write-file-buffer-'));
});
afterEach(() => {
fs.rmSync(tmpdir, { recursive: true, force: true });
});
test('writeFileSync with Buffer', () => {
const buf = Buffer.from(data, 'base64');
const testFile = path.join(tmpdir, 'test.jpg');
fs.writeFileSync(testFile, buf);
expect(fs.existsSync(testFile)).toBe(true);
expect(fs.readFileSync(testFile)).toEqual(buf);
});
//<#END_FILE: test-fs-write-file-buffer.js

View File

@@ -0,0 +1,25 @@
//#FILE: test-fs-write-no-fd.js
//#SHA1: eade06241743a0d7e72b5239633e1ddd947f3a28
//-----------------
'use strict';
const fs = require('fs');
test('fs.write with null fd and Buffer throws TypeError', () => {
expect(() => {
fs.write(null, Buffer.allocUnsafe(1), 0, 1, () => {});
}).toThrow(expect.objectContaining({
name: 'TypeError',
message: expect.any(String)
}));
});
test('fs.write with null fd and string throws TypeError', () => {
expect(() => {
fs.write(null, '1', 0, 1, () => {});
}).toThrow(expect.objectContaining({
name: 'TypeError',
message: expect.any(String)
}));
});
//<#END_FILE: test-fs-write-no-fd.js

View File

@@ -0,0 +1,38 @@
//#FILE: test-fs-write-stream-close-without-callback.js
//#SHA1: 63e0c345b440c8cfb157aa84340f387cf314e20f
//-----------------
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
const tmpdir = path.join(os.tmpdir(), 'test-fs-write-stream-close-without-callback');
beforeEach(() => {
// Create a fresh temporary directory before each test
if (!fs.existsSync(tmpdir)) {
fs.mkdirSync(tmpdir, { recursive: true });
}
});
afterEach(() => {
// Clean up the temporary directory after each test
if (fs.existsSync(tmpdir)) {
fs.rmSync(tmpdir, { recursive: true, force: true });
}
});
test('fs.WriteStream can be closed without a callback', () => {
const filePath = path.join(tmpdir, 'nocallback');
const s = fs.createWriteStream(filePath);
s.end('hello world');
s.close();
// We don't need to assert anything here as the test is checking
// that the above operations don't throw an error
expect(true).toBe(true);
});
//<#END_FILE: test-fs-write-stream-close-without-callback.js

View File

@@ -0,0 +1,76 @@
//#FILE: test-fs-write-stream-end.js
//#SHA1: a4194cfb1f416f5fddd5edc55b7d867db14a5320
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const fs = require('fs');
const path = require('path');
const tmpdir = path.join(__dirname, 'tmp');
beforeAll(() => {
if (!fs.existsSync(tmpdir)) {
fs.mkdirSync(tmpdir, { recursive: true });
}
});
afterAll(() => {
fs.rmSync(tmpdir, { recursive: true, force: true });
});
test('end without data', (done) => {
const file = path.join(tmpdir, 'write-end-test0.txt');
const stream = fs.createWriteStream(file);
stream.end();
stream.on('close', () => {
done();
});
});
test('end with data', (done) => {
const file = path.join(tmpdir, 'write-end-test1.txt');
const stream = fs.createWriteStream(file);
stream.end('a\n', 'utf8');
stream.on('close', () => {
const content = fs.readFileSync(file, 'utf8');
expect(content).toBe('a\n');
done();
});
});
test('end triggers open and finish events', (done) => {
const file = path.join(tmpdir, 'write-end-test2.txt');
const stream = fs.createWriteStream(file);
stream.end();
let calledOpen = false;
stream.on('open', () => {
calledOpen = true;
});
stream.on('finish', () => {
expect(calledOpen).toBe(true);
done();
});
});
//<#END_FILE: test-fs-write-stream-end.js

View File

@@ -0,0 +1,66 @@
//#FILE: test-fs-write-sync.js
//#SHA1: 4ae5fa7550eefe258b9c1de798f4a4092e9d15d1
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
const filename = path.join(os.tmpdir(), 'write.txt');
beforeEach(() => {
try {
fs.unlinkSync(filename);
} catch (err) {
// Ignore errors if file doesn't exist
}
});
test('fs.writeSync with various parameter combinations', () => {
const parameters = [Buffer.from('bár'), 0, Buffer.byteLength('bár')];
// The first time fs.writeSync is called with all parameters provided.
// After that, each pop in the cycle removes the final parameter. So:
// - The 2nd time fs.writeSync with a buffer, without the length parameter.
// - The 3rd time fs.writeSync with a buffer, without the offset and length
// parameters.
while (parameters.length > 0) {
const fd = fs.openSync(filename, 'w');
let written = fs.writeSync(fd, '');
expect(written).toBe(0);
fs.writeSync(fd, 'foo');
written = fs.writeSync(fd, ...parameters);
expect(written).toBeGreaterThan(3);
fs.closeSync(fd);
expect(fs.readFileSync(filename, 'utf-8')).toBe('foobár');
parameters.pop();
}
});
//<#END_FILE: test-fs-write-sync.js

View File

@@ -0,0 +1,43 @@
//#FILE: test-fs-writestream-open-write.js
//#SHA1: a4cb8508ae1f366c94442a43312a817f00b68de6
//-----------------
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
// Regression test for https://github.com/nodejs/node/issues/51993
let tmpdir;
beforeEach(() => {
tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-fs-writestream-open-write-'));
});
afterEach(() => {
fs.rmSync(tmpdir, { recursive: true, force: true });
});
test('fs.createWriteStream opens and writes correctly', (done) => {
const file = path.join(tmpdir, 'test-fs-writestream-open-write.txt');
const w = fs.createWriteStream(file);
w.on('open', () => {
w.write('hello');
process.nextTick(() => {
w.write('world');
w.end();
});
});
w.on('close', () => {
expect(fs.readFileSync(file, 'utf8')).toBe('helloworld');
fs.unlinkSync(file);
done();
});
});
//<#END_FILE: test-fs-writestream-open-write.js

View File

@@ -0,0 +1,36 @@
//#FILE: test-http-upgrade-reconsume-stream.js
//#SHA1: 4117d0b2212d192173b5bd6bf2ef7fe82f627079
//-----------------
"use strict";
const tls = require("tls");
const http = require("http");
// Tests that, after the HTTP parser stopped owning a socket that emits an
// 'upgrade' event, another C++ stream can start owning it (e.g. a TLSSocket).
test("HTTP upgrade and TLSSocket creation", done => {
const server = http.createServer(expect.any(Function));
server.on("upgrade", (request, socket, head) => {
// This should not crash.
new tls.TLSSocket(socket);
server.close();
socket.destroy();
done();
});
server.listen(0, () => {
http
.get({
port: server.address().port,
headers: {
"Connection": "Upgrade",
"Upgrade": "websocket",
},
})
.on("error", () => {});
});
});
//<#END_FILE: test-http-upgrade-reconsume-stream.js

View File

@@ -0,0 +1,59 @@
//#FILE: test-http-url.parse-auth-with-header-in-request.js
//#SHA1: 396adc5e441a57d24b11a42513c834b6b11ea7ff
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const http = require("http");
const url = require("url");
test("http url parse auth with header in request", async () => {
function check(request) {
// The correct authorization header is be passed
expect(request.headers.authorization).toBe("NoAuthForYOU");
}
const server = http.createServer((request, response) => {
// Run the check function
check(request);
response.writeHead(200, {});
response.end("ok");
server.close();
});
await new Promise(resolve => {
server.listen(0, () => {
const testURL = url.parse(`http://asdf:qwer@localhost:${server.address().port}`);
// The test here is if you set a specific authorization header in the
// request we should not override that with basic auth
testURL.headers = {
Authorization: "NoAuthForYOU",
};
// make the request
http.request(testURL).end();
resolve();
});
});
});
//<#END_FILE: test-http-url.parse-auth-with-header-in-request.js

View File

@@ -0,0 +1,56 @@
//#FILE: test-http-url.parse-auth.js
//#SHA1: 97f9b1c737c705489b2d6402750034291a9f6f63
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const http = require("http");
const url = require("url");
test("HTTP URL parse auth", async () => {
function check(request) {
// The correct authorization header is be passed
expect(request.headers.authorization).toBe("Basic dXNlcjpwYXNzOg==");
}
const server = http.createServer((request, response) => {
// Run the check function
check(request);
response.writeHead(200, {});
response.end("ok");
server.close();
});
await new Promise(resolve => {
server.listen(0, () => {
const port = server.address().port;
// username = "user", password = "pass:"
const testURL = url.parse(`http://user:pass%3A@localhost:${port}`);
// make the request
http.request(testURL).end();
resolve();
});
});
});
//<#END_FILE: test-http-url.parse-auth.js

View File

@@ -0,0 +1,65 @@
//#FILE: test-http-url.parse-basic.js
//#SHA1: f2f2841de1c82e38067e73196926090f350d89c6
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const http = require("http");
const url = require("url");
let testURL;
// Make sure the basics work
function check(request) {
// Default method should still be 'GET'
expect(request.method).toBe("GET");
// There are no URL params, so you should not see any
expect(request.url).toBe("/");
// The host header should use the url.parse.hostname
expect(request.headers.host).toBe(`${testURL.hostname}:${testURL.port}`);
}
test("HTTP URL parsing basics", async () => {
const server = http.createServer((request, response) => {
// Run the check function
check(request);
response.writeHead(200, {});
response.end("ok");
server.close();
});
await new Promise(resolve => {
server.listen(0, () => {
testURL = url.parse(`http://localhost:${server.address().port}`);
// make the request
const clientRequest = http.request(testURL);
// Since there is a little magic with the agent
// make sure that an http request uses the http.Agent
expect(clientRequest.agent).toBeInstanceOf(http.Agent);
clientRequest.end();
resolve();
});
});
});
//<#END_FILE: test-http-url.parse-basic.js

View File

@@ -0,0 +1,54 @@
//#FILE: test-http-url.parse-path.js
//#SHA1: 9eb246a6c09b70b76260a83bec4bb25452d38b7d
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const http = require("http");
const url = require("url");
test("HTTP request URL parsing", async () => {
function check(request) {
// A path should come over
expect(request.url).toBe("/asdf");
}
const server = http.createServer((request, response) => {
// Run the check function
check(request);
response.writeHead(200, {});
response.end("ok");
server.close();
});
await new Promise(resolve => {
server.listen(0, () => {
const testURL = url.parse(`http://localhost:${server.address().port}/asdf`);
// make the request
http.request(testURL).end();
resolve();
});
});
});
//<#END_FILE: test-http-url.parse-path.js

View File

@@ -0,0 +1,59 @@
//#FILE: test-http-url.parse-post.js
//#SHA1: e0e7f97c725fb9eaa6058365bef5021e9710e857
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const http = require("http");
const url = require("url");
let testURL;
function check(request) {
// url.parse should not mess with the method
expect(request.method).toBe("POST");
// Everything else should be right
expect(request.url).toBe("/asdf?qwer=zxcv");
// The host header should use the url.parse.hostname
expect(request.headers.host).toBe(`${testURL.hostname}:${testURL.port}`);
}
test("http.request with url.parse and POST method", done => {
const server = http.createServer((request, response) => {
// Run the check function
check(request);
response.writeHead(200, {});
response.end("ok");
server.close();
done();
});
server.listen(0, () => {
testURL = url.parse(`http://localhost:${server.address().port}/asdf?qwer=zxcv`);
testURL.method = "POST";
// make the request
http.request(testURL).end();
});
});
//<#END_FILE: test-http-url.parse-post.js

View File

@@ -0,0 +1,55 @@
//#FILE: test-http-url.parse-search.js
//#SHA1: 11d08b9c62625b7b554d5fb46d63c4aaa77c1a7c
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const http = require("http");
const url = require("url");
test("http url parse search", async () => {
function check(request) {
// A path should come over with params
expect(request.url).toBe("/asdf?qwer=zxcv");
}
const server = http.createServer((request, response) => {
// Run the check function
check(request);
response.writeHead(200, {});
response.end("ok");
server.close();
});
await new Promise(resolve => {
server.listen(0, () => {
const port = server.address().port;
const testURL = url.parse(`http://localhost:${port}/asdf?qwer=zxcv`);
// make the request
http.request(testURL).end();
resolve();
});
});
});
//<#END_FILE: test-http-url.parse-search.js

View File

@@ -0,0 +1,61 @@
//#FILE: test-http-write-empty-string.js
//#SHA1: 779199784d3142e353324041eeb30924c7e4d5b1
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const http = require("http");
test("HTTP server writing empty string", async () => {
const server = http.createServer(function (request, response) {
console.log(`responding to ${request.url}`);
response.writeHead(200, { "Content-Type": "text/plain" });
response.write("1\n");
response.write("");
response.write("2\n");
response.write("");
response.end("3\n");
this.close();
});
await new Promise(resolve => {
server.listen(0, () => {
http.get({ port: server.address().port }, res => {
let response = "";
expect(res.statusCode).toBe(200);
res.setEncoding("ascii");
res.on("data", chunk => {
response += chunk;
});
res.on("end", () => {
expect(response).toBe("1\n2\n3\n");
resolve();
});
});
});
});
});
//<#END_FILE: test-http-write-empty-string.js

View File

@@ -0,0 +1,30 @@
//#FILE: test-http-zerolengthbuffer.js
//#SHA1: 28fff143238744f829f63936c8902047ad2c2fc5
//-----------------
"use strict";
// Serving up a zero-length buffer should work.
const http = require("http");
test("Serve zero-length buffer", done => {
const server = http.createServer((req, res) => {
const buffer = Buffer.alloc(0);
res.writeHead(200, { "Content-Type": "text/html", "Content-Length": buffer.length });
res.end(buffer);
});
server.listen(0, () => {
http.get({ port: server.address().port }, res => {
const dataHandler = jest.fn();
res.on("data", dataHandler);
res.on("end", () => {
expect(dataHandler).not.toHaveBeenCalled();
server.close();
done();
});
});
});
});
//<#END_FILE: test-http-zerolengthbuffer.js

View File

@@ -0,0 +1,18 @@
//#FILE: test-module-builtin.js
//#SHA1: 18114886f66eccc937942a815feca25d9b324a37
//-----------------
'use strict';
const { builtinModules } = require('module');
test('builtinModules includes modules in lib/ (even deprecated ones)', () => {
expect(builtinModules).toContain('http');
expect(builtinModules).toContain('sys');
});
test('builtinModules does not include internal modules', () => {
const internalModules = builtinModules.filter((mod) => mod.startsWith('internal/'));
expect(internalModules).toHaveLength(0);
});
//<#END_FILE: test-module-builtin.js

View File

@@ -0,0 +1,37 @@
//#FILE: test-module-cache.js
//#SHA1: ff0f4c6ca37e23c009f98bba966e9daee2dcaef6
//-----------------
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
let tmpdir;
beforeEach(() => {
tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-module-cache-'));
});
afterEach(() => {
fs.rmSync(tmpdir, { recursive: true, force: true });
});
test('throws MODULE_NOT_FOUND when file does not exist', () => {
const filePath = path.join(tmpdir, 'test-module-cache.json');
expect(() => require(filePath)).toThrow(expect.objectContaining({
code: 'MODULE_NOT_FOUND',
message: expect.any(String)
}));
});
test('requires JSON file successfully after creation', () => {
const filePath = path.join(tmpdir, 'test-module-cache.json');
fs.writeFileSync(filePath, '[]');
const content = require(filePath);
expect(Array.isArray(content)).toBe(true);
expect(content.length).toBe(0);
});
//<#END_FILE: test-module-cache.js

View File

@@ -0,0 +1,39 @@
//#FILE: test-net-server-unref.js
//#SHA1: bb2f989bf01182d804d6a8a0d0f33950f357c617
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const net = require('net');
test('net server unref', () => {
const s = net.createServer();
s.listen(0);
s.unref();
const mockCallback = jest.fn();
setTimeout(mockCallback, 1000).unref();
expect(mockCallback).not.toHaveBeenCalled();
});
//<#END_FILE: test-net-server-unref.js

View File

@@ -0,0 +1,40 @@
//#FILE: test-net-socket-close-after-end.js
//#SHA1: d3abfad3599a4245fb35f5589c55bb56a43ca3f7
//-----------------
'use strict';
const net = require('net');
test('socket emits "end" before "close"', (done) => {
const server = net.createServer();
server.on('connection', (socket) => {
let endEmitted = false;
socket.once('readable', () => {
setTimeout(() => {
socket.read();
}, 100);
});
socket.on('end', () => {
endEmitted = true;
});
socket.on('close', () => {
expect(endEmitted).toBe(true);
server.close();
done();
});
socket.end('foo');
});
server.listen(() => {
const socket = net.createConnection(server.address().port, () => {
socket.end('foo');
});
});
});
//<#END_FILE: test-net-socket-close-after-end.js

View File

@@ -0,0 +1,35 @@
//#FILE: test-net-socket-connect-without-cb.js
//#SHA1: 2441c4dfe4351f2e9a02cd08df36e4703096864a
//-----------------
'use strict';
const net = require('net');
// This test ensures that socket.connect can be called without callback
// which is optional.
test('socket.connect without callback', (done) => {
const server = net.createServer((conn) => {
conn.end();
server.close();
}).listen(0, () => {
const client = new net.Socket();
client.on('connect', () => {
client.end();
done();
});
const address = server.address();
if (process.version.startsWith('v') && !process.versions.bun && address.family === 'IPv6') {
// Necessary to pass CI running inside containers.
client.connect(address.port);
} else {
client.connect(address);
}
});
expect(server).toBeDefined();
});
//<#END_FILE: test-net-socket-connect-without-cb.js

View File

@@ -0,0 +1,65 @@
//#FILE: test-net-socket-timeout-unref.js
//#SHA1: 1583fd33473989bba11fead2493c70a79d9ff48e
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
// Test that unref'ed sockets with timeouts do not prevent exit.
const net = require('net');
test('unref\'ed sockets with timeouts do not prevent exit', () => {
const server = net.createServer((c) => {
c.write('hello');
c.unref();
});
server.listen(0);
server.unref();
let connections = 0;
const sockets = [];
const delays = [8, 5, 3, 6, 2, 4];
delays.forEach((T) => {
const socket = net.createConnection(server.address().port, 'localhost');
socket.on('connect', () => {
if (++connections === delays.length) {
sockets.forEach((s) => {
s.socket.setTimeout(s.timeout, () => {
s.socket.destroy();
throw new Error('socket timed out unexpectedly');
});
s.socket.unref();
});
}
});
sockets.push({ socket: socket, timeout: T * 1000 });
});
// We don't need to explicitly assert anything here.
// The test will pass if the process exits without throwing an error.
});
//<#END_FILE: test-net-socket-timeout-unref.js

View File

@@ -0,0 +1,34 @@
//#FILE: test-net-socket-write-error.js
//#SHA1: a69bb02fc98fc265ad23ff03e7ae16e9c984202d
//-----------------
'use strict';
const net = require('net');
test('net socket write error', (done) => {
const server = net.createServer().listen(0, connectToServer);
function connectToServer() {
const client = net.createConnection(this.address().port, () => {
client.on('error', () => {
throw new Error('Error event should not be emitted');
});
expect(() => {
client.write(1337);
}).toThrow(expect.objectContaining({
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: expect.any(String)
}));
client.destroy();
})
.on('close', () => {
server.close();
done();
});
}
});
//<#END_FILE: test-net-socket-write-error.js

View File

@@ -0,0 +1,26 @@
//#FILE: test-net-writable.js
//#SHA1: dfbbbc883e83311b16b93fc9e06d214552cb6448
//-----------------
'use strict';
const net = require('net');
test('net writable after end event', (done) => {
const server = net.createServer((s) => {
server.close();
s.end();
});
server.listen(0, '127.0.0.1', () => {
const socket = net.connect(server.address().port, '127.0.0.1');
socket.on('end', () => {
expect(socket.writable).toBe(true);
socket.write('hello world');
done();
});
});
expect.assertions(1);
});
//<#END_FILE: test-net-writable.js

View File

@@ -0,0 +1,37 @@
//#FILE: test-net-write-after-end-nt.js
//#SHA1: 086a5699d5eff4953af4e9f19757b8489e915579
//-----------------
'use strict';
const net = require('net');
// This test ensures those errors caused by calling `net.Socket.write()`
// after sockets ending will be emitted in the next tick.
test('net.Socket.write() after end emits error in next tick', (done) => {
const server = net.createServer((socket) => {
socket.end();
}).listen(() => {
const client = net.connect(server.address().port, () => {
let hasError = false;
client.on('error', (err) => {
hasError = true;
server.close();
done();
});
client.on('end', () => {
const ret = client.write('hello');
expect(ret).toBe(false);
expect(hasError).toBe(false);
// Check that the error is emitted in the next tick
setImmediate(() => {
expect(hasError).toBe(true);
});
});
client.end();
});
});
});
//<#END_FILE: test-net-write-after-end-nt.js

View File

@@ -0,0 +1,64 @@
//#FILE: test-net-write-connect-write.js
//#SHA1: 8d6e9a30cc58bee105db15dc48c8a13c451629be
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const net = require('net');
test('net write connect write', async () => {
const server = net.createServer((socket) => {
socket.pipe(socket);
});
await new Promise((resolve) => {
server.listen(0, resolve);
});
const conn = net.connect(server.address().port);
let received = '';
conn.setEncoding('utf8');
conn.write('before');
await new Promise((resolve) => {
conn.on('connect', () => {
conn.write(' after');
resolve();
});
});
await new Promise((resolve) => {
conn.on('data', (buf) => {
received += buf;
conn.end();
});
conn.on('end', () => {
server.close();
expect(received).toBe('before after');
resolve();
});
});
});
//<#END_FILE: test-net-write-connect-write.js

View File

@@ -0,0 +1,43 @@
//#FILE: test-net-write-fully-async-buffer.js
//#SHA1: b26773ed4c8c5bafaaa8a4513b25d1806a72ae5f
//-----------------
'use strict';
// Flags: --expose-gc
// Note: This is a variant of test-net-write-fully-async-hex-string.js.
// This always worked, but it seemed appropriate to add a test that checks the
// behavior for Buffers, too.
const net = require('net');
const data = Buffer.alloc(1000000);
test('net write fully async buffer', (done) => {
const server = net.createServer((conn) => {
conn.resume();
}).listen(0, () => {
const conn = net.createConnection(server.address().port, () => {
let count = 0;
function writeLoop() {
if (count++ === 200) {
conn.destroy();
server.close();
done();
return;
}
while (conn.write(Buffer.from(data)));
global.gc({ type: 'minor' });
// The buffer allocated above should still be alive.
}
conn.on('drain', writeLoop);
writeLoop();
});
});
expect(server.listening).toBe(true);
});
//<#END_FILE: test-net-write-fully-async-buffer.js

View File

@@ -0,0 +1,47 @@
//#FILE: test-net-write-fully-async-hex-string.js
//#SHA1: e5b365bb794f38e7153fc41ebfaf991031f85423
//-----------------
'use strict';
// Flags: --expose-gc
// Regression test for https://github.com/nodejs/node/issues/8251.
const net = require('net');
const data = Buffer.alloc(1000000).toString('hex');
test('net write fully async hex string', (done) => {
const server = net.createServer((conn) => {
conn.resume();
}).listen(0, () => {
const conn = net.createConnection(server.address().port, () => {
let count = 0;
function writeLoop() {
if (count++ === 20) {
conn.destroy();
server.close();
done();
return;
}
while (conn.write(data, 'hex'));
global.gc({ type: 'minor' });
// The buffer allocated inside the .write() call should still be alive.
}
conn.on('drain', writeLoop);
writeLoop();
});
});
expect.assertions(2);
server.on('listening', () => {
expect(server.address().port).toBeGreaterThan(0);
});
server.on('connection', () => {
expect(true).toBe(true); // Connection established
});
});
//<#END_FILE: test-net-write-fully-async-hex-string.js

View File

@@ -0,0 +1,23 @@
//#FILE: test-url-canParse-whatwg.js
//#SHA1: e1170e8b8d0057443bfb307c64dbd27b204ac2f0
//-----------------
'use strict';
test('URL.canParse requires one argument', () => {
expect(() => {
URL.canParse();
}).toThrow(expect.objectContaining({
code: 'ERR_MISSING_ARGS',
name: 'TypeError',
message: expect.any(String)
}));
});
test('URL.canParse works with v8 fast api', () => {
// This test is to ensure that the v8 fast api works.
for (let i = 0; i < 1e5; i++) {
expect(URL.canParse('https://www.example.com/path/?query=param#hash')).toBe(true);
}
});
//<#END_FILE: test-url-canParse-whatwg.js

View File

@@ -0,0 +1,39 @@
//#FILE: test-url-domain-ascii-unicode.js
//#SHA1: 717d40eef6d2d8f5adccf01fe09dc43f8b776e13
//-----------------
'use strict';
const url = require('url');
const domainToASCII = url.domainToASCII;
const domainToUnicode = url.domainToUnicode;
const domainWithASCII = [
['ıíd', 'xn--d-iga7r'],
['يٴ', 'xn--mhb8f'],
['www.ϧƽəʐ.com', 'www.xn--cja62apfr6c.com'],
['новини.com', 'xn--b1amarcd.com'],
['名がドメイン.com', 'xn--v8jxj3d1dzdz08w.com'],
['افغانستا.icom.museum', 'xn--mgbaal8b0b9b2b.icom.museum'],
['الجزائر.icom.fake', 'xn--lgbbat1ad8j.icom.fake'],
['भारत.org', 'xn--h2brj9c.org'],
];
describe('URL domain ASCII and Unicode conversion', () => {
// Skip the entire test suite if Intl is not available
beforeAll(() => {
if (typeof Intl === 'undefined') {
throw new Error('missing Intl');
}
});
test.each(domainWithASCII)('converts %s <-> %s', (domain, ascii) => {
const domainConvertedToASCII = domainToASCII(domain);
expect(domainConvertedToASCII).toBe(ascii);
const asciiConvertedToUnicode = domainToUnicode(ascii);
expect(asciiConvertedToUnicode).toBe(domain);
});
});
//<#END_FILE: test-url-domain-ascii-unicode.js

View File

@@ -0,0 +1,18 @@
//#FILE: test-url-revokeobjecturl.js
//#SHA1: 573bfad806102976807ad71fef71b079005d8bfa
//-----------------
'use strict';
// Test ensures that the function receives the url argument.
test('URL.revokeObjectURL() throws with missing argument', () => {
expect(() => {
URL.revokeObjectURL();
}).toThrow(expect.objectContaining({
code: 'ERR_MISSING_ARGS',
name: 'TypeError',
message: expect.any(String)
}));
});
//<#END_FILE: test-url-revokeobjecturl.js

View File

@@ -0,0 +1,48 @@
//#FILE: test-url-urltooptions.js
//#SHA1: 0ba1cb976ec5888306f7c820a39afcb93b882d03
//-----------------
'use strict';
const { URL } = require('url');
const { urlToHttpOptions } = require('url');
describe('urlToHttpOptions', () => {
test('converts URL object to HTTP options', () => {
const urlObj = new URL('http://user:pass@foo.bar.com:21/aaa/zzz?l=24#test');
const opts = urlToHttpOptions(urlObj);
expect(opts).not.toBeInstanceOf(URL);
expect(opts.protocol).toBe('http:');
expect(opts.auth).toBe('user:pass');
expect(opts.hostname).toBe('foo.bar.com');
expect(opts.port).toBe(21);
expect(opts.path).toBe('/aaa/zzz?l=24');
expect(opts.pathname).toBe('/aaa/zzz');
expect(opts.search).toBe('?l=24');
expect(opts.hash).toBe('#test');
});
test('handles IPv6 hostname correctly', () => {
const { hostname } = urlToHttpOptions(new URL('http://[::1]:21'));
expect(hostname).toBe('::1');
});
test('handles copied URL object with missing data properties', () => {
const urlObj = new URL('http://user:pass@foo.bar.com:21/aaa/zzz?l=24#test');
const copiedUrlObj = { ...urlObj };
const copiedOpts = urlToHttpOptions(copiedUrlObj);
expect(copiedOpts).not.toBeInstanceOf(URL);
expect(copiedOpts.protocol).toBeUndefined();
expect(copiedOpts.auth).toBeUndefined();
expect(copiedOpts.hostname).toBeUndefined();
expect(copiedOpts.port).toBeNaN();
expect(copiedOpts.path).toBe('');
expect(copiedOpts.pathname).toBeUndefined();
expect(copiedOpts.search).toBeUndefined();
expect(copiedOpts.hash).toBeUndefined();
expect(copiedOpts.href).toBeUndefined();
});
});
//<#END_FILE: test-url-urltooptions.js

View File

@@ -0,0 +1,79 @@
//#FILE: test-util-deprecate.js
//#SHA1: 43c232bacd8dcc9f39194125c071db2ab14dfb51
//-----------------
"use strict";
const util = require("util");
// Tests basic functionality of util.deprecate().
// Mock process.on for warnings
const mockWarningListener = jest.fn();
const mockExitListener = jest.fn();
process.on = jest.fn((event, listener) => {
if (event === "warning") mockWarningListener.mockImplementation(listener);
if (event === "exit") mockExitListener.mockImplementation(listener);
});
const expectedWarnings = new Map();
test("Emits deprecation only once if same function is called", () => {
const msg = "fhqwhgads";
const fn = util.deprecate(() => {}, msg);
expectedWarnings.set(msg, { code: undefined, count: 1 });
fn();
fn();
});
test("Emits deprecation twice for different functions", () => {
const msg = "sterrance";
const fn1 = util.deprecate(() => {}, msg);
const fn2 = util.deprecate(() => {}, msg);
expectedWarnings.set(msg, { code: undefined, count: 2 });
fn1();
fn2();
});
test("Emits deprecation only once if optional code is the same, even for different functions", () => {
const msg = "cannonmouth";
const code = "deprecatesque";
const fn1 = util.deprecate(() => {}, msg, code);
const fn2 = util.deprecate(() => {}, msg, code);
expectedWarnings.set(msg, { code, count: 1 });
fn1();
fn2();
fn1();
fn2();
});
test("Handles warnings correctly", () => {
expectedWarnings.forEach((expected, message) => {
for (let i = 0; i < expected.count; i++) {
mockWarningListener({
name: "DeprecationWarning",
message: message,
code: expected.code,
});
}
});
expect(mockWarningListener).toHaveBeenCalledTimes(
Array.from(expectedWarnings.values()).reduce((acc, curr) => acc + curr.count, 0),
);
mockWarningListener.mock.calls.forEach(([warning]) => {
expect(warning.name).toBe("DeprecationWarning");
expect(expectedWarnings.has(warning.message)).toBe(true);
const expected = expectedWarnings.get(warning.message);
expect(warning.code).toBe(expected.code);
expected.count--;
if (expected.count === 0) {
expectedWarnings.delete(warning.message);
}
});
});
test("All warnings are processed", () => {
mockExitListener();
expect(expectedWarnings.size).toBe(0);
});

View File

@@ -0,0 +1,62 @@
//#FILE: test-util-inspect-getters-accessing-this.js
//#SHA1: 92c41c06f838da46cbbfcd7f695a19784af3f581
//-----------------
"use strict";
const { inspect } = require("util");
// This test ensures that util.inspect logs getters
// which access this.
test("util.inspect logs getters accessing this", () => {
class X {
constructor() {
this._y = 123;
}
get y() {
return this._y;
}
}
const result = inspect(new X(), {
getters: true,
showHidden: true,
});
expect(result).toBe("X { _y: 123, [y]: [Getter: 123] }");
});
// Regression test for https://github.com/nodejs/node/issues/37054
test("util.inspect handles circular references in getters", () => {
class A {
constructor(B) {
this.B = B;
}
get b() {
return this.B;
}
}
class B {
constructor() {
this.A = new A(this);
}
get a() {
return this.A;
}
}
const result = inspect(new B(), {
depth: 1,
getters: true,
showHidden: true,
});
expect(result).toBe(
"<ref *1> B {\n" +
" A: A { B: [Circular *1], [b]: [Getter] [Circular *1] },\n" +
" [a]: [Getter] A { B: [Circular *1], [b]: [Getter] [Circular *1] }\n" +
"}",
);
});

View File

@@ -0,0 +1,26 @@
//#FILE: test-util-inspect-long-running.js
//#SHA1: 2e4cbb5743a4dfcf869e84ce6d58795f96465aeb
//-----------------
"use strict";
// Test that huge objects don't crash due to exceeding the maximum heap size.
const util = require("util");
test("util.inspect handles huge objects without crashing", () => {
// Create a difficult to stringify object. Without the artificial limitation
// this would crash or throw an maximum string size error.
let last = {};
const obj = last;
for (let i = 0; i < 1000; i++) {
last.next = { circular: obj, last, obj: { a: 1, b: 2, c: true } };
last = last.next;
obj[i] = last;
}
// If this doesn't throw, we consider the test passed
expect(() => {
util.inspect(obj, { depth: Infinity });
}).not.toThrow();
});

View File

@@ -0,0 +1,25 @@
//#FILE: test-util-primordial-monkeypatching.js
//#SHA1: 72e754f1abd435e598620901f26b087e0bf9d5a7
//-----------------
"use strict";
// Monkeypatch Object.keys() so that it throws an unexpected error. This tests
// that `util.inspect()` is unaffected by monkey-patching `Object`.
const util = require("util");
test("util.inspect() is unaffected by monkey-patching Object.keys()", () => {
const originalObjectKeys = Object.keys;
// Monkey-patch Object.keys
Object.keys = () => {
throw new Error("fhqwhgads");
};
try {
expect(util.inspect({})).toBe("{}");
} finally {
// Restore original Object.keys to avoid affecting other tests
Object.keys = originalObjectKeys;
}
});

View File

@@ -0,0 +1,39 @@
//#FILE: test-zlib-close-after-write.js
//#SHA1: 7fad593914e2a23d73598e4366e685b9aa91cc24
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const zlib = require("zlib");
test("zlib close after write", done => {
zlib.gzip("hello", (err, out) => {
expect(err).toBeNull();
const unzip = zlib.createGunzip();
unzip.write(out);
unzip.close(() => {
done();
});
});
});

View File

@@ -0,0 +1,16 @@
//#FILE: test-zlib-create-raw.js
//#SHA1: 187539d5696ec6b7c567dfba0d1528c4b65d1e0a
//-----------------
"use strict";
const zlib = require("zlib");
test("zlib.createInflateRaw() creates an instance of InflateRaw", () => {
const inflateRaw = zlib.createInflateRaw();
expect(inflateRaw).toBeInstanceOf(zlib.InflateRaw);
});
test("zlib.createDeflateRaw() creates an instance of DeflateRaw", () => {
const deflateRaw = zlib.createDeflateRaw();
expect(deflateRaw).toBeInstanceOf(zlib.DeflateRaw);
});

View File

@@ -0,0 +1,36 @@
//#FILE: test-zlib-deflate-raw-inherits.js
//#SHA1: 9e1873864f4af27abf3a8a36a87edd2d036805d8
//-----------------
"use strict";
const { DeflateRaw } = require("zlib");
const { Readable } = require("stream");
// Validates that zlib.DeflateRaw can be inherited
// with Object.setPrototypeOf
test("DeflateRaw can be inherited with Object.setPrototypeOf", done => {
function NotInitialized(options) {
DeflateRaw.call(this, options);
this.prop = true;
}
Object.setPrototypeOf(NotInitialized.prototype, DeflateRaw.prototype);
Object.setPrototypeOf(NotInitialized, DeflateRaw);
const dest = new NotInitialized();
const read = new Readable({
read() {
this.push(Buffer.from("a test string"));
this.push(null);
},
});
read.pipe(dest);
dest.on("finish", () => {
expect(dest.prop).toBe(true);
expect(dest instanceof DeflateRaw).toBe(true);
done();
});
dest.resume();
});

View File

@@ -0,0 +1,64 @@
//#FILE: test-zlib-dictionary-fail.js
//#SHA1: e9c6d383f9b0a202067a125c016f1ef3cd5be558
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const zlib = require("zlib");
// String "test" encoded with dictionary "dict".
const input = Buffer.from([0x78, 0xbb, 0x04, 0x09, 0x01, 0xa5]);
test("Inflate stream without dictionary", done => {
const stream = zlib.createInflate();
stream.on("error", err => {
expect(err.message).toMatch(/Missing dictionary/);
done();
});
stream.write(input);
});
test("Inflate stream with incorrect dictionary", done => {
const stream = zlib.createInflate({ dictionary: Buffer.from("fail") });
stream.on("error", err => {
expect(err.message).toMatch(/Bad dictionary/);
done();
});
stream.write(input);
});
test("InflateRaw stream with incorrect dictionary", done => {
const stream = zlib.createInflateRaw({ dictionary: Buffer.from("fail") });
stream.on("error", err => {
// It's not possible to separate invalid dict and invalid data when using
// the raw format
expect(err.message).toMatch(/(invalid|Operation-Ending-Supplemental Code is 0x12)/);
done();
});
stream.write(input);
});

View File

@@ -0,0 +1,35 @@
//#FILE: test-zlib-empty-buffer.js
//#SHA1: 7a2e8687dcd6e4bd815aa22c2bbff08251d9d91a
//-----------------
"use strict";
const zlib = require("zlib");
const { inspect, promisify } = require("util");
const emptyBuffer = Buffer.alloc(0);
describe("Zlib Empty Buffer", () => {
const testCases = [
["deflateRawSync", "inflateRawSync", "raw sync"],
["deflateSync", "inflateSync", "deflate sync"],
["gzipSync", "gunzipSync", "gzip sync"],
["brotliCompressSync", "brotliDecompressSync", "br sync"],
["deflateRaw", "inflateRaw", "raw"],
["deflate", "inflate", "deflate"],
["gzip", "gunzip", "gzip"],
["brotliCompress", "brotliDecompress", "br"],
];
testCases.forEach(([compressMethod, decompressMethod, methodName]) => {
test(`${methodName} compression and decompression`, async () => {
const compress = methodName.includes("sync") ? zlib[compressMethod] : promisify(zlib[compressMethod]);
const decompress = methodName.includes("sync") ? zlib[decompressMethod] : promisify(zlib[decompressMethod]);
const compressed = await compress(emptyBuffer);
const decompressed = await decompress(compressed);
expect(decompressed).toEqual(emptyBuffer);
});
});
});

View File

@@ -0,0 +1,119 @@
//#FILE: test-zlib-from-string.js
//#SHA1: 0514669607bbf01e20f41875fa716660ebfcf28b
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
// Test compressing and uncompressing a string with zlib
const zlib = require("zlib");
const inputString =
"ΩΩLorem ipsum dolor sit amet, consectetur adipiscing eli" +
"t. Morbi faucibus, purus at gravida dictum, libero arcu " +
"convallis lacus, in commodo libero metus eu nisi. Nullam" +
" commodo, neque nec porta placerat, nisi est fermentum a" +
"ugue, vitae gravida tellus sapien sit amet tellus. Aenea" +
"n non diam orci. Proin quis elit turpis. Suspendisse non" +
" diam ipsum. Suspendisse nec ullamcorper odio. Vestibulu" +
"m arcu mi, sodales non suscipit id, ultrices ut massa. S" +
"ed ac sem sit amet arcu malesuada fermentum. Nunc sed. ";
const expectedBase64Deflate =
"eJxdUUtOQzEMvMoc4OndgT0gJCT2buJWlpI4jePeqZfpmX" +
"AKLRKbLOzx/HK73q6vOrhCunlF1qIDJhNUeW5I2ozT5OkD" +
"lKWLJWkncJG5403HQXAkT3Jw29B9uIEmToMukglZ0vS6oc" +
"iBh4JG8sV4oVLEUCitK2kxq1WzPnChHDzsaGKy491LofoA" +
"bWh8do43oeuYhB5EPCjcLjzYJo48KrfQBvnJecNFJvHT1+" +
"RSQsGoC7dn2t/xjhduTA1NWyQIZR0pbHwMDatnD+crPqKS" +
"qGPHp1vnlsWM/07ubf7bheF7kqSj84Bm0R1fYTfaK8vqqq" +
"fKBtNMhe3OZh6N95CTvMX5HJJi4xOVzCgUOIMSLH7wmeOH" +
"aFE4RdpnGavKtrB5xzfO/Ll9";
const expectedBase64Gzip =
"H4sIAAAAAAAAA11RS05DMQy8yhzg6d2BPSAkJPZu4laWkjiN4" +
"96pl+mZcAotEpss7PH8crverq86uEK6eUXWogMmE1R5bkjajN" +
"Pk6QOUpYslaSdwkbnjTcdBcCRPcnDb0H24gSZOgy6SCVnS9Lq" +
"hyIGHgkbyxXihUsRQKK0raTGrVbM+cKEcPOxoYrLj3Uuh+gBt" +
"aHx2jjeh65iEHkQ8KNwuPNgmjjwqt9AG+cl5w0Um8dPX5FJCw" +
"agLt2fa3/GOF25MDU1bJAhlHSlsfAwNq2cP5ys+opKoY8enW+" +
"eWxYz/Tu5t/tuF4XuSpKPzgGbRHV9hN9ory+qqp8oG00yF7c5" +
"mHo33kJO8xfkckmLjE5XMKBQ4gxIsfvCZ44doUThF2mcZq8q2" +
"sHnHNzRtagj5AQAA";
test("deflate and inflate", async () => {
const buffer = await new Promise((resolve, reject) => {
zlib.deflate(inputString, (err, buffer) => {
if (err) reject(err);
else resolve(buffer);
});
});
const inflated = await new Promise((resolve, reject) => {
zlib.inflate(buffer, (err, inflated) => {
if (err) reject(err);
else resolve(inflated);
});
});
expect(inflated.toString()).toBe(inputString);
});
test("gzip and gunzip", async () => {
const buffer = await new Promise((resolve, reject) => {
zlib.gzip(inputString, (err, buffer) => {
if (err) reject(err);
else resolve(buffer);
});
});
const gunzipped = await new Promise((resolve, reject) => {
zlib.gunzip(buffer, (err, gunzipped) => {
if (err) reject(err);
else resolve(gunzipped);
});
});
expect(gunzipped.toString()).toBe(inputString);
});
test("unzip deflated data", async () => {
const buffer = Buffer.from(expectedBase64Deflate, "base64");
const unzipped = await new Promise((resolve, reject) => {
zlib.unzip(buffer, (err, unzipped) => {
if (err) reject(err);
else resolve(unzipped);
});
});
expect(unzipped.toString()).toBe(inputString);
});
test("unzip gzipped data", async () => {
const buffer = Buffer.from(expectedBase64Gzip, "base64");
const unzipped = await new Promise((resolve, reject) => {
zlib.unzip(buffer, (err, unzipped) => {
if (err) reject(err);
else resolve(unzipped);
});
});
expect(unzipped.toString()).toBe(inputString);
});

View File

@@ -0,0 +1,19 @@
//#FILE: test-zlib-no-stream.js
//#SHA1: 5755924e9363a20243c326747623e8e266f81625
//-----------------
/* eslint-disable node-core/required-modules */
/* eslint-disable node-core/require-common-first */
"use strict";
// We are not loading common because it will load the stream module,
// defeating the purpose of this test.
const { gzipSync } = require("zlib");
// Avoid regressions such as https://github.com/nodejs/node/issues/36615
test("gzipSync should not throw", () => {
// This must not throw
expect(() => gzipSync("fooobar")).not.toThrow();
});

View File

@@ -0,0 +1,21 @@
//#FILE: test-zlib-not-string-or-buffer.js
//#SHA1: d07db97d9393df2ab9453800ae80f2921d93b6e2
//-----------------
"use strict";
// Check the error condition testing for passing something other than a string
// or buffer.
const zlib = require("zlib");
test("zlib.deflateSync throws for invalid input types", () => {
[undefined, null, true, false, 0, 1, [1, 2, 3], { foo: "bar" }].forEach(input => {
expect(() => zlib.deflateSync(input)).toThrow(
expect.objectContaining({
code: "ERR_INVALID_ARG_TYPE",
name: "TypeError",
message: expect.any(String),
}),
);
});
});

View File

@@ -0,0 +1,164 @@
//#FILE: test-zlib-random-byte-pipes.js
//#SHA1: ef7e7d3683660b911f9e24a6f40947a47be3dbba
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const crypto = require("crypto");
const stream = require("stream");
const zlib = require("zlib");
const Stream = stream.Stream;
// Emit random bytes, and keep a shasum
class RandomReadStream extends Stream {
constructor(opt) {
super();
this.readable = true;
this._paused = false;
this._processing = false;
this._hasher = crypto.createHash("sha1");
opt = opt || {};
// base block size.
opt.block = opt.block || 256 * 1024;
// Total number of bytes to emit
opt.total = opt.total || 256 * 1024 * 1024;
this._remaining = opt.total;
// How variable to make the block sizes
opt.jitter = opt.jitter || 1024;
this._opt = opt;
this._process = this._process.bind(this);
process.nextTick(this._process);
}
pause() {
this._paused = true;
this.emit("pause");
}
resume() {
// console.error("rrs resume");
this._paused = false;
this.emit("resume");
this._process();
}
_process() {
if (this._processing) return;
if (this._paused) return;
this._processing = true;
if (!this._remaining) {
this._hash = this._hasher.digest("hex").toLowerCase().trim();
this._processing = false;
this.emit("end");
return;
}
// Figure out how many bytes to output
// if finished, then just emit end.
let block = this._opt.block;
const jitter = this._opt.jitter;
if (jitter) {
block += Math.ceil(Math.random() * jitter - jitter / 2);
}
block = Math.min(block, this._remaining);
const buf = Buffer.allocUnsafe(block);
for (let i = 0; i < block; i++) {
buf[i] = Math.random() * 256;
}
this._hasher.update(buf);
this._remaining -= block;
this._processing = false;
this.emit("data", buf);
process.nextTick(this._process);
}
}
// A filter that just verifies a shasum
class HashStream extends Stream {
constructor() {
super();
this.readable = this.writable = true;
this._hasher = crypto.createHash("sha1");
}
write(c) {
// Simulate the way that an fs.ReadStream returns false
// on *every* write, only to resume a moment later.
this._hasher.update(c);
process.nextTick(() => this.resume());
return false;
}
resume() {
this.emit("resume");
process.nextTick(() => this.emit("drain"));
}
end(c) {
if (c) {
this.write(c);
}
this._hash = this._hasher.digest("hex").toLowerCase().trim();
this.emit("data", this._hash);
this.emit("end");
}
}
test("zlib random byte pipes", async () => {
const testCases = [
[zlib.createGzip, zlib.createGunzip],
[zlib.createBrotliCompress, zlib.createBrotliDecompress],
];
for (const [createCompress, createDecompress] of testCases) {
const inp = new RandomReadStream({ total: 1024, block: 256, jitter: 16 });
const out = new HashStream();
const gzip = createCompress();
const gunz = createDecompress();
inp.pipe(gzip).pipe(gunz).pipe(out);
await new Promise(resolve => {
out.on("data", c => {
expect(c).toBe(inp._hash);
resolve();
});
});
}
});

View File

@@ -0,0 +1,28 @@
//#FILE: test-zlib-sync-no-event.js
//#SHA1: 382796f607eb25a85aa067e0dbc3d5103d321def
//-----------------
"use strict";
const zlib = require("zlib");
const message = "Come on, Fhqwhgads.";
const buffer = Buffer.from(message);
test("Gzip and Gunzip synchronously without emitting events", () => {
const zipper = new zlib.Gzip();
const closeSpy = jest.fn();
zipper.on("close", closeSpy);
const zipped = zipper._processChunk(buffer, zlib.constants.Z_FINISH);
const unzipper = new zlib.Gunzip();
const unzipperCloseSpy = jest.fn();
unzipper.on("close", unzipperCloseSpy);
const unzipped = unzipper._processChunk(zipped, zlib.constants.Z_FINISH);
expect(zipped.toString()).not.toBe(message);
expect(unzipped.toString()).toBe(message);
expect(closeSpy).not.toHaveBeenCalled();
expect(unzipperCloseSpy).not.toHaveBeenCalled();
});

View File

@@ -0,0 +1,87 @@
//#FILE: test-zlib-truncated.js
//#SHA1: 79f9bcf3c52b3d0736ebe457652d579a856d1f7b
//-----------------
"use strict";
// Tests zlib streams with truncated compressed input
const zlib = require("zlib");
const inputString =
"ΩΩLorem ipsum dolor sit amet, consectetur adipiscing eli" +
"t. Morbi faucibus, purus at gravida dictum, libero arcu " +
"convallis lacus, in commodo libero metus eu nisi. Nullam" +
" commodo, neque nec porta placerat, nisi est fermentum a" +
"ugue, vitae gravida tellus sapien sit amet tellus. Aenea" +
"n non diam orci. Proin quis elit turpis. Suspendisse non" +
" diam ipsum. Suspendisse nec ullamcorper odio. Vestibulu" +
"m arcu mi, sodales non suscipit id, ultrices ut massa. S" +
"ed ac sem sit amet arcu malesuada fermentum. Nunc sed. ";
const errMessage = /unexpected end of file/;
[
{ comp: "gzip", decomp: "gunzip", decompSync: "gunzipSync" },
{ comp: "gzip", decomp: "unzip", decompSync: "unzipSync" },
{ comp: "deflate", decomp: "inflate", decompSync: "inflateSync" },
{ comp: "deflateRaw", decomp: "inflateRaw", decompSync: "inflateRawSync" },
].forEach(function (methods) {
test(`Test ${methods.comp} compression and ${methods.decomp} decompression`, async () => {
const compressed = await new Promise((resolve, reject) => {
zlib[methods.comp](inputString, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
const truncated = compressed.slice(0, compressed.length / 2);
const toUTF8 = buffer => buffer.toString("utf-8");
// sync sanity
const decompressed = zlib[methods.decompSync](compressed);
expect(toUTF8(decompressed)).toBe(inputString);
// async sanity
await new Promise((resolve, reject) => {
zlib[methods.decomp](compressed, (err, result) => {
if (err) reject(err);
else {
expect(toUTF8(result)).toBe(inputString);
resolve();
}
});
});
// Sync truncated input test
expect(() => {
zlib[methods.decompSync](truncated);
}).toThrow(expect.objectContaining({ message: expect.stringMatching(errMessage) }));
// Async truncated input test
await expect(
new Promise((resolve, reject) => {
zlib[methods.decomp](truncated, (err, result) => {
if (err) reject(err);
else resolve(result);
});
}),
).rejects.toThrow(expect.objectContaining({ message: expect.stringMatching(errMessage) }));
const syncFlushOpt = { finishFlush: zlib.constants.Z_SYNC_FLUSH };
// Sync truncated input test, finishFlush = Z_SYNC_FLUSH
const result = toUTF8(zlib[methods.decompSync](truncated, syncFlushOpt));
expect(result).toBe(inputString.slice(0, result.length));
// Async truncated input test, finishFlush = Z_SYNC_FLUSH
await new Promise((resolve, reject) => {
zlib[methods.decomp](truncated, syncFlushOpt, (err, decompressed) => {
if (err) reject(err);
else {
const result = toUTF8(decompressed);
expect(result).toBe(inputString.slice(0, result.length));
resolve();
}
});
});
});
});

View File

@@ -0,0 +1,30 @@
//#FILE: test-zlib-unzip-one-byte-chunks.js
//#SHA1: 3c242140501ae0e8e9277c68696c231a04070018
//-----------------
"use strict";
const zlib = require("zlib");
test("unzip one byte chunks", done => {
const data = Buffer.concat([zlib.gzipSync("abc"), zlib.gzipSync("def")]);
const resultBuffers = [];
const unzip = zlib
.createUnzip()
.on("error", err => {
expect(err).toBeFalsy();
})
.on("data", data => resultBuffers.push(data))
.on("finish", () => {
const unzipped = Buffer.concat(resultBuffers).toString();
expect(unzipped).toBe("abcdef");
done();
});
for (let i = 0; i < data.length; i++) {
// Write each single byte individually.
unzip.write(Buffer.from([data[i]]));
}
unzip.end();
});

View File

@@ -0,0 +1,54 @@
//#FILE: test-zlib-zero-byte.js
//#SHA1: 54539c28619fb98230547ba0929ddad146f15bc5
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const zlib = require("zlib");
for (const Compressor of [zlib.Gzip, zlib.BrotliCompress]) {
test(`${Compressor.name} compresses empty buffer`, async () => {
const gz = new Compressor();
const emptyBuffer = Buffer.alloc(0);
let received = 0;
gz.on("data", c => {
received += c.length;
});
const endPromise = new Promise(resolve => {
gz.on("end", resolve);
});
const finishPromise = new Promise(resolve => {
gz.on("finish", resolve);
});
gz.write(emptyBuffer);
gz.end();
await Promise.all([endPromise, finishPromise]);
const expected = Compressor === zlib.Gzip ? 20 : 1;
expect(received).toBe(expected);
});
}