// Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The SFC licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. 'use strict' const assert = require('node:assert'), fs = require('node:fs'), path = require('node:path') const io = require('selenium-webdriver/io') describe('io', function () { describe('copy', function () { let tmpDir before(function () { return io.tmpDir().then(function (d) { tmpDir = d fs.writeFileSync(path.join(d, 'foo'), 'Hello, world') }) }) it('can copy one file to another', function () { return io.tmpFile().then(function (f) { return io.copy(path.join(tmpDir, 'foo'), f).then(function (p) { assert.strictEqual(p, f) assert.strictEqual('Hello, world', fs.readFileSync(p, 'utf-8')) }) }) }) it('can copy symlink to destination', function () { if (process.platform === 'win32') { return // No symlinks on windows. } fs.symlinkSync(path.join(tmpDir, 'foo'), path.join(tmpDir, 'symlinked-foo')) return io.tmpFile().then(function (f) { return io.copy(path.join(tmpDir, 'symlinked-foo'), f).then(function (p) { assert.strictEqual(p, f) assert.strictEqual('Hello, world', fs.readFileSync(p, 'utf-8')) }) }) }) it('fails if given a directory as a source', function () { return io .tmpFile() .then(function (f) { return io.copy(tmpDir, f) }) .then( function () { throw Error('Should have failed with a type error') }, function () { // Do nothing; expected. }, ) }) }) describe('copyDir', function () { it('copies recursively', function () { return io.tmpDir().then(function (dir) { fs.writeFileSync(path.join(dir, 'file1'), 'hello') fs.mkdirSync(path.join(dir, 'sub')) fs.mkdirSync(path.join(dir, 'sub/folder')) fs.writeFileSync(path.join(dir, 'sub/folder/file2'), 'goodbye') return io.tmpDir().then(function (dst) { return io.copyDir(dir, dst).then(function (ret) { assert.strictEqual(dst, ret) assert.strictEqual('hello', fs.readFileSync(path.join(dst, 'file1'), 'utf-8')) assert.strictEqual('goodbye', fs.readFileSync(path.join(dst, 'sub/folder/file2'), 'utf-8')) }) }) }) }) it('creates destination dir if necessary', function () { return io .tmpDir() .then(function (srcDir) { fs.writeFileSync(path.join(srcDir, 'foo'), 'hi') return io.tmpDir().then(function (dstDir) { return io.copyDir(srcDir, path.join(dstDir, 'sub')) }) }) .then(function (p) { assert.strictEqual('sub', path.basename(p)) assert.strictEqual('hi', fs.readFileSync(path.join(p, 'foo'), 'utf-8')) }) }) it('supports regex exclusion filter', function () { return io .tmpDir() .then(function (src) { fs.writeFileSync(path.join(src, 'foo'), 'a') fs.writeFileSync(path.join(src, 'bar'), 'b') fs.writeFileSync(path.join(src, 'baz'), 'c') fs.mkdirSync(path.join(src, 'sub')) fs.writeFileSync(path.join(src, 'sub/quux'), 'd') fs.writeFileSync(path.join(src, 'sub/quot'), 'e') return io.tmpDir().then(function (dst) { return io.copyDir(src, dst, /(bar|quux)/) }) }) .then(function (dir) { assert.strictEqual('a', fs.readFileSync(path.join(dir, 'foo'), 'utf-8')) assert.strictEqual('c', fs.readFileSync(path.join(dir, 'baz'), 'utf-8')) assert.strictEqual('e', fs.readFileSync(path.join(dir, 'sub/quot'), 'utf-8')) assert.ok(!fs.existsSync(path.join(dir, 'bar'))) assert.ok(!fs.existsSync(path.join(dir, 'sub/quux'))) }) }) it('supports exclusion filter function', function () { return io .tmpDir() .then(function (src) { fs.writeFileSync(path.join(src, 'foo'), 'a') fs.writeFileSync(path.join(src, 'bar'), 'b') fs.writeFileSync(path.join(src, 'baz'), 'c') fs.mkdirSync(path.join(src, 'sub')) fs.writeFileSync(path.join(src, 'sub/quux'), 'd') fs.writeFileSync(path.join(src, 'sub/quot'), 'e') return io.tmpDir().then(function (dst) { return io.copyDir(src, dst, function (f) { return f !== path.join(src, 'foo') && f !== path.join(src, 'sub/quot') }) }) }) .then(function (dir) { assert.strictEqual('b', fs.readFileSync(path.join(dir, 'bar'), 'utf-8')) assert.strictEqual('c', fs.readFileSync(path.join(dir, 'baz'), 'utf-8')) assert.strictEqual('d', fs.readFileSync(path.join(dir, 'sub/quux'), 'utf-8')) assert.ok(!fs.existsSync(path.join(dir, 'foo'))) assert.ok(!fs.existsSync(path.join(dir, 'sub/quot'))) }) }) }) describe('exists', function () { var dir before(function () { return io.tmpDir().then(function (d) { dir = d }) }) it('returns a rejected promise if input value is invalid', function () { return io.exists(undefined).then( () => assert.fail('should have failed'), (e) => assert.ok(e instanceof TypeError), ) }) it('works for directories', function () { return io.exists(dir).then(assert.ok) }) it('works for files', function () { var file = path.join(dir, 'foo') fs.writeFileSync(file, '') return io.exists(file).then(assert.ok) }) it('does not return a rejected promise if file does not exist', function () { return io.exists(path.join(dir, 'not-there')).then(function (exists) { assert.ok(!exists) }) }) }) describe('unlink', function () { let dir before(function () { return io.tmpDir().then(function (d) { dir = d }) }) it('silently succeeds if the path does not exist', function () { return io.unlink(path.join(dir, 'not-there')) }) it('deletes files', function () { const file = path.join(dir, 'foo') fs.writeFileSync(file, '') return io .exists(file) .then(assert.ok) .then(function () { return io.unlink(file) }) .then(function () { return io.exists(file) }) .then(function (exists) { return assert.ok(!exists) }) }) }) describe('rmDir', function () { it('succeeds if the designated directory does not exist', function () { return io.tmpDir().then(function (d) { return io.rmDir(path.join(d, 'i/do/not/exist')) }) }) it('deletes recursively', function () { return io.tmpDir().then(function (dir) { fs.writeFileSync(path.join(dir, 'file1'), 'hello') fs.mkdirSync(path.join(dir, 'sub')) fs.mkdirSync(path.join(dir, 'sub/folder')) fs.writeFileSync(path.join(dir, 'sub/folder/file2'), 'goodbye') return io.rmDir(dir).then(function () { assert.ok(!fs.existsSync(dir)) assert.ok(!fs.existsSync(path.join(dir, 'sub/folder/file2'))) }) }) }) }) describe('findInPath', function () { const savedPathEnv = process.env['PATH'] afterEach(() => (process.env['PATH'] = savedPathEnv)) const cwd = process.cwd afterEach(() => (process.cwd = cwd)) let dirs beforeEach(() => { return Promise.all([io.tmpDir(), io.tmpDir(), io.tmpDir()]).then((arr) => { dirs = arr process.env['PATH'] = arr.join(path.delimiter) }) }) it('returns null if file cannot be found', () => { assert.strictEqual(io.findInPath('foo.txt'), null) }) it('can find file on path', () => { let filePath = path.join(dirs[1], 'foo.txt') fs.writeFileSync(filePath, 'hi') assert.strictEqual(io.findInPath('foo.txt'), filePath) }) it('returns null if file is in a subdir of a directory on the path', () => { let subDir = path.join(dirs[2], 'sub') fs.mkdirSync(subDir) let filePath = path.join(subDir, 'foo.txt') fs.writeFileSync(filePath, 'hi') assert.strictEqual(io.findInPath('foo.txt'), null) }) it('does not match on directories', () => { fs.mkdirSync(path.join(dirs[2], 'sub')) assert.strictEqual(io.findInPath('sub'), null) }) it('will look in cwd first if requested', () => { return io.tmpDir().then((fakeCwd) => { process.cwd = () => fakeCwd let theFile = path.join(fakeCwd, 'foo.txt') fs.writeFileSync(path.join(dirs[1], 'foo.txt'), 'hi') fs.writeFileSync(theFile, 'bye') assert.strictEqual(io.findInPath('foo.txt', true), theFile) }) }) }) describe('read', function () { let tmpDir before(function () { return io.tmpDir().then(function (d) { tmpDir = d fs.writeFileSync(path.join(d, 'foo'), 'Hello, world') }) }) it('can read a file', function () { return io.read(path.join(tmpDir, 'foo')).then((buff) => { assert.ok(buff instanceof Buffer) assert.strictEqual('Hello, world', buff.toString()) }) }) it('catches errors from invalid input', function () { return io.read({}).then( () => assert.fail('should have failed'), (e) => assert.ok(e instanceof TypeError), ) }) it('rejects returned promise if file does not exist', function () { return io.read(path.join(tmpDir, 'not-there')).then( () => assert.fail('should have failed'), (e) => assert.strictEqual('ENOENT', e.code), ) }) }) describe('mkdirp', function () { it('recursively creates entire directory path', function () { return io.tmpDir().then((root) => { let dst = path.join(root, 'foo/bar/baz') return io.mkdirp(dst).then((d) => { assert.strictEqual(d, dst) return io.stat(d).then((stats) => { assert.ok(stats.isDirectory()) }) }) }) }) it('does nothing if the directory already exists', function () { return io.tmpDir().then((dir) => io.mkdirp(dir).then((d) => assert.strictEqual(d, dir))) }) }) describe('walkDir', function () { it('walk directory', async function () { let dir = await io.tmpDir() fs.writeFileSync(path.join(dir, 'file1'), 'hello') fs.mkdirSync(path.join(dir, 'sub')) fs.mkdirSync(path.join(dir, 'sub/folder')) fs.writeFileSync(path.join(dir, 'sub/folder/file2'), 'goodbye') let seen = await io.walkDir(dir) seen.sort((a, b) => { if (a.path < b.path) return -1 if (a.path > b.path) return 1 return 0 }) assert.deepStrictEqual(seen, [ { path: 'file1', dir: false }, { path: 'sub', dir: true }, { path: path.join('sub', 'folder'), dir: true }, { path: path.join('sub', 'folder', 'file2'), dir: false }, ]) }) }) })