Skip to content

Commit

Permalink
Create fixture symlinks as junctions if pointing at directories
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacs committed Nov 16, 2020
1 parent 82184d9 commit 1e462d9
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 4 deletions.
2 changes: 2 additions & 0 deletions docs/src/content/docs/api/fixtures/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ this:
const dir = t.testdir({
'some-file': 'some contents',
// use t.fixture() to create links and symlinks
// this will use junctions on Windows as of v14.11.0 if the
// target is a directory, so Administrator perms aren't needed.
link: t.fixture('symlink', 'some-file'),
nested: {
'README.md': 'nested dirs work, too!'
Expand Down
29 changes: 25 additions & 4 deletions lib/fixture.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const {writeFileSync, linkSync, symlinkSync} = require('fs')
const {writeFileSync, linkSync, statSync, symlinkSync} = require('fs')
const {resolve, dirname} = require('path')
const mkdirp = require('mkdirp')

Expand Down Expand Up @@ -29,30 +29,51 @@ class Fixture {
return 'Fixture<' + this.type + '>'
}

static make (abs, f) {
// have to gather up symlinks for the end
static make (abs, f, symlinks = null) {
if (typeof f === 'string' || Buffer.isBuffer(f))
f = new Fixture('file', f)
else if (f && typeof f === 'object' && !(f instanceof Fixture))
f = new Fixture('dir', f)
else if (!(f instanceof Fixture))
throw new Error('invalid fixture type: ' + f)

const isRoot = symlinks === null
symlinks = symlinks || {}

switch (f.type) {
case 'symlink':
symlinkSync(f.content, abs)
// have to gather up symlinks for the end, because windows
symlinks[abs] = f.content
break
case 'link':
linkSync(resolve(dirname(abs), f.content), abs)
break
case 'dir':
mkdirp.sync(abs)
for (const [name, fixture] of Object.entries(f.content))
Fixture.make(`${abs}/${name}`, fixture)
Fixture.make(`${abs}/${name}`, fixture, symlinks)
break
case 'file':
writeFileSync(abs, f.content)
break
}

// create all those symlinks we were asked for
if (isRoot) {
for (const [abs, target] of Object.entries(symlinks)) {
symlinkSync(target, abs, isDir(abs, target) ? 'junction' : 'file')
}
}
}
}

// check if a symlink target is a directory
const isDir = (abs, target) => {
try {
return statSync(resolve(dirname(abs), target)).isDirectory()
} catch (er) {
return false
}
}

Expand Down
6 changes: 6 additions & 0 deletions test/fixture.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const t = require('../')
const Fixture = require('../lib/fixture.js')

const dir = t.testdirName
require('rimraf').sync(dir)

const f = new Fixture('file', 'bar')
t.match(f, {
type: 'file',
Expand Down Expand Up @@ -33,9 +35,12 @@ t.throws(() => new Fixture('file'), {

Fixture.make(dir, {
file: 'content',
dir: {},
symlink: new Fixture('symlink', 'file'),
dirlink: new Fixture('symlink', 'dir'),
link: new Fixture('link', 'file'),
dir: new Fixture('dir', {}),
noexist: new Fixture('symlink', 'non-existent-file'),
})
const fs = require('fs')
t.ok(fs.statSync(dir).isDirectory(), 'dir is a dir')
Expand All @@ -44,4 +49,5 @@ t.match(fs.statSync(`${dir}/link`), fs.statSync(`${dir}/file`),
'hardlink is hard link')
t.equal(fs.readlinkSync(`${dir}/symlink`), 'file', 'symlink is symlink')
t.ok(fs.statSync(`${dir}/dir`).isDirectory(), 'subdir is a dir')

require('rimraf').sync(dir)

0 comments on commit 1e462d9

Please sign in to comment.