[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_style = tab\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.yml]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto eol=lf\n"
  },
  {
    "path": ".github/security.md",
    "content": "# Security Policy\n\nTo report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: CI\non:\n  - push\n  - pull_request\njobs:\n  test:\n    name: Node.js ${{ matrix.node-version }} on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        node-version:\n          - 20\n          - 18\n        os:\n          - ubuntu-latest\n          - macos-latest\n          - windows-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node-version }}\n      - run: npm install\n      - run: npm test\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\nyarn.lock\n.nyc_output\ncoverage\ntemp\n"
  },
  {
    "path": ".npmrc",
    "content": "package-lock=false\n"
  },
  {
    "path": "copy-file-error.js",
    "content": "export default class CopyFileError extends Error {\n\tconstructor(message, {cause} = {}) {\n\t\tsuper(message, {cause});\n\t\tObject.assign(this, cause);\n\t\tthis.name = 'CopyFileError';\n\t}\n}\n"
  },
  {
    "path": "fs.js",
    "content": "import {promisify} from 'node:util';\nimport fs from 'graceful-fs';\nimport {pEvent} from 'p-event';\nimport CopyFileError from './copy-file-error.js';\n\nconst statP = promisify(fs.stat);\nconst lstatP = promisify(fs.lstat);\nconst utimesP = promisify(fs.utimes);\nconst chmodP = promisify(fs.chmod);\nconst makeDirectoryP = promisify(fs.mkdir);\n\nexport const closeSync = fs.closeSync.bind(fs);\nexport const createWriteStream = fs.createWriteStream.bind(fs);\n\nexport async function createReadStream(path, options) {\n\tconst read = fs.createReadStream(path, options);\n\n\ttry {\n\t\tawait pEvent(read, ['readable', 'end']);\n\t} catch (error) {\n\t\tthrow new CopyFileError(`Cannot read from \\`${path}\\`: ${error.message}`, {cause: error});\n\t}\n\n\treturn read;\n}\n\nexport const stat = path => statP(path).catch(error => {\n\tthrow new CopyFileError(`Cannot stat path \\`${path}\\`: ${error.message}`, {cause: error});\n});\n\nexport const lstat = path => lstatP(path).catch(error => {\n\tthrow new CopyFileError(`lstat \\`${path}\\` failed: ${error.message}`, {cause: error});\n});\n\nexport const utimes = (path, atime, mtime) => utimesP(path, atime, mtime).catch(error => {\n\tthrow new CopyFileError(`utimes \\`${path}\\` failed: ${error.message}`, {cause: error});\n});\n\nexport const chmod = (path, mode) => chmodP(path, mode).catch(error => {\n\tthrow new CopyFileError(`chmod \\`${path}\\` failed: ${error.message}`, {cause: error});\n});\n\nexport const statSync = path => {\n\ttry {\n\t\treturn fs.statSync(path);\n\t} catch (error) {\n\t\tthrow new CopyFileError(`stat \\`${path}\\` failed: ${error.message}`, {cause: error});\n\t}\n};\n\nexport const lstatSync = path => {\n\ttry {\n\t\treturn fs.statSync(path);\n\t} catch (error) {\n\t\tthrow new CopyFileError(`stat \\`${path}\\` failed: ${error.message}`, {cause: error});\n\t}\n};\n\nexport const utimesSync = (path, atime, mtime) => {\n\ttry {\n\t\treturn fs.utimesSync(path, atime, mtime);\n\t} catch (error) {\n\t\tthrow new CopyFileError(`utimes \\`${path}\\` failed: ${error.message}`, {cause: error});\n\t}\n};\n\nexport const makeDirectory = (path, options) => makeDirectoryP(path, {...options, recursive: true}).catch(error => {\n\tthrow new CopyFileError(`Cannot create directory \\`${path}\\`: ${error.message}`, {cause: error});\n});\n\nexport const makeDirectorySync = (path, options) => {\n\ttry {\n\t\tfs.mkdirSync(path, {...options, recursive: true});\n\t} catch (error) {\n\t\tthrow new CopyFileError(`Cannot create directory \\`${path}\\`: ${error.message}`, {cause: error});\n\t}\n};\n\nexport const copyFileSync = (source, destination, flags) => {\n\ttry {\n\t\tfs.copyFileSync(source, destination, flags);\n\t} catch (error) {\n\t\tthrow new CopyFileError(`Cannot copy from \\`${source}\\` to \\`${destination}\\`: ${error.message}`, {cause: error});\n\t}\n};\n"
  },
  {
    "path": "index.d.ts",
    "content": "export type Options = {\n\t/**\n\tOverwrite existing destination file.\n\n\t@default true\n\t*/\n\treadonly overwrite?: boolean;\n\n\t/**\n\t[Permissions](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation) for created directories.\n\n\tIt has no effect on Windows.\n\n\t@default 0o777\n\t*/\n\treadonly directoryMode?: number;\n\n\t/**\n\tThe working directory to find source files.\n\n\tThe source and destination path are relative to this.\n\n\t@default process.cwd()\n\t*/\n\treadonly cwd?: string;\n};\n\nexport type AsyncOptions = {\n\t/**\n\tThe given function is called whenever there is measurable progress.\n\n\tNote: For empty files, the `onProgress` event is emitted only once.\n\n\t@example\n\t```\n\timport {copyFile} from 'copy-file';\n\n\tawait copyFile('source/unicorn.png', 'destination/unicorn.png', {\n\t\tonProgress: progress => {\n\t\t\t// …\n\t\t}\n\t});\n\t```\n\t*/\n\treadonly onProgress?: (progress: ProgressData) => void;\n};\n\nexport type ProgressData = {\n\t/**\n\tAbsolute path to source.\n\t*/\n\tsourcePath: string;\n\n\t/**\n\tAbsolute path to destination.\n\t*/\n\tdestinationPath: string;\n\n\t/**\n\tFile size in bytes.\n\t*/\n\tsize: number;\n\n\t/**\n\tCopied size in bytes.\n\t*/\n\twrittenBytes: number;\n\n\t/**\n\tCopied percentage, a value between `0` and `1`.\n\t*/\n\tpercent: number;\n};\n\n/**\nCopy a file.\n\n@param source - The file you want to copy.\n@param destination - Where you want the file copied.\n@returns A `Promise` that resolves when the file is copied.\n\nThe file is cloned if the `onProgress` option is not passed and the [file system supports it](https://stackoverflow.com/a/76496347/64949).\n\n@example\n```\nimport {copyFile} from 'copy-file';\n\nawait copyFile('source/unicorn.png', 'destination/unicorn.png');\nconsole.log('File copied');\n```\n*/\nexport function copyFile(source: string, destination: string, options?: Options & AsyncOptions): Promise<void>;\n\n/**\nCopy a file synchronously.\n\n@param source - The file you want to copy.\n@param destination - Where you want the file copied.\n\nThe file is cloned if the [file system supports it](https://stackoverflow.com/a/76496347/64949).\n\n@example\n```\nimport {copyFileSync} from 'copy-file';\n\ncopyFileSync('source/unicorn.png', 'destination/unicorn.png');\n```\n*/\nexport function copyFileSync(source: string, destination: string, options?: Options): void;\n"
  },
  {
    "path": "index.js",
    "content": "import path from 'node:path';\nimport realFS, {constants as fsConstants} from 'node:fs';\nimport realFSPromises from 'node:fs/promises';\nimport {pEvent} from 'p-event';\nimport CopyFileError from './copy-file-error.js';\nimport * as fs from './fs.js';\n\nconst resolvePath = (cwd, sourcePath, destinationPath) => ({\n\tsourcePath: path.resolve(cwd, sourcePath),\n\tdestinationPath: path.resolve(cwd, destinationPath),\n});\n\nconst checkSourceIsFile = (stat, source) => {\n\tif (!stat.isFile()) {\n\t\tthrow Object.assign(new CopyFileError(`EISDIR: illegal operation on a directory '${source}'`), {\n\t\t\terrno: -21,\n\t\t\tcode: 'EISDIR',\n\t\t\tsource,\n\t\t});\n\t}\n};\n\nexport async function copyFile(sourcePath, destinationPath, options = {}) {\n\tif (!sourcePath || !destinationPath) {\n\t\tthrow new CopyFileError('`source` and `destination` required');\n\t}\n\n\tif (options.cwd) {\n\t\t({sourcePath, destinationPath} = resolvePath(options.cwd, sourcePath, destinationPath));\n\t}\n\n\toptions = {\n\t\toverwrite: true,\n\t\t...options,\n\t};\n\n\tconst stats = await fs.lstat(sourcePath);\n\tconst {size} = stats;\n\tcheckSourceIsFile(stats, sourcePath);\n\n\tconst destinationDirectory = path.dirname(destinationPath);\n\tconst isRootDirectory = path.parse(destinationDirectory).root === destinationDirectory;\n\tif (!isRootDirectory) {\n\t\tawait fs.makeDirectory(path.dirname(destinationPath), {mode: options.directoryMode});\n\t}\n\n\tif (typeof options.onProgress === 'function') {\n\t\tconst readStream = await fs.createReadStream(sourcePath);\n\t\tconst writeStream = fs.createWriteStream(destinationPath, {flags: options.overwrite ? 'w' : 'wx'});\n\n\t\tconst emitProgress = writtenBytes => {\n\t\t\toptions.onProgress({\n\t\t\t\tsourcePath: path.resolve(sourcePath),\n\t\t\t\tdestinationPath: path.resolve(destinationPath),\n\t\t\t\tsize,\n\t\t\t\twrittenBytes,\n\t\t\t\tpercent: writtenBytes === size ? 1 : writtenBytes / size,\n\t\t\t});\n\t\t};\n\n\t\tlet lastEmittedPercent = -1;\n\n\t\treadStream.on('data', () => {\n\t\t\tconst written = writeStream.bytesWritten;\n\t\t\tconst percent = written === size ? 1 : written / size;\n\n\t\t\t// Throttle progress events.\n\t\t\tif (percent === 1 || (percent - lastEmittedPercent) >= 0.01) {\n\t\t\t\tlastEmittedPercent = percent;\n\t\t\t\temitProgress(written);\n\t\t\t}\n\t\t});\n\n\t\tlet readError;\n\n\t\treadStream.once('error', error => {\n\t\t\treadError = new CopyFileError(`Cannot read from \\`${sourcePath}\\`: ${error.message}`, {cause: error});\n\t\t});\n\n\t\tlet shouldUpdateStats = false;\n\t\ttry {\n\t\t\tconst writePromise = pEvent(writeStream, 'close');\n\t\t\treadStream.pipe(writeStream);\n\t\t\tawait writePromise;\n\t\t\temitProgress(size);\n\t\t\tshouldUpdateStats = true;\n\t\t} catch (error) {\n\t\t\tthrow new CopyFileError(`Cannot write to \\`${destinationPath}\\`: ${error.message}`, {cause: error});\n\t\t}\n\n\t\tif (readError) {\n\t\t\tthrow readError;\n\t\t}\n\n\t\tif (shouldUpdateStats) {\n\t\t\tconst stats = await fs.lstat(sourcePath);\n\n\t\t\treturn Promise.all([\n\t\t\t\tfs.utimes(destinationPath, stats.atime, stats.mtime).catch(error => {\n\t\t\t\t\t// Ignore EPERM errors on utime (e.g., Samba shares)\n\t\t\t\t\tif (error.code !== 'EPERM') {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t\tfs.chmod(destinationPath, stats.mode),\n\t\t\t]);\n\t\t}\n\t} else {\n\t\t// eslint-disable-next-line no-bitwise\n\t\tconst flags = options.overwrite ? fsConstants.COPYFILE_FICLONE : (fsConstants.COPYFILE_FICLONE | fsConstants.COPYFILE_EXCL);\n\n\t\ttry {\n\t\t\tawait realFSPromises.copyFile(sourcePath, destinationPath, flags);\n\n\t\t\tawait Promise.all([\n\t\t\t\trealFSPromises.utimes(destinationPath, stats.atime, stats.mtime).catch(error => {\n\t\t\t\t\t// Ignore EPERM errors on utime (e.g., Samba shares)\n\t\t\t\t\tif (error.code !== 'EPERM') {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t\trealFSPromises.chmod(destinationPath, stats.mode),\n\t\t\t]);\n\t\t} catch (error) {\n\t\t\tthrow new CopyFileError(error.message, {cause: error});\n\t\t}\n\t}\n}\n\nexport function copyFileSync(sourcePath, destinationPath, options = {}) {\n\tif (!sourcePath || !destinationPath) {\n\t\tthrow new CopyFileError('`source` and `destination` required');\n\t}\n\n\tif (options.cwd) {\n\t\t({sourcePath, destinationPath} = resolvePath(options.cwd, sourcePath, destinationPath));\n\t}\n\n\toptions = {\n\t\toverwrite: true,\n\t\t...options,\n\t};\n\n\tconst stats = fs.lstatSync(sourcePath);\n\tcheckSourceIsFile(stats, sourcePath);\n\n\tconst destinationDirectory = path.dirname(destinationPath);\n\tconst isRootDirectory = path.parse(destinationDirectory).root === destinationDirectory;\n\tif (!isRootDirectory) {\n\t\tfs.makeDirectorySync(path.dirname(destinationPath), {mode: options.directoryMode});\n\t}\n\n\t// eslint-disable-next-line no-bitwise\n\tconst flags = options.overwrite ? fsConstants.COPYFILE_FICLONE : (fsConstants.COPYFILE_FICLONE | fsConstants.COPYFILE_EXCL);\n\ttry {\n\t\trealFS.copyFileSync(sourcePath, destinationPath, flags);\n\t} catch (error) {\n\t\tthrow new CopyFileError(error.message, {cause: error});\n\t}\n\n\ttry {\n\t\tfs.utimesSync(destinationPath, stats.atime, stats.mtime);\n\t} catch (error) {\n\t\t// Ignore EPERM errors on utime (e.g., Samba shares)\n\t\tif (error.code !== 'EPERM') {\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tfs.chmod(destinationPath, stats.mode);\n}\n"
  },
  {
    "path": "index.test-d.ts",
    "content": "import {expectError, expectType} from 'tsd';\nimport {copyFile, copyFileSync, type ProgressData} from './index.js';\n\nexpectType<Promise<void> >(\n\tcopyFile('source/unicorn.png', 'destination/unicorn.png'),\n);\nexpectType<Promise<void>>(\n\tcopyFile('source/unicorn.png', 'destination/unicorn.png', {overwrite: false}),\n);\nexpectType<Promise<void>>(\n\tcopyFile('source/unicorn.png', 'destination/unicorn.png', {\n\t\tdirectoryMode: 0o700,\n\t}),\n);\nexpectError(\n\tawait copyFile('source/unicorn.png', 'destination/unicorn.png', {\n\t\tdirectoryMode: '700',\n\t}),\n);\nexpectType<Promise<void>>(\n\tcopyFile('source/unicorn.png', 'destination/unicorn.png', {\n\t\tonProgress(progress) {\n\t\t\texpectType<ProgressData>(progress);\n\t\t\texpectType<string>(progress.sourcePath);\n\t\t\texpectType<string>(progress.destinationPath);\n\t\t\texpectType<number>(progress.size);\n\t\t\texpectType<number>(progress.writtenBytes);\n\t\t\texpectType<number>(progress.percent);\n\t\t},\n\t}),\n);\n\nexpectType<void>(copyFileSync('source/unicorn.png', 'destination/unicorn.png'));\nexpectType<void>(\n\tcopyFileSync('source/unicorn.png', 'destination/unicorn.png', {\n\t\toverwrite: false,\n\t}),\n);\nexpectType<void>(\n\tcopyFileSync('source/unicorn.png', 'destination/unicorn.png', {\n\t\tdirectoryMode: 0o700,\n\t}),\n);\nexpectError(\n\tcopyFileSync('source/unicorn.png', 'destination/unicorn.png', {\n\t\tdirectoryMode: '700',\n\t}),\n);\n"
  },
  {
    "path": "license",
    "content": "MIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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.\n"
  },
  {
    "path": "package.json",
    "content": "{\n\t\"name\": \"copy-file\",\n\t\"version\": \"11.1.0\",\n\t\"description\": \"Copy a file\",\n\t\"license\": \"MIT\",\n\t\"repository\": \"sindresorhus/copy-file\",\n\t\"funding\": \"https://github.com/sponsors/sindresorhus\",\n\t\"author\": {\n\t\t\"name\": \"Sindre Sorhus\",\n\t\t\"email\": \"sindresorhus@gmail.com\",\n\t\t\"url\": \"https://sindresorhus.com\"\n\t},\n\t\"type\": \"module\",\n\t\"exports\": {\n\t\t\"types\": \"./index.d.ts\",\n\t\t\"default\": \"./index.js\"\n\t},\n\t\"sideEffects\": false,\n\t\"engines\": {\n\t\t\"node\": \">=18\"\n\t},\n\t\"scripts\": {\n\t\t\"test\": \"xo && nyc ava && tsd\"\n\t},\n\t\"files\": [\n\t\t\"index.js\",\n\t\t\"index.d.ts\",\n\t\t\"copy-file-error.js\",\n\t\t\"fs.js\"\n\t],\n\t\"keywords\": [\n\t\t\"copy\",\n\t\t\"copying\",\n\t\t\"cp\",\n\t\t\"file\",\n\t\t\"clone\",\n\t\t\"fs\",\n\t\t\"stream\",\n\t\t\"file-system\",\n\t\t\"filesystem\",\n\t\t\"ncp\",\n\t\t\"fast\",\n\t\t\"quick\",\n\t\t\"data\",\n\t\t\"content\",\n\t\t\"contents\",\n\t\t\"read\",\n\t\t\"write\",\n\t\t\"io\"\n\t],\n\t\"dependencies\": {\n\t\t\"graceful-fs\": \"^4.2.11\",\n\t\t\"p-event\": \"^6.0.0\"\n\t},\n\t\"devDependencies\": {\n\t\t\"ava\": \"^5.3.1\",\n\t\t\"clear-module\": \"^4.1.2\",\n\t\t\"coveralls\": \"^3.1.1\",\n\t\t\"del\": \"^7.1.0\",\n\t\t\"import-fresh\": \"^3.3.0\",\n\t\t\"nyc\": \"^15.1.0\",\n\t\t\"sinon\": \"^17.0.1\",\n\t\t\"tsd\": \"^0.29.0\",\n\t\t\"xo\": \"^0.56.0\"\n\t},\n\t\"xo\": {\n\t\t\"rules\": {\n\t\t\t\"ava/assertion-arguments\": \"off\"\n\t\t}\n\t},\n\t\"ava\": {\n\t\t\"workerThreads\": false,\n\t\t\"serial\": true\n\t}\n}\n"
  },
  {
    "path": "readme.md",
    "content": "# copy-file\n\n> Copy a file\n\n## Highlights\n\n- It's super fast by [cloning](https://stackoverflow.com/questions/71629903/node-js-why-we-should-use-copyfile-ficlone-and-copyfile-ficlone-force-what-is) the file whenever possible.\n- Resilient by using [graceful-fs](https://github.com/isaacs/node-graceful-fs).\n- User-friendly by creating non-existent destination directories for you.\n- Can be safe by turning off [overwriting](#overwrite).\n- Preserves file mode [but not ownership](https://github.com/sindresorhus/copy-file/issues/22#issuecomment-502079547).\n- User-friendly errors.\n\n## Install\n\n```sh\nnpm install copy-file\n```\n\n## Usage\n\n```js\nimport {copyFile} from 'copy-file';\n\nawait copyFile('source/unicorn.png', 'destination/unicorn.png');\nconsole.log('File copied');\n```\n\n## API\n\n### copyFile(source, destination, options?)\n\nReturns a `Promise` that resolves when the file is copied.\n\nThe file is cloned if the `onProgress` option is not passed and the [file system supports it](https://stackoverflow.com/a/76496347/64949).\n\n### copyFileSync(source, destination, options?)\n\n#### source\n\nType: `string`\n\nThe file you want to copy.\n\nThe file is cloned if the [file system supports it](https://stackoverflow.com/a/76496347/64949).\n\n#### destination\n\nType: `string`\n\nWhere you want the file copied.\n\n#### options\n\nType: `object`\n\n##### overwrite\n\nType: `boolean`\\\nDefault: `true`\n\nOverwrite existing destination file.\n\n##### cwd\n\nType: `string`\\\nDefault: `process.cwd()`\n\nThe working directory to find source files.\n\nThe source and destination path are relative to this.\n\n##### directoryMode\n\nType: `number`\\\nDefault: `0o777`\n\n[Permissions](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation) for created directories.\n\nIt has no effect on Windows.\n\n##### onProgress\n\nType: `(progress: ProgressData) => void`\n\nThe given function is called whenever there is measurable progress.\n\nOnly available when using the async method.\n\n###### `ProgressData`\n\n```js\n{\n\tsourcePath: string,\n\tdestinationPath: string,\n\tsize: number,\n\twrittenBytes: number,\n\tpercent: number\n}\n```\n\n- `sourcePath` and `destinationPath` are absolute paths.\n- `size` and `writtenBytes` are in bytes.\n- `percent` is a value between `0` and `1`.\n\n###### Notes\n\n- For empty files, the `onProgress` callback function is emitted only once.\n\n```js\nimport {copyFile} from 'copy-file';\n\nawait copyFile(source, destination, {\n\tonProgress: progress => {\n\t\t// …\n\t}\n});\n```\n\n## Related\n\n- [cpy](https://github.com/sindresorhus/cpy) - Copy files\n- [cpy-cli](https://github.com/sindresorhus/cpy-cli) - Copy files on the command-line\n- [move-file](https://github.com/sindresorhus/move-file) - Move a file\n- [make-dir](https://github.com/sindresorhus/make-dir) - Make a directory and its parents if needed\n"
  },
  {
    "path": "test/async.js",
    "content": "import process from 'node:process';\nimport crypto from 'node:crypto';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport {fileURLToPath} from 'node:url';\nimport importFresh from 'import-fresh';\nimport clearModule from 'clear-module';\nimport {deleteSync} from 'del';\nimport test from 'ava';\nimport sinon from 'sinon';\nimport {copyFile} from '../index.js';\nimport assertDateEqual from './helpers/_assert.js';\nimport {buildEACCES, buildENOSPC, buildENOENT, buildEPERM, buildERRSTREAMWRITEAFTEREND} from './helpers/_fs-errors.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst THREE_HUNDRED_KILO = (100 * 3 * 1024) + 1;\n\ntest.before(() => {\n\tprocess.chdir(path.dirname(__dirname));\n\tdeleteSync('temp'); // In case last test run failed.\n\tfs.mkdirSync('temp');\n});\n\ntest.after(() => {\n\tdeleteSync('temp');\n});\n\ntest.beforeEach(t => {\n\tt.context.source = path.join('temp', crypto.randomUUID());\n\tt.context.destination = path.join('temp', crypto.randomUUID());\n});\n\ntest('reject an Error on missing `source`', async t => {\n\tawait t.throwsAsync(copyFile(), {\n\t\tmessage: /`source`/,\n\t});\n});\n\ntest('reject an Error on missing `destination`', async t => {\n\tawait t.throwsAsync(copyFile('TARGET'), {\n\t\tmessage: /`destination`/,\n\t});\n});\n\ntest('copy a file', async t => {\n\tawait copyFile('license', t.context.destination);\n\tt.is(fs.readFileSync(t.context.destination, 'utf8'), fs.readFileSync('license', 'utf8'));\n});\n\ntest('copy an empty file', async t => {\n\tfs.writeFileSync(t.context.source, '');\n\tawait copyFile(t.context.source, t.context.destination);\n\tt.is(fs.readFileSync(t.context.destination, 'utf8'), '');\n});\n\ntest('copy big files', async t => {\n\tconst buffer = crypto.randomBytes(THREE_HUNDRED_KILO);\n\tfs.writeFileSync(t.context.source, buffer);\n\tawait copyFile(t.context.source, t.context.destination);\n\tt.true(buffer.equals(fs.readFileSync(t.context.destination)));\n});\n\ntest('do not alter overwrite option', async t => {\n\tconst options = {};\n\tawait copyFile('license', t.context.destination, options);\n\tt.false('overwrite' in options);\n});\n\ntest('overwrite when enabled', async t => {\n\tfs.writeFileSync(t.context.destination, '');\n\tawait copyFile('license', t.context.destination, {overwrite: true});\n\tt.is(fs.readFileSync(t.context.destination, 'utf8'), fs.readFileSync('license', 'utf8'));\n});\n\ntest('overwrite when options are undefined', async t => {\n\tfs.writeFileSync(t.context.destination, '');\n\tawait copyFile('license', t.context.destination);\n\tt.is(fs.readFileSync(t.context.destination, 'utf8'), fs.readFileSync('license', 'utf8'));\n});\n\ntest('do not overwrite when disabled', async t => {\n\tfs.writeFileSync(t.context.destination, '');\n\tconst error = await t.throwsAsync(copyFile('license', t.context.destination, {overwrite: false}));\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.code, 'EEXIST', error.message);\n});\n\nif (process.platform !== 'win32') {\n\ttest('create directories with specified mode', async t => {\n\t\tconst directory = t.context.destination;\n\t\tconst destination = `${directory}/${crypto.randomUUID()}`;\n\t\tconst directoryMode = 0o700;\n\t\tawait copyFile('license', destination, {directoryMode});\n\t\tconst stat = fs.statSync(directory);\n\t\tt.is(stat.mode & directoryMode, directoryMode); // eslint-disable-line no-bitwise\n\t});\n}\n\ntest('do not create `destination` on unreadable `source`', async t => {\n\tconst error = await t.throwsAsync(copyFile('node_modules', t.context.destination));\n\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.code, 'EISDIR', error.message);\n\n\tt.throws(() => {\n\t\tfs.statSync(t.context.destination);\n\t}, {\n\t\tmessage: /ENOENT/,\n\t});\n});\n\ntest('do not create `destination` directory on unreadable `source`', async t => {\n\tconst error = await t.throwsAsync(copyFile('node_modules', path.join('temp/subdir', crypto.randomUUID())));\n\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.code, 'EISDIR', error.message);\n\tt.false(fs.existsSync('subdir'));\n});\n\ntest('preserve timestamps', async t => {\n\tawait copyFile('license', t.context.destination);\n\tconst licenseStats = fs.lstatSync('license');\n\tconst temporaryStats = fs.lstatSync(t.context.destination);\n\tassertDateEqual(t, licenseStats.atime, temporaryStats.atime);\n\tassertDateEqual(t, licenseStats.mtime, temporaryStats.mtime);\n});\n\ntest('preserve mode', async t => {\n\tawait copyFile('license', t.context.destination);\n\tconst licenseStats = fs.lstatSync('license');\n\tconst temporaryStats = fs.lstatSync(t.context.destination);\n\tt.is(licenseStats.mode, temporaryStats.mode);\n});\n\ntest('throw an Error if `source` does not exists', async t => {\n\tconst error = await t.throwsAsync(copyFile('NO_ENTRY', t.context.destination));\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.code, 'ENOENT', error.message);\n\tt.regex(error.message, /`NO_ENTRY`/, error.message);\n\tt.regex(error.stack, /`NO_ENTRY`/, error.message);\n});\n\ntest.serial.failing('rethrow mkdir EACCES errors', async t => {\n\tconst directoryPath = `/root/NO_ACCESS_${crypto.randomUUID()}`;\n\tconst destination = path.join(directoryPath, crypto.randomUUID());\n\tconst mkdirError = buildEACCES(directoryPath);\n\n\tfs.stat = sinon.stub(fs, 'stat').throws(mkdirError);\n\tfs.mkdir = sinon.stub(fs, 'mkdir').throws(mkdirError);\n\n\tconst error = await t.throwsAsync(copyFile('license', destination));\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.errno, mkdirError.errno, error.message);\n\tt.is(error.code, mkdirError.code, error.message);\n\tt.is(error.path, mkdirError.path, error.message);\n\tt.true(fs.mkdir.called || fs.stat.called);\n\n\tfs.mkdir.restore();\n\tfs.stat.restore();\n});\n\ntest.serial.failing('rethrow ENOSPC errors', async t => {\n\tconst {createWriteStream} = fs;\n\tconst noSpaceError = buildENOSPC();\n\tlet isCalled = false;\n\n\tfs.createWriteStream = (path, options) => {\n\t\tconst stream = createWriteStream(path, options);\n\t\tif (path === t.context.destination) {\n\t\t\tstream.on('pipe', () => {\n\t\t\t\tif (!isCalled) {\n\t\t\t\t\tisCalled = true;\n\t\t\t\t\tstream.emit('error', noSpaceError);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn stream;\n\t};\n\n\tclearModule('../fs.js');\n\tconst uncached = importFresh('../index.js');\n\tconst error = await t.throwsAsync(uncached('license', t.context.destination));\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.errno, noSpaceError.errno, error.message);\n\tt.is(error.code, noSpaceError.code, error.message);\n\tt.true(isCalled);\n\n\tfs.createWriteStream = createWriteStream;\n});\n\ntest.serial.failing('rethrow stat errors', async t => {\n\tconst fstatError = buildENOENT();\n\n\tfs.writeFileSync(t.context.source, '');\n\tfs.lstat = sinon.stub(fs, 'lstat').throws(fstatError);\n\n\tclearModule('../fs.js');\n\tconst uncached = importFresh('../index.js');\n\tconst error = await t.throwsAsync(uncached(t.context.source, t.context.destination));\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.errno, fstatError.errno, error.message);\n\tt.is(error.code, fstatError.code, error.message);\n\tt.true(fs.lstat.called);\n\n\tfs.lstat.restore();\n});\n\ntest.serial.failing('rethrow utimes errors', async t => {\n\tconst utimesError = buildENOENT();\n\n\tfs.utimes = sinon.stub(fs, 'utimes').throws(utimesError);\n\n\tclearModule('../fs.js');\n\tconst uncached = importFresh('../index.js');\n\tconst error = await t.throwsAsync(uncached('license', t.context.destination));\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.code, 'ENOENT', error.message);\n\tt.true(fs.utimes.called);\n\n\tfs.utimes.restore();\n});\n\ntest.serial.failing('rethrow chmod errors', async t => {\n\tconst chmodError = buildEPERM(t.context.destination, 'chmod');\n\n\tfs.chmod = sinon.stub(fs, 'chmod').throws(chmodError);\n\n\tclearModule('../fs.js');\n\tconst uncached = importFresh('../index.js');\n\tconst error = await t.throwsAsync(uncached('license', t.context.destination));\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.code, chmodError.code, error.message);\n\tt.is(error.path, chmodError.path, error.message);\n\tt.true(fs.chmod.called);\n\n\tfs.chmod.restore();\n});\n\ntest.serial.failing('rethrow read after open errors', async t => {\n\tconst {createWriteStream, createReadStream} = fs;\n\tlet calledWriteEnd = 0;\n\tlet readStream;\n\tconst readError = buildERRSTREAMWRITEAFTEREND();\n\n\tfs.createWriteStream = (...arguments_) => {\n\t\tconst stream = createWriteStream(...arguments_);\n\t\tconst {end} = stream;\n\n\t\tstream.on('pipe', () => {\n\t\t\treadStream.emit('error', readError);\n\t\t});\n\n\t\tstream.end = (...endArgs) => {\n\t\t\tcalledWriteEnd++;\n\t\t\treturn end.apply(stream, endArgs);\n\t\t};\n\n\t\treturn stream;\n\t};\n\n\tfs.createReadStream = (...arguments_) => {\n\t\t/* Fake stream */\n\t\treadStream = createReadStream(...arguments_);\n\t\treadStream.pause();\n\n\t\treturn readStream;\n\t};\n\n\tclearModule('../fs.js');\n\tconst uncached = importFresh('../index.js');\n\tconst error = await t.throwsAsync(uncached('license', t.context.destination));\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.code, readError.code, error.message);\n\tt.is(error.errno, readError.errno, error.message);\n\tt.is(calledWriteEnd, 1);\n\n\tObject.assign(fs, {createWriteStream, createReadStream});\n});\n\ntest('cwd option', async t => {\n\tconst error = await t.throwsAsync(copyFile('sync.js', t.context.destination));\n\n\tt.is(error.name, 'CopyFileError');\n\tt.is(error.code, 'ENOENT');\n\n\tawait t.notThrowsAsync(copyFile('sync.js', t.context.destination, {cwd: 'test'}));\n});\n"
  },
  {
    "path": "test/helpers/_assert.js",
    "content": "/**\nTests equality of Date objects, w/o considering milliseconds.\n\n@see {@link https://github.com/joyent/node/issues/7000|File timestamp resolution is inconsistent with fs.stat / fs.utimes}\n\n@param {Object} t - AVA's t\n@param {*} actual - the actual value\n@param {*} expected - the expected value\n@param {*} message - error message\n*/\nexport default function assertDateEqual(t, actual, expected, message) {\n\tactual = new Date(actual);\n\texpected = new Date(expected);\n\n\tactual.setMilliseconds(0);\n\texpected.setMilliseconds(0);\n\n\tt.is(actual.getTime(), expected.getTime(), message);\n}\n"
  },
  {
    "path": "test/helpers/_fs-errors.js",
    "content": "export const buildEACCES = path => Object.assign(new Error(`EACCES: permission denied '${path}'`), {\n\terrno: -13,\n\tcode: 'EACCES',\n\tpath,\n});\n\nexport const buildENOSPC = () => Object.assign(new Error('ENOSPC, write'), {\n\terrno: -28,\n\tcode: 'ENOSPC',\n});\n\nexport const buildENOENT = path => Object.assign(new Error(`ENOENT: no such file or directory '${path}'`), {\n\terrno: -2,\n\tcode: 'ENOENT',\n\tpath,\n});\n\nexport const buildERRSTREAMWRITEAFTEREND = () => Object.assign(new Error('ERR_STREAM_WRITE_AFTER_END'), {\n\tcode: 'ERR_STREAM_WRITE_AFTER_END',\n});\n\nexport const buildEBADF = () => Object.assign(new Error('EBADF: bad file descriptor'), {\n\terrno: -9,\n\tcode: 'EBADF',\n});\n\nexport const buildEPERM = (path, method) => Object.assign(new Error(`EPERM: ${method} '${path}''`), {\n\terrno: 50,\n\tcode: 'EPERM',\n});\n"
  },
  {
    "path": "test/progress.js",
    "content": "import {Buffer} from 'node:buffer';\nimport process from 'node:process';\nimport crypto from 'node:crypto';\nimport path from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport fs from 'node:fs';\nimport {deleteSync} from 'del';\nimport test from 'ava';\nimport {copyFile} from '../index.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst THREE_HUNDRED_KILO = (100 * 3 * 1024) + 1;\n\ntest.before(() => {\n\tprocess.chdir(path.dirname(__dirname));\n\tdeleteSync('temp'); // In case last test run failed.\n\tfs.mkdirSync('temp');\n});\n\ntest.after(() => {\n\tdeleteSync('temp');\n});\n\ntest.beforeEach(t => {\n\tt.context.source = path.join('temp', crypto.randomUUID());\n\tt.context.destination = path.join('temp', crypto.randomUUID());\n});\n\ntest('report progress', async t => {\n\tconst buffer = crypto.randomBytes(THREE_HUNDRED_KILO);\n\tfs.writeFileSync(t.context.source, buffer);\n\n\tlet callCount = 0;\n\n\tawait copyFile(t.context.source, t.context.destination, {\n\t\tonProgress(progress) {\n\t\t\tcallCount++;\n\t\t\tt.is(typeof progress.sourcePath, 'string');\n\t\t\tt.is(typeof progress.destinationPath, 'string');\n\t\t\tt.is(typeof progress.size, 'number');\n\t\t\tt.is(typeof progress.writtenBytes, 'number');\n\t\t\tt.is(typeof progress.percent, 'number');\n\t\t\tt.is(progress.size, THREE_HUNDRED_KILO);\n\t\t},\n\t});\n\n\tt.true(callCount > 0);\n});\n\ntest('report progress of 100% on end', async t => {\n\tconst buffer = crypto.randomBytes(THREE_HUNDRED_KILO);\n\tfs.writeFileSync(t.context.source, buffer);\n\n\tlet lastRecord;\n\n\tawait copyFile(t.context.source, t.context.destination, {\n\t\tonProgress(progress) {\n\t\t\tlastRecord = progress;\n\t\t},\n\t});\n\n\tt.is(lastRecord.percent, 1);\n\tt.is(lastRecord.writtenBytes, THREE_HUNDRED_KILO);\n});\n\ntest('report progress for empty files once', async t => {\n\tfs.writeFileSync(t.context.source, '');\n\n\tlet callCount = 0;\n\n\tawait copyFile(t.context.source, t.context.destination, {\n\t\tonProgress(progress) {\n\t\t\tcallCount++;\n\t\t\tt.is(progress.size, 0);\n\t\t\tt.is(progress.writtenBytes, 0);\n\t\t\tt.is(progress.percent, 1);\n\t\t},\n\t});\n\n\tt.is(callCount, 1);\n});\n\ntest('progress emits ≤101 times and finishes at 100%', async t => {\n\tconst size = 10 * 1024 * 1024; // 10 MiB\n\tconst source = path.join('temp', `cap-${crypto.randomUUID()}.bin`);\n\tconst destination = path.join('temp', `cap-out-${crypto.randomUUID()}.bin`);\n\tfs.mkdirSync('temp', {recursive: true});\n\tfs.writeFileSync(source, crypto.randomBytes(size));\n\n\tlet callCount = 0;\n\tlet lastRecord;\n\tawait copyFile(source, destination, {\n\t\tonProgress(progress) {\n\t\t\tcallCount++;\n\t\t\tlastRecord = progress;\n\t\t},\n\t});\n\n\tt.true(callCount <= 101);\n\tt.is(lastRecord.percent, 1);\n\tt.is(lastRecord.writtenBytes, size);\n\tt.true(fs.existsSync(destination));\n});\n\ntest('progress emits at least once for tiny/empty files', async t => {\n\tfor (const bytes of [0, 1, 42]) {\n\t\tconst source = path.join('temp', `tiny-${bytes}-${crypto.randomUUID()}`);\n\t\tconst destination = path.join('temp', `tiny-out-${bytes}-${crypto.randomUUID()}`);\n\t\tfs.writeFileSync(source, Buffer.alloc(bytes));\n\n\t\tlet callCount = 0;\n\t\tlet lastRecord;\n\n\t\t// eslint-disable-next-line no-await-in-loop\n\t\tawait copyFile(source, destination, {\n\t\t\tonProgress(progress) {\n\t\t\t\tcallCount++;\n\t\t\t\tlastRecord = progress;\n\t\t\t},\n\t\t});\n\n\t\tt.true(callCount >= 1);\n\t\tt.is(lastRecord.percent, 1);\n\t\tt.is(lastRecord.writtenBytes, bytes);\n\t}\n});\n"
  },
  {
    "path": "test/sync.js",
    "content": "import process from 'node:process';\nimport crypto from 'node:crypto';\nimport {fileURLToPath} from 'node:url';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport {deleteSync} from 'del';\nimport test from 'ava';\nimport sinon from 'sinon';\nimport {copyFileSync} from '../index.js';\nimport assertDateEqual from './helpers/_assert.js';\nimport {buildEACCES, buildENOSPC, buildEBADF} from './helpers/_fs-errors.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst THREE_HUNDRED_KILO = (100 * 3 * 1024) + 1;\n\ntest.before(() => {\n\tprocess.chdir(path.dirname(__dirname));\n\tdeleteSync('temp'); // In case last test run failed.\n\tfs.mkdirSync('temp');\n});\n\ntest.after(() => {\n\tdeleteSync('temp');\n});\n\ntest.beforeEach(t => {\n\tt.context.source = path.join('temp', crypto.randomUUID());\n\tt.context.destination = path.join('temp', crypto.randomUUID());\n});\n\ntest('throw an Error on missing `source`', t => {\n\tt.throws(() => {\n\t\tcopyFileSync();\n\t}, {\n\t\tmessage: /`source`/,\n\t});\n});\n\ntest('throw an Error on missing `destination`', t => {\n\tt.throws(() => {\n\t\tcopyFileSync('TARGET');\n\t}, {\n\t\tmessage: /`destination`/,\n\t});\n});\n\ntest('copy a file', t => {\n\tcopyFileSync('license', t.context.destination);\n\tt.is(fs.readFileSync(t.context.destination, 'utf8'), fs.readFileSync('license', 'utf8'));\n});\n\ntest('copy an empty file', t => {\n\tfs.writeFileSync(t.context.source, '');\n\tcopyFileSync(t.context.source, t.context.destination);\n\tt.is(fs.readFileSync(t.context.destination, 'utf8'), '');\n});\n\ntest('copy big files', t => {\n\tconst buffer = crypto.randomBytes(THREE_HUNDRED_KILO);\n\tfs.writeFileSync(t.context.source, buffer);\n\tcopyFileSync(t.context.source, t.context.destination);\n\tt.true(buffer.equals(fs.readFileSync(t.context.destination)));\n});\n\ntest('do not alter overwrite option', t => {\n\tconst options = {};\n\tcopyFileSync('license', t.context.destination, options);\n\tt.false('overwrite' in options);\n});\n\ntest('overwrite when enabled', t => {\n\tfs.writeFileSync(t.context.destination, '');\n\tcopyFileSync('license', t.context.destination, {overwrite: true});\n\tt.is(fs.readFileSync(t.context.destination, 'utf8'), fs.readFileSync('license', 'utf8'));\n});\n\ntest('overwrite when options are undefined', t => {\n\tfs.writeFileSync(t.context.destination, '');\n\tcopyFileSync('license', t.context.destination);\n\tt.is(fs.readFileSync(t.context.destination, 'utf8'), fs.readFileSync('license', 'utf8'));\n});\n\ntest('do not overwrite when disabled', t => {\n\tfs.writeFileSync(t.context.destination, '');\n\n\tconst error = t.throws(() => {\n\t\tcopyFileSync('license', t.context.destination, {overwrite: false});\n\t}, {\n\t\tname: 'CopyFileError',\n\t});\n\n\tt.is(error.code, 'EEXIST');\n\tt.is(fs.readFileSync(t.context.destination, 'utf8'), '');\n});\n\nif (process.platform !== 'win32') {\n\ttest('create directories with specified mode', t => {\n\t\tconst directory = t.context.destination;\n\t\tconst destination = `${directory}/${crypto.randomUUID()}`;\n\t\tconst directoryMode = 0o700;\n\t\tcopyFileSync('license', destination, {directoryMode});\n\t\tconst stat = fs.statSync(directory);\n\t\tt.is(stat.mode & directoryMode, directoryMode); // eslint-disable-line no-bitwise\n\t});\n}\n\ntest('do not create `destination` on unreadable `source`', t => {\n\tt.throws(\n\t\t() => {\n\t\t\tcopyFileSync('node_modules', t.context.destination);\n\t\t},\n\t\t{\n\t\t\tname: 'CopyFileError',\n\t\t\tcode: 'EISDIR',\n\t\t},\n\t);\n\n\tt.throws(() => {\n\t\tfs.statSync(t.context.destination);\n\t}, {\n\t\tmessage: /ENOENT/,\n\t});\n});\n\ntest('do not create `destination` directory on unreadable `source`', t => {\n\tt.throws(\n\t\t() => {\n\t\t\tcopyFileSync('node_modules', `subdir/${crypto.randomUUID()}`);\n\t\t},\n\t\t{\n\t\t\tname: 'CopyFileError',\n\t\t\tcode: 'EISDIR',\n\t\t},\n\t);\n\n\tt.throws(() => {\n\t\tfs.statSync('subdir');\n\t}, {\n\t\tmessage: /ENOENT/,\n\t});\n});\n\ntest('preserve timestamps', t => {\n\tcopyFileSync('license', t.context.destination);\n\tconst licenseStats = fs.lstatSync('license');\n\tconst temporaryStats = fs.lstatSync(t.context.destination);\n\tassertDateEqual(t, licenseStats.atime, temporaryStats.atime);\n\tassertDateEqual(t, licenseStats.mtime, temporaryStats.mtime);\n});\n\ntest('preserve mode', t => {\n\tcopyFileSync('license', t.context.destination);\n\tconst licenseStats = fs.lstatSync('license');\n\tconst temporaryStats = fs.lstatSync(t.context.destination);\n\tt.is(licenseStats.mode, temporaryStats.mode);\n});\n\ntest('throw an Error if `source` does not exists', t => {\n\tconst error = t.throws(() => {\n\t\tcopyFileSync('NO_ENTRY', t.context.destination);\n\t});\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.code, 'ENOENT', error.message);\n\tt.regex(error.message, /`NO_ENTRY`/, error.message);\n\tt.regex(error.stack, /`NO_ENTRY`/, error.message);\n});\n\ntest.failing('rethrow mkdir EACCES errors', t => {\n\tconst directoryPath = `/root/NO_ACCESS_${crypto.randomUUID()}`;\n\tconst destination = path.join(directoryPath, crypto.randomUUID());\n\tconst mkdirError = buildEACCES(directoryPath);\n\n\tfs.mkdirSync = sinon.stub(fs, 'mkdirSync').throws(mkdirError);\n\n\tconst error = t.throws(() => {\n\t\tcopyFileSync('license', destination);\n\t});\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.errno, mkdirError.errno, error.message);\n\tt.is(error.code, mkdirError.code, error.message);\n\tt.is(error.path, mkdirError.path, error.message);\n\tt.true(fs.mkdirSync.called);\n\n\tfs.mkdirSync.restore();\n});\n\ntest('rethrow ENOSPC errors', t => {\n\tconst noSpaceError = buildENOSPC();\n\n\tfs.writeFileSync(t.context.source, '');\n\tfs.copyFileSync = sinon.stub(fs, 'copyFileSync').throws(noSpaceError);\n\n\tconst error = t.throws(() => {\n\t\tcopyFileSync('license', t.context.destination);\n\t});\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.errno, noSpaceError.errno, error.message);\n\tt.is(error.code, noSpaceError.code, error.message);\n\tt.true(fs.copyFileSync.called);\n\n\tfs.copyFileSync.restore();\n});\n\ntest.failing('rethrow stat errors', t => {\n\tconst statError = buildEBADF();\n\n\tfs.writeFileSync(t.context.source, '');\n\n\tfs.statSync = sinon.stub(fs, 'statSync').throws(statError);\n\n\tconst error = t.throws(() => {\n\t\tcopyFileSync(t.context.source, t.context.destination);\n\t});\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.errno, statError.errno, error.message);\n\tt.is(error.code, statError.code, error.message);\n\tt.true(fs.statSync.called);\n\n\tfs.statSync.restore();\n});\n\ntest.failing('rethrow utimes errors', t => {\n\tconst futimesError = buildEBADF();\n\n\tfs.utimesSync = sinon.stub(fs, 'utimesSync').throws(futimesError);\n\n\tconst error = t.throws(() => {\n\t\tcopyFileSync('license', t.context.destination);\n\t});\n\tt.is(error.name, 'CopyFileError', error.message);\n\tt.is(error.errno, futimesError.errno, error.message);\n\tt.is(error.code, futimesError.code, error.message);\n\tt.true(fs.utimesSync.called);\n\n\tfs.utimesSync.restore();\n});\n\ntest('cwd option', t => {\n\tconst error = t.throws(() => {\n\t\tcopyFileSync('sync.js', t.context.destination);\n\t});\n\n\tt.is(error.name, 'CopyFileError');\n\tt.is(error.code, 'ENOENT');\n\n\tt.notThrows(() => {\n\t\tcopyFileSync('sync.js', t.context.destination, {cwd: 'test'});\n\t});\n});\n"
  }
]