'use strict'; const common = require('../common'); const tmpdir = require('../common/tmpdir'); const { ok, strictEqual, throws, } = require('node:assert'); const { open, openSync, readFile, renameSync, } = require('node:fs'); const { Utf8Stream } = require('node:fs'); const { join } = require('node:path'); const { isMainThread } = require('node:worker_threads'); tmpdir.refresh(); let fileCounter = 0; if (isMainThread) { process.umask(0o000); } function getTempFile() { return join(tmpdir.path, `fastutf8stream-${process.pid}-${Date.now()}-${fileCounter++}.log`); } runTests(false); runTests(true); function runTests(sync) { { const dest = getTempFile(); const stream = new Utf8Stream({ dest, sync }); ok(stream.write('hello world\n')); ok(stream.write('something else\n')); const after = dest + '-moved'; stream.once('drain', common.mustCall(() => { renameSync(dest, after); stream.reopen(); stream.once('ready', common.mustCall(() => { ok(stream.write('after reopen\n')); stream.once('drain', common.mustCall(() => { readFile(after, 'utf8', common.mustSucceed((data) => { strictEqual(data, 'hello world\nsomething else\n'); readFile(dest, 'utf8', common.mustSucceed((data) => { strictEqual(data, 'after reopen\n'); stream.end(); })); })); })); })); })); } { const dest = getTempFile(); const stream = new Utf8Stream({ dest, sync }); ok(stream.write('hello world\n')); ok(stream.write('something else\n')); stream.reopen(); stream.end(); stream.on('close', common.mustCall()); } { const dest = getTempFile(); const stream = new Utf8Stream({ dest, minLength: 0, sync }); ok(stream.write('hello world\n')); ok(stream.write('something else\n')); const after = dest + '-new'; stream.once('drain', common.mustCall(() => { stream.reopen(after); strictEqual(stream.file, after); stream.once('ready', common.mustCall(() => { ok(stream.write('after reopen\n')); stream.once('drain', common.mustCall(() => { readFile(dest, 'utf8', common.mustSucceed((data) => { strictEqual(data, 'hello world\nsomething else\n'); readFile(after, 'utf8', common.mustSucceed((data) => { strictEqual(data, 'after reopen\n'); stream.end(); })); })); })); })); })); } { let throwOnNextOpen = false; const err = new Error('open error'); const fsOverride = {}; if (sync) { fsOverride.openSync = function(...args) { if (throwOnNextOpen) { throwOnNextOpen = false; throw err; } return openSync(...args); }; } else { fsOverride.open = function(file, flags, mode, cb) { if (throwOnNextOpen) { throwOnNextOpen = false; process.nextTick(() => cb(err)); return; } return open(file, flags, mode, cb); }; } const dest = getTempFile(); const stream = new Utf8Stream({ dest, sync, fs: fsOverride, }); ok(stream.write('hello world\n')); ok(stream.write('something else\n')); const after = dest + '-moved'; stream.on('error', common.mustCall()); stream.once('drain', common.mustCall(() => { renameSync(dest, after); throwOnNextOpen = true; if (sync) { throws(() => stream.reopen(), err); } else { stream.reopen(); } setTimeout(common.mustCall(() => { ok(stream.write('after reopen\n')); stream.end(); stream.on('finish', common.mustCall(() => { readFile(after, 'utf8', common.mustSucceed((data) => { strictEqual(data, 'hello world\nsomething else\nafter reopen\n'); })); })); }), 10); })); } { const dest = getTempFile(); const stream = new Utf8Stream({ dest, sync }); ok(stream.write('hello world\n')); ok(stream.write('something else\n')); const after = dest + '-moved'; stream.once('drain', common.mustCall(() => { renameSync(dest, after); stream.reopen(); stream.once('drain', common.mustCall(() => { ok(stream.write('after reopen\n')); stream.once('drain', common.mustCall(() => { readFile(after, 'utf8', common.mustSucceed((data) => { strictEqual(data, 'hello world\nsomething else\n'); readFile(dest, 'utf8', common.mustSucceed((data) => { strictEqual(data, 'after reopen\n'); stream.end(); })); })); })); })); })); } }