1'use strict';
2// Flags: --expose-internals
3
4const common = require('../common');
5const tmpdir = require('../common/tmpdir');
6
7// The following tests validate aggregate errors are thrown correctly
8// when both an operation and close throw.
9
10const path = require('path');
11const {
12  readFile,
13  writeFile,
14  truncate,
15  lchmod,
16} = require('fs/promises');
17const {
18  FileHandle,
19} = require('internal/fs/promises');
20
21const assert = require('assert');
22const originalFd = Object.getOwnPropertyDescriptor(FileHandle.prototype, 'fd');
23
24let count = 0;
25async function createFile() {
26  const filePath = path.join(tmpdir.path, `close_errors_${++count}.txt`);
27  await writeFile(filePath, 'content');
28  return filePath;
29}
30
31async function checkCloseError(op) {
32  try {
33    const filePath = await createFile();
34    Object.defineProperty(FileHandle.prototype, 'fd', {
35      get: function() {
36        // Close is set by using a setter,
37        // so it needs to be set on the instance.
38        const originalClose = this.close;
39        this.close = async () => {
40          // close the file
41          await originalClose.call(this);
42          const closeError = new Error('CLOSE_ERROR');
43          closeError.code = 456;
44          throw closeError;
45        };
46        return originalFd.get.call(this);
47      }
48    });
49
50    await assert.rejects(op(filePath), {
51      name: 'Error',
52      message: 'CLOSE_ERROR',
53      code: 456,
54    });
55  } finally {
56    Object.defineProperty(FileHandle.prototype, 'fd', originalFd);
57  }
58}
59(async function() {
60  tmpdir.refresh();
61  await checkCloseError((filePath) => truncate(filePath));
62  await checkCloseError((filePath) => readFile(filePath));
63  await checkCloseError((filePath) => writeFile(filePath, '123'));
64  if (common.isOSX) {
65    await checkCloseError((filePath) => lchmod(filePath, 0o777));
66  }
67})().then(common.mustCall());
68