blob: 41d583a0ce9524e9efb4ba6fc07baf93f62cadc5 [file] [log] [blame]
/**
* @license
* Copyright 2019 The Bazel Authors. All rights reserved.
*
* Licensed 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.
*/
import * as assert from 'node:assert'
import * as fs from 'node:fs'
import { withFixtures } from 'inline-fixtures'
import * as path from 'node:path'
import * as util from 'node:util'
import { patcher } from '../../node-patches/src/fs.cjs'
// We don't want to bring jest into this repo so we just fake the describe and it functions here
async function describe(_, fn) {
await fn()
}
async function it(_, fn) {
await fn()
}
describe('testing lstat', async () => {
await it('can lstat symlink in root', async () => {
await withFixtures(
{
a: {},
b: { file: 'contents' },
},
async (fixturesDir) => {
fixturesDir = fs.realpathSync(fixturesDir)
// create symlink from a/link to b/file
fs.symlinkSync(
path.join(fixturesDir, 'b', 'file'),
path.join(fixturesDir, 'a', 'link')
)
const revertPatches = patcher([path.join(fixturesDir)])
const linkPath = path.join(fixturesDir, 'a', 'link')
assert.ok(
fs.lstatSync(linkPath).isSymbolicLink(),
'lstatSync should find symbolic link if link is the root'
)
assert.ok(
(await util.promisify(fs.lstat)(linkPath)).isSymbolicLink(),
'lstat should find symbolic link if link is the root'
)
assert.ok(
(await fs.promises.lstat(linkPath)).isSymbolicLink(),
'promises.lstat should find symbolic link if link is the root'
)
revertPatches()
}
)
})
await it('can lstatSync throwIfNoEntry:false', async () => {
await withFixtures(
{
a: { g: {} },
b: { file: 'contents' },
},
async (fixturesDir) => {
fixturesDir = fs.realpathSync(fixturesDir)
const revertPatches = patcher([
path.join(fixturesDir),
path.join(fixturesDir, 'a', 'g'),
])
assert.equal(
undefined,
fs.lstatSync(path.join(fixturesDir, 'doesnt-exist'), {
throwIfNoEntry: false,
})
)
revertPatches()
}
)
})
await it('can lstat symlink in guard is file', async () => {
await withFixtures(
{
a: { g: {} },
b: { file: 'contents' },
},
async (fixturesDir) => {
fixturesDir = fs.realpathSync(fixturesDir)
// create symlink from a/g/link to b/file
fs.symlinkSync(
path.join(fixturesDir, 'b', 'file'),
path.join(fixturesDir, 'a', 'g', 'link')
)
const revertPatches = patcher([
path.join(fixturesDir),
path.join(fixturesDir, 'a', 'g'),
])
console.error('Starting')
console.error(fs.readlink.toString())
const linkPath = path.join(fixturesDir, 'a', 'g', 'link')
assert.ok(
fs.lstatSync(linkPath).isFile(),
'lstatSync should find file if link is in guard'
)
assert.ok(
(await util.promisify(fs.lstat)(linkPath)).isFile(),
'lstat should find file if link is in guard'
)
assert.ok(
(await fs.promises.lstat(linkPath)).isFile(),
'promises.lstat should find file if link is in guard'
)
revertPatches()
}
)
})
await it('lstat of symlink out of root is file.', async () => {
await withFixtures(
{
a: {},
b: { file: 'contents' },
},
async (fixturesDir) => {
fixturesDir = fs.realpathSync(fixturesDir)
// create symlink from a/link to b/file
fs.symlinkSync(
path.join(fixturesDir, 'b', 'file'),
path.join(fixturesDir, 'a', 'link')
)
const revertPatches = patcher([path.join(fixturesDir, 'a')])
const linkPath = path.join(fixturesDir, 'a', 'link')
assert.ok(
fs.lstatSync(linkPath).isFile(),
'lstatSync should find file it file link is out of root'
)
assert.ok(
(await util.promisify(fs.lstat)(linkPath)).isFile(),
'lstat should find file it file link is out of root'
)
assert.ok(
(await fs.promises.lstat(linkPath)).isFile(),
'promises.lstat should find file it file link is out of root'
)
let brokenLinkPath = path.join(fixturesDir, 'a', 'broken-link')
fs.symlinkSync(
path.join(fixturesDir, 'doesnt-exist'),
brokenLinkPath
)
assert.ok(
fs.lstatSync(brokenLinkPath).isSymbolicLink(),
'if a symlink is broken but is escaping return it as a link.'
)
assert.ok(
(
await util.promisify(fs.lstat)(brokenLinkPath)
).isSymbolicLink(),
'if a symlink is broken but is escaping return it as a link.'
)
assert.ok(
(await fs.promises.lstat(brokenLinkPath)).isSymbolicLink(),
'if a symlink is broken but is escaping return it as a link.'
)
brokenLinkPath = path.join(fixturesDir, 'a', 'broken-link2')
fs.symlinkSync(
path.join(fixturesDir, 'a', 'doesnt-exist'),
brokenLinkPath
)
const stat = await fs.promises.lstat(brokenLinkPath)
assert.ok(
stat.isSymbolicLink(),
'if a symlink is broken but not escaping return it as a link.'
)
revertPatches()
}
)
})
await it('not in root, symlinks do what they would have before.', async () => {
await withFixtures(
{
a: {},
b: { file: 'contents' },
},
async (fixturesDir) => {
fixturesDir = fs.realpathSync(fixturesDir)
// create symlink from a/link to b/file
fs.symlinkSync(
path.join(fixturesDir, 'b', 'file'),
path.join(fixturesDir, 'b', 'link')
)
const revertPatches = patcher([path.join(fixturesDir, 'a')])
const linkPath = path.join(fixturesDir, 'b', 'link')
assert.ok(
fs.lstatSync(linkPath).isSymbolicLink(),
'lstatSync should find symbolic link if link is out of the root'
)
assert.ok(
fs
.lstatSync(new URL(`file://${linkPath}`))
.isSymbolicLink(),
'lstatSync should find symbolic link if link is out of the root'
)
const stat = await util.promisify(fs.lstat)(linkPath)
assert.ok(
stat.isSymbolicLink(),
'lstat should find symbolic link if link is outside'
)
assert.ok(
(await fs.promises.lstat(linkPath)).isSymbolicLink(),
'promises.lstat should find symbolic link if link is outside'
)
revertPatches()
}
)
})
await it('includes parent calls in stack traces', async function lstatStackTest1() {
let err
try {
fs.lstatSync(null)
} catch (e) {
err = e
} finally {
if (!err) assert.fail('lstat should fail on invalid path')
if (!err.stack.includes('lstatStackTest1'))
assert.fail(
`lstat error stack should contain calling method: ${err.stack}`
)
}
})
})